From 6cbaed39dcef3a1d7d41d24fa4d62bbe5c67bdeb Mon Sep 17 00:00:00 2001 From: aherlihy Date: Wed, 11 Mar 2015 16:11:53 -0400 Subject: [PATCH] PYTHON-822: Added CRUD YAML tests. --- test/crud/read/aggregate.json | 104 +++++++ test/crud/read/count.json | 60 ++++ test/crud/read/distinct.json | 55 ++++ test/crud/read/find.json | 105 +++++++ test/crud/write/deleteMany.json | 76 +++++ test/crud/write/deleteOne.json | 96 +++++++ test/crud/write/findOneAndDelete.json | 127 ++++++++ test/crud/write/findOneAndReplace.json | 366 +++++++++++++++++++++++ test/crud/write/findOneAndUpdate.json | 382 +++++++++++++++++++++++++ test/crud/write/insertMany.json | 52 ++++ test/crud/write/insertOne.json | 39 +++ test/crud/write/replaceOne.json | 199 +++++++++++++ test/crud/write/updateMany.json | 178 ++++++++++++ test/crud/write/updateOne.json | 162 +++++++++++ test/test_crud.py | 154 ++++++++++ 15 files changed, 2155 insertions(+) create mode 100644 test/crud/read/aggregate.json create mode 100644 test/crud/read/count.json create mode 100644 test/crud/read/distinct.json create mode 100644 test/crud/read/find.json create mode 100644 test/crud/write/deleteMany.json create mode 100644 test/crud/write/deleteOne.json create mode 100644 test/crud/write/findOneAndDelete.json create mode 100644 test/crud/write/findOneAndReplace.json create mode 100644 test/crud/write/findOneAndUpdate.json create mode 100644 test/crud/write/insertMany.json create mode 100644 test/crud/write/insertOne.json create mode 100644 test/crud/write/replaceOne.json create mode 100644 test/crud/write/updateMany.json create mode 100644 test/crud/write/updateOne.json create mode 100644 test/test_crud.py diff --git a/test/crud/read/aggregate.json b/test/crud/read/aggregate.json new file mode 100644 index 000000000..cbda0483c --- /dev/null +++ b/test/crud/read/aggregate.json @@ -0,0 +1,104 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "Aggregate with multiple stages", + "operation": { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "batchSize": 2 + } + }, + "outcome": { + "result": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + }, + { + "description": "Aggregate with $out", + "operation": { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ], + "batchSize": 2 + } + }, + "outcome": { + "result": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "collection": { + "name": "other_test_collection", + "data": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/read/count.json b/test/crud/read/count.json new file mode 100644 index 000000000..85c17e11a --- /dev/null +++ b/test/crud/read/count.json @@ -0,0 +1,60 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "Count without a filter", + "operation": { + "name": "count", + "arguments": { + "filter": {} + } + }, + "outcome": { + "result": 3 + } + }, + { + "description": "Count with a filter", + "operation": { + "name": "count", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + } + } + }, + "outcome": { + "result": 2 + } + }, + { + "description": "Count with skip and limit", + "operation": { + "name": "count", + "arguments": { + "filter": {}, + "skip": 1, + "limit": 3 + } + }, + "outcome": { + "result": 2 + } + } + ] +} \ No newline at end of file diff --git a/test/crud/read/distinct.json b/test/crud/read/distinct.json new file mode 100644 index 000000000..408d8a480 --- /dev/null +++ b/test/crud/read/distinct.json @@ -0,0 +1,55 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "Distinct without a filter", + "operation": { + "name": "distinct", + "arguments": { + "fieldName": "x", + "filter": {} + } + }, + "outcome": { + "result": [ + 11, + 22, + 33 + ] + } + }, + { + "description": "Distinct with a filter", + "operation": { + "name": "distinct", + "arguments": { + "fieldName": "x", + "filter": { + "_id": { + "$gt": 1 + } + } + } + }, + "outcome": { + "result": [ + 22, + 33 + ] + } + } + ] +} \ No newline at end of file diff --git a/test/crud/read/find.json b/test/crud/read/find.json new file mode 100644 index 000000000..d92081d55 --- /dev/null +++ b/test/crud/read/find.json @@ -0,0 +1,105 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ], + "tests": [ + { + "description": "Find with filter", + "operation": { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + } + }, + "outcome": { + "result": [ + { + "_id": 1, + "x": 11 + } + ] + } + }, + { + "description": "Find with filter, sort, skip, and limit", + "operation": { + "name": "find", + "arguments": { + "filter": { + "_id": { + "$gt": 2 + } + }, + "sort": { + "_id": 1 + }, + "skip": 2, + "limit": 2 + } + }, + "outcome": { + "result": [ + { + "_id": 5, + "x": 55 + } + ] + } + }, + { + "description": "Find with limit, sort, and batchsize", + "operation": { + "name": "find", + "arguments": { + "filter": {}, + "sort": { + "_id": 1 + }, + "limit": 4, + "batchSize": 2 + } + }, + "outcome": { + "result": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/deleteMany.json b/test/crud/write/deleteMany.json new file mode 100644 index 000000000..885ebd200 --- /dev/null +++ b/test/crud/write/deleteMany.json @@ -0,0 +1,76 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "DeleteMany when many documents match", + "operation": { + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + } + } + }, + "outcome": { + "result": { + "deletedCount": 2 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + } + ] + } + } + }, + { + "description": "DeleteMany when no document matches", + "operation": { + "name": "deleteMany", + "arguments": { + "filter": { + "_id": 4 + } + } + }, + "outcome": { + "result": { + "deletedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/deleteOne.json b/test/crud/write/deleteOne.json new file mode 100644 index 000000000..50226bdd5 --- /dev/null +++ b/test/crud/write/deleteOne.json @@ -0,0 +1,96 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "DeleteOne when many documents match", + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + } + } + }, + "outcome": { + "result": { + "deletedCount": 1 + } + } + }, + { + "description": "DeleteOne when one document matches", + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 2 + } + } + }, + "outcome": { + "result": { + "deletedCount": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "DeleteOne when no documents match", + "operation": { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 4 + } + } + }, + "outcome": { + "result": { + "deletedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/findOneAndDelete.json b/test/crud/write/findOneAndDelete.json new file mode 100644 index 000000000..2bfcc32c6 --- /dev/null +++ b/test/crud/write/findOneAndDelete.json @@ -0,0 +1,127 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "FindOneAndDelete when many documents match", + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndDelete when one document matches", + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 2 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndDelete when no documents match", + "operation": { + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 4 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/findOneAndReplace.json b/test/crud/write/findOneAndReplace.json new file mode 100644 index 000000000..c24100614 --- /dev/null +++ b/test/crud/write/findOneAndReplace.json @@ -0,0 +1,366 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "FindOneAndReplace when many documents match returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 32 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 32 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when many documents match returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 32 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 32 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 32 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when one document matches returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 2 + }, + "replacement": { + "x": 32 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 32 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when one document matches returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 2 + }, + "replacement": { + "x": 32 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 32 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 32 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match with upsert returning the document before modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndReplace when no documents match with upsert returning the document after modification", + "operation": { + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 44 + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "x": 44 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/findOneAndUpdate.json b/test/crud/write/findOneAndUpdate.json new file mode 100644 index 000000000..df973110d --- /dev/null +++ b/test/crud/write/findOneAndUpdate.json @@ -0,0 +1,382 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "FindOneAndUpdate when many documents match returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when many documents match returning the document after modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 23 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when one document matches returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 22 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when one document matches returning the document after modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": { + "x": 23 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when no documents match returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when no documents match with upsert returning the document before modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when no documents match returning the document after modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + } + } + }, + "outcome": { + "result": null, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "FindOneAndUpdate when no documents match with upsert returning the document after modification", + "operation": { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "projection": { + "x": 1, + "_id": 0 + }, + "returnDocument": "After", + "sort": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "x": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/insertMany.json b/test/crud/write/insertMany.json new file mode 100644 index 000000000..f604ef75f --- /dev/null +++ b/test/crud/write/insertMany.json @@ -0,0 +1,52 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + } + ], + "tests": [ + { + "description": "InsertMany with non-existing documents", + "operation": { + "name": "insertMany", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + }, + "outcome": { + "result": { + "insertedIds": [ + 2, + 3 + ] + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/insertOne.json b/test/crud/write/insertOne.json new file mode 100644 index 000000000..83597fca8 --- /dev/null +++ b/test/crud/write/insertOne.json @@ -0,0 +1,39 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + } + ], + "tests": [ + { + "description": "InsertOne with a non-existing document", + "operation": { + "name": "insertOne", + "arguments": { + "document": { + "_id": 2, + "x": 22 + } + } + }, + "outcome": { + "result": { + "insertedId": 2 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/replaceOne.json b/test/crud/write/replaceOne.json new file mode 100644 index 000000000..d079c8800 --- /dev/null +++ b/test/crud/write/replaceOne.json @@ -0,0 +1,199 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "ReplaceOne when many documents match", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1 + } + } + }, + { + "description": "ReplaceOne when one document matches", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": 111 + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 111 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "ReplaceOne when no documents match", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 1 + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "ReplaceOne with upsert when no documents match without an id specified", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + }, + { + "description": "ReplaceOne with upsert when no documents match with an id specified", + "operation": { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 1 + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/updateMany.json b/test/crud/write/updateMany.json new file mode 100644 index 000000000..b601c6d1f --- /dev/null +++ b/test/crud/write/updateMany.json @@ -0,0 +1,178 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "UpdateMany when many documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 2, + "modifiedCount": 2 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 34 + } + ] + } + } + }, + { + "description": "UpdateMany when one document matches", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateMany when no documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateMany with upsert when no documents match", + "operation": { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/crud/write/updateOne.json b/test/crud/write/updateOne.json new file mode 100644 index 000000000..cf4b13d8d --- /dev/null +++ b/test/crud/write/updateOne.json @@ -0,0 +1,162 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ], + "tests": [ + { + "description": "UpdateOne when many documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1 + } + } + }, + { + "description": "UpdateOne when one document matches", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 1, + "modifiedCount": 1 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateOne when no documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + } + }, + { + "description": "UpdateOne with upsert when no documents match", + "operation": { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "upsert": true + } + }, + "outcome": { + "result": { + "matchedCount": 0, + "modifiedCount": 0, + "upsertedId": 4 + }, + "collection": { + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 1 + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/test/test_crud.py b/test/test_crud.py new file mode 100644 index 000000000..fbc7d0574 --- /dev/null +++ b/test/test_crud.py @@ -0,0 +1,154 @@ +# Copyright 2015 MongoDB, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Test the collection module.""" + +import json +import os +import re +import sys + +sys.path[0:0] = [""] + +from bson.py3compat import iteritems +from pymongo.command_cursor import CommandCursor +from pymongo.cursor import Cursor +from pymongo.results import _WriteResult + +from test import unittest, ClientContext, IntegrationTest + + +# Reusable client context +client_context = ClientContext() + +# Location of JSON test specifications. +_TEST_PATH = os.path.join( + os.path.dirname(os.path.realpath(__file__)), 'crud') + + +class TestAllScenarios(IntegrationTest): + pass + + +def camel_to_snake(camel): + # Regex to convert CamelCase to snake_case. + snake = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', camel) + return re.sub('([a-z0-9])([A-Z])', r'\1_\2', snake).lower() + + +def check_result(expected_result, result): + if isinstance(result, Cursor) or isinstance(result, CommandCursor): + return list(result) == expected_result + + elif isinstance(result, _WriteResult): + for r in expected_result: + prop = camel_to_snake(r) + return getattr(result, prop) == expected_result[r] + else: + if not expected_result: + return result is None + else: + return result == expected_result + + +def create_test(scenario_def, test, ignore_result): + def run_scenario(self): + # Load data. + assert scenario_def['data'], "tests must have non-empty data" + self.db.test.drop() + self.db.test.insert_many(scenario_def['data']) + + # Convert command from CamelCase to pymongo.collection method. + operation = camel_to_snake(test['operation']['name']) + cmd = getattr(self.db.test, operation) + + # Convert arguments to snake_case and handle special cases. + arguments = test['operation']['arguments'] + for arg_name in list(arguments): + c2s = camel_to_snake(arg_name) + # PyMongo accepts sort as list of tuples. Asserting len=1 + # because ordering dicts from JSON in 2.6 is unwieldy. + if arg_name == "sort": + sort_dict = arguments[arg_name] + assert len(sort_dict) == 1, 'test can only have 1 sort key' + arguments[arg_name] = list(iteritems(sort_dict)) + # Named "key" instead not fieldName. + if arg_name == "fieldName": + arguments["key"] = arguments.pop(arg_name) + # Aggregate uses "batchSize", while find uses batch_size. + elif arg_name == "batchSize" and operation == "aggregate": + continue + # Requires boolean returnDocument. + elif arg_name == "returnDocument": + arguments[c2s] = arguments[arg_name] == "After" + else: + arguments[c2s] = arguments.pop(arg_name) + + result = cmd(**arguments) + + # Assert result is expected, excluding the $out aggregation test. + if not ignore_result: + check_result(test['outcome'].get('result'), result) + + # Assert final state is expected. + expected_c = test['outcome'].get('collection') + if expected_c is not None: + expected_name = expected_c.get('name') + if expected_name is not None: + db_coll = db_coll = self.db[expected_name] + else: + db_coll = self.db.test + self.assertEqual(list(db_coll.find()), expected_c['data']) + + return run_scenario + + +def create_tests(): + for dirpath, _, filenames in os.walk(_TEST_PATH): + dirname = os.path.split(dirpath)[-1] + + for filename in filenames: + with open(os.path.join(dirpath, filename)) as scenario_stream: + scenario_def = json.load(scenario_stream) + + test_type = os.path.splitext(filename)[0] + + # Construct test from scenario. + for test in scenario_def['tests']: + desc = test['description'] + # Special case tests that require specific versions + if ("without an id specified" in desc or + "FindOneAndReplace" in desc and "with upsert" in desc): + new_test = client_context.require_version_min(2, 6, 0)( + create_test(scenario_def, test, False)) + elif (desc == "Aggregate with $out" or + desc == "Aggregate with multiple stages"): + new_test = client_context.require_version_min(2, 6, 0)( + create_test(scenario_def, test, True)) + else: + new_test = create_test(scenario_def, test, False) + + test_name = 'test_%s_%s_%s' % ( + dirname, + test_type, + str(test['description'].replace(" ", "_"))) + + new_test.__name__ = test_name + setattr(TestAllScenarios, new_test.__name__, new_test) + + +create_tests() + +if __name__ == "__main__": + unittest.main()