2022-06-28 04:46:39 +02:00
|
|
|
/**
|
|
|
|
* Tests that the validate command detects various types of BSON inconsistencies.
|
2022-07-27 20:24:08 +02:00
|
|
|
*
|
2022-09-08 20:47:58 +02:00
|
|
|
* @tags: [requires_fcv_62]
|
2022-06-28 04:46:39 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
import {
|
|
|
|
getUriForColl,
|
|
|
|
insertDocDuplicateFieldName,
|
2022-07-27 20:24:08 +02:00
|
|
|
insertDocSymbolField,
|
2022-08-09 16:19:38 +02:00
|
|
|
insertInvalidRegex,
|
2022-08-20 09:33:08 +02:00
|
|
|
insertInvalidUTF8,
|
2022-06-28 04:46:39 +02:00
|
|
|
insertNonSequentialArrayIndexes,
|
|
|
|
startMongodOnExistingPath,
|
|
|
|
} from "jstests/disk/libs/wt_file_helper.js";
|
|
|
|
|
|
|
|
const baseName = "validate_bson_inconsistency";
|
|
|
|
const collNamePrefix = "test_";
|
|
|
|
let count = 0;
|
|
|
|
const dbpath = MongoRunner.dataPath + baseName + "/";
|
|
|
|
|
|
|
|
resetDbpath(dbpath);
|
|
|
|
|
|
|
|
(function validateDocumentsDuplicateFieldNames() {
|
|
|
|
jsTestLog("Validate documents with duplicate field names");
|
|
|
|
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
const collName = collNamePrefix + count++;
|
|
|
|
db.createCollection(collName);
|
|
|
|
let testColl = db[collName];
|
|
|
|
|
|
|
|
let uri = getUriForColl(testColl);
|
|
|
|
const numDocs = 10;
|
|
|
|
insertDocDuplicateFieldName(testColl, uri, mongod, numDocs);
|
|
|
|
|
|
|
|
mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
db = mongod.getDB(baseName);
|
|
|
|
testColl = db[collName];
|
2022-08-20 03:10:31 +02:00
|
|
|
testColl.insert({a: 1, b: 2, c: {b: 3}, d: {a: [2, 3, 4], b: {a: 2}}});
|
|
|
|
testColl.insert({a: 1, b: 1});
|
2022-06-28 04:46:39 +02:00
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
// Warnings should be triggered iff checkBSONConformance is set to true.
|
2022-06-28 04:46:39 +02:00
|
|
|
let res = assert.commandWorked(testColl.validate());
|
|
|
|
assert(res.valid, tojson(res));
|
2022-08-20 03:10:31 +02:00
|
|
|
assert.eq(res.nNonCompliantDocuments, 0);
|
|
|
|
assert.eq(res.warnings.length, 0);
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
res = assert.commandWorked(testColl.validate({checkBSONConformance: true}));
|
2022-08-20 03:10:31 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, numDocs);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
2022-08-02 15:45:56 +02:00
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
|
|
|
})();
|
2022-06-28 04:46:39 +02:00
|
|
|
|
2022-08-02 15:45:56 +02:00
|
|
|
(function validateDocumentsInvalidUUIDLength() {
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
const collName = collNamePrefix + count++;
|
|
|
|
db.createCollection(collName);
|
|
|
|
let coll = db[collName];
|
|
|
|
|
|
|
|
jsTestLog(
|
|
|
|
"Checks that warnings are triggered when validating UUIDs that are either too short or too long.");
|
|
|
|
coll.insert({u: HexData(4, "deadbeefdeadbeefdeadbeefdeadbeef")});
|
|
|
|
coll.insert({u: HexData(4, "deadbeef")});
|
|
|
|
coll.insert({
|
|
|
|
u: HexData(
|
|
|
|
4,
|
|
|
|
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
|
|
|
|
});
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
let res = coll.validate({checkBSONConformance: true});
|
2022-08-02 15:45:56 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 2);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
res = coll.validate({checkBSONConformance: false});
|
2022-08-02 15:45:56 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 2);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
2022-06-28 04:46:39 +02:00
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
|
|
|
})();
|
2022-07-27 20:24:08 +02:00
|
|
|
|
2022-08-09 16:19:38 +02:00
|
|
|
(function validateDocumentsInvalidRegexOptions() {
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
|
|
|
|
const collName = collNamePrefix + count++;
|
|
|
|
db.getCollection(collName).drop();
|
|
|
|
assert.commandWorked(db.createCollection(collName));
|
|
|
|
let coll = db[collName];
|
|
|
|
|
|
|
|
jsTestLog(
|
|
|
|
"Checks that issues are found when we validate regex expressions with invalid options.");
|
|
|
|
insertInvalidRegex(coll, mongod, 5);
|
|
|
|
mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
db = mongod.getDB(baseName);
|
|
|
|
coll = db[collName];
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
let res = coll.validate({checkBSONConformance: false});
|
2022-08-09 16:19:38 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 5);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
res = coll.validate({checkBSONConformance: true});
|
2022-08-09 16:19:38 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 5);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
|
|
|
})();
|
|
|
|
|
2022-07-28 20:21:40 +02:00
|
|
|
(function validateDocumentsInvalidMD5Length() {
|
|
|
|
jsTestLog("Validate document with invalid MD5 length");
|
|
|
|
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
const collName = collNamePrefix + count++;
|
|
|
|
|
|
|
|
db.createCollection(collName);
|
|
|
|
let testColl = db[collName];
|
|
|
|
const properMD5 = HexData(5, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
|
|
const improperMD5 = HexData(5, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
|
|
|
|
|
|
// Tests that calling validate on a collection with a properly sized md5 doesn't return a
|
|
|
|
// warning.
|
|
|
|
assert.commandWorked(testColl.insert({"md5Proper": properMD5}));
|
|
|
|
let res = assert.commandWorked(testColl.validate());
|
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 0);
|
|
|
|
assert.eq(res.warnings.length, 0);
|
|
|
|
|
|
|
|
// Tests that calling validate on a collection with an improperly sized md5 returns a
|
|
|
|
// warning.
|
|
|
|
assert.commandWorked(testColl.insert({"md5Improper": improperMD5}));
|
|
|
|
res = assert.commandWorked(testColl.validate());
|
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 1);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
|
|
|
// Tests that calling validate, with BSONConsistencyCheck true, on a collection with an
|
|
|
|
// improperly sized md5 returns a warning.
|
|
|
|
assert.commandWorked(testColl.insert({"md5ImproperBSONConsistencyCheck": improperMD5}));
|
2022-08-25 15:57:20 +02:00
|
|
|
res = assert.commandWorked(testColl.validate({checkBSONConformance: true}));
|
2022-07-28 20:21:40 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 2);
|
|
|
|
|
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
|
|
|
})();
|
|
|
|
|
2022-07-27 20:24:08 +02:00
|
|
|
(function validateDocumentsDeprecatedTypes() {
|
|
|
|
jsTestLog("Validate documents with deprecated types");
|
|
|
|
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
const collName = collNamePrefix + count++;
|
2022-07-28 20:21:40 +02:00
|
|
|
|
2022-07-27 20:24:08 +02:00
|
|
|
db.createCollection(collName);
|
|
|
|
let testColl = db[collName];
|
|
|
|
|
|
|
|
let uri = getUriForColl(testColl);
|
|
|
|
const numDocs = 1;
|
|
|
|
insertDocSymbolField(testColl, uri, mongod, numDocs);
|
|
|
|
|
|
|
|
mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
db = mongod.getDB(baseName);
|
|
|
|
testColl = db[collName];
|
|
|
|
|
|
|
|
assert.commandWorked(testColl.insert({a: undefined}));
|
|
|
|
assert.commandWorked(
|
|
|
|
testColl.insert({b: DBPointer("db", new ObjectId("dbdbdbdbdbdbdbdbdbdbdbdb"))}));
|
|
|
|
assert.commandWorked(testColl.insert({c: Code("function(){return 1;}", {})}));
|
|
|
|
assert.commandWorked(testColl.insert(
|
|
|
|
{d: BinData(2, "KwAAAFRoZSBxdWljayBicm93biBmb3gganVtcHMgb3ZlciB0aGUgbGF6eSBkb2c=")}));
|
|
|
|
assert.commandWorked(testColl.insert({e: BinData(3, "000102030405060708090a0b0c0d0e0f")}));
|
|
|
|
assert.commandWorked(testColl.insert({
|
|
|
|
a: undefined,
|
|
|
|
b: DBPointer("db", new ObjectId("dbdbdbdbdbdbdbdbdbdbdbdb")),
|
|
|
|
c: Code("function(){return 1;}", {}),
|
|
|
|
d: BinData(2, "KwAAAFRoZSBxdWljayBicm93biBmb3gganVtcHMgb3ZlciB0aGUgbGF6eSBkb2c="),
|
|
|
|
e: BinData(3, "000102030405060708090a0b0c0d0e0f")
|
|
|
|
}));
|
|
|
|
|
|
|
|
let res = assert.commandWorked(testColl.validate());
|
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 7);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
res = assert.commandWorked(testColl.validate({checkBSONConformance: true}));
|
2022-07-27 20:24:08 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 7);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
|
|
|
})();
|
2022-08-16 21:48:10 +02:00
|
|
|
|
2022-08-19 19:55:53 +02:00
|
|
|
(function validateDocumentsCorruptedBinDataColumn() {
|
|
|
|
jsTestLog("Validate documents with corrupted or misformed BinData Columns.");
|
|
|
|
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
const collName = collNamePrefix + count++;
|
|
|
|
db.createCollection(collName);
|
|
|
|
let testColl = db[collName];
|
|
|
|
|
2023-11-07 16:32:59 +01:00
|
|
|
// Inserts a rubbish (random string) BSON Column (should fail validation to insert)
|
2022-08-19 19:55:53 +02:00
|
|
|
testColl.insert({a: BinData(7, "O2FkZmdqYWtsamhnJ2xhamhkZzthaCdmZGphZ2hkYQ==")});
|
|
|
|
// Inserts one valid BSON Column to check that it doesn't cause a false positive.
|
|
|
|
testColl.insert(
|
|
|
|
{a: BinData(7, "AQAAAAAAAAAAQJN/AAAAAAAAAAIAAAAAAAAABwAAAAAAAAAOAAAAAAAAAAA=")});
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
// Calling validate without 'checkBSONConformance' should not return any warnings.
|
2022-08-19 19:55:53 +02:00
|
|
|
let res = assert.commandWorked(testColl.validate());
|
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.warnings.length, 0);
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 0);
|
|
|
|
|
2023-11-07 16:32:59 +01:00
|
|
|
// Calling validate with 'checkBSONConformance' also should not return warnings
|
2022-08-25 15:57:20 +02:00
|
|
|
res = assert.commandWorked(testColl.validate({checkBSONConformance: true}));
|
2022-08-19 19:55:53 +02:00
|
|
|
assert(res.valid, tojson(res));
|
2023-11-07 16:32:59 +01:00
|
|
|
assert.eq(res.warnings.length, 0);
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 0);
|
2022-08-19 19:55:53 +02:00
|
|
|
|
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
|
|
|
})();
|
|
|
|
|
2022-08-16 21:48:10 +02:00
|
|
|
(function validateDocumentsNonSequentialArrayIndexes() {
|
|
|
|
jsTestLog("Validate documents with array indices that are not sequential");
|
|
|
|
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
const collName = collNamePrefix + count++;
|
|
|
|
db.createCollection(collName);
|
|
|
|
let testColl = db[collName];
|
|
|
|
|
|
|
|
let uri = getUriForColl(testColl);
|
|
|
|
const numDocs = 10;
|
|
|
|
insertNonSequentialArrayIndexes(testColl, uri, mongod, numDocs);
|
|
|
|
|
|
|
|
mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
db = mongod.getDB(baseName);
|
|
|
|
testColl = db[collName];
|
|
|
|
|
|
|
|
let res = assert.commandWorked(testColl.validate());
|
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 10);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
res = assert.commandWorked(testColl.validate({checkBSONConformance: true}));
|
2022-08-16 21:48:10 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 10);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
|
|
|
})();
|
2022-08-20 09:33:08 +02:00
|
|
|
|
|
|
|
(function validateDocumentsInvalidUTF8() {
|
|
|
|
jsTestLog("Validate documents with invalid UTF-8 strings");
|
|
|
|
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
const collName = collNamePrefix + count++;
|
|
|
|
db.createCollection(collName);
|
|
|
|
let testColl = db[collName];
|
|
|
|
|
|
|
|
let uri = getUriForColl(testColl);
|
|
|
|
const numDocs = 10;
|
|
|
|
insertInvalidUTF8(testColl, uri, mongod, numDocs);
|
|
|
|
|
|
|
|
mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
db = mongod.getDB(baseName);
|
|
|
|
testColl = db[collName];
|
|
|
|
|
|
|
|
let res = assert.commandWorked(testColl.validate());
|
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 0);
|
|
|
|
assert.eq(res.warnings.length, 0);
|
|
|
|
|
2022-08-25 15:57:20 +02:00
|
|
|
res = assert.commandWorked(testColl.validate({checkBSONConformance: true}));
|
2022-08-20 09:33:08 +02:00
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 10);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
|
|
|
})();
|
2022-09-01 21:16:42 +02:00
|
|
|
|
|
|
|
(function validateDocumentsInvalidEncryptedBSONValue() {
|
|
|
|
jsTestLog("Validate documents with invalid Encrypted BSON Value");
|
|
|
|
|
|
|
|
let mongod = startMongodOnExistingPath(dbpath);
|
|
|
|
let db = mongod.getDB(baseName);
|
|
|
|
const collName = collNamePrefix + count++;
|
|
|
|
|
|
|
|
db.createCollection(collName);
|
|
|
|
let testColl = db[collName];
|
|
|
|
// A valid Encrypted BSON document with the type byte, 16-byte key uuid, original BSON type
|
|
|
|
// byte, and an empty cipher text.
|
|
|
|
const properFLE = HexData(6, "060102030405060708091011121314151610");
|
|
|
|
// Invalid Encrypted BSON Value subtype 3.
|
|
|
|
const improperFLE1 = HexData(6, "030102030405060708091011121314151610");
|
|
|
|
// Invalid original BSON type MinKey.
|
|
|
|
const improperFLE2 = HexData(6, "0601020304050607080910111213141516ff");
|
|
|
|
// Empty Encrypted BSON Value.
|
|
|
|
const improperFLE3 = HexData(6, "");
|
|
|
|
// Short Encrypted BSON Value.
|
|
|
|
const improperFLE4 = HexData(6, "0601");
|
|
|
|
|
|
|
|
assert.commandWorked(testColl.insertMany([
|
|
|
|
{"fle": properFLE},
|
|
|
|
{"fle": improperFLE1},
|
|
|
|
{"fle": improperFLE2},
|
|
|
|
{"fle": improperFLE3},
|
|
|
|
{"fle": improperFLE4},
|
|
|
|
]));
|
|
|
|
|
|
|
|
let res = assert.commandWorked(testColl.validate());
|
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 4);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
|
|
|
res = assert.commandWorked(testColl.validate({checkBSONConformance: true}));
|
|
|
|
assert(res.valid, tojson(res));
|
|
|
|
assert.eq(res.nNonCompliantDocuments, 4);
|
|
|
|
assert.eq(res.warnings.length, 1);
|
|
|
|
|
|
|
|
MongoRunner.stopMongod(mongod, null, {skipValidation: true});
|
2022-06-28 04:46:39 +02:00
|
|
|
})();
|