11
11
// // that it executed properly. Accepts the result of
12
12
// // the noop request to validate it.
13
13
// }
14
- function getNoopWriteCommands ( coll ) {
14
+ function getNoopWriteCommands ( coll , setupType ) {
15
15
const db = coll . getDB ( ) ;
16
16
const collName = coll . getName ( ) ;
17
17
const commands = [ ] ;
18
18
19
+ assert ( setupType === "rs" || setupType === "sharding" ,
20
+ `invalid setupType '${ setupType } ' used for tests` ) ;
21
+
19
22
// 'applyOps' where the update has already been done.
20
23
commands . push ( {
21
24
req : { applyOps : [ { op : "u" , ns : coll . getFullName ( ) , o : { _id : 1 } , o2 : { _id : 1 } } ] } ,
22
- setupFunc : function ( ) {
25
+ setupFunc : ( ) => {
23
26
assert . commandWorked ( coll . insert ( { _id : 1 } ) ) ;
24
27
} ,
25
- confirmFunc : function ( res ) {
28
+ confirmFunc : ( res ) => {
26
29
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
27
30
assert . eq ( res . applied , 1 ) ;
28
31
assert . eq ( res . results [ 0 ] , true ) ;
29
32
assert . eq ( coll . find ( ) . itcount ( ) , 1 ) ;
30
33
assert . eq ( coll . count ( { _id : 1 } ) , 1 ) ;
31
- }
34
+ } ,
32
35
} ) ;
33
36
34
37
// 'update' where the document to update does not exist.
35
38
commands . push ( {
36
39
req : { update : collName , updates : [ { q : { a : 1 } , u : { b : 2 } } ] } ,
37
- setupFunc : function ( ) {
40
+ setupFunc : ( ) => {
38
41
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
39
42
assert . commandWorked ( coll . update ( { a : 1 } , { b : 2 } ) ) ;
40
43
} ,
41
- confirmFunc : function ( res ) {
44
+ confirmFunc : ( res ) => {
42
45
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
43
46
assert . eq ( res . n , 0 ) ;
44
47
assert . eq ( res . nModified , 0 ) ;
45
48
assert . eq ( coll . find ( ) . itcount ( ) , 1 ) ;
46
49
assert . eq ( coll . count ( { b : 2 } ) , 1 ) ;
47
- }
50
+ } ,
48
51
} ) ;
49
52
50
53
// 'update' where the update has already been done.
51
54
commands . push ( {
55
+ checkWriteConcern : ( res ) => {
56
+ assertWriteConcernError ( res ) ;
57
+ } ,
52
58
req : { update : collName , updates : [ { q : { a : 1 } , u : { $set : { b : 2 } } } ] } ,
53
- setupFunc : function ( ) {
59
+ setupFunc : ( ) => {
54
60
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
55
61
assert . commandWorked ( coll . update ( { a : 1 } , { $set : { b : 2 } } ) ) ;
56
62
} ,
57
- confirmFunc : function ( res ) {
63
+ confirmFunc : ( res ) => {
58
64
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
59
65
assert . eq ( res . n , 1 ) ;
60
66
assert . eq ( res . nModified , 0 ) ;
61
67
assert . eq ( coll . find ( ) . itcount ( ) , 1 ) ;
62
68
assert . eq ( coll . count ( { a : 1 , b : 2 } ) , 1 ) ;
63
- }
69
+ } ,
64
70
} ) ;
65
71
66
72
// 'update' with immutable field error.
67
73
commands . push ( {
74
+ checkWriteConcern : ( res ) => {
75
+ assertWriteConcernError ( res ) ;
76
+ } ,
68
77
req : { update : collName , updates : [ { q : { _id : 1 } , u : { $set : { _id : 2 } } } ] } ,
69
- setupFunc : function ( ) {
78
+ setupFunc : ( ) => {
70
79
assert . commandWorked ( coll . insert ( { _id : 1 } ) ) ;
71
80
} ,
72
- confirmFunc : function ( res ) {
81
+ confirmFunc : ( res ) => {
73
82
assert . eq ( res . n , 0 ) ;
74
83
assert . eq ( res . nModified , 0 ) ;
75
84
assert . eq ( coll . count ( { _id : 1 } ) , 1 ) ;
76
- }
85
+ } ,
77
86
} ) ;
78
87
79
88
// 'delete' where the document to delete does not exist.
80
89
commands . push ( {
81
90
req : { delete : collName , deletes : [ { q : { a : 1 } , limit : 1 } ] } ,
82
- setupFunc : function ( ) {
91
+ setupFunc : ( ) => {
83
92
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
84
93
assert . commandWorked ( coll . remove ( { a : 1 } ) ) ;
85
94
} ,
86
- confirmFunc : function ( res ) {
95
+ confirmFunc : ( res ) => {
87
96
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
88
97
assert . eq ( res . n , 0 ) ;
89
98
assert . eq ( coll . count ( { a : 1 } ) , 0 ) ;
90
- }
99
+ } ,
91
100
} ) ;
92
101
93
102
// 'createIndexes' where the index has already been created.
@@ -100,15 +109,15 @@ function getNoopWriteCommands(coll) {
100
109
indexes : [ { key : { a : 1 } , name : "a_1" } ] ,
101
110
commitQuorum : "majority"
102
111
} ,
103
- setupFunc : function ( ) {
112
+ setupFunc : ( ) => {
104
113
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
105
114
assert . commandWorkedIgnoringWriteConcernErrors ( db . runCommand ( {
106
115
createIndexes : collName ,
107
116
indexes : [ { key : { a : 1 } , name : "a_1" } ] ,
108
117
commitQuorum : "majority"
109
118
} ) ) ;
110
119
} ,
111
- confirmFunc : function ( res ) {
120
+ confirmFunc : ( res ) => {
112
121
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
113
122
let details = res ;
114
123
if ( "raw" in details ) {
@@ -117,95 +126,135 @@ function getNoopWriteCommands(coll) {
117
126
}
118
127
assert . eq ( details . numIndexesBefore , details . numIndexesAfter ) ;
119
128
assert . eq ( details . note , 'all indexes already exist' ) ;
120
- }
129
+ } ,
121
130
} ) ;
122
131
123
132
// 'findAndModify' where the document to update does not exist.
124
133
commands . push ( {
125
134
req : { findAndModify : collName , query : { a : 1 } , update : { b : 2 } } ,
126
- setupFunc : function ( ) {
135
+ setupFunc : ( ) => {
127
136
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
128
137
assert . commandWorkedIgnoringWriteConcernErrors (
129
138
db . runCommand ( { findAndModify : collName , query : { a : 1 } , update : { b : 2 } } ) ) ;
130
139
} ,
131
- confirmFunc : function ( res ) {
140
+ confirmFunc : ( res ) => {
132
141
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
133
142
assert . eq ( res . lastErrorObject . updatedExisting , false ) ;
134
143
assert . eq ( coll . find ( ) . itcount ( ) , 1 ) ;
135
144
assert . eq ( coll . count ( { b : 2 } ) , 1 ) ;
136
- }
145
+ } ,
137
146
} ) ;
138
147
139
148
// 'findAndModify' where the update has already been done.
140
149
commands . push ( {
141
150
req : { findAndModify : collName , query : { a : 1 } , update : { $set : { b : 2 } } } ,
142
- setupFunc : function ( ) {
151
+ setupFunc : ( ) => {
143
152
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
144
153
assert . commandWorkedIgnoringWriteConcernErrors (
145
154
db . runCommand ( { findAndModify : collName , query : { a : 1 } , update : { $set : { b : 2 } } } ) ) ;
146
155
} ,
147
- confirmFunc : function ( res ) {
156
+ confirmFunc : ( res ) => {
148
157
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
149
158
assert . eq ( res . lastErrorObject . updatedExisting , true ) ;
150
159
assert . eq ( coll . find ( ) . itcount ( ) , 1 ) ;
151
160
assert . eq ( coll . count ( { a : 1 , b : 2 } ) , 1 ) ;
152
- }
161
+ } ,
153
162
} ) ;
154
163
164
+ // 'findAndModify' causing a unique index key violation. Only works in a replica set.
165
+ if ( setupType === "rs" ) {
166
+ commands . push ( {
167
+ req : { findAndModify : collName , query : { value : { $lt : 3 } } , update : { $set : { value : 3 } } } ,
168
+ setupFunc : ( shell ) => {
169
+ coll . createIndex ( { value : 1 } , { unique : true } ) ;
170
+ assert . commandWorked ( coll . insert ( { value : 1 } ) ) ;
171
+ assert . commandWorked ( coll . insert ( { value : 2 } ) ) ;
172
+ assert . commandWorked ( coll . insert ( { value : 3 } ) ) ;
173
+ } ,
174
+ confirmFunc : ( res ) => {
175
+ assert . commandFailedWithCode ( res , ErrorCodes . DuplicateKey ) ;
176
+ assert . eq ( coll . count ( { value : 1 } ) , 1 ) ;
177
+ assert . eq ( coll . count ( { value : 2 } ) , 1 ) ;
178
+ assert . eq ( coll . count ( { value : 3 } ) , 1 ) ;
179
+ } ,
180
+ } ) ;
181
+ }
182
+
183
+ // 'findAndModify' causing a unique index key violation. Only works in a sharded cluster.
184
+ if ( setupType === "sharding" ) {
185
+ commands . push ( {
186
+ req : { findAndModify : collName , query : { value : { $lt : 3 } } , update : { $set : { value : 3 } } } ,
187
+ setupFunc : ( shell ) => {
188
+ coll . createIndex ( { value : 1 } , { unique : true } ) ;
189
+ assert . commandWorked (
190
+ shell . adminCommand ( { shardCollection : coll . getFullName ( ) , key : { value : 1 } } ) ) ;
191
+ assert . commandWorked ( coll . insert ( { value : 1 } ) ) ;
192
+ assert . commandWorked ( coll . insert ( { value : 2 } ) ) ;
193
+ assert . commandWorked ( coll . insert ( { value : 3 } ) ) ;
194
+ } ,
195
+ confirmFunc : ( res ) => {
196
+ assert . commandFailedWithCode ( res , 31025 ) ;
197
+ assert . eq ( coll . count ( { value : 1 } ) , 1 ) ;
198
+ assert . eq ( coll . count ( { value : 2 } ) , 1 ) ;
199
+ assert . eq ( coll . count ( { value : 3 } ) , 1 ) ;
200
+ } ,
201
+ } ) ;
202
+ }
203
+
155
204
// 'findAndModify' with immutable field error.
156
205
commands . push ( {
157
206
req : { findAndModify : collName , query : { _id : 1 } , update : { $set : { _id : 2 } } } ,
158
- setupFunc : function ( ) {
207
+ setupFunc : ( ) => {
159
208
assert . commandWorked ( coll . insert ( { _id : 1 } ) ) ;
160
209
} ,
161
- confirmFunc : function ( res ) {
210
+ confirmFunc : ( res ) => {
162
211
assert . commandFailedWithCode ( res , ErrorCodes . ImmutableField ) ;
163
212
assert . eq ( coll . find ( ) . itcount ( ) , 1 ) ;
164
213
assert . eq ( coll . count ( { _id : 1 } ) , 1 ) ;
165
- }
214
+ } ,
166
215
} ) ;
167
216
168
217
// 'findAndModify' where the document to delete does not exist.
169
218
commands . push ( {
170
219
req : { findAndModify : collName , query : { a : 1 } , remove : true } ,
171
- setupFunc : function ( ) {
220
+ setupFunc : ( ) => {
172
221
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
173
222
assert . commandWorked ( coll . remove ( { a : 1 } ) ) ;
174
223
} ,
175
- confirmFunc : function ( res ) {
224
+ confirmFunc : ( res ) => {
176
225
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
177
226
assert . eq ( res . lastErrorObject . n , 0 ) ;
178
- }
227
+ } ,
179
228
} ) ;
180
229
181
230
// 'dropDatabase' where the database has already been dropped.
182
231
commands . push ( {
183
232
req : { dropDatabase : 1 } ,
184
- setupFunc : function ( ) {
233
+ setupFunc : ( ) => {
185
234
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
186
235
assert . commandWorkedIgnoringWriteConcernErrors ( db . runCommand ( { dropDatabase : 1 } ) ) ;
187
236
} ,
188
- confirmFunc : function ( res ) {
237
+ confirmFunc : ( res ) => {
189
238
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
190
- }
239
+ } ,
191
240
} ) ;
192
241
193
242
// 'drop' where the collection has already been dropped.
194
243
commands . push ( {
195
244
req : { drop : collName } ,
196
- setupFunc : function ( ) {
245
+ setupFunc : ( ) => {
197
246
assert . commandWorked ( coll . insert ( { a : 1 } ) ) ;
198
247
assert . commandWorkedIgnoringWriteConcernErrors ( db . runCommand ( { drop : collName } ) ) ;
199
248
} ,
200
- confirmFunc : function ( res ) {
249
+ confirmFunc : ( res ) => {
201
250
assert . commandWorkedIgnoringWriteConcernErrors ( res ) ;
202
- }
251
+ } ,
203
252
} ) ;
204
253
205
254
// 'create' where the collection has already been created.
206
255
commands . push ( {
207
256
req : { create : collName } ,
208
- setupFunc : function ( ) {
257
+ setupFunc : ( ) => {
209
258
assert . commandWorkedIgnoringWriteConcernErrors ( db . runCommand ( { create : collName } ) ) ;
210
259
} ,
211
260
confirmFunc : function ( res ) {
@@ -223,15 +272,55 @@ function getNoopWriteCommands(coll) {
223
272
// 'insert' where the document with the same _id has already been inserted.
224
273
commands . push ( {
225
274
req : { insert : collName , documents : [ { _id : 1 } ] } ,
226
- setupFunc : function ( ) {
275
+ setupFunc : ( ) => {
227
276
assert . commandWorked ( coll . insert ( { _id : 1 } ) ) ;
228
277
} ,
229
- confirmFunc : function ( res ) {
278
+ confirmFunc : ( res ) => {
230
279
assert . commandWorkedIgnoringWriteErrorsAndWriteConcernErrors ( res ) ;
231
280
assert . eq ( res . n , 0 ) ;
232
281
assert . eq ( res . writeErrors [ 0 ] . code , ErrorCodes . DuplicateKey ) ;
233
282
assert . eq ( coll . count ( { _id : 1 } ) , 1 ) ;
234
- }
283
+ } ,
284
+ } ) ;
285
+
286
+ commands . forEach ( ( cmd ) => {
287
+ // Validate that all commands have proper definitions.
288
+ [ 'req' , 'setupFunc' , 'confirmFunc' ] . forEach ( ( field ) => {
289
+ assert ( cmd . hasOwnProperty ( field ) ,
290
+ `command does not have required field '${ field } ': ${ tojson ( cmd ) } ` ) ;
291
+ } ) ;
292
+
293
+ // Attach a 'run' function to each command for the actual test execution.
294
+ let self = cmd ;
295
+ cmd . run = ( dbName , coll , shell ) => {
296
+ // Drop test collection.
297
+ coll . drop ( ) ;
298
+ assert . eq ( 0 , coll . find ( ) . itcount ( ) , "test collection not empty" ) ;
299
+
300
+ jsTest . log ( "Testing command: " + tojson ( self . req ) ) ;
301
+
302
+ // Create environment for command to run in.
303
+ self . setupFunc ( shell ) ;
304
+
305
+ // Provide a small wtimeout that we expect to time out.
306
+ self . req . writeConcern = { w : 3 , wtimeout : 1000 } ;
307
+
308
+ // We check the error code of 'res' in the 'confirmFunc'.
309
+ const res = "bulkWrite" in self . req ? shell . adminCommand ( self . req )
310
+ : shell . getDB ( dbName ) . runCommand ( self . req ) ;
311
+
312
+ try {
313
+ // Tests that the command receives a write concern error. If we don't wait for write
314
+ // concern on noop writes then we won't get a write concern error.
315
+ assertWriteConcernError ( res ) ;
316
+ // Validate post-conditions of the commands.
317
+ self . confirmFunc ( res ) ;
318
+ } catch ( e ) {
319
+ // Make sure that we print out the response.
320
+ printjson ( res ) ;
321
+ throw e ;
322
+ }
323
+ } ;
235
324
} ) ;
236
325
237
326
return commands ;
0 commit comments