summaryrefslogtreecommitdiff
path: root/jstests/replsets/lastop.js
blob: f3eca2ccb3dbd1a8848420d0b23f1cbdf7243f04 (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
134
135
136
// Test that lastOp is updated properly in the face of no-op writes and for writes that generate
// errors based on the preexisting data (e.g. duplicate key errors, but not parse errors).
// lastOp is used as the optime to wait for when write concern waits for replication.
(function () {
    var replTest = new ReplSetTest({ name: 'testSet', nodes: 1 });
    replTest.startSet();
    replTest.initiate();

    var primary = replTest.getPrimary();

    // Two connections
    var m1 = new Mongo(primary.host);
    var m2 = new Mongo(primary.host);

    // Do a write with m1, then a write with m2, then a no-op write with m1. m1 should have a lastOp
    // of m2's write.
    
    assert.writeOK(m1.getCollection("test.foo").insert({ m1 : 1 }));
    var firstOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;
    
    assert.writeOK(m2.getCollection("test.foo").insert({ m2 : 99 }));
    var secondOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    // No-op update
    assert.writeOK(m1.getCollection("test.foo").update({ m1 : 1 }, { $set: { m1 : 1 }}));
    var noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.eq(noOp, secondOp);

    assert.writeOK(m1.getCollection("test.foo").remove({ m1 : 1 }));
    var thirdOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.writeOK(m2.getCollection("test.foo").insert({ m2 : 98 }));
    var fourthOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    // No-op delete
    assert.writeOK(m1.getCollection("test.foo").remove({ m1 : 1 }));
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.eq(noOp, fourthOp);

    
    // Dummy write, for a new lastOp.
    assert.writeOK(m1.getCollection("test.foo").insert({ m1 : 99 }));
    var fifthOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.writeOK(m2.getCollection("test.foo").insert({ m2 : 97 }));
    var sixthOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    // No-op find-and-modify delete
    m1.getCollection("test.foo").findAndModify( { query: { m1 : 1 } , remove: 'true'} );
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.eq(noOp, sixthOp);

    assert.commandWorked(m1.getCollection("test.foo").createIndex({x:1}));
    var seventhOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.writeOK(m2.getCollection("test.foo").insert({ m2 : 96 }));
    var eighthOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    // No-op create index.
    assert.commandWorked(m1.getCollection("test.foo").createIndex({x:1}));
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.eq(noOp, eighthOp);

    assert.writeOK(m1.getCollection("test.foo").insert({ _id : 1, x : 1 }));
    var ninthOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.writeOK(m2.getCollection("test.foo").insert({ m2 : 991 }));
    var tenthOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    // update with immutable field error
    assert.writeError(m1.getCollection("test.foo").update({ _id : 1, x : 1 },
                                                          { $set: { _id : 2 }}));
    // "After applying the update to the document {_id: 1.0 , ...}, the (immutable) field '_id'
    // was found to have been altered to _id: 2.0"
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.eq(noOp, tenthOp);

    assert.writeOK(m2.getCollection("test.foo").insert({ m2 : 992 }));
    var eleventhOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    // find-and-modify immutable field error
    try {
        m1.getCollection("test.foo").findAndModify( { query: { _id : 1, x : 1 },
                                                      update: { $set: { _id : 2 } } } );
        // The findAndModify shell helper should throw.
        assert(false);
    } catch (e) {
        assert.eq(e.code, 66);
    }
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.eq(noOp, eleventhOp);

    var bigString = new Array(3000).toString();
    assert.writeOK(m2.getCollection("test.foo").insert({ m2 : 994, m3: bigString}));

    // createIndex with a >1024 byte field fails.
    var twelfthOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;
    assert.commandFailed(m1.getCollection("test.foo").createIndex({m3:1}));
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.eq(noOp, twelfthOp);

    // No-op insert
    assert.writeOK(m1.getCollection("test.foo").insert({ _id : 5, x : 5 }));
    var thirteenthOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.writeOK(m2.getCollection("test.foo").insert({ m2 : 991 }));
    var fourteenthOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    // Hits DuplicateKey error and fails insert -- no-op
    assert.writeError(m1.getCollection("test.foo").insert({ _id : 5, x : 5 }));
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    assert.eq(noOp, fourteenthOp);

    // Test update and delete failures in legacy write mode.
    m2.forceWriteMode('legacy');
    m1.forceWriteMode('legacy');
    m2.getCollection("test.foo").insert({ m2 : 995 });
    var fifthteenthOp = m2.getCollection("test.foo").getDB().getLastErrorObj().lastOp;

    m1.getCollection("test.foo").remove({ m1 : 1 });
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;
    assert.eq(noOp, fifthteenthOp);

    m1.getCollection("test.foo").update({ m1 : 1 }, {$set: {m1: 4}});
    noOp = m1.getCollection("test.foo").getDB().getLastErrorObj().lastOp;
    assert.eq(noOp, fifthteenthOp);

})();