@@ -7,6 +7,7 @@ import * as sinon from 'sinon';
7
7
import { type CommandStartedEvent } from '../../../mongodb' ;
8
8
import {
9
9
type CommandSucceededEvent ,
10
+ MongoBulkWriteError ,
10
11
MongoClient ,
11
12
MongoOperationTimeoutError ,
12
13
MongoServerSelectionError ,
@@ -28,7 +29,7 @@ describe('CSOT spec prose tests', function () {
28
29
await client ?. close ( ) ;
29
30
} ) ;
30
31
31
- context . skip ( '1. Multi-batch writes' , ( ) => {
32
+ describe ( '1. Multi-batch writes' , { requires : { topology : 'single' , mongodb : '>=4.4' } } , ( ) => {
32
33
/**
33
34
* This test MUST only run against standalones on server versions 4.4 and higher.
34
35
* The `insertMany` call takes an exceedingly long time on replicasets and sharded
@@ -55,6 +56,46 @@ describe('CSOT spec prose tests', function () {
55
56
* - Expect this to fail with a timeout error.
56
57
* 1. Verify that two `insert` commands were executed against `db.coll` as part of the `insertMany` call.
57
58
*/
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
+ } ) ;
58
99
} ) ;
59
100
60
101
context . skip ( '2. maxTimeMS is not set for commands sent to mongocryptd' , ( ) => {
@@ -901,4 +942,103 @@ describe('CSOT spec prose tests', function () {
901
942
} ) ;
902
943
} ) ;
903
944
} ) ;
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
+ ) ;
904
1044
} ) ;
0 commit comments