@@ -4,11 +4,11 @@ import { Readable } from 'stream';
4
4
import { clearTimeout , setTimeout as setTimeoutCb } from 'timers' ;
5
5
import { setInterval } from 'timers/promises' ;
6
6
7
- import { type Collection , type Document , type MongoClient , ObjectId } from '../mongodb' ;
7
+ import { type Collection , type Document , isSuperset , type MongoClient , ObjectId } from '../mongodb' ;
8
8
9
9
class TimeoutController extends AbortController {
10
10
timeoutId : NodeJS . Timeout ;
11
- constructor ( private timeoutMS : number ) {
11
+ constructor ( timeoutMS : number ) {
12
12
super ( ) ;
13
13
14
14
this . timeoutId = setTimeoutCb ( ( ) => {
@@ -39,20 +39,24 @@ describe('Index Management Prose Tests', function () {
39
39
let collection : Collection ;
40
40
41
41
/**
42
- * waits until the search indexes for `collection` satisfy `predicate`, optionally pre-filtering
42
+ * waits until the search indexes for `collection` satisfy `predicate`.
43
+ *
44
+ * This optionally pre-filtering
43
45
* for indexes with name = `indexName`
44
46
*/
45
47
function waitForIndexes ( {
46
48
predicate,
47
- indexName
49
+ indexNames
48
50
} : {
49
51
predicate : ( arg0 : Array < Document > ) => boolean ;
50
- indexName ? : string ;
52
+ indexNames : string | string [ ] ;
51
53
} ) : Promise < Array < Document > > {
54
+ const names = new Set ( [ indexNames ] . flat ( ) ) ;
52
55
return Readable . from (
53
56
setInterval ( 5000 , undefined , { signal : timeoutController . signal , ref : false } )
54
57
)
55
- . map ( ( ) => collection . listSearchIndexes ( indexName ) . toArray ( ) )
58
+ . map ( ( ) => collection . listSearchIndexes ( ) . toArray ( ) )
59
+ . map ( ( indexes : Document [ ] ) => indexes . filter ( index => names . has ( index . name ) ) )
56
60
. find ( predicate ) ;
57
61
}
58
62
@@ -71,6 +75,7 @@ describe('Index Management Prose Tests', function () {
71
75
client = this . configuration . newClient ( ) ;
72
76
await client . connect ( ) ;
73
77
78
+ // Create a collection with the "create" command using a randomly generated name (referred to as coll0).
74
79
collection = await client . db ( 'node-test' ) . createCollection ( new ObjectId ( ) . toHexString ( ) ) ;
75
80
76
81
timeoutController = new TimeoutController ( 60 * 1000 * 4 ) ;
@@ -86,20 +91,31 @@ describe('Index Management Prose Tests', function () {
86
91
'Case 1: Driver can successfully create and list search indexes' ,
87
92
metadata ,
88
93
async function ( ) {
94
+ // Create a new search index on coll0 with the createSearchIndex helper. Use the following definition:
95
+ // {
96
+ // name: 'test-search-index',
97
+ // definition: {
98
+ // mappings: { dynamic: false }
99
+ // }
100
+ // }
89
101
const name = await collection . createSearchIndex ( {
90
102
name : 'test-search-index' ,
91
103
definition : {
92
104
mappings : { dynamic : false }
93
105
}
94
106
} ) ;
95
107
108
+ // Assert that the command returns the name of the index: "test-search-index".
96
109
expect ( name ) . to . equal ( 'test-search-index' ) ;
97
110
111
+ // Run coll0.listSearchIndexes() repeatedly every 5 seconds until the following condition is satisfied and store the value in a variable index:
112
+ // 1. An index with the name of test-search-index is present and the index has a field queryable with a value of true.
98
113
const [ index ] = await waitForIndexes ( {
99
114
predicate : indexes => indexes . every ( index => index . queryable ) ,
100
- indexName : 'test-search-index'
115
+ indexNames : 'test-search-index'
101
116
} ) ;
102
117
118
+ // Assert that index has a property latestDefinition whose value is { 'mappings': { 'dynamic': false } }
103
119
expect ( index ) . to . exist ;
104
120
expect ( index )
105
121
. to . have . property ( 'latestDefinition' )
@@ -111,6 +127,19 @@ describe('Index Management Prose Tests', function () {
111
127
'Case 2: Driver can successfully create multiple indexes in batch' ,
112
128
metadata ,
113
129
async function ( ) {
130
+ // Create two new search indexes on coll0 with the createSearchIndexes helper. Use the following definitions when creating the indexes. These definitions are referred to as indexDefinitions.
131
+ // {
132
+ // name: 'test-search-index-1',
133
+ // definition: {
134
+ // mappings: { dynamic: false }
135
+ // }
136
+ // }
137
+ // {
138
+ // name: 'test-search-index-2',
139
+ // definition: {
140
+ // mappings: { dynamic: false }
141
+ // }
142
+ // }
114
143
const indexDefinitions = [
115
144
{
116
145
name : 'test-search-index-1' ,
@@ -127,72 +156,118 @@ describe('Index Management Prose Tests', function () {
127
156
] ;
128
157
129
158
const names = await collection . createSearchIndexes ( indexDefinitions ) ;
159
+
160
+ // Assert that the command returns an array containing the new indexes' names: ["test-search-index-1", "test-search-index-2"].
130
161
expect ( names ) . to . deep . equal ( [ 'test-search-index-1' , 'test-search-index-2' ] ) ;
131
162
163
+ // Run coll0.listSearchIndexes() repeatedly every 5 seconds until the following condition is satisfied.
164
+ // 1. An index with the name of test-search-index-1 is present and index has a field queryable with the value of true. Store result in index1.
165
+ // 2. An index with the name of test-search-index-2 is present and index has a field queryable with the value of true. Store result in index2.
132
166
const indexes = await waitForIndexes ( {
133
- predicate : indexes => indexes . every ( index => index . queryable )
167
+ predicate : indexes => indexes . every ( index => index . queryable ) ,
168
+ indexNames : [ 'test-search-index-1' , 'test-search-index-2' ]
134
169
} ) ;
135
170
136
- for ( const indexDescription of indexDefinitions ) {
137
- const index = indexes . find ( ( { name } ) => name === indexDescription . name ) ;
138
- expect ( index , `expected ${ indexDescription . name } to exist` ) . to . exist ;
171
+ const index1 = indexes . find ( ( { name } ) => name === 'test-search-index-1' ) ;
172
+ const index2 = indexes . find ( ( { name } ) => name === 'test-search-index-2' ) ;
139
173
140
- expect ( index )
141
- . to . have . property ( 'latestDefinition' )
142
- . to . deep . equal ( { mappings : { dynamic : false } } ) ;
143
- }
174
+ // Assert that index1 and index2 have the property latestDefinition whose value is { "mappings" : { "dynamic" : false } }
175
+ expect ( index1 )
176
+ . to . have . property ( 'latestDefinition' )
177
+ . to . deep . equal ( { mappings : { dynamic : false } } ) ;
178
+ expect ( index2 )
179
+ . to . have . property ( 'latestDefinition' )
180
+ . to . deep . equal ( { mappings : { dynamic : false } } ) ;
144
181
}
145
182
) ;
146
183
147
184
it ( 'Case 3: Driver can successfully drop search indexes' , metadata , async function ( ) {
185
+ // Create a new search index on coll0 with the following definition:
186
+ // {
187
+ // name: 'test-search-index',
188
+ // definition: {
189
+ // mappings: { dynamic: false }
190
+ // }
191
+ // }
148
192
const name = await collection . createSearchIndex ( {
149
193
name : 'test-search-index' ,
150
194
definition : {
151
195
mappings : { dynamic : false }
152
196
}
153
197
} ) ;
154
198
199
+ // Assert that the command returns the name of the index: "test-search-index".
155
200
expect ( name ) . to . equal ( 'test-search-index' ) ;
156
201
202
+ // Run coll0.listSearchIndexes() repeatedly every 5 seconds until the following condition is satisfied:
203
+ // 1. An index with the name of test-search-index is present and index has a field queryable with the value of true.
157
204
await waitForIndexes ( {
158
205
predicate : indexes => indexes . every ( index => index . queryable ) ,
159
- indexName : 'test-search-index'
206
+ indexNames : 'test-search-index'
160
207
} ) ;
161
208
209
+ // Run a dropSearchIndex on coll0, using test-search-index for the name.
162
210
await collection . dropSearchIndex ( 'test-search-index' ) ;
163
211
212
+ // Run coll0.listSearchIndexes() repeatedly every 5 seconds until listSearchIndexes returns an empty array.
213
+ // This test fails if it times out waiting for the deletion to succeed.
164
214
const indexes = await waitForIndexes ( {
165
215
predicate : indexes => indexes . length === 0 ,
166
- indexName : 'test-search-index'
216
+ indexNames : 'test-search-index'
167
217
} ) ;
168
218
169
219
expect ( indexes ) . to . deep . equal ( [ ] ) ;
170
220
} ) ;
171
221
172
222
it ( 'Case 4: Driver can update a search index' , metadata , async function ( ) {
223
+ // Create a new search index on coll0 with the following definition:
224
+ // {
225
+ // name: 'test-search-index',
226
+ // definition: {
227
+ // mappings: { dynamic: false }
228
+ // }
229
+ // }
173
230
const name = await collection . createSearchIndex ( {
174
231
name : 'test-search-index' ,
175
232
definition : {
176
233
mappings : { dynamic : false }
177
234
}
178
235
} ) ;
179
236
237
+ // Assert that the command returns the name of the index: "test-search-index".
180
238
expect ( name ) . to . equal ( 'test-search-index' ) ;
181
239
240
+ // Run coll0.listSearchIndexes() repeatedly every 5 seconds until the following condition is satisfied:
241
+ // 1. An index with the name of test-search-index is present and index has a field queryable with the value of true.
182
242
await waitForIndexes ( {
183
243
predicate : indexes => indexes . every ( index => index . queryable ) ,
184
- indexName : 'test-search-index'
244
+ indexNames : 'test-search-index'
185
245
} ) ;
186
246
247
+ // Run a updateSearchIndex on coll0, using the following definition.
248
+ // {
249
+ // name: 'test-search-index',
250
+ // definition: {
251
+ // mappings: { dynamic: true }
252
+ // }
253
+ // }
187
254
await collection . updateSearchIndex ( 'test-search-index' , { mappings : { dynamic : true } } ) ;
188
255
189
- const [ updatedIndex ] = await waitForIndexes ( {
256
+ // Assert that the command does not error and the server responds with a success.
257
+ // The above command throws on failure.
258
+
259
+ // Run coll0.listSearchIndexes() repeatedly every 5 seconds until the following condition is satisfied:
260
+ // 1. An index with the name of test-search-index is present. This index is referred to as index.
261
+ // 2. The index has a field queryable with a value of true and has a field status with the value of READY.
262
+ const [ index2 ] = await waitForIndexes ( {
190
263
predicate : indexes => indexes . every ( index => index . queryable && index . status === 'READY' ) ,
191
- indexName : 'test-search-index'
264
+ indexNames : 'test-search-index'
192
265
} ) ;
193
266
194
- expect ( updatedIndex ) . to . have . property ( 'name' , 'test-search-index' ) ;
195
- expect ( updatedIndex )
267
+ // Assert that an index is present with the name test-search-index and the definition has a
268
+ // property latestDefinition whose value is { 'mappings': { 'dynamic': true } }.
269
+ expect ( index2 ) . to . have . property ( 'name' , 'test-search-index' ) ;
270
+ expect ( index2 )
196
271
. to . have . property ( 'latestDefinition' )
197
272
. to . deep . equal ( { mappings : { dynamic : true } } ) ;
198
273
} ) ;
@@ -201,8 +276,10 @@ describe('Index Management Prose Tests', function () {
201
276
'Case 5: `dropSearchIndex` suppresses namespace not found errors' ,
202
277
metadata ,
203
278
async function ( ) {
279
+ // Create a driver-side collection object for a randomly generated collection name. Do not create this collection on the server.
204
280
const collection = await client . db ( 'node-test' ) . collection ( new ObjectId ( ) . toHexString ( ) ) ;
205
281
282
+ // Run a dropSearchIndex command and assert that no error is thrown.
206
283
await collection . dropSearchIndex ( 'test-search-index' ) ;
207
284
}
208
285
) ;
0 commit comments