@@ -7,6 +7,7 @@ import * as sinon from 'sinon';
77import { type CommandStartedEvent } from '../../../mongodb' ;
88import {
99 type CommandSucceededEvent ,
10+ MongoBulkWriteError ,
1011 MongoClient ,
1112 MongoOperationTimeoutError ,
1213 MongoServerSelectionError ,
@@ -28,7 +29,7 @@ describe('CSOT spec prose tests', function () {
2829 await client ?. close ( ) ;
2930 } ) ;
3031
31- context . skip ( '1. Multi-batch writes' , ( ) => {
32+ describe ( '1. Multi-batch writes' , { requires : { topology : 'single' , mongodb : '>=4.4' } } , ( ) => {
3233 /**
3334 * This test MUST only run against standalones on server versions 4.4 and higher.
3435 * The `insertMany` call takes an exceedingly long time on replicasets and sharded
@@ -55,6 +56,46 @@ describe('CSOT spec prose tests', function () {
5556 * - Expect this to fail with a timeout error.
5657 * 1. Verify that two `insert` commands were executed against `db.coll` as part of the `insertMany` call.
5758 */
59+
60+ const failpoint : FailPoint = {
61+ configureFailPoint : 'failCommand' ,
62+ mode : {
63+ times : 2
64+ } ,
65+ data : {
66+ failCommands : [ 'insert' ] ,
67+ blockConnection : true ,
68+ blockTimeMS : 1010
69+ }
70+ } ;
71+
72+ beforeEach ( async function ( ) {
73+ await internalClient
74+ . db ( 'db' )
75+ . collection ( 'coll' )
76+ . drop ( )
77+ . catch ( ( ) => null ) ;
78+ await internalClient . db ( 'admin' ) . command ( failpoint ) ;
79+
80+ client = this . configuration . newClient ( { timeoutMS : 2000 , monitorCommands : true } ) ;
81+ } ) ;
82+
83+ it ( 'performs two inserts which fail to complete before 2000 ms' , async ( ) => {
84+ const inserts = [ ] ;
85+ client . on ( 'commandStarted' , ev => inserts . push ( ev ) ) ;
86+
87+ const a = new Uint8Array ( 1000000 - 22 ) ;
88+ const oneMBDocs = Array . from ( { length : 50 } , ( _ , _id ) => ( { _id, a } ) ) ;
89+ const error = await client
90+ . db ( 'db' )
91+ . collection < { _id : number ; a : Uint8Array } > ( 'coll' )
92+ . insertMany ( oneMBDocs )
93+ . catch ( error => error ) ;
94+
95+ expect ( error ) . to . be . instanceOf ( MongoBulkWriteError ) ;
96+ expect ( error . errorResponse ) . to . be . instanceOf ( MongoOperationTimeoutError ) ;
97+ expect ( inserts . map ( ev => ev . commandName ) ) . to . deep . equal ( [ 'insert' , 'insert' ] ) ;
98+ } ) ;
5899 } ) ;
59100
60101 context . skip ( '2. maxTimeMS is not set for commands sent to mongocryptd' , ( ) => {
@@ -901,4 +942,103 @@ describe('CSOT spec prose tests', function () {
901942 } ) ;
902943 } ) ;
903944 } ) ;
945+
946+ describe . skip (
947+ '11. Multi-batch bulkWrites' ,
948+ { requires : { mongodb : '>=8.0' , serverless : 'forbid' } } ,
949+ function ( ) {
950+ /**
951+ * ### 11. Multi-batch bulkWrites
952+ *
953+ * This test MUST only run against server versions 8.0+. This test must be skipped on Atlas Serverless.
954+ *
955+ * 1. Using `internalClient`, drop the `db.coll` collection.
956+ *
957+ * 2. Using `internalClient`, set the following fail point:
958+ *
959+ * @example
960+ * ```javascript
961+ * {
962+ * configureFailPoint: "failCommand",
963+ * mode: {
964+ * times: 2
965+ * },
966+ * data: {
967+ * failCommands: ["bulkWrite"],
968+ * blockConnection: true,
969+ * blockTimeMS: 1010
970+ * }
971+ * }
972+ * ```
973+ *
974+ * 3. Using `internalClient`, perform a `hello` command and record the `maxBsonObjectSize` and `maxMessageSizeBytes` values
975+ * in the response.
976+ *
977+ * 4. Create a new MongoClient (referred to as `client`) with `timeoutMS=2000`.
978+ *
979+ * 5. Create a list of write models (referred to as `models`) with the following write model repeated
980+ * (`maxMessageSizeBytes / maxBsonObjectSize + 1`) times:
981+ *
982+ * @example
983+ * ```json
984+ * InsertOne {
985+ * "namespace": "db.coll",
986+ * "document": { "a": "b".repeat(maxBsonObjectSize - 500) }
987+ * }
988+ * ```
989+ *
990+ * 6. Call `bulkWrite` on `client` with `models`.
991+ *
992+ * - Expect this to fail with a timeout error.
993+ *
994+ * 7. Verify that two `bulkWrite` commands were executed as part of the `MongoClient.bulkWrite` call.
995+ */
996+ const failpoint : FailPoint = {
997+ configureFailPoint : 'failCommand' ,
998+ mode : {
999+ times : 2
1000+ } ,
1001+ data : {
1002+ failCommands : [ 'bulkWrite' ] ,
1003+ blockConnection : true ,
1004+ blockTimeMS : 1010
1005+ }
1006+ } ;
1007+
1008+ let maxBsonObjectSize : number ;
1009+ let maxMessageSizeBytes : number ;
1010+
1011+ beforeEach ( async function ( ) {
1012+ await internalClient
1013+ . db ( 'db' )
1014+ . collection ( 'coll' )
1015+ . drop ( )
1016+ . catch ( ( ) => null ) ;
1017+ await internalClient . db ( 'admin' ) . command ( failpoint ) ;
1018+
1019+ const hello = await internalClient . db ( 'admin' ) . command ( { hello : 1 } ) ;
1020+ maxBsonObjectSize = hello . maxBsonObjectSize ;
1021+ maxMessageSizeBytes = hello . maxMessageSizeBytes ;
1022+
1023+ client = this . configuration . newClient ( { timeoutMS : 2000 , monitorCommands : true } ) ;
1024+ } ) ;
1025+
1026+ it . skip ( 'performs two bulkWrites which fail to complete before 2000 ms' , async function ( ) {
1027+ const writes = [ ] ;
1028+ client . on ( 'commandStarted' , ev => writes . push ( ev ) ) ;
1029+
1030+ const length = maxMessageSizeBytes / maxBsonObjectSize + 1 ;
1031+ const models = Array . from ( { length } , ( ) => ( {
1032+ namespace : 'db.coll' ,
1033+ name : 'insertOne' as const ,
1034+ document : { a : 'b' . repeat ( maxBsonObjectSize - 500 ) }
1035+ } ) ) ;
1036+
1037+ const error = await client . bulkWrite ( models ) . catch ( error => error ) ;
1038+
1039+ expect ( error , error . stack ) . to . be . instanceOf ( MongoOperationTimeoutError ) ;
1040+ expect ( writes . map ( ev => ev . commandName ) ) . to . deep . equal ( [ 'bulkWrite' , 'bulkWrite' ] ) ;
1041+ } ) . skipReason = 'TODO(NODE-6403): client.bulkWrite is implemented in a follow up' ;
1042+ }
1043+ ) ;
9041044} ) ;
0 commit comments