diff options
Diffstat (limited to 'jstests')
23 files changed, 278 insertions, 57 deletions
diff --git a/jstests/core/capped6.js b/jstests/core/capped6.js index 945567ee976..c92006f0d01 100644 --- a/jstests/core/capped6.js +++ b/jstests/core/capped6.js @@ -1,6 +1,12 @@ -// @tags: [requires_non_retryable_commands] - // 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 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_non_retryable_commands, +// ] (function() { var coll = db.capped6; diff --git a/jstests/core/collation_plan_cache.js b/jstests/core/collation_plan_cache.js index b28747a88cf..d75c6f215b3 100644 --- a/jstests/core/collation_plan_cache.js +++ b/jstests/core/collation_plan_cache.js @@ -1,6 +1,12 @@ -// @tags: [does_not_support_stepdowns] - // 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, +// does_not_support_stepdowns, +// ] (function() { 'use strict'; @@ -240,4 +246,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/count10.js b/jstests/core/count10.js index 5e3bf10a8af..75838521527 100644 --- a/jstests/core/count10.js +++ b/jstests/core/count10.js @@ -1,6 +1,12 @@ -// @tags: [does_not_support_stepdowns] - // 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, +// does_not_support_stepdowns, +// ] t = db.count10; t.drop(); diff --git a/jstests/core/count_plan_summary.js b/jstests/core/count_plan_summary.js index d252c00919a..b928eb287fc 100644 --- a/jstests/core/count_plan_summary.js +++ b/jstests/core/count_plan_summary.js @@ -1,7 +1,12 @@ -// @tags: [does_not_support_stepdowns] - -// 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, +// does_not_support_stepdowns, +// ] var t = db.jstests_count_plan_summary; t.drop(); diff --git a/jstests/core/geo_s2cursorlimitskip.js b/jstests/core/geo_s2cursorlimitskip.js index dab23124e86..ab907919108 100644 --- a/jstests/core/geo_s2cursorlimitskip.js +++ b/jstests/core/geo_s2cursorlimitskip.js @@ -1,6 +1,13 @@ -// @tags: [does_not_support_stepdowns, requires_getmore] - // 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, +// does_not_support_stepdowns, +// requires_getmore, +// ] var testDB = db.getSiblingDB("geo_s2cursorlimitskip"); var t = testDB.geo_s2getmmm; diff --git a/jstests/core/getlog2.js b/jstests/core/getlog2.js index 987992dbd67..46514813732 100644 --- a/jstests/core/getlog2.js +++ b/jstests/core/getlog2.js @@ -1,6 +1,12 @@ -// @tags: [does_not_support_stepdowns] - // 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, +// does_not_support_stepdowns, +// ] // We turn off gossiping the mongo shell's clusterTime because it causes the slow command log // messages to get truncated since they'll exceed 512 characters. The truncated log messages will diff --git a/jstests/core/index_filter_commands.js b/jstests/core/index_filter_commands.js index aefc40c72de..45acbb10a49 100644 --- a/jstests/core/index_filter_commands.js +++ b/jstests/core/index_filter_commands.js @@ -1,7 +1,3 @@ -// Cannot implicitly shard accessed collections because of collection existing when none -// expected. -// @tags: [assumes_no_implicit_collection_creation_after_drop, does_not_support_stepdowns] - /** * Index Filter commands * @@ -10,20 +6,28 @@ * 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: [ + * # Cannot implicitly shard accessed collections because of collection existing when none + * # expected. + * assumes_no_implicit_collection_creation_after_drop, + * # 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, + * does_not_support_stepdowns, + * ] */ load("jstests/libs/analyze_plan.js"); diff --git a/jstests/core/index_stats.js b/jstests/core/index_stats.js index 4781484132f..69517475191 100644 --- a/jstests/core/index_stats.js +++ b/jstests/core/index_stats.js @@ -1,7 +1,15 @@ -// Cannot implicitly shard accessed collections because of following errmsg: A single -// update/delete on a sharded collection must contain an exact match on _id or contain the shard -// key. -// @tags: [assumes_unsharded_collection, does_not_support_stepdowns, requires_non_retryable_writes] +// @tags: [ +// # Cannot implicitly shard accessed collections because of following errmsg: A single +// # update/delete on a sharded collection must contain an exact match on _id or contain the shard +// # key. +// assumes_unsharded_collection, +// # 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, +// does_not_support_stepdowns, +// requires_non_retryable_writes, +// ] (function() { "use strict"; diff --git a/jstests/core/list_all_local_sessions.js b/jstests/core/list_all_local_sessions.js index 177afadf24a..10108341a06 100644 --- a/jstests/core/list_all_local_sessions.js +++ b/jstests/core/list_all_local_sessions.js @@ -1,8 +1,14 @@ -// Sessions are asynchronously flushed to disk, so a stepdown immediately after calling -// startSession may cause this test to fail to find the returned sessionId. -// @tags: [does_not_support_stepdowns] - // Basic tests for the $listLocalSessions {allUsers: true} aggregation stage. +// +// @tags: [ +// # This test attempts to start a session and find it using the $listLocalSessions 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, +// # Sessions are asynchronously flushed to disk, so a stepdown immediately after calling +// # startSession may cause this test to fail to find the returned sessionId. +// does_not_support_stepdowns, +// ] (function() { 'use strict'; diff --git a/jstests/core/list_local_sessions.js b/jstests/core/list_local_sessions.js index ee0d7eb759f..865777fde66 100644 --- a/jstests/core/list_local_sessions.js +++ b/jstests/core/list_local_sessions.js @@ -1,8 +1,14 @@ -// Sessions are asynchronously flushed to disk, so a stepdown immediately after calling -// startSession may cause this test to fail to find the returned sessionId. -// @tags: [does_not_support_stepdowns] - // Basic tests for the $listLocalSessions aggregation stage. +// +// @tags: [ +// # This test attempts to start a session and find it using the $listLocalSessions 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, +// # Sessions are asynchronously flushed to disk, so a stepdown immediately after calling +// # startSession may cause this test to fail to find the returned sessionId. +// does_not_support_stepdowns, +// ] (function() { 'use strict'; diff --git a/jstests/core/max_time_ms.js b/jstests/core/max_time_ms.js index 468a474aef3..f10ffb0bce1 100644 --- a/jstests/core/max_time_ms.js +++ b/jstests/core/max_time_ms.js @@ -1,6 +1,12 @@ -// @tags: [requires_getmore] - // 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_getmore, +// ] var t = db.max_time_ms; var exceededTimeLimit = 50; // ErrorCodes::ExceededTimeLimit diff --git a/jstests/core/mr_optim.js b/jstests/core/mr_optim.js index 19ec4e55b6b..d0fc6c8d371 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/notablescan.js b/jstests/core/notablescan.js index d6ff16fc1f5..69da1e9c547 100644 --- a/jstests/core/notablescan.js +++ b/jstests/core/notablescan.js @@ -1,6 +1,12 @@ -// @tags: [does_not_support_stepdowns] - // 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, +// does_not_support_stepdowns, +// ] t = db.test_notablescan; t.drop(); diff --git a/jstests/core/operation_latency_histogram.js b/jstests/core/operation_latency_histogram.js index 64d6bd6a33a..e0fc3dfaf6c 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 a03ec7fb08c..77a9e407f50 100644 --- a/jstests/core/plan_cache_clear.js +++ b/jstests/core/plan_cache_clear.js @@ -1,7 +1,13 @@ -// @tags: [does_not_support_stepdowns] - // 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, +// does_not_support_stepdowns, +// ] 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 e82f8f1cdd4..caa1cc9cd55 100644 --- a/jstests/core/plan_cache_list_plans.js +++ b/jstests/core/plan_cache_list_plans.js @@ -1,6 +1,12 @@ -// @tags: [does_not_support_stepdowns] - // 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, +// does_not_support_stepdowns, +// ] (function() { "use strict"; diff --git a/jstests/core/plan_cache_list_shapes.js b/jstests/core/plan_cache_list_shapes.js index f78021c54ea..8e873f4894c 100644 --- a/jstests/core/plan_cache_list_shapes.js +++ b/jstests/core/plan_cache_list_shapes.js @@ -1,7 +1,13 @@ -// @tags: [does_not_support_stepdowns] - // 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, +// does_not_support_stepdowns, +// ] 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 6ffbae8bed5..8f7399fea54 100644 --- a/jstests/core/plan_cache_shell_helpers.js +++ b/jstests/core/plan_cache_shell_helpers.js @@ -1,6 +1,12 @@ -// @tags: [does_not_support_stepdowns] - // 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, +// does_not_support_stepdowns, +// ] var t = db.jstests_plan_cache_shell_helpers; t.drop(); diff --git a/jstests/core/startup_log.js b/jstests/core/startup_log.js index aafae9bd8e4..b869221e7dd 100644 --- a/jstests/core/startup_log.js +++ b/jstests/core/startup_log.js @@ -1,3 +1,10 @@ +/** + * 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() { 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/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index 3480ad47816..99b5d1a7b2a 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -309,14 +309,19 @@ }, command: function(conn) { // First get and check a partial result for an aggregate command. - let aggCmd = {aggregate: "view", pipeline: [], cursor: {batchSize: 2}}; + let aggCmd = { + aggregate: "view", + pipeline: [{$sort: {_id: 1}}], + cursor: {batchSize: 2} + }; let res = conn.runCommand(aggCmd); assert.commandWorked(res, aggCmd); let cursor = res.cursor; assert.eq( cursor.ns, "test.view", "expected view namespace in cursor: " + tojson(cursor)); let expectedFirstBatch = [{_id: 1}, {_id: 2}]; - assert.eq(cursor.firstBatch, expectedFirstBatch, "find returned wrong firstBatch"); + assert.eq( + cursor.firstBatch, expectedFirstBatch, "aggregate returned wrong firstBatch"); // Then check correct execution of the killCursors command. let killCursorsCmd = {killCursors: "view", cursors: [cursor.id]}; 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/libs/override_methods/set_read_preference_secondary.js b/jstests/libs/override_methods/set_read_preference_secondary.js index d81532bf8d5..d1d26433c5c 100644 --- a/jstests/libs/override_methods/set_read_preference_secondary.js +++ b/jstests/libs/override_methods/set_read_preference_secondary.js @@ -22,6 +22,33 @@ "parallelCollectionScan", ]); + // This list of cursor-generating commands is incomplete. For example, "listCollections", + // "listIndexes", "parallelCollectionScan", and "repairCursor" are all missing from this list. + // If we ever add tests that attempt to run getMore or killCursors on cursors generated from + // those commands, then we should update the contents of this list and also handle any + // differences in the server's response format. + const kCursorGeneratingCommands = new Set(["aggregate", "find"]); + + const CursorTracker = (function() { + const kNoCursor = new NumberLong(0); + + const connectionsByCursorId = {}; + + return { + getConnectionUsedForCursor: function getConnectionUsedForCursor(cursorId) { + return (cursorId instanceof NumberLong) ? connectionsByCursorId[cursorId] + : undefined; + }, + + setConnectionUsedForCursor: function setConnectionUsedForCursor(cursorId, cursorConn) { + if (cursorId instanceof NumberLong && + !bsonBinaryEqual({_: cursorId}, {_: kNoCursor})) { + connectionsByCursorId[cursorId] = cursorConn; + } + }, + }; + })(); + function runCommandWithReadPreferenceSecondary( conn, dbName, commandName, commandObj, func, makeFuncArgs) { if (typeof commandObj !== "object" || commandObj === null) { @@ -36,6 +63,54 @@ commandName = Object.keys(commandObjUnwrapped)[0]; } + if (commandObj[commandName] === "system.profile") { + throw new Error("Cowardly refusing to run test with overridden read preference" + + " when it reads from a non-replicated collection: " + + tojson(commandObj)); + } + + if (conn.isReplicaSetConnection()) { + // When a "getMore" or "killCursors" command is issued on a replica set connection, we + // attempt to automatically route the command to the server the cursor(s) were + // originally established on. This makes it possible to use the + // set_read_preference_secondary.js override without needing to update calls of + // DB#runCommand() to explicitly track the connection that was used. If the connection + // is actually a direct connection to a mongod or mongos process, or if the cursor id + // cannot be found in the CursorTracker, then we'll fall back to using DBClientRS's + // server selection and send the operation to the current primary. It is possible that + // the test is trying to exercise the behavior around when an unknown cursor id is sent + // to the server. + if (commandName === "getMore") { + const cursorId = commandObjUnwrapped[commandName]; + const cursorConn = CursorTracker.getConnectionUsedForCursor(cursorId); + if (cursorConn !== undefined) { + return func.apply(cursorConn, makeFuncArgs(commandObj)); + } + } else if (commandName === "killCursors") { + const cursorIds = commandObjUnwrapped.cursors; + if (Array.isArray(cursorIds)) { + let cursorConn; + + for (let cursorId of cursorIds) { + const otherCursorConn = CursorTracker.getConnectionUsedForCursor(cursorId); + if (cursorConn === undefined) { + cursorConn = otherCursorConn; + } else if (otherCursorConn !== undefined) { + // We set 'cursorConn' back to undefined and break out of the loop so + // that we don't attempt to automatically route the "killCursors" + // command when there are cursors from different servers. + cursorConn = undefined; + break; + } + } + + if (cursorConn !== undefined) { + return func.apply(cursorConn, makeFuncArgs(commandObj)); + } + } + } + } + let shouldForceReadPreference = kCommandsSupportingReadPreference.has(commandName); if (OverrideHelpers.isAggregationWithOutStage(commandName, commandObjUnwrapped)) { // An aggregation with a $out stage must be sent to the primary. @@ -66,7 +141,18 @@ commandObj.$readPreference = kReadPreferenceSecondary; } - return func.apply(conn, makeFuncArgs(commandObj)); + const serverResponse = func.apply(conn, makeFuncArgs(commandObj)); + + if (conn.isReplicaSetConnection() && kCursorGeneratingCommands.has(commandName) && + serverResponse.ok === 1 && serverResponse.hasOwnProperty("cursor")) { + // We associate the cursor id returned by the server with the connection that was used + // to establish it so that we can attempt to automatically route subsequent "getMore" + // and "killCursors" commands. + CursorTracker.setConnectionUsedForCursor(serverResponse.cursor.id, + serverResponse._mongo); + } + + return serverResponse; } OverrideHelpers.prependOverrideInParallelShell( |