Skip to content

Commit c5bb3fb

Browse files
committed
NODE-840 Added CRUD specification test cases and fix minor issues with upserts reporting matchedCount > 0
1 parent 40ffae9 commit c5bb3fb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+4324
-18
lines changed

lib/collection.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -892,10 +892,10 @@ var updateOne = function(self, filter, update, options, callback) {
892892
if(callback == null) return;
893893
if(err && callback) return callback(err);
894894
if(r == null) return callback(null, {result: {ok:1}});
895-
r.matchedCount = r.result.n;
896895
r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
897-
r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0] : null;
896+
r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0]._id : null;
898897
r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
898+
r.matchedCount = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
899899
if(callback) callback(null, r);
900900
});
901901
}
@@ -942,15 +942,16 @@ Collection.prototype.replaceOne = function(filter, doc, options, callback) {
942942
var replaceOne = function(self, filter, doc, options, callback) {
943943
// Set single document update
944944
options.multi = false;
945+
945946
// Execute update
946947
updateDocuments(self, filter, doc, options, function(err, r) {
947948
if(callback == null) return;
948949
if(err && callback) return callback(err);
949950
if(r == null) return callback(null, {result: {ok:1}});
950-
r.matchedCount = r.result.n;
951951
r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
952-
r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0] : null;
952+
r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0]._id : null;
953953
r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
954+
r.matchedCount = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
954955
r.ops = [doc];
955956
if(callback) callback(null, r);
956957
});
@@ -1002,10 +1003,10 @@ var updateMany = function(self, filter, update, options, callback) {
10021003
if(callback == null) return;
10031004
if(err && callback) return callback(err);
10041005
if(r == null) return callback(null, {result: {ok:1}});
1005-
r.matchedCount = r.result.n;
10061006
r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
1007-
r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0] : null;
1007+
r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0]._id : null;
10081008
r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
1009+
r.matchedCount = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
10091010
if(callback) callback(null, r);
10101011
});
10111012
}

lib/db.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ var debugFields = ['authSource', 'w', 'wtimeout', 'j', 'native_parser', 'forceSe
2727
, 'serializeFunctions', 'raw', 'promoteLongs', 'promoteValues', 'promoteBuffers', 'bufferMaxEntries', 'numberOfRetries', 'retryMiliSeconds'
2828
, 'readPreference', 'pkFactory', 'parentDb', 'promiseLibrary', 'noListener'];
2929

30+
// Filter out any write concern options
31+
var illegalCommandFields = ['w', 'wtimeout', 'j', 'fsync', 'autoIndexId'
32+
, 'strict', 'serializeFunctions', 'pkFactory', 'raw', 'readPreference'];
33+
3034
/**
3135
* @fileOverview The **Db** class is a class that represents a MongoDB Database.
3236
*
@@ -497,7 +501,6 @@ var createCollection = function(self, name, options, callback) {
497501
var finalOptions = writeConcern(shallowClone(options), self, options);
498502
// Did the user destroy the topology
499503
if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
500-
501504
// Check if we have the name
502505
self.listCollections({name: name})
503506
.setReadPreference(ReadPreference.PRIMARY)
@@ -515,11 +518,12 @@ var createCollection = function(self, name, options, callback) {
515518

516519
// Decorate command with writeConcern if supported
517520
decorateWithWriteConcern(cmd, self, options);
518-
519521
// Add all optional parameters
520522
for(var n in options) {
521-
if(options[n] != null && typeof options[n] != 'function')
522-
cmd[n] = options[n];
523+
if(options[n] != null
524+
&& typeof options[n] != 'function' && illegalCommandFields.indexOf(n) == -1) {
525+
cmd[n] = options[n];
526+
}
523527
}
524528

525529
// Force a primary read Preference

test/functional/collection_tests.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@ exports['should correctly list back collection names containing .'] = {
7373
// Let's check that the collection was created correctly
7474
db1.listCollections().toArray(function(err, documents) {
7575
test.equal(null, err);
76-
// console.log("--------------------------------------------------")
77-
// console.dir(documents)
7876
var found = false;
7977
documents.forEach(function(x) {
8078
if(x.name == 'test.game') found = true;

test/functional/crud/README.rst

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
==========
2+
CRUD Tests
3+
==========
4+
5+
The YAML and JSON files in this directory tree are platform-independent tests
6+
meant to exercise the translation from the API to underlying commands that
7+
MongoDB understands. Given the variety of languages and implementations and
8+
limited nature of a description of a test, there are a number of things
9+
that aren't testable. For instance, none of these tests assert that maxTimeMS
10+
was properly sent to the server. This would involve a lot of infrastructure to
11+
define and setup. Therefore, these YAML tests are in no way a replacement for
12+
more thorough testing. However, they can provide an initial verification of
13+
your implementation.
14+
15+
16+
Converting to JSON
17+
==================
18+
19+
The tests are written in YAML
20+
because it is easier for humans to write and read,
21+
and because YAML includes a standard comment format.
22+
A JSONified version of each YAML file is included in this repository.
23+
Whenever you change the YAML, re-convert to JSON.
24+
One method to convert to JSON is using
25+
`yamljs <https://www.npmjs.com/package/yamljs>`_::
26+
27+
npm install -g yamljs
28+
yaml2json -s -p -r .
29+
30+
31+
Version
32+
=======
33+
34+
Files in the "specifications" repository have no version scheme.
35+
They are not tied to a MongoDB server version,
36+
and it is our intention that each specification moves from "draft" to "final"
37+
with no further revisions; it is superseded by a future spec, not revised.
38+
39+
However, implementers must have stable sets of tests to target.
40+
As test files evolve they will occasionally be tagged like
41+
"crud-tests-YYYY-MM-DD", until the spec is final.
42+
43+
Format
44+
======
45+
46+
Each YAML file has the following keys:
47+
48+
- data: The data that should exist in the collection under test before each test run.
49+
- minServerVersion: OPTIONAL: The minimum server version required to successfully run the test. If this field is not
50+
present, it should be assumed that there is no lower bound on the server version required.
51+
- maxServerVersion: OPTIONAL: The max server version against which this test can run successfully. If this field is not
52+
present, it should be assumed that there is no upper bound on the server version required.
53+
- tests:
54+
An array of tests that are to be run independently of each other. Each test will
55+
have some or all of the following fields
56+
57+
- description: The name of the test
58+
- operation:
59+
60+
- name: The name of the operation as defined in the specification.
61+
- arguments: The names and values of arguments from the specification.
62+
- outcome:
63+
64+
- result: The return value from the operation.
65+
- collection:
66+
67+
- name: OPTIONAL: The collection name to verify. If this isn't present
68+
then use the collection under test.
69+
- data: The data that should exist in the collection after the
70+
operation has been run.
71+
72+
73+
Use as integration tests
74+
========================
75+
76+
Running these as integration tests will require a running mongod server.
77+
Each of these tests is valid against a standalone mongod, a replica set, and a
78+
sharded system for server version 3.0.0. Many of them will run against 2.4 and
79+
2.6, but some will require conditional code. For instance, $out is not supported
80+
in an aggregation pipeline in server 2.4, so that test must be skipped.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"data": [
3+
{
4+
"_id": 1,
5+
"x": "ping"
6+
}
7+
],
8+
"minServerVersion": "3.4",
9+
"tests": [
10+
{
11+
"description": "Aggregate with collation",
12+
"operation": {
13+
"arguments": {
14+
"collation": {
15+
"locale": "en_US",
16+
"strength": 2
17+
},
18+
"pipeline": [
19+
{
20+
"$match": {
21+
"x": "PING"
22+
}
23+
}
24+
]
25+
},
26+
"name": "aggregate"
27+
},
28+
"outcome": {
29+
"result": [
30+
{
31+
"_id": 1,
32+
"x": "ping"
33+
}
34+
]
35+
}
36+
}
37+
]
38+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
data:
2+
- {_id: 1, x: 'ping'}
3+
minServerVersion: '3.4'
4+
5+
tests:
6+
-
7+
description: "Aggregate with collation"
8+
operation:
9+
name: aggregate
10+
arguments:
11+
pipeline:
12+
- $match:
13+
x: 'PING'
14+
collation: { locale: 'en_US', strength: 2 } # https://docs.mongodb.com/master/reference/collation/#collation-document
15+
outcome:
16+
result:
17+
- {_id: 1, x: 'ping'}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"data": [
3+
{
4+
"_id": 1,
5+
"x": 11
6+
},
7+
{
8+
"_id": 2,
9+
"x": 22
10+
},
11+
{
12+
"_id": 3,
13+
"x": 33
14+
}
15+
],
16+
"minServerVersion": "2.6",
17+
"tests": [
18+
{
19+
"description": "Aggregate with $out",
20+
"operation": {
21+
"arguments": {
22+
"batchSize": 2,
23+
"pipeline": [
24+
{
25+
"$sort": {
26+
"x": 1
27+
}
28+
},
29+
{
30+
"$match": {
31+
"_id": {
32+
"$gt": 1
33+
}
34+
}
35+
},
36+
{
37+
"$out": "other_test_collection"
38+
}
39+
]
40+
},
41+
"name": "aggregate"
42+
},
43+
"outcome": {
44+
"collection": {
45+
"data": [
46+
{
47+
"_id": 2,
48+
"x": 22
49+
},
50+
{
51+
"_id": 3,
52+
"x": 33
53+
}
54+
],
55+
"name": "other_test_collection"
56+
},
57+
"result": [
58+
{
59+
"_id": 2,
60+
"x": 22
61+
},
62+
{
63+
"_id": 3,
64+
"x": 33
65+
}
66+
]
67+
}
68+
}
69+
]
70+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
data:
2+
- {_id: 1, x: 11}
3+
- {_id: 2, x: 22}
4+
- {_id: 3, x: 33}
5+
minServerVersion: '2.6'
6+
7+
tests:
8+
-
9+
description: "Aggregate with $out"
10+
operation:
11+
name: aggregate
12+
arguments:
13+
pipeline:
14+
- $sort: {x: 1}
15+
- $match:
16+
_id: {$gt: 1}
17+
- $out: "other_test_collection"
18+
batchSize: 2
19+
20+
outcome:
21+
result:
22+
- {_id: 2, x: 22}
23+
- {_id: 3, x: 33}
24+
collection:
25+
name: "other_test_collection"
26+
data:
27+
- {_id: 2, x: 22}
28+
- {_id: 3, x: 33}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"data": [
3+
{
4+
"_id": 1,
5+
"x": 11
6+
},
7+
{
8+
"_id": 2,
9+
"x": 22
10+
},
11+
{
12+
"_id": 3,
13+
"x": 33
14+
}
15+
],
16+
"tests": [
17+
{
18+
"description": "Aggregate with multiple stages",
19+
"operation": {
20+
"arguments": {
21+
"batchSize": 2,
22+
"pipeline": [
23+
{
24+
"$sort": {
25+
"x": 1
26+
}
27+
},
28+
{
29+
"$match": {
30+
"_id": {
31+
"$gt": 1
32+
}
33+
}
34+
}
35+
]
36+
},
37+
"name": "aggregate"
38+
},
39+
"outcome": {
40+
"result": [
41+
{
42+
"_id": 2,
43+
"x": 22
44+
},
45+
{
46+
"_id": 3,
47+
"x": 33
48+
}
49+
]
50+
}
51+
}
52+
]
53+
}

0 commit comments

Comments
 (0)