summaryrefslogtreecommitdiff
path: root/jstests/core
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/core')
-rw-r--r--jstests/core/apply_ops1.js49
-rw-r--r--jstests/core/apply_ops_atomicity.js10
-rw-r--r--jstests/core/autocomplete.js42
-rw-r--r--jstests/core/batch_write_command_delete.js2
-rw-r--r--jstests/core/batch_write_command_insert.js2
-rw-r--r--jstests/core/batch_write_command_update.js2
-rw-r--r--jstests/core/bypass_doc_validation.js2
-rw-r--r--jstests/core/capped6.js7
-rw-r--r--jstests/core/collation_plan_cache.js9
-rw-r--r--jstests/core/collection_info_cache_race.js4
-rw-r--r--jstests/core/collmod.js2
-rw-r--r--jstests/core/collmod_bad_spec.js2
-rw-r--r--jstests/core/commands_that_do_not_write_do_not_accept_wc.js2
-rw-r--r--jstests/core/constructors.js2
-rw-r--r--jstests/core/count10.js7
-rw-r--r--jstests/core/count_plan_summary.js10
-rw-r--r--jstests/core/crud_api.js2
-rw-r--r--jstests/core/diagdata.js26
-rw-r--r--jstests/core/doc_validation.js2
-rw-r--r--jstests/core/doc_validation_invalid_validators.js2
-rw-r--r--jstests/core/doc_validation_options.js1
-rw-r--r--jstests/core/dropdb_race.js2
-rw-r--r--jstests/core/elemMatchProjection.js50
-rw-r--r--jstests/core/error2.js1
-rw-r--r--jstests/core/eval0.js2
-rw-r--r--jstests/core/eval1.js1
-rw-r--r--jstests/core/eval3.js1
-rw-r--r--jstests/core/eval4.js1
-rw-r--r--jstests/core/eval5.js1
-rw-r--r--jstests/core/eval6.js1
-rw-r--r--jstests/core/eval7.js2
-rw-r--r--jstests/core/eval9.js2
-rw-r--r--jstests/core/eval_mr.js2
-rw-r--r--jstests/core/eval_nolock.js1
-rw-r--r--jstests/core/evala.js1
-rw-r--r--jstests/core/evalb.js2
-rw-r--r--jstests/core/evald.js2
-rw-r--r--jstests/core/evale.js2
-rw-r--r--jstests/core/evalg.js2
-rw-r--r--jstests/core/evalh.js2
-rw-r--r--jstests/core/evalj.js2
-rw-r--r--jstests/core/existsa.js212
-rw-r--r--jstests/core/fsync.js2
-rw-r--r--jstests/core/fts_dotted_prefix_fields.js15
-rw-r--r--jstests/core/fts_trailing_fields.js22
-rw-r--r--jstests/core/function_string_representations.js38
-rw-r--r--jstests/core/geo_2d_trailing_fields.js45
-rw-r--r--jstests/core/geo_s2cursorlimitskip.js7
-rw-r--r--jstests/core/geo_update_btree.js2
-rw-r--r--jstests/core/getlog2.js7
-rw-r--r--jstests/core/index_elemmatch2.js63
-rw-r--r--jstests/core/index_filter_commands.js20
-rw-r--r--jstests/core/index_stats.js7
-rw-r--r--jstests/core/js3.js1
-rw-r--r--jstests/core/js7.js2
-rw-r--r--jstests/core/js9.js2
-rw-r--r--jstests/core/js_jit.js40
-rw-r--r--jstests/core/list_collections1.js8
-rw-r--r--jstests/core/list_collections_filter.js4
-rw-r--r--jstests/core/list_indexes.js8
-rw-r--r--jstests/core/list_indexes_invalidation.js2
-rw-r--r--jstests/core/list_namespaces_invalidation.js2
-rw-r--r--jstests/core/max_time_ms.js8
-rw-r--r--jstests/core/mr4.js6
-rw-r--r--jstests/core/mr_killop.js3
-rw-r--r--jstests/core/mr_optim.js15
-rw-r--r--jstests/core/no_db_created.js4
-rw-r--r--jstests/core/notablescan.js7
-rw-r--r--jstests/core/operation_latency_histogram.js6
-rw-r--r--jstests/core/plan_cache_clear.js7
-rw-r--r--jstests/core/plan_cache_list_plans.js7
-rw-r--r--jstests/core/plan_cache_list_shapes.js7
-rw-r--r--jstests/core/plan_cache_shell_helpers.js7
-rw-r--r--jstests/core/profile2.js2
-rw-r--r--jstests/core/profile_getmore.js13
-rw-r--r--jstests/core/profile_insert.js2
-rw-r--r--jstests/core/recursion.js6
-rw-r--r--jstests/core/regex_not_id.js6
-rw-r--r--jstests/core/remove8.js1
-rw-r--r--jstests/core/rename4.js2
-rw-r--r--jstests/core/rename_stayTemp.js2
-rw-r--r--jstests/core/shell_connection_strings.js33
-rw-r--r--jstests/core/shell_writeconcern.js3
-rw-r--r--jstests/core/stages_delete.js6
-rw-r--r--jstests/core/startup_log.js209
-rw-r--r--jstests/core/storefunc.js2
-rw-r--r--jstests/core/top.js6
-rw-r--r--jstests/core/update_affects_indexes.js100
-rw-r--r--jstests/core/update_multi5.js4
-rw-r--r--jstests/core/views/invalid_system_views.js2
-rw-r--r--jstests/core/views/views_all_commands.js2
-rw-r--r--jstests/core/views/views_basic.js2
-rw-r--r--jstests/core/views/views_change.js3
-rw-r--r--jstests/core/views/views_collation.js117
-rw-r--r--jstests/core/views/views_find.js2
-rw-r--r--jstests/core/views/views_rename.js17
-rw-r--r--jstests/core/views/views_stats.js6
-rw-r--r--jstests/core/views/views_validation.js1
-rw-r--r--jstests/core/write_result.js2
99 files changed, 1109 insertions, 295 deletions
diff --git a/jstests/core/apply_ops1.js b/jstests/core/apply_ops1.js
index 8ce15b1df22..7088145c718 100644
--- a/jstests/core/apply_ops1.js
+++ b/jstests/core/apply_ops1.js
@@ -286,9 +286,54 @@
'applyOps should fail on unknown operation type "x" with valid "ns" value');
assert.eq(0, t.find().count(), "Non-zero amount of documents in collection to start");
+
+ /**
+ * Test function for running CRUD operations on non-existent namespaces using various
+ * combinations of invalid namespaces (collection/database), allowAtomic and alwaysUpsert.
+ *
+ * Leave 'expectedErrorCode' undefined if this command is expected to run successfully.
+ */
+ function testCrudOperationOnNonExistentNamespace(optype, o, o2, expectedErrorCode) {
+ expectedErrorCode = expectedErrorCode || ErrorCodes.OK;
+ const t2 = db.getSiblingDB('apply_ops1_no_such_db').getCollection('t');
+ [t, t2].forEach(coll => {
+ const op = {op: optype, ns: coll.getFullName(), o: o, o2: o2};
+ [false, true].forEach(allowAtomic => {
+ [false, true].forEach(alwaysUpsert => {
+ const cmd = {
+ applyOps: [op],
+ allowAtomic: allowAtomic,
+ alwaysUpsert: alwaysUpsert
+ };
+ jsTestLog('Testing applyOps on non-existent namespace: ' + tojson(cmd));
+ if (expectedErrorCode === ErrorCodes.OK) {
+ assert.commandWorked(db.adminCommand(cmd));
+ } else {
+ assert.commandFailedWithCode(db.adminCommand(cmd), expectedErrorCode);
+ }
+ });
+ });
+ });
+ }
+
+ // Insert and update operations on non-existent collections/databases should return
+ // NamespaceNotFound.
+ testCrudOperationOnNonExistentNamespace('i', {_id: 0}, {}, ErrorCodes.NamespaceNotFound);
+ testCrudOperationOnNonExistentNamespace('u', {x: 0}, {_id: 0}, ErrorCodes.NamespaceNotFound);
+
+ // Delete operations on non-existent collections/databases should return OK for idempotency
+ // reasons.
+ testCrudOperationOnNonExistentNamespace('d', {_id: 0}, {});
+
assert.commandFailed(
- db.adminCommand({applyOps: [{"op": "i", "ns": t.getFullName(), "o": {_id: 5, x: 17}}]}),
- "Applying an insert operation on a non-existent collection should fail");
+ db.adminCommand({
+ applyOps: [{
+ "op": "c",
+ "ns": "admin.$cmd",
+ "o": {applyOps: [{"op": "i", "ns": t.getFullName(), "o": {_id: 5, x: 17}}]}
+ }]
+ }),
+ "Applying a nested insert operation on a non-existent collection should fail");
assert.commandWorked(db.createCollection(t.getName()));
var a = assert.commandWorked(
diff --git a/jstests/core/apply_ops_atomicity.js b/jstests/core/apply_ops_atomicity.js
index 911ce32a311..e704815a889 100644
--- a/jstests/core/apply_ops_atomicity.js
+++ b/jstests/core/apply_ops_atomicity.js
@@ -29,10 +29,12 @@
var newDBName = "apply_ops_atomicity";
var newDB = db.getSiblingDB(newDBName);
assert.commandWorked(newDB.dropDatabase());
- // Do an update on a non-existent database, since only 'u' ops can implicitly create
- // collections.
- assert.commandWorked(newDB.runCommand(
- {applyOps: [{op: "u", ns: newDBName + ".foo", o: {_id: 5, x: 17}, o2: {_id: 5, x: 16}}]}));
+ // Updates on a non-existent database no longer implicitly create collections and will fail with
+ // a NamespaceNotFound error.
+ assert.commandFailedWithCode(newDB.runCommand({
+ applyOps: [{op: "u", ns: newDBName + ".foo", o: {_id: 5, x: 17}, o2: {_id: 5, x: 16}}]
+ }),
+ ErrorCodes.NamespaceNotFound);
var sawTooManyLocksError = false;
diff --git a/jstests/core/autocomplete.js b/jstests/core/autocomplete.js
new file mode 100644
index 00000000000..6eb6e21a7a3
--- /dev/null
+++ b/jstests/core/autocomplete.js
@@ -0,0 +1,42 @@
+/**
+ * Validate auto complete works for various javascript types implemented by C++.
+ */
+(function() {
+ 'use strict';
+
+ function testAutoComplete(prefix) {
+ // This method updates a global object with an array of strings on success.
+ shellAutocomplete(prefix);
+ return __autocomplete__;
+ }
+
+ // Create a collection
+ db.auto_complete_coll.insert({});
+
+ // Validate DB auto completion
+ const db_stuff = testAutoComplete('db.');
+
+ // Verify we enumerate built-in methods
+ assert.contains('db.prototype', db_stuff);
+ assert.contains('db.hasOwnProperty', db_stuff);
+ assert.contains('db.toString(', db_stuff);
+
+ // Verify we have some methods we added
+ assert.contains('db.adminCommand(', db_stuff);
+ assert.contains('db.runCommand(', db_stuff);
+
+ // Verify we enumerate collections
+ assert.contains('db.auto_complete_coll', db_stuff);
+
+ // Validate Collection autocompletion
+ const coll_stuff = testAutoComplete('db.auto_complete_coll.');
+
+ // Verify we enumerate built-in methods
+ assert.contains('db.auto_complete_coll.prototype', coll_stuff);
+ assert.contains('db.auto_complete_coll.hasOwnProperty', coll_stuff);
+ assert.contains('db.auto_complete_coll.toString(', coll_stuff);
+
+ // Verify we have some methods we added
+ assert.contains('db.auto_complete_coll.aggregate(', coll_stuff);
+ assert.contains('db.auto_complete_coll.runCommand(', coll_stuff);
+})(); \ No newline at end of file
diff --git a/jstests/core/batch_write_command_delete.js b/jstests/core/batch_write_command_delete.js
index 2aefcea6a7f..99b5f8e3a61 100644
--- a/jstests/core/batch_write_command_delete.js
+++ b/jstests/core/batch_write_command_delete.js
@@ -1,3 +1,5 @@
+// @tags: [assumes_write_concern_unchanged]
+
//
// Ensures that mongod respects the batch write protocols for delete
//
diff --git a/jstests/core/batch_write_command_insert.js b/jstests/core/batch_write_command_insert.js
index 274f35513e7..3fa6cf98756 100644
--- a/jstests/core/batch_write_command_insert.js
+++ b/jstests/core/batch_write_command_insert.js
@@ -1,3 +1,5 @@
+// @tags: [assumes_write_concern_unchanged]
+
//
// Ensures that mongod respects the batch write protocol for inserts
//
diff --git a/jstests/core/batch_write_command_update.js b/jstests/core/batch_write_command_update.js
index 2d9d2d699b2..987525e2515 100644
--- a/jstests/core/batch_write_command_update.js
+++ b/jstests/core/batch_write_command_update.js
@@ -1,3 +1,5 @@
+// @tags: [assumes_write_concern_unchanged]
+
//
// Ensures that mongod respects the batch write protocols for updates
//
diff --git a/jstests/core/bypass_doc_validation.js b/jstests/core/bypass_doc_validation.js
index d9bca81ab6d..c2cdfff0bc9 100644
--- a/jstests/core/bypass_doc_validation.js
+++ b/jstests/core/bypass_doc_validation.js
@@ -1,5 +1,7 @@
// Test the bypassDocumentValidation flag with some database commands. The test uses relevant shell
// helpers when they're available for the respective server commands.
+//
+// @tags: [requires_collmod_command]
(function() {
'use strict';
diff --git a/jstests/core/capped6.js b/jstests/core/capped6.js
index e94e7ea44e8..ca216fbe96a 100644
--- a/jstests/core/capped6.js
+++ b/jstests/core/capped6.js
@@ -1,4 +1,11 @@
// Test NamespaceDetails::cappedTruncateAfter via "captrunc" command
+//
+// @tags: [
+// # This test attempts to perform read operations on a capped collection after truncating
+// # documents using the captrunc command. The writes from the captrunc command aren't guaranteed
+// # to become visible until a later w="majority" write occurs.
+// assumes_write_concern_unchanged,
+// ]
(function() {
var coll = db.capped6;
diff --git a/jstests/core/collation_plan_cache.js b/jstests/core/collation_plan_cache.js
index 0eec77388e4..790bbbadaa6 100644
--- a/jstests/core/collation_plan_cache.js
+++ b/jstests/core/collation_plan_cache.js
@@ -1,4 +1,11 @@
// Integration testing for the plan cache and index filter commands with collation.
+//
+// @tags: [
+// # This test attempts to perform queries and introspect the server's plan cache entries. The
+// # former operation may be routed to a secondary in the replica set, whereas the latter must be
+// # routed to the primary.
+// assumes_read_preference_unchanged,
+// ]
(function() {
'use strict';
@@ -237,4 +244,4 @@
assert.eq(0,
coll.runCommand('planCacheListFilters').filters.length,
'unexpected number of plan cache filters');
-})(); \ No newline at end of file
+})();
diff --git a/jstests/core/collection_info_cache_race.js b/jstests/core/collection_info_cache_race.js
index d57fc3340db..8fcde050e99 100644
--- a/jstests/core/collection_info_cache_race.js
+++ b/jstests/core/collection_info_cache_race.js
@@ -5,9 +5,9 @@ var coll = db.collection_info_cache_race;
coll.drop();
assert.commandWorked(db.createCollection(coll.getName(), {autoIndexId: false}));
// Fails when SERVER-16502 was not fixed, due to invariant
-assert.writeOK(coll.save({_id: false}, {writeConcern: {w: 1}}));
+assert.writeOK(coll.save({_id: false}));
coll.drop();
assert.commandWorked(db.createCollection(coll.getName(), {autoIndexId: false}));
assert.eq(null, coll.findOne());
-assert.writeOK(coll.save({_id: false}, {writeConcern: {w: 1}}));
+assert.writeOK(coll.save({_id: false}));
diff --git a/jstests/core/collmod.js b/jstests/core/collmod.js
index 16f9694560c..e366041bd99 100644
--- a/jstests/core/collmod.js
+++ b/jstests/core/collmod.js
@@ -1,5 +1,7 @@
// Basic js tests for the collMod command.
// Test setting the usePowerOf2Sizes flag, and modifying TTL indexes.
+//
+// @tags: [requires_collmod_command]
function debug(x) {
// printjson( x );
diff --git a/jstests/core/collmod_bad_spec.js b/jstests/core/collmod_bad_spec.js
index ccce81fd4b1..c3d5e7a148e 100644
--- a/jstests/core/collmod_bad_spec.js
+++ b/jstests/core/collmod_bad_spec.js
@@ -2,6 +2,8 @@
//
// Tests that a collMod with a bad specification does not cause any changes, and does not crash the
// server.
+//
+// @tags: [requires_collmod_command]
(function() {
"use strict";
diff --git a/jstests/core/commands_that_do_not_write_do_not_accept_wc.js b/jstests/core/commands_that_do_not_write_do_not_accept_wc.js
index ef5f8762a42..a9c72e108a1 100644
--- a/jstests/core/commands_that_do_not_write_do_not_accept_wc.js
+++ b/jstests/core/commands_that_do_not_write_do_not_accept_wc.js
@@ -2,6 +2,8 @@
* This file tests commands that do not support write concern. It passes both valid and invalid
* writeConcern fields to commands and expects the commands to fail with a writeConcernNotSupported
* error.
+ *
+ * @tags: [assumes_write_concern_unchanged]
*/
(function() {
diff --git a/jstests/core/constructors.js b/jstests/core/constructors.js
index 9e2cd26bbe8..93842780b42 100644
--- a/jstests/core/constructors.js
+++ b/jstests/core/constructors.js
@@ -1,4 +1,6 @@
// Tests to see what validity checks are done for 10gen specific object construction
+//
+// @tags: [requires_eval_command]
// Takes a list of constructors and returns a new list with an extra entry for each constructor with
// "new" prepended
diff --git a/jstests/core/count10.js b/jstests/core/count10.js
index 2a1853c399a..453775c97f5 100644
--- a/jstests/core/count10.js
+++ b/jstests/core/count10.js
@@ -1,4 +1,11 @@
// Test that interrupting a count returns an error code.
+//
+// @tags: [
+// # This test attempts to perform a count command and find it using the currentOp command. The
+// # former operation may be routed to a secondary in the replica set, whereas the latter must be
+// # routed to the primary.
+// assumes_read_preference_unchanged,
+// ]
t = db.count10;
t.drop();
diff --git a/jstests/core/count_plan_summary.js b/jstests/core/count_plan_summary.js
index 48891d21e8e..365f289c457 100644
--- a/jstests/core/count_plan_summary.js
+++ b/jstests/core/count_plan_summary.js
@@ -1,5 +1,11 @@
-// Test that the plan summary string appears in db.currentOp() for
-// count operations. SERVER-14064.
+// Test that the plan summary string appears in db.currentOp() for count operations. SERVER-14064.
+//
+// @tags: [
+// # This test attempts to perform a find command and find it using the currentOp command. The
+// # former operation may be routed to a secondary in the replica set, whereas the latter must be
+// # routed to the primary.
+// assumes_read_preference_unchanged,
+// ]
var t = db.jstests_count_plan_summary;
t.drop();
diff --git a/jstests/core/crud_api.js b/jstests/core/crud_api.js
index c9dbfb40c85..d572d4b90a5 100644
--- a/jstests/core/crud_api.js
+++ b/jstests/core/crud_api.js
@@ -1,3 +1,5 @@
+// @tags: [assumes_write_concern_unchanged]
+
(function() {
"use strict";
diff --git a/jstests/core/diagdata.js b/jstests/core/diagdata.js
index 490e4a3eb2b..6938f8c5102 100644
--- a/jstests/core/diagdata.js
+++ b/jstests/core/diagdata.js
@@ -1,4 +1,5 @@
// Test that verifies getDiagnosticData returns FTDC data
+load('jstests/libs/ftdc.js');
(function() {
"use strict";
@@ -6,28 +7,5 @@
// Verify we require admin database
assert.commandFailed(db.diagdata.runCommand("getDiagnosticData"));
- // We need to retry a few times if run this test immediately after mongod is started as FTDC may
- // not have run yet.
- var foundGoodDocument = false;
-
- for (var i = 0; i < 60; ++i) {
- var result = db.adminCommand("getDiagnosticData");
- assert.commandWorked(result);
-
- var data = result.data;
-
- if (!data.hasOwnProperty("start")) {
- // Wait a little longer for FTDC to start
- sleep(500);
- } else {
- // Check for a few common properties to ensure we got data
- assert(data.hasOwnProperty("serverStatus"),
- "does not have 'serverStatus' in '" + tojson(data) + "'");
- assert(data.hasOwnProperty("end"), "does not have 'end' in '" + tojson(data) + "'");
- foundGoodDocument = true;
- }
- }
- assert(foundGoodDocument,
- "getDiagnosticData failed to return a non-empty command, is FTDC running?");
-
+ verifyGetDiagnosticData(db.getSiblingDB('admin'));
})();
diff --git a/jstests/core/doc_validation.js b/jstests/core/doc_validation.js
index a30763869e7..95dbae1b219 100644
--- a/jstests/core/doc_validation.js
+++ b/jstests/core/doc_validation.js
@@ -1,4 +1,6 @@
// Test basic inserts and updates with document validation.
+//
+// @tags: [requires_collmod_command]
(function() {
"use strict";
diff --git a/jstests/core/doc_validation_invalid_validators.js b/jstests/core/doc_validation_invalid_validators.js
index b78b31c0977..70262f5de43 100644
--- a/jstests/core/doc_validation_invalid_validators.js
+++ b/jstests/core/doc_validation_invalid_validators.js
@@ -1,5 +1,7 @@
// Verify invalid validator statements won't work and that we
// can't create validated collections on restricted databases.
+//
+// @tags: [requires_collmod_command]
(function() {
"use strict";
diff --git a/jstests/core/doc_validation_options.js b/jstests/core/doc_validation_options.js
index 8a96685e48f..d1434af6d45 100644
--- a/jstests/core/doc_validation_options.js
+++ b/jstests/core/doc_validation_options.js
@@ -1,3 +1,4 @@
+// @tags: [requires_collmod_command]
(function() {
"use strict";
diff --git a/jstests/core/dropdb_race.js b/jstests/core/dropdb_race.js
index bd5e7e5ddba..d8b49d08174 100644
--- a/jstests/core/dropdb_race.js
+++ b/jstests/core/dropdb_race.js
@@ -1,4 +1,6 @@
// test dropping a db with simultaneous commits
+//
+// @tags: [assumes_write_concern_unchanged]
m = db.getMongo();
baseName = "jstests_dur_droprace";
diff --git a/jstests/core/elemMatchProjection.js b/jstests/core/elemMatchProjection.js
index 4e80e8a296e..5060d8a6346 100644
--- a/jstests/core/elemMatchProjection.js
+++ b/jstests/core/elemMatchProjection.js
@@ -4,35 +4,59 @@ t.drop();
date1 = new Date();
+// Generate monotonically increasing _id values. ObjectIds generated by the shell are not guaranteed
+// to be monotically increasing, and we will depend on the _id sort order later in the test.
+var currentId = 0;
+function nextId() {
+ return ++currentId;
+}
+
// Insert various styles of arrays
for (i = 0; i < 100; i++) {
- t.insert({group: 1, x: [1, 2, 3, 4, 5]});
- t.insert({group: 2, x: [{a: 1, b: 2}, {a: 2, c: 3}, {a: 1, d: 5}]});
+ t.insert({_id: nextId(), group: 1, x: [1, 2, 3, 4, 5]});
+ t.insert({_id: nextId(), group: 2, x: [{a: 1, b: 2}, {a: 2, c: 3}, {a: 1, d: 5}]});
t.insert({
+ _id: nextId(),
group: 3,
x: [{a: 1, b: 2}, {a: 2, c: 3}, {a: 1, d: 5}],
y: [{aa: 1, bb: 2}, {aa: 2, cc: 3}, {aa: 1, dd: 5}]
});
- t.insert({group: 3, x: [{a: 1, b: 3}, {a: -6, c: 3}]});
- t.insert({group: 4, x: [{a: 1, b: 4}, {a: -6, c: 3}]});
- t.insert({group: 5, x: [new Date(), 5, 10, 'string', new ObjectId(), 123.456]});
+ t.insert({_id: nextId(), group: 3, x: [{a: 1, b: 3}, {a: -6, c: 3}]});
+ t.insert({_id: nextId(), group: 4, x: [{a: 1, b: 4}, {a: -6, c: 3}]});
+ t.insert({_id: nextId(), group: 5, x: [new Date(), 5, 10, 'string', new ObjectId(), 123.456]});
t.insert({
+ _id: nextId(),
group: 6,
x: [{a: 'string', b: date1}, {a: new ObjectId(), b: 1.2345}, {a: 'string2', b: date1}]
});
- t.insert({group: 7, x: [{y: [1, 2, 3, 4]}]});
- t.insert({group: 8, x: [{y: [{a: 1, b: 2}, {a: 3, b: 4}]}]});
- t.insert({group: 9, x: [{y: [{a: 1, b: 2}, {a: 3, b: 4}]}, {z: [{a: 1, b: 2}, {a: 3, b: 4}]}]});
- t.insert({group: 10, x: [{a: 1, b: 2}, {a: 3, b: 4}], y: [{c: 1, d: 2}, {c: 3, d: 4}]});
- t.insert({group: 10, x: [{a: 1, b: 2}, {a: 3, b: 4}], y: [{c: 1, d: 2}, {c: 3, d: 4}]});
+ t.insert({_id: nextId(), group: 7, x: [{y: [1, 2, 3, 4]}]});
+ t.insert({_id: nextId(), group: 8, x: [{y: [{a: 1, b: 2}, {a: 3, b: 4}]}]});
+ t.insert({
+ _id: nextId(),
+ group: 9,
+ x: [{y: [{a: 1, b: 2}, {a: 3, b: 4}]}, {z: [{a: 1, b: 2}, {a: 3, b: 4}]}]
+ });
+ t.insert({
+ _id: nextId(),
+ group: 10,
+ x: [{a: 1, b: 2}, {a: 3, b: 4}],
+ y: [{c: 1, d: 2}, {c: 3, d: 4}]
+ });
+ t.insert({
+ _id: nextId(),
+ group: 10,
+ x: [{a: 1, b: 2}, {a: 3, b: 4}],
+ y: [{c: 1, d: 2}, {c: 3, d: 4}]
+ });
t.insert({
+ _id: nextId(),
group: 11,
x: [{a: 1, b: 2}, {a: 2, c: 3}, {a: 1, d: 5}],
covered: [{aa: 1, bb: 2}, {aa: 2, cc: 3}, {aa: 1, dd: 5}]
});
- t.insert({group: 12, x: {y: [{a: 1, b: 1}, {a: 1, b: 2}]}});
- t.insert({group: 13, x: [{a: 1, b: 1}, {a: 1, b: 2}]});
- t.insert({group: 13, x: [{a: 1, b: 2}, {a: 1, b: 1}]});
+ t.insert({_id: nextId(), group: 12, x: {y: [{a: 1, b: 1}, {a: 1, b: 2}]}});
+ t.insert({_id: nextId(), group: 13, x: [{a: 1, b: 1}, {a: 1, b: 2}]});
+ t.insert({_id: nextId(), group: 13, x: [{a: 1, b: 2}, {a: 1, b: 1}]});
}
t.ensureIndex({
group: 1,
diff --git a/jstests/core/error2.js b/jstests/core/error2.js
index 6f0b95bc17e..fb6a8e6e3b2 100644
--- a/jstests/core/error2.js
+++ b/jstests/core/error2.js
@@ -1,4 +1,5 @@
// Test that client gets stack trace on failed invoke
+// @tags: [requires_eval_command]
f = db.jstests_error2;
diff --git a/jstests/core/eval0.js b/jstests/core/eval0.js
index 5802f2597cb..c21c6be66c6 100644
--- a/jstests/core/eval0.js
+++ b/jstests/core/eval0.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
assert.writeOK(db.evalprep.insert({}), "db must exist for eval to succeed");
db.evalprep.drop();
assert.eq(17,
diff --git a/jstests/core/eval1.js b/jstests/core/eval1.js
index 8b139cae02a..b5bffac892e 100644
--- a/jstests/core/eval1.js
+++ b/jstests/core/eval1.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.eval1;
t.drop();
diff --git a/jstests/core/eval3.js b/jstests/core/eval3.js
index c4f8be21056..b95837a6817 100644
--- a/jstests/core/eval3.js
+++ b/jstests/core/eval3.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.eval3;
t.drop();
diff --git a/jstests/core/eval4.js b/jstests/core/eval4.js
index 0d120b393de..9b0c2a49d82 100644
--- a/jstests/core/eval4.js
+++ b/jstests/core/eval4.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.eval4;
t.drop();
diff --git a/jstests/core/eval5.js b/jstests/core/eval5.js
index 46bd679dd77..815365ac8b9 100644
--- a/jstests/core/eval5.js
+++ b/jstests/core/eval5.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.eval5;
t.drop();
diff --git a/jstests/core/eval6.js b/jstests/core/eval6.js
index 31258f6917b..96b43b3516c 100644
--- a/jstests/core/eval6.js
+++ b/jstests/core/eval6.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.eval6;
t.drop();
diff --git a/jstests/core/eval7.js b/jstests/core/eval7.js
index 80197fcdde6..3bace093db1 100644
--- a/jstests/core/eval7.js
+++ b/jstests/core/eval7.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
assert.writeOK(db.evalprep.insert({}), "db must exist for eval to succeed");
db.evalprep.drop();
diff --git a/jstests/core/eval9.js b/jstests/core/eval9.js
index 1480ff6519c..82c230a8a95 100644
--- a/jstests/core/eval9.js
+++ b/jstests/core/eval9.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
assert.writeOK(db.evalprep.insert({}), "db must exist for eval to succeed");
db.evalprep.drop();
diff --git a/jstests/core/eval_mr.js b/jstests/core/eval_mr.js
index 4a3dc8dad6c..33ca96eea01 100644
--- a/jstests/core/eval_mr.js
+++ b/jstests/core/eval_mr.js
@@ -1,4 +1,6 @@
// Test that the eval command can't be used to invoke the mapReduce command. SERVER-17889.
+//
+// @tags: [requires_eval_command]
(function() {
"use strict";
db.eval_mr.drop();
diff --git a/jstests/core/eval_nolock.js b/jstests/core/eval_nolock.js
index 9511784becb..0fde2666f5d 100644
--- a/jstests/core/eval_nolock.js
+++ b/jstests/core/eval_nolock.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.eval_nolock;
t.drop();
diff --git a/jstests/core/evala.js b/jstests/core/evala.js
index 7ccf33ac754..09241eeedee 100644
--- a/jstests/core/evala.js
+++ b/jstests/core/evala.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.evala;
t.drop();
diff --git a/jstests/core/evalb.js b/jstests/core/evalb.js
index 3391c4cc4f2..2de16f4ea83 100644
--- a/jstests/core/evalb.js
+++ b/jstests/core/evalb.js
@@ -1,5 +1,7 @@
// Check the return value of a db.eval function running a database query, and ensure the function's
// contents are logged in the profile log.
+//
+// @tags: [requires_eval_command]
// Use a reserved database name to avoid a conflict in the parallel test suite.
var stddb = db;
diff --git a/jstests/core/evald.js b/jstests/core/evald.js
index 8049d2ba8ae..43e74fc4600 100644
--- a/jstests/core/evald.js
+++ b/jstests/core/evald.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
t = db.jstests_evald;
t.drop();
diff --git a/jstests/core/evale.js b/jstests/core/evale.js
index 1ddc8519fc6..20384e0d741 100644
--- a/jstests/core/evale.js
+++ b/jstests/core/evale.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
t = db.jstests_evale;
t.drop();
diff --git a/jstests/core/evalg.js b/jstests/core/evalg.js
index 18503659217..56cb1dedd5f 100644
--- a/jstests/core/evalg.js
+++ b/jstests/core/evalg.js
@@ -1,4 +1,6 @@
// SERVER-17499: Test behavior of getMore on aggregation cursor under eval command.
+//
+// @tags: [requires_eval_command]
db.evalg.drop();
for (var i = 0; i < 102; ++i) {
db.evalg.insert({});
diff --git a/jstests/core/evalh.js b/jstests/core/evalh.js
index 11e672f6bf4..b9c0d486d59 100644
--- a/jstests/core/evalh.js
+++ b/jstests/core/evalh.js
@@ -1,5 +1,7 @@
/**
* Test that db.eval does not support auth.
+ *
+ * @tags: [requires_eval_command]
*/
(function() {
'use strict';
diff --git a/jstests/core/evalj.js b/jstests/core/evalj.js
index f2326fff365..d6ef46430de 100644
--- a/jstests/core/evalj.js
+++ b/jstests/core/evalj.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
(function() {
"use strict";
diff --git a/jstests/core/existsa.js b/jstests/core/existsa.js
index e9430b489a3..d98fd3f2d68 100644
--- a/jstests/core/existsa.js
+++ b/jstests/core/existsa.js
@@ -1,101 +1,111 @@
-// Sparse indexes are disallowed for $exists:false queries. SERVER-3918
-
-t = db.jstests_existsa;
-t.drop();
-
-t.save({});
-t.save({a: 1});
-t.save({a: {x: 1}, b: 1});
-
-/** Configure testing of an index { <indexKeyField>:1 }. */
-function setIndex(_indexKeyField) {
- indexKeyField = _indexKeyField;
- indexKeySpec = {};
- indexKeySpec[indexKeyField] = 1;
- t.ensureIndex(indexKeySpec, {sparse: true});
-}
-setIndex('a');
-
-/** @return count when hinting the index to use. */
-function hintedCount(query) {
- return t.find(query).hint(indexKeySpec).itcount();
-}
-
-/** The query field does not exist and the sparse index is not used without a hint. */
-function assertMissing(query, expectedMissing, expectedIndexedMissing) {
- expectedMissing = expectedMissing || 1;
- expectedIndexedMissing = expectedIndexedMissing || 0;
- assert.eq(expectedMissing, t.count(query));
- // We also shouldn't get a different count depending on whether
- // an index is used or not.
- assert.eq(expectedIndexedMissing, hintedCount(query));
-}
-
-/** The query field exists and the sparse index is used without a hint. */
-function assertExists(query, expectedExists) {
- expectedExists = expectedExists || 2;
- assert.eq(expectedExists, t.count(query));
- // An $exists:true predicate generates no index filters. Add another predicate on the index key
- // to trigger use of the index.
- andClause = {};
- andClause[indexKeyField] = {$ne: null};
- Object.extend(query, {$and: [andClause]});
- assert.eq(expectedExists, t.count(query));
- assert.eq(expectedExists, hintedCount(query));
-}
-
-/** The query field exists and the sparse index is not used without a hint. */
-function assertExistsUnindexed(query, expectedExists) {
- expectedExists = expectedExists || 2;
- assert.eq(expectedExists, t.count(query));
- // Even with another predicate on the index key, the sparse index is disallowed.
- andClause = {};
- andClause[indexKeyField] = {$ne: null};
- Object.extend(query, {$and: [andClause]});
- assert.eq(expectedExists, t.count(query));
- assert.eq(expectedExists, hintedCount(query));
-}
-
-// $exists:false queries match the proper number of documents and disallow the sparse index.
-assertMissing({a: {$exists: false}});
-assertMissing({a: {$not: {$exists: true}}});
-assertMissing({$and: [{a: {$exists: false}}]});
-assertMissing({$or: [{a: {$exists: false}}]});
-assertMissing({$nor: [{a: {$exists: true}}]});
-assertMissing({'a.x': {$exists: false}}, 2, 1);
-
-// Currently a sparse index is disallowed even if the $exists:false query is on a different field.
-assertMissing({b: {$exists: false}}, 2, 1);
-assertMissing({b: {$exists: false}, a: {$ne: 6}}, 2, 1);
-assertMissing({b: {$not: {$exists: true}}}, 2, 1);
-
-// Top level $exists:true queries match the proper number of documents
-// and use the sparse index on { a : 1 }.
-assertExists({a: {$exists: true}});
-
-// Nested $exists queries match the proper number of documents and disallow the sparse index.
-assertExistsUnindexed({$nor: [{a: {$exists: false}}]});
-assertExistsUnindexed({$nor: [{'a.x': {$exists: false}}]}, 1);
-assertExistsUnindexed({a: {$not: {$exists: false}}});
-
-// Nested $exists queries disallow the sparse index in some cases where it is not strictly
-// necessary to do so. (Descriptive tests.)
-assertExistsUnindexed({$nor: [{b: {$exists: false}}]}, 1); // Unindexed field.
-assertExists({$or: [{a: {$exists: true}}]}); // $exists:true not $exists:false.
-
-// Behavior is similar with $elemMatch.
-t.drop();
-t.save({a: [{}]});
-t.save({a: [{b: 1}]});
-t.save({a: [{b: 1}]});
-setIndex('a.b');
-
-assertMissing({a: {$elemMatch: {b: {$exists: false}}}});
-// A $elemMatch predicate is treated as nested, and the index should be used for $exists:true.
-assertExists({a: {$elemMatch: {b: {$exists: true}}}});
-
-// A non sparse index will not be disallowed.
-t.drop();
-t.save({});
-t.ensureIndex({a: 1});
-assert.eq(1, t.find({a: {$exists: false}}).itcount());
+/**
+ * Tests that sparse indexes are disallowed for $exists:false queries.
+ */
+(function() {
+ "use strict";
+
+ const coll = db.jstests_existsa;
+ coll.drop();
+
+ assert.writeOK(coll.insert({}));
+ assert.writeOK(coll.insert({a: 1}));
+ assert.writeOK(coll.insert({a: {x: 1}, b: 1}));
+
+ let indexKeySpec = {};
+ let indexKeyField = '';
+
+ /** Configure testing of an index { <indexKeyField>:1 }. */
+ function setIndex(_indexKeyField) {
+ indexKeyField = _indexKeyField;
+ indexKeySpec = {};
+ indexKeySpec[indexKeyField] = 1;
+ coll.ensureIndex(indexKeySpec, {sparse: true});
+ }
+ setIndex('a');
+
+ /** @return count when hinting the index to use. */
+ function hintedCount(query) {
+ return coll.find(query).hint(indexKeySpec).itcount();
+ }
+
+ /** The query field does not exist and the sparse index is not used without a hint. */
+ function assertMissing(query, expectedMissing = 1, expectedIndexedMissing = 0) {
+ assert.eq(expectedMissing, coll.count(query));
+ // We also shouldn't get a different count depending on whether
+ // an index is used or not.
+ assert.eq(expectedIndexedMissing, hintedCount(query));
+ }
+
+ /** The query field exists and the sparse index is used without a hint. */
+ function assertExists(query, expectedExists = 2) {
+ assert.eq(expectedExists, coll.count(query));
+ // An $exists:true predicate generates no index filters. Add another predicate on the index
+ // key to trigger use of the index.
+ let andClause = {};
+ andClause[indexKeyField] = {$ne: null};
+ Object.extend(query, {$and: [andClause]});
+ assert.eq(expectedExists, coll.count(query));
+ assert.eq(expectedExists, hintedCount(query));
+ }
+
+ /** The query field exists and the sparse index is not used without a hint. */
+ function assertExistsUnindexed(query, expectedExists = 2) {
+ assert.eq(expectedExists, coll.count(query));
+ // Even with another predicate on the index key, the sparse index is disallowed.
+ let andClause = {};
+ andClause[indexKeyField] = {$ne: null};
+ Object.extend(query, {$and: [andClause]});
+ assert.eq(expectedExists, coll.count(query));
+ assert.eq(expectedExists, hintedCount(query));
+ }
+
+ // $exists:false queries match the proper number of documents and disallow the sparse index.
+ assertMissing({a: {$exists: false}});
+ assertMissing({a: {$not: {$exists: true}}});
+ assertMissing({$and: [{a: {$exists: false}}]});
+ assertMissing({$or: [{a: {$exists: false}}]});
+ assertMissing({$nor: [{a: {$exists: true}}]});
+ assertMissing({'a.x': {$exists: false}}, 2, 1);
+
+ // Currently a sparse index is disallowed even if the $exists:false query is on a different
+ // field.
+ assertMissing({b: {$exists: false}}, 2, 1);
+ assertMissing({b: {$exists: false}, a: {$ne: 6}}, 2, 1);
+ assertMissing({b: {$not: {$exists: true}}}, 2, 1);
+
+ // Top level $exists:true queries match the proper number of documents
+ // and use the sparse index on { a : 1 }.
+ assertExists({a: {$exists: true}});
+
+ // Nested $exists queries match the proper number of documents and disallow the sparse index.
+ assertExistsUnindexed({$nor: [{a: {$exists: false}}]});
+ assertExistsUnindexed({$nor: [{'a.x': {$exists: false}}]}, 1);
+ assertExistsUnindexed({a: {$not: {$exists: false}}});
+
+ // Nested $exists queries disallow the sparse index in some cases where it is not strictly
+ // necessary to do so. (Descriptive tests.)
+ assertExistsUnindexed({$nor: [{b: {$exists: false}}]}, 1); // Unindexed field.
+ assertExists({$or: [{a: {$exists: true}}]}); // $exists:true not $exists:false.
+
+ // Behavior is similar with $elemMatch.
+ coll.drop();
+ assert.writeOK(coll.insert({a: [{}]}));
+ assert.writeOK(coll.insert({a: [{b: 1}]}));
+ assert.writeOK(coll.insert({a: [{b: [1]}]}));
+ setIndex('a.b');
+
+ assertMissing({a: {$elemMatch: {b: {$exists: false}}}});
+
+ // A $elemMatch predicate is treated as nested, and the index should be used for $exists:true.
+ assertExists({a: {$elemMatch: {b: {$exists: true}}}});
+
+ // A $not within $elemMatch should not attempt to use a sparse index for $exists:false.
+ assertExistsUnindexed({'a.b': {$elemMatch: {$not: {$exists: false}}}}, 1);
+ assertExistsUnindexed({'a.b': {$elemMatch: {$gt: 0, $not: {$exists: false}}}}, 1);
+
+ // A non sparse index will not be disallowed.
+ coll.drop();
+ assert.writeOK(coll.insert({}));
+ coll.ensureIndex({a: 1});
+ assert.eq(1, coll.find({a: {$exists: false}}).itcount());
+})();
diff --git a/jstests/core/fsync.js b/jstests/core/fsync.js
index 13ff20e4177..2ad625d88ba 100644
--- a/jstests/core/fsync.js
+++ b/jstests/core/fsync.js
@@ -6,6 +6,8 @@
* - Confirm that writes can progress after fsyncUnlock
* - Confirm that the command can be run repeatedly without breaking things
* - Confirm that the pseudo commands and eval can perform fsyncLock/Unlock
+ *
+ * @tags: [requires_eval_command]
*/
(function() {
"use strict";
diff --git a/jstests/core/fts_dotted_prefix_fields.js b/jstests/core/fts_dotted_prefix_fields.js
new file mode 100644
index 00000000000..f811c4a7203
--- /dev/null
+++ b/jstests/core/fts_dotted_prefix_fields.js
@@ -0,0 +1,15 @@
+// Test that text search works correct when the text index has dotted paths as the non-text
+// prefixes.
+(function() {
+ "use strict";
+
+ let coll = db.fts_dotted_prefix_fields;
+ coll.drop();
+ assert.commandWorked(coll.createIndex({"a.x": 1, "a.y": 1, "b.x": 1, "b.y": 1, words: "text"}));
+ assert.writeOK(coll.insert({a: {x: 1, y: 2}, b: {x: 3, y: 4}, words: "lorem ipsum dolor sit"}));
+ assert.writeOK(coll.insert({a: {x: 1, y: 2}, b: {x: 5, y: 4}, words: "lorem ipsum dolor sit"}));
+
+ assert.eq(1,
+ coll.find({$text: {$search: "lorem ipsum"}, "a.x": 1, "a.y": 2, "b.x": 3, "b.y": 4})
+ .itcount());
+}());
diff --git a/jstests/core/fts_trailing_fields.js b/jstests/core/fts_trailing_fields.js
new file mode 100644
index 00000000000..2c7f79b423d
--- /dev/null
+++ b/jstests/core/fts_trailing_fields.js
@@ -0,0 +1,22 @@
+// Tests for predicates which can use the trailing field of a text index.
+(function() {
+ "use strict";
+
+ const coll = db.fts_trailing_fields;
+
+ coll.drop();
+ assert.commandWorked(coll.createIndex({a: 1, b: "text", c: 1}));
+ assert.writeOK(coll.insert({a: 2, b: "lorem ipsum"}));
+
+ assert.eq(0, coll.find({a: 2, $text: {$search: "lorem"}, c: {$exists: true}}).itcount());
+ assert.eq(1, coll.find({a: 2, $text: {$search: "lorem"}, c: null}).itcount());
+ assert.eq(1, coll.find({a: 2, $text: {$search: "lorem"}, c: {$exists: false}}).itcount());
+
+ // An equality predicate on the leading field isn't useful, but it shouldn't cause any problems.
+ // Same with an $elemMatch predicate on one of the trailing fields.
+ coll.drop();
+ assert.commandWorked(coll.createIndex({a: 1, b: "text", "c.d": 1}));
+ assert.writeOK(coll.insert({a: 2, b: "lorem ipsum", c: {d: 3}}));
+ assert.eq(0, coll.find({a: [1, 2], $text: {$search: "lorem"}}).itcount());
+ assert.eq(0, coll.find({a: 2, $text: {$search: "lorem"}, c: {$elemMatch: {d: 3}}}).itcount());
+}());
diff --git a/jstests/core/function_string_representations.js b/jstests/core/function_string_representations.js
new file mode 100644
index 00000000000..af66e9160a9
--- /dev/null
+++ b/jstests/core/function_string_representations.js
@@ -0,0 +1,38 @@
+/** Demonstrate that mapReduce can accept functions represented by strings.
+ * Some drivers do not have a type which represents a Javascript function. These languages represent
+ * the arguments to mapReduce as strings.
+ */
+
+(function() {
+ "use strict";
+
+ var col = db.function_string_representations;
+ col.drop();
+ assert.writeOK(col.insert({
+ _id: "abc123",
+ ord_date: new Date("Oct 04, 2012"),
+ status: 'A',
+ price: 25,
+ items: [{sku: "mmm", qty: 5, price: 2.5}, {sku: "nnn", qty: 5, price: 2.5}]
+ }));
+
+ var mapFunction = "function() {emit(this._id, this.price);}";
+ var reduceFunction = "function(keyCustId, valuesPrices) {return Array.sum(valuesPrices);}";
+ assert.commandWorked(col.mapReduce(mapFunction, reduceFunction, {out: "map_reduce_example"}));
+
+ // Provided strings may end with semicolons and/or whitespace
+ mapFunction += " ; ";
+ reduceFunction += " ; ";
+ assert.commandWorked(col.mapReduce(mapFunction, reduceFunction, {out: "map_reduce_example"}));
+
+ // $where exhibits the same behavior
+ var whereFunction = "function() {return this.price === 25;}";
+ assert.eq(1, col.find({$where: whereFunction}).itcount());
+
+ whereFunction += ";";
+ assert.eq(1, col.find({$where: whereFunction}).itcount());
+
+ // db.eval does not need to be tested, as it accepts code fragments, not functions.
+ // system.js does not need to be tested, as its contents types' are preserved, and
+ // strings are not promoted into functions.
+})();
diff --git a/jstests/core/geo_2d_trailing_fields.js b/jstests/core/geo_2d_trailing_fields.js
new file mode 100644
index 00000000000..8f9c881ae4c
--- /dev/null
+++ b/jstests/core/geo_2d_trailing_fields.js
@@ -0,0 +1,45 @@
+// Tests for predicates which can use the trailing field of a 2d index.
+(function() {
+ "use strict";
+
+ const coll = db.geo_2d_trailing_fields;
+
+ const isMaster = assert.commandWorked(db.adminCommand({isMaster: 1}));
+ const isMongos = (isMaster.msg === "isdbgrid");
+
+ coll.drop();
+ assert.commandWorked(coll.createIndex({a: "2d", b: 1}));
+ assert.writeOK(coll.insert({a: [0, 0]}));
+
+ // Verify that $near queries handle existence predicates over the trailing fields correctly.
+ if (!isMongos) {
+ assert.eq(0, coll.find({a: {$near: [0, 0]}, b: {$exists: true}}).itcount());
+ assert.eq(1, coll.find({a: {$near: [0, 0]}, b: null}).itcount());
+ assert.eq(1, coll.find({a: {$near: [0, 0]}, b: {$exists: false}}).itcount());
+ }
+
+ // Verify that non-near 2d queries handle existence predicates over the trailing fields
+ // correctly.
+ assert.eq(0,
+ coll.find({a: {$geoWithin: {$center: [[0, 0], 1]}}, b: {$exists: true}}).itcount());
+ assert.eq(1, coll.find({a: {$geoWithin: {$center: [[0, 0], 1]}}, b: null}).itcount());
+ assert.eq(1,
+ coll.find({a: {$geoWithin: {$center: [[0, 0], 1]}}, b: {$exists: false}}).itcount());
+
+ coll.drop();
+ assert.commandWorked(coll.createIndex({a: "2d", "b.c": 1}));
+ assert.writeOK(coll.insert({a: [0, 0], b: [{c: 2}, {c: 3}]}));
+
+ // Verify that $near queries correctly handle predicates which cannot be covered due to array
+ // semantics.
+ if (!isMongos) {
+ assert.eq(0, coll.find({a: {$near: [0, 0]}, "b.c": [2, 3]}).itcount());
+ assert.eq(0, coll.find({a: {$near: [0, 0]}, "b.c": {$type: "array"}}).itcount());
+ }
+
+ // Verify that non-near 2d queries correctly handle predicates which cannot be covered due to
+ // array semantics.
+ assert.eq(0, coll.find({a: {$geoWithin: {$center: [[0, 0], 1]}}, "b.c": [2, 3]}).itcount());
+ assert.eq(
+ 0, coll.find({a: {$geoWithin: {$center: [[0, 0], 1]}}, "b.c": {$type: "array"}}).itcount());
+}());
diff --git a/jstests/core/geo_s2cursorlimitskip.js b/jstests/core/geo_s2cursorlimitskip.js
index 427fbf8fe29..dc645dc68af 100644
--- a/jstests/core/geo_s2cursorlimitskip.js
+++ b/jstests/core/geo_s2cursorlimitskip.js
@@ -1,4 +1,11 @@
// Test various cursor behaviors
+//
+// @tags: [
+// # This test attempts to enable profiling on a server and then get profiling data by reading
+// # from the "system.profile" collection. The former operation must be routed to the primary in
+// # a replica set, whereas the latter may be routed to a secondary.
+// assumes_read_preference_unchanged,
+// ]
var testDB = db.getSiblingDB("geo_s2cursorlimitskip");
var t = testDB.geo_s2getmmm;
diff --git a/jstests/core/geo_update_btree.js b/jstests/core/geo_update_btree.js
index a85d4274415..b4fa24df57e 100644
--- a/jstests/core/geo_update_btree.js
+++ b/jstests/core/geo_update_btree.js
@@ -1,4 +1,6 @@
// Tests whether the geospatial search is stable under btree updates
+//
+// @tags: [assumes_write_concern_unchanged]
var coll = db.getCollection("jstests_geo_update_btree");
coll.drop();
diff --git a/jstests/core/getlog2.js b/jstests/core/getlog2.js
index 597a85e20ee..e5287ea8c1b 100644
--- a/jstests/core/getlog2.js
+++ b/jstests/core/getlog2.js
@@ -1,4 +1,11 @@
// tests getlog as well as slow querying logging
+//
+// @tags: [
+// # This test attempts to perform a find command and see that it ran using the getLog command.
+// # The former operation may be routed to a secondary in the replica set, whereas the latter must
+// # be routed to the primary.
+// assumes_read_preference_unchanged,
+// ]
glcol = db.getLogTest2;
glcol.drop();
diff --git a/jstests/core/index_elemmatch2.js b/jstests/core/index_elemmatch2.js
new file mode 100644
index 00000000000..ecd24035284
--- /dev/null
+++ b/jstests/core/index_elemmatch2.js
@@ -0,0 +1,63 @@
+/**
+ * Test that queries containing $elemMatch correctly use an index if each child expression is
+ * compatible with the index.
+ */
+(function() {
+ "use strict";
+
+ load("jstests/libs/analyze_plan.js");
+
+ const coll = db.elemMatch_index;
+ coll.drop();
+
+ assert.writeOK(coll.insert({a: 1}));
+ assert.writeOK(coll.insert({a: [{}]}));
+ assert.writeOK(coll.insert({a: [1, null]}));
+ assert.writeOK(coll.insert({a: [{type: "Point", coordinates: [0, 0]}]}));
+
+ assert.commandWorked(coll.createIndex({a: 1}, {sparse: true}));
+
+ function assertIndexResults(coll, query, useIndex, nReturned) {
+ const explainPlan = coll.find(query).explain("executionStats");
+ assert.eq(isIxscan(explainPlan.queryPlanner.winningPlan), useIndex);
+ assert.eq(explainPlan.executionStats.nReturned, nReturned);
+ }
+
+ assertIndexResults(coll, {a: {$elemMatch: {$exists: false}}}, false, 0);
+
+ // An $elemMatch predicate is treated as nested, and the index should be used for $exists:true.
+ assertIndexResults(coll, {a: {$elemMatch: {$exists: true}}}, true, 3);
+
+ // $not within $elemMatch should not attempt to use a sparse index for $exists:false.
+ assertIndexResults(coll, {a: {$elemMatch: {$not: {$exists: false}}}}, false, 3);
+ assertIndexResults(coll, {a: {$elemMatch: {$gt: 0, $not: {$exists: false}}}}, false, 1);
+
+ // $geo within $elemMatch should not attempt to use a non-geo index.
+ assertIndexResults(
+ coll,
+ {
+ a: {
+ $elemMatch: {
+ $geoWithin: {
+ $geometry:
+ {type: "Polygon", coordinates: [[[0, 0], [0, 1], [1, 0], [0, 0]]]}
+ }
+ }
+ }
+ },
+ false,
+ 1);
+
+ // $in with a null value within $elemMatch should use a sparse index.
+ assertIndexResults(coll, {a: {$elemMatch: {$in: [null]}}}, true, 1);
+
+ // $eq with a null value within $elemMatch should use a sparse index.
+ assertIndexResults(coll, {a: {$elemMatch: {$eq: null}}}, true, 1);
+
+ // A negated regex within $elemMatch should not use an index, sparse or not.
+ assertIndexResults(coll, {a: {$elemMatch: {$not: {$in: [/^a/]}}}}, false, 3);
+
+ coll.dropIndexes();
+ assert.commandWorked(coll.createIndex({a: 1}));
+ assertIndexResults(coll, {a: {$elemMatch: {$not: {$in: [/^a/]}}}}, false, 3);
+})();
diff --git a/jstests/core/index_filter_commands.js b/jstests/core/index_filter_commands.js
index 8684be3b2b9..58f78d0514e 100644
--- a/jstests/core/index_filter_commands.js
+++ b/jstests/core/index_filter_commands.js
@@ -6,20 +6,24 @@
* Displays index filters for all query shapes in a collection.
*
* - planCacheClearFilters
- * Clears index filter for a single query shape or,
- * if the query shape is omitted, all filters for the collection.
+ * Clears index filter for a single query shape or, if the query shape is omitted, all filters for
+ * the collection.
*
* - planCacheSetFilter
* Sets index filter for a query shape. Overrides existing filter.
*
- * Not a lot of data access in this test suite. Hint commands
- * manage a non-persistent mapping in the server of
- * query shape to list of index specs.
+ * Not a lot of data access in this test suite. Hint commands manage a non-persistent mapping in the
+ * server of query shape to list of index specs.
*
- * Only time we might need to execute a query is to check the plan
- * cache state. We would do this with the planCacheListPlans command
- * on the same query shape with the index filters.
+ * Only time we might need to execute a query is to check the plan cache state. We would do this
+ * with the planCacheListPlans command on the same query shape with the index filters.
*
+ * @tags: [
+ * # This test attempts to perform queries with plan cache filters set up. The former operation
+ * # may be routed to a secondary in the replica set, whereas the latter must be routed to the
+ * # primary.
+ * assumes_read_preference_unchanged,
+ * ]
*/
load("jstests/libs/analyze_plan.js");
diff --git a/jstests/core/index_stats.js b/jstests/core/index_stats.js
index 60b37fd571e..ee4d13d4d0a 100644
--- a/jstests/core/index_stats.js
+++ b/jstests/core/index_stats.js
@@ -1,3 +1,10 @@
+// @tags: [
+// # This test attempts to perform write operations and get index usage statistics using the
+// # $indexStats stage. The former operation must be routed to the primary in a replica set,
+// # whereas the latter may be routed to a secondary.
+// assumes_read_preference_unchanged,
+// ]
+
(function() {
"use strict";
diff --git a/jstests/core/js3.js b/jstests/core/js3.js
index 4d46c25bbf7..c808e7ec75a 100644
--- a/jstests/core/js3.js
+++ b/jstests/core/js3.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.jstests_js3;
diff --git a/jstests/core/js7.js b/jstests/core/js7.js
index 810f4692d4f..99cddd114f8 100644
--- a/jstests/core/js7.js
+++ b/jstests/core/js7.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
t = db.jstests_js7;
t.drop();
diff --git a/jstests/core/js9.js b/jstests/core/js9.js
index 515fa883aea..e0703ac39ea 100644
--- a/jstests/core/js9.js
+++ b/jstests/core/js9.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
c = db.jstests_js9;
c.drop();
diff --git a/jstests/core/js_jit.js b/jstests/core/js_jit.js
new file mode 100644
index 00000000000..4ccdd2917ae
--- /dev/null
+++ b/jstests/core/js_jit.js
@@ -0,0 +1,40 @@
+/**
+ * Validate various native types continue to work when run in JITed code.
+ *
+ * In SERVER-30362, the JIT would not compile natives types which had custom getProperty
+ * implementations correctly. We force the JIT to kick in by using large loops.
+ */
+(function() {
+ 'use strict';
+
+ function testDBCollection() {
+ const c = new DBCollection(null, null, "foo", "test.foo");
+ for (let i = 0; i < 100000; i++) {
+ if (c.toString() != "test.foo") {
+ throw i;
+ }
+ }
+ }
+
+ function testDB() {
+ const c = new DB(null, "test");
+ for (let i = 0; i < 100000; i++) {
+ if (c.toString() != "test") {
+ throw i;
+ }
+ }
+ }
+
+ function testDBQuery() {
+ const c = DBQuery('a', 'b', 'c', 'd');
+ for (let i = 0; i < 100000; i++) {
+ if (c.toString() != "DBQuery: d -> null") {
+ throw i;
+ }
+ }
+ }
+
+ testDBCollection();
+ testDB();
+ testDBQuery();
+})(); \ No newline at end of file
diff --git a/jstests/core/list_collections1.js b/jstests/core/list_collections1.js
index c8c3f92fbc9..ff1aac304ff 100644
--- a/jstests/core/list_collections1.js
+++ b/jstests/core/list_collections1.js
@@ -72,8 +72,8 @@
//
var getListCollectionsCursor = function(options, subsequentBatchSize) {
- return new DBCommandCursor(
- mydb.getMongo(), mydb.runCommand("listCollections", options), subsequentBatchSize);
+ var res = mydb.runCommand("listCollections", options);
+ return new DBCommandCursor(res._mongo, res, subsequentBatchSize);
};
var cursorCountMatching = function(cursor, pred) {
@@ -282,9 +282,9 @@
assert.commandWorked(mydb.createCollection("quux"));
res = mydb.runCommand("listCollections", {cursor: {batchSize: 0}});
- cursor = new DBCommandCursor(mydb.getMongo(), res, 2);
+ cursor = new DBCommandCursor(res._mongo, res, 2);
cursor.close();
- cursor = new DBCommandCursor(mydb.getMongo(), res, 2);
+ cursor = new DBCommandCursor(res._mongo, res, 2);
assert.throws(function() {
cursor.hasNext();
});
diff --git a/jstests/core/list_collections_filter.js b/jstests/core/list_collections_filter.js
index e0d18f055d0..0516d57a417 100644
--- a/jstests/core/list_collections_filter.js
+++ b/jstests/core/list_collections_filter.js
@@ -19,8 +19,8 @@
filter = {};
}
- var cursor = new DBCommandCursor(mydb.getMongo(),
- mydb.runCommand("listCollections", {filter: filter}));
+ var res = mydb.runCommand("listCollections", {filter: filter});
+ var cursor = new DBCommandCursor(res._mongo, res);
function stripToName(result) {
return result.name;
}
diff --git a/jstests/core/list_indexes.js b/jstests/core/list_indexes.js
index de0f4473980..6ec9a7a13e1 100644
--- a/jstests/core/list_indexes.js
+++ b/jstests/core/list_indexes.js
@@ -27,8 +27,8 @@
//
var getListIndexesCursor = function(coll, options, subsequentBatchSize) {
- return new DBCommandCursor(
- coll.getDB().getMongo(), coll.runCommand("listIndexes", options), subsequentBatchSize);
+ var res = coll.runCommand("listIndexes", options);
+ return new DBCommandCursor(res._mongo, res, subsequentBatchSize);
};
var cursorGetIndexSpecs = function(cursor) {
@@ -163,9 +163,9 @@
assert.commandWorked(coll.ensureIndex({c: 1}, {unique: true}));
res = coll.runCommand("listIndexes", {cursor: {batchSize: 0}});
- cursor = new DBCommandCursor(coll.getDB().getMongo(), res, 2);
+ cursor = new DBCommandCursor(res._mongo, res, 2);
cursor.close();
- cursor = new DBCommandCursor(coll.getDB().getMongo(), res, 2);
+ cursor = new DBCommandCursor(res._mongo, res, 2);
assert.throws(function() {
cursor.hasNext();
});
diff --git a/jstests/core/list_indexes_invalidation.js b/jstests/core/list_indexes_invalidation.js
index b8cbe5eb134..9fe94de5efc 100644
--- a/jstests/core/list_indexes_invalidation.js
+++ b/jstests/core/list_indexes_invalidation.js
@@ -19,7 +19,7 @@
printjson(res);
// Ensure the cursor has data, rename or drop the collection, and exhaust the cursor.
- let cursor = new DBCommandCursor(db.getMongo(), res);
+ let cursor = new DBCommandCursor(res._mongo, res);
let errMsg =
'expected more data from command ' + tojson(cmd) + ', with result ' + tojson(res);
assert(cursor.hasNext(), errMsg);
diff --git a/jstests/core/list_namespaces_invalidation.js b/jstests/core/list_namespaces_invalidation.js
index 6f8033b5fe4..85eb26510bb 100644
--- a/jstests/core/list_namespaces_invalidation.js
+++ b/jstests/core/list_namespaces_invalidation.js
@@ -1,4 +1,6 @@
// SERVER-27996/SERVER-28022 Missing invalidation for system.namespaces writes
+//
+// @tags: [requires_collmod_command]
(function() {
'use strict';
let dbInvalidName = 'system_namespaces_invalidations';
diff --git a/jstests/core/max_time_ms.js b/jstests/core/max_time_ms.js
index 0442ffcba68..efe3dabcc6d 100644
--- a/jstests/core/max_time_ms.js
+++ b/jstests/core/max_time_ms.js
@@ -1,4 +1,12 @@
// Tests query/command option $maxTimeMS.
+//
+// @tags: [
+// # This test attempts to perform read operations after having enabled the maxTimeAlwaysTimeOut
+// # failpoint. The former operations may be routed to a secondary in the replica set, whereas the
+// # latter must be routed to the primary.
+// assumes_read_preference_unchanged,
+// requires_collmod_command,
+// ]
var t = db.max_time_ms;
var exceededTimeLimit = 50; // ErrorCodes::ExceededTimeLimit
diff --git a/jstests/core/mr4.js b/jstests/core/mr4.js
index 58ea303f7e8..683583acecd 100644
--- a/jstests/core/mr4.js
+++ b/jstests/core/mr4.js
@@ -9,7 +9,7 @@ t.save({x: 4, tags: ["b", "c"]});
m = function() {
this.tags.forEach(function(z) {
- emit(z, {count: xx});
+ emit(z, {count: xx.val});
});
};
@@ -21,7 +21,7 @@ r = function(key, values) {
return {count: total};
};
-res = t.mapReduce(m, r, {out: "mr4_out", scope: {xx: 1}});
+res = t.mapReduce(m, r, {out: "mr4_out", scope: {xx: {val: 1}}});
z = res.convertToSingleObject();
assert.eq(3, Object.keySet(z).length, "A1");
@@ -31,7 +31,7 @@ assert.eq(3, z.c.count, "A4");
res.drop();
-res = t.mapReduce(m, r, {scope: {xx: 2}, out: "mr4_out"});
+res = t.mapReduce(m, r, {scope: {xx: {val: 2}}, out: "mr4_out"});
z = res.convertToSingleObject();
assert.eq(3, Object.keySet(z).length, "A1");
diff --git a/jstests/core/mr_killop.js b/jstests/core/mr_killop.js
index 78e98f0bcaa..e85986e2fc0 100644
--- a/jstests/core/mr_killop.js
+++ b/jstests/core/mr_killop.js
@@ -4,7 +4,7 @@ t = db.jstests_mr_killop;
t.drop();
t2 = db.jstests_mr_killop_out;
t2.drop();
-
+db.adminCommand({"configureFailPoint": 'mr_killop_test_fp', "mode": 'alwaysOn'});
function debug(x) {
// printjson( x );
}
@@ -171,3 +171,4 @@ var loop = function() {
};
runMRTests(loop, false);
runFinalizeTests(loop, false);
+db.adminCommand({"configureFailPoint": 'mr_killop_test_fp', "mode": 'off'});
diff --git a/jstests/core/mr_optim.js b/jstests/core/mr_optim.js
index 7437753ca67..1c525ae3de3 100644
--- a/jstests/core/mr_optim.js
+++ b/jstests/core/mr_optim.js
@@ -3,8 +3,17 @@
t = db.mr_optim;
t.drop();
+// We drop the output collection to ensure the test can be run multiple times successfully. We
+// explicitly avoid using the DBCollection#drop() shell helper to avoid implicitly sharding the
+// collection during the sharded_collections_jscore_passthrough.yml test suite when reading the
+// results from the output collection in the reformat() function.
+var res = db.runCommand({drop: "mr_optim_out"});
+if (res.ok !== 1) {
+ assert.commandFailedWithCode(res, ErrorCodes.NamespaceNotFound);
+}
+
for (var i = 0; i < 1000; ++i) {
- t.save({a: Math.random(1000), b: Math.random(10000)});
+ assert.writeOK(t.save({a: Math.random(1000), b: Math.random(10000)}));
}
function m() {
@@ -21,7 +30,7 @@ function reformat(r) {
if (r.results)
cursor = r.results;
else
- cursor = r.find();
+ cursor = r.find().sort({_id: 1});
cursor.forEach(function(z) {
x[z._id] = z.value;
});
@@ -43,4 +52,4 @@ res.drop();
assert.eq(x, x2, "object from inline and collection are not equal");
-t.drop(); \ No newline at end of file
+t.drop();
diff --git a/jstests/core/no_db_created.js b/jstests/core/no_db_created.js
index 3491914d470..b67b193494c 100644
--- a/jstests/core/no_db_created.js
+++ b/jstests/core/no_db_created.js
@@ -1,4 +1,6 @@
// checks that operations do not create a database
+//
+// @tags: [requires_collmod_command]
(function() {
"use strict";
@@ -32,4 +34,4 @@
noDB(mydb);
assert.writeOK(coll.insert({}));
mydb.dropDatabase();
-}()); \ No newline at end of file
+}());
diff --git a/jstests/core/notablescan.js b/jstests/core/notablescan.js
index 80306c08cf2..bb4c170a603 100644
--- a/jstests/core/notablescan.js
+++ b/jstests/core/notablescan.js
@@ -1,4 +1,11 @@
// check notablescan mode
+//
+// @tags: [
+// # This test attempts to perform read operations after having enabled the notablescan server
+// # parameter. The former operations may be routed to a secondary in the replica set, whereas the
+// # latter must be routed to the primary.
+// assumes_read_preference_unchanged,
+// ]
t = db.test_notablescan;
t.drop();
diff --git a/jstests/core/operation_latency_histogram.js b/jstests/core/operation_latency_histogram.js
index 1e3f1a59b95..947a8be6520 100644
--- a/jstests/core/operation_latency_histogram.js
+++ b/jstests/core/operation_latency_histogram.js
@@ -1,4 +1,10 @@
// Checks that histogram counters for collections are updated as we expect.
+//
+// This test attempts to perform write operations and get latency statistics using the $collStats
+// stage. The former operation must be routed to the primary in a replica set, whereas the latter
+// may be routed to a secondary.
+//
+// @tags: [assumes_read_preference_unchanged]
(function() {
"use strict";
diff --git a/jstests/core/plan_cache_clear.js b/jstests/core/plan_cache_clear.js
index 8f9cf0ea302..778239616b5 100644
--- a/jstests/core/plan_cache_clear.js
+++ b/jstests/core/plan_cache_clear.js
@@ -1,5 +1,12 @@
// Test clearing of the plan cache, either manually through the planCacheClear command,
// or due to system events such as an index build.
+//
+// @tags: [
+// # This test attempts to perform queries and introspect/manipulate the server's plan cache
+// # entries. The former operation may be routed to a secondary in the replica set, whereas the
+// # latter must be routed to the primary.
+// assumes_read_preference_unchanged,
+// ]
var t = db.jstests_plan_cache_clear;
t.drop();
diff --git a/jstests/core/plan_cache_list_plans.js b/jstests/core/plan_cache_list_plans.js
index 7ca599483ff..3359980ab07 100644
--- a/jstests/core/plan_cache_list_plans.js
+++ b/jstests/core/plan_cache_list_plans.js
@@ -1,4 +1,11 @@
// Test the planCacheListPlans command.
+//
+// @tags: [
+// # This test attempts to perform queries and introspect the server's plan cache entries. The
+// # former operation may be routed to a secondary in the replica set, whereas the latter must be
+// # routed to the primary.
+// assumes_read_preference_unchanged,
+// ]
var t = db.jstests_plan_cache_list_plans;
t.drop();
diff --git a/jstests/core/plan_cache_list_shapes.js b/jstests/core/plan_cache_list_shapes.js
index 1c9ecdf9e1b..61c3111cd8a 100644
--- a/jstests/core/plan_cache_list_shapes.js
+++ b/jstests/core/plan_cache_list_shapes.js
@@ -1,5 +1,12 @@
// Test the planCacheListQueryShapes command, which returns a list of query shapes
// for the queries currently cached in the collection.
+//
+// @tags: [
+// # This test attempts to perform queries with plan cache filters set up. The former operation
+// # may be routed to a secondary in the replica set, whereas the latter must be routed to the
+// # primary.
+// assumes_read_preference_unchanged,
+// ]
var t = db.jstests_plan_cache_list_shapes;
t.drop();
diff --git a/jstests/core/plan_cache_shell_helpers.js b/jstests/core/plan_cache_shell_helpers.js
index dc990b19dcc..6c4ff185014 100644
--- a/jstests/core/plan_cache_shell_helpers.js
+++ b/jstests/core/plan_cache_shell_helpers.js
@@ -1,4 +1,11 @@
// Test the shell helpers which wrap the plan cache commands.
+//
+// @tags: [
+// # This test attempts to perform queries and introspect the server's plan cache entries. The
+// # former operation may be routed to a secondary in the replica set, whereas the latter must be
+// # routed to the primary.
+// assumes_read_preference_unchanged,
+// ]
var t = db.jstests_plan_cache_shell_helpers;
t.drop();
diff --git a/jstests/core/profile2.js b/jstests/core/profile2.js
index bb1605abd1e..9da6410d2ac 100644
--- a/jstests/core/profile2.js
+++ b/jstests/core/profile2.js
@@ -24,7 +24,7 @@ assert(result.hasOwnProperty('millis'));
assert(result.hasOwnProperty('query'));
assert.eq('string', typeof(result.query));
// String value is truncated.
-assert(result.query.match(/filter: { a: "a+\.\.\." } }$/));
+assert(result.query.match(/filter: { a: "a+\.\.\." }/));
assert.commandWorked(coll.getDB().runCommand({profile: 0}));
coll.getDB().system.profile.drop();
diff --git a/jstests/core/profile_getmore.js b/jstests/core/profile_getmore.js
index a9272567b1a..3f6f492597e 100644
--- a/jstests/core/profile_getmore.js
+++ b/jstests/core/profile_getmore.js
@@ -24,12 +24,13 @@
var cursor = coll.find({a: {$gt: 0}}).sort({a: 1}).batchSize(2);
cursor.next(); // Perform initial query and consume first of 2 docs returned.
- var cursorId = getLatestProfilerEntry(testDB).cursorid; // Save cursorid from find.
+ var cursorId =
+ getLatestProfilerEntry(testDB, {op: "query"}).cursorid; // Save cursorid from find.
cursor.next(); // Consume second of 2 docs from initial query.
cursor.next(); // getMore performed, leaving open cursor.
- var profileObj = getLatestProfilerEntry(testDB);
+ var profileObj = getLatestProfilerEntry(testDB, {op: "getmore"});
assert.eq(profileObj.ns, coll.getFullName(), tojson(profileObj));
assert.eq(profileObj.op, "getmore", tojson(profileObj));
@@ -67,7 +68,7 @@
cursor.next(); // Consume second of 2 docs from initial query.
cursor.next(); // getMore performed, leaving open cursor.
- profileObj = getLatestProfilerEntry(testDB);
+ profileObj = getLatestProfilerEntry(testDB, {op: "getmore"});
assert.eq(profileObj.hasSortStage, true, tojson(profileObj));
@@ -83,7 +84,7 @@
cursor.next(); // Perform initial query and consume first of 3 docs returned.
cursor.itcount(); // Exhaust the cursor.
- profileObj = getLatestProfilerEntry(testDB);
+ profileObj = getLatestProfilerEntry(testDB, {op: "getmore"});
assert(profileObj.hasOwnProperty("cursorid"),
tojson(profileObj)); // cursorid should always be present on getMore.
@@ -101,12 +102,12 @@
assert.commandWorked(coll.createIndex({a: 1}));
var cursor = coll.aggregate([{$match: {a: {$gte: 0}}}], {cursor: {batchSize: 0}});
- var cursorId = getLatestProfilerEntry(testDB).cursorid;
+ var cursorId = getLatestProfilerEntry(testDB, {"command.aggregate": coll.getName()}).cursorid;
assert.neq(0, cursorId);
cursor.next(); // Consume the result set.
- profileObj = getLatestProfilerEntry(testDB);
+ profileObj = getLatestProfilerEntry(testDB, {op: "getmore"});
assert.eq(profileObj.ns, coll.getFullName(), tojson(profileObj));
assert.eq(profileObj.op, "getmore", tojson(profileObj));
diff --git a/jstests/core/profile_insert.js b/jstests/core/profile_insert.js
index 3994c896bda..836ec2ecff2 100644
--- a/jstests/core/profile_insert.js
+++ b/jstests/core/profile_insert.js
@@ -1,4 +1,6 @@
// Confirms that profiled insert execution contains all expected metrics with proper values.
+//
+// @tags: [assumes_write_concern_unchanged]
(function() {
"use strict";
diff --git a/jstests/core/recursion.js b/jstests/core/recursion.js
index 926250be20d..1db491c8ae9 100644
--- a/jstests/core/recursion.js
+++ b/jstests/core/recursion.js
@@ -1,5 +1,7 @@
-// Basic tests for a form of stack recursion that's been shown to cause C++
-// side stack overflows in the past. See SERVER-19614.
+// Basic tests for a form of stack recursion that's been shown to cause C++ side stack overflows in
+// the past. See SERVER-19614.
+//
+// @tags: [requires_eval_command]
(function() {
"use strict";
diff --git a/jstests/core/regex_not_id.js b/jstests/core/regex_not_id.js
index 1f15250f240..35b2c858867 100644
--- a/jstests/core/regex_not_id.js
+++ b/jstests/core/regex_not_id.js
@@ -3,10 +3,10 @@
var testColl = db.regex_not_id;
testColl.drop();
-assert.writeOK(testColl.insert({_id: "ABCDEF1"}, {writeConcern: {w: 1}}));
+assert.writeOK(testColl.insert({_id: "ABCDEF1"}));
// Should be an error.
-assert.writeError(testColl.insert({_id: /^A/}, {writeConcern: {w: 1}}));
+assert.writeError(testColl.insert({_id: /^A/}));
// _id doesn't have to be first; still disallowed
-assert.writeError(testColl.insert({xxx: "ABCDEF", _id: /ABCDEF/}, {writeConcern: {w: 1}})); \ No newline at end of file
+assert.writeError(testColl.insert({xxx: "ABCDEF", _id: /ABCDEF/}));
diff --git a/jstests/core/remove8.js b/jstests/core/remove8.js
index 563e4708cf9..3c9fd6a11a1 100644
--- a/jstests/core/remove8.js
+++ b/jstests/core/remove8.js
@@ -1,3 +1,4 @@
+// @tags: [requires_eval_command]
t = db.remove8;
t.drop();
diff --git a/jstests/core/rename4.js b/jstests/core/rename4.js
index 185193deaa9..756918db5f6 100644
--- a/jstests/core/rename4.js
+++ b/jstests/core/rename4.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
t = db.jstests_rename4;
t.drop();
diff --git a/jstests/core/rename_stayTemp.js b/jstests/core/rename_stayTemp.js
index d8451af2d2d..8dee8f89fea 100644
--- a/jstests/core/rename_stayTemp.js
+++ b/jstests/core/rename_stayTemp.js
@@ -11,7 +11,7 @@ function ns(coll) {
function istemp(name) {
var result = db.runCommand("listCollections", {filter: {name: name}});
assert(result.ok);
- var collections = new DBCommandCursor(db.getMongo(), result).toArray();
+ var collections = new DBCommandCursor(result._mongo, result).toArray();
assert.eq(1, collections.length);
return collections[0].options.temp ? true : false;
}
diff --git a/jstests/core/shell_connection_strings.js b/jstests/core/shell_connection_strings.js
new file mode 100644
index 00000000000..22861e6ce25
--- /dev/null
+++ b/jstests/core/shell_connection_strings.js
@@ -0,0 +1,33 @@
+// Test mongo shell connect strings.
+(function() {
+ 'use strict';
+
+ const mongod = new MongoURI(db.getMongo().host).servers[0];
+ const host = mongod.host;
+ const port = mongod.port;
+
+ function testConnect(ok, ...args) {
+ const exitCode = runMongoProgram('mongo', '--eval', ';', ...args);
+ if (ok) {
+ assert.eq(exitCode, 0, "failed to connect with `" + args.join(' ') + "`");
+ } else {
+ assert.neq(
+ exitCode, 0, "unexpectedly succeeded connecting with `" + args.join(' ') + "`");
+ }
+ }
+
+ testConnect(true, `${host}:${port}`);
+ testConnect(true, `${host}:${port}/test`);
+ testConnect(true, `${host}:${port}/admin`);
+ testConnect(true, host, '--port', port);
+ testConnect(true, '--host', host, '--port', port, 'test');
+ testConnect(true, '--host', host, '--port', port, 'admin');
+ testConnect(true, `mongodb://${host}:${port}/test`);
+ testConnect(true, `mongodb://${host}:${port}/test?connectTimeoutMS=10000`);
+
+ // if a full URI is provided, you cannot also specify host or port
+ testConnect(false, `${host}/test`, '--port', port);
+ testConnect(false, `mongodb://${host}:${port}/test`, '--port', port);
+ testConnect(false, `mongodb://${host}:${port}/test`, '--host', host);
+ testConnect(false, `mongodb://${host}:${port}/test`, '--host', host, '--port', port);
+})();
diff --git a/jstests/core/shell_writeconcern.js b/jstests/core/shell_writeconcern.js
index f3f190061cf..e3e7a23a9aa 100644
--- a/jstests/core/shell_writeconcern.js
+++ b/jstests/core/shell_writeconcern.js
@@ -1,7 +1,10 @@
"use strict";
+
// check that shell writeconcern work correctly
// 1.) tests that it can be set on each level and is inherited
// 2.) tests that each operation (update/insert/remove/save) take and ensure a write concern
+//
+// @tags: [assumes_write_concern_unchanged]
var collA = db.shell_wc_a;
var collB = db.shell_wc_b;
diff --git a/jstests/core/stages_delete.js b/jstests/core/stages_delete.js
index f8e7380c75a..98a270cedf3 100644
--- a/jstests/core/stages_delete.js
+++ b/jstests/core/stages_delete.js
@@ -1,3 +1,9 @@
+// @tags: [
+// # This test attempts to remove documents using the stageDebug command, which doesn't support
+// # specifying a writeConcern.
+// assumes_write_concern_unchanged,
+// ]
+
// Test basic delete stage functionality.
var coll = db.stages_delete;
var collScanStage = {cscan: {args: {direction: 1}, filter: {deleteMe: true}}};
diff --git a/jstests/core/startup_log.js b/jstests/core/startup_log.js
index 3b0cbe3464d..c73013d1744 100644
--- a/jstests/core/startup_log.js
+++ b/jstests/core/startup_log.js
@@ -1,101 +1,108 @@
-load('jstests/aggregation/extras/utils.js');
-
-(function() {
- 'use strict';
-
- // Check that smallArray is entirely contained by largeArray
- // returns false if a member of smallArray is not in largeArray
- function arrayIsSubset(smallArray, largeArray) {
- for (var i = 0; i < smallArray.length; i++) {
- if (!Array.contains(largeArray, smallArray[i])) {
- print("Could not find " + smallArray[i] + " in largeArray");
- return false;
- }
- }
-
- return true;
- }
-
- // Test startup_log
- var stats = db.getSisterDB("local").startup_log.stats();
- assert(stats.capped);
-
- var latestStartUpLog =
- db.getSisterDB("local").startup_log.find().sort({$natural: -1}).limit(1).next();
- var serverStatus = db._adminCommand("serverStatus");
- var cmdLine = db._adminCommand("getCmdLineOpts").parsed;
-
- // Test that the startup log has the expected keys
- var verbose = false;
- var expectedKeys =
- ["_id", "hostname", "startTime", "startTimeLocal", "cmdLine", "pid", "buildinfo"];
- var keys = Object.keySet(latestStartUpLog);
- assert(arrayEq(expectedKeys, keys, verbose), 'startup_log keys failed');
-
- // Tests _id implicitly - should be comprised of host-timestamp
- // Setup expected startTime and startTimeLocal from the supplied timestamp
- var _id = latestStartUpLog._id.split('-'); // _id should consist of host-timestamp
- var _idUptime = _id.pop();
- var _idHost = _id.join('-');
- var uptimeSinceEpochRounded = Math.floor(_idUptime / 1000) * 1000;
- var startTime = new Date(uptimeSinceEpochRounded); // Expected startTime
-
- assert.eq(_idHost, latestStartUpLog.hostname, "Hostname doesn't match one from _id");
- assert.eq(serverStatus.host.split(':')[0],
- latestStartUpLog.hostname,
- "Hostname doesn't match one in server status");
- assert.closeWithinMS(startTime,
- latestStartUpLog.startTime,
- "StartTime doesn't match one from _id",
- 2000); // Expect less than 2 sec delta
- assert.eq(cmdLine, latestStartUpLog.cmdLine, "cmdLine doesn't match that from getCmdLineOpts");
- assert.eq(serverStatus.pid, latestStartUpLog.pid, "pid doesn't match that from serverStatus");
-
- // Test buildinfo
- var buildinfo = db.runCommand("buildinfo");
- delete buildinfo.ok; // Delete extra meta info not in startup_log
- var isMaster = db._adminCommand("ismaster");
-
- // Test buildinfo has the expected keys
- var expectedKeys = [
- "version",
- "gitVersion",
- "allocator",
- "versionArray",
- "javascriptEngine",
- "openssl",
- "buildEnvironment",
- "debug",
- "maxBsonObjectSize",
- "bits",
- "modules"
- ];
-
- var keys = Object.keySet(latestStartUpLog.buildinfo);
- // Disabled to check
- assert(arrayIsSubset(expectedKeys, keys),
- "buildinfo keys failed! \n expected:\t" + expectedKeys + "\n actual:\t" + keys);
- assert.eq(buildinfo,
- latestStartUpLog.buildinfo,
- "buildinfo doesn't match that from buildinfo command");
-
- // Test version and version Array
- var version = latestStartUpLog.buildinfo.version.split('-')[0];
- var versionArray = latestStartUpLog.buildinfo.versionArray;
- var versionArrayCleaned = versionArray.slice(0, 3);
- if (versionArray[3] == -100) {
- versionArrayCleaned[2] -= 1;
- }
-
- assert.eq(serverStatus.version,
- latestStartUpLog.buildinfo.version,
- "Mongo version doesn't match that from ServerStatus");
- assert.eq(
- version, versionArrayCleaned.join('.'), "version doesn't match that from the versionArray");
- var jsEngine = latestStartUpLog.buildinfo.javascriptEngine;
- assert((jsEngine == "none") || jsEngine.startsWith("mozjs"));
- assert.eq(isMaster.maxBsonObjectSize,
- latestStartUpLog.buildinfo.maxBsonObjectSize,
- "maxBsonObjectSize doesn't match one from ismaster");
-
-})();
+/**
+ * This test attempts to read from the "local.startup_log" collection and assert that it has an
+ * entry matching the server's response from the "getCmdLineOpts" command. The former operation may
+ * be routed to a secondary in the replica set, whereas the latter must be routed to the primary.
+ *
+ * @tags: [assumes_read_preference_unchanged]
+ */
+load('jstests/aggregation/extras/utils.js');
+
+(function() {
+ 'use strict';
+
+ // Check that smallArray is entirely contained by largeArray
+ // returns false if a member of smallArray is not in largeArray
+ function arrayIsSubset(smallArray, largeArray) {
+ for (var i = 0; i < smallArray.length; i++) {
+ if (!Array.contains(largeArray, smallArray[i])) {
+ print("Could not find " + smallArray[i] + " in largeArray");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // Test startup_log
+ var stats = db.getSisterDB("local").startup_log.stats();
+ assert(stats.capped);
+
+ var latestStartUpLog =
+ db.getSisterDB("local").startup_log.find().sort({$natural: -1}).limit(1).next();
+ var serverStatus = db._adminCommand("serverStatus");
+ var cmdLine = db._adminCommand("getCmdLineOpts").parsed;
+
+ // Test that the startup log has the expected keys
+ var verbose = false;
+ var expectedKeys =
+ ["_id", "hostname", "startTime", "startTimeLocal", "cmdLine", "pid", "buildinfo"];
+ var keys = Object.keySet(latestStartUpLog);
+ assert(arrayEq(expectedKeys, keys, verbose), 'startup_log keys failed');
+
+ // Tests _id implicitly - should be comprised of host-timestamp
+ // Setup expected startTime and startTimeLocal from the supplied timestamp
+ var _id = latestStartUpLog._id.split('-'); // _id should consist of host-timestamp
+ var _idUptime = _id.pop();
+ var _idHost = _id.join('-');
+ var uptimeSinceEpochRounded = Math.floor(_idUptime / 1000) * 1000;
+ var startTime = new Date(uptimeSinceEpochRounded); // Expected startTime
+
+ assert.eq(_idHost, latestStartUpLog.hostname, "Hostname doesn't match one from _id");
+ assert.eq(serverStatus.host.split(':')[0],
+ latestStartUpLog.hostname,
+ "Hostname doesn't match one in server status");
+ assert.closeWithinMS(startTime,
+ latestStartUpLog.startTime,
+ "StartTime doesn't match one from _id",
+ 2000); // Expect less than 2 sec delta
+ assert.eq(cmdLine, latestStartUpLog.cmdLine, "cmdLine doesn't match that from getCmdLineOpts");
+ assert.eq(serverStatus.pid, latestStartUpLog.pid, "pid doesn't match that from serverStatus");
+
+ // Test buildinfo
+ var buildinfo = db.runCommand("buildinfo");
+ delete buildinfo.ok; // Delete extra meta info not in startup_log
+ var isMaster = db._adminCommand("ismaster");
+
+ // Test buildinfo has the expected keys
+ var expectedKeys = [
+ "version",
+ "gitVersion",
+ "allocator",
+ "versionArray",
+ "javascriptEngine",
+ "openssl",
+ "buildEnvironment",
+ "debug",
+ "maxBsonObjectSize",
+ "bits",
+ "modules"
+ ];
+
+ var keys = Object.keySet(latestStartUpLog.buildinfo);
+ // Disabled to check
+ assert(arrayIsSubset(expectedKeys, keys),
+ "buildinfo keys failed! \n expected:\t" + expectedKeys + "\n actual:\t" + keys);
+ assert.eq(buildinfo,
+ latestStartUpLog.buildinfo,
+ "buildinfo doesn't match that from buildinfo command");
+
+ // Test version and version Array
+ var version = latestStartUpLog.buildinfo.version.split('-')[0];
+ var versionArray = latestStartUpLog.buildinfo.versionArray;
+ var versionArrayCleaned = versionArray.slice(0, 3);
+ if (versionArray[3] == -100) {
+ versionArrayCleaned[2] -= 1;
+ }
+
+ assert.eq(serverStatus.version,
+ latestStartUpLog.buildinfo.version,
+ "Mongo version doesn't match that from ServerStatus");
+ assert.eq(
+ version, versionArrayCleaned.join('.'), "version doesn't match that from the versionArray");
+ var jsEngine = latestStartUpLog.buildinfo.javascriptEngine;
+ assert((jsEngine == "none") || jsEngine.startsWith("mozjs"));
+ assert.eq(isMaster.maxBsonObjectSize,
+ latestStartUpLog.buildinfo.maxBsonObjectSize,
+ "maxBsonObjectSize doesn't match one from ismaster");
+
+})();
diff --git a/jstests/core/storefunc.js b/jstests/core/storefunc.js
index 8598e9cc62b..15abc56421e 100644
--- a/jstests/core/storefunc.js
+++ b/jstests/core/storefunc.js
@@ -1,3 +1,5 @@
+// @tags: [requires_eval_command]
+
// Use a private sister database to avoid conflicts with other tests that use system.js
var testdb = db.getSisterDB("storefunc");
var res;
diff --git a/jstests/core/top.js b/jstests/core/top.js
index 819b41b0981..3d98f5a7b2d 100644
--- a/jstests/core/top.js
+++ b/jstests/core/top.js
@@ -1,5 +1,11 @@
/**
* 1. check top numbers are correct
+ *
+ * This test attempts to perform read operations and get statistics using the top command. The
+ * former operation may be routed to a secondary in the replica set, whereas the latter must be
+ * routed to the primary.
+ *
+ * @tags: [assumes_read_preference_unchanged]
*/
(function() {
load("jstests/libs/stats.js");
diff --git a/jstests/core/update_affects_indexes.js b/jstests/core/update_affects_indexes.js
new file mode 100644
index 00000000000..91db3ebe565
--- /dev/null
+++ b/jstests/core/update_affects_indexes.js
@@ -0,0 +1,100 @@
+// This is a regression test for SERVER-32048. It checks that index keys are correctly updated when
+// an update modifier implicitly creates a new array element.
+(function() {
+ "use strict";
+
+ let coll = db.update_affects_indexes;
+ coll.drop();
+ let indexKeyPattern = {"a.b": 1};
+ assert.commandWorked(coll.createIndex(indexKeyPattern));
+
+ // Tests that the document 'docId' has all the index keys in 'expectedKeys' and none of the
+ // index keys in 'unexpectedKeys'.
+ function assertExpectedIndexKeys(docId, expectedKeys, unexpectedKeys) {
+ for (let key of expectedKeys) {
+ let res = coll.find(docId).hint(indexKeyPattern).min(key).returnKey().toArray();
+ assert.eq(1, res.length, tojson(res));
+ assert.eq(key, res[0]);
+ }
+
+ for (let key of unexpectedKeys) {
+ let res = coll.find(docId).hint(indexKeyPattern).min(key).returnKey().toArray();
+ if (res.length > 0) {
+ assert.eq(1, res.length, tojson(res));
+ assert.neq(key, res[0]);
+ }
+ }
+ }
+
+ // $set implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 0, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 0}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 0}, {$set: {"a.1.c": 0}}));
+ assertExpectedIndexKeys({_id: 0}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $set implicitly creates array element beyond end of array.
+ assert.writeOK(coll.insert({_id: 1, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 1}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 1}, {$set: {"a.3.c": 0}}));
+ assertExpectedIndexKeys({_id: 1}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $set implicitly creates array element in empty array (no index key changes needed).
+ assert.writeOK(coll.insert({_id: 2, a: []}));
+ assertExpectedIndexKeys({_id: 2}, [{"a.b": null}], []);
+ assert.writeOK(coll.update({_id: 2}, {$set: {"a.0.c": 0}}));
+ assertExpectedIndexKeys({_id: 2}, [{"a.b": null}], []);
+
+ // $inc implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 3, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 3}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 3}, {$inc: {"a.1.c": 0}}));
+ assertExpectedIndexKeys({_id: 3}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $mul implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 4, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 4}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 4}, {$mul: {"a.1.c": 0}}));
+ assertExpectedIndexKeys({_id: 4}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $addToSet implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 5, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 5}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 5}, {$addToSet: {"a.1.c": 0}}));
+ assertExpectedIndexKeys({_id: 5}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $bit implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 6, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 6}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 6}, {$bit: {"a.1.c": {and: NumberInt(1)}}}));
+ assertExpectedIndexKeys({_id: 6}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $min implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 7, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 7}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 7}, {$min: {"a.1.c": 0}}));
+ assertExpectedIndexKeys({_id: 7}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $max implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 8, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 8}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 8}, {$max: {"a.1.c": 0}}));
+ assertExpectedIndexKeys({_id: 8}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $currentDate implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 9, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 9}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 9}, {$currentDate: {"a.1.c": true}}));
+ assertExpectedIndexKeys({_id: 9}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $push implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 10, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 10}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 10}, {$push: {"a.1.c": 0}}));
+ assertExpectedIndexKeys({_id: 10}, [{"a.b": 0}, {"a.b": null}], []);
+
+ // $pushAll implicitly creates array element at end of array.
+ assert.writeOK(coll.insert({_id: 11, a: [{b: 0}]}));
+ assertExpectedIndexKeys({_id: 11}, [{"a.b": 0}], [{"a.b": null}]);
+ assert.writeOK(coll.update({_id: 11}, {$pushAll: {"a.1.c": [0]}}));
+ assertExpectedIndexKeys({_id: 11}, [{"a.b": 0}, {"a.b": null}], []);
+}());
diff --git a/jstests/core/update_multi5.js b/jstests/core/update_multi5.js
index e610462a620..9e9550bc554 100644
--- a/jstests/core/update_multi5.js
+++ b/jstests/core/update_multi5.js
@@ -7,8 +7,8 @@
assert.writeOK(t.insert({path: 'r1', subscribers: [1, 2]}));
assert.writeOK(t.insert({path: 'r2', subscribers: [3, 4]}));
- var res = assert.writeOK(t.update(
- {}, {$addToSet: {subscribers: 5}}, {upsert: false, multi: true, writeConcern: {w: 1}}));
+ var res =
+ assert.writeOK(t.update({}, {$addToSet: {subscribers: 5}}, {upsert: false, multi: true}));
assert.eq(res.nMatched, 2, tojson(res));
diff --git a/jstests/core/views/invalid_system_views.js b/jstests/core/views/invalid_system_views.js
index 3ba282d2ca1..49ac600ba8b 100644
--- a/jstests/core/views/invalid_system_views.js
+++ b/jstests/core/views/invalid_system_views.js
@@ -1,6 +1,8 @@
/**
* Tests that invalid view definitions in system.views do not impact valid commands on existing
* collections.
+ *
+ * @tags: [requires_collmod_command]
*/
(function() {
"use strict";
diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js
index 0115672dcda..e1798803a1b 100644
--- a/jstests/core/views/views_all_commands.js
+++ b/jstests/core/views/views_all_commands.js
@@ -48,6 +48,8 @@
*
* skipStandalone
* If true, do not run this command on a standalone mongod.
+ *
+ * @tags: [requires_collmod_command]
*/
(function() {
diff --git a/jstests/core/views/views_basic.js b/jstests/core/views/views_basic.js
index d6032b105df..b4a2f177982 100644
--- a/jstests/core/views/views_basic.js
+++ b/jstests/core/views/views_basic.js
@@ -13,7 +13,7 @@
let res = viewsDB.runCommand(cmd);
assert.commandWorked(res);
- let cursor = new DBCommandCursor(db.getMongo(), res, 5);
+ let cursor = new DBCommandCursor(res._mongo, res, 5);
let actual = cursor.toArray();
assert(arrayEq(actual, expected),
"actual: " + tojson(cursor.toArray()) + ", expected:" + tojson(expected));
diff --git a/jstests/core/views/views_change.js b/jstests/core/views/views_change.js
index 002284095c5..a62e7e7f04f 100644
--- a/jstests/core/views/views_change.js
+++ b/jstests/core/views/views_change.js
@@ -1,6 +1,7 @@
/**
* Tests the behavior of views when the backing view or collection is changed.
- * @tags: [requires_find_command]
+ *
+ * @tags: [requires_collmod_command, requires_find_command]
*/
(function() {
"use strict";
diff --git a/jstests/core/views/views_collation.js b/jstests/core/views/views_collation.js
index 9e4ed7feb30..38557358ce9 100644
--- a/jstests/core/views/views_collation.js
+++ b/jstests/core/views/views_collation.js
@@ -1,9 +1,13 @@
/**
* Tests the behavior of operations when interacting with a view's default collation.
+ *
+ * @tags: [requires_collmod_command]
*/
(function() {
"use strict";
+ load("jstests/libs/analyze_plan.js");
+
let viewsDB = db.getSiblingDB("views_collation");
assert.commandWorked(viewsDB.dropDatabase());
assert.commandWorked(viewsDB.runCommand({create: "simpleCollection"}));
@@ -58,6 +62,15 @@
assert.commandWorked(viewsDB.runCommand({count: "filView"}));
assert.commandWorked(viewsDB.runCommand({distinct: "filView", key: "x"}));
+ // Explain of operations that do not specify a collation succeed.
+ assert.commandWorked(viewsDB.runCommand({aggregate: "filView", pipeline: [], explain: true}));
+ assert.commandWorked(
+ viewsDB.runCommand({explain: {find: "filView"}, verbosity: "allPlansExecution"}));
+ assert.commandWorked(
+ viewsDB.runCommand({explain: {count: "filView"}, verbosity: "allPlansExecution"}));
+ assert.commandWorked(viewsDB.runCommand(
+ {explain: {distinct: "filView", key: "x"}, verbosity: "allPlansExecution"}));
+
// Operations with a matching collation succeed.
assert.commandWorked(
viewsDB.runCommand({aggregate: "filView", pipeline: [], collation: {locale: "fil"}}));
@@ -66,6 +79,18 @@
assert.commandWorked(
viewsDB.runCommand({distinct: "filView", key: "x", collation: {locale: "fil"}}));
+ // Explain of operations with a matching collation succeed.
+ assert.commandWorked(viewsDB.runCommand(
+ {aggregate: "filView", pipeline: [], explain: true, collation: {locale: "fil"}}));
+ assert.commandWorked(viewsDB.runCommand(
+ {explain: {find: "filView", collation: {locale: "fil"}}, verbosity: "allPlansExecution"}));
+ assert.commandWorked(viewsDB.runCommand(
+ {explain: {count: "filView", collation: {locale: "fil"}}, verbosity: "allPlansExecution"}));
+ assert.commandWorked(viewsDB.runCommand({
+ explain: {distinct: "filView", key: "x", collation: {locale: "fil"}},
+ verbosity: "allPlansExecution"
+ }));
+
// Attempting to override the non-simple default collation of a view fails.
assert.commandFailedWithCode(
viewsDB.runCommand({aggregate: "filView", pipeline: [], collation: {locale: "en"}}),
@@ -90,6 +115,46 @@
viewsDB.runCommand({distinct: "filView", key: "x", collation: {locale: "simple"}}),
ErrorCodes.OptionNotSupportedOnView);
+ // Attempting to override the default collation of a view with explain fails.
+ assert.commandFailedWithCode(
+ viewsDB.runCommand(
+ {aggregate: "filView", pipeline: [], explain: true, collation: {locale: "en"}}),
+ ErrorCodes.OptionNotSupportedOnView);
+ assert.commandFailedWithCode(
+ viewsDB.runCommand(
+ {aggregate: "filView", pipeline: [], explain: true, collation: {locale: "simple"}}),
+ ErrorCodes.OptionNotSupportedOnView);
+ assert.commandFailedWithCode(viewsDB.runCommand({
+ explain: {find: "filView", collation: {locale: "fr"}},
+ verbosity: "allPlansExecution"
+ }),
+ ErrorCodes.OptionNotSupportedOnView);
+ assert.commandFailedWithCode(viewsDB.runCommand({
+ explain: {find: "filView", collation: {locale: "simple"}},
+ verbosity: "allPlansExecution"
+ }),
+ ErrorCodes.OptionNotSupportedOnView);
+ assert.commandFailedWithCode(viewsDB.runCommand({
+ explain: {count: "filView", collation: {locale: "zh"}},
+ verbosity: "allPlansExecution"
+ }),
+ ErrorCodes.OptionNotSupportedOnView);
+ assert.commandFailedWithCode(viewsDB.runCommand({
+ explain: {count: "filView", collation: {locale: "simple"}},
+ verbosity: "allPlansExecution"
+ }),
+ ErrorCodes.OptionNotSupportedOnView);
+ assert.commandFailedWithCode(viewsDB.runCommand({
+ explain: {distinct: "filView", key: "x", collation: {locale: "es"}},
+ verbosity: "allPlansExecution"
+ }),
+ ErrorCodes.OptionNotSupportedOnView);
+ assert.commandFailedWithCode(viewsDB.runCommand({
+ explain: {distinct: "filView", key: "x", collation: {locale: "simple"}},
+ verbosity: "allPlansExecution"
+ }),
+ ErrorCodes.OptionNotSupportedOnView);
+
const lookupSimpleView = {
$lookup: {from: "simpleView", localField: "x", foreignField: "x", as: "result"}
};
@@ -253,4 +318,56 @@
viewsDB.runCommand(
{collMod: "esView", viewOn: "simpleCollection", pipeline: [graphLookupFilView]}),
ErrorCodes.OptionNotSupportedOnView);
+
+ // Make sure that when an operation does not specify the collation, it correctly uses the
+ // default collation associated with the view. For this, we set up a new backing collection with
+ // a case-insensitive view.
+ assert.commandWorked(viewsDB.runCommand({create: "case_sensitive_coll"}));
+ assert.commandWorked(viewsDB.runCommand({
+ create: "case_insensitive_view",
+ viewOn: "case_sensitive_coll",
+ collation: {locale: "en", strength: 1}
+ }));
+
+ assert.writeOK(viewsDB.case_sensitive_coll.insert({f: "case"}));
+ assert.writeOK(viewsDB.case_sensitive_coll.insert({f: "Case"}));
+ assert.writeOK(viewsDB.case_sensitive_coll.insert({f: "CASE"}));
+
+ let explain, cursorStage;
+
+ // Test that aggregate against a view with a default collation correctly uses the collation.
+ assert.eq(1, viewsDB.case_sensitive_coll.aggregate([{$match: {f: "case"}}]).itcount());
+ assert.eq(3, viewsDB.case_insensitive_view.aggregate([{$match: {f: "case"}}]).itcount());
+ explain = viewsDB.case_insensitive_view.explain().aggregate([{$match: {f: "case"}}]);
+ cursorStage = getAggPlanStage(explain, "$cursor");
+ assert.neq(null, cursorStage, tojson(explain));
+ assert.eq(1, cursorStage.$cursor.queryPlanner.collation.strength, tojson(cursorStage));
+
+ // Test that count against a view with a default collation correctly uses the collation.
+ assert.eq(1, viewsDB.case_sensitive_coll.count({f: "case"}));
+ assert.eq(3, viewsDB.case_insensitive_view.count({f: "case"}));
+ explain = viewsDB.case_insensitive_view.explain().count({f: "case"});
+ cursorStage = getAggPlanStage(explain, "$cursor");
+ assert.neq(null, cursorStage, tojson(explain));
+ assert.eq(1, cursorStage.$cursor.queryPlanner.collation.strength, tojson(cursorStage));
+
+ // Test that distinct against a view with a default collation correctly uses the collation.
+ assert.eq(3, viewsDB.case_sensitive_coll.distinct("f").length);
+ assert.eq(1, viewsDB.case_insensitive_view.distinct("f").length);
+ explain = viewsDB.case_insensitive_view.explain().distinct("f");
+ cursorStage = getAggPlanStage(explain, "$cursor");
+ assert.neq(null, cursorStage, tojson(explain));
+ assert.eq(1, cursorStage.$cursor.queryPlanner.collation.strength, tojson(cursorStage));
+
+ // Test that find against a view with a default collation correctly uses the collation.
+ let findRes = viewsDB.runCommand({find: "case_sensitive_coll", filter: {f: "case"}});
+ assert.commandWorked(findRes);
+ assert.eq(1, findRes.cursor.firstBatch.length);
+ findRes = viewsDB.runCommand({find: "case_insensitive_view", filter: {f: "case"}});
+ assert.commandWorked(findRes);
+ assert.eq(3, findRes.cursor.firstBatch.length);
+ explain = viewsDB.runCommand({explain: {find: "case_insensitive_view", filter: {f: "case"}}});
+ cursorStage = getAggPlanStage(explain, "$cursor");
+ assert.neq(null, cursorStage, tojson(explain));
+ assert.eq(1, cursorStage.$cursor.queryPlanner.collation.strength, tojson(cursorStage));
}());
diff --git a/jstests/core/views/views_find.js b/jstests/core/views/views_find.js
index c196e980ce5..53c9d4e8b98 100644
--- a/jstests/core/views/views_find.js
+++ b/jstests/core/views/views_find.js
@@ -15,7 +15,7 @@
let assertFindResultEq = function(cmd, expected, ordered) {
let res = viewsDB.runCommand(cmd);
assert.commandWorked(res);
- let arr = new DBCommandCursor(db.getMongo(), res, 5).toArray();
+ let arr = new DBCommandCursor(res._mongo, res, 5).toArray();
let errmsg = tojson({expected: expected, got: arr});
if (typeof(ordered) === "undefined" || !ordered)
diff --git a/jstests/core/views/views_rename.js b/jstests/core/views/views_rename.js
new file mode 100644
index 00000000000..ad656671ea1
--- /dev/null
+++ b/jstests/core/views/views_rename.js
@@ -0,0 +1,17 @@
+(function() {
+ // SERVER-30406 Test that renaming system.views correctly invalidates the view catalog
+ 'use strict';
+ db.view.drop();
+ db.coll.drop();
+ assert.commandWorked(db.createView("view", "coll", []));
+ assert.writeOK(db.coll.insert({_id: 1}));
+ assert.eq(db.view.find().count(), 1, "couldn't find document in view");
+ assert.commandWorked(db.system.views.renameCollection("views", /*dropTarget*/ true));
+ assert.eq(db.view.find().count(),
+ 0,
+ "find on view should have returned no results after renaming away system.views");
+ assert.commandWorked(db.views.renameCollection("system.views"));
+ assert.eq(db.view.find().count(),
+ 1,
+ "find on view should have worked again after renaming system.views back in place");
+})();
diff --git a/jstests/core/views/views_stats.js b/jstests/core/views/views_stats.js
index 75feb857c9a..22261e9fa81 100644
--- a/jstests/core/views/views_stats.js
+++ b/jstests/core/views/views_stats.js
@@ -1,4 +1,10 @@
// Test that top and latency histogram statistics are recorded for views.
+//
+// This test attempts to perform write operations and get latency statistics using the $collStats
+// stage. The former operation must be routed to the primary in a replica set, whereas the latter
+// may be routed to a secondary.
+//
+// @tags: [assumes_read_preference_unchanged]
(function() {
"use strict";
diff --git a/jstests/core/views/views_validation.js b/jstests/core/views/views_validation.js
index 84c7f1d3510..b32750a082f 100644
--- a/jstests/core/views/views_validation.js
+++ b/jstests/core/views/views_validation.js
@@ -1,3 +1,4 @@
+// @tags: [requires_collmod_command]
(function() {
"use strict";
let viewsDb = db.getSiblingDB("views_validation");
diff --git a/jstests/core/write_result.js b/jstests/core/write_result.js
index 86486089c68..453be4ca1c9 100644
--- a/jstests/core/write_result.js
+++ b/jstests/core/write_result.js
@@ -1,6 +1,8 @@
//
// Tests the behavior of single writes using write commands
//
+// @tags: [assumes_write_concern_unchanged]
+//
var coll = db.write_result;
coll.drop();