mongo/jstests/multiVersion/validate_cross_version.js

222 lines
8.3 KiB
JavaScript

/**
* Tests that the '--validate' command-line flag works on historic mongo collections.
* Checks that validate works when there are no errors and correctly reports when
* there are validation errors
*/
import "jstests/multiVersion/libs/verify_versions.js";
import {getUriForColl, getUriForIndex, runWiredTigerTool} from "jstests/disk/libs/wt_file_helper.js";
import {allLtsVersions} from "jstests/multiVersion/libs/lts_versions.js";
// Setup the dbpath for this test.
const dbpath = MongoRunner.dataPath + "validate_cross_version";
function setupCommon(db) {
assert.commandWorked(db.createCollection("collect"));
assert.commandWorked(db["collect"].insert({a: 1}));
assert.commandWorked(db["collect"].createIndex({b: 1}));
}
function checkCommon(validateLogs, shouldCorrupt) {
let results = validateLogs.filter((json) => json.id === 9437301 && json.attr.results.ns == "test.collect");
assert.eq(1, results.length);
let result = results[0].attr.results;
assert(result, "Couldn't find validation result for test.collect");
jsTestLog(result);
assert.eq(false, result.repaired);
assert.eq(true, result.indexDetails.b_1.valid);
assert.eq(!shouldCorrupt, result.indexDetails["_id_"].valid);
assert.eq(1, result.nrecords);
assert.eq(2, result.nIndexes);
assert.eq(1, result.keysPerIndex["b_1"]);
if (shouldCorrupt) {
assert.eq(1, validateLogs.filter((json) => json.id === 9437304).length);
} else {
assert.eq(1, validateLogs.filter((json) => json.id === 9437303).length);
}
}
function setup4(db) {
// Removed in 5.0 as per https://www.mongodb.com/docs/v6.2/core/geohaystack/
assert.commandWorked(db.createCollection("geohaystack"));
assert.commandWorked(db["geohaystack"].insert({_id: 100, pos: {lng: 126.9, lat: 35.2}, type: "restaurant"}));
assert.commandWorked(db["geohaystack"].insert({_id: 200, pos: {lng: 127.5, lat: 36.1}, type: "restaurant"}));
assert.commandWorked(db["geohaystack"].createIndex({pos: "geoHaystack", type: 1}, {bucketSize: 1}));
}
function corrupt4(conn) {
// Check _id_ because we can't even open pos_geoHaystack_type_1
return [getUri(conn, "geohaystack", "_id_")];
}
function check4(validateLogs, shouldCorrupt) {
let results = validateLogs.filter((json) => json.id === 9437301 && json.attr.results.ns == "test.geohaystack");
assert.eq(1, results.length);
let result = results[0].attr.results;
assert(result, "Couldn't find validation result for test.geohaystack");
jsTestLog(result);
assert.eq(!shouldCorrupt, result.valid);
// The geohaystack index isn't visible
assert.eq(1, result.nIndexes);
assert.eq(!shouldCorrupt, result.indexDetails["_id_"].valid);
assert.eq(2, result.nrecords);
}
function setup5(db) {
// https://www.mongodb.com/docs/manual/core/timeseries-collections/#std-label-manual-timeseries-collection
// May have changed in 6.0 as it wasn't downgrade safe
assert.commandWorked(
db.createCollection("weather", {
timeseries: {timeField: "timestamp", metaField: "metadata", granularity: "seconds"},
expireAfterSeconds: 86400,
}),
);
assert.commandWorked(
db.weather.insertMany([
{
metadata: {sensorId: 5578, type: "temperature"},
timestamp: ISODate("2021-05-18T00:00:00.000Z"),
temp: 12,
},
{
metadata: {sensorId: 5578, type: "temperature"},
timestamp: ISODate("2021-05-18T04:00:00.000Z"),
temp: 11,
},
{
metadata: {sensorId: 5578, type: "temperature"},
timestamp: ISODate("2021-05-18T08:00:00.000Z"),
},
]),
);
assert.commandWorked(db.weather.createIndex({"metadata.sensorId": 1}));
// https://www.mongodb.com/docs/manual/release-notes/6.0-compatibility/#index-key-format
assert.commandWorked(db.createCollection("uniqueColl"));
assert.commandWorked(
db.uniqueColl.insertMany([
{uniq: 14, value: 23},
{uniq: 11, value: 17},
{uniq: 21, value: 23},
]),
);
assert.commandWorked(db.uniqueColl.createIndex({uniq: 1}, {unique: true}));
}
function corrupt5(conn) {
// Truncate the collection to force validation to traverse the indexes that potentially have
// strange formats
return [
getUriForColl(conn.getDB("test").getCollection("weather")),
getUriForColl(conn.getDB("test").getCollection("uniqueColl")),
];
}
function check5(validateLogs, shouldCorrupt) {
let weatherResults = validateLogs.filter(
(json) => json.id === 9437301 && json.attr.results.ns == "test.system.buckets.weather",
);
assert.eq(1, weatherResults.length);
let weatherResult = weatherResults[0].attr.results;
assert(weatherResult, "Couldn't find validation result for test.weather");
jsTestLog(weatherResult);
assert.eq(!shouldCorrupt, weatherResult.valid);
assert.eq(1, weatherResult.nIndexes);
assert.eq(!shouldCorrupt, weatherResult.indexDetails["metadata.sensorId_1"].valid);
if (shouldCorrupt) {
assert.eq(3, weatherResult.extraIndexEntries.length);
} else {
assert.eq(3, weatherResult.nrecords);
}
let uniqResults = validateLogs.filter((json) => json.id === 9437301 && json.attr.results.ns == "test.uniqueColl");
assert.eq(1, uniqResults.length);
let uniqResult = uniqResults[0].attr.results;
assert(uniqResult, "Couldn't find validation result for test.uniqueColl");
jsTestLog(uniqResult);
assert.eq(!shouldCorrupt, uniqResult.valid);
assert.eq(2, uniqResult.nIndexes);
assert.eq(!shouldCorrupt, uniqResult.indexDetails["_id_"].valid);
assert.eq(!shouldCorrupt, uniqResult.indexDetails["uniq_1"].valid);
if (shouldCorrupt) {
assert.eq(6, uniqResult.extraIndexEntries.length);
} else {
assert.eq(3, uniqResult.nrecords);
}
}
function getUri(conn, collection = "collect", indexName = "_id_") {
let coll = conn.getDB("test").getCollection(collection);
const uri = getUriForIndex(coll, indexName);
return uri;
}
function corruptUris(dbpath, uris) {
for (let i = 0; i < uris.length; i++) {
runWiredTigerTool("-h", dbpath, "truncate", uris[i]);
}
}
function testVersion(binVersion, fcv, shouldCorrupt) {
jsTestLog("Testing Version: " + binVersion + ", corrupted index? " + shouldCorrupt);
resetDbpath(dbpath);
let opts = {dbpath: dbpath, binVersion: binVersion};
let conn = MongoRunner.runMongod(opts);
let adminDB = conn.getDB("admin");
const res = adminDB.runCommand({"setFeatureCompatibilityVersion": fcv});
if (!res.ok && res.code === 7369100) {
// We failed due to requiring 'confirm: true' on the command. This will only
// occur on 7.0+ nodes that have 'enableTestCommands' set to false. Retry the
// setFCV command with 'confirm: true'.
assert.commandWorked(
adminDB.runCommand({
"setFeatureCompatibilityVersion": fcv,
confirm: true,
}),
);
} else {
assert.commandWorked(res, "Failed to run command with args: " + binVersion + " " + fcv);
}
let testDB1 = conn.getDB("test");
const port = conn.port;
setupCommon(testDB1);
if (shouldCorrupt) {
let toTruncate = [];
toTruncate.push(getUri(conn));
jsTestLog(toTruncate);
MongoRunner.stopMongod(conn, null, {skipValidation: true});
corruptUris(conn.dbpath, toTruncate);
} else {
MongoRunner.stopMongod(conn, null, {skipValidation: true});
}
clearRawMongoProgramOutput();
jsTestLog("Beginning command line validation");
MongoRunner.runMongod({port: port, dbpath: dbpath, validate: "", noCleanData: true});
let validateLogs = rawMongoProgramOutput("(9437301|9437303|9437304)")
.split("\n")
.filter((line) => line.trim() !== "")
.map((line) => JSON.parse(line.split("|").slice(1).join("|")));
checkCommon(validateLogs, shouldCorrupt);
}
for (let i = 0; i < allLtsVersions.length; i++) {
testVersion(allLtsVersions[i].binVersion, allLtsVersions[i].featureCompatibilityVersion, false);
}
for (let i = 0; i < allLtsVersions.length; i++) {
testVersion(allLtsVersions[i].binVersion, allLtsVersions[i].featureCompatibilityVersion, true);
}