1
2
3
4
5
6
7 package integration
8
9 import (
10 "context"
11 "errors"
12 "fmt"
13 "reflect"
14 "testing"
15
16 "go.mongodb.org/mongo-driver/bson"
17 "go.mongodb.org/mongo-driver/bson/bsontype"
18 "go.mongodb.org/mongo-driver/bson/primitive"
19 "go.mongodb.org/mongo-driver/internal/assert"
20 "go.mongodb.org/mongo-driver/internal/handshake"
21 "go.mongodb.org/mongo-driver/mongo"
22 "go.mongodb.org/mongo-driver/mongo/integration/mtest"
23 "go.mongodb.org/mongo-driver/mongo/options"
24 "go.mongodb.org/mongo-driver/mongo/readpref"
25 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
26 )
27
28 const (
29 listCollCapped = "listcoll_capped"
30 listCollUncapped = "listcoll_uncapped"
31 )
32
33 var (
34 interfaceAsMapRegistry = bson.NewRegistryBuilder().
35 RegisterTypeMapEntry(bsontype.EmbeddedDocument, reflect.TypeOf(bson.M{})).
36 Build()
37 )
38
39 func TestDatabase(t *testing.T) {
40 mt := mtest.New(t, mtest.NewOptions().CreateClient(false))
41
42 mt.RunOpts("run command", noClientOpts, func(mt *mtest.T) {
43 mt.Run("decode raw", func(mt *mtest.T) {
44 res, err := mt.DB.RunCommand(context.Background(), bson.D{{handshake.LegacyHello, 1}}).Raw()
45 assert.Nil(mt, err, "RunCommand error: %v", err)
46
47 ok, err := res.LookupErr("ok")
48 assert.Nil(mt, err, "ok field not found in result")
49 assert.Equal(mt, bson.TypeDouble, ok.Type, "expected ok type %v, got %v", bson.TypeDouble, ok.Type)
50 assert.Equal(mt, 1.0, ok.Double(), "expected ok value 1.0, got %v", ok.Double())
51
52 hello, err := res.LookupErr(handshake.LegacyHelloLowercase)
53 assert.Nil(mt, err, "legacy hello response field not found in result")
54 assert.Equal(mt, bson.TypeBoolean, hello.Type, "expected hello type %v, got %v", bson.TypeBoolean, hello.Type)
55 assert.True(mt, hello.Boolean(), "expected hello value true, got false")
56 })
57 mt.Run("decode struct", func(mt *mtest.T) {
58 result := struct {
59 Ok float64 `bson:"ok"`
60 }{}
61 err := mt.DB.RunCommand(context.Background(), bson.D{{"ping", 1}}).Decode(&result)
62 assert.Nil(mt, err, "RunCommand error: %v", err)
63 assert.Equal(mt, 1.0, result.Ok, "expected ok value 1.0, got %v", result.Ok)
64 })
65
66
67
68
69 readPrefOpts := mtest.NewOptions().
70 Topologies(mtest.Sharded).
71 MinServerVersion("3.6")
72 mt.RunOpts("read pref passed to mongos", readPrefOpts, func(mt *mtest.T) {
73
74
75
76 runCmdOpts := options.RunCmd().
77 SetReadPreference(readpref.SecondaryPreferred())
78 err := mt.DB.RunCommand(context.Background(), bson.D{{handshake.LegacyHello, 1}}, runCmdOpts).Err()
79 assert.Nil(mt, err, "RunCommand error: %v", err)
80
81 expected := bson.Raw(bsoncore.NewDocumentBuilder().
82 AppendString("mode", "secondaryPreferred").
83 Build())
84 evt := mt.GetStartedEvent()
85 assert.Equal(mt, handshake.LegacyHello, evt.CommandName, "expected legacy hello command to be sent, got %q", evt.CommandName)
86 actual, ok := evt.Command.Lookup("$readPreference").DocumentOK()
87 assert.True(mt, ok, "expected command %v to contain a $readPreference document", evt.Command)
88 assert.Equal(mt, expected, actual, "expected $readPreference document %v, got %v", expected, actual)
89 })
90 failpointOpts := mtest.NewOptions().MinServerVersion("4.0").Topologies(mtest.ReplicaSet)
91 mt.RunOpts("gets result and error", failpointOpts, func(mt *mtest.T) {
92 mt.SetFailPoint(mtest.FailPoint{
93 ConfigureFailPoint: "failCommand",
94 Mode: mtest.FailPointMode{
95 Times: 1,
96 },
97 Data: mtest.FailPointData{
98 FailCommands: []string{"insert"},
99 WriteConcernError: &mtest.WriteConcernErrorData{
100 Code: 100,
101 },
102 },
103 })
104 cmd := bson.D{
105 {"insert", "test"},
106 {"documents", bson.A{bson.D{{"a", 1}}}},
107 }
108 res, gotErr := mt.DB.RunCommand(context.Background(), cmd).Raw()
109
110 n, ok := res.Lookup("n").Int32OK()
111 assert.True(mt, ok, "expected n in response")
112 assert.Equal(mt, int32(1), n, "expected n value 1, got %v", n)
113
114 writeExcept, ok := gotErr.(mongo.WriteException)
115 assert.True(mt, ok, "expected WriteCommandError, got %T", gotErr)
116 assert.NotNil(mt, writeExcept.WriteConcernError, "expected WriteConcernError to be non-nil")
117 assert.Equal(mt, writeExcept.WriteConcernError.Code, 100, "expected error code 100, got %v", writeExcept.WriteConcernError.Code)
118 })
119 mt.Run("multi key map command", func(mt *mtest.T) {
120 err := mt.DB.RunCommand(context.Background(), bson.M{"insert": "test", "documents": bson.A{bson.D{{"a", 1}}}}).Err()
121 assert.Equal(mt, mongo.ErrMapForOrderedArgument{"cmd"}, err, "expected error %v, got %v", mongo.ErrMapForOrderedArgument{"cmd"}, err)
122 })
123 })
124
125 dropOpts := mtest.NewOptions().DatabaseName("dropDb")
126 mt.RunOpts("drop", dropOpts, func(mt *mtest.T) {
127 err := mt.DB.Drop(context.Background())
128 assert.Nil(mt, err, "Drop error: %v", err)
129
130 list, err := mt.Client.ListDatabaseNames(context.Background(), bson.D{})
131 assert.Nil(mt, err, "ListDatabaseNames error: %v", err)
132 for _, db := range list {
133 if db == "dropDb" {
134 mt.Fatal("dropped database 'dropDb' found in database names")
135 }
136 }
137 })
138
139 lcNamesOpts := mtest.NewOptions().MinServerVersion("4.0")
140 mt.RunOpts("list collection names", lcNamesOpts, func(mt *mtest.T) {
141 collName := "lcNamesCollection"
142 mt.CreateCollection(mtest.Collection{Name: collName}, true)
143
144 testCases := []struct {
145 name string
146 filter bson.D
147 found bool
148 }{
149 {"no filter", bson.D{}, true},
150 {"filter", bson.D{{"name", "lcNamesCollection"}}, true},
151 {"filter not found", bson.D{{"name", "123"}}, false},
152 }
153 for _, tc := range testCases {
154 mt.Run(tc.name, func(mt *mtest.T) {
155 colls, err := mt.DB.ListCollectionNames(context.Background(), tc.filter)
156 assert.Nil(mt, err, "ListCollectionNames error: %v", err)
157
158 var found bool
159 for _, coll := range colls {
160 if coll == collName {
161 found = true
162 break
163 }
164 }
165
166 assert.Equal(mt, tc.found, found, "expected to find collection: %v, found collection: %v", tc.found, found)
167 })
168 }
169 })
170
171 mt.RunOpts("list collections", noClientOpts, func(mt *mtest.T) {
172 createCollections := func(mt *mtest.T, numCollections int) {
173 mt.Helper()
174
175 for i := 0; i < numCollections; i++ {
176 mt.CreateCollection(mtest.Collection{
177 Name: fmt.Sprintf("list-collections-test-%d", i),
178 }, true)
179 }
180 }
181
182 mt.RunOpts("verify results", noClientOpts, func(mt *mtest.T) {
183 testCases := []struct {
184 name string
185 expectedTopology mtest.TopologyKind
186 cappedOnly bool
187 }{
188 {"standalone no filter", mtest.Single, false},
189 {"standalone filter", mtest.Single, true},
190 {"replica set no filter", mtest.ReplicaSet, false},
191 {"replica set filter", mtest.ReplicaSet, true},
192 {"sharded no filter", mtest.Sharded, false},
193 {"sharded filter", mtest.Sharded, true},
194 }
195 for _, tc := range testCases {
196 tcOpts := mtest.NewOptions().Topologies(tc.expectedTopology)
197 mt.RunOpts(tc.name, tcOpts, func(mt *mtest.T) {
198 mt.CreateCollection(mtest.Collection{Name: listCollUncapped}, true)
199 mt.CreateCollection(mtest.Collection{
200 Name: listCollCapped,
201 CreateOpts: options.CreateCollection().SetCapped(true).SetSizeInBytes(64 * 1024),
202 }, true)
203
204 filter := bson.D{}
205 if tc.cappedOnly {
206 filter = bson.D{{"options.capped", true}}
207 }
208
209 var err error
210 for i := 0; i < 1; i++ {
211 cursor, err := mt.DB.ListCollections(context.Background(), filter)
212 assert.Nil(mt, err, "ListCollections error (iteration %v): %v", i, err)
213
214 err = verifyListCollections(cursor, tc.cappedOnly)
215 if err == nil {
216 return
217 }
218 }
219 mt.Fatalf("error verifying list collections result: %v", err)
220 })
221 }
222 })
223
224
225
226
227 cmdMonitoringCmdName := "listCollections"
228 if mtest.CompareServerVersions(mtest.ServerVersion(), "3.0") < 0 {
229 cmdMonitoringCmdName = "find"
230 }
231 mt.Run("batch size", func(mt *mtest.T) {
232
233 createCollections(mt, 2)
234
235 mt.ClearEvents()
236 lcOpts := options.ListCollections().SetBatchSize(2)
237 _, err := mt.DB.ListCollectionNames(context.Background(), bson.D{}, lcOpts)
238 assert.Nil(mt, err, "ListCollectionNames error: %v", err)
239
240 evt := mt.GetStartedEvent()
241 assert.Equal(
242 mt,
243 cmdMonitoringCmdName,
244 evt.CommandName,
245 "expected %q command to be sent, got %q",
246 cmdMonitoringCmdName,
247 evt.CommandName)
248 _, err = evt.Command.LookupErr("cursor", "batchSize")
249 assert.Nil(mt, err, "expected command %s to contain key 'batchSize'", evt.Command)
250 })
251 mt.RunOpts("authorizedCollections", mtest.NewOptions().MinServerVersion("4.0"), func(mt *mtest.T) {
252 mt.ClearEvents()
253 lcOpts := options.ListCollections().SetAuthorizedCollections(true)
254 _, err := mt.DB.ListCollections(context.Background(), bson.D{}, lcOpts)
255 assert.Nil(mt, err, "ListCollections error: %v", err)
256
257 evt := mt.GetStartedEvent()
258 assert.Equal(mt, "listCollections", evt.CommandName,
259 "expected 'listCollections' command to be sent, got %q", evt.CommandName)
260 _, err = evt.Command.LookupErr("authorizedCollections")
261 assert.Nil(mt, err, "expected command to contain key 'authorizedCollections'")
262
263 })
264 mt.Run("getMore commands are monitored", func(mt *mtest.T) {
265 createCollections(mt, 2)
266 assertGetMoreCommandsAreMonitored(mt, cmdMonitoringCmdName, func() (*mongo.Cursor, error) {
267 return mt.DB.ListCollections(context.Background(), bson.D{}, options.ListCollections().SetBatchSize(2))
268 })
269 })
270 mt.Run("killCursors commands are monitored", func(mt *mtest.T) {
271 createCollections(mt, 2)
272 assertKillCursorsCommandsAreMonitored(mt, cmdMonitoringCmdName, func() (*mongo.Cursor, error) {
273 return mt.DB.ListCollections(context.Background(), bson.D{}, options.ListCollections().SetBatchSize(2))
274 })
275 })
276 })
277
278 mt.RunOpts("list collection specifications", noClientOpts, func(mt *mtest.T) {
279 mt.Run("filter passed to listCollections", func(mt *mtest.T) {
280
281 cappedName := "list-collection-specs-capped"
282 mt.CreateCollection(mtest.Collection{
283 Name: cappedName,
284 CreateOpts: options.CreateCollection().SetCapped(true).SetSizeInBytes(4096),
285 }, true)
286
287 filter := bson.M{
288 "options.capped": true,
289 }
290 cursor, err := mt.DB.ListCollections(context.Background(), filter)
291 assert.Nil(mt, err, "ListCollections error: %v", err)
292 defer cursor.Close(context.Background())
293 assert.True(mt, cursor.Next(context.Background()), "expected Next to return true, got false; cursor error: %v",
294 cursor.Err())
295
296 optionsDoc := bsoncore.NewDocumentBuilder().
297 AppendBoolean("capped", true).
298 AppendInt32("size", 4096).
299 Build()
300
301 expectedSpec := &mongo.CollectionSpecification{
302 Name: cappedName,
303 Type: "collection",
304 ReadOnly: false,
305 Options: bson.Raw(optionsDoc),
306 }
307 if mtest.CompareServerVersions(mtest.ServerVersion(), "3.6") >= 0 {
308 uuidSubtype, uuidData := cursor.Current.Lookup("info", "uuid").Binary()
309 expectedSpec.UUID = &primitive.Binary{Subtype: uuidSubtype, Data: uuidData}
310 }
311 if mtest.CompareServerVersions(mtest.ServerVersion(), "3.4") >= 0 {
312 keysDoc := bsoncore.NewDocumentBuilder().
313 AppendInt32("_id", 1).
314 Build()
315 expectedSpec.IDIndex = &mongo.IndexSpecification{
316 Name: "_id_",
317 Namespace: mt.DB.Name() + "." + cappedName,
318 KeysDocument: bson.Raw(keysDoc),
319 Version: 2,
320 }
321 }
322
323 specs, err := mt.DB.ListCollectionSpecifications(context.Background(), filter)
324 assert.Nil(mt, err, "ListCollectionSpecifications error: %v", err)
325 assert.Equal(mt, 1, len(specs), "expected 1 CollectionSpecification, got %d", len(specs))
326 assert.Equal(mt, expectedSpec, specs[0], "expected specification %v, got %v", expectedSpec, specs[0])
327 })
328
329 mt.RunOpts("options passed to listCollections", mtest.NewOptions().MinServerVersion("3.0"), func(mt *mtest.T) {
330
331
332 opts := options.ListCollections().SetNameOnly(true)
333 _, err := mt.DB.ListCollectionSpecifications(context.Background(), bson.D{}, opts)
334 assert.Nil(mt, err, "ListCollectionSpecifications error: %v", err)
335
336 evt := mt.GetStartedEvent()
337 assert.Equal(mt, "listCollections", evt.CommandName, "expected %q command to be sent, got %q",
338 "listCollections", evt.CommandName)
339 nameOnly, ok := evt.Command.Lookup("nameOnly").BooleanOK()
340 assert.True(mt, ok, "expected command %v to contain %q field", evt.Command, "nameOnly")
341 assert.True(mt, nameOnly, "expected nameOnly value to be true, got false")
342 })
343 })
344
345 mt.RunOpts("run command cursor", noClientOpts, func(mt *mtest.T) {
346 var data []interface{}
347 for i := 0; i < 5; i++ {
348 data = append(data, bson.D{{"x", i}})
349 }
350 findCollName := "runcommandcursor_find"
351 findCmd := bson.D{{"find", findCollName}}
352 aggCollName := "runcommandcursor_agg"
353 aggCmd := bson.D{
354 {"aggregate", aggCollName},
355 {"pipeline", bson.A{}},
356 {"cursor", bson.D{}},
357 }
358 pingCmd := bson.D{{"ping", 1}}
359 pingErr := errors.New("database response does not contain a cursor; try using RunCommand instead")
360
361 testCases := []struct {
362 name string
363 collName string
364 cmd interface{}
365 toInsert []interface{}
366 expectedErr error
367 numExpected int
368 minVersion string
369 }{
370 {"success find", findCollName, findCmd, data, nil, 5, "3.2"},
371 {"success aggregate", aggCollName, aggCmd, data, nil, 5, ""},
372 {"failures", "runcommandcursor_ping", pingCmd, nil, pingErr, 0, ""},
373 }
374 for _, tc := range testCases {
375 tcOpts := mtest.NewOptions().CollectionName(tc.collName)
376 if tc.minVersion != "" {
377 tcOpts.MinServerVersion(tc.minVersion)
378 }
379
380 mt.RunOpts(tc.name, tcOpts, func(mt *mtest.T) {
381 if len(tc.toInsert) > 0 {
382 _, err := mt.Coll.InsertMany(context.Background(), tc.toInsert)
383 assert.Nil(mt, err, "InsertMany error: %v", err)
384 }
385
386 cursor, err := mt.DB.RunCommandCursor(context.Background(), tc.cmd)
387 assert.Equal(mt, tc.expectedErr, err, "expected error %v, got %v", tc.expectedErr, err)
388 if tc.expectedErr != nil {
389 return
390 }
391
392 var count int
393 for cursor.Next(context.Background()) {
394 count++
395 }
396 assert.Equal(mt, tc.numExpected, count, "expected document count %v, got %v", tc.numExpected, count)
397 })
398 }
399
400
401 cmdMonitoringMtOpts := mtest.NewOptions().MinServerVersion("3.2")
402 mt.RunOpts("getMore commands are monitored", cmdMonitoringMtOpts, func(mt *mtest.T) {
403 initCollection(mt, mt.Coll)
404 assertGetMoreCommandsAreMonitored(mt, "find", func() (*mongo.Cursor, error) {
405 findCmd := bson.D{
406 {"find", mt.Coll.Name()},
407 {"batchSize", 2},
408 }
409 return mt.DB.RunCommandCursor(context.Background(), findCmd)
410 })
411 })
412 mt.RunOpts("killCursors commands are monitored", cmdMonitoringMtOpts, func(mt *mtest.T) {
413 initCollection(mt, mt.Coll)
414 assertKillCursorsCommandsAreMonitored(mt, "find", func() (*mongo.Cursor, error) {
415 findCmd := bson.D{
416 {"find", mt.Coll.Name()},
417 {"batchSize", 2},
418 }
419 return mt.DB.RunCommandCursor(context.Background(), findCmd)
420 })
421 })
422 })
423
424 mt.RunOpts("create collection", noClientOpts, func(mt *mtest.T) {
425 collectionName := "create-collection-test"
426
427 mt.RunOpts("options", noClientOpts, func(mt *mtest.T) {
428
429
430
431
432
433
434
435 storageEngine := bson.M{
436 "wiredTiger": bson.M{
437 "configString": "block_compressor=zlib",
438 },
439 }
440 defaultIndexOpts := options.DefaultIndex().SetStorageEngine(storageEngine)
441 validator := bson.M{
442 "$or": bson.A{
443 bson.M{
444 "phone": bson.M{"$type": "string"},
445 },
446 bson.M{
447 "email": bson.M{"$type": "string"},
448 },
449 },
450 }
451 nonCollationOpts := options.CreateCollection().
452 SetCapped(true).
453 SetDefaultIndexOptions(defaultIndexOpts).
454 SetMaxDocuments(100).
455 SetSizeInBytes(1024).
456 SetStorageEngine(storageEngine).
457 SetValidator(validator).
458 SetValidationAction("warn").
459 SetValidationLevel("moderate")
460 nonCollationExpected := bson.M{
461 "capped": true,
462 "indexOptionDefaults": bson.M{
463 "storageEngine": storageEngine,
464 },
465 "max": int32(100),
466 "size": int32(1024),
467 "storageEngine": storageEngine,
468 "validator": validator,
469 "validationAction": "warn",
470 "validationLevel": "moderate",
471 }
472
473 csppiOpts := options.CreateCollection().SetChangeStreamPreAndPostImages(bson.M{"enabled": true})
474 csppiExpected := bson.M{
475 "changeStreamPreAndPostImages": bson.M{
476 "enabled": true,
477 },
478 }
479
480 testCases := []struct {
481 name string
482 minServerVersion string
483 maxServerVersion string
484 createOpts *options.CreateCollectionOptions
485 expectedOpts bson.M
486 }{
487 {"all options except collation and csppi", "3.2", "", nonCollationOpts, nonCollationExpected},
488 {"changeStreamPreAndPostImages", "6.0", "", csppiOpts, csppiExpected},
489 }
490
491 for _, tc := range testCases {
492 mtOpts := mtest.NewOptions().
493 MinServerVersion(tc.minServerVersion).
494 MaxServerVersion(tc.maxServerVersion)
495
496 mt.RunOpts(tc.name, mtOpts, func(mt *mtest.T) {
497 mt.CreateCollection(mtest.Collection{
498 Name: collectionName,
499 }, false)
500
501 err := mt.DB.CreateCollection(context.Background(), collectionName, tc.createOpts)
502 assert.Nil(mt, err, "CreateCollection error: %v", err)
503
504 actualOpts := getCollectionOptions(mt, collectionName)
505 assert.Equal(mt, tc.expectedOpts, actualOpts, "options mismatch; expected %v, got %v",
506 tc.expectedOpts, actualOpts)
507 })
508 }
509 })
510 mt.RunOpts("collation", mtest.NewOptions().MinServerVersion("3.4"), func(mt *mtest.T) {
511 mt.CreateCollection(mtest.Collection{
512 Name: collectionName,
513 }, false)
514
515 locale := "en_US"
516 createOpts := options.CreateCollection().SetCollation(&options.Collation{
517 Locale: locale,
518 })
519 err := mt.DB.CreateCollection(context.Background(), collectionName, createOpts)
520 assert.Nil(mt, err, "CreateCollection error: %v", err)
521
522 actualOpts := getCollectionOptions(mt, collectionName)
523 collationVal, ok := actualOpts["collation"]
524 assert.True(mt, ok, "expected key 'collation' in collection options %v", actualOpts)
525 collation := collationVal.(bson.M)
526 assert.Equal(mt, locale, collation["locale"], "expected locale %v, got %v", locale, collation["locale"])
527 })
528 mt.Run("write concern", func(mt *mtest.T) {
529 mt.CreateCollection(mtest.Collection{
530 Name: collectionName,
531 }, false)
532
533 err := mt.DB.CreateCollection(context.Background(), collectionName)
534 assert.Nil(mt, err, "CreateCollection error: %v", err)
535
536 evt := mt.GetStartedEvent()
537 assert.Equal(mt, evt.CommandName, "create", "expected event for 'create', got '%v'", evt.CommandName)
538 _, err = evt.Command.LookupErr("writeConcern")
539 assert.Nil(mt, err, "expected write concern to be included in command %v", evt.Command)
540 })
541 })
542
543 mt.RunOpts("create view", mtest.NewOptions().CreateClient(false).MinServerVersion("3.4"), func(mt *mtest.T) {
544 sourceCollectionName := "create-view-test-collection"
545 viewName := "create-view-test-view"
546 projectStage := bson.M{
547 "$project": bson.M{
548 "projectedField": "foo",
549 },
550 }
551 pipeline := []bson.M{projectStage}
552
553 mt.Run("function parameters are translated into options", func(mt *mtest.T) {
554 mt.CreateCollection(mtest.Collection{
555 Name: viewName,
556 }, false)
557
558 err := mt.DB.CreateView(context.Background(), viewName, sourceCollectionName, pipeline)
559 assert.Nil(mt, err, "CreateView error: %v", err)
560
561 expectedOpts := bson.M{
562 "viewOn": sourceCollectionName,
563 "pipeline": bson.A{projectStage},
564 }
565 actualOpts := getCollectionOptions(mt, viewName)
566 assert.Equal(mt, expectedOpts, actualOpts, "options mismatch; expected %v, got %v", expectedOpts,
567 actualOpts)
568 })
569 mt.Run("collation", func(mt *mtest.T) {
570 mt.CreateCollection(mtest.Collection{
571 Name: viewName,
572 }, false)
573
574 locale := "en_US"
575 viewOpts := options.CreateView().SetCollation(&options.Collation{
576 Locale: locale,
577 })
578 err := mt.DB.CreateView(context.Background(), viewName, sourceCollectionName, mongo.Pipeline{}, viewOpts)
579 assert.Nil(mt, err, "CreateView error: %v", err)
580
581 actualOpts := getCollectionOptions(mt, viewName)
582 collationVal, ok := actualOpts["collation"]
583 assert.True(mt, ok, "expected key 'collation' in view options %v", actualOpts)
584 collation := collationVal.(bson.M)
585 assert.Equal(mt, locale, collation["locale"], "expected locale %v, got %v", locale, collation["locale"])
586 })
587 })
588 }
589
590 func getCollectionOptions(mt *mtest.T, collectionName string) bson.M {
591 mt.Helper()
592
593 filter := bson.M{
594 "name": collectionName,
595 }
596 cursor, err := mt.DB.ListCollections(context.Background(), filter)
597 assert.Nil(mt, err, "ListCollections error: %v", err)
598 defer cursor.Close(context.Background())
599 assert.True(mt, cursor.Next(context.Background()), "expected Next to return true, got false")
600
601 var actualOpts bson.M
602 err = bson.UnmarshalWithRegistry(interfaceAsMapRegistry, cursor.Current.Lookup("options").Document(), &actualOpts)
603 assert.Nil(mt, err, "UnmarshalWithRegistry error: %v", err)
604
605 return actualOpts
606 }
607
608 func verifyListCollections(cursor *mongo.Cursor, cappedOnly bool) error {
609 var cappedFound, uncappedFound bool
610
611 for cursor.Next(context.Background()) {
612 nameElem, err := cursor.Current.LookupErr("name")
613 if err != nil {
614 return fmt.Errorf("name element not found in document %v", cursor.Current)
615 }
616 if nameElem.Type != bson.TypeString {
617 return fmt.Errorf("expected name type %v, got %v", bson.TypeString, nameElem.Type)
618 }
619
620 name := nameElem.StringValue()
621
622 if name != listCollUncapped && name != listCollCapped {
623 continue
624 }
625
626 if name == listCollUncapped && !uncappedFound {
627 if cappedOnly {
628 return fmt.Errorf("found uncapped collection %v but expected only capped collections", listCollUncapped)
629 }
630
631 uncappedFound = true
632 continue
633 }
634 if name == listCollCapped && !cappedFound {
635 cappedFound = true
636 continue
637 }
638
639
640 return fmt.Errorf("found duplicate collection %v", name)
641 }
642
643 if !cappedFound {
644 return fmt.Errorf("capped collection %v not found", listCollCapped)
645 }
646 if !cappedOnly && !uncappedFound {
647 return fmt.Errorf("uncapped collection %v not found", listCollUncapped)
648 }
649 return nil
650 }
651
View as plain text