1
2
3
4
5
6
7 package mongo
8
9 import (
10 "context"
11 "fmt"
12 "testing"
13 "time"
14
15 "go.mongodb.org/mongo-driver/bson"
16 "go.mongodb.org/mongo-driver/internal/assert"
17 "go.mongodb.org/mongo-driver/internal/require"
18 "go.mongodb.org/mongo-driver/mongo/options"
19 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
20 "go.mongodb.org/mongo-driver/x/mongo/driver"
21 )
22
23 type testBatchCursor struct {
24 batches []*bsoncore.DocumentSequence
25 batch *bsoncore.DocumentSequence
26 closed bool
27 }
28
29 func newTestBatchCursor(numBatches, batchSize int) *testBatchCursor {
30 batches := make([]*bsoncore.DocumentSequence, 0, numBatches)
31
32 counter := 0
33 for batch := 0; batch < numBatches; batch++ {
34 var docSequence []byte
35
36 for doc := 0; doc < batchSize; doc++ {
37 var elem []byte
38 elem = bsoncore.AppendInt32Element(elem, "foo", int32(counter))
39 counter++
40
41 var doc []byte
42 doc = bsoncore.BuildDocumentFromElements(doc, elem)
43 docSequence = append(docSequence, doc...)
44 }
45
46 batches = append(batches, &bsoncore.DocumentSequence{
47 Style: bsoncore.SequenceStyle,
48 Data: docSequence,
49 })
50 }
51
52 return &testBatchCursor{
53 batches: batches,
54 }
55 }
56
57 func (tbc *testBatchCursor) ID() int64 {
58 if len(tbc.batches) == 0 {
59 return 0
60 }
61
62 return 10
63 }
64
65 func (tbc *testBatchCursor) Next(context.Context) bool {
66 if len(tbc.batches) == 0 {
67 return false
68 }
69
70 tbc.batch = tbc.batches[0]
71 tbc.batches = tbc.batches[1:]
72 return true
73 }
74
75 func (tbc *testBatchCursor) Batch() *bsoncore.DocumentSequence {
76 return tbc.batch
77 }
78
79 func (tbc *testBatchCursor) Server() driver.Server {
80 return nil
81 }
82
83 func (tbc *testBatchCursor) Err() error {
84 return nil
85 }
86
87 func (tbc *testBatchCursor) Close(context.Context) error {
88 tbc.closed = true
89 return nil
90 }
91
92 func (tbc *testBatchCursor) SetBatchSize(int32) {}
93 func (tbc *testBatchCursor) SetComment(interface{}) {}
94 func (tbc *testBatchCursor) SetMaxTime(time.Duration) {}
95
96 func TestCursor(t *testing.T) {
97 t.Run("loops until docs available", func(t *testing.T) {})
98 t.Run("returns false on context cancellation", func(t *testing.T) {})
99 t.Run("returns false if error occurred", func(t *testing.T) {})
100 t.Run("returns false if ID is zero and no more docs", func(t *testing.T) {})
101
102 t.Run("TestAll", func(t *testing.T) {
103 t.Run("errors if argument is not pointer to slice", func(t *testing.T) {
104 cursor, err := newCursor(newTestBatchCursor(1, 5), nil, nil)
105 assert.Nil(t, err, "newCursor error: %v", err)
106 err = cursor.All(context.Background(), []bson.D{})
107 assert.NotNil(t, err, "expected error, got nil")
108 })
109
110 t.Run("fills slice with all documents", func(t *testing.T) {
111 cursor, err := newCursor(newTestBatchCursor(1, 5), nil, nil)
112 assert.Nil(t, err, "newCursor error: %v", err)
113
114 var docs []bson.D
115 err = cursor.All(context.Background(), &docs)
116 assert.Nil(t, err, "All error: %v", err)
117 assert.Equal(t, 5, len(docs), "expected 5 docs, got %v", len(docs))
118
119 for index, doc := range docs {
120 expected := bson.D{{"foo", int32(index)}}
121 assert.Equal(t, expected, doc, "expected doc %v, got %v", expected, doc)
122 }
123 })
124
125 t.Run("decodes each document into slice type", func(t *testing.T) {
126 cursor, err := newCursor(newTestBatchCursor(1, 5), nil, nil)
127 assert.Nil(t, err, "newCursor error: %v", err)
128
129 type Document struct {
130 Foo int32 `bson:"foo"`
131 }
132 var docs []Document
133 err = cursor.All(context.Background(), &docs)
134 assert.Nil(t, err, "All error: %v", err)
135 assert.Equal(t, 5, len(docs), "expected 5 documents, got %v", len(docs))
136
137 for index, doc := range docs {
138 expected := Document{Foo: int32(index)}
139 assert.Equal(t, expected, doc, "expected doc %v, got %v", expected, doc)
140 }
141 })
142
143 t.Run("multiple batches are included", func(t *testing.T) {
144 cursor, err := newCursor(newTestBatchCursor(2, 5), nil, nil)
145 assert.Nil(t, err, "newCursor error: %v", err)
146 var docs []bson.D
147 err = cursor.All(context.Background(), &docs)
148 assert.Nil(t, err, "All error: %v", err)
149 assert.Equal(t, 10, len(docs), "expected 10 docs, got %v", len(docs))
150
151 for index, doc := range docs {
152 expected := bson.D{{"foo", int32(index)}}
153 assert.Equal(t, expected, doc, "expected doc %v, got %v", expected, doc)
154 }
155 })
156
157 t.Run("cursor is closed after All is called", func(t *testing.T) {
158 var docs []bson.D
159
160 tbc := newTestBatchCursor(1, 5)
161 cursor, err := newCursor(tbc, nil, nil)
162 assert.Nil(t, err, "newCursor error: %v", err)
163
164 err = cursor.All(context.Background(), &docs)
165 assert.Nil(t, err, "All error: %v", err)
166 assert.True(t, tbc.closed, "expected batch cursor to be closed but was not")
167 })
168
169 t.Run("does not error given interface as parameter", func(t *testing.T) {
170 var docs interface{} = []bson.D{}
171
172 cursor, err := newCursor(newTestBatchCursor(1, 5), nil, nil)
173 assert.Nil(t, err, "newCursor error: %v", err)
174
175 err = cursor.All(context.Background(), &docs)
176 assert.Nil(t, err, "expected Nil, got error: %v", err)
177 assert.Equal(t, 5, len(docs.([]bson.D)), "expected 5 documents, got %v", len(docs.([]bson.D)))
178 })
179 t.Run("errors when not given pointer to slice", func(t *testing.T) {
180 var docs interface{} = "test"
181
182 cursor, err := newCursor(newTestBatchCursor(1, 5), nil, nil)
183 assert.Nil(t, err, "newCursor error: %v", err)
184
185 err = cursor.All(context.Background(), &docs)
186 assert.NotNil(t, err, "expected error, got: %v", err)
187 })
188 t.Run("with BSONOptions", func(t *testing.T) {
189 cursor, err := newCursor(
190 newTestBatchCursor(1, 5),
191 &options.BSONOptions{
192 UseJSONStructTags: true,
193 },
194 nil)
195 require.NoError(t, err, "newCursor error")
196
197 type myDocument struct {
198 A int32 `json:"foo"`
199 }
200 var got []myDocument
201
202 err = cursor.All(context.Background(), &got)
203 require.NoError(t, err, "All error")
204
205 want := []myDocument{{A: 0}, {A: 1}, {A: 2}, {A: 3}, {A: 4}}
206
207 assert.Equal(t, want, got, "expected and actual All results are different")
208 })
209 })
210 }
211
212 func TestNewCursorFromDocuments(t *testing.T) {
213
214 t.Run("mock Find", func(t *testing.T) {
215 findResult := []interface{}{
216 bson.D{{"_id", 0}, {"foo", "bar"}},
217 bson.D{{"_id", 1}, {"baz", "qux"}},
218 bson.D{{"_id", 2}, {"quux", "quuz"}},
219 }
220 cur, err := NewCursorFromDocuments(findResult, nil, nil)
221 assert.Nil(t, err, "NewCursorFromDocuments error: %v", err)
222
223
224 var i int
225 for cur.Next(context.Background()) {
226 docBytes, err := bson.Marshal(findResult[i])
227 assert.Nil(t, err, "Marshal error: %v", err)
228 expectedDecoded := bson.Raw(docBytes)
229
230 var decoded bson.Raw
231 err = cur.Decode(&decoded)
232 assert.Nil(t, err, "Decode error: %v", err)
233 assert.Equal(t, expectedDecoded, decoded,
234 "expected decoded document %v of Cursor to be %v, got %v",
235 i, expectedDecoded, decoded)
236 i++
237 }
238 assert.Equal(t, 3, i, "expected 3 calls to cur.Next, got %v", i)
239
240
241 assert.Nil(t, cur.Err(), "Cursor error: %v", cur.Err())
242
243
244 err = cur.Close(context.Background())
245 assert.Nil(t, err, "Close error: %v", err)
246 })
247
248
249 t.Run("mock Find with error", func(t *testing.T) {
250 mockErr := fmt.Errorf("mock error")
251 findResult := []interface{}{bson.D{{"_id", 0}, {"foo", "bar"}}}
252 cur, err := NewCursorFromDocuments(findResult, mockErr, nil)
253 assert.Nil(t, err, "NewCursorFromDocuments error: %v", err)
254
255
256 next := cur.Next(context.Background())
257 assert.False(t, next, "expected call to Next to return false, got true")
258
259
260 assert.NotNil(t, cur.Err(), "expected Cursor error, got nil")
261 assert.Equal(t, mockErr, cur.Err(), "expected Cursor error %v, got %v",
262 mockErr, cur.Err())
263 })
264 }
265
View as plain text