diff options
author | Huayu Ouyang <huayu.ouyang@mongodb.com> | 2021-04-22 22:57:03 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-04-28 17:47:34 +0000 |
commit | 75a84d831d04c13ee6d0578f2b22b01e234c9737 (patch) | |
tree | 1d345e323aab969240138cbcf04029298275e16f | |
parent | ddd0a40a0d53de5b4269db46ef7bf8ffdd765cc2 (diff) | |
download | mongo-75a84d831d04c13ee6d0578f2b22b01e234c9737.tar.gz |
SERVER-55697 Don't allow removing CWWC once it is set
-rw-r--r-- | jstests/hooks/run_fuzzer_restore_settings.js | 11 | ||||
-rw-r--r-- | jstests/noPassthrough/read_write_concern_defaults_metrics.js | 27 | ||||
-rw-r--r-- | jstests/replsets/server_status_metrics.js | 6 | ||||
-rw-r--r-- | jstests/sharding/cannot_unset_cluster_wide_write_concern_once_set.js | 59 | ||||
-rw-r--r-- | jstests/sharding/read_write_concern_defaults_application.js | 7 | ||||
-rw-r--r-- | jstests/sharding/read_write_concern_defaults_commands_api.js | 172 | ||||
-rw-r--r-- | src/mongo/db/SConscript | 4 | ||||
-rw-r--r-- | src/mongo/db/read_write_concern_defaults.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/read_write_concern_defaults_test.cpp | 63 |
9 files changed, 222 insertions, 143 deletions
diff --git a/jstests/hooks/run_fuzzer_restore_settings.js b/jstests/hooks/run_fuzzer_restore_settings.js index 54da47e21f0..9c72058514e 100644 --- a/jstests/hooks/run_fuzzer_restore_settings.js +++ b/jstests/hooks/run_fuzzer_restore_settings.js @@ -1,13 +1,20 @@ (function() { 'use strict'; +// Randomly resets the cluster wide write concern to either w:1 or w:majority. +const defaultWriteConcern = + (Math.random() < 0.5) ? {w: 1, wtimeout: 0} : {w: 'majority', wtimeout: 0}; + // Unsetting read/write settings. This command will also cause the server to refresh and get -// the new settings. A standalone, mongos or old version will return an error; ignore it. +// the new settings. A standalone, shard server, or old version will return an error; ignore it. const result = db.adminCommand({ setDefaultRWConcern: 1, defaultReadConcern: {}, - defaultWriteConcern: {}, + defaultWriteConcern: defaultWriteConcern, writeConcern: {w: 1} }); assert.commandWorkedOrFailedWithCode(result, [51300, 51301, 40415]); +if (result.ok) { + jsTestLog("Resetting the global cluster wide write concern to " + tojson(defaultWriteConcern)); +} })(); diff --git a/jstests/noPassthrough/read_write_concern_defaults_metrics.js b/jstests/noPassthrough/read_write_concern_defaults_metrics.js index 2137fe44ddd..fedd2814a9a 100644 --- a/jstests/noPassthrough/read_write_concern_defaults_metrics.js +++ b/jstests/noPassthrough/read_write_concern_defaults_metrics.js @@ -51,19 +51,21 @@ function testServerStatus(conn) { // When no defaults have been set. verifyServerStatus(conn, {expectNoDefaultsDocument: true}); - // When only write concern is set. - assert.commandWorked( - conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: "majority"}})); - verifyServerStatus(conn, {expectedWC: {w: "majority", wtimeout: 0}}); - // When only read concern is set. - assert.commandWorked(conn.adminCommand({ - setDefaultRWConcern: 1, - defaultWriteConcern: {}, - defaultReadConcern: {level: "majority"} - })); + assert.commandWorked( + conn.adminCommand({setDefaultRWConcern: 1, defaultReadConcern: {level: "majority"}})); verifyServerStatus(conn, {expectedRC: {level: "majority"}}); + // When read concern is explicitly unset and write concern is unset. + assert.commandWorked(conn.adminCommand( + {setDefaultRWConcern: 1, defaultReadConcern: {}, defaultWriteConcern: {}})); + verifyServerStatus(conn, {}); + + // When only write concern is set. + assert.commandWorked(conn.adminCommand( + {setDefaultRWConcern: 1, defaultReadConcern: {}, defaultWriteConcern: {w: "majority"}})); + verifyServerStatus(conn, {expectedWC: {w: "majority", wtimeout: 0}}); + // When both read and write concern are set. assert.commandWorked(conn.adminCommand({ setDefaultRWConcern: 1, @@ -73,11 +75,6 @@ function testServerStatus(conn) { verifyServerStatus(conn, {expectedRC: {level: "majority"}, expectedWC: {w: "majority", wtimeout: 0}}); - // When both read and write concern are explicitly unset. - assert.commandWorked(conn.adminCommand( - {setDefaultRWConcern: 1, defaultReadConcern: {}, defaultWriteConcern: {}})); - verifyServerStatus(conn, {}); - // When the defaults document has been deleted. assert.commandWorked(conn.getDB("config").settings.remove({_id: "ReadWriteConcernDefaults"})); assert.soon(() => { diff --git a/jstests/replsets/server_status_metrics.js b/jstests/replsets/server_status_metrics.js index 12ecc9ece6f..6f0806b0bf2 100644 --- a/jstests/replsets/server_status_metrics.js +++ b/jstests/replsets/server_status_metrics.js @@ -194,9 +194,9 @@ var res = testDB.a.insert({x: 1}); assert.commandFailedWithCode(res, ErrorCodes.UnsatisfiableWriteConcern); assert.eq(res.getWriteConcernError().errInfo.writeConcern.provenance, "customDefault"); -// Unset the default WC. -assert.commandWorked( - testDB.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {}, writeConcern: {w: 1}})); +// Set the default WC back to {w: 1, wtimeout: 0}. +assert.commandWorked(testDB.adminCommand( + {setDefaultRWConcern: 1, defaultWriteConcern: {w: 1, wtimeout: 0}, writeConcern: {w: 1}})); // Validate counters. var endGLEMetrics = testDB.serverStatus().metrics.getLastError; diff --git a/jstests/sharding/cannot_unset_cluster_wide_write_concern_once_set.js b/jstests/sharding/cannot_unset_cluster_wide_write_concern_once_set.js new file mode 100644 index 00000000000..81d953e8157 --- /dev/null +++ b/jstests/sharding/cannot_unset_cluster_wide_write_concern_once_set.js @@ -0,0 +1,59 @@ +/** + * Tests that CWWC cannot be unset once it is set. + * @tags: [requires_fcv_50] + */ +(function() { +"use strict"; +function runTest(conn) { + const featureEnabled = assert + .commandWorked(conn.adminCommand( + {getParameter: 1, featureFlagDefaultWriteConcernMajority: 1})) + .featureFlagDefaultWriteConcernMajority.value; + if (!featureEnabled) { + jsTestLog("Skipping test because the default WC majority feature flag is disabled"); + return; + } + let res = conn.adminCommand({getDefaultRWConcern: 1}); + assert(!res.hasOwnProperty("defaultWriteConcern")); + jsTestLog("Setting the default write concern to empty initially works."); + assert.commandWorked(conn.adminCommand({ + setDefaultRWConcern: 1, + defaultWriteConcern: {}, + })); + + res = conn.adminCommand({getDefaultRWConcern: 1}); + assert(!res.hasOwnProperty("defaultWriteConcern")); + + jsTestLog("Setting the default write concern."); + const newDefaultWriteConcern = {w: 2, wtimeout: 60}; + assert.commandWorked(conn.adminCommand({ + setDefaultRWConcern: 1, + defaultWriteConcern: newDefaultWriteConcern, + })); + res = conn.adminCommand({getDefaultRWConcern: 1}); + assert.eq(res.defaultWriteConcern, newDefaultWriteConcern); + + jsTestLog("Attempting to unset the default write concern should fail."); + assert.commandFailedWithCode(conn.adminCommand({ + setDefaultRWConcern: 1, + defaultWriteConcern: {}, + }), + ErrorCodes.IllegalOperation); + + res = conn.adminCommand({getDefaultRWConcern: 1}); + assert.eq(res.defaultWriteConcern, newDefaultWriteConcern); +} + +const name = jsTestName(); +const rst = new ReplSetTest({name: name, nodes: 2}); +rst.startSet(); +rst.initiate(); +const primary = rst.getPrimary(); +runTest(primary); +rst.stopSet(); + +const st = new ShardingTest({name: name}); +const mongos = st.s; +runTest(mongos); +st.stop(); +})(); diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js index 1afaa4345e6..90eb29549ae 100644 --- a/jstests/sharding/read_write_concern_defaults_application.js +++ b/jstests/sharding/read_write_concern_defaults_application.js @@ -968,14 +968,13 @@ function runTests(conn, regularCheckConn, configSvrCheckConn) { configSvrCheckConn, {explicitRWC: true, explicitProvenance: true}); - assert.commandWorked(conn.adminCommand( - {setDefaultRWConcern: 1, defaultReadConcern: {}, defaultWriteConcern: {}})); - runScenario("Scenario: RWC defaults unset, explicit RWC present, absent provenance", + assert.commandWorked(conn.adminCommand({setDefaultRWConcern: 1, defaultReadConcern: {}})); + runScenario("Scenario: Read concern defaults unset, explicit RWC present, absent provenance", conn, regularCheckConn, configSvrCheckConn, {explicitRWC: true, explicitProvenance: false}); - runScenario("Scenario: RWC defaults unset, explicit RWC present, explicit provenance", + runScenario("Scenario: Read concern defaults unset, explicit RWC present, explicit provenance", conn, regularCheckConn, configSvrCheckConn, diff --git a/jstests/sharding/read_write_concern_defaults_commands_api.js b/jstests/sharding/read_write_concern_defaults_commands_api.js index 2e433244f2d..21c30ad99ae 100644 --- a/jstests/sharding/read_write_concern_defaults_commands_api.js +++ b/jstests/sharding/read_write_concern_defaults_commands_api.js @@ -1,5 +1,6 @@ // Tests the basic API of the getDefaultRWConcern and setDefaultRWConcern commands and their // associated persisted state against different topologies. +// @tags: [requires_fcv_50] (function() { "use strict"; @@ -65,6 +66,17 @@ function verifyDefaultRWCommandsInvalidInput(conn) { }), ErrorCodes.BadValue); + // Empty write concern is not allowed if write concern has already been set. + const featureEnabled = assert + .commandWorked(conn.adminCommand( + {getParameter: 1, featureFlagDefaultWriteConcernMajority: 1})) + .featureFlagDefaultWriteConcernMajority.value; + if (featureEnabled) { + assert.commandFailedWithCode( + conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {}}), + ErrorCodes.IllegalOperation); + } + // Invalid read concern. assert.commandFailedWithCode(conn.adminCommand({setDefaultRWConcern: 1, defaultReadConcern: 1}), ErrorCodes.TypeMismatch); @@ -100,21 +112,6 @@ function verifyDefaultRWCommandsInvalidInput(conn) { ErrorCodes.BadValue); } -// Sets a default read and write concern. -function setDefaultRWConcern(conn) { - assert.commandWorked(conn.adminCommand({ - setDefaultRWConcern: 1, - defaultReadConcern: {level: "local"}, - defaultWriteConcern: {w: 1} - })); -} - -// Unsets the default read and write concerns. -function unsetDefaultRWConcern(conn) { - assert.commandWorked(conn.adminCommand( - {setDefaultRWConcern: 1, defaultReadConcern: {}, defaultWriteConcern: {}})); -} - // Verifies the default responses for the default RWC commands and the default persisted state. function verifyDefaultState(conn) { const res = assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})); @@ -147,9 +144,9 @@ function verifyDefaultState(conn) { assert.eq(null, getPersistedRWCDocument(conn)); } -function verifyDefaultRWCommandsValidInput(conn) { +function verifyDefaultRWCommandsValidInputOnSuccess(conn) { // - // Test parameters for getDefaultRWConcern. + // Test getDefaultRWConcern when neither read nor write concern are set. // // No parameters is allowed. @@ -159,121 +156,66 @@ function verifyDefaultRWCommandsValidInput(conn) { assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1, inMemory: true})); assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1, inMemory: false})); - // - // Test parameters for setDefaultRWConcern. - // - - // Setting only rc is allowed. - assert.commandWorked( - conn.adminCommand({setDefaultRWConcern: 1, defaultReadConcern: {level: "local"}})); - assert.commandWorked( - conn.adminCommand({setDefaultRWConcern: 1, defaultReadConcern: {level: "majority"}})); - - // Setting only wc is allowed. - assert.commandWorked(conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}})); - assert.commandWorked( - conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1, j: false}})); - assert.commandWorked( - conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: "majority"}})); - - // Setting both wc and rc is allowed. - assert.commandWorked(conn.adminCommand({ - setDefaultRWConcern: 1, - defaultWriteConcern: {w: 1}, - defaultReadConcern: {level: "local"} - })); - - // Empty write concern is allowed. - assert.commandWorked(conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {}})); - - // Empty read concern is allowed. - assert.commandWorked(conn.adminCommand({setDefaultRWConcern: 1, defaultReadConcern: {}})); -} - -// Verifies the responses from successful rwc commands and the persisted state after they complete -// have the expected format. -function verifyDefaultRWCommandsOnSuccess(conn) { - // - // Test responses for getDefaultRWConcern. - // - - // When neither read nor write concern is set. - unsetDefaultRWConcern(conn); - verifyFields(assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})), - {expectRC: false, expectWC: false}); - - // When only read concern is set. - assert.commandWorked(conn.adminCommand( - {setDefaultRWConcern: 1, defaultReadConcern: {level: "local"}, defaultWriteConcern: {}})); - verifyFields(assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})), - {expectRC: true, expectWC: false}); - - // When only write concern is set. - assert.commandWorked(conn.adminCommand( - {setDefaultRWConcern: 1, defaultReadConcern: {}, defaultWriteConcern: {w: 1}})); - verifyFields(assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})), - {expectRC: false, expectWC: true}); - - // When both read and write concern are set. - assert.commandWorked(conn.adminCommand({ - setDefaultRWConcern: 1, - defaultReadConcern: {level: "local"}, - defaultWriteConcern: {w: 1} - })); - verifyFields(assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})), - {expectRC: true, expectWC: true}); - // An inMemory response should contain inMemory=true. const inMemoryRes = assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1, inMemory: true})); assert.eq(inMemoryRes.inMemory, true, tojson(inMemoryRes)); // - // Test responses for setDefaultRWConcern and persisted state after. + // Test getting and setting read concern. // - // When unsetting both read and write concern. - setDefaultRWConcern(conn); + // Test setDefaultRWConcern when only read concern is set. verifyFields(assert.commandWorked(conn.adminCommand( - {setDefaultRWConcern: 1, defaultReadConcern: {}, defaultWriteConcern: {}})), - {expectRC: false, expectWC: false}); + {setDefaultRWConcern: 1, defaultReadConcern: {level: "local"}})), + {expectRC: true, expectWC: false}); verifyFields(getPersistedRWCDocument(conn), - {expectRC: false, expectWC: false, isPersistedDocument: true}); + {expectRC: true, expectWC: false, isPersistedDocument: true}); + + // Test getDefaultRWConcern when only read concern is set. + verifyFields(assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})), + {expectRC: true, expectWC: false}); - // When unsetting only read concern. - setDefaultRWConcern(conn); + // Test unsetting read concern. verifyFields( assert.commandWorked(conn.adminCommand({setDefaultRWConcern: 1, defaultReadConcern: {}})), - {expectRC: false, expectWC: true}); + {expectRC: false, expectWC: false}); verifyFields(getPersistedRWCDocument(conn), - {expectRC: false, expectWC: true, isPersistedDocument: true}); + {expectRC: false, expectWC: false, isPersistedDocument: true}); + verifyFields(assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})), + {expectRC: false, expectWC: false}); - // When unsetting only write concern. - setDefaultRWConcern(conn); + // + // Test getting and setting write concern. + // + + // Empty write concern is allowed if write concern has not already been set. verifyFields( assert.commandWorked(conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {}})), - {expectRC: true, expectWC: false}); + {expectRC: false, expectWC: false}); verifyFields(getPersistedRWCDocument(conn), - {expectRC: true, expectWC: false, isPersistedDocument: true}); + {expectRC: false, expectWC: false, isPersistedDocument: true}); + + // Test setRWConcern when only write concern is set. + assert.commandWorked(conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}})); + assert.commandWorked( + conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1, j: false}})); + assert.commandWorked( + conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: "majority"}})); - // When setting only write concern. - unsetDefaultRWConcern(conn); verifyFields(assert.commandWorked( conn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}})), {expectRC: false, expectWC: true}); verifyFields(getPersistedRWCDocument(conn), {expectRC: false, expectWC: true, isPersistedDocument: true}); - // When setting only read concern. - unsetDefaultRWConcern(conn); - verifyFields(assert.commandWorked(conn.adminCommand( - {setDefaultRWConcern: 1, defaultReadConcern: {level: "local"}})), - {expectRC: true, expectWC: false}); - verifyFields(getPersistedRWCDocument(conn), - {expectRC: true, expectWC: false, isPersistedDocument: true}); + // Test getRWConcern when only write concern is set. + verifyFields(assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})), + {expectRC: false, expectWC: true}); - // When setting both read and write concern. - unsetDefaultRWConcern(conn); + // + // Test getting and setting both read and write concern. + // verifyFields(assert.commandWorked(conn.adminCommand({ setDefaultRWConcern: 1, defaultReadConcern: {level: "local"}, @@ -282,6 +224,10 @@ function verifyDefaultRWCommandsOnSuccess(conn) { {expectRC: true, expectWC: true}); verifyFields(getPersistedRWCDocument(conn), {expectRC: true, expectWC: true, isPersistedDocument: true}); + + // Test getRWConcern when both read and write concern are set. + verifyFields(assert.commandWorked(conn.adminCommand({getDefaultRWConcern: 1})), + {expectRC: true, expectWC: true}); } function getPersistedRWCDocument(conn) { @@ -315,9 +261,8 @@ jsTestLog("Testing standalone replica set..."); // Primary succeeds. verifyDefaultState(rst.getPrimary()); - verifyDefaultRWCommandsValidInput(rst.getPrimary()); + verifyDefaultRWCommandsValidInputOnSuccess(rst.getPrimary()); verifyDefaultRWCommandsInvalidInput(rst.getPrimary()); - verifyDefaultRWCommandsOnSuccess(rst.getPrimary()); // Secondary can run getDefaultRWConcern, but not setDefaultRWConcern. assert.commandWorked(rst.getSecondary().adminCommand({getDefaultRWConcern: 1})); @@ -331,13 +276,12 @@ jsTestLog("Testing standalone replica set..."); jsTestLog("Testing sharded cluster..."); { - const st = new ShardingTest({shards: 1, rs: {nodes: 2}}); + let st = new ShardingTest({shards: 1, rs: {nodes: 2}}); // Mongos succeeds. verifyDefaultState(st.s); - verifyDefaultRWCommandsValidInput(st.s); + verifyDefaultRWCommandsValidInputOnSuccess(st.s); verifyDefaultRWCommandsInvalidInput(st.s); - verifyDefaultRWCommandsOnSuccess(st.s); // Shard node fails. verifyDefaultRWCommandsFailWithCode(st.rs0.getPrimary(), {failureCode: 51301}); @@ -349,10 +293,12 @@ jsTestLog("Testing sharded cluster..."); {setDefaultRWConcern: 1, defaultReadConcern: {level: "local"}}), ErrorCodes.NotWritablePrimary); + st.stop(); + st = new ShardingTest({shards: 1, rs: {nodes: 2}}); // Config server primary succeeds. - verifyDefaultRWCommandsValidInput(st.configRS.getPrimary()); + verifyDefaultState(st.configRS.getPrimary()); + verifyDefaultRWCommandsValidInputOnSuccess(st.configRS.getPrimary()); verifyDefaultRWCommandsInvalidInput(st.configRS.getPrimary()); - verifyDefaultRWCommandsOnSuccess(st.configRS.getPrimary()); // Config server secondary can run getDefaultRWConcern, but not setDefaultRWConcern. assert.commandWorked(st.configRS.getSecondary().adminCommand({getDefaultRWConcern: 1})); diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 2556198a1c1..b44f18ffb60 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -432,8 +432,11 @@ env.Library( 'write_concern_options', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/idl/feature_flag', '$BUILD_DIR/mongo/util/caching', '$BUILD_DIR/mongo/util/concurrency/thread_pool', + 'repl/repl_server_parameters', + 'server_options_core', 'vector_clock', ], ) @@ -2421,6 +2424,7 @@ if wiredtiger: 'repl/mock_repl_coord_server_fixture', 'repl/oplog_interface_local', 'repl/repl_coordinator_interface', + 'repl/repl_server_parameters', 'repl/replica_set_aware_service', 'repl/replmocks', 'repl/storage_interface_impl', diff --git a/src/mongo/db/read_write_concern_defaults.cpp b/src/mongo/db/read_write_concern_defaults.cpp index 536d3a2471d..a046927eb3b 100644 --- a/src/mongo/db/read_write_concern_defaults.cpp +++ b/src/mongo/db/read_write_concern_defaults.cpp @@ -32,7 +32,8 @@ #include "mongo/platform/basic.h" #include "mongo/db/read_write_concern_defaults.h" - +#include "mongo/db/repl/repl_server_parameters_gen.h" +#include "mongo/db/server_options.h" #include "mongo/db/vector_clock.h" #include "mongo/logv2/log.h" @@ -130,6 +131,19 @@ RWConcernDefault ReadWriteConcernDefaults::generateNewConcerns( if (!wc && current) { rwc.setDefaultWriteConcern(current->getDefaultWriteConcern()); } + // If the setDefaultRWConcern command tries to unset the global default write concern when it + // has already been set, throw an error. + // wc->usedDefault indicates that the defaultWriteConcern given in the setDefaultRWConcern + // command was empty (i.e. {defaultWriteConcern: {}}) + // If current->getDefaultWriteConcern exists, that means the global default write concern has + // already been set. + if (repl::feature_flags::gDefaultWCMajority.isEnabled( + serverGlobalParams.featureCompatibility) && + wc && wc->usedDefault && current) { + uassert(ErrorCodes::IllegalOperation, + str::stream() << "The global default write concern cannot be unset once it is set.", + !current->getDefaultWriteConcern()); + } return rwc; } diff --git a/src/mongo/db/read_write_concern_defaults_test.cpp b/src/mongo/db/read_write_concern_defaults_test.cpp index c07de0e93f0..e902efbbc52 100644 --- a/src/mongo/db/read_write_concern_defaults_test.cpp +++ b/src/mongo/db/read_write_concern_defaults_test.cpp @@ -32,6 +32,8 @@ #include "mongo/db/read_write_concern_defaults.h" #include "mongo/db/read_write_concern_defaults_cache_lookup_mock.h" #include "mongo/db/repl/optime.h" +#include "mongo/db/repl/repl_server_parameters_gen.h" +#include "mongo/db/server_options.h" #include "mongo/db/service_context_test_fixture.h" #include "mongo/db/vector_clock_mutable.h" #include "mongo/db/vector_clock_test_fixture.h" @@ -403,13 +405,14 @@ TEST_F(ReadWriteConcernDefaultsTestWithClusterTime, ASSERT_LT(oldDefaults.localUpdateWallClockTime(), newDefaults.localUpdateWallClockTime()); } -TEST_F(ReadWriteConcernDefaultsTestWithClusterTime, - TestGenerateNewConcernsValidUnsetReadConcernAndWriteConcern) { +TEST_F(ReadWriteConcernDefaultsTestWithClusterTime, TestGenerateNewConcernsValidUnsetReadConcern) { auto oldDefaults = setupOldDefaults(); - auto defaults = _rwcd.generateNewConcerns( - operationContext(), repl::ReadConcernArgs(), WriteConcernOptions()); + auto defaults = + _rwcd.generateNewConcerns(operationContext(), repl::ReadConcernArgs(), boost::none); ASSERT(!defaults.getDefaultReadConcern()); - ASSERT(!defaults.getDefaultWriteConcern()); + ASSERT(defaults.getDefaultWriteConcern()); + ASSERT_EQ(oldDefaults.getDefaultWriteConcern()->wNumNodes, + defaults.getDefaultWriteConcern()->wNumNodes); ASSERT_LT(*oldDefaults.getUpdateOpTime(), *defaults.getUpdateOpTime()); ASSERT_LT(*oldDefaults.getUpdateWallClockTime(), *defaults.getUpdateWallClockTime()); @@ -420,6 +423,56 @@ TEST_F(ReadWriteConcernDefaultsTestWithClusterTime, } TEST_F(ReadWriteConcernDefaultsTestWithClusterTime, + TestGenerateNewConcernsInvalidUnsetWriteConcern) { + auto oldDefaults = setupOldDefaults(); + if (repl::feature_flags::gDefaultWCMajority.isEnabled( + serverGlobalParams.featureCompatibility)) { + ASSERT_THROWS_CODE( + _rwcd.generateNewConcerns(operationContext(), boost::none, WriteConcernOptions()), + AssertionException, + ErrorCodes::IllegalOperation); + } else { + auto defaults = + _rwcd.generateNewConcerns(operationContext(), boost::none, WriteConcernOptions()); + ASSERT(defaults.getDefaultReadConcern()); + ASSERT(oldDefaults.getDefaultReadConcern()->getLevel() == + defaults.getDefaultReadConcern()->getLevel()); + ASSERT(!defaults.getDefaultWriteConcern()); + ASSERT_LT(*oldDefaults.getUpdateOpTime(), *defaults.getUpdateOpTime()); + ASSERT_LT(*oldDefaults.getUpdateWallClockTime(), *defaults.getUpdateWallClockTime()); + + _lookupMock.setLookupCallReturnValue(std::move(defaults)); + _rwcd.refreshIfNecessary(operationContext()); + auto newDefaults = _rwcd.getDefault(operationContext()); + ASSERT_LT(oldDefaults.localUpdateWallClockTime(), newDefaults.localUpdateWallClockTime()); + } +} + +TEST_F(ReadWriteConcernDefaultsTestWithClusterTime, + TestGenerateNewConcernsInvalidUnsetReadWriteConcern) { + auto oldDefaults = setupOldDefaults(); + if (repl::feature_flags::gDefaultWCMajority.isEnabled( + serverGlobalParams.featureCompatibility)) { + ASSERT_THROWS_CODE(_rwcd.generateNewConcerns( + operationContext(), repl::ReadConcernArgs(), WriteConcernOptions()), + AssertionException, + ErrorCodes::IllegalOperation); + } else { + auto defaults = _rwcd.generateNewConcerns( + operationContext(), repl::ReadConcernArgs(), WriteConcernOptions()); + ASSERT(!defaults.getDefaultReadConcern()); + ASSERT(!defaults.getDefaultWriteConcern()); + ASSERT_LT(*oldDefaults.getUpdateOpTime(), *defaults.getUpdateOpTime()); + ASSERT_LT(*oldDefaults.getUpdateWallClockTime(), *defaults.getUpdateWallClockTime()); + + _lookupMock.setLookupCallReturnValue(std::move(defaults)); + _rwcd.refreshIfNecessary(operationContext()); + auto newDefaults = _rwcd.getDefault(operationContext()); + ASSERT_LT(oldDefaults.localUpdateWallClockTime(), newDefaults.localUpdateWallClockTime()); + } +} + +TEST_F(ReadWriteConcernDefaultsTestWithClusterTime, TestGenerateNewConcernsValidSetWriteConcernWithOnlyJ) { auto oldDefaults = setupOldDefaults(); auto defaults = |