Skip to content

Commit 1902c76

Browse files
authored
CSHARP-4839: Avoid Appending Write/Read Concern in Atlas Search Index Helper Commands (#1349)
1 parent af7c9d1 commit 1902c76

File tree

9 files changed

+758
-234
lines changed

9 files changed

+758
-234
lines changed
Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
# Index Management Tests
2+
3+
______________________________________________________________________
4+
5+
## Test Plan
6+
7+
These prose tests are ported from the legacy enumerate-indexes spec.
8+
9+
### Configurations
10+
11+
- standalone node
12+
- replica set primary node
13+
- replica set secondary node
14+
- mongos node
15+
16+
### Preparation
17+
18+
For each of the configurations:
19+
20+
- Create a (new) database
21+
- Create a collection
22+
- Create a single column index, a compound index, and a unique index
23+
- Insert at least one document containing all the fields that the above indicated indexes act on
24+
25+
### Tests
26+
27+
- Run the driver's method that returns a list of index names, and:
28+
- verify that *all* index names are represented in the result
29+
- verify that there are no duplicate index names
30+
- verify there are no returned indexes that do not exist
31+
- Run the driver's method that returns a list of index information records, and:
32+
- verify all the indexes are represented in the result
33+
- verify the "unique" flags show up for the unique index
34+
- verify there are no duplicates in the returned list
35+
- if the result consists of statically defined index models that include an `ns` field, verify that its value is
36+
accurate
37+
38+
### Search Index Management Helpers
39+
40+
These tests are intended to smoke test the search management helpers end-to-end against a live Atlas cluster.
41+
42+
The search index management commands are asynchronous and mongod/mongos returns before the changes to a clusters' search
43+
indexes have completed. When these prose tests specify "waiting for the changes", drivers should repeatedly poll the
44+
cluster with `listSearchIndexes` until the changes are visible. Each test specifies the condition that is considered
45+
"ready". For example, when creating a new search index, waiting until the inserted index has a status `queryable: true`
46+
indicates that the index was successfully created.
47+
48+
The commands tested in these prose tests take a while to successfully complete. Drivers should raise the timeout for
49+
each test to avoid timeout errors if the test timeout is too low. 5 minutes is a sufficiently large timeout that any
50+
timeout that occurs indicates a real failure, but this value is not required and can be tweaked per-driver.
51+
52+
There is a server-side limitation that prevents multiple search indexes from being created with the same name,
53+
definition and collection name. This limitation does not take into account collection uuid. Because these commands are
54+
asynchronous, any cleanup code that may run after a test (cleaning a database or dropping search indexes) may not have
55+
completed by the next iteration of the test (or the next test run, if running locally). To address this issue, each test
56+
uses a randomly generated collection name. Drivers may generate this collection name however they like, but a suggested
57+
implementation is a hex representation of an ObjectId (`new ObjectId().toHexString()` in Node).
58+
59+
#### Setup
60+
61+
These tests must run against an Atlas cluster with a 7.0+ server.
62+
[Scripts are available](https://github.com/mongodb-labs/drivers-evergreen-tools/tree/master/.evergreen/atlas) in
63+
drivers-evergreen-tools which can setup and teardown Atlas clusters. To ensure that the Atlas cluster is cleaned up
64+
after each CI run, drivers should configure evergreen to run these tests as a part of a task group. Be sure that the
65+
cluster gets torn down!
66+
67+
When working locally on these tests, the same Atlas setup and teardown scripts can be used locally to provision a
68+
cluster for development.
69+
70+
#### Case 1: Driver can successfully create and list search indexes
71+
72+
1. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
73+
74+
2. Create a new search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
75+
76+
```typescript
77+
{
78+
name: 'test-search-index',
79+
definition: {
80+
mappings: { dynamic: false }
81+
}
82+
}
83+
```
84+
85+
3. Assert that the command returns the name of the index: `"test-search-index"`.
86+
87+
4. Run `coll0.listSearchIndexes()` repeatedly every 5 seconds until the following condition is satisfied and store the
88+
value in a variable `index`:
89+
90+
- An index with the `name` of `test-search-index` is present and the index has a field `queryable` with a value of
91+
`true`.
92+
93+
5. Assert that `index` has a property `latestDefinition` whose value is `{ 'mappings': { 'dynamic': false } }`
94+
95+
#### Case 2: Driver can successfully create multiple indexes in batch
96+
97+
1. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
98+
99+
2. Create two new search indexes on `coll0` with the `createSearchIndexes` helper. Use the following definitions when
100+
creating the indexes. These definitions are referred to as `indexDefinitions`.
101+
102+
```typescript
103+
{
104+
name: 'test-search-index-1',
105+
definition: {
106+
mappings: { dynamic: false }
107+
}
108+
}
109+
110+
{
111+
name: 'test-search-index-2',
112+
definition: {
113+
mappings: { dynamic: false }
114+
}
115+
}
116+
```
117+
118+
3. Assert that the command returns an array containing the new indexes' names:
119+
`["test-search-index-1", "test-search-index-2"]`.
120+
121+
4. Run `coll0.listSearchIndexes()` repeatedly every 5 seconds until the following conditions are satisfied.
122+
123+
- An index with the `name` of `test-search-index-1` is present and index has a field `queryable` with the value of
124+
`true`. Store result in `index1`.
125+
- An index with the `name` of `test-search-index-2` is present and index has a field `queryable` with the value of
126+
`true`. Store result in `index2`.
127+
128+
5. Assert that `index1` and `index2` have the property `latestDefinition` whose value is
129+
`{ "mappings" : { "dynamic" : false } }`
130+
131+
#### Case 3: Driver can successfully drop search indexes
132+
133+
1. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
134+
135+
2. Create a new search index on `coll0` with the following definition:
136+
137+
```typescript
138+
{
139+
name: 'test-search-index',
140+
definition: {
141+
mappings: { dynamic: false }
142+
}
143+
}
144+
```
145+
146+
3. Assert that the command returns the name of the index: `"test-search-index"`.
147+
148+
4. Run `coll0.listSearchIndexes()` repeatedly every 5 seconds until the following condition is satisfied:
149+
150+
- An index with the `name` of `test-search-index` is present and index has a field `queryable` with the value of
151+
`true`.
152+
153+
5. Run a `dropSearchIndex` on `coll0`, using `test-search-index` for the name.
154+
155+
6. Run `coll0.listSearchIndexes()` repeatedly every 5 seconds until `listSearchIndexes` returns an empty array.
156+
157+
This test fails if it times out waiting for the deletion to succeed.
158+
159+
#### Case 4: Driver can update a search index
160+
161+
1. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
162+
163+
2. Create a new search index on `coll0` with the following definition:
164+
165+
```typescript
166+
{
167+
name: 'test-search-index',
168+
definition: {
169+
mappings: { dynamic: false }
170+
}
171+
}
172+
```
173+
174+
3. Assert that the command returns the name of the index: `"test-search-index"`.
175+
176+
4. Run `coll0.listSearchIndexes()` repeatedly every 5 seconds until the following condition is satisfied:
177+
178+
- An index with the `name` of `test-search-index` is present and index has a field `queryable` with the value of
179+
`true`.
180+
181+
5. Run a `updateSearchIndex` on `coll0`, using the following definition.
182+
183+
```typescript
184+
{
185+
name: 'test-search-index',
186+
definition: {
187+
mappings: { dynamic: true }
188+
}
189+
}
190+
```
191+
192+
6. Assert that the command does not error and the server responds with a success.
193+
194+
7. Run `coll0.listSearchIndexes()` repeatedly every 5 seconds until the following conditions are satisfied:
195+
196+
- An index with the `name` of `test-search-index` is present. This index is referred to as `index`.
197+
- The index has a field `queryable` with a value of `true` and has a field `status` with the value of `READY`.
198+
199+
8. Assert that an index is present with the name `test-search-index` and the definition has a property
200+
`latestDefinition` whose value is `{ 'mappings': { 'dynamic': true } }`.
201+
202+
#### Case 5: `dropSearchIndex` suppresses namespace not found errors
203+
204+
1. Create a driver-side collection object for a randomly generated collection name. Do not create this collection on the
205+
server.
206+
2. Run a `dropSearchIndex` command and assert that no error is thrown.
207+
208+
#### Case 6: Driver can successfully create and list search indexes with non-default readConcern and writeConcern
209+
210+
1. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
211+
212+
2. Apply a write concern `WriteConcern(w=1)` and a read concern with `ReadConcern(level="majority")` to `coll0`.
213+
214+
3. Create a new search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
215+
216+
```typescript
217+
{
218+
name: 'test-search-index-case6',
219+
definition: {
220+
mappings: { dynamic: false }
221+
}
222+
}
223+
```
224+
225+
4. Assert that the command returns the name of the index: `"test-search-index-case6"`.
226+
227+
5. Run `coll0.listSearchIndexes()` repeatedly every 5 seconds until the following condition is satisfied and store the
228+
value in a variable `index`:
229+
230+
- An index with the `name` of `test-search-index-case6` is present and the index has a field `queryable` with a value
231+
of `true`.
232+
233+
6. Assert that `index` has a property `latestDefinition` whose value is `{ 'mappings': { 'dynamic': false } }`
234+
235+
#### Case 7: Driver can successfully handle search index types when creating indexes
236+
237+
01. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
238+
239+
02. Create a new search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
240+
241+
```typescript
242+
243+
{
244+
name: 'test-search-index-case7-implicit',
245+
definition: {
246+
mappings: { dynamic: false }
247+
}
248+
}
249+
```
250+
251+
03. Assert that the command returns the name of the index: `"test-search-index-case7-implicit"`.
252+
253+
04. Run `coll0.listSearchIndexes('test-search-index-case7-implicit')` repeatedly every 5 seconds until the following
254+
condition is satisfied and store the value in a variable `index1`:
255+
256+
- An index with the `name` of `test-search-index-case7-implicit` is present and the index has a field `queryable`
257+
with a value of `true`.
258+
259+
05. Assert that `index1` has a property `type` whose value is `search`.
260+
261+
06. Create a new search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
262+
263+
```typescript
264+
265+
{
266+
name: 'test-search-index-case7-explicit',
267+
type: 'search',
268+
definition: {
269+
mappings: { dynamic: false }
270+
}
271+
}
272+
```
273+
274+
07. Assert that the command returns the name of the index: `"test-search-index-case7-explicit"`.
275+
276+
08. Run `coll0.listSearchIndexes('test-search-index-case7-explicit')` repeatedly every 5 seconds until the following
277+
condition is satisfied and store the value in a variable `index2`:
278+
279+
- An index with the `name` of `test-search-index-case7-explicit` is present and the index has a field `queryable`
280+
with a value of `true`.
281+
282+
09. Assert that `index2` has a property `type` whose value is `search`.
283+
284+
10. Create a new vector search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
285+
286+
```typescript
287+
288+
{
289+
name: 'test-search-index-case7-vector',
290+
type: 'vectorSearch',
291+
definition: {
292+
fields: [
293+
{
294+
type: 'vector',
295+
path: 'plot_embedding',
296+
numDimensions: 1536,
297+
similarity: 'euclidean',
298+
},
299+
]
300+
}
301+
}
302+
```
303+
304+
11. Assert that the command returns the name of the index: `"test-search-index-case7-vector"`.
305+
306+
12. Run `coll0.listSearchIndexes('test-search-index-case7-vector')` repeatedly every 5 seconds until the following
307+
condition is satisfied and store the value in a variable `index3`:
308+
309+
- An index with the `name` of `test-search-index-case7-vector` is present and the index has a field `queryable` with
310+
a value of `true`.
311+
312+
13. Assert that `index3` has a property `type` whose value is `vectorSearch`.
313+
314+
#### Case 8: Driver requires explicit type to create a vector search index
315+
316+
1. Create a collection with the "create" command using a randomly generated name (referred to as `coll0`).
317+
318+
2. Create a new vector search index on `coll0` with the `createSearchIndex` helper. Use the following definition:
319+
320+
```typescript
321+
322+
{
323+
name: 'test-search-index-case8-error',
324+
definition: {
325+
fields: [
326+
{
327+
type: 'vector',
328+
path: 'plot_embedding',
329+
numDimensions: 1536,
330+
similarity: 'euclidean',
331+
},
332+
]
333+
}
334+
}
335+
```
336+
337+
3. Assert that the command throws an exception containing the string "Attribute mappings missing" due to the `mappings`
338+
field missing.

0 commit comments

Comments
 (0)