diff options
Diffstat (limited to 'jstests/multiVersion/genericSetFCVUsage')
15 files changed, 1243 insertions, 1273 deletions
diff --git a/jstests/multiVersion/genericSetFCVUsage/crash_mongos_against_upgraded_cluster.js b/jstests/multiVersion/genericSetFCVUsage/crash_mongos_against_upgraded_cluster.js index 2fb02f419ce..c49abeafa8f 100644 --- a/jstests/multiVersion/genericSetFCVUsage/crash_mongos_against_upgraded_cluster.js +++ b/jstests/multiVersion/genericSetFCVUsage/crash_mongos_against_upgraded_cluster.js @@ -8,48 +8,47 @@ TestData.skipCheckingUUIDsConsistentAcrossCluster = true; (function() { - "use strict"; - - load("jstests/libs/feature_compatibility_version.js"); - - const lastStable = "last-stable"; - - let st = new ShardingTest({mongos: 1, shards: 1}); - const ns = "testDB.testColl"; - let mongosAdminDB = st.s.getDB("admin"); - - // Assert that a mongos using the 'last-stable' binary version will crash when connecting to a - // cluster running on the 'latest' binary version with the 'latest' FCV. - let lastStableMongos = - MongoRunner.runMongos({configdb: st.configRS.getURL(), binVersion: lastStable}); - - assert(!lastStableMongos); - - // Assert that a mongos using the 'last-stable' binary version will successfully connect to a - // cluster running on the 'latest' binary version with the 'last-stable' FCV. - assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); - lastStableMongos = - MongoRunner.runMongos({configdb: st.configRS.getURL(), binVersion: lastStable}); - assert.neq(null, - lastStableMongos, - "mongos was unable to start up with binary version=" + lastStable + - " and connect to FCV=" + lastStableFCV + " cluster"); - - // Ensure that the 'lastStable' binary mongos can perform reads and writes to the shards in the - // cluster. - assert.writeOK(lastStableMongos.getDB("test").foo.insert({x: 1})); - let foundDoc = lastStableMongos.getDB("test").foo.findOne({x: 1}); - assert.neq(null, foundDoc); - assert.eq(1, foundDoc.x, tojson(foundDoc)); - - // Assert that the 'lastStable' binary mongos will crash after the cluster is upgraded to - // 'latestFCV'. - assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); - let error = assert.throws(function() { - lastStableMongos.getDB("test").foo.insert({x: 1}); - }); - assert(isNetworkError(error)); - assert(!lastStableMongos.conn); - - st.stop(); +"use strict"; + +load("jstests/libs/feature_compatibility_version.js"); + +const lastStable = "last-stable"; + +let st = new ShardingTest({mongos: 1, shards: 1}); +const ns = "testDB.testColl"; +let mongosAdminDB = st.s.getDB("admin"); + +// Assert that a mongos using the 'last-stable' binary version will crash when connecting to a +// cluster running on the 'latest' binary version with the 'latest' FCV. +let lastStableMongos = + MongoRunner.runMongos({configdb: st.configRS.getURL(), binVersion: lastStable}); + +assert(!lastStableMongos); + +// Assert that a mongos using the 'last-stable' binary version will successfully connect to a +// cluster running on the 'latest' binary version with the 'last-stable' FCV. +assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); +lastStableMongos = MongoRunner.runMongos({configdb: st.configRS.getURL(), binVersion: lastStable}); +assert.neq(null, + lastStableMongos, + "mongos was unable to start up with binary version=" + lastStable + + " and connect to FCV=" + lastStableFCV + " cluster"); + +// Ensure that the 'lastStable' binary mongos can perform reads and writes to the shards in the +// cluster. +assert.writeOK(lastStableMongos.getDB("test").foo.insert({x: 1})); +let foundDoc = lastStableMongos.getDB("test").foo.findOne({x: 1}); +assert.neq(null, foundDoc); +assert.eq(1, foundDoc.x, tojson(foundDoc)); + +// Assert that the 'lastStable' binary mongos will crash after the cluster is upgraded to +// 'latestFCV'. +assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); +let error = assert.throws(function() { + lastStableMongos.getDB("test").foo.insert({x: 1}); +}); +assert(isNetworkError(error)); +assert(!lastStableMongos.conn); + +st.stop(); })(); diff --git a/jstests/multiVersion/genericSetFCVUsage/do_upgrade_downgrade.js b/jstests/multiVersion/genericSetFCVUsage/do_upgrade_downgrade.js index 6a858400ae4..e280a82451e 100644 --- a/jstests/multiVersion/genericSetFCVUsage/do_upgrade_downgrade.js +++ b/jstests/multiVersion/genericSetFCVUsage/do_upgrade_downgrade.js @@ -1,304 +1,224 @@ // Perform the upgrade/downgrade procedure by first setting the featureCompatibilityVersion and // then switching the binary. (function() { - "use strict"; - - load("jstests/replsets/rslib.js"); - load("jstests/libs/feature_compatibility_version.js"); - load("jstests/libs/get_index_helpers.js"); - load("jstests/libs/check_uuids.js"); - load("jstests/libs/check_unique_indexes.js"); - - const latestBinary = "latest"; - const lastStableBinary = "last-stable"; - - let setFCV = function(adminDB, version) { - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: version})); - checkFCV(adminDB, version); - }; - - let insertDataForConn = function(conn, dbs, nodeOptions) { - for (let i = 0; i < 20; i++) { - let doc = {id: i, sno: i, a: "foo", conn: conn.name}; - for (let j in dbs) { - if (nodeOptions.hasOwnProperty("configsvr")) { - if (j !== "admin" && j !== "local") { - // We can't create user databases on a --configsvr instance. - continue; - } - // Config servers have a majority write concern. - assert.writeOK( - conn.getDB(dbs[j]).foo.insert(doc, {writeConcern: {w: "majority"}})); - } else { - assert.writeOK(conn.getDB(dbs[j]).foo.insert(doc)); - } - } - } +"use strict"; + +load("jstests/replsets/rslib.js"); +load("jstests/libs/feature_compatibility_version.js"); +load("jstests/libs/get_index_helpers.js"); +load("jstests/libs/check_uuids.js"); +load("jstests/libs/check_unique_indexes.js"); - // Create unique indexes on collection "foo" with two index formatVersions. - // Providing index version explicitly allows index creation with corresponding - // formatVersion. +const latestBinary = "latest"; +const lastStableBinary = "last-stable"; + +let setFCV = function(adminDB, version) { + assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: version})); + checkFCV(adminDB, version); +}; + +let insertDataForConn = function(conn, dbs, nodeOptions) { + for (let i = 0; i < 20; i++) { + let doc = {id: i, sno: i, a: "foo", conn: conn.name}; for (let j in dbs) { - let testDB = conn.getDB(dbs[j]); - testDB.getCollectionInfos().forEach(function(c) { - if (c.name === "foo") { - let foo = testDB.getCollection(c.name); - assert.commandWorked(foo.createIndex({id: 1}, {unique: true})); - assert.commandWorked(foo.createIndex({sno: 1}, {unique: true, v: 1})); + if (nodeOptions.hasOwnProperty("configsvr")) { + if (j !== "admin" && j !== "local") { + // We can't create user databases on a --configsvr instance. + continue; } - }); + // Config servers have a majority write concern. + assert.writeOK(conn.getDB(dbs[j]).foo.insert(doc, {writeConcern: {w: "majority"}})); + } else { + assert.writeOK(conn.getDB(dbs[j]).foo.insert(doc)); + } } - }; - - let recreateUniqueIndexes = function(db, secondary) { - // Obtain list of all v1 and v2 unique indexes - var unique_idx = []; - var unique_idx_v1 = []; - db.adminCommand("listDatabases").databases.forEach(function(d) { - if (secondary && !(d.name === "local")) { - // All replicated indexes will be dropped on the primary, and have that - // drop propogated. Secondary nodes need to recreate unique indexes - // associated with local collections. - return; + } + + // Create unique indexes on collection "foo" with two index formatVersions. + // Providing index version explicitly allows index creation with corresponding + // formatVersion. + for (let j in dbs) { + let testDB = conn.getDB(dbs[j]); + testDB.getCollectionInfos().forEach(function(c) { + if (c.name === "foo") { + let foo = testDB.getCollection(c.name); + assert.commandWorked(foo.createIndex({id: 1}, {unique: true})); + assert.commandWorked(foo.createIndex({sno: 1}, {unique: true, v: 1})); } - let mdb = db.getSiblingDB(d.name); - mdb.getCollectionInfos().forEach(function(c) { - let currentCollection = mdb.getCollection(c.name); - currentCollection.getIndexes().forEach(function(i) { - if (i.unique) { - if (i.v === 1) { - unique_idx_v1.push(i); - return; - } - unique_idx.push(i); - } - }); - }); }); - - // Drop and create all v:2 indexes - for (let idx of unique_idx) { - let [dbName, collName] = idx.ns.split("."); - let res = db.getSiblingDB(dbName).runCommand({dropIndexes: collName, index: idx.name}); - assert.commandWorked(res); - res = db.getSiblingDB(dbName).runCommand({ - createIndexes: collName, - indexes: [{"key": idx.key, "name": idx.name, "unique": true}] - }); - assert.commandWorked(res); + } +}; + +let recreateUniqueIndexes = function(db, secondary) { + // Obtain list of all v1 and v2 unique indexes + var unique_idx = []; + var unique_idx_v1 = []; + db.adminCommand("listDatabases").databases.forEach(function(d) { + if (secondary && !(d.name === "local")) { + // All replicated indexes will be dropped on the primary, and have that + // drop propogated. Secondary nodes need to recreate unique indexes + // associated with local collections. + return; } - - // Drop and create all v:1 indexes - for (let idx of unique_idx_v1) { - let [dbName, collName] = idx.ns.split("."); - let res = db.getSiblingDB(dbName).runCommand({dropIndexes: collName, index: idx.name}); - assert.commandWorked(res); - res = db.getSiblingDB(dbName).runCommand({ - createIndexes: collName, - indexes: [{"key": idx.key, "name": idx.name, "unique": true, "v": 1}] + let mdb = db.getSiblingDB(d.name); + mdb.getCollectionInfos().forEach(function(c) { + let currentCollection = mdb.getCollection(c.name); + currentCollection.getIndexes().forEach(function(i) { + if (i.unique) { + if (i.v === 1) { + unique_idx_v1.push(i); + return; + } + unique_idx.push(i); + } }); - assert.commandWorked(res); - } - }; - - // Create and clear dbpath - let sharedDbPath = MongoRunner.dataPath + "do_upgrade_downgrade"; - resetDbpath(sharedDbPath); - - // Return a mongodb connection with startup options, version and dbpath options - let startMongodWithVersion = function(nodeOptions, ver, path) { - let version = ver || latestBinary; - let dbpath = path || sharedDbPath; - let conn = MongoRunner.runMongod( - Object.assign({}, nodeOptions, {dbpath: dbpath, binVersion: version})); - assert.neq(null, - conn, - "mongod was unable to start up with version=" + version + " and path=" + dbpath); - return conn; - }; - - // - // Standalone tests. - // - let standaloneTest = function(nodeOptions) { - let noCleanDataOptions = Object.assign({noCleanData: true}, nodeOptions); - - // New latest binary version standalone. - jsTest.log("Starting a latest binVersion standalone"); - let conn = startMongodWithVersion(nodeOptions, latestBinary); - let adminDB = conn.getDB("admin"); - - // Insert some data. - insertDataForConn(conn, ["admin", "local", "test"], nodeOptions); - - if (!nodeOptions.hasOwnProperty("shardsvr")) { - // Initially featureCompatibilityVersion is latest except for when we run with shardsvr. - // We expect featureCompatibilityVersion to be last-stable for shardsvr. - checkFCV(adminDB, latestFCV); - - // Ensure all collections have UUIDs and all unique indexes have new version in latest - // featureCompatibilityVersion mode. - checkCollectionUUIDs(adminDB); - checkUniqueIndexFormatVersion(adminDB); - - // Set featureCompatibilityVersion to last-stable. - setFCV(adminDB, lastStableFCV); - } - - // Ensure featureCompatibilityVersion is last-stable and all collections still have UUIDs. - checkFCV(adminDB, lastStableFCV); - checkCollectionUUIDs(adminDB); - - // Drop and recreate unique indexes with the older FCV - recreateUniqueIndexes(adminDB, false); - - // Stop latest binary version mongod. - MongoRunner.stopMongod(conn); - - // Start last-stable binary version mongod with same dbpath - jsTest.log("Starting a last-stable binVersion standalone to test downgrade"); - let lastStableConn = startMongodWithVersion(noCleanDataOptions, lastStableBinary); - let lastStableAdminDB = lastStableConn.getDB("admin"); - - // Check FCV document. - checkFCV(lastStableAdminDB, lastStableFCV); - - // Ensure all collections still have UUIDs on a last-stable mongod. - checkCollectionUUIDs(lastStableAdminDB); - - // Stop last-stable binary version mongod. - MongoRunner.stopMongod(lastStableConn); - - // Start latest binary version mongod again. - jsTest.log("Starting a latest binVersion standalone to test upgrade"); - conn = startMongodWithVersion(noCleanDataOptions, latestBinary); - adminDB = conn.getDB("admin"); - - // Ensure setFeatureCompatibilityVersion to latest succeeds, all collections have UUIDs - // and all unique indexes are in new version. - setFCV(adminDB, latestFCV); + }); + }); + + // Drop and create all v:2 indexes + for (let idx of unique_idx) { + let [dbName, collName] = idx.ns.split("."); + let res = db.getSiblingDB(dbName).runCommand({dropIndexes: collName, index: idx.name}); + assert.commandWorked(res); + res = db.getSiblingDB(dbName).runCommand({ + createIndexes: collName, + indexes: [{"key": idx.key, "name": idx.name, "unique": true}] + }); + assert.commandWorked(res); + } + + // Drop and create all v:1 indexes + for (let idx of unique_idx_v1) { + let [dbName, collName] = idx.ns.split("."); + let res = db.getSiblingDB(dbName).runCommand({dropIndexes: collName, index: idx.name}); + assert.commandWorked(res); + res = db.getSiblingDB(dbName).runCommand({ + createIndexes: collName, + indexes: [{"key": idx.key, "name": idx.name, "unique": true, "v": 1}] + }); + assert.commandWorked(res); + } +}; + +// Create and clear dbpath +let sharedDbPath = MongoRunner.dataPath + "do_upgrade_downgrade"; +resetDbpath(sharedDbPath); + +// Return a mongodb connection with startup options, version and dbpath options +let startMongodWithVersion = function(nodeOptions, ver, path) { + let version = ver || latestBinary; + let dbpath = path || sharedDbPath; + let conn = MongoRunner.runMongod( + Object.assign({}, nodeOptions, {dbpath: dbpath, binVersion: version})); + assert.neq(null, + conn, + "mongod was unable to start up with version=" + version + " and path=" + dbpath); + return conn; +}; + +// +// Standalone tests. +// +let standaloneTest = function(nodeOptions) { + let noCleanDataOptions = Object.assign({noCleanData: true}, nodeOptions); + + // New latest binary version standalone. + jsTest.log("Starting a latest binVersion standalone"); + let conn = startMongodWithVersion(nodeOptions, latestBinary); + let adminDB = conn.getDB("admin"); + + // Insert some data. + insertDataForConn(conn, ["admin", "local", "test"], nodeOptions); + + if (!nodeOptions.hasOwnProperty("shardsvr")) { + // Initially featureCompatibilityVersion is latest except for when we run with shardsvr. + // We expect featureCompatibilityVersion to be last-stable for shardsvr. checkFCV(adminDB, latestFCV); + + // Ensure all collections have UUIDs and all unique indexes have new version in latest + // featureCompatibilityVersion mode. checkCollectionUUIDs(adminDB); checkUniqueIndexFormatVersion(adminDB); - // Stop latest binary version mongod for the last time - MongoRunner.stopMongod(conn); - }; - - // - // Replica set tests. - // - let replicaSetTest = function(nodeOptions) { - - // New latest binary version replica set. - jsTest.log("Starting a latest binVersion ReplSetTest"); - let rst = new ReplSetTest({nodes: 3, nodeOptions: nodeOptions}); - rst.startSet(); - rst.initiate(); - let primaryAdminDB = rst.getPrimary().getDB("admin"); - let secondaries = rst.getSecondaries(); - - // Insert some data. - insertDataForConn(rst.getPrimary(), ["admin", "local", "test"], nodeOptions); - rst.awaitReplication(); - - for (let j = 0; j < secondaries.length; j++) { - let secondaryAdminDB = secondaries[j].getDB("admin"); - // Insert some data into the local DB. - insertDataForConn(secondaries[j], ["local"], nodeOptions); - } - - if (!nodeOptions.hasOwnProperty("shardsvr")) { - // Initially featureCompatibilityVersion is latest on primary and secondaries except for - // when we run with shardsvr. We expect featureCompatibilityVersion to be last-stable - // for shardsvr. - checkFCV(primaryAdminDB, latestFCV); - - for (let j = 0; j < secondaries.length; j++) { - let secondaryAdminDB = secondaries[j].getDB("admin"); - checkFCV(secondaryAdminDB, latestFCV); - } - - // Ensure all collections have UUIDs and unique indexes are in new version in latest - // featureCompatibilityVersion mode on both primary and secondaries. - checkCollectionUUIDs(primaryAdminDB); - checkUniqueIndexFormatVersion(primaryAdminDB); - for (let j = 0; j < secondaries.length; j++) { - let secondaryAdminDB = secondaries[j].getDB("admin"); - checkCollectionUUIDs(secondaryAdminDB); - checkUniqueIndexFormatVersion(secondaryAdminDB); - } - - // Change featureCompatibilityVersion to last-stable. - setFCV(primaryAdminDB, lastStableFCV); - rst.awaitReplication(); - } - - // Ensure featureCompatibilityVersion is last-stable and all collections still have UUIDs. - checkFCV(primaryAdminDB, lastStableFCV); - for (let j = 0; j < secondaries.length; j++) { - let secondaryAdminDB = secondaries[j].getDB("admin"); - checkFCV(secondaryAdminDB, lastStableFCV); - } - - checkCollectionUUIDs(primaryAdminDB); - for (let j = 0; j < secondaries.length; j++) { - let secondaryAdminDB = secondaries[j].getDB("admin"); - checkCollectionUUIDs(secondaryAdminDB); - } - - // Drop and recreate unique indexes with the older FCV - recreateUniqueIndexes(primaryAdminDB, false); - - // Now drop and recreate unique indexes on secondaries' "local" database - for (let j = 0; j < secondaries.length; j++) { - let secondaryAdminDB = secondaries[j].getDB("admin"); - recreateUniqueIndexes(secondaryAdminDB, true); - } - - // Stop latest binary version replica set. - rst.stopSet(null /* signal */, true /* forRestart */); - - // Downgrade the ReplSetTest binaries and make sure everything is okay. - jsTest.log("Starting a last-stable binVersion ReplSetTest to test downgrade"); - rst.startSet({restart: true, binVersion: lastStableBinary}); - - // Check that the featureCompatiblityVersion is set to last-stable and all - // collections still have UUIDs. - let lastStablePrimaryAdminDB = rst.getPrimary().getDB("admin"); - let lastStableSecondaries = rst.getSecondaries(); - - checkFCV(lastStablePrimaryAdminDB, lastStableFCV); - for (let j = 0; j < lastStableSecondaries.length; j++) { - let secondaryAdminDB = lastStableSecondaries[j].getDB("admin"); - checkFCV(secondaryAdminDB, lastStableFCV); - } - - checkCollectionUUIDs(lastStablePrimaryAdminDB); - for (let j = 0; j < secondaries.length; j++) { - let secondaryAdminDB = lastStableSecondaries[j].getDB("admin"); - checkCollectionUUIDs(secondaryAdminDB); - } - - rst.stopSet(null /* signal */, true /* forRestart */); - - // Start latest binary version replica set again. - jsTest.log("Starting a latest binVersion ReplSetTest to test upgrade"); - rst.startSet({restart: true, binVersion: latestBinary}); - primaryAdminDB = rst.getPrimary().getDB("admin"); - secondaries = rst.getSecondaries(); - - // Ensure all collections have UUIDs and unique indexes are in new version after switching - // back to latest featureCompatibilityVersion on both primary and secondaries. - setFCV(primaryAdminDB, latestFCV); - rst.awaitReplication(); - + // Set featureCompatibilityVersion to last-stable. + setFCV(adminDB, lastStableFCV); + } + + // Ensure featureCompatibilityVersion is last-stable and all collections still have UUIDs. + checkFCV(adminDB, lastStableFCV); + checkCollectionUUIDs(adminDB); + + // Drop and recreate unique indexes with the older FCV + recreateUniqueIndexes(adminDB, false); + + // Stop latest binary version mongod. + MongoRunner.stopMongod(conn); + + // Start last-stable binary version mongod with same dbpath + jsTest.log("Starting a last-stable binVersion standalone to test downgrade"); + let lastStableConn = startMongodWithVersion(noCleanDataOptions, lastStableBinary); + let lastStableAdminDB = lastStableConn.getDB("admin"); + + // Check FCV document. + checkFCV(lastStableAdminDB, lastStableFCV); + + // Ensure all collections still have UUIDs on a last-stable mongod. + checkCollectionUUIDs(lastStableAdminDB); + + // Stop last-stable binary version mongod. + MongoRunner.stopMongod(lastStableConn); + + // Start latest binary version mongod again. + jsTest.log("Starting a latest binVersion standalone to test upgrade"); + conn = startMongodWithVersion(noCleanDataOptions, latestBinary); + adminDB = conn.getDB("admin"); + + // Ensure setFeatureCompatibilityVersion to latest succeeds, all collections have UUIDs + // and all unique indexes are in new version. + setFCV(adminDB, latestFCV); + checkFCV(adminDB, latestFCV); + checkCollectionUUIDs(adminDB); + checkUniqueIndexFormatVersion(adminDB); + + // Stop latest binary version mongod for the last time + MongoRunner.stopMongod(conn); +}; + +// +// Replica set tests. +// +let replicaSetTest = function(nodeOptions) { + // New latest binary version replica set. + jsTest.log("Starting a latest binVersion ReplSetTest"); + let rst = new ReplSetTest({nodes: 3, nodeOptions: nodeOptions}); + rst.startSet(); + rst.initiate(); + let primaryAdminDB = rst.getPrimary().getDB("admin"); + let secondaries = rst.getSecondaries(); + + // Insert some data. + insertDataForConn(rst.getPrimary(), ["admin", "local", "test"], nodeOptions); + rst.awaitReplication(); + + for (let j = 0; j < secondaries.length; j++) { + let secondaryAdminDB = secondaries[j].getDB("admin"); + // Insert some data into the local DB. + insertDataForConn(secondaries[j], ["local"], nodeOptions); + } + + if (!nodeOptions.hasOwnProperty("shardsvr")) { + // Initially featureCompatibilityVersion is latest on primary and secondaries except for + // when we run with shardsvr. We expect featureCompatibilityVersion to be last-stable + // for shardsvr. checkFCV(primaryAdminDB, latestFCV); + for (let j = 0; j < secondaries.length; j++) { let secondaryAdminDB = secondaries[j].getDB("admin"); checkFCV(secondaryAdminDB, latestFCV); } + // Ensure all collections have UUIDs and unique indexes are in new version in latest + // featureCompatibilityVersion mode on both primary and secondaries. checkCollectionUUIDs(primaryAdminDB); checkUniqueIndexFormatVersion(primaryAdminDB); for (let j = 0; j < secondaries.length; j++) { @@ -307,18 +227,96 @@ checkUniqueIndexFormatVersion(secondaryAdminDB); } - rst.stopSet(); - }; - - // Do tests for regular standalones and replica sets. - standaloneTest({}); - replicaSetTest({}); - - // Do tests for standalones and replica sets started with --shardsvr. - standaloneTest({shardsvr: ""}); - replicaSetTest({shardsvr: ""}); - - // Do tests for standalones and replica sets started with --configsvr. - standaloneTest({configsvr: ""}); - replicaSetTest({configsvr: ""}); + // Change featureCompatibilityVersion to last-stable. + setFCV(primaryAdminDB, lastStableFCV); + rst.awaitReplication(); + } + + // Ensure featureCompatibilityVersion is last-stable and all collections still have UUIDs. + checkFCV(primaryAdminDB, lastStableFCV); + for (let j = 0; j < secondaries.length; j++) { + let secondaryAdminDB = secondaries[j].getDB("admin"); + checkFCV(secondaryAdminDB, lastStableFCV); + } + + checkCollectionUUIDs(primaryAdminDB); + for (let j = 0; j < secondaries.length; j++) { + let secondaryAdminDB = secondaries[j].getDB("admin"); + checkCollectionUUIDs(secondaryAdminDB); + } + + // Drop and recreate unique indexes with the older FCV + recreateUniqueIndexes(primaryAdminDB, false); + + // Now drop and recreate unique indexes on secondaries' "local" database + for (let j = 0; j < secondaries.length; j++) { + let secondaryAdminDB = secondaries[j].getDB("admin"); + recreateUniqueIndexes(secondaryAdminDB, true); + } + + // Stop latest binary version replica set. + rst.stopSet(null /* signal */, true /* forRestart */); + + // Downgrade the ReplSetTest binaries and make sure everything is okay. + jsTest.log("Starting a last-stable binVersion ReplSetTest to test downgrade"); + rst.startSet({restart: true, binVersion: lastStableBinary}); + + // Check that the featureCompatiblityVersion is set to last-stable and all + // collections still have UUIDs. + let lastStablePrimaryAdminDB = rst.getPrimary().getDB("admin"); + let lastStableSecondaries = rst.getSecondaries(); + + checkFCV(lastStablePrimaryAdminDB, lastStableFCV); + for (let j = 0; j < lastStableSecondaries.length; j++) { + let secondaryAdminDB = lastStableSecondaries[j].getDB("admin"); + checkFCV(secondaryAdminDB, lastStableFCV); + } + + checkCollectionUUIDs(lastStablePrimaryAdminDB); + for (let j = 0; j < secondaries.length; j++) { + let secondaryAdminDB = lastStableSecondaries[j].getDB("admin"); + checkCollectionUUIDs(secondaryAdminDB); + } + + rst.stopSet(null /* signal */, true /* forRestart */); + + // Start latest binary version replica set again. + jsTest.log("Starting a latest binVersion ReplSetTest to test upgrade"); + rst.startSet({restart: true, binVersion: latestBinary}); + primaryAdminDB = rst.getPrimary().getDB("admin"); + secondaries = rst.getSecondaries(); + + // Ensure all collections have UUIDs and unique indexes are in new version after switching + // back to latest featureCompatibilityVersion on both primary and secondaries. + setFCV(primaryAdminDB, latestFCV); + rst.awaitReplication(); + + checkFCV(primaryAdminDB, latestFCV); + for (let j = 0; j < secondaries.length; j++) { + let secondaryAdminDB = secondaries[j].getDB("admin"); + checkFCV(secondaryAdminDB, latestFCV); + } + + checkCollectionUUIDs(primaryAdminDB); + checkUniqueIndexFormatVersion(primaryAdminDB); + for (let j = 0; j < secondaries.length; j++) { + let secondaryAdminDB = secondaries[j].getDB("admin"); + checkCollectionUUIDs(secondaryAdminDB); + checkUniqueIndexFormatVersion(secondaryAdminDB); + } + + rst.stopSet(); +}; + +// Do tests for regular standalones and replica sets. +standaloneTest({}); +replicaSetTest({}); + +// Do tests for standalones and replica sets started with --shardsvr. +standaloneTest({shardsvr: ""}); +replicaSetTest({shardsvr: ""}); + +// Do tests for standalones and replica sets started with --configsvr. +standaloneTest({configsvr: ""}); +replicaSetTest({configsvr: ""}); })(); diff --git a/jstests/multiVersion/genericSetFCVUsage/feature_compatibility_version_lagging_secondary.js b/jstests/multiVersion/genericSetFCVUsage/feature_compatibility_version_lagging_secondary.js index 008164a5a80..2148a26111e 100644 --- a/jstests/multiVersion/genericSetFCVUsage/feature_compatibility_version_lagging_secondary.js +++ b/jstests/multiVersion/genericSetFCVUsage/feature_compatibility_version_lagging_secondary.js @@ -1,53 +1,52 @@ // Tests that a primary with upgrade featureCompatibilityVersion cannot connect with a secondary // with a lower binary version. (function() { - "use strict"; +"use strict"; - load("jstests/libs/feature_compatibility_version.js"); - load("jstests/libs/write_concern_util.js"); +load("jstests/libs/feature_compatibility_version.js"); +load("jstests/libs/write_concern_util.js"); - const latest = "latest"; - const downgrade = "last-stable"; +const latest = "latest"; +const downgrade = "last-stable"; - // Start a new replica set with two latest version nodes. - let rst = new ReplSetTest({ - nodes: [{binVersion: latest}, {binVersion: latest, rsConfig: {priority: 0}}], - settings: {chainingAllowed: false} - }); - rst.startSet(); - rst.initiate(); +// Start a new replica set with two latest version nodes. +let rst = new ReplSetTest({ + nodes: [{binVersion: latest}, {binVersion: latest, rsConfig: {priority: 0}}], + settings: {chainingAllowed: false} +}); +rst.startSet(); +rst.initiate(); - let primary = rst.getPrimary(); - let latestSecondary = rst.getSecondary(); +let primary = rst.getPrimary(); +let latestSecondary = rst.getSecondary(); - // Set the featureCompatibilityVersion to the downgrade version so that a downgrade node can - // join the set. - assert.commandWorked( - primary.getDB("admin").runCommand({setFeatureCompatibilityVersion: lastStableFCV})); +// Set the featureCompatibilityVersion to the downgrade version so that a downgrade node can +// join the set. +assert.commandWorked( + primary.getDB("admin").runCommand({setFeatureCompatibilityVersion: lastStableFCV})); - // Add a downgrade node to the set. - let downgradeSecondary = rst.add({binVersion: downgrade, rsConfig: {priority: 0}}); - rst.reInitiate(); +// Add a downgrade node to the set. +let downgradeSecondary = rst.add({binVersion: downgrade, rsConfig: {priority: 0}}); +rst.reInitiate(); - // Wait for the downgrade secondary to finish initial sync. - rst.awaitSecondaryNodes(); - rst.awaitReplication(); +// Wait for the downgrade secondary to finish initial sync. +rst.awaitSecondaryNodes(); +rst.awaitReplication(); - // Stop replication on the downgrade secondary. - stopServerReplication(downgradeSecondary); +// Stop replication on the downgrade secondary. +stopServerReplication(downgradeSecondary); - // Set the featureCompatibilityVersion to the upgrade version. This will not replicate to - // the downgrade secondary, but the downgrade secondary will no longer be able to - // communicate with the rest of the set. - assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV})); +// Set the featureCompatibilityVersion to the upgrade version. This will not replicate to +// the downgrade secondary, but the downgrade secondary will no longer be able to +// communicate with the rest of the set. +assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV})); - // Shut down the latest version secondary. - rst.stop(latestSecondary); +// Shut down the latest version secondary. +rst.stop(latestSecondary); - // The primary should step down, since it can no longer see a majority of the replica set. - rst.waitForState(primary, ReplSetTest.State.SECONDARY); - - restartServerReplication(downgradeSecondary); - rst.stopSet(); +// The primary should step down, since it can no longer see a majority of the replica set. +rst.waitForState(primary, ReplSetTest.State.SECONDARY); +restartServerReplication(downgradeSecondary); +rst.stopSet(); })(); diff --git a/jstests/multiVersion/genericSetFCVUsage/major_version_upgrade.js b/jstests/multiVersion/genericSetFCVUsage/major_version_upgrade.js index 6e54a1f0642..273695dbc05 100644 --- a/jstests/multiVersion/genericSetFCVUsage/major_version_upgrade.js +++ b/jstests/multiVersion/genericSetFCVUsage/major_version_upgrade.js @@ -10,299 +10,291 @@ */ (function() { - 'use strict'; - - load('jstests/libs/get_index_helpers.js'); - load('jstests/multiVersion/libs/multi_rs.js'); - load('jstests/multiVersion/libs/verify_versions.js'); - - // Setup the dbpath for this test. - const dbpath = MongoRunner.dataPath + 'major_version_upgrade'; - resetDbpath(dbpath); - - // We set noCleanData to true in order to preserve the data files between iterations. - const defaultOptions = { - dbpath: dbpath, - noCleanData: true, - }; - - // This lists all supported releases and needs to be kept up to date as versions are added and - // dropped. - // TODO SERVER-26792: In the future, we should have a common place from which both the - // multiversion setup procedure and this test get information about supported major releases. - const versions = [ - {binVersion: '3.2', testCollection: 'three_two'}, - {binVersion: '3.4', featureCompatibilityVersion: '3.4', testCollection: 'three_four'}, - {binVersion: '3.6', featureCompatibilityVersion: '3.6', testCollection: 'three_six'}, - {binVersion: '4.0', featureCompatibilityVersion: '4.0', testCollection: 'four_zero'}, - {binVersion: 'last-stable', testCollection: 'last_stable'}, - {binVersion: 'latest', featureCompatibilityVersion: '4.2', testCollection: 'latest'}, - ]; - - // These key patterns are considered valid for existing v:0 and v:1 indexes, but are considered - // invalid for v:2 indexes or new index builds. - var invalidIndexSpecs = [ - {a: 0}, - {a: NaN}, - {a: true}, - ]; - - // When running the oldest supported version, insert indexes with bad key patterns. - function insertBadIndexes(testDB) { - invalidIndexSpecs.forEach((spec) => { - // Generate a unique and identifiable collection name. - let collName = 'bad_index_' + tojson(spec.a); - assert.commandWorked(testDB[collName].createIndex(spec, {name: 'badkp'}), - 'failed to create index with key pattern' + tojson(spec)); - - }); - } +'use strict'; + +load('jstests/libs/get_index_helpers.js'); +load('jstests/multiVersion/libs/multi_rs.js'); +load('jstests/multiVersion/libs/verify_versions.js'); + +// Setup the dbpath for this test. +const dbpath = MongoRunner.dataPath + 'major_version_upgrade'; +resetDbpath(dbpath); + +// We set noCleanData to true in order to preserve the data files between iterations. +const defaultOptions = { + dbpath: dbpath, + noCleanData: true, +}; + +// This lists all supported releases and needs to be kept up to date as versions are added and +// dropped. +// TODO SERVER-26792: In the future, we should have a common place from which both the +// multiversion setup procedure and this test get information about supported major releases. +const versions = [ + {binVersion: '3.2', testCollection: 'three_two'}, + {binVersion: '3.4', featureCompatibilityVersion: '3.4', testCollection: 'three_four'}, + {binVersion: '3.6', featureCompatibilityVersion: '3.6', testCollection: 'three_six'}, + {binVersion: '4.0', featureCompatibilityVersion: '4.0', testCollection: 'four_zero'}, + {binVersion: 'last-stable', testCollection: 'last_stable'}, + {binVersion: 'latest', featureCompatibilityVersion: '4.2', testCollection: 'latest'}, +]; + +// These key patterns are considered valid for existing v:0 and v:1 indexes, but are considered +// invalid for v:2 indexes or new index builds. +var invalidIndexSpecs = [ + {a: 0}, + {a: NaN}, + {a: true}, +]; + +// When running the oldest supported version, insert indexes with bad key patterns. +function insertBadIndexes(testDB) { + invalidIndexSpecs.forEach((spec) => { + // Generate a unique and identifiable collection name. + let collName = 'bad_index_' + tojson(spec.a); + assert.commandWorked(testDB[collName].createIndex(spec, {name: 'badkp'}), + 'failed to create index with key pattern' + tojson(spec)); + }); +} + +// When running the newest version, check that the indexes with bad key patterns are readable. +function validateBadIndexesStandalone(testDB) { + invalidIndexSpecs.forEach((spec) => { + // Generate a unique and identifiable collection name. + let collName = 'bad_index_' + tojson(spec.a); + let indexSpec = GetIndexHelpers.findByName(testDB[collName].getIndexes(), 'badkp'); + assert.neq(null, indexSpec, 'could not find index "badkp"'); + assert.eq(1, indexSpec.v, tojson(indexSpec)); + + // Collection compact command should succeed, despite the presence of the v:1 index + // which would fail v:2 validation rules. + assert.commandWorked(testDB.runCommand({compact: collName})); + + // reIndex will fail because when featureCompatibilityVersion>=3.4, reIndex + // automatically upgrades v=1 indexes to v=2. + assert.commandFailed(testDB[collName].reIndex()); + + // reIndex should not drop the index. + indexSpec = GetIndexHelpers.findByName(testDB[collName].getIndexes(), 'badkp'); + assert.neq(null, indexSpec, 'could not find index "badkp" after reIndex'); + assert.eq(1, indexSpec.v, tojson(indexSpec)); + + // A query that hints the index should succeed. + assert.commandWorked(testDB.runCommand({find: collName, hint: "badkp"})); + + // Newly created indexes will do stricter validation and should fail if the + // key pattern is invalid. + assert.commandWorked(testDB[collName].dropIndexes()); + assert.commandFailedWithCode( + testDB[collName].createIndex(spec), + ErrorCodes.CannotCreateIndex, + 'creating index with key pattern ' + tojson(spec) + ' unexpectedly succeeded'); + // Index build should also fail if v:1 or v:2 is explicitly requested. + assert.commandFailedWithCode( + testDB[collName].createIndex(spec, {v: 1}), + ErrorCodes.CannotCreateIndex, + 'creating index with key pattern ' + tojson(spec) + ' unexpectedly succeeded'); + assert.commandFailedWithCode( + testDB[collName].createIndex(spec, {v: 2}), + ErrorCodes.CannotCreateIndex, + 'creating index with key pattern ' + tojson(spec) + ' unexpectedly succeeded'); + }); +} + +// Check that secondary nodes have the v:1 indexes. +function validateBadIndexesSecondary(testDB) { + invalidIndexSpecs.forEach((spec) => { + // Generate a unique and identifiable collection name. + let collName = 'bad_index_' + tojson(spec.a); + // Verify that the secondary has the v:1 index. + let indexSpec = GetIndexHelpers.findByName(testDB[collName].getIndexes(), 'badkp'); + assert.neq(null, indexSpec, 'could not find index "badkp"'); + assert.eq(1, indexSpec.v, tojson(indexSpec)); + }); +} + +// Standalone +// Iterate from earliest to latest versions specified in the versions list, and follow the steps +// outlined at the top of this test file. +let authSchemaUpgraded = false; +for (let i = 0; i < versions.length; i++) { + let version = versions[i]; + let mongodOptions = Object.extend({binVersion: version.binVersion}, defaultOptions); + + // Start a mongod with specified version. + let conn = MongoRunner.runMongod(mongodOptions); + + if ((conn === null) && (i > 0) && !authSchemaUpgraded) { + // As of 4.0, mongod will refuse to start up with authSchema 3 + // until the schema has been upgraded. + // Step back a version (to 3.6) in order to perform the upgrade, + // Then try startuing 4.0 again. + print( + "Failed starting mongod, going to try upgrading the auth schema on the prior version"); + conn = MongoRunner.runMongod( + Object.extend({binVersion: versions[i - 1].binVersion}, defaultOptions)); + assert.neq(null, + conn, + 'mongod was previously able to start with version ' + + tojson(version.binVersion) + " but now can't"); + assert.commandWorked(conn.getDB('admin').runCommand({authSchemaUpgrade: 1})); + MongoRunner.stopMongod(conn); - // When running the newest version, check that the indexes with bad key patterns are readable. - function validateBadIndexesStandalone(testDB) { - invalidIndexSpecs.forEach((spec) => { - // Generate a unique and identifiable collection name. - let collName = 'bad_index_' + tojson(spec.a); - let indexSpec = GetIndexHelpers.findByName(testDB[collName].getIndexes(), 'badkp'); - assert.neq(null, indexSpec, 'could not find index "badkp"'); - assert.eq(1, indexSpec.v, tojson(indexSpec)); - - // Collection compact command should succeed, despite the presence of the v:1 index - // which would fail v:2 validation rules. - assert.commandWorked(testDB.runCommand({compact: collName})); - - // reIndex will fail because when featureCompatibilityVersion>=3.4, reIndex - // automatically upgrades v=1 indexes to v=2. - assert.commandFailed(testDB[collName].reIndex()); - - // reIndex should not drop the index. - indexSpec = GetIndexHelpers.findByName(testDB[collName].getIndexes(), 'badkp'); - assert.neq(null, indexSpec, 'could not find index "badkp" after reIndex'); - assert.eq(1, indexSpec.v, tojson(indexSpec)); - - // A query that hints the index should succeed. - assert.commandWorked(testDB.runCommand({find: collName, hint: "badkp"})); - - // Newly created indexes will do stricter validation and should fail if the - // key pattern is invalid. - assert.commandWorked(testDB[collName].dropIndexes()); - assert.commandFailedWithCode( - testDB[collName].createIndex(spec), - ErrorCodes.CannotCreateIndex, - 'creating index with key pattern ' + tojson(spec) + ' unexpectedly succeeded'); - // Index build should also fail if v:1 or v:2 is explicitly requested. - assert.commandFailedWithCode( - testDB[collName].createIndex(spec, {v: 1}), - ErrorCodes.CannotCreateIndex, - 'creating index with key pattern ' + tojson(spec) + ' unexpectedly succeeded'); - assert.commandFailedWithCode( - testDB[collName].createIndex(spec, {v: 2}), - ErrorCodes.CannotCreateIndex, - 'creating index with key pattern ' + tojson(spec) + ' unexpectedly succeeded'); - - }); + authSchemaUpgraded = true; + conn = MongoRunner.runMongod(mongodOptions); } - // Check that secondary nodes have the v:1 indexes. - function validateBadIndexesSecondary(testDB) { - invalidIndexSpecs.forEach((spec) => { - // Generate a unique and identifiable collection name. - let collName = 'bad_index_' + tojson(spec.a); - // Verify that the secondary has the v:1 index. - let indexSpec = GetIndexHelpers.findByName(testDB[collName].getIndexes(), 'badkp'); - assert.neq(null, indexSpec, 'could not find index "badkp"'); - assert.eq(1, indexSpec.v, tojson(indexSpec)); - }); + assert.neq(null, conn, 'mongod was unable to start up with options: ' + tojson(mongodOptions)); + assert.binVersion(conn, version.binVersion); + + if ((i === 0) && (version.binVersion <= 3.6)) { + // Simulate coming from a <= 2.6 installation where MONGODB-CR was the default/only + // authentication mechanism. Eventually, the upgrade process will fail (above) when + // running on 4.0 where support for MONGODB-CR has been removed. + conn.getDB('admin').system.version.save({"_id": "authSchema", "currentVersion": 3}); } - // Standalone - // Iterate from earliest to latest versions specified in the versions list, and follow the steps - // outlined at the top of this test file. - let authSchemaUpgraded = false; - for (let i = 0; i < versions.length; i++) { - let version = versions[i]; - let mongodOptions = Object.extend({binVersion: version.binVersion}, defaultOptions); - - // Start a mongod with specified version. - let conn = MongoRunner.runMongod(mongodOptions); - - if ((conn === null) && (i > 0) && !authSchemaUpgraded) { - // As of 4.0, mongod will refuse to start up with authSchema 3 - // until the schema has been upgraded. - // Step back a version (to 3.6) in order to perform the upgrade, - // Then try startuing 4.0 again. - print( - "Failed starting mongod, going to try upgrading the auth schema on the prior version"); - conn = MongoRunner.runMongod( - Object.extend({binVersion: versions[i - 1].binVersion}, defaultOptions)); - assert.neq(null, - conn, - 'mongod was previously able to start with version ' + - tojson(version.binVersion) + " but now can't"); - assert.commandWorked(conn.getDB('admin').runCommand({authSchemaUpgrade: 1})); - MongoRunner.stopMongod(conn); - - authSchemaUpgraded = true; - conn = MongoRunner.runMongod(mongodOptions); - } + // Connect to the 'test' database. + let testDB = conn.getDB('test'); + // Verify that the data and indices from previous iterations are still accessible. + for (let j = 0; j < i; j++) { + let oldVersionCollection = versions[j].testCollection; + assert.eq(1, + testDB[oldVersionCollection].count(), + `data from ${oldVersionCollection} should be available; options: ` + + tojson(mongodOptions)); assert.neq( - null, conn, 'mongod was unable to start up with options: ' + tojson(mongodOptions)); - assert.binVersion(conn, version.binVersion); - - if ((i === 0) && (version.binVersion <= 3.6)) { - // Simulate coming from a <= 2.6 installation where MONGODB-CR was the default/only - // authentication mechanism. Eventually, the upgrade process will fail (above) when - // running on 4.0 where support for MONGODB-CR has been removed. - conn.getDB('admin').system.version.save({"_id": "authSchema", "currentVersion": 3}); - } + null, + GetIndexHelpers.findByKeyPattern(testDB[oldVersionCollection].getIndexes(), {a: 1}), + `index from ${oldVersionCollection} should be available; options: ` + + tojson(mongodOptions)); + } - // Connect to the 'test' database. - let testDB = conn.getDB('test'); - - // Verify that the data and indices from previous iterations are still accessible. - for (let j = 0; j < i; j++) { - let oldVersionCollection = versions[j].testCollection; - assert.eq(1, - testDB[oldVersionCollection].count(), - `data from ${oldVersionCollection} should be available; options: ` + - tojson(mongodOptions)); - assert.neq( - null, - GetIndexHelpers.findByKeyPattern(testDB[oldVersionCollection].getIndexes(), {a: 1}), - `index from ${oldVersionCollection} should be available; options: ` + - tojson(mongodOptions)); - } + // Create a new collection. + assert.commandWorked(testDB.createCollection(version.testCollection)); + + // Insert a document into the new collection. + assert.writeOK(testDB[version.testCollection].insert({a: 1})); + assert.eq(1, + testDB[version.testCollection].count(), + `mongo should have inserted 1 document into collection ${version.testCollection}; ` + + 'options: ' + tojson(mongodOptions)); + + // Create an index on the new collection. + assert.commandWorked(testDB[version.testCollection].createIndex({a: 1})); + + if (i === 0) { + // We're on the earliest version, insert indexes with bad key patterns. + insertBadIndexes(testDB); + } else if (i === versions.length - 1) { + // We're on the latest version, check bad indexes are still readable. + validateBadIndexesStandalone(testDB); + } - // Create a new collection. - assert.commandWorked(testDB.createCollection(version.testCollection)); - - // Insert a document into the new collection. - assert.writeOK(testDB[version.testCollection].insert({a: 1})); - assert.eq( - 1, - testDB[version.testCollection].count(), - `mongo should have inserted 1 document into collection ${version.testCollection}; ` + - 'options: ' + tojson(mongodOptions)); - - // Create an index on the new collection. - assert.commandWorked(testDB[version.testCollection].createIndex({a: 1})); - - if (i === 0) { - // We're on the earliest version, insert indexes with bad key patterns. - insertBadIndexes(testDB); - } else if (i === versions.length - 1) { - // We're on the latest version, check bad indexes are still readable. - validateBadIndexesStandalone(testDB); - } + // Set the appropriate featureCompatibilityVersion upon upgrade, if applicable. + if (version.hasOwnProperty('featureCompatibilityVersion')) { + let adminDB = conn.getDB("admin"); + assert.commandWorked(adminDB.runCommand( + {"setFeatureCompatibilityVersion": version.featureCompatibilityVersion})); + } - // Set the appropriate featureCompatibilityVersion upon upgrade, if applicable. - if (version.hasOwnProperty('featureCompatibilityVersion')) { - let adminDB = conn.getDB("admin"); - assert.commandWorked(adminDB.runCommand( - {"setFeatureCompatibilityVersion": version.featureCompatibilityVersion})); + // Shutdown the current mongod. + MongoRunner.stopMongod(conn); +} + +// Replica Sets +// Setup the ReplSetTest object. +let nodes = { + n1: {binVersion: versions[0].binVersion}, + n2: {binVersion: versions[0].binVersion}, + n3: {binVersion: versions[0].binVersion}, +}; +let rst = new ReplSetTest({nodes}); + +// Start up and initiate the replica set. +rst.startSet(); +rst.initiate(); + +// Iterate from earliest to latest versions specified in the versions list, and follow the steps +// outlined at the top of this test file. +for (let i = 0; i < versions.length; i++) { + let version = versions[i]; + + // Connect to the primary running the old version to ensure that the test can insert and + // create indices. + let primary = rst.getPrimary(); + + // Upgrade the secondary nodes first. + rst.upgradeSecondaries(primary, {binVersion: version.binVersion}); + + assert.neq(null, + primary, + `replica set was unable to start up after upgrading secondaries to version: ${ + version.binVersion}`); + + // Connect to the 'test' database. + let testDB = primary.getDB('test'); + assert.commandWorked(testDB.createCollection(version.testCollection)); + assert.writeOK(testDB[version.testCollection].insert({a: 1})); + assert.eq(1, + testDB[version.testCollection].count(), + `mongo should have inserted 1 document into collection ${version.testCollection}; ` + + 'nodes: ' + tojson(nodes)); + + // Create an index on the new collection. + assert.commandWorked(testDB[version.testCollection].createIndex({a: 1})); + + if (i === 0) { + // We're on the earliest version, insert indexes with bad key patterns. + insertBadIndexes(testDB); + } else if (i === versions.length - 1) { + // We're on the latest version, check bad indexes are still readable. + for (let secondary of rst.getSecondaries()) { + validateBadIndexesSecondary(secondary.getDB('test')); } - - // Shutdown the current mongod. - MongoRunner.stopMongod(conn); } - // Replica Sets - // Setup the ReplSetTest object. - let nodes = { - n1: {binVersion: versions[0].binVersion}, - n2: {binVersion: versions[0].binVersion}, - n3: {binVersion: versions[0].binVersion}, - }; - let rst = new ReplSetTest({nodes}); - - // Start up and initiate the replica set. - rst.startSet(); - rst.initiate(); - - // Iterate from earliest to latest versions specified in the versions list, and follow the steps - // outlined at the top of this test file. - for (let i = 0; i < versions.length; i++) { - let version = versions[i]; - - // Connect to the primary running the old version to ensure that the test can insert and - // create indices. - let primary = rst.getPrimary(); - - // Upgrade the secondary nodes first. - rst.upgradeSecondaries(primary, {binVersion: version.binVersion}); - + // Do the index creation and insertion again after upgrading the primary node. + primary = rst.upgradePrimary(primary, {binVersion: version.binVersion}); + assert.neq( + null, primary, `replica set was unable to start up with version: ${version.binVersion}`); + assert.binVersion(primary, version.binVersion); + testDB = primary.getDB('test'); + + assert.writeOK(testDB[version.testCollection].insert({b: 1})); + assert.eq(2, + testDB[version.testCollection].count(), + `mongo should have inserted 2 documents into collection ${version.testCollection}; ` + + 'nodes: ' + tojson(nodes)); + + assert.commandWorked(testDB[version.testCollection].createIndex({b: 1})); + + // Verify that all previously inserted data and indices are accessible. + for (let j = 0; j <= i; j++) { + let oldVersionCollection = versions[j].testCollection; + assert.eq(2, + testDB[oldVersionCollection].count(), + `data from ${oldVersionCollection} should be available; nodes: ${tojson(nodes)}`); assert.neq( null, - primary, - `replica set was unable to start up after upgrading secondaries to version: ${version.binVersion}`); - - // Connect to the 'test' database. - let testDB = primary.getDB('test'); - assert.commandWorked(testDB.createCollection(version.testCollection)); - assert.writeOK(testDB[version.testCollection].insert({a: 1})); - assert.eq( - 1, - testDB[version.testCollection].count(), - `mongo should have inserted 1 document into collection ${version.testCollection}; ` + - 'nodes: ' + tojson(nodes)); - - // Create an index on the new collection. - assert.commandWorked(testDB[version.testCollection].createIndex({a: 1})); - - if (i === 0) { - // We're on the earliest version, insert indexes with bad key patterns. - insertBadIndexes(testDB); - } else if (i === versions.length - 1) { - // We're on the latest version, check bad indexes are still readable. - for (let secondary of rst.getSecondaries()) { - validateBadIndexesSecondary(secondary.getDB('test')); - } - } - - // Do the index creation and insertion again after upgrading the primary node. - primary = rst.upgradePrimary(primary, {binVersion: version.binVersion}); - assert.neq(null, - primary, - `replica set was unable to start up with version: ${version.binVersion}`); - assert.binVersion(primary, version.binVersion); - testDB = primary.getDB('test'); - - assert.writeOK(testDB[version.testCollection].insert({b: 1})); - assert.eq( - 2, - testDB[version.testCollection].count(), - `mongo should have inserted 2 documents into collection ${version.testCollection}; ` + - 'nodes: ' + tojson(nodes)); - - assert.commandWorked(testDB[version.testCollection].createIndex({b: 1})); - - // Verify that all previously inserted data and indices are accessible. - for (let j = 0; j <= i; j++) { - let oldVersionCollection = versions[j].testCollection; - assert.eq( - 2, - testDB[oldVersionCollection].count(), - `data from ${oldVersionCollection} should be available; nodes: ${tojson(nodes)}`); - assert.neq( - null, - GetIndexHelpers.findByKeyPattern(testDB[oldVersionCollection].getIndexes(), {a: 1}), - `index from ${oldVersionCollection} should be available; nodes: ${tojson(nodes)}`); - assert.neq( - null, - GetIndexHelpers.findByKeyPattern(testDB[oldVersionCollection].getIndexes(), {b: 1}), - `index from ${oldVersionCollection} should be available; nodes: ${tojson(nodes)}`); - } + GetIndexHelpers.findByKeyPattern(testDB[oldVersionCollection].getIndexes(), {a: 1}), + `index from ${oldVersionCollection} should be available; nodes: ${tojson(nodes)}`); + assert.neq( + null, + GetIndexHelpers.findByKeyPattern(testDB[oldVersionCollection].getIndexes(), {b: 1}), + `index from ${oldVersionCollection} should be available; nodes: ${tojson(nodes)}`); + } - // Set the appropriate featureCompatibilityVersion upon upgrade, if applicable. - if (version.hasOwnProperty('featureCompatibilityVersion')) { - let primaryAdminDB = primary.getDB("admin"); - assert.commandWorked(primaryAdminDB.runCommand( - {setFeatureCompatibilityVersion: version.featureCompatibilityVersion})); - rst.awaitReplication(); - } + // Set the appropriate featureCompatibilityVersion upon upgrade, if applicable. + if (version.hasOwnProperty('featureCompatibilityVersion')) { + let primaryAdminDB = primary.getDB("admin"); + assert.commandWorked(primaryAdminDB.runCommand( + {setFeatureCompatibilityVersion: version.featureCompatibilityVersion})); + rst.awaitReplication(); } +} - // Stop the replica set. - rst.stopSet(); +// Stop the replica set. +rst.stopSet(); })(); diff --git a/jstests/multiVersion/genericSetFCVUsage/migration_between_mixed_FCV_mixed_version_mongods.js b/jstests/multiVersion/genericSetFCVUsage/migration_between_mixed_FCV_mixed_version_mongods.js index fe78152e548..b2b2aee05ad 100644 --- a/jstests/multiVersion/genericSetFCVUsage/migration_between_mixed_FCV_mixed_version_mongods.js +++ b/jstests/multiVersion/genericSetFCVUsage/migration_between_mixed_FCV_mixed_version_mongods.js @@ -4,38 +4,37 @@ */ (function() { - "use strict"; - - load("jstests/libs/feature_compatibility_version.js"); - - let st = new ShardingTest({ - shards: [{binVersion: "latest"}, {binVersion: "last-stable"}], - mongos: {binVersion: "latest"}, - other: {shardAsReplicaSet: false}, - }); - - let testDB = st.s.getDB("test"); - - // Create a sharded collection with primary shard 0. - assert.commandWorked(st.s.adminCommand({enableSharding: testDB.getName()})); - st.ensurePrimaryShard(testDB.getName(), st.shard0.shardName); - assert.commandWorked( - st.s.adminCommand({shardCollection: testDB.coll.getFullName(), key: {a: 1}})); - - // Set the featureCompatibilityVersion to latestFCV. This will fail because the - // featureCompatibilityVersion cannot be set to latestFCV on shard 1, but it will set the - // featureCompatibilityVersion to latestFCV on shard 0. - assert.commandFailed(st.s.adminCommand({setFeatureCompatibilityVersion: latestFCV})); - checkFCV(st.configRS.getPrimary().getDB("admin"), lastStableFCV, latestFCV); - checkFCV(st.shard0.getDB("admin"), latestFCV); - checkFCV(st.shard1.getDB("admin"), lastStableFCV); - - // It is not possible to move a chunk from a latestFCV shard to a last-stable binary version - // shard. - assert.commandFailedWithCode( - st.s.adminCommand( - {moveChunk: testDB.coll.getFullName(), find: {a: 1}, to: st.shard1.shardName}), - ErrorCodes.IncompatibleServerVersion); - - st.stop(); +"use strict"; + +load("jstests/libs/feature_compatibility_version.js"); + +let st = new ShardingTest({ + shards: [{binVersion: "latest"}, {binVersion: "last-stable"}], + mongos: {binVersion: "latest"}, + other: {shardAsReplicaSet: false}, +}); + +let testDB = st.s.getDB("test"); + +// Create a sharded collection with primary shard 0. +assert.commandWorked(st.s.adminCommand({enableSharding: testDB.getName()})); +st.ensurePrimaryShard(testDB.getName(), st.shard0.shardName); +assert.commandWorked(st.s.adminCommand({shardCollection: testDB.coll.getFullName(), key: {a: 1}})); + +// Set the featureCompatibilityVersion to latestFCV. This will fail because the +// featureCompatibilityVersion cannot be set to latestFCV on shard 1, but it will set the +// featureCompatibilityVersion to latestFCV on shard 0. +assert.commandFailed(st.s.adminCommand({setFeatureCompatibilityVersion: latestFCV})); +checkFCV(st.configRS.getPrimary().getDB("admin"), lastStableFCV, latestFCV); +checkFCV(st.shard0.getDB("admin"), latestFCV); +checkFCV(st.shard1.getDB("admin"), lastStableFCV); + +// It is not possible to move a chunk from a latestFCV shard to a last-stable binary version +// shard. +assert.commandFailedWithCode( + st.s.adminCommand( + {moveChunk: testDB.coll.getFullName(), find: {a: 1}, to: st.shard1.shardName}), + ErrorCodes.IncompatibleServerVersion); + +st.stop(); })(); diff --git a/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_primary.js b/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_primary.js index 54e654c4dcb..48e710d330d 100644 --- a/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_primary.js +++ b/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_primary.js @@ -1,14 +1,14 @@ (function() { - 'use strict'; +'use strict'; - load("jstests/libs/feature_compatibility_version.js"); - load("jstests/replsets/libs/rename_across_dbs.js"); +load("jstests/libs/feature_compatibility_version.js"); +load("jstests/replsets/libs/rename_across_dbs.js"); - const nodes = [{binVersion: 'last-stable'}, {binVersion: 'latest'}, {}]; - const options = { - nodes: nodes, - setFeatureCompatibilityVersion: lastStableFCV, - }; +const nodes = [{binVersion: 'last-stable'}, {binVersion: 'latest'}, {}]; +const options = { + nodes: nodes, + setFeatureCompatibilityVersion: lastStableFCV, +}; - new RenameAcrossDatabasesTest(options).run(); +new RenameAcrossDatabasesTest(options).run(); }()); diff --git a/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_primary_drop_target.js b/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_primary_drop_target.js index 4cdab3f5a61..a1e5869800d 100644 --- a/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_primary_drop_target.js +++ b/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_primary_drop_target.js @@ -1,15 +1,15 @@ (function() { - 'use strict'; +'use strict'; - load("jstests/libs/feature_compatibility_version.js"); - load("jstests/replsets/libs/rename_across_dbs.js"); +load("jstests/libs/feature_compatibility_version.js"); +load("jstests/replsets/libs/rename_across_dbs.js"); - const nodes = [{binVersion: 'last-stable'}, {binVersion: 'latest'}, {}]; - const options = { - nodes: nodes, - setFeatureCompatibilityVersion: lastStableFCV, - dropTarget: true, - }; +const nodes = [{binVersion: 'last-stable'}, {binVersion: 'latest'}, {}]; +const options = { + nodes: nodes, + setFeatureCompatibilityVersion: lastStableFCV, + dropTarget: true, +}; - new RenameAcrossDatabasesTest(options).run(); +new RenameAcrossDatabasesTest(options).run(); }()); diff --git a/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_secondary.js b/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_secondary.js index 3fd541a0ffc..2fb9c126ca6 100644 --- a/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_secondary.js +++ b/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_secondary.js @@ -1,14 +1,14 @@ (function() { - 'use strict'; +'use strict'; - load("jstests/libs/feature_compatibility_version.js"); - load("jstests/replsets/libs/rename_across_dbs.js"); +load("jstests/libs/feature_compatibility_version.js"); +load("jstests/replsets/libs/rename_across_dbs.js"); - const nodes = [{binVersion: 'latest'}, {binVersion: 'last-stable'}, {}]; - const options = { - nodes: nodes, - setFeatureCompatibilityVersion: lastStableFCV, - }; +const nodes = [{binVersion: 'latest'}, {binVersion: 'last-stable'}, {}]; +const options = { + nodes: nodes, + setFeatureCompatibilityVersion: lastStableFCV, +}; - new RenameAcrossDatabasesTest(options).run(); +new RenameAcrossDatabasesTest(options).run(); }()); diff --git a/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_secondary_drop_target.js b/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_secondary_drop_target.js index 90ca1312db3..814fa096f47 100644 --- a/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_secondary_drop_target.js +++ b/jstests/multiVersion/genericSetFCVUsage/rename_across_dbs_last_stable_secondary_drop_target.js @@ -1,15 +1,15 @@ (function() { - 'use strict'; +'use strict'; - load("jstests/libs/feature_compatibility_version.js"); - load("jstests/replsets/libs/rename_across_dbs.js"); +load("jstests/libs/feature_compatibility_version.js"); +load("jstests/replsets/libs/rename_across_dbs.js"); - const nodes = [{binVersion: 'latest'}, {binVersion: 'last-stable'}, {}]; - const options = { - nodes: nodes, - setFeatureCompatibilityVersion: lastStableFCV, - dropTarget: true, - }; +const nodes = [{binVersion: 'latest'}, {binVersion: 'last-stable'}, {}]; +const options = { + nodes: nodes, + setFeatureCompatibilityVersion: lastStableFCV, + dropTarget: true, +}; - new RenameAcrossDatabasesTest(options).run(); +new RenameAcrossDatabasesTest(options).run(); }()); diff --git a/jstests/multiVersion/genericSetFCVUsage/repair_feature_compatibility_version.js b/jstests/multiVersion/genericSetFCVUsage/repair_feature_compatibility_version.js index 8eeea0ed427..d37e40c5816 100644 --- a/jstests/multiVersion/genericSetFCVUsage/repair_feature_compatibility_version.js +++ b/jstests/multiVersion/genericSetFCVUsage/repair_feature_compatibility_version.js @@ -4,87 +4,82 @@ */ (function() { - "use strict"; +"use strict"; - load("jstests/libs/feature_compatibility_version.js"); +load("jstests/libs/feature_compatibility_version.js"); - let dbpath = MongoRunner.dataPath + "feature_compatibility_version"; - resetDbpath(dbpath); - let connection; - let adminDB; +let dbpath = MongoRunner.dataPath + "feature_compatibility_version"; +resetDbpath(dbpath); +let connection; +let adminDB; - const latest = "latest"; +const latest = "latest"; - /** - * Ensure that a mongod (without using --repair) fails to start up if there are non-local - * collections and the FCV document in the admin database has been removed. - * - * The mongod has 'version' binary and is started up on 'dbpath'. - */ - let doStartupFailTests = function(version, dbpath) { - // Set up a mongod with an admin database but without a FCV document in the admin database. - setupMissingFCVDoc(version, dbpath); - - // Now attempt to start up a new mongod without clearing the data files from 'dbpath', which - // contain the admin database but are missing the FCV document. The mongod should fail to - // start up if there is a non-local collection and the FCV document is missing. - let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: version, noCleanData: true}); - assert.eq( - null, - conn, - "expected mongod to fail when data files are present but no FCV document is found."); - }; +/** + * Ensure that a mongod (without using --repair) fails to start up if there are non-local + * collections and the FCV document in the admin database has been removed. + * + * The mongod has 'version' binary and is started up on 'dbpath'. + */ +let doStartupFailTests = function(version, dbpath) { + // Set up a mongod with an admin database but without a FCV document in the admin database. + setupMissingFCVDoc(version, dbpath); - /** - * Starts up a mongod with binary 'version' on 'dbpath', then removes the FCV document from the - * admin database and returns the mongod. - */ - let setupMissingFCVDoc = function(version, dbpath) { - let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: version}); - assert.neq(null, - conn, - "mongod was unable to start up with version=" + version + " and no data files"); - adminDB = conn.getDB("admin"); - removeFCVDocument(adminDB); - MongoRunner.stopMongod(conn); - return conn; - }; + // Now attempt to start up a new mongod without clearing the data files from 'dbpath', which + // contain the admin database but are missing the FCV document. The mongod should fail to + // start up if there is a non-local collection and the FCV document is missing. + let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: version, noCleanData: true}); + assert.eq(null, + conn, + "expected mongod to fail when data files are present but no FCV document is found."); +}; - // Check that start up without --repair fails if there is non-local DB data and the FCV doc was - // deleted. - doStartupFailTests(latest, dbpath); +/** + * Starts up a mongod with binary 'version' on 'dbpath', then removes the FCV document from the + * admin database and returns the mongod. + */ +let setupMissingFCVDoc = function(version, dbpath) { + let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: version}); + assert.neq( + null, conn, "mongod was unable to start up with version=" + version + " and no data files"); + adminDB = conn.getDB("admin"); + removeFCVDocument(adminDB); + MongoRunner.stopMongod(conn); + return conn; +}; - // --repair can be used to restore a missing featureCompatibilityVersion document to an existing - // admin database, as long as all collections have UUIDs. The FCV should be initialized to - // lastStableFCV / downgraded FCV. - connection = setupMissingFCVDoc(latest, dbpath); - let returnCode = - runMongoProgram("mongod", "--port", connection.port, "--repair", "--dbpath", dbpath); - assert.eq( - returnCode, - 0, - "expected mongod --repair to execute successfully when restoring a missing FCV document."); +// Check that start up without --repair fails if there is non-local DB data and the FCV doc was +// deleted. +doStartupFailTests(latest, dbpath); - connection = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true}); - assert.neq(null, - connection, - "mongod was unable to start up with version=" + latest + " and existing data files"); - adminDB = connection.getDB("admin"); - assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, - lastStableFCV); - assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).targetVersion, - null); - MongoRunner.stopMongod(connection); +// --repair can be used to restore a missing featureCompatibilityVersion document to an existing +// admin database, as long as all collections have UUIDs. The FCV should be initialized to +// lastStableFCV / downgraded FCV. +connection = setupMissingFCVDoc(latest, dbpath); +let returnCode = + runMongoProgram("mongod", "--port", connection.port, "--repair", "--dbpath", dbpath); +assert.eq( + returnCode, + 0, + "expected mongod --repair to execute successfully when restoring a missing FCV document."); - // If the featureCompatibilityVersion document is present, --repair should just return success. - connection = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); - assert.neq(null, - connection, - "mongod was unable to start up with version=" + latest + " and no data files"); - MongoRunner.stopMongod(connection); +connection = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true}); +assert.neq(null, + connection, + "mongod was unable to start up with version=" + latest + " and existing data files"); +adminDB = connection.getDB("admin"); +assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, + lastStableFCV); +assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).targetVersion, null); +MongoRunner.stopMongod(connection); - returnCode = - runMongoProgram("mongod", "--port", connection.port, "--repair", "--dbpath", dbpath); - assert.eq(returnCode, 0); +// If the featureCompatibilityVersion document is present, --repair should just return success. +connection = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); +assert.neq(null, + connection, + "mongod was unable to start up with version=" + latest + " and no data files"); +MongoRunner.stopMongod(connection); +returnCode = runMongoProgram("mongod", "--port", connection.port, "--repair", "--dbpath", dbpath); +assert.eq(returnCode, 0); })(); diff --git a/jstests/multiVersion/genericSetFCVUsage/rollback_last_stable_to_latest.js b/jstests/multiVersion/genericSetFCVUsage/rollback_last_stable_to_latest.js index d88d7452ed5..9d3c1a60172 100644 --- a/jstests/multiVersion/genericSetFCVUsage/rollback_last_stable_to_latest.js +++ b/jstests/multiVersion/genericSetFCVUsage/rollback_last_stable_to_latest.js @@ -4,9 +4,9 @@ */ (function() { - "use strict"; - load("jstests/multiVersion/libs/multiversion_rollback.js"); +"use strict"; +load("jstests/multiVersion/libs/multiversion_rollback.js"); - var testName = "multiversion_rollback_last_stable_to_latest"; - testMultiversionRollback(testName, "last-stable", "latest"); +var testName = "multiversion_rollback_last_stable_to_latest"; +testMultiversionRollback(testName, "last-stable", "latest"); })();
\ No newline at end of file diff --git a/jstests/multiVersion/genericSetFCVUsage/rollback_latest_to_last_stable.js b/jstests/multiVersion/genericSetFCVUsage/rollback_latest_to_last_stable.js index 951b6c91ae9..546065ecc5f 100644 --- a/jstests/multiVersion/genericSetFCVUsage/rollback_latest_to_last_stable.js +++ b/jstests/multiVersion/genericSetFCVUsage/rollback_latest_to_last_stable.js @@ -4,9 +4,9 @@ */ (function() { - "use strict"; - load("jstests/multiVersion/libs/multiversion_rollback.js"); +"use strict"; +load("jstests/multiVersion/libs/multiversion_rollback.js"); - var testName = "multiversion_rollback_latest_to_last_stable"; - testMultiversionRollback(testName, "latest", "last-stable"); +var testName = "multiversion_rollback_latest_to_last_stable"; +testMultiversionRollback(testName, "latest", "last-stable"); })();
\ No newline at end of file diff --git a/jstests/multiVersion/genericSetFCVUsage/setFCV_collmod_transaction_rollback.js b/jstests/multiVersion/genericSetFCVUsage/setFCV_collmod_transaction_rollback.js index 985e3a62c78..0e8573cef56 100644 --- a/jstests/multiVersion/genericSetFCVUsage/setFCV_collmod_transaction_rollback.js +++ b/jstests/multiVersion/genericSetFCVUsage/setFCV_collmod_transaction_rollback.js @@ -3,50 +3,50 @@ * collMod command. */ (function() { - 'use strict'; +'use strict'; - load("jstests/libs/feature_compatibility_version.js"); +load("jstests/libs/feature_compatibility_version.js"); - let dbpath = MongoRunner.dataPath + "setFCV_collmod_transaction_rollback"; - resetDbpath(dbpath); +let dbpath = MongoRunner.dataPath + "setFCV_collmod_transaction_rollback"; +resetDbpath(dbpath); - const latest = "latest"; +const latest = "latest"; - let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); - assert.neq( - null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); - let adminDB = conn.getDB("admin"); +let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); +assert.neq( + null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); +let adminDB = conn.getDB("admin"); - var collName = "collModTest"; - var coll = adminDB.getCollection(collName); - var ttlBeforeRollback = 50; +var collName = "collModTest"; +var coll = adminDB.getCollection(collName); +var ttlBeforeRollback = 50; - assert.commandWorked( - coll.createIndex({b: 1}, {"name": "index1", "expireAfterSeconds": ttlBeforeRollback})); +assert.commandWorked( + coll.createIndex({b: 1}, {"name": "index1", "expireAfterSeconds": ttlBeforeRollback})); - // The failpoint causes an interrupt in the collMod's WriteUnitOfWork, thus triggers a rollback. - assert.commandWorked( - adminDB.adminCommand({configureFailPoint: "assertAfterIndexUpdate", mode: "alwaysOn"})); +// The failpoint causes an interrupt in the collMod's WriteUnitOfWork, thus triggers a rollback. +assert.commandWorked( + adminDB.adminCommand({configureFailPoint: "assertAfterIndexUpdate", mode: "alwaysOn"})); - // Test transaction rollback after index ttl update collMod. - assert.commandFailedWithCode( - adminDB.runCommand( - {"collMod": collName, "index": {"name": "index1", "expireAfterSeconds": 100}}), - 50970); +// Test transaction rollback after index ttl update collMod. +assert.commandFailedWithCode( + adminDB.runCommand( + {"collMod": collName, "index": {"name": "index1", "expireAfterSeconds": 100}}), + 50970); - const index = coll.getIndexes(); - var ttlAfterRollback = index[1].expireAfterSeconds; - assert.eq(ttlAfterRollback, ttlBeforeRollback); +const index = coll.getIndexes(); +var ttlAfterRollback = index[1].expireAfterSeconds; +assert.eq(ttlAfterRollback, ttlBeforeRollback); - // SERVER-37634 should remove this test post 4.2. - // Test transaction rollback after unique index upgrade collMod. - assert.commandWorked(adminDB.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); +// SERVER-37634 should remove this test post 4.2. +// Test transaction rollback after unique index upgrade collMod. +assert.commandWorked(adminDB.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); - assert.commandWorked(coll.createIndex({a: 1}, {unique: true})); - assert.writeOK(coll.insert({_id: 0, a: 1})); +assert.commandWorked(coll.createIndex({a: 1}, {unique: true})); +assert.writeOK(coll.insert({_id: 0, a: 1})); - assert.commandFailedWithCode(adminDB.adminCommand({setFeatureCompatibilityVersion: latestFCV}), - 50971); +assert.commandFailedWithCode(adminDB.adminCommand({setFeatureCompatibilityVersion: latestFCV}), + 50971); - MongoRunner.stopMongod(conn); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js b/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js index a404d8d01e3..9c62bdb5ee1 100644 --- a/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js +++ b/jstests/multiVersion/genericSetFCVUsage/set_feature_compatibility_version.js @@ -10,382 +10,373 @@ TestData.skipCheckingUUIDsConsistentAcrossCluster = true; TestData.skipCheckDBHashes = true; (function() { - "use strict"; - - load("jstests/libs/feature_compatibility_version.js"); - load("jstests/libs/get_index_helpers.js"); - load("jstests/libs/write_concern_util.js"); - load("jstests/replsets/rslib.js"); - - let dbpath = MongoRunner.dataPath + "feature_compatibility_version"; - resetDbpath(dbpath); - let res; - - const latest = "latest"; - const lastStable = "last-stable"; - - // - // Standalone tests. - // - - let conn; - let adminDB; - - // A 'latest' binary standalone should default to 'latestFCV'. - conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); - assert.neq( - null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); - adminDB = conn.getDB("admin"); - checkFCV(adminDB, latestFCV); - - jsTestLog("EXPECTED TO FAIL: featureCompatibilityVersion cannot be set to an invalid value"); - assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: 5})); - assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); - assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "4.4"})); - assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); - - jsTestLog("EXPECTED TO FAIL: setFeatureCompatibilityVersion rejects unknown fields."); - assert.commandFailed( - adminDB.runCommand({setFeatureCompatibilityVersion: lastStable, unknown: 1})); - - jsTestLog( - "EXPECTED TO FAIL: setFeatureCompatibilityVersion can only be run on the admin database"); - assert.commandFailed( - conn.getDB("test").runCommand({setFeatureCompatibilityVersion: lastStable})); - - jsTestLog("EXPECTED TO FAIL: featureCompatibilityVersion cannot be set via setParameter"); - assert.commandFailed( - adminDB.runCommand({setParameter: 1, featureCompatibilityVersion: lastStable})); - - // setFeatureCompatibilityVersion fails to downgrade FCV if the write fails. - assert.commandWorked(adminDB.runCommand({ - configureFailPoint: "failCollectionUpdates", - data: {collectionNS: "admin.system.version"}, - mode: "alwaysOn" - })); - jsTestLog( - "EXPECTED TO FAIL: setFeatureCompatibilityVersion fails to downgrade FCV if the write fails"); - assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); - checkFCV(adminDB, latestFCV); - assert.commandWorked(adminDB.runCommand({ - configureFailPoint: "failCollectionUpdates", - data: {collectionNS: "admin.system.version"}, - mode: "off" - })); - - // featureCompatibilityVersion can be downgraded to 'lastStableFCV'. - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); - checkFCV(adminDB, lastStableFCV); - - // setFeatureCompatibilityVersion fails to upgrade to 'latestFCV' if the write fails. - assert.commandWorked(adminDB.runCommand({ - configureFailPoint: "failCollectionUpdates", - data: {collectionNS: "admin.system.version"}, - mode: "alwaysOn" - })); - jsTestLog( - "EXPECTED TO FAIL: setFeatureCompatibilityVersion fails to upgrade to 'latestFCV' if the write fails"); - assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); - checkFCV(adminDB, lastStableFCV); - assert.commandWorked(adminDB.runCommand({ - configureFailPoint: "failCollectionUpdates", - data: {collectionNS: "admin.system.version"}, - mode: "off" - })); - - // featureCompatibilityVersion can be upgraded to 'latestFCV'. - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); - checkFCV(adminDB, latestFCV); - - MongoRunner.stopMongod(conn); - - // featureCompatibilityVersion is durable. - conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); - assert.neq( - null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); - adminDB = conn.getDB("admin"); - checkFCV(adminDB, latestFCV); - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); - checkFCV(adminDB, lastStableFCV); - MongoRunner.stopMongod(conn); - - conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true}); - assert.neq(null, - conn, - "mongod was unable to start up with binary version=" + latest + - " and last-stable featureCompatibilityVersion"); - adminDB = conn.getDB("admin"); - checkFCV(adminDB, lastStableFCV); - MongoRunner.stopMongod(conn); - - // If you upgrade from 'lastStable' binary to 'latest' binary and have non-local databases, FCV - // remains 'lastStableFCV'. - conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: lastStable}); - assert.neq(null, - conn, - "mongod was unable to start up with version=" + lastStable + " and no data files"); - assert.writeOK(conn.getDB("test").coll.insert({a: 5})); - adminDB = conn.getDB("admin"); - checkFCV(adminDB, lastStableFCV); - MongoRunner.stopMongod(conn); - - conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true}); - assert.neq(null, - conn, - "mongod was unable to start up with binary version=" + latest + - " and featureCompatibilityVersion=" + lastStableFCV); - adminDB = conn.getDB("admin"); - checkFCV(adminDB, lastStableFCV); - MongoRunner.stopMongod(conn); - - // A 'latest' binary mongod started with --shardsvr and clean data files defaults to - // 'lastStableFCV'. - conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, shardsvr: ""}); - assert.neq( - null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); - adminDB = conn.getDB("admin"); - checkFCV(adminDB, lastStableFCV); - MongoRunner.stopMongod(conn); - - // - // Replica set tests. - // - - let rst; - let rstConns; - let replSetConfig; - let primaryAdminDB; - let secondaryAdminDB; - - // 'latest' binary replica set. - rst = new ReplSetTest({nodes: 2, nodeOpts: {binVersion: latest}}); - rst.startSet(); - rst.initiate(); - primaryAdminDB = rst.getPrimary().getDB("admin"); - secondaryAdminDB = rst.getSecondary().getDB("admin"); - - // FCV should default to 'latestFCV' on primary and secondary in a 'latest' binary replica set. - checkFCV(primaryAdminDB, latestFCV); - rst.awaitReplication(); - checkFCV(secondaryAdminDB, latestFCV); - - // featureCompatibilityVersion propagates to secondary. - assert.commandWorked( - primaryAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); - checkFCV(primaryAdminDB, lastStableFCV); - rst.awaitReplication(); - checkFCV(secondaryAdminDB, lastStableFCV); - - jsTestLog("EXPECTED TO FAIL: setFeatureCompatibilityVersion cannot be run on secondary"); - assert.commandFailed(secondaryAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); - - rst.stopSet(); - - // A 'latest' binary secondary with a 'lastStable' binary primary will have 'lastStableFCV' - rst = new ReplSetTest({nodes: [{binVersion: lastStable}, {binVersion: latest}]}); - rstConns = rst.startSet(); - replSetConfig = rst.getReplSetConfig(); - replSetConfig.members[1].priority = 0; - replSetConfig.members[1].votes = 0; - rst.initiate(replSetConfig); - rst.waitForState(rstConns[0], ReplSetTest.State.PRIMARY); - secondaryAdminDB = rst.getSecondary().getDB("admin"); - checkFCV(secondaryAdminDB, lastStableFCV); - rst.stopSet(); - - // Test that a 'lastStable' secondary can successfully perform initial sync from a 'latest' - // primary with 'lastStableFCV'. - rst = new ReplSetTest({ - nodes: [{binVersion: latest}, {binVersion: latest, rsConfig: {priority: 0}}], - settings: {chainingAllowed: false} - }); - rst.startSet(); - rst.initiate(); - - let primary = rst.getPrimary(); - primaryAdminDB = primary.getDB("admin"); - assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); - - let secondary = rst.getSecondary(); - - // The command should fail because wtimeout expires before a majority responds. - stopServerReplication(secondary); - res = primary.adminCommand( - {setFeatureCompatibilityVersion: latestFCV, writeConcern: {wtimeout: 1000}}); - assert.eq(0, res.ok); - assert.commandFailedWithCode(res, ErrorCodes.WriteConcernFailed); - restartServerReplication(secondary); - - // Because the failed setFCV command left the primary in an intermediary state, complete the - // upgrade then reset back to the lastStable version. - assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV})); - assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); - - secondary = rst.add({binVersion: lastStable}); - secondaryAdminDB = secondary.getDB("admin"); - - // Rig the election so that the first node running latest version remains the primary after the - // 'lastStable' secondary is added to the replica set. - replSetConfig = rst.getReplSetConfig(); - replSetConfig.version = 4; - replSetConfig.members[2].priority = 0; - reconfig(rst, replSetConfig); - - // Verify that the 'lastStable' secondary successfully performed its initial sync. - assert.writeOK( - primaryAdminDB.getSiblingDB("test").coll.insert({awaitRepl: true}, {writeConcern: {w: 3}})); - - // Test that a 'lastStable' secondary can no longer replicate from the primary after the FCV is - // upgraded to 'latestFCV'. - // Note: the 'lastStable' secondary must stop replicating during the upgrade to ensure it has no - // chance of seeing the 'upgrading to latest' message in the oplog, whereupon it would crash. - stopServerReplication(secondary); - assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV})); - restartServerReplication(secondary); - checkFCV(secondaryAdminDB, lastStableFCV); - assert.writeOK(primaryAdminDB.getSiblingDB("test").coll.insert({shouldReplicate: false})); - assert.eq(secondaryAdminDB.getSiblingDB("test").coll.find({shouldReplicate: false}).itcount(), - 0); - rst.stopSet(); - - // Test idempotency for setFeatureCompatibilityVersion. - rst = new ReplSetTest({nodes: 2, nodeOpts: {binVersion: latest}}); - rst.startSet(); - rst.initiate(); - - // Set FCV to 'lastStableFCV' so that a 'lastStable' binary node can join the set. - primary = rst.getPrimary(); - assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); - rst.awaitReplication(); - - // Add a 'lastStable' binary node to the set. - secondary = rst.add({binVersion: lastStable}); - rst.reInitiate(); - - // Ensure the 'lastStable' binary node succeeded its initial sync. - assert.writeOK(primary.getDB("test").coll.insert({awaitRepl: true}, {writeConcern: {w: 3}})); - - // Run {setFCV: lastStableFCV}. This should be idempotent. - assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); - rst.awaitReplication(); - - // Ensure the secondary is still running. - rst.stopSet(); - - // - // Sharding tests. - // - - let st; - let mongosAdminDB; - let configPrimaryAdminDB; - let shardPrimaryAdminDB; - - // A 'latest' binary cluster started with clean data files will set FCV to 'latestFCV'. - st = new ShardingTest({ - shards: {rs0: {nodes: [{binVersion: latest}, {binVersion: latest}]}}, - other: {useBridge: true} - }); - mongosAdminDB = st.s.getDB("admin"); - configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin"); - shardPrimaryAdminDB = st.rs0.getPrimary().getDB("admin"); - - checkFCV(configPrimaryAdminDB, latestFCV); - checkFCV(shardPrimaryAdminDB, latestFCV); - - jsTestLog( - "EXPECTED TO FAIL: featureCompatibilityVersion cannot be set to invalid value on mongos"); - assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: 5})); - assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); - assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "4.4"})); - - jsTestLog("EXPECTED TO FAIL: setFeatureCompatibilityVersion rejects unknown fields on mongos"); - assert.commandFailed( - mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV, unknown: 1})); - - jsTestLog( - "EXPECTED TO FAIL: setFeatureCompatibilityVersion can only be run on the admin database on mongos"); - assert.commandFailed( - st.s.getDB("test").runCommand({setFeatureCompatibilityVersion: lastStableFCV})); - - jsTestLog( - "EXPECTED TO FAIL: featureCompatibilityVersion cannot be set via setParameter on mongos"); - assert.commandFailed( - mongosAdminDB.runCommand({setParameter: 1, featureCompatibilityVersion: lastStableFCV})); - - // Prevent the shard primary from receiving messages from the config server primary. When we try - // to set FCV to 'lastStableFCV', the command should fail because the shard cannot be contacted. - st.rs0.getPrimary().discardMessagesFrom(st.configRS.getPrimary(), 1.0); - jsTestLog( - "EXPECTED TO FAIL: setFeatureCompatibilityVersion cannot be set because the shard primary is not reachable"); - assert.commandFailed( - mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV, maxTimeMS: 1000})); - checkFCV( - configPrimaryAdminDB, lastStableFCV, lastStableFCV /* indicates downgrade in progress */); - st.rs0.getPrimary().discardMessagesFrom(st.configRS.getPrimary(), 0.0); - - // FCV can be set to 'lastStableFCV' on mongos. - // This is run through assert.soon() because we've just caused a network interruption - // by discarding messages in the bridge. - assert.soon(function() { - res = mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV}); - if (res.ok == 0) { - print("Failed to set feature compatibility version: " + tojson(res)); - return false; - } - return true; - }); - - // featureCompatibilityVersion propagates to config and shard. - checkFCV(configPrimaryAdminDB, lastStableFCV); - checkFCV(shardPrimaryAdminDB, lastStableFCV); - - // A 'latest' binary replica set started as a shard server defaults to 'lastStableFCV'. - let latestShard = new ReplSetTest({ - name: "latestShard", - nodes: [{binVersion: latest}, {binVersion: latest}], - nodeOptions: {shardsvr: ""}, - useHostName: true - }); - latestShard.startSet(); - latestShard.initiate(); - let latestShardPrimaryAdminDB = latestShard.getPrimary().getDB("admin"); - checkFCV(latestShardPrimaryAdminDB, lastStableFCV); - assert.commandWorked(mongosAdminDB.runCommand({addShard: latestShard.getURL()})); - checkFCV(latestShardPrimaryAdminDB, lastStableFCV); - - // FCV can be set to 'latestFCV' on mongos. - assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); - checkFCV(st.configRS.getPrimary().getDB("admin"), latestFCV); - checkFCV(shardPrimaryAdminDB, latestFCV); - checkFCV(latestShardPrimaryAdminDB, latestFCV); - - // Call ShardingTest.stop before shutting down latestShard, so that the UUID check in - // ShardingTest.stop can talk to latestShard. - st.stop(); - latestShard.stopSet(); - - // Create cluster with a 'lastStable' binary mongos so that we can add 'lastStable' binary - // shards. - st = new ShardingTest({shards: 0, other: {mongosOptions: {binVersion: lastStable}}}); - mongosAdminDB = st.s.getDB("admin"); - configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin"); - checkFCV(configPrimaryAdminDB, lastStableFCV); - - // Adding a 'lastStable' binary shard to a cluster with 'lastStableFCV' succeeds. - let lastStableShard = new ReplSetTest({ - name: "lastStableShard", - nodes: [{binVersion: lastStable}, {binVersion: lastStable}], - nodeOptions: {shardsvr: ""}, - useHostName: true - }); - lastStableShard.startSet(); - lastStableShard.initiate(); - assert.commandWorked(mongosAdminDB.runCommand({addShard: lastStableShard.getURL()})); - checkFCV(lastStableShard.getPrimary().getDB("admin"), lastStableFCV); - - // call ShardingTest.stop before shutting down lastStableShard, so that the UUID check in - // ShardingTest.stop can talk to lastStableShard. - st.stop(); - lastStableShard.stopSet(); +"use strict"; + +load("jstests/libs/feature_compatibility_version.js"); +load("jstests/libs/get_index_helpers.js"); +load("jstests/libs/write_concern_util.js"); +load("jstests/replsets/rslib.js"); + +let dbpath = MongoRunner.dataPath + "feature_compatibility_version"; +resetDbpath(dbpath); +let res; + +const latest = "latest"; +const lastStable = "last-stable"; + +// +// Standalone tests. +// + +let conn; +let adminDB; + +// A 'latest' binary standalone should default to 'latestFCV'. +conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); +assert.neq( + null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); +adminDB = conn.getDB("admin"); +checkFCV(adminDB, latestFCV); + +jsTestLog("EXPECTED TO FAIL: featureCompatibilityVersion cannot be set to an invalid value"); +assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: 5})); +assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); +assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "4.4"})); +assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: "3.4"})); + +jsTestLog("EXPECTED TO FAIL: setFeatureCompatibilityVersion rejects unknown fields."); +assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: lastStable, unknown: 1})); + +jsTestLog("EXPECTED TO FAIL: setFeatureCompatibilityVersion can only be run on the admin database"); +assert.commandFailed(conn.getDB("test").runCommand({setFeatureCompatibilityVersion: lastStable})); + +jsTestLog("EXPECTED TO FAIL: featureCompatibilityVersion cannot be set via setParameter"); +assert.commandFailed( + adminDB.runCommand({setParameter: 1, featureCompatibilityVersion: lastStable})); + +// setFeatureCompatibilityVersion fails to downgrade FCV if the write fails. +assert.commandWorked(adminDB.runCommand({ + configureFailPoint: "failCollectionUpdates", + data: {collectionNS: "admin.system.version"}, + mode: "alwaysOn" +})); +jsTestLog( + "EXPECTED TO FAIL: setFeatureCompatibilityVersion fails to downgrade FCV if the write fails"); +assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); +checkFCV(adminDB, latestFCV); +assert.commandWorked(adminDB.runCommand({ + configureFailPoint: "failCollectionUpdates", + data: {collectionNS: "admin.system.version"}, + mode: "off" +})); + +// featureCompatibilityVersion can be downgraded to 'lastStableFCV'. +assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); +checkFCV(adminDB, lastStableFCV); + +// setFeatureCompatibilityVersion fails to upgrade to 'latestFCV' if the write fails. +assert.commandWorked(adminDB.runCommand({ + configureFailPoint: "failCollectionUpdates", + data: {collectionNS: "admin.system.version"}, + mode: "alwaysOn" +})); +jsTestLog( + "EXPECTED TO FAIL: setFeatureCompatibilityVersion fails to upgrade to 'latestFCV' if the write fails"); +assert.commandFailed(adminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); +checkFCV(adminDB, lastStableFCV); +assert.commandWorked(adminDB.runCommand({ + configureFailPoint: "failCollectionUpdates", + data: {collectionNS: "admin.system.version"}, + mode: "off" +})); + +// featureCompatibilityVersion can be upgraded to 'latestFCV'. +assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); +checkFCV(adminDB, latestFCV); + +MongoRunner.stopMongod(conn); + +// featureCompatibilityVersion is durable. +conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest}); +assert.neq( + null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); +adminDB = conn.getDB("admin"); +checkFCV(adminDB, latestFCV); +assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); +checkFCV(adminDB, lastStableFCV); +MongoRunner.stopMongod(conn); + +conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true}); +assert.neq(null, + conn, + "mongod was unable to start up with binary version=" + latest + + " and last-stable featureCompatibilityVersion"); +adminDB = conn.getDB("admin"); +checkFCV(adminDB, lastStableFCV); +MongoRunner.stopMongod(conn); + +// If you upgrade from 'lastStable' binary to 'latest' binary and have non-local databases, FCV +// remains 'lastStableFCV'. +conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: lastStable}); +assert.neq( + null, conn, "mongod was unable to start up with version=" + lastStable + " and no data files"); +assert.writeOK(conn.getDB("test").coll.insert({a: 5})); +adminDB = conn.getDB("admin"); +checkFCV(adminDB, lastStableFCV); +MongoRunner.stopMongod(conn); + +conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true}); +assert.neq(null, + conn, + "mongod was unable to start up with binary version=" + latest + + " and featureCompatibilityVersion=" + lastStableFCV); +adminDB = conn.getDB("admin"); +checkFCV(adminDB, lastStableFCV); +MongoRunner.stopMongod(conn); + +// A 'latest' binary mongod started with --shardsvr and clean data files defaults to +// 'lastStableFCV'. +conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, shardsvr: ""}); +assert.neq( + null, conn, "mongod was unable to start up with version=" + latest + " and no data files"); +adminDB = conn.getDB("admin"); +checkFCV(adminDB, lastStableFCV); +MongoRunner.stopMongod(conn); + +// +// Replica set tests. +// + +let rst; +let rstConns; +let replSetConfig; +let primaryAdminDB; +let secondaryAdminDB; + +// 'latest' binary replica set. +rst = new ReplSetTest({nodes: 2, nodeOpts: {binVersion: latest}}); +rst.startSet(); +rst.initiate(); +primaryAdminDB = rst.getPrimary().getDB("admin"); +secondaryAdminDB = rst.getSecondary().getDB("admin"); + +// FCV should default to 'latestFCV' on primary and secondary in a 'latest' binary replica set. +checkFCV(primaryAdminDB, latestFCV); +rst.awaitReplication(); +checkFCV(secondaryAdminDB, latestFCV); + +// featureCompatibilityVersion propagates to secondary. +assert.commandWorked(primaryAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV})); +checkFCV(primaryAdminDB, lastStableFCV); +rst.awaitReplication(); +checkFCV(secondaryAdminDB, lastStableFCV); + +jsTestLog("EXPECTED TO FAIL: setFeatureCompatibilityVersion cannot be run on secondary"); +assert.commandFailed(secondaryAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); + +rst.stopSet(); + +// A 'latest' binary secondary with a 'lastStable' binary primary will have 'lastStableFCV' +rst = new ReplSetTest({nodes: [{binVersion: lastStable}, {binVersion: latest}]}); +rstConns = rst.startSet(); +replSetConfig = rst.getReplSetConfig(); +replSetConfig.members[1].priority = 0; +replSetConfig.members[1].votes = 0; +rst.initiate(replSetConfig); +rst.waitForState(rstConns[0], ReplSetTest.State.PRIMARY); +secondaryAdminDB = rst.getSecondary().getDB("admin"); +checkFCV(secondaryAdminDB, lastStableFCV); +rst.stopSet(); + +// Test that a 'lastStable' secondary can successfully perform initial sync from a 'latest' +// primary with 'lastStableFCV'. +rst = new ReplSetTest({ + nodes: [{binVersion: latest}, {binVersion: latest, rsConfig: {priority: 0}}], + settings: {chainingAllowed: false} +}); +rst.startSet(); +rst.initiate(); + +let primary = rst.getPrimary(); +primaryAdminDB = primary.getDB("admin"); +assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); + +let secondary = rst.getSecondary(); + +// The command should fail because wtimeout expires before a majority responds. +stopServerReplication(secondary); +res = primary.adminCommand( + {setFeatureCompatibilityVersion: latestFCV, writeConcern: {wtimeout: 1000}}); +assert.eq(0, res.ok); +assert.commandFailedWithCode(res, ErrorCodes.WriteConcernFailed); +restartServerReplication(secondary); + +// Because the failed setFCV command left the primary in an intermediary state, complete the +// upgrade then reset back to the lastStable version. +assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV})); +assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); + +secondary = rst.add({binVersion: lastStable}); +secondaryAdminDB = secondary.getDB("admin"); + +// Rig the election so that the first node running latest version remains the primary after the +// 'lastStable' secondary is added to the replica set. +replSetConfig = rst.getReplSetConfig(); +replSetConfig.version = 4; +replSetConfig.members[2].priority = 0; +reconfig(rst, replSetConfig); + +// Verify that the 'lastStable' secondary successfully performed its initial sync. +assert.writeOK( + primaryAdminDB.getSiblingDB("test").coll.insert({awaitRepl: true}, {writeConcern: {w: 3}})); + +// Test that a 'lastStable' secondary can no longer replicate from the primary after the FCV is +// upgraded to 'latestFCV'. +// Note: the 'lastStable' secondary must stop replicating during the upgrade to ensure it has no +// chance of seeing the 'upgrading to latest' message in the oplog, whereupon it would crash. +stopServerReplication(secondary); +assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: latestFCV})); +restartServerReplication(secondary); +checkFCV(secondaryAdminDB, lastStableFCV); +assert.writeOK(primaryAdminDB.getSiblingDB("test").coll.insert({shouldReplicate: false})); +assert.eq(secondaryAdminDB.getSiblingDB("test").coll.find({shouldReplicate: false}).itcount(), 0); +rst.stopSet(); + +// Test idempotency for setFeatureCompatibilityVersion. +rst = new ReplSetTest({nodes: 2, nodeOpts: {binVersion: latest}}); +rst.startSet(); +rst.initiate(); + +// Set FCV to 'lastStableFCV' so that a 'lastStable' binary node can join the set. +primary = rst.getPrimary(); +assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); +rst.awaitReplication(); + +// Add a 'lastStable' binary node to the set. +secondary = rst.add({binVersion: lastStable}); +rst.reInitiate(); + +// Ensure the 'lastStable' binary node succeeded its initial sync. +assert.writeOK(primary.getDB("test").coll.insert({awaitRepl: true}, {writeConcern: {w: 3}})); + +// Run {setFCV: lastStableFCV}. This should be idempotent. +assert.commandWorked(primary.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); +rst.awaitReplication(); + +// Ensure the secondary is still running. +rst.stopSet(); + +// +// Sharding tests. +// + +let st; +let mongosAdminDB; +let configPrimaryAdminDB; +let shardPrimaryAdminDB; + +// A 'latest' binary cluster started with clean data files will set FCV to 'latestFCV'. +st = new ShardingTest({ + shards: {rs0: {nodes: [{binVersion: latest}, {binVersion: latest}]}}, + other: {useBridge: true} +}); +mongosAdminDB = st.s.getDB("admin"); +configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin"); +shardPrimaryAdminDB = st.rs0.getPrimary().getDB("admin"); + +checkFCV(configPrimaryAdminDB, latestFCV); +checkFCV(shardPrimaryAdminDB, latestFCV); + +jsTestLog("EXPECTED TO FAIL: featureCompatibilityVersion cannot be set to invalid value on mongos"); +assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: 5})); +assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "3.2"})); +assert.commandFailed(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: "4.4"})); + +jsTestLog("EXPECTED TO FAIL: setFeatureCompatibilityVersion rejects unknown fields on mongos"); +assert.commandFailed( + mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV, unknown: 1})); + +jsTestLog( + "EXPECTED TO FAIL: setFeatureCompatibilityVersion can only be run on the admin database on mongos"); +assert.commandFailed( + st.s.getDB("test").runCommand({setFeatureCompatibilityVersion: lastStableFCV})); + +jsTestLog("EXPECTED TO FAIL: featureCompatibilityVersion cannot be set via setParameter on mongos"); +assert.commandFailed( + mongosAdminDB.runCommand({setParameter: 1, featureCompatibilityVersion: lastStableFCV})); + +// Prevent the shard primary from receiving messages from the config server primary. When we try +// to set FCV to 'lastStableFCV', the command should fail because the shard cannot be contacted. +st.rs0.getPrimary().discardMessagesFrom(st.configRS.getPrimary(), 1.0); +jsTestLog( + "EXPECTED TO FAIL: setFeatureCompatibilityVersion cannot be set because the shard primary is not reachable"); +assert.commandFailed( + mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV, maxTimeMS: 1000})); +checkFCV(configPrimaryAdminDB, lastStableFCV, lastStableFCV /* indicates downgrade in progress */); +st.rs0.getPrimary().discardMessagesFrom(st.configRS.getPrimary(), 0.0); + +// FCV can be set to 'lastStableFCV' on mongos. +// This is run through assert.soon() because we've just caused a network interruption +// by discarding messages in the bridge. +assert.soon(function() { + res = mongosAdminDB.runCommand({setFeatureCompatibilityVersion: lastStableFCV}); + if (res.ok == 0) { + print("Failed to set feature compatibility version: " + tojson(res)); + return false; + } + return true; +}); + +// featureCompatibilityVersion propagates to config and shard. +checkFCV(configPrimaryAdminDB, lastStableFCV); +checkFCV(shardPrimaryAdminDB, lastStableFCV); + +// A 'latest' binary replica set started as a shard server defaults to 'lastStableFCV'. +let latestShard = new ReplSetTest({ + name: "latestShard", + nodes: [{binVersion: latest}, {binVersion: latest}], + nodeOptions: {shardsvr: ""}, + useHostName: true +}); +latestShard.startSet(); +latestShard.initiate(); +let latestShardPrimaryAdminDB = latestShard.getPrimary().getDB("admin"); +checkFCV(latestShardPrimaryAdminDB, lastStableFCV); +assert.commandWorked(mongosAdminDB.runCommand({addShard: latestShard.getURL()})); +checkFCV(latestShardPrimaryAdminDB, lastStableFCV); + +// FCV can be set to 'latestFCV' on mongos. +assert.commandWorked(mongosAdminDB.runCommand({setFeatureCompatibilityVersion: latestFCV})); +checkFCV(st.configRS.getPrimary().getDB("admin"), latestFCV); +checkFCV(shardPrimaryAdminDB, latestFCV); +checkFCV(latestShardPrimaryAdminDB, latestFCV); + +// Call ShardingTest.stop before shutting down latestShard, so that the UUID check in +// ShardingTest.stop can talk to latestShard. +st.stop(); +latestShard.stopSet(); + +// Create cluster with a 'lastStable' binary mongos so that we can add 'lastStable' binary +// shards. +st = new ShardingTest({shards: 0, other: {mongosOptions: {binVersion: lastStable}}}); +mongosAdminDB = st.s.getDB("admin"); +configPrimaryAdminDB = st.configRS.getPrimary().getDB("admin"); +checkFCV(configPrimaryAdminDB, lastStableFCV); + +// Adding a 'lastStable' binary shard to a cluster with 'lastStableFCV' succeeds. +let lastStableShard = new ReplSetTest({ + name: "lastStableShard", + nodes: [{binVersion: lastStable}, {binVersion: lastStable}], + nodeOptions: {shardsvr: ""}, + useHostName: true +}); +lastStableShard.startSet(); +lastStableShard.initiate(); +assert.commandWorked(mongosAdminDB.runCommand({addShard: lastStableShard.getURL()})); +checkFCV(lastStableShard.getPrimary().getDB("admin"), lastStableFCV); + +// call ShardingTest.stop before shutting down lastStableShard, so that the UUID check in +// ShardingTest.stop can talk to lastStableShard. +st.stop(); +lastStableShard.stopSet(); })(); diff --git a/jstests/multiVersion/genericSetFCVUsage/upgrade_downgrade_while_creating_collection.js b/jstests/multiVersion/genericSetFCVUsage/upgrade_downgrade_while_creating_collection.js index ba675fbae67..e80e36eb624 100644 --- a/jstests/multiVersion/genericSetFCVUsage/upgrade_downgrade_while_creating_collection.js +++ b/jstests/multiVersion/genericSetFCVUsage/upgrade_downgrade_while_creating_collection.js @@ -2,75 +2,72 @@ * Tests that upgrade/downgrade works correctly even while creating a new collection. */ (function() { - "use strict"; - load("jstests/libs/feature_compatibility_version.js"); - load("jstests/libs/parallel_shell_helpers.js"); +"use strict"; +load("jstests/libs/feature_compatibility_version.js"); +load("jstests/libs/parallel_shell_helpers.js"); - const rst = new ReplSetTest({nodes: 2}); - rst.startSet(); +const rst = new ReplSetTest({nodes: 2}); +rst.startSet(); - // Rig the election so that the first node is always primary and that modifying the - // featureCompatibilityVersion document doesn't need to wait for data to replicate. - var replSetConfig = rst.getReplSetConfig(); - replSetConfig.members[1].priority = 0; - replSetConfig.members[1].votes = 0; +// Rig the election so that the first node is always primary and that modifying the +// featureCompatibilityVersion document doesn't need to wait for data to replicate. +var replSetConfig = rst.getReplSetConfig(); +replSetConfig.members[1].priority = 0; +replSetConfig.members[1].votes = 0; - rst.initiate(replSetConfig); +rst.initiate(replSetConfig); - const primary = rst.getPrimary(); - const primaryDB = primary.getDB("test"); +const primary = rst.getPrimary(); +const primaryDB = primary.getDB("test"); - for (let versions - of[{from: lastStableFCV, to: latestFCV}, {from: latestFCV, to: lastStableFCV}]) { - jsTestLog("Changing FeatureCompatibilityVersion from " + versions.from + " to " + - versions.to + " while creating a collection"); - assert.commandWorked( - primaryDB.adminCommand({setFeatureCompatibilityVersion: versions.from})); +for (let versions of [{from: lastStableFCV, to: latestFCV}, {from: latestFCV, to: lastStableFCV}]) { + jsTestLog("Changing FeatureCompatibilityVersion from " + versions.from + " to " + versions.to + + " while creating a collection"); + assert.commandWorked(primaryDB.adminCommand({setFeatureCompatibilityVersion: versions.from})); - assert.commandWorked(primaryDB.adminCommand( - {configureFailPoint: "hangBeforeLoggingCreateCollection", mode: "alwaysOn"})); - primaryDB.mycoll.drop(); + assert.commandWorked(primaryDB.adminCommand( + {configureFailPoint: "hangBeforeLoggingCreateCollection", mode: "alwaysOn"})); + primaryDB.mycoll.drop(); - let awaitCreateCollection; - let awaitUpgradeFCV; + let awaitCreateCollection; + let awaitUpgradeFCV; - try { - awaitCreateCollection = startParallelShell(function() { - assert.commandWorked(db.runCommand({create: "mycoll"})); - }, primary.port); + try { + awaitCreateCollection = startParallelShell(function() { + assert.commandWorked(db.runCommand({create: "mycoll"})); + }, primary.port); - assert.soon(function() { - return rawMongoProgramOutput().match("createCollection: test.mycoll"); - }); + assert.soon(function() { + return rawMongoProgramOutput().match("createCollection: test.mycoll"); + }); - awaitUpgradeFCV = startParallelShell( - funWithArgs(function(version) { - assert.commandWorked( - db.adminCommand({setFeatureCompatibilityVersion: version})); - }, versions.to), primary.port); + awaitUpgradeFCV = startParallelShell( + funWithArgs(function(version) { + assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: version})); + }, versions.to), primary.port); - { - let res; - assert.soon( - function() { - res = assert.commandWorked(primaryDB.adminCommand( - {getParameter: 1, featureCompatibilityVersion: 1})); - return res.featureCompatibilityVersion.version === versions.from && - res.featureCompatibilityVersion.targetVersion === versions.new; - }, - function() { - return "targetVersion of featureCompatibilityVersion document wasn't " + - "updated on primary: " + tojson(res); - }); - } - } finally { - assert.commandWorked(primaryDB.adminCommand( - {configureFailPoint: "hangBeforeLoggingCreateCollection", mode: "off"})); + { + let res; + assert.soon( + function() { + res = assert.commandWorked( + primaryDB.adminCommand({getParameter: 1, featureCompatibilityVersion: 1})); + return res.featureCompatibilityVersion.version === versions.from && + res.featureCompatibilityVersion.targetVersion === versions.new; + }, + function() { + return "targetVersion of featureCompatibilityVersion document wasn't " + + "updated on primary: " + tojson(res); + }); } - - awaitCreateCollection(); - awaitUpgradeFCV(); - rst.checkReplicatedDataHashes(); + } finally { + assert.commandWorked(primaryDB.adminCommand( + {configureFailPoint: "hangBeforeLoggingCreateCollection", mode: "off"})); } - rst.stopSet(); + + awaitCreateCollection(); + awaitUpgradeFCV(); + rst.checkReplicatedDataHashes(); +} +rst.stopSet(); })(); |