diff options
author | Max Hirschhorn <max.hirschhorn@mongodb.com> | 2018-01-30 19:45:42 -0500 |
---|---|---|
committer | Max Hirschhorn <max.hirschhorn@mongodb.com> | 2018-01-30 19:45:42 -0500 |
commit | 35b5b72146ca570b5c6fed8aaa7e891edf7d6a78 (patch) | |
tree | 982b7782084039d440c75911b51ac6568569faec | |
parent | 784e55320f72ab9b9ec8b4f766d4be0c1b5e4a5b (diff) | |
download | mongo-35b5b72146ca570b5c6fed8aaa7e891edf7d6a78.tar.gz |
SERVER-32522 Clean up {read,write}Concern and readPreference overrides.
Introduces OverrideHelpers object with convenience methods for
inspecting certain aggregation and map-reduce commands, as well as
overriding startParallelShell(), Mongo.prototype.runCommand(), and
Mongo.prototype.runCommandWithMetadata().
Also removes a number of tests that were incorrectly blacklisted from
the read_concern_majority_passthrough.yml and
read_concern_linearizable_passthrough.yml test suites.
59 files changed, 765 insertions, 526 deletions
diff --git a/buildscripts/resmokeconfig/suites/aggregation_read_concern_majority_passthrough.yml b/buildscripts/resmokeconfig/suites/aggregation_read_concern_majority_passthrough.yml index a56e5d9dba8..9924171d5da 100644 --- a/buildscripts/resmokeconfig/suites/aggregation_read_concern_majority_passthrough.yml +++ b/buildscripts/resmokeconfig/suites/aggregation_read_concern_majority_passthrough.yml @@ -7,18 +7,32 @@ selector: - jstests/aggregation/expressions/*.js - jstests/aggregation/sources/*/*.js exclude_files: - - jstests/aggregation/bugs/server18198.js # Uses a mocked mongo client to test read preference. - - jstests/aggregation/mongos_merge.js # Cannot specify write concern when - # secondaryThrottle is not set. - - jstests/aggregation/mongos_slaveok.js # Majority read on secondary requires afterOpTime. - - jstests/aggregation/shard_targeting.js # Cannot specify write concern when - # secondaryThrottle is not set. - - jstests/aggregation/sources/collStats/shard_host_info.js # Cannot specify write concern when - # secondaryThrottle is not set. - - jstests/aggregation/sources/facet/use_cases.js # Cannot specify write concern when - # secondaryThrottle is not set. - - jstests/aggregation/testSlave.js # Majority read on secondary requires afterOpTime. - - jstests/aggregation/sources/out/*.js # Cannot specify write concern when secondaryThrottle is not set. + # This test specifies a $out stage not as the last stage in the aggregation pipeline, causing a + # non-local readConcern to erroneously be sent with the command. + - jstests/aggregation/sources/out/required_last_position.js + # These tests fail due to the inability to specify a writeConcern when secondaryThrottle is not + # set as part of the moveChunk command. + - jstests/aggregation/mongos_merge.js + - jstests/aggregation/shard_targeting.js + - jstests/aggregation/sources/facet/use_cases.js + # These test fail because afterOpTime is required to guarantee a secondary has advanced its + # majority-committed snapshot. + - jstests/aggregation/mongos_slaveok.js + - jstests/aggregation/testSlave.js + exclude_with_any_tags: + ## + # The next three tags correspond to the special errors thrown by the + # set_read_and_write_concerns.js override when it refuses to replace the readConcern or + # writeConcern of a particular command. Above each tag are the message(s) that cause the tag to be + # warranted. + ## + # "Cowardly refusing to override read concern of command: ..." + - assumes_read_concern_unchanged + # "Cowardly refusing to override write concern of command: ..." + - assumes_write_concern_unchanged + # "Cowardly refusing to run test with overridden write concern when it uses a command that can + # only perform w=1 writes: ..." + - requires_eval_command executor: config: @@ -27,7 +41,9 @@ executor: TestData: defaultReadConcernLevel: majority enableMajorityReadConcern: '' - eval: "var testingReplication = true; load('jstests/libs/override_methods/set_read_and_write_concerns.js');" + eval: >- + var testingReplication = true; + load('jstests/libs/override_methods/set_read_and_write_concerns.js'); readMode: commands hooks: # The CheckReplDBHash hook waits until all operations have replicated to and have been applied @@ -45,5 +61,3 @@ executor: enableTestCommands: 1 numInitialSyncAttempts: 1 num_nodes: 2 - # Needs to be set for any ephemeral or no-journaling storage engine - write_concern_majority_journal_default: false diff --git a/buildscripts/resmokeconfig/suites/change_streams.yml b/buildscripts/resmokeconfig/suites/change_streams.yml index b7f75f66b5c..fa117f85419 100644 --- a/buildscripts/resmokeconfig/suites/change_streams.yml +++ b/buildscripts/resmokeconfig/suites/change_streams.yml @@ -3,6 +3,20 @@ test_kind: js_test selector: roots: - jstests/change_streams/**/*.js + exclude_with_any_tags: + ## + # The next three tags correspond to the special errors thrown by the + # set_read_and_write_concerns.js override when it refuses to replace the readConcern or + # writeConcern of a particular command. Above each tag are the message(s) that cause the tag to be + # warranted. + ## + # "Cowardly refusing to override read concern of command: ..." + - assumes_read_concern_unchanged + # "Cowardly refusing to override write concern of command: ..." + - assumes_write_concern_unchanged + # "Cowardly refusing to run test with overridden write concern when it uses a command that can + # only perform w=1 writes: ..." + - requires_eval_command executor: config: diff --git a/buildscripts/resmokeconfig/suites/change_streams_mongos_passthrough.yml b/buildscripts/resmokeconfig/suites/change_streams_mongos_passthrough.yml index 21fc4db91f8..b4bca33769f 100644 --- a/buildscripts/resmokeconfig/suites/change_streams_mongos_passthrough.yml +++ b/buildscripts/resmokeconfig/suites/change_streams_mongos_passthrough.yml @@ -7,6 +7,21 @@ selector: # This test exercises an internal detail of mongos<->mongod communication and is not expected # to work against a mongos. - jstests/change_streams/report_latest_observed_oplog_timestamp.js + exclude_with_any_tags: + ## + # The next three tags correspond to the special errors thrown by the + # set_read_and_write_concerns.js override when it refuses to replace the readConcern or + # writeConcern of a particular command. Above each tag are the message(s) that cause the tag to be + # warranted. + ## + # "Cowardly refusing to override read concern of command: ..." + - assumes_read_concern_unchanged + # "Cowardly refusing to override write concern of command: ..." + - assumes_write_concern_unchanged + # "Cowardly refusing to run test with overridden write concern when it uses a command that can + # only perform w=1 writes: ..." + - requires_eval_command + executor: config: shell_options: diff --git a/buildscripts/resmokeconfig/suites/change_streams_secondary_reads.yml b/buildscripts/resmokeconfig/suites/change_streams_secondary_reads.yml index c9b1a449b48..502cf002879 100644 --- a/buildscripts/resmokeconfig/suites/change_streams_secondary_reads.yml +++ b/buildscripts/resmokeconfig/suites/change_streams_secondary_reads.yml @@ -9,6 +9,27 @@ selector: - jstests/change_streams/only_wake_getmore_for_relevant_changes.js # This test is not expected to work when run against a mongos. - jstests/change_streams/report_latest_observed_oplog_timestamp.js + exclude_with_any_tags: + ## + # The next three tags correspond to the special errors thrown by the + # set_read_and_write_concerns.js override when it refuses to replace the readConcern or + # writeConcern of a particular command. Above each tag are the message(s) that cause the tag to be + # warranted. + ## + # "Cowardly refusing to override read concern of command: ..." + - assumes_read_concern_unchanged + # "Cowardly refusing to override write concern of command: ..." + - assumes_write_concern_unchanged + # "Cowardly refusing to run test with overridden write concern when it uses a command that can + # only perform w=1 writes: ..." + - requires_eval_command + ## + # The next tag corresponds to the special error thrown by the set_read_preference_secondary.js + # override when it refuses to replace the readPreference of a particular command. Above each tag + # are the message(s) that cause the tag to be warranted. + ## + # "Cowardly refusing to override read preference of command: ..." + - assumes_read_preference_unchanged executor: config: diff --git a/buildscripts/resmokeconfig/suites/change_streams_sharded_collections_passthrough.yml b/buildscripts/resmokeconfig/suites/change_streams_sharded_collections_passthrough.yml index 02c305d732d..86b444d5dc3 100644 --- a/buildscripts/resmokeconfig/suites/change_streams_sharded_collections_passthrough.yml +++ b/buildscripts/resmokeconfig/suites/change_streams_sharded_collections_passthrough.yml @@ -6,6 +6,21 @@ selector: exclude_files: # Exercises an internal detail of mongos<->mongod communication. Not expected to work on mongos. - jstests/change_streams/report_latest_observed_oplog_timestamp.js + exclude_with_any_tags: + ## + # The next three tags correspond to the special errors thrown by the + # set_read_and_write_concerns.js override when it refuses to replace the readConcern or + # writeConcern of a particular command. Above each tag are the message(s) that cause the tag to be + # warranted. + ## + # "Cowardly refusing to override read concern of command: ..." + - assumes_read_concern_unchanged + # "Cowardly refusing to override write concern of command: ..." + - assumes_write_concern_unchanged + # "Cowardly refusing to run test with overridden write concern when it uses a command that can + # only perform w=1 writes: ..." + - requires_eval_command + executor: config: shell_options: diff --git a/buildscripts/resmokeconfig/suites/read_concern_linearizable_passthrough.yml b/buildscripts/resmokeconfig/suites/read_concern_linearizable_passthrough.yml index b94fe6e00a6..3805d48c249 100644 --- a/buildscripts/resmokeconfig/suites/read_concern_linearizable_passthrough.yml +++ b/buildscripts/resmokeconfig/suites/read_concern_linearizable_passthrough.yml @@ -4,78 +4,30 @@ selector: roots: - jstests/core/**/*.js exclude_files: - # Tests that won't work with an injected 'linearizable' readConcern - # and/or an injected 'majority' writeConcern. Where a function is - # listed the reason is we don't have a reliable solution to override - # the write concern for that function. - - jstests/core/batch_write_command*.js # these tests use various write concerns - - jstests/core/bench_test*.js # benchRun() used for writes - - jstests/core/capped_update.js # uses godinsert and can't run under replication. - - jstests/core/crud_api.js # has specific w:0 tests - - jstests/core/error2.js # db.eval() used - - jstests/core/eval0.js # db.eval() used - - jstests/core/eval1.js # db.eval() used - - jstests/core/eval3.js # db.eval() used - - jstests/core/eval4.js # db.eval() used - - jstests/core/eval5.js # db.eval() used - - jstests/core/eval6.js # db.eval() used - - jstests/core/eval7.js # db.eval() used - - jstests/core/eval9.js # db.eval() used - - jstests/core/evala.js # db.eval() used - - jstests/core/evalb.js # db.eval() used - - jstests/core/evald.js # db.eval() used - - jstests/core/evale.js # db.eval() used - - jstests/core/evalg.js # db.eval() used - - jstests/core/eval_mr.js # db.eval() used - - jstests/core/eval_nolock.js # db.eval() used - - jstests/core/fsync.js # Uses fsyncLock() which prevents a linearizable read from writing - # an entry to the oplog. - - jstests/core/geo_s2cursorlimitskip.js # drops system.profile collection and counts ops. - - jstests/core/js3.js # db.dbEval() used - - jstests/core/js7.js # db.eval() used - - jstests/core/js9.js # db.eval() used - - jstests/core/max_time_ms.js # SERVER-27665 maxTimeNeverTimeOut failPoint. - - jstests/core/mr_merge.js # mr temp tables aren't replicated - - jstests/core/mr_merge2.js # mr temp tables aren't replicated - - jstests/core/mr_outreduce.js # mr temp tables aren't replicated - - jstests/core/mr_outreduce2.js # mr temp tables aren't replicated - - jstests/core/opcounters_active.js # off by n problem with opcounters - - jstests/core/opcounters_write_cmd.js # off by n problem with opcounters - - jstests/core/profile1.js # system.profile not replicated - - jstests/core/profile2.js # system.profile not replicated - - jstests/core/profile3.js # system.profile not replicated - - jstests/core/profile_agg.js # system.profile not replicated - - jstests/core/profile_count.js # system.profile not replicated - - jstests/core/profile_delete.js # system.profile not replicated - - jstests/core/profile_distinct.js # system.profile not replicated - - jstests/core/profile_find.js # system.profile not replicated - - jstests/core/profile_findandmodify.js # system.profile not replicated - - jstests/core/profile_geonear.js # system.profile not replicated - - jstests/core/profile_getmore.js # system.profile not replicated - - jstests/core/profile_group.js # system.profile not replicated - - jstests/core/profile_insert.js # system.profile not replicated - - jstests/core/profile_list_collections.js # system.profile not replicated - - jstests/core/profile_list_indexes.js # system.profile not replicated - - jstests/core/profile_mapreduce.js # system.profile not replicated - - jstests/core/profile_parallel_collection_scan.js # system.profile not replicated - - jstests/core/profile_repair_cursor.js # system.profile not replicated - - jstests/core/profile_sampling.js # system.profile not replicated - - jstests/core/profile_update.js # system.profile not replicated - - jstests/core/read_after_optime.js # verifies read after optime fails on standalone - - jstests/core/remove8.js # db.eval() used - - jstests/core/rename4.js # db.eval() used - - jstests/core/shell1.js # tests setSlaveOk() variations on standalone mongod - - jstests/core/shellkillop.js # db.eval() used - - jstests/core/shell_writeconcern.js # checks write concern shell helpers - - jstests/core/storefunc.js # db.eval() used - - jstests/core/write_result.js # Tests invalid writeConcern, we shouldn't override. - # Tests that need triaging & remediation | blacklist decision - # Comments list possible problem point under review. - - jstests/core/capped6.js # Uses captrunc test command. - - jstests/core/stages_delete.js # Uses stageDebug command for deletes. - - jstests/core/list_all_local_cursors.js # collectionless aggregation stage - - jstests/core/list_all_local_sessions.js # collectionless aggregation stage - - jstests/core/list_local_sessions.js # collectionless aggregation stage + # These tests are not expected to pass with replica-sets: + - jstests/core/dbadmin.js + - jstests/core/opcounters_write_cmd.js + - jstests/core/read_after_optime.js + - jstests/core/capped_update.js + # These tests use benchRun(), which isn't configured to use the overridden writeConcern. + - jstests/core/bench_test*.js + # fsync.js runs the {fsync: 1, lock: 1} command, which prevents a linearizable read from writing + # an entry to the oplog. + - jstests/core/fsync.js + exclude_with_any_tags: + ## + # The next three tags correspond to the special errors thrown by the + # set_read_and_write_concerns.js override when it refuses to replace the readConcern or + # writeConcern of a particular command. Above each tag are the message(s) that cause the tag to be + # warranted. + ## + # "Cowardly refusing to override read concern of command: ..." + - assumes_read_concern_unchanged + # "Cowardly refusing to override write concern of command: ..." + - assumes_write_concern_unchanged + # "Cowardly refusing to run test with overridden write concern when it uses a command that can + # only perform w=1 writes: ..." + - requires_eval_command executor: config: @@ -83,7 +35,9 @@ executor: global_vars: TestData: defaultReadConcernLevel: linearizable - eval: "var testingReplication = true; load('jstests/libs/override_methods/set_read_and_write_concerns.js');" + eval: >- + var testingReplication = true; + load('jstests/libs/override_methods/set_read_and_write_concerns.js'); readMode: commands hooks: # The CheckReplDBHash hook waits until all operations have replicated to and have been applied @@ -103,4 +57,3 @@ executor: enableTestCommands: 1 numInitialSyncAttempts: 1 num_nodes: 2 - write_concern_majority_journal_default: false diff --git a/buildscripts/resmokeconfig/suites/read_concern_majority_passthrough.yml b/buildscripts/resmokeconfig/suites/read_concern_majority_passthrough.yml index de9af2574df..68db9a3d53e 100644 --- a/buildscripts/resmokeconfig/suites/read_concern_majority_passthrough.yml +++ b/buildscripts/resmokeconfig/suites/read_concern_majority_passthrough.yml @@ -4,75 +4,27 @@ selector: roots: - jstests/core/**/*.js exclude_files: - # Tests that won't work with an injected 'majority' readConcern - # and/or an injected 'majority' writeConcern. Where a function is - # listed the reason is we don't have a reliable solution to override - # the write concern for that function. - - jstests/core/batch_write_command*.js # these tests use various write concerns - - jstests/core/bench_test*.js # benchRun() used for writes - - jstests/core/capped_update.js # uses godinsert and can't run under replication. - - jstests/core/crud_api.js # has specific w:0 tests - - jstests/core/error2.js # db.eval() used - - jstests/core/eval0.js # db.eval() used - - jstests/core/eval1.js # db.eval() used - - jstests/core/eval3.js # db.eval() used - - jstests/core/eval4.js # db.eval() used - - jstests/core/eval5.js # db.eval() used - - jstests/core/eval6.js # db.eval() used - - jstests/core/eval7.js # db.eval() used - - jstests/core/eval9.js # db.eval() used - - jstests/core/evala.js # db.eval() used - - jstests/core/evalb.js # db.eval() used - - jstests/core/evald.js # db.eval() used - - jstests/core/evale.js # db.eval() used - - jstests/core/evalg.js # db.eval() used - - jstests/core/eval_mr.js # db.eval() used - - jstests/core/eval_nolock.js # db.eval() used - - jstests/core/geo_s2cursorlimitskip.js # drops system.profile collection and counts ops. - - jstests/core/js3.js # db.dbEval() used - - jstests/core/js7.js # db.eval() used - - jstests/core/js9.js # db.eval() used - - jstests/core/mr_merge.js # mr temp tables aren't replicated - - jstests/core/mr_merge2.js # mr temp tables aren't replicated - - jstests/core/mr_outreduce.js # mr temp tables aren't replicated - - jstests/core/mr_outreduce2.js # mr temp tables aren't replicated - - jstests/core/opcounters_active.js # off by n problem with opcounters - - jstests/core/opcounters_write_cmd.js # off by n problem with opcounters - - jstests/core/profile1.js # system.profile not replicated - - jstests/core/profile2.js # system.profile not replicated - - jstests/core/profile3.js # system.profile not replicated - - jstests/core/profile_agg.js # system.profile not replicated - - jstests/core/profile_count.js # system.profile not replicated - - jstests/core/profile_delete.js # system.profile not replicated - - jstests/core/profile_distinct.js # system.profile not replicated - - jstests/core/profile_find.js # system.profile not replicated - - jstests/core/profile_findandmodify.js # system.profile not replicated - - jstests/core/profile_geonear.js # system.profile not replicated - - jstests/core/profile_getmore.js # system.profile not replicated - - jstests/core/profile_group.js # system.profile not replicated - - jstests/core/profile_insert.js # system.profile not replicated - - jstests/core/profile_list_collections.js # system.profile not replicated - - jstests/core/profile_list_indexes.js # system.profile not replicated - - jstests/core/profile_mapreduce.js # system.profile not replicated - - jstests/core/profile_parallel_collection_scan.js # system.profile not replicated - - jstests/core/profile_repair_cursor.js # system.profile not replicated - - jstests/core/profile_sampling.js # system.profile not replicated - - jstests/core/profile_update.js # system.profile not replicated - - jstests/core/read_after_optime.js # verifies read after optime fails on standalone - - jstests/core/remove8.js # db.eval() used - - jstests/core/rename4.js # db.eval() used - - jstests/core/shell1.js # tests setSlaveOk() variations on standalone mongod - - jstests/core/shellkillop.js # db.eval() used - - jstests/core/shell_writeconcern.js # checks write concern shell helpers - - jstests/core/storefunc.js # db.eval() used - - jstests/core/write_result.js # Tests invalid writeConcern, we shouldn't override. - # Tests that need triaging & remediation | blacklist decision - # Comments list possible problem point under review. - - jstests/core/capped6.js # Uses captrunc test command. - - jstests/core/stages_delete.js # Uses stageDebug command for deletes. - - jstests/core/list_all_local_cursors.js # collectionless aggregation stage - - jstests/core/list_all_local_sessions.js # collectionless aggregation stage - - jstests/core/list_local_sessions.js # collectionless aggregation stage + # These tests are not expected to pass with replica-sets: + - jstests/core/dbadmin.js + - jstests/core/opcounters_write_cmd.js + - jstests/core/read_after_optime.js + - jstests/core/capped_update.js + # These tests use benchRun(), which isn't configured to use the overridden writeConcern. + - jstests/core/bench_test*.js + exclude_with_any_tags: + ## + # The next three tags correspond to the special errors thrown by the + # set_read_and_write_concerns.js override when it refuses to replace the readConcern or + # writeConcern of a particular command. Above each tag are the message(s) that cause the tag to be + # warranted. + ## + # "Cowardly refusing to override read concern of command: ..." + - assumes_read_concern_unchanged + # "Cowardly refusing to override write concern of command: ..." + - assumes_write_concern_unchanged + # "Cowardly refusing to run test with overridden write concern when it uses a command that can + # only perform w=1 writes: ..." + - requires_eval_command executor: config: @@ -80,7 +32,9 @@ executor: global_vars: TestData: defaultReadConcernLevel: majority - eval: "var testingReplication = true; load('jstests/libs/override_methods/set_read_and_write_concerns.js');" + eval: >- + var testingReplication = true; + load('jstests/libs/override_methods/set_read_and_write_concerns.js'); readMode: commands hooks: # The CheckReplDBHash hook waits until all operations have replicated to and have been applied @@ -101,5 +55,3 @@ executor: writePeriodicNoops: 1 enableMajorityReadConcern: '' num_nodes: 2 - # Needs to be set for any ephemeral or no-journaling storage engine - write_concern_majority_journal_default: false diff --git a/buildscripts/resmokeconfig/suites/retryable_writes_jscore_stepdown_passthrough.yml b/buildscripts/resmokeconfig/suites/retryable_writes_jscore_stepdown_passthrough.yml index e86873f2376..c003c2ad3ff 100644 --- a/buildscripts/resmokeconfig/suites/retryable_writes_jscore_stepdown_passthrough.yml +++ b/buildscripts/resmokeconfig/suites/retryable_writes_jscore_stepdown_passthrough.yml @@ -59,25 +59,21 @@ selector: - jstests/core/validate_cmd_ns.js # Calls _exec() directly, not retryable. exclude_with_any_tags: - - cannot_inject_read_write_concern - + ## # The next four tags correspond to the special errors thrown by the auto_retry_on_network_error.js - # override when it refuses to run a certain command. Above each tag are the messages that - # warrant it. - + # override when it refuses to run a certain command. Above each tag are the message(s) that cause + # the tag to be warranted. + ## # "Refusing to run a test that issues a getMore command since if a network error occurs during # it then we won't know whether the cursor was advanced or not" - requires_getmore - # "Refusing to run a test that issues non-retryable write operations since the test likely makes # assertions on the write results and can lead to spurious failures if a network error occurs" - requires_non_retryable_writes - # "Refusing to run a test that issues commands that are not blindly retryable" # "Refusing to run a test that issues an aggregation command with $out because it is not # retryable" - requires_non_retryable_commands - # "Refusing to run a test that issues commands that may return different values after a failover" # "Refusing to run a test that issues an aggregation command with explain because it may return # incomplete results" @@ -86,6 +82,19 @@ selector: # "Refusing to run a test that issues a mapReduce command, because it calls std::terminate() if # interrupted by a stepdown" - does_not_support_stepdowns + ## + # The next three tags correspond to the special errors thrown by the + # set_read_and_write_concerns.js override when it refuses to replace the readConcern or + # writeConcern of a particular command. Above each tag are the message(s) that cause the tag to be + # warranted. + ## + # "Cowardly refusing to override read concern of command: ..." + - assumes_read_concern_unchanged + # "Cowardly refusing to override write concern of command: ..." + - assumes_write_concern_unchanged + # "Cowardly refusing to run test with overridden write concern when it uses a command that can + # only perform w=1 writes: ..." + - requires_eval_command executor: config: diff --git a/jstests/change_streams/report_latest_observed_oplog_timestamp.js b/jstests/change_streams/report_latest_observed_oplog_timestamp.js index e75c50794a1..45abd52ada9 100644 --- a/jstests/change_streams/report_latest_observed_oplog_timestamp.js +++ b/jstests/change_streams/report_latest_observed_oplog_timestamp.js @@ -39,7 +39,7 @@ // in the stream. jsTestLog("Adding documents to collection."); for (let i = 1; i < batchSize * 2; i++) { - assert.writeOK(cursorCollection.insert({_id: i}, {writeConcern: {w: 1}})); + assert.writeOK(cursorCollection.insert({_id: i})); } // Look at one batch's worth. diff --git a/jstests/core/batch_write_command_delete.js b/jstests/core/batch_write_command_delete.js index 85098662d6c..37a65750524 100644 --- a/jstests/core/batch_write_command_delete.js +++ b/jstests/core/batch_write_command_delete.js @@ -1,7 +1,12 @@ // 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, requires_non_retryable_writes] +// +// @tags: [ +// assumes_unsharded_collection, +// assumes_write_concern_unchanged, +// requires_non_retryable_writes, +// ] // // 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 cf2907c0675..962a4eb37ad 100644 --- a/jstests/core/batch_write_command_insert.js +++ b/jstests/core/batch_write_command_insert.js @@ -1,6 +1,10 @@ // Cannot implicitly shard accessed collections because of not being able to create unique index // using hashed shard key pattern. -// @tags: [cannot_create_unique_index_when_using_hashed_shard_key] +// +// @tags: [ +// assumes_write_concern_unchanged, +// cannot_create_unique_index_when_using_hashed_shard_key, +// ] // // 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 8a37d77067e..24f86256d98 100644 --- a/jstests/core/batch_write_command_update.js +++ b/jstests/core/batch_write_command_update.js @@ -1,7 +1,11 @@ // 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, requires_non_retryable_writes] +// @tags: [ +// assumes_unsharded_collection, +// assumes_write_concern_unchanged, +// requires_non_retryable_writes, +// ] // // Ensures that mongod respects the batch write protocols for updates 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/commands_that_do_not_write_do_not_accept_wc.js b/jstests/core/commands_that_do_not_write_do_not_accept_wc.js index a87a38d8ae4..e2e4e55a51b 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 @@ -1,9 +1,12 @@ -// @tags: [does_not_support_stepdowns] - /** * 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, + * does_not_support_stepdowns, + * ] */ (function() { diff --git a/jstests/core/constructors.js b/jstests/core/constructors.js index 52ce8f04065..4d6f8b498cc 100644 --- a/jstests/core/constructors.js +++ b/jstests/core/constructors.js @@ -1,6 +1,10 @@ -// @tags: [does_not_support_stepdowns, requires_non_retryable_commands] - // Tests to see what validity checks are done for 10gen specific object construction +// +// @tags: [ +// does_not_support_stepdowns, +// requires_eval_command, +// requires_non_retryable_commands, +// ] // 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/crud_api.js b/jstests/core/crud_api.js index abf40389a43..3a1f7418305 100644 --- a/jstests/core/crud_api.js +++ b/jstests/core/crud_api.js @@ -1,7 +1,11 @@ // 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] +// +// @tags: [ +// assumes_unsharded_collection, +// assumes_write_concern_unchanged, +// ] (function() { "use strict"; diff --git a/jstests/core/dropdb_race.js b/jstests/core/dropdb_race.js index 9366df68a9b..40557dc8551 100644 --- a/jstests/core/dropdb_race.js +++ b/jstests/core/dropdb_race.js @@ -1,6 +1,9 @@ -// @tags: [does_not_support_stepdowns] - // test dropping a db with simultaneous commits +// +// @tags: [ +// assumes_write_concern_unchanged, +// does_not_support_stepdowns, +// ] m = db.getMongo(); baseName = "jstests_dur_droprace"; diff --git a/jstests/core/error2.js b/jstests/core/error2.js index 7c26f5688d7..6674d5663c6 100644 --- a/jstests/core/error2.js +++ b/jstests/core/error2.js @@ -1,6 +1,8 @@ -// @tags: [requires_non_retryable_commands] - // Test that client gets stack trace on failed invoke +// @tags: [ +// requires_eval_command, +// requires_non_retryable_commands, +// ] f = db.jstests_error2; diff --git a/jstests/core/eval0.js b/jstests/core/eval0.js index 4592f3c9d60..7e075feb2d5 100644 --- a/jstests/core/eval0.js +++ b/jstests/core/eval0.js @@ -1,4 +1,7 @@ -// @tags: [requires_non_retryable_commands] +// @tags: [ +// requires_eval_command, +// requires_non_retryable_commands, +// ] assert.writeOK(db.evalprep.insert({}), "db must exist for eval to succeed"); db.evalprep.drop(); diff --git a/jstests/core/eval1.js b/jstests/core/eval1.js index a18b6176c5c..fca8ef7c0ec 100644 --- a/jstests/core/eval1.js +++ b/jstests/core/eval1.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.eval1; t.drop(); diff --git a/jstests/core/eval3.js b/jstests/core/eval3.js index eacb6d70203..6c5e8b7c56d 100644 --- a/jstests/core/eval3.js +++ b/jstests/core/eval3.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.eval3; t.drop(); diff --git a/jstests/core/eval4.js b/jstests/core/eval4.js index b7d19a4ac3b..74d25b10184 100644 --- a/jstests/core/eval4.js +++ b/jstests/core/eval4.js @@ -1,7 +1,11 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands, -// requires_non_retryable_writes] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// requires_non_retryable_writes, +// ] t = db.eval4; t.drop(); diff --git a/jstests/core/eval5.js b/jstests/core/eval5.js index fc495d86403..f3d30c49779 100644 --- a/jstests/core/eval5.js +++ b/jstests/core/eval5.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.eval5; t.drop(); diff --git a/jstests/core/eval6.js b/jstests/core/eval6.js index 751bdbf9e34..d8ad52e95d5 100644 --- a/jstests/core/eval6.js +++ b/jstests/core/eval6.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.eval6; t.drop(); diff --git a/jstests/core/eval7.js b/jstests/core/eval7.js index 32c37139e53..751779dba29 100644 --- a/jstests/core/eval7.js +++ b/jstests/core/eval7.js @@ -1,4 +1,7 @@ -// @tags: [requires_non_retryable_commands] +// @tags: [ +// requires_eval_command, +// requires_non_retryable_commands, +// ] 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 2f015b46485..ce6f909dd2f 100644 --- a/jstests/core/eval9.js +++ b/jstests/core/eval9.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] 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 9c3ac3c7efe..33b56039321 100644 --- a/jstests/core/eval_mr.js +++ b/jstests/core/eval_mr.js @@ -1,9 +1,13 @@ -// Cannot implicitly shard accessed collections because of following errmsg: Cannot output to a -// non-sharded collection because sharded collection exists already. -// @tags: [assumes_unsharded_collection, does_not_support_stepdowns, -// requires_non_retryable_commands] - // Test that the eval command can't be used to invoke the mapReduce command. SERVER-17889. +// +// @tags: [ +// # Cannot implicitly shard accessed collections because of following errmsg: Cannot output to a +// # non-sharded collection because sharded collection exists already. +// assumes_unsharded_collection, +// does_not_support_stepdowns, +// requires_eval_command, +// requires_non_retryable_commands, +// ] (function() { "use strict"; db.eval_mr.drop(); diff --git a/jstests/core/eval_nolock.js b/jstests/core/eval_nolock.js index 8ae7f41f815..8ff0738110e 100644 --- a/jstests/core/eval_nolock.js +++ b/jstests/core/eval_nolock.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.eval_nolock; t.drop(); diff --git a/jstests/core/evala.js b/jstests/core/evala.js index 00c2b548636..2d3187fdcc1 100644 --- a/jstests/core/evala.js +++ b/jstests/core/evala.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.evala; t.drop(); diff --git a/jstests/core/evalb.js b/jstests/core/evalb.js index a3d9251af57..d92573eef1c 100644 --- a/jstests/core/evalb.js +++ b/jstests/core/evalb.js @@ -1,7 +1,11 @@ -// @tags: [does_not_support_stepdowns, requires_non_retryable_commands] - // 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: [ +// does_not_support_stepdowns, +// requires_eval_command, +// requires_non_retryable_commands, +// ] // 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 b4317c4a24a..bb81d08dfb0 100644 --- a/jstests/core/evald.js +++ b/jstests/core/evald.js @@ -1,7 +1,11 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, does_not_support_stepdowns, -// requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// does_not_support_stepdowns, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.jstests_evald; t.drop(); diff --git a/jstests/core/evale.js b/jstests/core/evale.js index 8e20ee5177e..659b83fd339 100644 --- a/jstests/core/evale.js +++ b/jstests/core/evale.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.jstests_evale; t.drop(); diff --git a/jstests/core/evalg.js b/jstests/core/evalg.js index dcb5b98f000..536fdcadb81 100644 --- a/jstests/core/evalg.js +++ b/jstests/core/evalg.js @@ -1,8 +1,12 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] - // SERVER-17499: Test behavior of getMore on aggregation cursor under eval command. +// +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] 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 3881c92be80..31ea47ce891 100644 --- a/jstests/core/evalh.js +++ b/jstests/core/evalh.js @@ -1,7 +1,10 @@ -// @tags: [requires_non_retryable_commands] - /** * Test that db.eval does not support auth. + * + * @tags: [ + * requires_eval_command, + * requires_non_retryable_commands, + * ] */ (function() { 'use strict'; diff --git a/jstests/core/evalj.js b/jstests/core/evalj.js index fa5e3305501..e58adf3c040 100644 --- a/jstests/core/evalj.js +++ b/jstests/core/evalj.js @@ -1,4 +1,7 @@ -// @tags: [requires_non_retryable_commands] +// @tags: [ +// requires_eval_command, +// requires_non_retryable_commands, +// ] (function() { "use strict"; diff --git a/jstests/core/explain_agg_write_concern.js b/jstests/core/explain_agg_write_concern.js index e007eb5d6d3..84f83cb0755 100644 --- a/jstests/core/explain_agg_write_concern.js +++ b/jstests/core/explain_agg_write_concern.js @@ -1,7 +1,12 @@ // Cannot implicitly shard accessed collections because unsupported use of sharded collection // for output collection of aggregation pipeline. -// @tags: [assumes_unsharded_collection, does_not_support_stepdowns, -// requires_non_retryable_commands] +// +// @tags: [ +// assumes_unsharded_collection, +// assumes_write_concern_unchanged, +// does_not_support_stepdowns, +// requires_non_retryable_commands, +// ] /** * Tests related to the aggregate commands behavior with writeConcern and writeConcern + explain. diff --git a/jstests/core/fsync.js b/jstests/core/fsync.js index 9e472dc640f..c5ba3fe13a0 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/geo_update_btree.js b/jstests/core/geo_update_btree.js index d40c5ad8719..6aa12733654 100644 --- a/jstests/core/geo_update_btree.js +++ b/jstests/core/geo_update_btree.js @@ -1,6 +1,9 @@ -// @tags: [requires_non_retryable_writes] - // Tests whether the geospatial search is stable under btree updates +// +// @tags: [ +// assumes_write_concern_unchanged, +// requires_non_retryable_writes, +// ] var coll = db.getCollection("jstests_geo_update_btree"); coll.drop(); diff --git a/jstests/core/js3.js b/jstests/core/js3.js index db7668243a3..d22a579141b 100644 --- a/jstests/core/js3.js +++ b/jstests/core/js3.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.jstests_js3; diff --git a/jstests/core/js7.js b/jstests/core/js7.js index 78a84cafa95..a9f0f703c30 100644 --- a/jstests/core/js7.js +++ b/jstests/core/js7.js @@ -1,4 +1,7 @@ -// @tags: [requires_non_retryable_commands] +// @tags: [ +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.jstests_js7; t.drop(); diff --git a/jstests/core/js9.js b/jstests/core/js9.js index c26c3544eb3..fdeb2615944 100644 --- a/jstests/core/js9.js +++ b/jstests/core/js9.js @@ -1,6 +1,10 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// ] c = db.jstests_js9; c.drop(); diff --git a/jstests/core/json_schema/misc_validation.js b/jstests/core/json_schema/misc_validation.js index 2e6a0eed6b0..d003e9af7ca 100644 --- a/jstests/core/json_schema/misc_validation.js +++ b/jstests/core/json_schema/misc_validation.js @@ -13,8 +13,12 @@ * - doTxn * - $elemMatch projection * - * @tags: [assumes_no_implicit_collection_creation_after_drop, requires_non_retryable_commands, - * requires_non_retryable_writes] + * @tags: [ + * assumes_no_implicit_collection_creation_after_drop, + * requires_eval_command, + * requires_non_retryable_commands, + * requires_non_retryable_writes, + * ] */ (function() { "use strict"; diff --git a/jstests/core/profile_insert.js b/jstests/core/profile_insert.js index 41d1b4e9b03..6c32162701c 100644 --- a/jstests/core/profile_insert.js +++ b/jstests/core/profile_insert.js @@ -1,6 +1,9 @@ -// @tags: [does_not_support_stepdowns] - // Confirms that profiled insert execution contains all expected metrics with proper values. +// +// @tags: [ +// assumes_write_concern_unchanged, +// does_not_support_stepdowns, +// ] (function() { "use strict"; diff --git a/jstests/core/recursion.js b/jstests/core/recursion.js index 4a0488a723d..0114b72515c 100644 --- a/jstests/core/recursion.js +++ b/jstests/core/recursion.js @@ -1,7 +1,11 @@ -// @tags: [does_not_support_stepdowns, requires_non_retryable_commands] - -// 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: [ +// does_not_support_stepdowns, +// requires_eval_command, +// requires_non_retryable_commands, +// ] (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 d45891faac6..ab82a915449 100644 --- a/jstests/core/remove8.js +++ b/jstests/core/remove8.js @@ -1,7 +1,11 @@ -// Cannot implicitly shard accessed collections because unsupported use of sharded collection -// from db.eval. -// @tags: [assumes_unsharded_collection, requires_non_retryable_commands, -// requires_non_retryable_writes] +// @tags: [ +// # Cannot implicitly shard accessed collections because unsupported use of sharded collection +// # from db.eval. +// assumes_unsharded_collection, +// requires_eval_command, +// requires_non_retryable_commands, +// requires_non_retryable_writes, +// ] t = db.remove8; t.drop(); diff --git a/jstests/core/rename4.js b/jstests/core/rename4.js index 2879140ed5c..e1e9dbe2a9b 100644 --- a/jstests/core/rename4.js +++ b/jstests/core/rename4.js @@ -1,4 +1,7 @@ -// @tags: [requires_non_retryable_writes] +// @tags: [ +// requires_eval_command, +// requires_non_retryable_commands, +// ] t = db.jstests_rename4; t.drop(); diff --git a/jstests/core/shell_writeconcern.js b/jstests/core/shell_writeconcern.js index 6d3680dee83..26d68304c63 100644 --- a/jstests/core/shell_writeconcern.js +++ b/jstests/core/shell_writeconcern.js @@ -1,7 +1,11 @@ // 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, cannot_inject_read_write_concern] +// +// @tags: [ +// assumes_unsharded_collection, +// assumes_write_concern_unchanged, +// ] "use strict"; // check that shell writeconcern work correctly diff --git a/jstests/core/stages_delete.js b/jstests/core/stages_delete.js index 1d33d778acc..46d7f316212 100644 --- a/jstests/core/stages_delete.js +++ b/jstests/core/stages_delete.js @@ -1,4 +1,9 @@ -// @tags: [does_not_support_stepdowns] +// @tags: [ +// # This test attempts to remove documents using the stageDebug command, which doesn't support +// # specifying a writeConcern. +// assumes_write_concern_unchanged, +// does_not_support_stepdowns, +// ] // Test basic delete stage functionality. var coll = db.stages_delete; diff --git a/jstests/core/storefunc.js b/jstests/core/storefunc.js index 960763753ed..42caed6f861 100644 --- a/jstests/core/storefunc.js +++ b/jstests/core/storefunc.js @@ -1,4 +1,8 @@ -// @tags: [requires_non_retryable_commands, requires_non_retryable_writes] +// @tags: [ +// requires_eval_command, +// requires_non_retryable_commands, +// requires_non_retryable_writes, +// ] // Use a private sister database to avoid conflicts with other tests that use system.js var testdb = db.getSisterDB("storefunc"); diff --git a/jstests/core/update_multi5.js b/jstests/core/update_multi5.js index 6c3ae9265a8..a1be71cd652 100644 --- a/jstests/core/update_multi5.js +++ b/jstests/core/update_multi5.js @@ -9,8 +9,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/write_result.js b/jstests/core/write_result.js index 9ccef44458d..dc641501815 100644 --- a/jstests/core/write_result.js +++ b/jstests/core/write_result.js @@ -1,7 +1,12 @@ // 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, requires_non_retryable_writes] +// +// @tags: [ +// assumes_unsharded_collection, +// assumes_write_concern_unchanged, +// requires_non_retryable_writes, +// ] // // Tests the behavior of single writes using write commands diff --git a/jstests/libs/override_methods/auto_retry_on_network_error.js b/jstests/libs/override_methods/auto_retry_on_network_error.js index f7f2138da28..14aa83a0a7f 100644 --- a/jstests/libs/override_methods/auto_retry_on_network_error.js +++ b/jstests/libs/override_methods/auto_retry_on_network_error.js @@ -11,6 +11,7 @@ (function() { "use strict"; + load("jstests/libs/override_methods/override_helpers.js"); load("jstests/libs/retryable_writes_util.js"); const kMaxNumRetries = 3; @@ -350,20 +351,8 @@ } while (numRetries >= 0); } - const startParallelShellOriginal = startParallelShell; - - startParallelShell = function(jsCode, port, noConnect) { - let newCode; - const overridesFile = "jstests/libs/override_methods/auto_retry_on_network_error.js"; - if (typeof(jsCode) === "function") { - // Load the override file and immediately invoke the supplied function. - newCode = `load("${overridesFile}"); (${jsCode})();`; - } else { - newCode = `load("${overridesFile}"); ${jsCode};`; - } - - return startParallelShellOriginal(newCode, port, noConnect); - }; + OverrideHelpers.prependOverrideInParallelShell( + "jstests/libs/override_methods/auto_retry_on_network_error.js"); const connectOriginal = connect; diff --git a/jstests/libs/override_methods/enable_causal_consistency.js b/jstests/libs/override_methods/enable_causal_consistency.js index f932304df7a..9e8a4bdde59 100644 --- a/jstests/libs/override_methods/enable_causal_consistency.js +++ b/jstests/libs/override_methods/enable_causal_consistency.js @@ -4,20 +4,11 @@ (function() { "use strict"; + load("jstests/libs/override_methods/override_helpers.js"); + db.getMongo().setCausalConsistency(); db.getMongo().setReadPref("secondary"); - var originalStartParallelShell = startParallelShell; - startParallelShell = function(jsCode, port, noConnect) { - var newCode; - var overridesFile = "jstests/libs/override_methods/enable_causal_consistency.js"; - if (typeof(jsCode) === "function") { - // Load the override file and immediately invoke the supplied function. - newCode = `load("${overridesFile}"); (${jsCode})();`; - } else { - newCode = `load("${overridesFile}"); ${jsCode};`; - } - - return originalStartParallelShell(newCode, port, noConnect); - }; + OverrideHelpers.prependOverrideInParallelShell( + "jstests/libs/override_methods/enable_causal_consistency.js"); })(); diff --git a/jstests/libs/override_methods/enable_sessions.js b/jstests/libs/override_methods/enable_sessions.js index ebb78f703c3..2d304927c35 100644 --- a/jstests/libs/override_methods/enable_sessions.js +++ b/jstests/libs/override_methods/enable_sessions.js @@ -4,6 +4,8 @@ (function() { "use strict"; + load("jstests/libs/override_methods/override_helpers.js"); + var runCommandOriginal = Mongo.prototype.runCommand; var runCommandWithMetadataOriginal = Mongo.prototype.runCommandWithMetadata; var getDBOriginal = Mongo.prototype.getDB; @@ -18,19 +20,8 @@ db = driverSession.getDatabase(db.getName()); sessionMap.set(db.getMongo(), driverSession); - var originalStartParallelShell = startParallelShell; - startParallelShell = function(jsCode, port, noConnect) { - var newCode; - var overridesFile = "jstests/libs/override_methods/enable_sessions.js"; - if (typeof(jsCode) === "function") { - // Load the override file and immediately invoke the supplied function. - newCode = `load("${overridesFile}"); (${jsCode})();`; - } else { - newCode = `load("${overridesFile}"); ${jsCode};`; - } - - return originalStartParallelShell(newCode, port, noConnect); - }; + OverrideHelpers.prependOverrideInParallelShell( + "jstests/libs/override_methods/enable_sessions.js"); function startSession(conn) { const driverSession = conn.startSession(sessionOptions); diff --git a/jstests/libs/override_methods/override_helpers.js b/jstests/libs/override_methods/override_helpers.js new file mode 100644 index 00000000000..437f1a07669 --- /dev/null +++ b/jstests/libs/override_methods/override_helpers.js @@ -0,0 +1,109 @@ +/** + * The OverrideHelpers object defines convenience methods for overriding commands and functions in + * the mongo shell. + */ +var OverrideHelpers = (function() { + "use strict"; + + function makeIsAggregationWithFirstStage(stageName) { + return function(commandName, commandObj) { + if (commandName !== "aggregate" || typeof commandObj !== "object" || + commandObj === null) { + return false; + } + + if (!Array.isArray(commandObj.pipeline) || commandObj.pipeline.length === 0) { + return false; + } + + const firstStage = commandObj.pipeline[0]; + if (typeof firstStage !== "object" || firstStage === null) { + return false; + } + + return Object.keys(firstStage)[0] === stageName; + }; + } + + function isAggregationWithOutStage(commandName, commandObj) { + if (commandName !== "aggregate" || typeof commandObj !== "object" || commandObj === null) { + return false; + } + + if (!Array.isArray(commandObj.pipeline) || commandObj.pipeline.length === 0) { + return false; + } + + const lastStage = commandObj.pipeline[commandObj.pipeline.length - 1]; + if (typeof lastStage !== "object" || lastStage === null) { + return false; + } + + return Object.keys(lastStage)[0] === "$out"; + } + + function isMapReduceWithInlineOutput(commandName, commandObj) { + if ((commandName !== "mapReduce" && commandName !== "mapreduce") || + typeof commandObj !== "object" || commandObj === null) { + return false; + } + + if (typeof commandObj.out !== "object") { + return false; + } + + return commandObj.out.hasOwnProperty("inline"); + } + + function prependOverrideInParallelShell(overrideFile) { + const startParallelShellOriginal = startParallelShell; + + startParallelShell = function(jsCode, port, noConnect) { + let newCode; + if (typeof jsCode === "function") { + // Load the override file and immediately invoke the supplied function. + newCode = `load("${overrideFile}"); (${jsCode})();`; + } else { + newCode = `load("${overrideFile}"); ${jsCode};`; + } + + return startParallelShellOriginal(newCode, port, noConnect); + }; + } + + function overrideRunCommand(overrideFunc) { + const mongoRunCommandOriginal = Mongo.prototype.runCommand; + const mongoRunCommandWithMetadataOriginal = Mongo.prototype.runCommandWithMetadata; + + Mongo.prototype.runCommand = function(dbName, commandObj, options) { + const commandName = Object.keys(commandObj)[0]; + return overrideFunc(this, + dbName, + commandName, + commandObj, + mongoRunCommandOriginal, + (commandObj) => [dbName, commandObj, options]); + }; + + Mongo.prototype.runCommandWithMetadata = function(dbName, metadata, commandArgs) { + const commandName = Object.keys(commandArgs)[0]; + return overrideFunc(this, + dbName, + commandName, + commandArgs, + mongoRunCommandWithMetadataOriginal, + (commandArgs) => [dbName, metadata, commandArgs]); + }; + } + + return { + isAggregationWithListLocalCursorsStage: + makeIsAggregationWithFirstStage("$listLocalCursors"), + isAggregationWithListLocalSessionsStage: + makeIsAggregationWithFirstStage("$listLocalSessions"), + isAggregationWithOutStage: isAggregationWithOutStage, + isMapReduceWithInlineOutput: isMapReduceWithInlineOutput, + prependOverrideInParallelShell: prependOverrideInParallelShell, + overrideRunCommand: overrideRunCommand, + }; +})(); diff --git a/jstests/libs/override_methods/retry_writes_at_least_once.js b/jstests/libs/override_methods/retry_writes_at_least_once.js index f0562c958d1..5e211d88b49 100644 --- a/jstests/libs/override_methods/retry_writes_at_least_once.js +++ b/jstests/libs/override_methods/retry_writes_at_least_once.js @@ -6,6 +6,7 @@ (function() { "use strict"; + load("jstests/libs/override_methods/override_helpers.js"); load("jstests/libs/retryable_writes_util.js"); Random.setRandomSeed(); @@ -64,18 +65,6 @@ return res; } - const startParallelShellOriginal = startParallelShell; - - startParallelShell = function(jsCode, port, noConnect) { - let newCode; - const overridesFile = "jstests/libs/override_methods/retry_writes_at_least_once.js"; - if (typeof(jsCode) === "function") { - // Load the override file and immediately invoke the supplied function. - newCode = `load("${overridesFile}"); (${jsCode})();`; - } else { - newCode = `load("${overridesFile}"); ${jsCode};`; - } - - return startParallelShellOriginal(newCode, port, noConnect); - }; + OverrideHelpers.prependOverrideInParallelShell( + "jstests/libs/override_methods/retry_writes_at_least_once.js"); })(); diff --git a/jstests/libs/override_methods/set_read_and_write_concerns.js b/jstests/libs/override_methods/set_read_and_write_concerns.js index a14efa41a7f..00af2133916 100644 --- a/jstests/libs/override_methods/set_read_and_write_concerns.js +++ b/jstests/libs/override_methods/set_read_and_write_concerns.js @@ -1,201 +1,221 @@ /** - * Use prototype overrides to set read concern and write concern while running core tests. + * Use prototype overrides to set read concern and write concern while running tests. */ (function() { "use strict"; + load("jstests/libs/override_methods/override_helpers.js"); + if (typeof TestData === "undefined" || !TestData.hasOwnProperty("defaultReadConcernLevel")) { throw new Error( - "The default read-concern level must be set as the 'defaultReadConcernLevel' " + - "property on TestData"); - } - var defaultReadConcern = {level: TestData.defaultReadConcernLevel}; - - var defaultWriteConcern = { - w: "majority", - // Use a "signature" value that won't typically match a value assigned in normal use. - // This way the wtimeout set by this override is distinguishable in the server logs. - wtimeout: 5 * 60 * 1000 + 321, // 300321ms - }; - if (TestData.hasOwnProperty("defaultWriteConcern")) { - defaultWriteConcern = TestData.defaultWriteConcern; + "The readConcern level to use must be set as the 'defaultReadConcernLevel'" + + " property on the global TestData object"); } - var originalDBQuery = DBQuery; + const kDefaultReadConcern = {level: TestData.defaultReadConcernLevel}; + const kDefaultWriteConcern = + (TestData.hasOwnProperty("defaultWriteConcern")) ? TestData.defaultWriteConcern : { + w: "majority", + // Use a "signature" value that won't typically match a value assigned in normal use. + // This way the wtimeout set by this override is distinguishable in the server logs. + wtimeout: 5 * 60 * 1000 + 321, // 300321ms + }; + + const kCommandsSupportingReadConcern = new Set([ + "aggregate", + "count", + "distinct", + "find", + "geoNear", + "geoSearch", + "group", + "parallelCollectionScan", + ]); + + const kCommandsSupportingWriteConcern = new Set([ + "_configsvrAddShard", + "_configsvrAddShardToZone", + "_configsvrCommitChunkMerge", + "_configsvrCommitChunkMigration", + "_configsvrCommitChunkSplit", + "_configsvrCreateDatabase", + "_configsvrEnableSharding", + "_configsvrMoveChunk", + "_configsvrMovePrimary", + "_configsvrRemoveShard", + "_configsvrRemoveShardFromZone", + "_configsvrShardCollection", + "_configsvrUpdateZoneKeyRange", + "_mergeAuthzCollections", + "_recvChunkStart", + "appendOplogNote", + "applyOps", + "aggregate", + "captrunc", + "cleanupOrphaned", + "clone", + "cloneCollection", + "cloneCollectionAsCapped", + "collMod", + "convertToCapped", + "copydb", + "create", + "createIndexes", + "createRole", + "createUser", + "delete", + "doTxn", + "drop", + "dropAllRolesFromDatabase", + "dropAllUsersFromDatabase", + "dropDatabase", + "dropIndexes", + "dropRole", + "dropUser", + "emptycapped", + "findAndModify", + "findandmodify", + "godinsert", + "grantPrivilegesToRole", + "grantRolesToRole", + "grantRolesToUser", + "insert", + "mapReduce", + "mapreduce", + "mapreduce.shardedfinish", + "moveChunk", + "renameCollection", + "revokePrivilegesFromRole", + "revokeRolesFromRole", + "revokeRolesFromUser", + "setFeatureCompatibilityVersion", + "update", + "updateRole", + "updateUser", + ]); + + function runCommandWithReadAndWriteConcerns( + conn, dbName, commandName, commandObj, func, makeFuncArgs) { + if (typeof commandObj !== "object" || commandObj === null) { + return func.apply(conn, makeFuncArgs(commandObj)); + } - DBQuery = function(mongo, db, collection, ns, query, fields, limit, skip, batchSize, options) { - if (ns.endsWith("$cmd")) { - if (query.hasOwnProperty("writeConcern") && - bsonWoCompare(query.writeConcern, defaultWriteConcern) !== 0) { - jsTestLog("Warning: DBQuery overriding existing writeConcern of: " + - tojson(query.writeConcern)); - query.writeConcern = defaultWriteConcern; - } + // If the command is in a wrapped form, then we look for the actual command object inside + // the query/$query object. + let commandObjUnwrapped = commandObj; + if (commandName === "query" || commandName === "$query") { + commandObjUnwrapped = commandObj[commandName]; + commandName = Object.keys(commandObjUnwrapped)[0]; } - return originalDBQuery.apply(this, arguments); - }; + if (commandName === "eval" || commandName === "$eval") { + throw new Error("Cowardly refusing to run test with overridden write concern when it" + + " uses a command that can only perform w=1 writes: " + + tojson(commandObj)); + } - DBQuery.Option = originalDBQuery.Option; + let shouldForceReadConcern = kCommandsSupportingReadConcern.has(commandName); + let shouldForceWriteConcern = kCommandsSupportingWriteConcern.has(commandName); - var originalStartParallelShell = startParallelShell; - startParallelShell = function(jsCode, port, noConnect) { - var newCode; - var overridesFile = "jstests/libs/override_methods/set_read_and_write_concerns.js"; - if (typeof(jsCode) === "function") { - // Load the override file and immediately invoke the supplied function. - newCode = `load("${overridesFile}"); (${jsCode})();`; - } else { - newCode = `load("${overridesFile}"); ${jsCode};`; - } + if (commandName === "aggregate") { + if (OverrideHelpers.isAggregationWithListLocalCursorsStage(commandName, + commandObjUnwrapped)) { + // The $listLocalCursors stage can only be used with readConcern={level: "local"}. + shouldForceReadConcern = false; + } - return originalStartParallelShell(newCode, port, noConnect); - }; + if (OverrideHelpers.isAggregationWithListLocalSessionsStage(commandName, + commandObjUnwrapped)) { + // The $listLocalSessions stage can only be used with readConcern={level: "local"}. + shouldForceReadConcern = false; + } - const originalRunCommand = DB.prototype._runCommandImpl; - DB.prototype._runCommandImpl = function(dbName, obj, options) { - var cmdName = ""; - for (var fieldName in obj) { - cmdName = fieldName; - break; - } + if (OverrideHelpers.isAggregationWithOutStage(commandName, commandObjUnwrapped)) { + // The $out stage can only be used with readConcern={level: "local"}. + shouldForceReadConcern = false; + } else { + // A writeConcern can only be used with a $out stage. + shouldForceWriteConcern = false; + } - // These commands directly support a writeConcern argument. - var commandsToForceWriteConcern = [ - "_configsvrAddShard", - "_configsvrAddShardToZone", - "_configsvrCommitChunkMerge", - "_configsvrCommitChunkMigration", - "_configsvrCommitChunkSplit", - "_configsvrCreateDatabase", - "_configsvrEnableSharding", - "_configsvrMoveChunk", - "_configsvrMovePrimary", - "_configsvrRemoveShard", - "_configsvrRemoveShardFromZone", - "_configsvrShardCollection", - "_configsvrUpdateZoneKeyRange", - "_mergeAuthzCollections", - "_recvChunkStart", - "appendOplogNote", - "applyOps", - "captrunc", - "cleanupOrphaned", - "clone", - "cloneCollection", - "cloneCollectionAsCapped", - "collMod", - "convertToCapped", - "copydb", - "create", - "createIndexes", - "createRole", - "createUser", - "delete", - "doTxn", - "drop", - "dropAllRolesFromDatabase", - "dropAllUsersFromDatabase", - "dropDatabase", - "dropIndexes", - "dropRole", - "dropUser", - "emptycapped", - "findAndModify", - "findandmodify", - "godinsert", - "grantPrivilegesToRole", - "grantRolesToRole", - "grantRolesToUser", - "insert", - "mapreduce.shardedfinish", - "moveChunk", - "renameCollection", - "revokePrivilegesFromRole", - "revokeRolesFromRole", - "revokeRolesFromUser", - "setFeatureCompatibilityVersion", - "update", - "updateRole", - "updateUser", - ]; - - // These are reading commands that support majority readConcern. - var commandsToForceReadConcern = [ - "count", - "distinct", - "find", - "geoNear", - "geoSearch", - "group", - "parallelCollectionScan", - ]; - - var forceWriteConcern = Array.contains(commandsToForceWriteConcern, cmdName); - var forceReadConcern = Array.contains(commandsToForceReadConcern, cmdName); - - if (cmdName === "aggregate") { - // Aggregate can be either a read or a write depending on whether it has a $out stage. - // $out is required to be the last stage of the pipeline. - var stages = obj.pipeline; - const lastStage = stages && Array.isArray(stages) && (stages.length !== 0) - ? stages[stages.length - 1] - : undefined; - const hasOut = - lastStage && (typeof lastStage === 'object') && lastStage.hasOwnProperty('$out'); - const hasExplain = obj.hasOwnProperty("explain"); - if (!hasExplain) { - if (hasOut) { - forceWriteConcern = true; - } else { - forceReadConcern = true; - } + if (commandObjUnwrapped.explain) { + // Attempting to specify a readConcern while explaining an aggregation would always + // return an error prior to SERVER-30582 and it otherwise only compatible with + // readConcern={level: "local"}. + shouldForceReadConcern = false; } + } else if (OverrideHelpers.isMapReduceWithInlineOutput(commandName, commandObjUnwrapped)) { + // A writeConcern can only be used with non-inline output. + shouldForceWriteConcern = false; } - else if (cmdName === "mapReduce") { - var stages = obj.pipeline; - const lastStage = stages && Array.isArray(stages) && (stages.length !== 0) - ? stages[stages.length - 1] - : undefined; - const hasOut = - lastStage && (typeof lastStage === 'object') && lastStage.hasOwnProperty('$out'); - if (hasOut) { - forceWriteConcern = true; + const inWrappedForm = commandObj !== commandObjUnwrapped; + + if (shouldForceReadConcern) { + // We create a copy of 'commandObj' to avoid mutating the parameter the caller + // specified. + commandObj = Object.assign({}, commandObj); + if (inWrappedForm) { + commandObjUnwrapped = Object.assign({}, commandObjUnwrapped); + commandObj[Object.keys(commandObj)[0]] = commandObjUnwrapped; + } else { + commandObjUnwrapped = commandObj; } - } - if (forceWriteConcern) { - if (obj.hasOwnProperty("writeConcern")) { - if (bsonWoCompare(obj.writeConcern, defaultWriteConcern) !== 0) { - jsTestLog("Warning: _runCommandImpl overriding existing writeConcern of: " + - tojson(obj.writeConcern)); - obj.writeConcern = defaultWriteConcern; + if (commandObjUnwrapped.hasOwnProperty("readConcern")) { + let readConcern = commandObjUnwrapped.readConcern; + + if (typeof readConcern !== "object" || readConcern === null || + (readConcern.hasOwnProperty("level") && + bsonWoCompare({_: readConcern.level}, {_: kDefaultReadConcern.level}) !== 0)) { + throw new Error("Cowardly refusing to override read concern of command: " + + tojson(commandObj)); } + + // We create a copy of the readConcern object to avoid mutating the parameter the + // caller specified. + readConcern = Object.assign({}, readConcern, kDefaultReadConcern); + commandObjUnwrapped.readConcern = readConcern; + } else { + commandObjUnwrapped.readConcern = kDefaultReadConcern; + } + } + + if (shouldForceWriteConcern) { + // We create a copy of 'commandObj' to avoid mutating the parameter the caller + // specified. + commandObj = Object.assign({}, commandObj); + if (inWrappedForm) { + commandObjUnwrapped = Object.assign({}, commandObjUnwrapped); + commandObj[Object.keys(commandObj)[0]] = commandObjUnwrapped; } else { - obj.writeConcern = defaultWriteConcern; + commandObjUnwrapped = commandObj; } - } else if (forceReadConcern) { - if (obj.hasOwnProperty("readConcern")) { - if (bsonWoCompare(obj.readConcern, defaultReadConcern) !== 0) { - jsTestLog("Warning: _runCommandImpl overriding existing readConcern of: " + - tojson(obj.readConcern)); - obj.readConcern = defaultReadConcern; + if (commandObjUnwrapped.hasOwnProperty("writeConcern")) { + let writeConcern = commandObjUnwrapped.writeConcern; + + if (typeof writeConcern !== "object" || writeConcern === null || + (writeConcern.hasOwnProperty("w") && + bsonWoCompare({_: writeConcern.w}, {_: kDefaultWriteConcern.w}) !== 0)) { + throw new Error("Cowardly refusing to override write concern of command: " + + tojson(commandObj)); } + + // We create a copy of the writeConcern object to avoid mutating the parameter the + // caller specified. + writeConcern = Object.assign({}, writeConcern, kDefaultWriteConcern); + commandObjUnwrapped.writeConcern = writeConcern; } else { - obj.readConcern = defaultReadConcern; + commandObjUnwrapped.writeConcern = kDefaultWriteConcern; } } - var res = originalRunCommand.call(this, dbName, obj, options); - - return res; - }; + return func.apply(conn, makeFuncArgs(commandObj)); + } - // Use a majority write concern if the operation does not specify one. - DBCollection.prototype.getWriteConcern = function() { - return new WriteConcern(defaultWriteConcern); - }; + OverrideHelpers.prependOverrideInParallelShell( + "jstests/libs/override_methods/set_read_and_write_concerns.js"); + OverrideHelpers.overrideRunCommand(runCommandWithReadAndWriteConcerns); })(); diff --git a/jstests/libs/override_methods/set_read_preference_secondary.js b/jstests/libs/override_methods/set_read_preference_secondary.js index 9955c7f016d..d81532bf8d5 100644 --- a/jstests/libs/override_methods/set_read_preference_secondary.js +++ b/jstests/libs/override_methods/set_read_preference_secondary.js @@ -4,31 +4,16 @@ (function() { "use strict"; - const readPreferenceSecondary = {mode: "secondary"}; + load("jstests/libs/override_methods/override_helpers.js"); - db.getMongo().setReadPref("secondary"); - - const originalStartParallelShell = startParallelShell; - startParallelShell = function(jsCode, port, noConnect) { - let newCode; - const overridesFile = "jstests/libs/override_methods/set_read_preference_secondary.js"; - if (typeof(jsCode) === "function") { - // Load the override file and immediately invoke the supplied function. - newCode = `load("${overridesFile}"); (${jsCode})();`; - } else { - newCode = `load("${overridesFile}"); ${jsCode};`; - } - - return originalStartParallelShell(newCode, port, noConnect); - }; - - // These are reading commands that support a read preference. - const commandsToForceReadPreference = new Set([ + const kReadPreferenceSecondary = {mode: "secondary"}; + const kCommandsSupportingReadPreference = new Set([ "aggregate", "collStats", "count", "dbStats", "distinct", + "find", "geoNear", "geoSearch", "group", @@ -37,33 +22,55 @@ "parallelCollectionScan", ]); - const originalRunCommand = DB.prototype._runCommandImpl; - DB.prototype._runCommandImpl = function(dbName, obj, options) { - const cmdName = Object.keys(obj)[0]; + function runCommandWithReadPreferenceSecondary( + conn, dbName, commandName, commandObj, func, makeFuncArgs) { + if (typeof commandObj !== "object" || commandObj === null) { + return func.apply(conn, makeFuncArgs(commandObj)); + } - let forceReadPreference = commandsToForceReadPreference.has(cmdName); - if (cmdName === "aggregate" && obj.pipeline && Array.isArray(obj.pipeline) && - obj.pipeline.length > 0 && - obj.pipeline[obj.pipeline.length - 1].hasOwnProperty("$out")) { - forceReadPreference = false; - } else if ((cmdName === "mapReduce" || cmdName === "mapreduce") && - obj.hasOwnProperty("out") && typeof obj.out === "object" && !obj.out.inline) { - forceReadPreference = false; + // If the command is in a wrapped form, then we look for the actual command object inside + // the query/$query object. + let commandObjUnwrapped = commandObj; + if (commandName === "query" || commandName === "$query") { + commandObjUnwrapped = commandObj[commandName]; + commandName = Object.keys(commandObjUnwrapped)[0]; } - if (forceReadPreference) { - if (obj.hasOwnProperty("$readPreference")) { - if (bsonWoCompare(obj.$readPreference, readPreferenceSecondary) !== 0) { - jsTestLog("Warning: _runCommandImpl overriding existing $readPreference of: " + - tojson(obj.$readPreference)); - obj.$readPreference = readPreferenceSecondary; - } + let shouldForceReadPreference = kCommandsSupportingReadPreference.has(commandName); + if (OverrideHelpers.isAggregationWithOutStage(commandName, commandObjUnwrapped)) { + // An aggregation with a $out stage must be sent to the primary. + shouldForceReadPreference = false; + } else if ((commandName === "mapReduce" || commandName === "mapreduce") && + !OverrideHelpers.isMapReduceWithInlineOutput(commandName, commandObjUnwrapped)) { + // A map-reduce operation with non-inline output must be sent to the primary. + shouldForceReadPreference = false; + } + + if (shouldForceReadPreference) { + if (commandObj === commandObjUnwrapped) { + // We wrap the command object using a "query" field rather than a "$query" field to + // match the implementation of DB.prototype._attachReadPreferenceToCommand(). + commandObj = {query: commandObj}; } else { - obj.$readPreference = readPreferenceSecondary; + // We create a copy of 'commandObj' to avoid mutating the parameter the caller + // specified. + commandObj = Object.assign({}, commandObj); + } + + if (commandObj.hasOwnProperty("$readPreference") && + !bsonBinaryEqual({_: commandObj.$readPreference}, {_: kReadPreferenceSecondary})) { + throw new Error("Cowardly refusing to override read preference of command: " + + tojson(commandObj)); } + + commandObj.$readPreference = kReadPreferenceSecondary; } - return originalRunCommand.call(this, dbName, obj, options); - }; + return func.apply(conn, makeFuncArgs(commandObj)); + } + + OverrideHelpers.prependOverrideInParallelShell( + "jstests/libs/override_methods/set_read_preference_secondary.js"); + OverrideHelpers.overrideRunCommand(runCommandWithReadPreferenceSecondary); })(); |