summaryrefslogtreecommitdiff
path: root/jstests/multiVersion
diff options
context:
space:
mode:
authorMax Hirschhorn <max.hirschhorn@mongodb.com>2017-11-08 19:29:28 -0500
committerMax Hirschhorn <max.hirschhorn@mongodb.com>2017-11-08 19:29:28 -0500
commit6d8e6b9cce052cdd442e207a27df10e698b2bb00 (patch)
tree5a7bb7b5cf93902bf00a681dccb0f54adb2f1ab0 /jstests/multiVersion
parentf7756c41c5ed54e8e546461395bc8898d885af0c (diff)
downloadmongo-6d8e6b9cce052cdd442e207a27df10e698b2bb00.tar.gz
SERVER-31296 Update sessions, causal, and retryable in the mongo shell.
* Removes the initialClusterTime and initialOperationTime session options. * Enables causal consistency by default when using an explicit session. * Adds a --retryWrites command line option to the mongo shell for enabling retryable writes in the mongo shell. The retryWrites options to SessionOptions is left for convenience with testing. * Renames setClusterTime() to advanceClusterTime(), and adds a corresponding advanceOperationTime() method to DriverSession. * Enables assigning transaction numbers for write commands where ordered=false. * Prevents the mongo shell from sending afterClusterTime or assigning transaction numbers when talking to a stand-alone mongod. * Prevents the mongo shell from assigning transaction numbers when using an unacknowledged (w=0) writeConcern. * Changes DBClientRS to re-discover the current primary of the replica set when it receives an error code representing "not master" in addition to an error message representing "not master". * Adds a shellPrint() pretty-printer for SessionOptions and DriverSession instances so they no longer print out their entire object definition.
Diffstat (limited to 'jstests/multiVersion')
-rw-r--r--jstests/multiVersion/shell_causal_consistency_downgrade.js119
-rw-r--r--jstests/multiVersion/shell_retryable_writes_downgrade.js122
2 files changed, 241 insertions, 0 deletions
diff --git a/jstests/multiVersion/shell_causal_consistency_downgrade.js b/jstests/multiVersion/shell_causal_consistency_downgrade.js
new file mode 100644
index 00000000000..68a416297c7
--- /dev/null
+++ b/jstests/multiVersion/shell_causal_consistency_downgrade.js
@@ -0,0 +1,119 @@
+/**
+ * Tests that the mongo shell doesn't gossip its highest seen clusterTime or inject an
+ * afterClusterTime into its command requests after downgrading from 3.6 to 3.4.
+ */
+(function() {
+ "use strict";
+
+ load("jstests/replsets/rslib.js");
+
+ const rst = new ReplSetTest({nodes: 1});
+ rst.startSet();
+ rst.initiate();
+
+ const primary = rst.getPrimary();
+ primary.setCausalConsistency();
+
+ const db = primary.getDB("test");
+ const coll = db.shell_causal_consistency_downgrade;
+
+ function testCommandCanBeCausallyConsistent(func, {
+ expectedGossipClusterTime: expectedGossipClusterTime = true,
+ expectedAfterClusterTime: expectedAfterClusterTime = true
+ } = {}) {
+ const mongoRunCommandOriginal = Mongo.prototype.runCommand;
+
+ const sentinel = {};
+ let cmdObjSeen = sentinel;
+
+ Mongo.prototype.runCommand = function runCommandSpy(dbName, cmdObj, options) {
+ cmdObjSeen = cmdObj;
+ return mongoRunCommandOriginal.apply(this, arguments);
+ };
+
+ try {
+ assert.doesNotThrow(func);
+ } finally {
+ Mongo.prototype.runCommand = mongoRunCommandOriginal;
+ }
+
+ if (cmdObjSeen === sentinel) {
+ throw new Error("Mongo.prototype.runCommand() was never called: " + func.toString());
+ }
+
+ let cmdName = Object.keys(cmdObjSeen)[0];
+
+ // If the command is in a wrapped form, then we look for the actual command object inside
+ // the query/$query object.
+ if (cmdName === "query" || cmdName === "$query") {
+ cmdObjSeen = cmdObjSeen[cmdName];
+ cmdName = Object.keys(cmdObjSeen)[0];
+ }
+
+ if (expectedGossipClusterTime) {
+ assert(cmdObjSeen.hasOwnProperty("$clusterTime"),
+ "Expected operation " + tojson(cmdObjSeen) + " to have a $clusterTime object: " +
+ func.toString());
+ } else {
+ assert(!cmdObjSeen.hasOwnProperty("$clusterTime"),
+ "Expected operation " + tojson(cmdObjSeen) +
+ " to not have a $clusterTime object: " + func.toString());
+ }
+
+ if (expectedAfterClusterTime) {
+ assert(cmdObjSeen.hasOwnProperty("readConcern"),
+ "Expected operation " + tojson(cmdObjSeen) +
+ " to have a readConcern object since it can be causally consistent: " +
+ func.toString());
+
+ const readConcern = cmdObjSeen.readConcern;
+ assert(readConcern.hasOwnProperty("afterClusterTime"),
+ "Expected operation " + tojson(cmdObjSeen) +
+ " to specify afterClusterTime since it can be causally consistent: " +
+ func.toString());
+ } else {
+ assert(!cmdObjSeen.hasOwnProperty("readConcern"),
+ "Expected operation " + tojson(cmdObjSeen) + " to not have a readConcern" +
+ " object since it cannot be causally consistent: " + func.toString());
+ }
+ }
+
+ assert.writeOK(coll.insert({}));
+
+ testCommandCanBeCausallyConsistent(function() {
+ assert.commandWorked(db.runCommand({count: coll.getName()}));
+ });
+
+ assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: "3.4"}));
+
+ // The server continues to accept $clusterTime and afterClusterTime while in
+ // featureCompatibilityVersion=3.4.
+ testCommandCanBeCausallyConsistent(function() {
+ assert.commandWorked(db.runCommand({count: coll.getName()}));
+ });
+
+ rst.restart(primary, {binVersion: "3.4"});
+ rst.waitForMaster();
+ reconnect(primary);
+
+ assert(primary.isCausalConsistency(),
+ "Re-establishing the connection shouldn't change the state of the Mongo object");
+
+ // After downgrading to MongoDB 3.4, the mongo shell shouldn't gossip its highest seen
+ // clusterTime or inject an afterClusterTime into its command requests.
+ testCommandCanBeCausallyConsistent(function() {
+ assert.commandWorked(db.runCommand({count: coll.getName()}));
+ }, {expectedGossipClusterTime: false, expectedAfterClusterTime: false});
+
+ rst.restart(primary, {binVersion: "latest", noReplSet: true});
+ rst.waitForMaster();
+ reconnect(primary);
+
+ // When upgrading to MongoDB 3.6 but running as a stand-alone server, the mongo shell shouldn't
+ // gossip its highest seen clusterTime or inject an afterClusterTime into its command requests.
+ testCommandCanBeCausallyConsistent(function() {
+ assert.commandWorked(db.runCommand({count: coll.getName()}));
+ }, {expectedGossipClusterTime: false, expectedAfterClusterTime: false});
+
+ rst.stopSet();
+})();
diff --git a/jstests/multiVersion/shell_retryable_writes_downgrade.js b/jstests/multiVersion/shell_retryable_writes_downgrade.js
new file mode 100644
index 00000000000..652d33c0ddc
--- /dev/null
+++ b/jstests/multiVersion/shell_retryable_writes_downgrade.js
@@ -0,0 +1,122 @@
+/**
+ * Tests that the mongo shell doesn't attempt to retry its write operations after downgrading from
+ * 3.6 to 3.4.
+ */
+(function() {
+ "use strict";
+
+ load("jstests/replsets/rslib.js");
+
+ const rst = new ReplSetTest({nodes: 1});
+ rst.startSet();
+ rst.initiate();
+
+ const primary = rst.getPrimary();
+
+ const db = primary.startSession({retryWrites: true}).getDatabase("test");
+ const coll = db.shell_retryable_writes_downgrade;
+
+ function testCommandCanBeRetried(func, {
+ expectedLogicalSessionId: expectedLogicalSessionId = true,
+ expectedTransactionNumber: expectedTransactionNumber = true
+ } = {}) {
+ const mongoRunCommandOriginal = Mongo.prototype.runCommand;
+
+ const sentinel = {};
+ let cmdObjSeen = sentinel;
+
+ Mongo.prototype.runCommand = function runCommandSpy(dbName, cmdObj, options) {
+ cmdObjSeen = cmdObj;
+ return mongoRunCommandOriginal.apply(this, arguments);
+ };
+
+ try {
+ assert.doesNotThrow(func);
+ } finally {
+ Mongo.prototype.runCommand = mongoRunCommandOriginal;
+ }
+
+ if (cmdObjSeen === sentinel) {
+ throw new Error("Mongo.prototype.runCommand() was never called: " + func.toString());
+ }
+
+ let cmdName = Object.keys(cmdObjSeen)[0];
+
+ // If the command is in a wrapped form, then we look for the actual command object inside
+ // the query/$query object.
+ if (cmdName === "query" || cmdName === "$query") {
+ cmdObjSeen = cmdObjSeen[cmdName];
+ cmdName = Object.keys(cmdObjSeen)[0];
+ }
+
+ if (expectedLogicalSessionId) {
+ assert(cmdObjSeen.hasOwnProperty("lsid"),
+ "Expected operation " + tojson(cmdObjSeen) + " to have a logical session id: " +
+ func.toString());
+ } else {
+ assert(!cmdObjSeen.hasOwnProperty("lsid"),
+ "Expected operation " + tojson(cmdObjSeen) +
+ " to not have a logical session id: " + func.toString());
+ }
+
+ if (expectedTransactionNumber) {
+ assert(cmdObjSeen.hasOwnProperty("txnNumber"),
+ "Expected operation " + tojson(cmdObjSeen) +
+ " to be assigned a transaction number since it can be retried: " +
+ func.toString());
+ } else {
+ assert(!cmdObjSeen.hasOwnProperty("txnNumber"),
+ "Expected operation " + tojson(cmdObjSeen) +
+ " to not be assigned a transaction number since it cannot be retried: " +
+ func.toString());
+ }
+ }
+
+ testCommandCanBeRetried(function() {
+ assert.writeOK(coll.insert({_id: "while fCV=3.6"}));
+ });
+
+ assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: "3.4"}));
+
+ // The server continues to accept lsid and txnNumber while in featureCompatibilityVersion=3.4.
+ //
+ // TODO SERVER-31777: The server should return an error if an lsid or txnNumber is specified
+ // while in featureCompatibilityVersion=3.4.
+ testCommandCanBeRetried(function() {
+ assert.writeOK(coll.insert({_id: "while fCV=3.4"}));
+ });
+
+ rst.restart(primary, {binVersion: "3.4"});
+ rst.waitForMaster();
+
+ assert(db.getSession().getOptions().shouldRetryWrites(),
+ "Re-establishing the connection shouldn't change the state of the SessionOptions");
+
+ // After downgrading to MongoDB 3.4, the mongo shell shouldn't attempt to automatically retry
+ // write operations.
+ assert.throws(function() {
+ coll.insert({_id: "while in binVersion=3.4 and disconnected"});
+ });
+
+ // After downgrading to MongoDB 3.4, the mongo shell shouldn't inject an lsid or assign a
+ // transaction number to its write requests.
+ testCommandCanBeRetried(function() {
+ assert.writeOK(coll.insert({_id: "while binVersion=3.4 and reconnected"}));
+ }, {expectedLogicalSessionId: false, expectedTransactionNumber: false});
+
+ rst.restart(primary, {binVersion: "latest", noReplSet: true});
+ rst.waitForMaster();
+ reconnect(primary);
+
+ // When upgrading to MongoDB 3.6 but running as a stand-alone server, the mongo shell should
+ // still assign a transaction number to its write requests (per the Driver's specification).
+ //
+ // TODO SERVER-31777: The server should return an error if an lsid or txnNumber is specified
+ // while in featureCompatibilityVersion=3.4.
+ testCommandCanBeRetried(function() {
+ assert.writeOK(coll.insert({_id: "while binVersion=3.6 as stand-alone and reconnected"}));
+ });
+
+ db.getSession().endSession();
+ rst.stopSet();
+})();