summaryrefslogtreecommitdiff
path: root/jstests/change_streams/whole_cluster.js
blob: b95453d12bcb53e6b6e1eb4f4bfc1b32989b8255 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Basic tests for $changeStream against all databases in the cluster.
(function() {
    "use strict";

    load("jstests/libs/collection_drop_recreate.js");  // For assert[Drop|Create]Collection.
    load("jstests/libs/change_stream_util.js");        // For ChangeStreamTest and
                                                       // assert[Valid|Invalid]ChangeStreamNss.
    load("jstests/libs/fixture_helpers.js");           // For FixtureHelpers.

    db = db.getSiblingDB(jsTestName());
    const adminDB = db.getSiblingDB("admin");
    const otherDB = db.getSiblingDB(jsTestName() + "_other");

    // Drop and recreate the collections to be used in this set of tests.
    assertDropAndRecreateCollection(db, "t1");
    assertDropAndRecreateCollection(otherDB, "t2");

    // Test that a change stream can be opened on the admin database if {allChangesForCluster:true}
    // is specified.
    assertValidChangeStreamNss("admin", 1, {allChangesForCluster: true});
    // Test that a change stream cannot be opened on the admin database if a collection is
    // specified, even with {allChangesForCluster:true}.
    assertInvalidChangeStreamNss("admin", "testcoll", {allChangesForCluster: true});
    // Test that a change stream cannot be opened on a database other than admin if
    // {allChangesForCluster:true} is specified.
    assertInvalidChangeStreamNss(db.getName(), 1, {allChangesForCluster: true});

    let cst = new ChangeStreamTest(adminDB);
    let cursor = cst.startWatchingAllChangesForCluster();

    // Test that if there are no changes, we return an empty batch.
    assert.eq(0, cursor.firstBatch.length, "Cursor had changes: " + tojson(cursor));

    // Test that the change stream returns an inserted doc.
    assert.writeOK(db.t1.insert({_id: 0, a: 1}));
    let expected = {
        documentKey: {_id: 0},
        fullDocument: {_id: 0, a: 1},
        ns: {db: db.getName(), coll: "t1"},
        operationType: "insert",
    };
    cst.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]});

    // Test that the change stream returns another inserted doc in a different database.
    assert.writeOK(otherDB.t2.insert({_id: 0, a: 2}));
    expected = {
        documentKey: {_id: 0},
        fullDocument: {_id: 0, a: 2},
        ns: {db: otherDB.getName(), coll: "t2"},
        operationType: "insert",
    };
    cst.assertNextChangesEqual({cursor: cursor, expectedChanges: [expected]});

    // Test that the change stream returns an inserted doc on a user-created database whose name
    // includes 'admin', 'local', or 'config'.
    const validUserDBs = [
        "admin1",
        "1admin",
        "_admin_",
        "local_",
        "_local",
        "_local_",
        "config_",
        "_config",
        "_config_"
    ];
    validUserDBs.forEach(dbName => {
        assert.writeOK(db.getSiblingDB(dbName).test.insert({_id: 0, a: 1}));
        expected = [
            {
              documentKey: {_id: 0},
              fullDocument: {_id: 0, a: 1},
              ns: {db: dbName, coll: "test"},
              operationType: "insert",
            },
        ];
        cst.assertNextChangesEqual({cursor: cursor, expectedChanges: expected});
    });

    // Test that the change stream returns an inserted doc on a user-created collection whose name
    // includes "system" but is not considered an internal collection.
    const validSystemColls = ["system", "systems.views", "ssystem.views", "test.system"];
    validSystemColls.forEach(collName => {
        assert.writeOK(db.getCollection(collName).insert({_id: 0, a: 1}));
        expected = [
            {
              documentKey: {_id: 0},
              fullDocument: {_id: 0, a: 1},
              ns: {db: db.getName(), coll: collName},
              operationType: "insert",
            },
        ];
        cst.assertNextChangesEqual({cursor: cursor, expectedChanges: expected});
    });

    // Test that the change stream filters out operations on any collection in the 'admin', 'local',
    // or 'config' databases.
    const filteredDBs = ["admin", "local", "config"];
    filteredDBs.forEach(dbName => {
        // Not allowed to use 'local' db through mongos.
        if (FixtureHelpers.isMongos(db) && dbName == "local")
            return;

        assert.writeOK(db.getSiblingDB(dbName).test.insert({_id: 0, a: 1}));
        // Insert to the test collection to ensure that the change stream has something to
        // return.
        assert.writeOK(db.t1.insert({_id: dbName}));
        expected = [
            {
              documentKey: {_id: dbName},
              fullDocument: {_id: dbName},
              ns: {db: db.getName(), coll: "t1"},
              operationType: "insert",
            },
        ];
        cst.assertNextChangesEqual({cursor: cursor, expectedChanges: expected});
        // Drop the test collection to avoid duplicate key errors if this test is run multiple
        // times.
        assertDropCollection(db.getSiblingDB(dbName), "test");
    });

    // Dropping a database should generate drop entries for each collection followed by a database
    // drop.
    assert.commandWorked(otherDB.dropDatabase());
    cst.assertDatabaseDrop({cursor: cursor, db: otherDB});

    // Drop the remaining databases and clean up the test.
    assert.commandWorked(db.dropDatabase());
    validUserDBs.forEach(dbName => {
        db.getSiblingDB(dbName).dropDatabase();
    });
    cst.cleanUp();
}());