-
Notifications
You must be signed in to change notification settings - Fork 881
/
collection_data.go
122 lines (105 loc) · 4.38 KB
/
collection_data.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package unified
import (
"bytes"
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
testhelpers "go.mongodb.org/mongo-driver/internal/testutil/helpers"
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readconcern"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
type collectionData struct {
DatabaseName string `bson:"databaseName"`
CollectionName string `bson:"collectionName"`
Documents []bson.Raw `bson:"documents"`
Options *collectionDataOptions `bson:"collectionOptions"`
}
type collectionDataOptions struct {
Capped *bool `bson:"capped"`
SizeInBytes *int64 `bson:"size"`
}
// createCollection configures the collection represented by the receiver using the internal client. This function
// first drops the collection and then creates it with specified options (if any) and inserts the seed data if needed.
func (c *collectionData) createCollection(ctx context.Context) error {
db := mtest.GlobalClient().Database(c.DatabaseName, options.Database().SetWriteConcern(mtest.MajorityWc))
coll := db.Collection(c.CollectionName)
if err := coll.Drop(ctx); err != nil {
return fmt.Errorf("error dropping collection: %v", err)
}
// Explicitly create collection if Options are specified.
if c.Options != nil {
createOpts := options.CreateCollection()
if c.Options.Capped != nil {
createOpts = createOpts.SetCapped(*c.Options.Capped)
}
if c.Options.SizeInBytes != nil {
createOpts = createOpts.SetSizeInBytes(*c.Options.SizeInBytes)
}
if err := db.CreateCollection(ctx, c.CollectionName, createOpts); err != nil {
return fmt.Errorf("error creating collection: %v", err)
}
}
// If neither documents nor options are provided, still create the collection with write concern "majority".
if len(c.Documents) == 0 && c.Options == nil {
// The write concern has to be manually specified in the command document because RunCommand does not honor
// the database's write concern.
create := bson.D{
{"create", coll.Name()},
{"writeConcern", bson.D{
{"w", "majority"},
}},
}
if err := db.RunCommand(ctx, create).Err(); err != nil {
return fmt.Errorf("error creating collection: %v", err)
}
return nil
}
docs := testhelpers.RawSliceToInterfaceSlice(c.Documents)
if _, err := coll.InsertMany(ctx, docs); err != nil {
return fmt.Errorf("error inserting data: %v", err)
}
return nil
}
// verifyContents asserts that the collection on the server represented by this collectionData instance contains the
// expected documents.
func (c *collectionData) verifyContents(ctx context.Context) error {
collOpts := options.Collection().
SetReadPreference(readpref.Primary()).
SetReadConcern(readconcern.Local())
coll := mtest.GlobalClient().Database(c.DatabaseName).Collection(c.CollectionName, collOpts)
cursor, err := coll.Find(ctx, bson.D{}, options.Find().SetSort(bson.M{"_id": 1}))
if err != nil {
return fmt.Errorf("Find error: %v", err)
}
defer cursor.Close(ctx)
var docs []bson.Raw
if err := cursor.All(ctx, &docs); err != nil {
return fmt.Errorf("cursor iteration error: %v", err)
}
// Verify the slice lengths are equal. This also covers the case of asserting that the collection is empty if
// c.Documents is an empty slice.
if len(c.Documents) != len(docs) {
return fmt.Errorf("expected %d documents but found %d: %v", len(c.Documents), len(docs), docs)
}
// We can't use verifyValuesMatch here because the rules for evaluating matches (e.g. flexible numeric comparisons
// and special $$ operators) do not apply when verifying collection outcomes. We have to permit variations in key
// order, though, so we sort documents before doing a byte-wise comparison.
for idx, expected := range c.Documents {
expected = sortDocument(expected)
actual := sortDocument(docs[idx])
if !bytes.Equal(expected, actual) {
return fmt.Errorf("document comparison error at index %d: expected %s, got %s", idx, expected, actual)
}
}
return nil
}
func (c *collectionData) namespace() string {
return fmt.Sprintf("%s.%s", c.DatabaseName, c.CollectionName)
}