mongo/jstests/change_streams/ddl_create_drop_index_event...

178 lines
7.1 KiB
JavaScript

/**
* Tests the behavior of the createIndex and dropIndex events without various command parameters.
*
* @tags: [
* requires_fcv_60,
* assumes_unsharded_collection,
* assumes_against_mongod_not_mongos,
* ]
*/
import {ChangeStreamTest} from "jstests/libs/query/change_stream_util.js";
const testDB = db.getSiblingDB(jsTestName());
const dbName = testDB.getName();
const collName = jsTestName();
const ns = {
db: dbName,
coll: collName,
};
const cst = new ChangeStreamTest(testDB);
function assertNextChangeEvent(cursor, expectedEvent) {
cst.assertNextChangesEqual({cursor: cursor, expectedChanges: expectedEvent});
}
function runTest(startChangeStream, pipeline, insertDataBeforeCreateIndex) {
const cst = new ChangeStreamTest(testDB);
assert.commandWorked(testDB.runCommand({create: collName}));
if (insertDataBeforeCreateIndex) {
testDB[collName].insert({a: 1, b: "j", c: "k", d: "l", e: "m", f: [55.5, 42.3]});
}
function testCreateIndexAndDropIndex(key, options, opDescKey = key, dropKey) {
let name = "";
if (options.hasOwnProperty("name")) {
// If the "name" option was explicitly specified, use that
name = options.name;
dropKey = name;
} else {
// Otherwise, determine what "name" should be based on "key"
let arr = [];
for (let property in key) {
arr.push(property);
arr.push(key[property]);
}
name = arr.join("_");
}
if (dropKey == undefined) {
dropKey = name;
}
let cursor = startChangeStream();
let opDesc = {indexes: [Object.assign({v: 2, key: opDescKey, name: name}, options)]};
assert.commandWorked(testDB[collName].createIndex(key, options));
if (insertDataBeforeCreateIndex && pipeline[0].$changeStream.showSystemEvents) {
assertNextChangeEvent(cursor, {operationType: "startIndexBuild", ns: ns, operationDescription: opDesc});
}
assertNextChangeEvent(cursor, {operationType: "createIndexes", ns: ns, operationDescription: opDesc});
assert.commandWorked(testDB[collName].dropIndexes([dropKey]));
assertNextChangeEvent(cursor, {operationType: "dropIndexes", ns: ns, operationDescription: opDesc});
}
// Test createIndex() with various option followed by dropIndexes("*").
let options = {
hidden: true,
partialFilterExpression: {a: {$gte: 0}},
expireAfterSeconds: 86400,
storageEngine: {wiredTiger: {}},
};
testCreateIndexAndDropIndex({a: 1}, options);
// Test createIndex() with a non-simple collation followed by dropIndex(). We include all
// fields in the collation spec so that we don't rely on any default settings.
options = {
collation: {
locale: "en_US",
caseLevel: false,
caseFirst: "off",
strength: 3,
numericOrdering: false,
alternate: "non-ignorable",
maxVariable: "punct",
normalization: false,
backwards: false,
version: "57.1",
},
};
testCreateIndexAndDropIndex({e: 1}, options, {e: 1}, "*");
// Test createIndex() for a wildcard index on all fields with the wildcardProjection option,
// followed by dropIndex().
options = {name: "wi", wildcardProjection: {a: true, b: true, _id: false}};
testCreateIndexAndDropIndex({"$**": 1}, options);
// Test createIndex() for a text index with various options, followed by dropIndex().
options = {
name: "text",
weights: {e: 1},
default_language: "english",
language_override: "language",
textIndexVersion: 3,
};
testCreateIndexAndDropIndex({e: "text"}, options, {_fts: "text", _ftsx: 1});
// Test createIndex() for a 2d index with various options, followed by dropIndex().
options = {name: "2d", min: -150.0, max: 150.0, bits: 26};
testCreateIndexAndDropIndex({f: "2d"}, options);
// Test createIndex() for a 2dsphere index with various options, followed by dropIndex().
options = {name: "2dsphere", "2dsphereIndexVersion": 3};
testCreateIndexAndDropIndex({f: "2dsphere"}, options);
// Test createIndexes() to create two sparse indexes (with one index being a compound index),
// followed by dropIndexes().
let cursor = startChangeStream();
let opDesc1 = {indexes: [{v: 2, key: {b: 1, c: -1}, name: "b_1_c_-1", sparse: true}]};
let opDesc2 = {indexes: [{v: 2, key: {d: "hashed"}, name: "d_hashed", sparse: true}]};
if (!insertDataBeforeCreateIndex) {
// If the collection was empty before calling createIndexes(), then there will be a separate
// change stream event for each index.
assert.commandWorked(testDB[collName].createIndexes([{b: 1, c: -1}, {d: "hashed"}], {sparse: true}));
cst.assertNextChangesEqualUnordered({
cursor: cursor,
expectedChanges: [
{operationType: "createIndexes", ns: ns, operationDescription: opDesc1},
{operationType: "createIndexes", ns: ns, operationDescription: opDesc2},
],
});
} else {
// If the collection was not empty before calling createIndexes(), then there will be a
// single change stream event that covers both indexes.
assert.commandWorked(testDB[collName].createIndexes([{b: 1, c: -1}, {d: "hashed"}], {sparse: true}));
if (pipeline[0].$changeStream.showSystemEvents) {
assertNextChangeEvent(cursor, {
operationType: "startIndexBuild",
ns: ns,
operationDescription: {indexes: [opDesc1.indexes[0], opDesc2.indexes[0]]},
});
}
assertNextChangeEvent(cursor, {
operationType: "createIndexes",
ns: ns,
operationDescription: {indexes: [opDesc1.indexes[0], opDesc2.indexes[0]]},
});
}
assert.commandWorked(testDB[collName].dropIndexes(["b_1_c_-1", "d_hashed"]));
cst.assertNextChangesEqualUnordered({
cursor: cursor,
expectedChanges: [
{operationType: "dropIndexes", ns: ns, operationDescription: opDesc1},
{operationType: "dropIndexes", ns: ns, operationDescription: opDesc2},
],
});
testDB[collName].drop();
}
const runTests = function (pipeline) {
// Run the test using a whole-db change stream on an empty collection.
runTest(() => cst.startWatchingChanges({pipeline, collection: 1}), pipeline, false);
// Run the test using a single change stream on an empty collection.
runTest(() => cst.startWatchingChanges({pipeline, collection: collName}), pipeline, false);
// Run the test using a whole-db collection change stream on a non-empty collection.
runTest(() => cst.startWatchingChanges({pipeline, collection: 1}), pipeline, true);
// Run the test using a single collection change stream on a non-empty collection.
runTest(() => cst.startWatchingChanges({pipeline, collection: collName}), pipeline, true);
};
runTests([{$changeStream: {showExpandedEvents: true}}]);
runTests([{$changeStream: {showExpandedEvents: true, showSystemEvents: true}}]);