11import { expect } from 'chai' ;
22import { on , once } from 'events' ;
3+ import { gte } from 'semver' ;
4+ import * as sinon from 'sinon' ;
35
46import {
57 type Collection ,
68 type CommandStartedEvent ,
9+ type CommandSucceededEvent ,
710 type Db ,
811 LEGACY_HELLO_COMMAND ,
9- MongoClient
12+ MongoClient ,
13+ OpMsgRequest
1014} from '../../mongodb' ;
1115import * as mock from '../../tools/mongodb-mock/index' ;
1216import { filterForCommands } from '../shared' ;
1317
14- describe . only ( 'Write Concern' , function ( ) {
18+ describe ( 'Write Concern' , function ( ) {
1519 context ( 'when the WriteConcern is set in the uri' , function ( ) {
1620 let client ;
1721 const events : CommandStartedEvent [ ] = [ ] ;
@@ -29,8 +33,7 @@ describe.only('Write Concern', function () {
2933 expect ( events [ 0 ] ) . to . containSubset ( {
3034 commandName : 'insert' ,
3135 command : {
32- writeConcern : { w : 0 } ,
33- moreToCome : true
36+ writeConcern : { w : 0 }
3437 }
3538 } ) ;
3639 } ) ;
@@ -169,4 +172,136 @@ describe.only('Write Concern', function () {
169172 } ) ;
170173 } ) ;
171174 } ) ;
175+
176+ describe ( 'fire-and-forget protocol' , function ( ) {
177+ context ( 'when writeConcern = 0 and OP_MSG is used' , function ( ) {
178+ const writeOperations : { name : string ; command : any ; expectedReturnVal : any } [ ] = [
179+ {
180+ name : 'insertOne' ,
181+ command : client => client . db ( 'test' ) . collection ( 'test' ) . insertOne ( { a : 1 } ) ,
182+ expectedReturnVal : { acknowledged : false }
183+ } ,
184+ {
185+ name : 'insertMany' ,
186+ command : client =>
187+ client
188+ . db ( 'test' )
189+ . collection ( 'test' )
190+ . insertMany ( [ { a : 1 } , { b : 2 } ] ) ,
191+ expectedReturnVal : { acknowledged : false }
192+ } ,
193+ {
194+ name : 'updateOne' ,
195+ command : client =>
196+ client
197+ . db ( 'test' )
198+ . collection ( 'test' )
199+ . updateOne ( { i : 128 } , { $set : { c : 2 } } ) ,
200+ expectedReturnVal : { acknowledged : false }
201+ } ,
202+ {
203+ name : 'updateMany' ,
204+ command : client =>
205+ client
206+ . db ( 'test' )
207+ . collection ( 'test' )
208+ . updateMany ( { name : 'foobar' } , { $set : { name : 'fizzbuzz' } } ) ,
209+ expectedReturnVal : { acknowledged : false }
210+ } ,
211+ {
212+ name : 'deleteOne' ,
213+ command : client => client . db ( 'test' ) . collection ( 'test' ) . deleteOne ( { a : 1 } ) ,
214+ expectedReturnVal : { acknowledged : false }
215+ } ,
216+ {
217+ name : 'deleteMany' ,
218+ command : client => client . db ( 'test' ) . collection ( 'test' ) . deleteMany ( { name : 'foobar' } ) ,
219+ expectedReturnVal : { acknowledged : false }
220+ } ,
221+ {
222+ name : 'replaceOne' ,
223+ command : client => client . db ( 'test' ) . collection ( 'test' ) . replaceOne ( { a : 1 } , { b : 2 } ) ,
224+ expectedReturnVal : { acknowledged : false }
225+ } ,
226+ {
227+ name : 'removeUser' ,
228+ command : client => client . db ( 'test' ) . removeUser ( 'albert' ) ,
229+ expectedReturnVal : true
230+ } ,
231+ {
232+ name : 'findAndModify' ,
233+ command : client =>
234+ client
235+ . db ( 'test' )
236+ . collection ( 'test' )
237+ . findOneAndUpdate ( { } , { $setOnInsert : { a : 1 } } , { upsert : true } ) ,
238+ expectedReturnVal : null
239+ } ,
240+ {
241+ name : 'dropDatabase' ,
242+ command : client => client . db ( 'test' ) . dropDatabase ( ) ,
243+ expectedReturnVal : true
244+ } ,
245+ {
246+ name : 'dropCollection' ,
247+ command : client => client . db ( 'test' ) . dropCollection ( 'test' ) ,
248+ expectedReturnVal : true
249+ } ,
250+ {
251+ name : 'dropIndexes' ,
252+ command : client => client . db ( 'test' ) . collection ( 'test' ) . dropIndex ( 'a' ) ,
253+ expectedReturnVal : { ok : 1 }
254+ } ,
255+ {
256+ name : 'createIndexes' ,
257+ command : client => client . db ( 'test' ) . collection ( 'test' ) . createIndex ( { a : 1 } ) ,
258+ expectedReturnVal : 'a_1'
259+ } ,
260+ {
261+ name : 'createCollection' ,
262+ command : client => client . db ( 'test' ) . createCollection ( 'test' ) ,
263+ expectedReturnVal : { }
264+ }
265+ ] ;
266+
267+ for ( const op of writeOperations ) {
268+ context ( `when the write operation ${ op . name } is run` , function ( ) {
269+ let client ;
270+ let spy ;
271+
272+ beforeEach ( async function ( ) {
273+ if ( gte ( '3.6.0' , this . configuration . version ) ) {
274+ this . currentTest . skipReason = 'Test requires OP_MSG, needs to be on MongoDB 3.6+' ;
275+ this . skip ( ) ;
276+ }
277+ spy = sinon . spy ( OpMsgRequest . prototype , 'toBin' ) ;
278+ client = this . configuration . newClient ( { monitorCommands : true , w : 0 } ) ;
279+ await client . connect ( ) ;
280+ } ) ;
281+
282+ afterEach ( function ( ) {
283+ sinon . restore ( ) ;
284+ client . close ( ) ;
285+ } ) ;
286+
287+ it ( 'the request should have moreToCome bit set' , async function ( ) {
288+ await op . command ( client ) ;
289+ expect ( spy . returnValues [ spy . returnValues . length - 1 ] [ 0 ] [ 16 ] ) . to . equal ( 2 ) ;
290+ } ) ;
291+
292+ it ( 'the return value of the command should be nullish' , async function ( ) {
293+ const result = await op . command ( client ) ;
294+ expect ( result ) . to . containSubset ( op . expectedReturnVal ) ;
295+ } ) ;
296+
297+ it ( 'commandSucceededEvent should have reply with only {ok: 1}' , async function ( ) {
298+ const events : CommandSucceededEvent [ ] = [ ] ;
299+ client . on ( 'commandSucceeded' , event => events . push ( event ) ) ;
300+ await op . command ( client ) ;
301+ expect ( events [ 0 ] ) . to . containSubset ( { reply : { ok : 1 } } ) ;
302+ } ) ;
303+ } ) ;
304+ }
305+ } ) ;
306+ } ) ;
172307} ) ;
0 commit comments