diff options
Diffstat (limited to 'jstests/change_streams/show_system_events.js')
-rw-r--r-- | jstests/change_streams/show_system_events.js | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/jstests/change_streams/show_system_events.js b/jstests/change_streams/show_system_events.js new file mode 100644 index 00000000000..ba7633fdcc0 --- /dev/null +++ b/jstests/change_streams/show_system_events.js @@ -0,0 +1,258 @@ +/** + * Tests the behavior of change streams in the presence of 'showSystemEvents' flag. + * + * @tags: [ + * requires_fcv_60, + * # This test assumes certain ordering of events. + * assumes_unsharded_collection, + * # Assumes to implicit index creation. + * assumes_no_implicit_index_creation + * ] + */ +(function() { +"use strict"; + +load('jstests/libs/change_stream_util.js'); // For 'ChangeStreamTest' and + // 'assertChangeStreamEventEq'. +load('jstests/libs/collection_drop_recreate.js'); // For 'assertDropCollection'. + +const testDB = db.getSiblingDB(jsTestName()); + +if (!isChangeStreamsVisibilityEnabled(testDB)) { + assert.commandFailedWithCode(testDB.runCommand({ + aggregate: 1, + pipeline: [{$changeStream: {showSystemEvents: true}}], + cursor: {}, + }), + 6189301); + return; +} + +// Assert that the flag is not allowed with 'apiStrict'. +assert.commandFailedWithCode(testDB.runCommand({ + aggregate: 1, + pipeline: [{$changeStream: {showSystemEvents: true}}], + cursor: {}, + apiVersion: "1", + apiStrict: true +}), + ErrorCodes.APIStrictError); + +const test = new ChangeStreamTest(testDB); + +const systemNS = { + db: testDB.getName(), + coll: 'system.js' +}; +const collRenamed = 'collRenamed'; + +function runWholeDbChangeStreamTestWithoutSystemEvents(test, cursor, nonSystemColl) { + assertDropCollection(testDB, nonSystemColl.getName()); + + let expected = { + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "drop", + }; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]}); + + // Write to the 'normal' collection. + assert.commandWorked(nonSystemColl.insert({_id: 1, a: 1})); + + // Insert a document into the system.js collection. + assert.commandWorked(testDB.system.js.insert({_id: 3, c: 1})); + + // The next event should still be only the insert into the 'regular' collection, even though + // we've inserted into the system collection. + let expectedChanges = [ + { + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "create", + }, + { + documentKey: {_id: 1}, + fullDocument: {_id: 1, a: 1}, + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "insert", + } + ]; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: expectedChanges}); + + // Update into a system collection. + assert.commandWorked(testDB.system.js.update({_id: 3}, {c: 2})); + // Delete from a system collection. + assert.commandWorked(testDB.system.js.remove({_id: 3})); + + // Rename the system collection. + assert.commandWorked(testDB.system.js.renameCollection(collRenamed)); + // Rename back to system collection. + assert.commandWorked(testDB[collRenamed].renameCollection(systemNS.coll)); + + // We should see both renames because they involve a normal namespace. However, we don't see any + // of the preceding CRUD operations on the system collection. + expectedChanges = [ + { + ns: {db: testDB.getName(), coll: systemNS.coll}, + to: {db: testDB.getName(), coll: collRenamed}, + operationType: "rename", + }, + { + ns: {db: testDB.getName(), coll: collRenamed}, + to: {db: testDB.getName(), coll: systemNS.coll}, + operationType: "rename", + } + ]; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: expectedChanges}); + + // Once again write to the 'normal' collection. + assert.commandWorked(nonSystemColl.insert({_id: 2, a: 1})); + + // Similar as to before, the next event should be the insert on the 'regular' collection even + // though we have performed a number of operations on the system collection. + expected = { + documentKey: {_id: 2}, + fullDocument: {_id: 2, a: 1}, + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "insert", + }; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]}); +} + +function runWholeDbChangeStreamTestWithSystemEvents(test, cursor, nonSystemColl) { + assertDropCollection(testDB, nonSystemColl.getName()); + + let expected = { + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "drop", + }; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]}); + + // Write to the 'normal' collection. + assert.commandWorked(nonSystemColl.insert({_id: 1, a: 1})); + + let expectedChanges = [ + { + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "create", + }, + { + documentKey: {_id: 1}, + fullDocument: {_id: 1, a: 1}, + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "insert", + } + ]; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: expectedChanges}); + + // Insert into a system collection. + assert.commandWorked(testDB.system.js.insert({_id: 2, b: 1})); + + expected = { + documentKey: {_id: 2}, + fullDocument: {_id: 2, b: 1}, + ns: {db: testDB.getName(), coll: systemNS.coll}, + operationType: "insert", + }; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]}); + + // Update into a system collection. + assert.commandWorked(testDB.system.js.update({_id: 2}, {b: 2})); + + expected = { + documentKey: {_id: 2}, + fullDocument: {_id: 2, b: 2}, + ns: {db: testDB.getName(), coll: systemNS.coll}, + operationType: "replace", + }; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]}); + + // Delete from a system collection. + assert.commandWorked(testDB.system.js.remove({_id: 2})); + + expected = { + documentKey: {_id: 2}, + ns: {db: testDB.getName(), coll: systemNS.coll}, + operationType: "delete", + }; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]}); + + // Rename the system collection. + assert.commandWorked(testDB.system.js.renameCollection(collRenamed)); + // Rename back to system collection. + assert.commandWorked(testDB[collRenamed].renameCollection(systemNS.coll)); + + expectedChanges = [ + { + ns: {db: testDB.getName(), coll: systemNS.coll}, + to: {db: testDB.getName(), coll: collRenamed}, + operationType: "rename", + }, + { + ns: {db: testDB.getName(), coll: collRenamed}, + to: {db: testDB.getName(), coll: systemNS.coll}, + operationType: "rename", + } + ]; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: expectedChanges}); +} + +function runSingleCollectionChangeStreamTest(test, cursor, nonSystemColl) { + // Write to the 'normal' collection. + assert.commandWorked(nonSystemColl.insert({_id: 1, a: 1})); + + let expected = { + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "create", + }; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]}); + + // Insert into a system collection. + assert.commandWorked(testDB.system.js.insert({_id: 1, a: 1})); + // Update into a system collection. + assert.commandWorked(testDB.system.js.update({_id: 1}, {a: 2})); + // Delete from a system collection. + assert.commandWorked(testDB.system.js.remove({_id: 1})); + + // Rename the system collection. + assert.commandWorked(testDB.system.js.renameCollection(collRenamed)); + // Rename back to system collection. + assert.commandWorked(testDB[collRenamed].renameCollection(systemNS.coll)); + + // Write again to the 'normal' collection as a sentinel write. + assert.commandWorked(nonSystemColl.insert({_id: 2, a: 2})); + + // The only expected events should be the two inserts into the non-system collection. + const expectedChanges = [ + { + documentKey: {_id: 1}, + fullDocument: {_id: 1, a: 1}, + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "insert", + }, + { + documentKey: {_id: 2}, + fullDocument: {_id: 2, a: 2}, + ns: {db: testDB.getName(), coll: nonSystemColl.getName()}, + operationType: "insert", + } + ]; + test.assertNextChangesEqual({cursor: cursor, expectedChanges: expectedChanges}); +} + +const regularColl = testDB.test_coll; +regularColl.drop(); + +// Run a single-collection stream on a normal collection with 'showSystemEvents' set to 'true'. +let pipeline = [{$changeStream: {showExpandedEvents: true, showSystemEvents: true}}]; +let cursor = test.startWatchingChanges({pipeline: pipeline, collection: regularColl}); +runSingleCollectionChangeStreamTest(test, cursor, regularColl); + +// Run a whole-DB stream with 'showSystemEvents' set to 'true'. +pipeline = [{$changeStream: {showExpandedEvents: true, showSystemEvents: true}}]; +cursor = test.startWatchingChanges({pipeline: pipeline, collection: 1}); +runWholeDbChangeStreamTestWithSystemEvents(test, cursor, regularColl); + +// Now run a whole-DB stream with 'showSystemEvents' set to 'false'. +pipeline = [{$changeStream: {showExpandedEvents: true, showSystemEvents: false}}]; +cursor = test.startWatchingChanges({pipeline: pipeline, collection: 1}); +runWholeDbChangeStreamTestWithoutSystemEvents(test, cursor, regularColl); +}());
\ No newline at end of file |