[required variant with jstestshell changes](https://spruce.mongodb.com/version/6643e8bf8571a30007c6562d/tasks?sorts=STATUS%3AASC%3BBASE_STATUS%3ADESC) <- 242 hours [required variant without jstestshell changes](https://spruce.mongodb.com/version/6643e9dd8571a30007c6576b/tasks?sorts=STATUS%3AASC%3BBASE_STATUS%3ADESC) <- 301 hours 20% reduction in compute. [AUBSAN After](https://spruce.mongodb.com/version/6644ecfaf87baf0007e4b124/tasks): 412 hours [AUBSAN Before](https://spruce.mongodb.com/version/6644e4b131a6190007b0526c/tasks) 539 hours 24% reduction in compute [TSAN After](https://spruce.mongodb.com/version/6644ecabe2618d0007a54406/tasks) 356 hours [TSAN Before](https://spruce.mongodb.com/version/6644e47f9b110e0007e9820f/tasks) 580 hours 39% reduction in compute According to project outliers this should reduce our spend on mongodb-mongo-master by (20%*20.32%) = 4.06% (39%*14.82%) = 5.78% (24%*8.73%) = 2.10% **Total: 11.94%** In all these patches we use a jstest shell compiled without debug symbols and statically linked. This increased the startup speed from 1.2 seconds to .02 seconds. Since each javascript test is run with a separate invocation of the shell this speeds up ever javascript test by about 1.2 seconds. The tradeoff is that we are not going to catch tsan or aubsan bugs in the jstestshell and it makes our test running process just that much more complicated. Not included here is another optimization to run batches of javascript tests together to avoid having to re-handshake with the database. [Final PB](https://spruce.mongodb.com/version/664b780cceb3230007a77382/tasks?sorts=STATUS%3AASC%3BBASE_STATUS%3ADESC) showing mostly green. GitOrigin-RevId: db2f54f832512676f6f8159e1267d5ae69aa6b3d
159 lines
5.3 KiB
JavaScript
159 lines
5.3 KiB
JavaScript
/**
|
|
* Tests basic CRUD operations with queryable encrypted fields.
|
|
*
|
|
* @tags: [
|
|
* no_selinux,
|
|
* tenant_migration_incompatible,
|
|
* does_not_support_transactions,
|
|
* does_not_support_stepdowns,
|
|
* # Test requires an internal connection for the keyvault that can't be overriden by the
|
|
* # `simulate_atlas_proxy` override.
|
|
* simulate_atlas_proxy_incompatible,
|
|
* ]
|
|
*/
|
|
import {
|
|
assertIsIndexedEncryptedField,
|
|
EncryptedClient,
|
|
kSafeContentField
|
|
} from "jstests/fle2/libs/encrypted_client_util.js";
|
|
|
|
const buildInfo = assert.commandWorked(db.runCommand({"buildInfo": 1}));
|
|
|
|
if (!(buildInfo.modules.includes("enterprise"))) {
|
|
jsTestLog("Skipping test as it requires the enterprise module");
|
|
quit();
|
|
}
|
|
|
|
const dbName = "qetestdb";
|
|
const collName = "qetestcoll";
|
|
const initialConn = db.getMongo();
|
|
const localKMS = {
|
|
key: BinData(
|
|
0,
|
|
"/tu9jUCBqZdwCelwE/EAm/4WqdxrSMi04B8e9uAV+m30rI1J2nhKZZtQjdvsSCwuI4erR6IEcEK+5eGUAODv43NDNIR9QheT2edWFewUfHKsl9cnzTc86meIzOmYl6dr")
|
|
};
|
|
|
|
// Some tests silently change the DB name to prefix it with a tenant ID, but we
|
|
// need to pass the real DB name for the keyvault when setting up the auto encryption,
|
|
// so that the internal connection for the key vault will target the right DB name.
|
|
const kvDbName = (typeof (initialConn.getDbNameWithTenantPrefix) === "function")
|
|
? initialConn.getDbNameWithTenantPrefix(dbName)
|
|
: dbName;
|
|
jsTestLog("Using key vault db " + kvDbName);
|
|
|
|
const clientSideFLEOptions = {
|
|
kmsProviders: {local: localKMS},
|
|
keyVaultNamespace: kvDbName + ".keystore",
|
|
schemaMap: {},
|
|
};
|
|
|
|
db.getSiblingDB(dbName).dropDatabase();
|
|
|
|
assert(initialConn.setAutoEncryption(clientSideFLEOptions));
|
|
|
|
let encryptedClient = new EncryptedClient(initialConn, dbName);
|
|
assert.commandWorked(encryptedClient.createEncryptionCollection(collName, {
|
|
encryptedFields: {
|
|
"fields": [
|
|
{"path": "first", "bsonType": "string", "queries": {"queryType": "equality"}},
|
|
]
|
|
}
|
|
}));
|
|
|
|
initialConn.toggleAutoEncryption(true);
|
|
|
|
function runIndexedEqualityEncryptedCRUDTest(client, iterations) {
|
|
let conn = client.getDB().getMongo();
|
|
let ecoll = client.getDB()[collName];
|
|
let values =
|
|
[["frodo", "baggins"], ["sam", "gamgee"], ["pippin", "took"], ["merry", "brandybuck"]];
|
|
let count = 0;
|
|
let escCount = 0;
|
|
let ecocCount = 0;
|
|
|
|
// Do encrypted inserts
|
|
for (let it = 0; it < iterations; it++) {
|
|
for (let val of values) {
|
|
assert.commandWorked(ecoll.insert({_id: count, first: val[0], last: val[1]}));
|
|
count++;
|
|
client.assertEncryptedCollectionCounts(collName, count, count, count);
|
|
}
|
|
}
|
|
escCount = count;
|
|
ecocCount = count;
|
|
|
|
// Do finds using unencrypted connection
|
|
{
|
|
conn.toggleAutoEncryption(false);
|
|
|
|
let rawDocs = ecoll.find().toArray();
|
|
assert.eq(rawDocs.length, count);
|
|
for (let rawDoc of rawDocs) {
|
|
assertIsIndexedEncryptedField(rawDoc.first);
|
|
assert(rawDoc[kSafeContentField] !== undefined);
|
|
}
|
|
conn.toggleAutoEncryption(true);
|
|
}
|
|
|
|
// Do encrypted queries using encrypted connection
|
|
for (let mod = 0; mod < values.length; mod++) {
|
|
let docs = ecoll.find({last: values[mod][1]}).toArray();
|
|
|
|
for (let doc of docs) {
|
|
assert.eq(doc._id % values.length, mod);
|
|
assert.eq(doc.first, values[mod][0]);
|
|
assert(doc[kSafeContentField] !== undefined);
|
|
}
|
|
}
|
|
|
|
// Do updates on encrypted fields
|
|
for (let it = 0; it < iterations; it++) {
|
|
let res = assert.commandWorked(ecoll.updateOne(
|
|
{$and: [{last: "baggins"}, {first: "frodo"}]}, {$set: {first: "bilbo"}}));
|
|
assert.eq(res.matchedCount, 1);
|
|
assert.eq(res.modifiedCount, 1);
|
|
escCount++;
|
|
ecocCount++;
|
|
client.assertEncryptedCollectionCounts(collName, count, escCount, ecocCount);
|
|
|
|
res = assert.commandWorked(
|
|
ecoll.replaceOne({last: "took"}, {first: "paladin", last: "took"}));
|
|
assert.eq(res.matchedCount, 1);
|
|
assert.eq(res.modifiedCount, 1);
|
|
escCount++;
|
|
ecocCount++;
|
|
client.assertEncryptedCollectionCounts(collName, count, escCount, ecocCount);
|
|
}
|
|
|
|
// Do findAndModifies
|
|
for (let it = 0; it < iterations; it++) {
|
|
let res = assert.commandWorked(ecoll.runCommand({
|
|
findAndModify: ecoll.getName(),
|
|
query: {$and: [{last: "gamgee"}, {first: "sam"}]},
|
|
update: {$set: {first: "rosie"}},
|
|
}));
|
|
print(tojson(res));
|
|
assert.eq(res.value.first, "sam");
|
|
assert(res.value[kSafeContentField] !== undefined);
|
|
escCount++;
|
|
ecocCount++;
|
|
client.assertEncryptedCollectionCounts(collName, count, escCount, ecocCount);
|
|
}
|
|
|
|
// Do deletes
|
|
for (let it = 0; it < iterations; it++) {
|
|
let res = assert.commandWorked(
|
|
ecoll.deleteOne({last: "brandybuck"}, {writeConcern: {w: "majority"}}));
|
|
assert.eq(res.deletedCount, 1);
|
|
count--;
|
|
client.assertEncryptedCollectionCounts(collName, count, escCount, ecocCount);
|
|
}
|
|
assert.eq(ecoll.find({last: "brandybuck"}).count(), 0);
|
|
}
|
|
|
|
// Test CRUD on indexed equality encrypted fields
|
|
runIndexedEqualityEncryptedCRUDTest(encryptedClient, 10);
|
|
|
|
encryptedClient = undefined;
|
|
initialConn.unsetAutoEncryption();
|