1// mgo - MongoDB driver for Go
2//
3// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
4//
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are met:
9//
10// 1. Redistributions of source code must retain the above copyright notice, this
11//    list of conditions and the following disclaimer.
12// 2. Redistributions in binary form must reproduce the above copyright notice,
13//    this list of conditions and the following disclaimer in the documentation
14//    and/or other materials provided with the distribution.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27package mgo_test
28
29import (
30	"flag"
31	"fmt"
32	"math"
33	"os"
34	"runtime"
35	"sort"
36	"strconv"
37	"strings"
38	"time"
39
40	. "gopkg.in/check.v1"
41	"gopkg.in/mgo.v2"
42	"gopkg.in/mgo.v2/bson"
43)
44
45func (s *S) TestRunString(c *C) {
46	session, err := mgo.Dial("localhost:40001")
47	c.Assert(err, IsNil)
48	defer session.Close()
49
50	result := struct{ Ok int }{}
51	err = session.Run("ping", &result)
52	c.Assert(err, IsNil)
53	c.Assert(result.Ok, Equals, 1)
54}
55
56func (s *S) TestRunValue(c *C) {
57	session, err := mgo.Dial("localhost:40001")
58	c.Assert(err, IsNil)
59	defer session.Close()
60
61	result := struct{ Ok int }{}
62	err = session.Run(M{"ping": 1}, &result)
63	c.Assert(err, IsNil)
64	c.Assert(result.Ok, Equals, 1)
65}
66
67func (s *S) TestPing(c *C) {
68	session, err := mgo.Dial("localhost:40001")
69	c.Assert(err, IsNil)
70	defer session.Close()
71
72	// Just ensure the nonce has been received.
73	result := struct{}{}
74	err = session.Run("ping", &result)
75
76	mgo.ResetStats()
77
78	err = session.Ping()
79	c.Assert(err, IsNil)
80
81	// Pretty boring.
82	stats := mgo.GetStats()
83	c.Assert(stats.SentOps, Equals, 1)
84	c.Assert(stats.ReceivedOps, Equals, 1)
85}
86
87func (s *S) TestDialIPAddress(c *C) {
88	session, err := mgo.Dial("127.0.0.1:40001")
89	c.Assert(err, IsNil)
90	defer session.Close()
91
92	if os.Getenv("NOIPV6") != "1" {
93		session, err = mgo.Dial("[::1%]:40001")
94		c.Assert(err, IsNil)
95		defer session.Close()
96	}
97}
98
99func (s *S) TestURLSingle(c *C) {
100	session, err := mgo.Dial("mongodb://localhost:40001/")
101	c.Assert(err, IsNil)
102	defer session.Close()
103
104	result := struct{ Ok int }{}
105	err = session.Run("ping", &result)
106	c.Assert(err, IsNil)
107	c.Assert(result.Ok, Equals, 1)
108}
109
110func (s *S) TestURLMany(c *C) {
111	session, err := mgo.Dial("mongodb://localhost:40011,localhost:40012/")
112	c.Assert(err, IsNil)
113	defer session.Close()
114
115	result := struct{ Ok int }{}
116	err = session.Run("ping", &result)
117	c.Assert(err, IsNil)
118	c.Assert(result.Ok, Equals, 1)
119}
120
121func (s *S) TestURLParsing(c *C) {
122	urls := []string{
123		"localhost:40001?foo=1&bar=2",
124		"localhost:40001?foo=1;bar=2",
125	}
126	for _, url := range urls {
127		session, err := mgo.Dial(url)
128		if session != nil {
129			session.Close()
130		}
131		c.Assert(err, ErrorMatches, "unsupported connection URL option: (foo=1|bar=2)")
132	}
133}
134
135func (s *S) TestInsertFindOne(c *C) {
136	session, err := mgo.Dial("localhost:40001")
137	c.Assert(err, IsNil)
138	defer session.Close()
139
140	coll := session.DB("mydb").C("mycoll")
141	err = coll.Insert(M{"a": 1, "b": 2})
142	c.Assert(err, IsNil)
143	err = coll.Insert(M{"a": 1, "b": 3})
144	c.Assert(err, IsNil)
145
146	result := struct{ A, B int }{}
147
148	err = coll.Find(M{"a": 1}).Sort("b").One(&result)
149	c.Assert(err, IsNil)
150	c.Assert(result.A, Equals, 1)
151	c.Assert(result.B, Equals, 2)
152
153	err = coll.Find(M{"a": 1}).Sort("-b").One(&result)
154	c.Assert(err, IsNil)
155	c.Assert(result.A, Equals, 1)
156	c.Assert(result.B, Equals, 3)
157}
158
159func (s *S) TestInsertFindOneNil(c *C) {
160	session, err := mgo.Dial("localhost:40002")
161	c.Assert(err, IsNil)
162	defer session.Close()
163
164	coll := session.DB("mydb").C("mycoll")
165	err = coll.Find(nil).One(nil)
166	c.Assert(err, ErrorMatches, "unauthorized.*|not authorized.*")
167}
168
169func (s *S) TestInsertFindOneMap(c *C) {
170	session, err := mgo.Dial("localhost:40001")
171	c.Assert(err, IsNil)
172	defer session.Close()
173
174	coll := session.DB("mydb").C("mycoll")
175	err = coll.Insert(M{"a": 1, "b": 2})
176	c.Assert(err, IsNil)
177	result := make(M)
178	err = coll.Find(M{"a": 1}).One(result)
179	c.Assert(err, IsNil)
180	c.Assert(result["a"], Equals, 1)
181	c.Assert(result["b"], Equals, 2)
182}
183
184func (s *S) TestInsertFindAll(c *C) {
185	session, err := mgo.Dial("localhost:40001")
186	c.Assert(err, IsNil)
187	defer session.Close()
188
189	coll := session.DB("mydb").C("mycoll")
190	err = coll.Insert(M{"a": 1, "b": 2})
191	c.Assert(err, IsNil)
192	err = coll.Insert(M{"a": 3, "b": 4})
193	c.Assert(err, IsNil)
194
195	type R struct{ A, B int }
196	var result []R
197
198	assertResult := func() {
199		c.Assert(len(result), Equals, 2)
200		c.Assert(result[0].A, Equals, 1)
201		c.Assert(result[0].B, Equals, 2)
202		c.Assert(result[1].A, Equals, 3)
203		c.Assert(result[1].B, Equals, 4)
204	}
205
206	// nil slice
207	err = coll.Find(nil).Sort("a").All(&result)
208	c.Assert(err, IsNil)
209	assertResult()
210
211	// Previously allocated slice
212	allocd := make([]R, 5)
213	result = allocd
214	err = coll.Find(nil).Sort("a").All(&result)
215	c.Assert(err, IsNil)
216	assertResult()
217
218	// Ensure result is backed by the originally allocated array
219	c.Assert(&result[0], Equals, &allocd[0])
220
221	// Non-pointer slice error
222	f := func() { coll.Find(nil).All(result) }
223	c.Assert(f, Panics, "result argument must be a slice address")
224
225	// Non-slice error
226	f = func() { coll.Find(nil).All(new(int)) }
227	c.Assert(f, Panics, "result argument must be a slice address")
228}
229
230func (s *S) TestFindRef(c *C) {
231	session, err := mgo.Dial("localhost:40001")
232	c.Assert(err, IsNil)
233	defer session.Close()
234
235	db1 := session.DB("db1")
236	db1col1 := db1.C("col1")
237
238	db2 := session.DB("db2")
239	db2col1 := db2.C("col1")
240
241	err = db1col1.Insert(M{"_id": 1, "n": 1})
242	c.Assert(err, IsNil)
243	err = db1col1.Insert(M{"_id": 2, "n": 2})
244	c.Assert(err, IsNil)
245	err = db2col1.Insert(M{"_id": 2, "n": 3})
246	c.Assert(err, IsNil)
247
248	result := struct{ N int }{}
249
250	ref1 := &mgo.DBRef{Collection: "col1", Id: 1}
251	ref2 := &mgo.DBRef{Collection: "col1", Id: 2, Database: "db2"}
252
253	err = db1.FindRef(ref1).One(&result)
254	c.Assert(err, IsNil)
255	c.Assert(result.N, Equals, 1)
256
257	err = db1.FindRef(ref2).One(&result)
258	c.Assert(err, IsNil)
259	c.Assert(result.N, Equals, 3)
260
261	err = db2.FindRef(ref1).One(&result)
262	c.Assert(err, Equals, mgo.ErrNotFound)
263
264	err = db2.FindRef(ref2).One(&result)
265	c.Assert(err, IsNil)
266	c.Assert(result.N, Equals, 3)
267
268	err = session.FindRef(ref2).One(&result)
269	c.Assert(err, IsNil)
270	c.Assert(result.N, Equals, 3)
271
272	f := func() { session.FindRef(ref1).One(&result) }
273	c.Assert(f, PanicMatches, "Can't resolve database for &mgo.DBRef{Collection:\"col1\", Id:1, Database:\"\"}")
274}
275
276func (s *S) TestDatabaseAndCollectionNames(c *C) {
277	session, err := mgo.Dial("localhost:40001")
278	c.Assert(err, IsNil)
279	defer session.Close()
280
281	db1 := session.DB("db1")
282	db1col1 := db1.C("col1")
283	db1col2 := db1.C("col2")
284
285	db2 := session.DB("db2")
286	db2col1 := db2.C("col3")
287
288	err = db1col1.Insert(M{"_id": 1})
289	c.Assert(err, IsNil)
290	err = db1col2.Insert(M{"_id": 1})
291	c.Assert(err, IsNil)
292	err = db2col1.Insert(M{"_id": 1})
293	c.Assert(err, IsNil)
294
295	names, err := session.DatabaseNames()
296	c.Assert(err, IsNil)
297	c.Assert(filterDBs(names), DeepEquals, []string{"db1", "db2"})
298
299	// Try to exercise cursor logic. 2.8.0-rc3 still ignores this.
300	session.SetBatch(2)
301
302	names, err = db1.CollectionNames()
303	c.Assert(err, IsNil)
304	c.Assert(names, DeepEquals, []string{"col1", "col2", "system.indexes"})
305
306	names, err = db2.CollectionNames()
307	c.Assert(err, IsNil)
308	c.Assert(names, DeepEquals, []string{"col3", "system.indexes"})
309}
310
311func (s *S) TestSelect(c *C) {
312	session, err := mgo.Dial("localhost:40001")
313	c.Assert(err, IsNil)
314	defer session.Close()
315
316	coll := session.DB("mydb").C("mycoll")
317	coll.Insert(M{"a": 1, "b": 2})
318
319	result := struct{ A, B int }{}
320
321	err = coll.Find(M{"a": 1}).Select(M{"b": 1}).One(&result)
322	c.Assert(err, IsNil)
323	c.Assert(result.A, Equals, 0)
324	c.Assert(result.B, Equals, 2)
325}
326
327func (s *S) TestInlineMap(c *C) {
328	session, err := mgo.Dial("localhost:40001")
329	c.Assert(err, IsNil)
330	defer session.Close()
331
332	coll := session.DB("mydb").C("mycoll")
333
334	var v, result1 struct {
335		A int
336		M map[string]int ",inline"
337	}
338
339	v.A = 1
340	v.M = map[string]int{"b": 2}
341	err = coll.Insert(v)
342	c.Assert(err, IsNil)
343
344	noId := M{"_id": 0}
345
346	err = coll.Find(nil).Select(noId).One(&result1)
347	c.Assert(err, IsNil)
348	c.Assert(result1.A, Equals, 1)
349	c.Assert(result1.M, DeepEquals, map[string]int{"b": 2})
350
351	var result2 M
352	err = coll.Find(nil).Select(noId).One(&result2)
353	c.Assert(err, IsNil)
354	c.Assert(result2, DeepEquals, M{"a": 1, "b": 2})
355
356}
357
358func (s *S) TestUpdate(c *C) {
359	session, err := mgo.Dial("localhost:40001")
360	c.Assert(err, IsNil)
361	defer session.Close()
362
363	coll := session.DB("mydb").C("mycoll")
364
365	ns := []int{40, 41, 42, 43, 44, 45, 46}
366	for _, n := range ns {
367		err := coll.Insert(M{"k": n, "n": n})
368		c.Assert(err, IsNil)
369	}
370
371	// No changes is a no-op and shouldn't return an error.
372	err = coll.Update(M{"k": 42}, M{"$set": M{"n": 42}})
373	c.Assert(err, IsNil)
374
375	err = coll.Update(M{"k": 42}, M{"$inc": M{"n": 1}})
376	c.Assert(err, IsNil)
377
378	result := make(M)
379	err = coll.Find(M{"k": 42}).One(result)
380	c.Assert(err, IsNil)
381	c.Assert(result["n"], Equals, 43)
382
383	err = coll.Update(M{"k": 47}, M{"k": 47, "n": 47})
384	c.Assert(err, Equals, mgo.ErrNotFound)
385
386	err = coll.Find(M{"k": 47}).One(result)
387	c.Assert(err, Equals, mgo.ErrNotFound)
388}
389
390func (s *S) TestUpdateId(c *C) {
391	session, err := mgo.Dial("localhost:40001")
392	c.Assert(err, IsNil)
393	defer session.Close()
394
395	coll := session.DB("mydb").C("mycoll")
396
397	ns := []int{40, 41, 42, 43, 44, 45, 46}
398	for _, n := range ns {
399		err := coll.Insert(M{"_id": n, "n": n})
400		c.Assert(err, IsNil)
401	}
402
403	err = coll.UpdateId(42, M{"$inc": M{"n": 1}})
404	c.Assert(err, IsNil)
405
406	result := make(M)
407	err = coll.FindId(42).One(result)
408	c.Assert(err, IsNil)
409	c.Assert(result["n"], Equals, 43)
410
411	err = coll.UpdateId(47, M{"k": 47, "n": 47})
412	c.Assert(err, Equals, mgo.ErrNotFound)
413
414	err = coll.FindId(47).One(result)
415	c.Assert(err, Equals, mgo.ErrNotFound)
416}
417
418func (s *S) TestUpdateNil(c *C) {
419	session, err := mgo.Dial("localhost:40001")
420	c.Assert(err, IsNil)
421	defer session.Close()
422
423	coll := session.DB("mydb").C("mycoll")
424
425	err = coll.Insert(M{"k": 42, "n": 42})
426	c.Assert(err, IsNil)
427	err = coll.Update(nil, M{"$inc": M{"n": 1}})
428	c.Assert(err, IsNil)
429
430	result := make(M)
431	err = coll.Find(M{"k": 42}).One(result)
432	c.Assert(err, IsNil)
433	c.Assert(result["n"], Equals, 43)
434
435	err = coll.Insert(M{"k": 45, "n": 45})
436	c.Assert(err, IsNil)
437	_, err = coll.UpdateAll(nil, M{"$inc": M{"n": 1}})
438	c.Assert(err, IsNil)
439
440	err = coll.Find(M{"k": 42}).One(result)
441	c.Assert(err, IsNil)
442	c.Assert(result["n"], Equals, 44)
443	err = coll.Find(M{"k": 45}).One(result)
444	c.Assert(err, IsNil)
445	c.Assert(result["n"], Equals, 46)
446}
447
448func (s *S) TestUpsert(c *C) {
449	session, err := mgo.Dial("localhost:40001")
450	c.Assert(err, IsNil)
451	defer session.Close()
452
453	coll := session.DB("mydb").C("mycoll")
454
455	ns := []int{40, 41, 42, 43, 44, 45, 46}
456	for _, n := range ns {
457		err := coll.Insert(bson.D{{"k", n}, {"n", n}})
458		c.Assert(err, IsNil)
459	}
460
461	info, err := coll.Upsert(M{"k": 42}, bson.D{{"k", 42}, {"n", 24}})
462	c.Assert(err, IsNil)
463	c.Assert(info.Updated, Equals, 1)
464	c.Assert(info.Matched, Equals, 1)
465	c.Assert(info.UpsertedId, IsNil)
466
467	result := M{}
468	err = coll.Find(M{"k": 42}).One(result)
469	c.Assert(err, IsNil)
470	c.Assert(result["n"], Equals, 24)
471
472	// Match but do not change.
473	info, err = coll.Upsert(M{"k": 42}, bson.D{{"k", 42}, {"n", 24}})
474	c.Assert(err, IsNil)
475	c.Assert(info.Updated, Equals, 1) // On 2.6+ this feels like a server mistake.
476	c.Assert(info.Matched, Equals, 1)
477	c.Assert(info.UpsertedId, IsNil)
478
479	// Insert with internally created id.
480	info, err = coll.Upsert(M{"k": 47}, M{"k": 47, "n": 47})
481	c.Assert(err, IsNil)
482	c.Assert(info.Updated, Equals, 0)
483	c.Assert(info.Matched, Equals, 0)
484	c.Assert(info.UpsertedId, NotNil)
485
486	err = coll.Find(M{"k": 47}).One(result)
487	c.Assert(err, IsNil)
488	c.Assert(result["n"], Equals, 47)
489
490	result = M{}
491	err = coll.Find(M{"_id": info.UpsertedId}).One(result)
492	c.Assert(err, IsNil)
493	c.Assert(result["n"], Equals, 47)
494
495	// Insert with provided id.
496	info, err = coll.Upsert(M{"k": 48}, M{"k": 48, "n": 48, "_id": 48})
497	c.Assert(err, IsNil)
498	c.Assert(info.Updated, Equals, 0)
499	c.Assert(info.Matched, Equals, 0)
500	if s.versionAtLeast(2, 6) {
501		c.Assert(info.UpsertedId, Equals, 48)
502	} else {
503		c.Assert(info.UpsertedId, IsNil) // Unfortunate, but that's what Mongo gave us.
504	}
505
506	err = coll.Find(M{"k": 48}).One(result)
507	c.Assert(err, IsNil)
508	c.Assert(result["n"], Equals, 48)
509}
510
511func (s *S) TestUpsertId(c *C) {
512	session, err := mgo.Dial("localhost:40001")
513	c.Assert(err, IsNil)
514	defer session.Close()
515
516	coll := session.DB("mydb").C("mycoll")
517
518	ns := []int{40, 41, 42, 43, 44, 45, 46}
519	for _, n := range ns {
520		err := coll.Insert(M{"_id": n, "n": n})
521		c.Assert(err, IsNil)
522	}
523
524	info, err := coll.UpsertId(42, M{"n": 24})
525	c.Assert(err, IsNil)
526	c.Assert(info.Updated, Equals, 1)
527	c.Assert(info.UpsertedId, IsNil)
528
529	result := M{}
530	err = coll.FindId(42).One(result)
531	c.Assert(err, IsNil)
532	c.Assert(result["n"], Equals, 24)
533
534	info, err = coll.UpsertId(47, M{"_id": 47, "n": 47})
535	c.Assert(err, IsNil)
536	c.Assert(info.Updated, Equals, 0)
537	if s.versionAtLeast(2, 6) {
538		c.Assert(info.UpsertedId, Equals, 47)
539	} else {
540		c.Assert(info.UpsertedId, IsNil)
541	}
542
543	err = coll.FindId(47).One(result)
544	c.Assert(err, IsNil)
545	c.Assert(result["n"], Equals, 47)
546}
547
548func (s *S) TestUpdateAll(c *C) {
549	session, err := mgo.Dial("localhost:40001")
550	c.Assert(err, IsNil)
551	defer session.Close()
552
553	coll := session.DB("mydb").C("mycoll")
554
555	ns := []int{40, 41, 42, 43, 44, 45, 46}
556	for _, n := range ns {
557		err := coll.Insert(M{"k": n, "n": n})
558		c.Assert(err, IsNil)
559	}
560
561	info, err := coll.UpdateAll(M{"k": M{"$gt": 42}}, M{"$unset": M{"missing": 1}})
562	c.Assert(err, IsNil)
563	if s.versionAtLeast(2, 6) {
564		c.Assert(info.Updated, Equals, 0)
565		c.Assert(info.Matched, Equals, 4)
566	} else {
567		c.Assert(info.Updated, Equals, 4)
568		c.Assert(info.Matched, Equals, 4)
569	}
570
571	info, err = coll.UpdateAll(M{"k": M{"$gt": 42}}, M{"$inc": M{"n": 1}})
572	c.Assert(err, IsNil)
573	c.Assert(info.Updated, Equals, 4)
574	c.Assert(info.Matched, Equals, 4)
575
576	result := make(M)
577	err = coll.Find(M{"k": 42}).One(result)
578	c.Assert(err, IsNil)
579	c.Assert(result["n"], Equals, 42)
580
581	err = coll.Find(M{"k": 43}).One(result)
582	c.Assert(err, IsNil)
583	c.Assert(result["n"], Equals, 44)
584
585	err = coll.Find(M{"k": 44}).One(result)
586	c.Assert(err, IsNil)
587	c.Assert(result["n"], Equals, 45)
588
589	if !s.versionAtLeast(2, 6) {
590		// 2.6 made this invalid.
591		info, err = coll.UpdateAll(M{"k": 47}, M{"k": 47, "n": 47})
592		c.Assert(err, Equals, nil)
593		c.Assert(info.Updated, Equals, 0)
594	}
595}
596
597func (s *S) TestRemove(c *C) {
598	session, err := mgo.Dial("localhost:40001")
599	c.Assert(err, IsNil)
600	defer session.Close()
601
602	coll := session.DB("mydb").C("mycoll")
603
604	ns := []int{40, 41, 42, 43, 44, 45, 46}
605	for _, n := range ns {
606		err := coll.Insert(M{"n": n})
607		c.Assert(err, IsNil)
608	}
609
610	err = coll.Remove(M{"n": M{"$gt": 42}})
611	c.Assert(err, IsNil)
612
613	result := &struct{ N int }{}
614	err = coll.Find(M{"n": 42}).One(result)
615	c.Assert(err, IsNil)
616	c.Assert(result.N, Equals, 42)
617
618	err = coll.Find(M{"n": 43}).One(result)
619	c.Assert(err, Equals, mgo.ErrNotFound)
620
621	err = coll.Find(M{"n": 44}).One(result)
622	c.Assert(err, IsNil)
623	c.Assert(result.N, Equals, 44)
624}
625
626func (s *S) TestRemoveId(c *C) {
627	session, err := mgo.Dial("localhost:40001")
628	c.Assert(err, IsNil)
629	defer session.Close()
630
631	coll := session.DB("mydb").C("mycoll")
632
633	err = coll.Insert(M{"_id": 40}, M{"_id": 41}, M{"_id": 42})
634	c.Assert(err, IsNil)
635
636	err = coll.RemoveId(41)
637	c.Assert(err, IsNil)
638
639	c.Assert(coll.FindId(40).One(nil), IsNil)
640	c.Assert(coll.FindId(41).One(nil), Equals, mgo.ErrNotFound)
641	c.Assert(coll.FindId(42).One(nil), IsNil)
642}
643
644func (s *S) TestRemoveUnsafe(c *C) {
645	session, err := mgo.Dial("localhost:40001")
646	c.Assert(err, IsNil)
647	defer session.Close()
648
649	session.SetSafe(nil)
650
651	coll := session.DB("mydb").C("mycoll")
652
653	err = coll.Insert(M{"_id": 40}, M{"_id": 41}, M{"_id": 42})
654	c.Assert(err, IsNil)
655
656	err = coll.RemoveId(41)
657	c.Assert(err, IsNil)
658
659	c.Assert(coll.FindId(40).One(nil), IsNil)
660	c.Assert(coll.FindId(41).One(nil), Equals, mgo.ErrNotFound)
661	c.Assert(coll.FindId(42).One(nil), IsNil)
662}
663
664func (s *S) TestRemoveAll(c *C) {
665	session, err := mgo.Dial("localhost:40001")
666	c.Assert(err, IsNil)
667	defer session.Close()
668
669	coll := session.DB("mydb").C("mycoll")
670
671	ns := []int{40, 41, 42, 43, 44, 45, 46}
672	for _, n := range ns {
673		err := coll.Insert(M{"n": n})
674		c.Assert(err, IsNil)
675	}
676
677	info, err := coll.RemoveAll(M{"n": M{"$gt": 42}})
678	c.Assert(err, IsNil)
679	c.Assert(info.Updated, Equals, 0)
680	c.Assert(info.Removed, Equals, 4)
681	c.Assert(info.Matched, Equals, 4)
682	c.Assert(info.UpsertedId, IsNil)
683
684	result := &struct{ N int }{}
685	err = coll.Find(M{"n": 42}).One(result)
686	c.Assert(err, IsNil)
687	c.Assert(result.N, Equals, 42)
688
689	err = coll.Find(M{"n": 43}).One(result)
690	c.Assert(err, Equals, mgo.ErrNotFound)
691
692	err = coll.Find(M{"n": 44}).One(result)
693	c.Assert(err, Equals, mgo.ErrNotFound)
694
695	info, err = coll.RemoveAll(nil)
696	c.Assert(err, IsNil)
697	c.Assert(info.Updated, Equals, 0)
698	c.Assert(info.Removed, Equals, 3)
699	c.Assert(info.Matched, Equals, 3)
700	c.Assert(info.UpsertedId, IsNil)
701
702	n, err := coll.Find(nil).Count()
703	c.Assert(err, IsNil)
704	c.Assert(n, Equals, 0)
705}
706
707func (s *S) TestDropDatabase(c *C) {
708	session, err := mgo.Dial("localhost:40001")
709	c.Assert(err, IsNil)
710	defer session.Close()
711
712	db1 := session.DB("db1")
713	db1.C("col").Insert(M{"_id": 1})
714
715	db2 := session.DB("db2")
716	db2.C("col").Insert(M{"_id": 1})
717
718	err = db1.DropDatabase()
719	c.Assert(err, IsNil)
720
721	names, err := session.DatabaseNames()
722	c.Assert(err, IsNil)
723	c.Assert(filterDBs(names), DeepEquals, []string{"db2"})
724
725	err = db2.DropDatabase()
726	c.Assert(err, IsNil)
727
728	names, err = session.DatabaseNames()
729	c.Assert(err, IsNil)
730	c.Assert(filterDBs(names), DeepEquals, []string{})
731}
732
733func filterDBs(dbs []string) []string {
734	var i int
735	for _, name := range dbs {
736		switch name {
737		case "admin", "local":
738		default:
739			dbs[i] = name
740			i++
741		}
742	}
743	if len(dbs) == 0 {
744		return []string{}
745	}
746	return dbs[:i]
747}
748
749func (s *S) TestDropCollection(c *C) {
750	session, err := mgo.Dial("localhost:40001")
751	c.Assert(err, IsNil)
752	defer session.Close()
753
754	db := session.DB("db1")
755	db.C("col1").Insert(M{"_id": 1})
756	db.C("col2").Insert(M{"_id": 1})
757
758	err = db.C("col1").DropCollection()
759	c.Assert(err, IsNil)
760
761	names, err := db.CollectionNames()
762	c.Assert(err, IsNil)
763	c.Assert(names, DeepEquals, []string{"col2", "system.indexes"})
764
765	err = db.C("col2").DropCollection()
766	c.Assert(err, IsNil)
767
768	names, err = db.CollectionNames()
769	c.Assert(err, IsNil)
770	c.Assert(names, DeepEquals, []string{"system.indexes"})
771}
772
773func (s *S) TestCreateCollectionCapped(c *C) {
774	session, err := mgo.Dial("localhost:40001")
775	c.Assert(err, IsNil)
776	defer session.Close()
777
778	coll := session.DB("mydb").C("mycoll")
779
780	info := &mgo.CollectionInfo{
781		Capped:   true,
782		MaxBytes: 1024,
783		MaxDocs:  3,
784	}
785	err = coll.Create(info)
786	c.Assert(err, IsNil)
787
788	ns := []int{1, 2, 3, 4, 5}
789	for _, n := range ns {
790		err := coll.Insert(M{"n": n})
791		c.Assert(err, IsNil)
792	}
793
794	n, err := coll.Find(nil).Count()
795	c.Assert(err, IsNil)
796	c.Assert(n, Equals, 3)
797}
798
799func (s *S) TestCreateCollectionNoIndex(c *C) {
800	session, err := mgo.Dial("localhost:40001")
801	c.Assert(err, IsNil)
802	defer session.Close()
803
804	coll := session.DB("mydb").C("mycoll")
805
806	info := &mgo.CollectionInfo{
807		DisableIdIndex: true,
808	}
809	err = coll.Create(info)
810	c.Assert(err, IsNil)
811
812	err = coll.Insert(M{"n": 1})
813	c.Assert(err, IsNil)
814
815	indexes, err := coll.Indexes()
816	c.Assert(indexes, HasLen, 0)
817}
818
819func (s *S) TestCreateCollectionForceIndex(c *C) {
820	session, err := mgo.Dial("localhost:40001")
821	c.Assert(err, IsNil)
822	defer session.Close()
823
824	coll := session.DB("mydb").C("mycoll")
825
826	info := &mgo.CollectionInfo{
827		ForceIdIndex: true,
828		Capped:       true,
829		MaxBytes:     1024,
830	}
831	err = coll.Create(info)
832	c.Assert(err, IsNil)
833
834	err = coll.Insert(M{"n": 1})
835	c.Assert(err, IsNil)
836
837	indexes, err := coll.Indexes()
838	c.Assert(indexes, HasLen, 1)
839}
840
841func (s *S) TestCreateCollectionValidator(c *C) {
842	if !s.versionAtLeast(3, 2) {
843		c.Skip("validation depends on MongoDB 3.2+")
844	}
845	session, err := mgo.Dial("localhost:40001")
846	c.Assert(err, IsNil)
847	defer session.Close()
848
849	db := session.DB("mydb")
850	coll := db.C("mycoll")
851
852	// Test Validator.
853	info := &mgo.CollectionInfo{
854		Validator: M{"b": M{"$exists": true}},
855	}
856	err = coll.Create(info)
857	c.Assert(err, IsNil)
858	err = coll.Insert(M{"a": 1})
859	c.Assert(err, ErrorMatches, "Document failed validation")
860	err = coll.DropCollection()
861	c.Assert(err, IsNil)
862
863	// Test ValidatorAction.
864	info = &mgo.CollectionInfo{
865		Validator:        M{"b": M{"$exists": true}},
866		ValidationAction: "warn",
867	}
868	err = coll.Create(info)
869	c.Assert(err, IsNil)
870	err = coll.Insert(M{"a": 1})
871	c.Assert(err, IsNil)
872	err = coll.DropCollection()
873	c.Assert(err, IsNil)
874
875	// Test ValidationLevel.
876	info = &mgo.CollectionInfo{
877		Validator:       M{"a": M{"$exists": true}},
878		ValidationLevel: "moderate",
879	}
880	err = coll.Create(info)
881	err = coll.Insert(M{"a": 1})
882	c.Assert(err, IsNil)
883	err = db.Run(bson.D{{"collMod", "mycoll"}, {"validator", M{"b": M{"$exists": true}}}}, nil)
884	c.Assert(err, IsNil)
885	err = coll.Insert(M{"a": 2})
886	c.Assert(err, ErrorMatches, "Document failed validation")
887	err = coll.Update(M{"a": 1}, M{"c": 1})
888	c.Assert(err, IsNil)
889	err = coll.DropCollection()
890	c.Assert(err, IsNil)
891}
892
893func (s *S) TestCreateCollectionStorageEngine(c *C) {
894	if !s.versionAtLeast(3, 0) {
895		c.Skip("storageEngine option depends on MongoDB 3.0+")
896	}
897	session, err := mgo.Dial("localhost:40001")
898	c.Assert(err, IsNil)
899	defer session.Close()
900
901	db := session.DB("mydb")
902	coll := db.C("mycoll")
903
904	info := &mgo.CollectionInfo{
905		StorageEngine: M{"test": M{}},
906	}
907	err = coll.Create(info)
908	c.Assert(err, ErrorMatches, "test is not a registered storage engine for this server")
909}
910
911func (s *S) TestIsDupValues(c *C) {
912	c.Assert(mgo.IsDup(nil), Equals, false)
913	c.Assert(mgo.IsDup(&mgo.LastError{Code: 1}), Equals, false)
914	c.Assert(mgo.IsDup(&mgo.QueryError{Code: 1}), Equals, false)
915	c.Assert(mgo.IsDup(&mgo.LastError{Code: 11000}), Equals, true)
916	c.Assert(mgo.IsDup(&mgo.QueryError{Code: 11000}), Equals, true)
917	c.Assert(mgo.IsDup(&mgo.LastError{Code: 11001}), Equals, true)
918	c.Assert(mgo.IsDup(&mgo.QueryError{Code: 11001}), Equals, true)
919	c.Assert(mgo.IsDup(&mgo.LastError{Code: 12582}), Equals, true)
920	c.Assert(mgo.IsDup(&mgo.QueryError{Code: 12582}), Equals, true)
921	lerr := &mgo.LastError{Code: 16460, Err: "error inserting 1 documents to shard ... caused by :: E11000 duplicate key error index: ..."}
922	c.Assert(mgo.IsDup(lerr), Equals, true)
923}
924
925func (s *S) TestIsDupPrimary(c *C) {
926	session, err := mgo.Dial("localhost:40001")
927	c.Assert(err, IsNil)
928	defer session.Close()
929
930	coll := session.DB("mydb").C("mycoll")
931
932	err = coll.Insert(M{"_id": 1})
933	c.Assert(err, IsNil)
934	err = coll.Insert(M{"_id": 1})
935	c.Assert(err, ErrorMatches, ".*duplicate key error.*")
936	c.Assert(mgo.IsDup(err), Equals, true)
937}
938
939func (s *S) TestIsDupUnique(c *C) {
940	session, err := mgo.Dial("localhost:40001")
941	c.Assert(err, IsNil)
942	defer session.Close()
943
944	index := mgo.Index{
945		Key:    []string{"a", "b"},
946		Unique: true,
947	}
948
949	coll := session.DB("mydb").C("mycoll")
950
951	err = coll.EnsureIndex(index)
952	c.Assert(err, IsNil)
953
954	err = coll.Insert(M{"a": 1, "b": 1})
955	c.Assert(err, IsNil)
956	err = coll.Insert(M{"a": 1, "b": 1})
957	c.Assert(err, ErrorMatches, ".*duplicate key error.*")
958	c.Assert(mgo.IsDup(err), Equals, true)
959}
960
961func (s *S) TestIsDupCapped(c *C) {
962	session, err := mgo.Dial("localhost:40001")
963	c.Assert(err, IsNil)
964	defer session.Close()
965
966	coll := session.DB("mydb").C("mycoll")
967
968	info := &mgo.CollectionInfo{
969		ForceIdIndex: true,
970		Capped:       true,
971		MaxBytes:     1024,
972	}
973	err = coll.Create(info)
974	c.Assert(err, IsNil)
975
976	err = coll.Insert(M{"_id": 1})
977	c.Assert(err, IsNil)
978	err = coll.Insert(M{"_id": 1})
979	// The error was different for capped collections before 2.6.
980	c.Assert(err, ErrorMatches, ".*duplicate key.*")
981	// The issue is reduced by using IsDup.
982	c.Assert(mgo.IsDup(err), Equals, true)
983}
984
985func (s *S) TestIsDupFindAndModify(c *C) {
986	session, err := mgo.Dial("localhost:40001")
987	c.Assert(err, IsNil)
988	defer session.Close()
989
990	coll := session.DB("mydb").C("mycoll")
991
992	err = coll.EnsureIndex(mgo.Index{Key: []string{"n"}, Unique: true})
993	c.Assert(err, IsNil)
994
995	err = coll.Insert(M{"n": 1})
996	c.Assert(err, IsNil)
997	err = coll.Insert(M{"n": 2})
998	c.Assert(err, IsNil)
999	_, err = coll.Find(M{"n": 1}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, bson.M{})
1000	c.Assert(err, ErrorMatches, ".*duplicate key error.*")
1001	c.Assert(mgo.IsDup(err), Equals, true)
1002}
1003
1004func (s *S) TestIsDupRetryUpsert(c *C) {
1005	session, err := mgo.Dial("localhost:40001")
1006	c.Assert(err, IsNil)
1007	defer session.Close()
1008
1009	coll := session.DB("mydb").C("mycoll")
1010
1011	err = coll.Insert(bson.M{"_id": 1, "x": 1})
1012	c.Assert(err, IsNil)
1013
1014	_, err = coll.Upsert(bson.M{"_id": 1, "x": 2}, bson.M{"$set": bson.M{"x": 3}})
1015	c.Assert(mgo.IsDup(err), Equals, true)
1016
1017	_, err = coll.Find(bson.M{"_id": 1, "x": 2}).Apply(mgo.Change{
1018		Update: bson.M{"$set": bson.M{"x": 3}},
1019		Upsert: true,
1020	}, nil)
1021	c.Assert(mgo.IsDup(err), Equals, true)
1022}
1023
1024func (s *S) TestFindAndModify(c *C) {
1025	session, err := mgo.Dial("localhost:40011")
1026	c.Assert(err, IsNil)
1027	defer session.Close()
1028
1029	coll := session.DB("mydb").C("mycoll")
1030
1031	err = coll.Insert(M{"n": 42})
1032
1033	session.SetMode(mgo.Monotonic, true)
1034
1035	result := M{}
1036	info, err := coll.Find(M{"n": 42}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, result)
1037	c.Assert(err, IsNil)
1038	c.Assert(result["n"], Equals, 42)
1039	c.Assert(info.Updated, Equals, 1)
1040	c.Assert(info.Matched, Equals, 1)
1041	c.Assert(info.Removed, Equals, 0)
1042	c.Assert(info.UpsertedId, IsNil)
1043
1044	// A nil result parameter should be acceptable.
1045	info, err = coll.Find(M{"n": 43}).Apply(mgo.Change{Update: M{"$unset": M{"missing": 1}}}, nil)
1046	c.Assert(err, IsNil)
1047	c.Assert(info.Updated, Equals, 1) // On 2.6+ this feels like a server mistake.
1048	c.Assert(info.Matched, Equals, 1)
1049	c.Assert(info.Removed, Equals, 0)
1050	c.Assert(info.UpsertedId, IsNil)
1051
1052	result = M{}
1053	info, err = coll.Find(M{"n": 43}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}, ReturnNew: true}, result)
1054	c.Assert(err, IsNil)
1055	c.Assert(result["n"], Equals, 44)
1056	c.Assert(info.Updated, Equals, 1)
1057	c.Assert(info.Removed, Equals, 0)
1058	c.Assert(info.UpsertedId, IsNil)
1059
1060	result = M{}
1061	info, err = coll.Find(M{"n": 50}).Apply(mgo.Change{Upsert: true, Update: M{"n": 51, "o": 52}}, result)
1062	c.Assert(err, IsNil)
1063	c.Assert(result["n"], IsNil)
1064	c.Assert(info.Updated, Equals, 0)
1065	c.Assert(info.Removed, Equals, 0)
1066	c.Assert(info.UpsertedId, NotNil)
1067
1068	result = M{}
1069	info, err = coll.Find(nil).Sort("-n").Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}, ReturnNew: true}, result)
1070	c.Assert(err, IsNil)
1071	c.Assert(result["n"], Equals, 52)
1072	c.Assert(info.Updated, Equals, 1)
1073	c.Assert(info.Removed, Equals, 0)
1074	c.Assert(info.UpsertedId, IsNil)
1075
1076	result = M{}
1077	info, err = coll.Find(M{"n": 52}).Select(M{"o": 1}).Apply(mgo.Change{Remove: true}, result)
1078	c.Assert(err, IsNil)
1079	c.Assert(result["n"], IsNil)
1080	c.Assert(result["o"], Equals, 52)
1081	c.Assert(info.Updated, Equals, 0)
1082	c.Assert(info.Removed, Equals, 1)
1083	c.Assert(info.UpsertedId, IsNil)
1084
1085	result = M{}
1086	info, err = coll.Find(M{"n": 60}).Apply(mgo.Change{Remove: true}, result)
1087	c.Assert(err, Equals, mgo.ErrNotFound)
1088	c.Assert(len(result), Equals, 0)
1089	c.Assert(info, IsNil)
1090}
1091
1092func (s *S) TestFindAndModifyBug997828(c *C) {
1093	session, err := mgo.Dial("localhost:40001")
1094	c.Assert(err, IsNil)
1095	defer session.Close()
1096
1097	coll := session.DB("mydb").C("mycoll")
1098
1099	err = coll.Insert(M{"n": "not-a-number"})
1100
1101	result := make(M)
1102	_, err = coll.Find(M{"n": "not-a-number"}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, result)
1103	c.Assert(err, ErrorMatches, `(exception: )?Cannot apply \$inc .*`)
1104	if s.versionAtLeast(2, 1) {
1105		qerr, _ := err.(*mgo.QueryError)
1106		c.Assert(qerr, NotNil, Commentf("err: %#v", err))
1107		if s.versionAtLeast(2, 6) {
1108			// Oh, the dance of error codes. :-(
1109			c.Assert(qerr.Code, Equals, 16837)
1110		} else {
1111			c.Assert(qerr.Code, Equals, 10140)
1112		}
1113	} else {
1114		lerr, _ := err.(*mgo.LastError)
1115		c.Assert(lerr, NotNil, Commentf("err: %#v", err))
1116		c.Assert(lerr.Code, Equals, 10140)
1117	}
1118}
1119
1120func (s *S) TestFindAndModifyErrmsgDoc(c *C) {
1121	session, err := mgo.Dial("localhost:40001")
1122	c.Assert(err, IsNil)
1123	defer session.Close()
1124
1125	coll := session.DB("mydb").C("mycoll")
1126
1127	err = coll.Insert(M{"errmsg": "an error"})
1128
1129	var result M
1130	_, err = coll.Find(M{}).Apply(mgo.Change{Update: M{"$set": M{"n": 1}}}, &result)
1131	c.Assert(err, IsNil)
1132}
1133
1134func (s *S) TestCountCollection(c *C) {
1135	session, err := mgo.Dial("localhost:40001")
1136	c.Assert(err, IsNil)
1137	defer session.Close()
1138
1139	coll := session.DB("mydb").C("mycoll")
1140
1141	ns := []int{40, 41, 42}
1142	for _, n := range ns {
1143		err := coll.Insert(M{"n": n})
1144		c.Assert(err, IsNil)
1145	}
1146
1147	n, err := coll.Count()
1148	c.Assert(err, IsNil)
1149	c.Assert(n, Equals, 3)
1150}
1151
1152func (s *S) TestCountQuery(c *C) {
1153	session, err := mgo.Dial("localhost:40001")
1154	c.Assert(err, IsNil)
1155	defer session.Close()
1156
1157	coll := session.DB("mydb").C("mycoll")
1158
1159	ns := []int{40, 41, 42}
1160	for _, n := range ns {
1161		err := coll.Insert(M{"n": n})
1162		c.Assert(err, IsNil)
1163	}
1164
1165	n, err := coll.Find(M{"n": M{"$gt": 40}}).Count()
1166	c.Assert(err, IsNil)
1167	c.Assert(n, Equals, 2)
1168}
1169
1170func (s *S) TestCountQuerySorted(c *C) {
1171	session, err := mgo.Dial("localhost:40001")
1172	c.Assert(err, IsNil)
1173	defer session.Close()
1174
1175	coll := session.DB("mydb").C("mycoll")
1176
1177	ns := []int{40, 41, 42}
1178	for _, n := range ns {
1179		err := coll.Insert(M{"n": n})
1180		c.Assert(err, IsNil)
1181	}
1182
1183	n, err := coll.Find(M{"n": M{"$gt": 40}}).Sort("n").Count()
1184	c.Assert(err, IsNil)
1185	c.Assert(n, Equals, 2)
1186}
1187
1188func (s *S) TestCountSkipLimit(c *C) {
1189	session, err := mgo.Dial("localhost:40001")
1190	c.Assert(err, IsNil)
1191	defer session.Close()
1192
1193	coll := session.DB("mydb").C("mycoll")
1194
1195	ns := []int{40, 41, 42, 43, 44}
1196	for _, n := range ns {
1197		err := coll.Insert(M{"n": n})
1198		c.Assert(err, IsNil)
1199	}
1200
1201	n, err := coll.Find(nil).Skip(1).Limit(3).Count()
1202	c.Assert(err, IsNil)
1203	c.Assert(n, Equals, 3)
1204
1205	n, err = coll.Find(nil).Skip(1).Limit(5).Count()
1206	c.Assert(err, IsNil)
1207	c.Assert(n, Equals, 4)
1208}
1209
1210func (s *S) TestQueryExplain(c *C) {
1211	session, err := mgo.Dial("localhost:40001")
1212	c.Assert(err, IsNil)
1213	defer session.Close()
1214
1215	coll := session.DB("mydb").C("mycoll")
1216
1217	ns := []int{40, 41, 42}
1218	for _, n := range ns {
1219		err := coll.Insert(M{"n": n})
1220		c.Assert(err, IsNil)
1221	}
1222
1223	m := M{}
1224	query := coll.Find(nil).Limit(2)
1225	err = query.Explain(m)
1226	c.Assert(err, IsNil)
1227	if m["queryPlanner"] != nil {
1228		c.Assert(m["executionStats"].(M)["totalDocsExamined"], Equals, 2)
1229	} else {
1230		c.Assert(m["cursor"], Equals, "BasicCursor")
1231		c.Assert(m["nscanned"], Equals, 2)
1232		c.Assert(m["n"], Equals, 2)
1233	}
1234
1235	n := 0
1236	var result M
1237	iter := query.Iter()
1238	for iter.Next(&result) {
1239		n++
1240	}
1241	c.Assert(iter.Close(), IsNil)
1242	c.Assert(n, Equals, 2)
1243}
1244
1245func (s *S) TestQuerySetMaxScan(c *C) {
1246	session, err := mgo.Dial("localhost:40001")
1247	c.Assert(err, IsNil)
1248	defer session.Close()
1249	coll := session.DB("mydb").C("mycoll")
1250
1251	ns := []int{40, 41, 42}
1252	for _, n := range ns {
1253		err := coll.Insert(M{"n": n})
1254		c.Assert(err, IsNil)
1255	}
1256
1257	query := coll.Find(nil).SetMaxScan(2)
1258	var result []M
1259	err = query.All(&result)
1260	c.Assert(err, IsNil)
1261	c.Assert(result, HasLen, 2)
1262}
1263
1264func (s *S) TestQuerySetMaxTime(c *C) {
1265	if !s.versionAtLeast(2, 6) {
1266		c.Skip("SetMaxTime only supported in 2.6+")
1267	}
1268
1269	session, err := mgo.Dial("localhost:40001")
1270	c.Assert(err, IsNil)
1271	defer session.Close()
1272	coll := session.DB("mydb").C("mycoll")
1273
1274	for i := 0; i < 1000; i++ {
1275		err := coll.Insert(M{"n": i})
1276		c.Assert(err, IsNil)
1277	}
1278
1279	query := coll.Find(nil)
1280	query.SetMaxTime(1 * time.Millisecond)
1281	query.Batch(2)
1282	var result []M
1283	err = query.All(&result)
1284	c.Assert(err, ErrorMatches, "operation exceeded time limit")
1285}
1286
1287func (s *S) TestQueryHint(c *C) {
1288	session, err := mgo.Dial("localhost:40001")
1289	c.Assert(err, IsNil)
1290	defer session.Close()
1291
1292	coll := session.DB("mydb").C("mycoll")
1293	coll.EnsureIndexKey("a")
1294
1295	m := M{}
1296	err = coll.Find(nil).Hint("a").Explain(m)
1297	c.Assert(err, IsNil)
1298
1299	if m["queryPlanner"] != nil {
1300		m = m["queryPlanner"].(M)
1301		m = m["winningPlan"].(M)
1302		m = m["inputStage"].(M)
1303		c.Assert(m["indexName"], Equals, "a_1")
1304	} else {
1305		c.Assert(m["indexBounds"], NotNil)
1306		c.Assert(m["indexBounds"].(M)["a"], NotNil)
1307	}
1308}
1309
1310func (s *S) TestQueryComment(c *C) {
1311	session, err := mgo.Dial("localhost:40001")
1312	c.Assert(err, IsNil)
1313	defer session.Close()
1314
1315	db := session.DB("mydb")
1316	coll := db.C("mycoll")
1317
1318	err = db.Run(bson.M{"profile": 2}, nil)
1319	c.Assert(err, IsNil)
1320
1321	ns := []int{40, 41, 42}
1322	for _, n := range ns {
1323		err := coll.Insert(M{"n": n})
1324		c.Assert(err, IsNil)
1325	}
1326
1327	query := coll.Find(bson.M{"n": 41})
1328	query.Comment("some comment")
1329	err = query.One(nil)
1330	c.Assert(err, IsNil)
1331
1332	query = coll.Find(bson.M{"n": 41})
1333	query.Comment("another comment")
1334	err = query.One(nil)
1335	c.Assert(err, IsNil)
1336
1337	commentField := "query.$comment"
1338	nField := "query.$query.n"
1339	if s.versionAtLeast(3, 2) {
1340		commentField = "query.comment"
1341		nField = "query.filter.n"
1342	}
1343	n, err := session.DB("mydb").C("system.profile").Find(bson.M{nField: 41, commentField: "some comment"}).Count()
1344	c.Assert(err, IsNil)
1345	c.Assert(n, Equals, 1)
1346}
1347
1348func (s *S) TestFindOneNotFound(c *C) {
1349	session, err := mgo.Dial("localhost:40001")
1350	c.Assert(err, IsNil)
1351	defer session.Close()
1352
1353	coll := session.DB("mydb").C("mycoll")
1354
1355	result := struct{ A, B int }{}
1356	err = coll.Find(M{"a": 1}).One(&result)
1357	c.Assert(err, Equals, mgo.ErrNotFound)
1358	c.Assert(err, ErrorMatches, "not found")
1359	c.Assert(err == mgo.ErrNotFound, Equals, true)
1360}
1361
1362func (s *S) TestFindIterNotFound(c *C) {
1363	session, err := mgo.Dial("localhost:40001")
1364	c.Assert(err, IsNil)
1365	defer session.Close()
1366
1367	coll := session.DB("mydb").C("mycoll")
1368
1369	result := struct{ A, B int }{}
1370	iter := coll.Find(M{"a": 1}).Iter()
1371	ok := iter.Next(&result)
1372	c.Assert(ok, Equals, false)
1373	c.Assert(iter.Err(), IsNil)
1374}
1375
1376func (s *S) TestFindNil(c *C) {
1377	session, err := mgo.Dial("localhost:40001")
1378	c.Assert(err, IsNil)
1379	defer session.Close()
1380
1381	coll := session.DB("mydb").C("mycoll")
1382	err = coll.Insert(M{"n": 1})
1383	c.Assert(err, IsNil)
1384
1385	result := struct{ N int }{}
1386
1387	err = coll.Find(nil).One(&result)
1388	c.Assert(err, IsNil)
1389	c.Assert(result.N, Equals, 1)
1390}
1391
1392func (s *S) TestFindId(c *C) {
1393	session, err := mgo.Dial("localhost:40001")
1394	c.Assert(err, IsNil)
1395	defer session.Close()
1396
1397	coll := session.DB("mydb").C("mycoll")
1398	err = coll.Insert(M{"_id": 41, "n": 41})
1399	c.Assert(err, IsNil)
1400	err = coll.Insert(M{"_id": 42, "n": 42})
1401	c.Assert(err, IsNil)
1402
1403	result := struct{ N int }{}
1404
1405	err = coll.FindId(42).One(&result)
1406	c.Assert(err, IsNil)
1407	c.Assert(result.N, Equals, 42)
1408}
1409
1410func (s *S) TestFindIterAll(c *C) {
1411	session, err := mgo.Dial("localhost:40001")
1412	c.Assert(err, IsNil)
1413	defer session.Close()
1414
1415	coll := session.DB("mydb").C("mycoll")
1416
1417	ns := []int{40, 41, 42, 43, 44, 45, 46}
1418	for _, n := range ns {
1419		coll.Insert(M{"n": n})
1420	}
1421
1422	session.Refresh() // Release socket.
1423
1424	mgo.ResetStats()
1425
1426	iter := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2).Iter()
1427	result := struct{ N int }{}
1428	for i := 2; i < 7; i++ {
1429		ok := iter.Next(&result)
1430		c.Assert(ok, Equals, true, Commentf("err=%v", err))
1431		c.Assert(result.N, Equals, ns[i])
1432		if i == 1 {
1433			stats := mgo.GetStats()
1434			c.Assert(stats.ReceivedDocs, Equals, 2)
1435		}
1436	}
1437
1438	ok := iter.Next(&result)
1439	c.Assert(ok, Equals, false)
1440	c.Assert(iter.Close(), IsNil)
1441
1442	session.Refresh() // Release socket.
1443
1444	stats := mgo.GetStats()
1445	c.Assert(stats.SentOps, Equals, 3)     // 1*QUERY_OP + 2*GET_MORE_OP
1446	c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs.
1447	if s.versionAtLeast(3, 2) {
1448		// In 3.2+ responses come in batches inside the op reply docs.
1449		c.Assert(stats.ReceivedDocs, Equals, 3)
1450	} else {
1451		c.Assert(stats.ReceivedDocs, Equals, 5)
1452	}
1453	c.Assert(stats.SocketsInUse, Equals, 0)
1454}
1455
1456func (s *S) TestFindIterTwiceWithSameQuery(c *C) {
1457	session, err := mgo.Dial("localhost:40001")
1458	c.Assert(err, IsNil)
1459	defer session.Close()
1460
1461	coll := session.DB("mydb").C("mycoll")
1462
1463	for i := 40; i != 47; i++ {
1464		err := coll.Insert(M{"n": i})
1465		c.Assert(err, IsNil)
1466	}
1467
1468	query := coll.Find(M{}).Sort("n")
1469
1470	iter1 := query.Skip(1).Iter()
1471	iter2 := query.Skip(2).Iter()
1472
1473	var result struct{ N int }
1474	ok := iter2.Next(&result)
1475	c.Assert(ok, Equals, true)
1476	c.Assert(result.N, Equals, 42)
1477	ok = iter1.Next(&result)
1478	c.Assert(ok, Equals, true)
1479	c.Assert(result.N, Equals, 41)
1480}
1481
1482func (s *S) TestFindIterWithoutResults(c *C) {
1483	session, err := mgo.Dial("localhost:40001")
1484	c.Assert(err, IsNil)
1485	defer session.Close()
1486
1487	coll := session.DB("mydb").C("mycoll")
1488	coll.Insert(M{"n": 42})
1489
1490	iter := coll.Find(M{"n": 0}).Iter()
1491
1492	result := struct{ N int }{}
1493	ok := iter.Next(&result)
1494	c.Assert(ok, Equals, false)
1495	c.Assert(iter.Close(), IsNil)
1496	c.Assert(result.N, Equals, 0)
1497}
1498
1499func (s *S) TestFindIterLimit(c *C) {
1500	session, err := mgo.Dial("localhost:40001")
1501	c.Assert(err, IsNil)
1502	defer session.Close()
1503
1504	coll := session.DB("mydb").C("mycoll")
1505
1506	ns := []int{40, 41, 42, 43, 44, 45, 46}
1507	for _, n := range ns {
1508		err := coll.Insert(M{"n": n})
1509		c.Assert(err, IsNil)
1510	}
1511
1512	session.Refresh() // Release socket.
1513
1514	mgo.ResetStats()
1515
1516	query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Limit(3)
1517	iter := query.Iter()
1518
1519	result := struct{ N int }{}
1520	for i := 2; i < 5; i++ {
1521		ok := iter.Next(&result)
1522		c.Assert(ok, Equals, true)
1523		c.Assert(result.N, Equals, ns[i])
1524	}
1525
1526	ok := iter.Next(&result)
1527	c.Assert(ok, Equals, false)
1528	c.Assert(iter.Close(), IsNil)
1529
1530	session.Refresh() // Release socket.
1531
1532	stats := mgo.GetStats()
1533	if s.versionAtLeast(3, 2) {
1534		// Limit works properly in 3.2+, and results are batched in single doc.
1535		c.Assert(stats.SentOps, Equals, 1)     // 1*QUERY_OP
1536		c.Assert(stats.ReceivedOps, Equals, 1) // and its REPLY_OP
1537		c.Assert(stats.ReceivedDocs, Equals, 1)
1538	} else {
1539		c.Assert(stats.SentOps, Equals, 2)     // 1*QUERY_OP + 1*KILL_CURSORS_OP
1540		c.Assert(stats.ReceivedOps, Equals, 1) // and its REPLY_OP
1541		c.Assert(stats.ReceivedDocs, Equals, 3)
1542	}
1543	c.Assert(stats.SocketsInUse, Equals, 0)
1544}
1545
1546var cursorTimeout = flag.Bool("cursor-timeout", false, "Enable cursor timeout test")
1547
1548func (s *S) TestFindIterCursorTimeout(c *C) {
1549	if !*cursorTimeout {
1550		c.Skip("-cursor-timeout")
1551	}
1552	session, err := mgo.Dial("localhost:40001")
1553	c.Assert(err, IsNil)
1554	defer session.Close()
1555
1556	type Doc struct {
1557		Id int "_id"
1558	}
1559
1560	coll := session.DB("test").C("test")
1561	coll.Remove(nil)
1562	for i := 0; i < 100; i++ {
1563		err = coll.Insert(Doc{i})
1564		c.Assert(err, IsNil)
1565	}
1566
1567	session.SetBatch(1)
1568	iter := coll.Find(nil).Iter()
1569	var doc Doc
1570	if !iter.Next(&doc) {
1571		c.Fatalf("iterator failed to return any documents")
1572	}
1573
1574	for i := 10; i > 0; i-- {
1575		c.Logf("Sleeping... %d minutes to go...", i)
1576		time.Sleep(1*time.Minute + 2*time.Second)
1577	}
1578
1579	// Drain any existing documents that were fetched.
1580	if !iter.Next(&doc) {
1581		c.Fatalf("iterator with timed out cursor failed to return previously cached document")
1582	}
1583	if iter.Next(&doc) {
1584		c.Fatalf("timed out cursor returned document")
1585	}
1586
1587	c.Assert(iter.Err(), Equals, mgo.ErrCursor)
1588}
1589
1590func (s *S) TestTooManyItemsLimitBug(c *C) {
1591	if *fast {
1592		c.Skip("-fast")
1593	}
1594
1595	session, err := mgo.Dial("localhost:40001")
1596	c.Assert(err, IsNil)
1597	defer session.Close()
1598	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))
1599
1600	mgo.SetDebug(false)
1601	coll := session.DB("mydb").C("mycoll")
1602	words := strings.Split("foo bar baz", " ")
1603	for i := 0; i < 5; i++ {
1604		words = append(words, words...)
1605	}
1606	doc := bson.D{{"words", words}}
1607	inserts := 10000
1608	limit := 5000
1609	iters := 0
1610	c.Assert(inserts > limit, Equals, true)
1611	for i := 0; i < inserts; i++ {
1612		err := coll.Insert(&doc)
1613		c.Assert(err, IsNil)
1614	}
1615	iter := coll.Find(nil).Limit(limit).Iter()
1616	for iter.Next(&doc) {
1617		if iters%100 == 0 {
1618			c.Logf("Seen %d docments", iters)
1619		}
1620		iters++
1621	}
1622	c.Assert(iter.Close(), IsNil)
1623	c.Assert(iters, Equals, limit)
1624}
1625
1626func (s *S) TestBatchSizeZeroGetMore(c *C) {
1627	if *fast {
1628		c.Skip("-fast")
1629	}
1630
1631	session, err := mgo.Dial("localhost:40001")
1632	c.Assert(err, IsNil)
1633	defer session.Close()
1634	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))
1635
1636	mgo.SetDebug(false)
1637	coll := session.DB("mydb").C("mycoll")
1638	words := strings.Split("foo bar baz", " ")
1639	for i := 0; i < 5; i++ {
1640		words = append(words, words...)
1641	}
1642	doc := bson.D{{"words", words}}
1643	inserts := 10000
1644	iters := 0
1645	for i := 0; i < inserts; i++ {
1646		err := coll.Insert(&doc)
1647		c.Assert(err, IsNil)
1648	}
1649	iter := coll.Find(nil).Iter()
1650	for iter.Next(&doc) {
1651		if iters%100 == 0 {
1652			c.Logf("Seen %d docments", iters)
1653		}
1654		iters++
1655	}
1656	c.Assert(iter.Close(), IsNil)
1657}
1658
1659func serverCursorsOpen(session *mgo.Session) int {
1660	var result struct {
1661		Cursors struct {
1662			TotalOpen int `bson:"totalOpen"`
1663			TimedOut  int `bson:"timedOut"`
1664		}
1665	}
1666	err := session.Run("serverStatus", &result)
1667	if err != nil {
1668		panic(err)
1669	}
1670	return result.Cursors.TotalOpen
1671}
1672
1673func (s *S) TestFindIterLimitWithMore(c *C) {
1674	session, err := mgo.Dial("localhost:40001")
1675	c.Assert(err, IsNil)
1676	defer session.Close()
1677
1678	coll := session.DB("mydb").C("mycoll")
1679
1680	// Insane amounts of logging otherwise due to the
1681	// amount of data being shuffled.
1682	mgo.SetDebug(false)
1683	defer mgo.SetDebug(true)
1684
1685	// Should amount to more than 4MB bson payload,
1686	// the default limit per result chunk.
1687	const total = 4096
1688	var d struct{ A [1024]byte }
1689	docs := make([]interface{}, total)
1690	for i := 0; i < total; i++ {
1691		docs[i] = &d
1692	}
1693	err = coll.Insert(docs...)
1694	c.Assert(err, IsNil)
1695
1696	n, err := coll.Count()
1697	c.Assert(err, IsNil)
1698	c.Assert(n, Equals, total)
1699
1700	// First, try restricting to a single chunk with a negative limit.
1701	nresults := 0
1702	iter := coll.Find(nil).Limit(-total).Iter()
1703	var discard struct{}
1704	for iter.Next(&discard) {
1705		nresults++
1706	}
1707	if nresults < total/2 || nresults >= total {
1708		c.Fatalf("Bad result size with negative limit: %d", nresults)
1709	}
1710
1711	cursorsOpen := serverCursorsOpen(session)
1712
1713	// Try again, with a positive limit. Should reach the end now,
1714	// using multiple chunks.
1715	nresults = 0
1716	iter = coll.Find(nil).Limit(total).Iter()
1717	for iter.Next(&discard) {
1718		nresults++
1719	}
1720	c.Assert(nresults, Equals, total)
1721
1722	// Ensure the cursor used is properly killed.
1723	c.Assert(serverCursorsOpen(session), Equals, cursorsOpen)
1724
1725	// Edge case, -MinInt == -MinInt.
1726	nresults = 0
1727	iter = coll.Find(nil).Limit(math.MinInt32).Iter()
1728	for iter.Next(&discard) {
1729		nresults++
1730	}
1731	if nresults < total/2 || nresults >= total {
1732		c.Fatalf("Bad result size with MinInt32 limit: %d", nresults)
1733	}
1734}
1735
1736func (s *S) TestFindIterLimitWithBatch(c *C) {
1737	session, err := mgo.Dial("localhost:40001")
1738	c.Assert(err, IsNil)
1739	defer session.Close()
1740
1741	coll := session.DB("mydb").C("mycoll")
1742
1743	ns := []int{40, 41, 42, 43, 44, 45, 46}
1744	for _, n := range ns {
1745		coll.Insert(M{"n": n})
1746	}
1747
1748	// Ping the database to ensure the nonce has been received already.
1749	c.Assert(session.Ping(), IsNil)
1750
1751	session.Refresh() // Release socket.
1752
1753	mgo.ResetStats()
1754
1755	query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Limit(3).Batch(2)
1756	iter := query.Iter()
1757	result := struct{ N int }{}
1758	for i := 2; i < 5; i++ {
1759		ok := iter.Next(&result)
1760		c.Assert(ok, Equals, true)
1761		c.Assert(result.N, Equals, ns[i])
1762		if i == 3 {
1763			stats := mgo.GetStats()
1764			if s.versionAtLeast(3, 2) {
1765				// In 3.2+ responses come in batches inside the op reply docs.
1766				c.Assert(stats.ReceivedDocs, Equals, 1)
1767			} else {
1768				c.Assert(stats.ReceivedDocs, Equals, 2)
1769			}
1770		}
1771	}
1772
1773	ok := iter.Next(&result)
1774	c.Assert(ok, Equals, false)
1775	c.Assert(iter.Close(), IsNil)
1776
1777	session.Refresh() // Release socket.
1778
1779	stats := mgo.GetStats()
1780	if s.versionAtLeast(3, 2) {
1781		// In 3.2+ limit works properly even with multiple batches..
1782		c.Assert(stats.SentOps, Equals, 2)     // 1*QUERY_OP + 1*GET_MORE_OP
1783		c.Assert(stats.ReceivedOps, Equals, 2) // and its REPLY_OPs
1784
1785		// In 3.2+ responses come in batches inside the op reply docs.
1786		c.Assert(stats.ReceivedDocs, Equals, 2)
1787	} else {
1788		c.Assert(stats.SentOps, Equals, 3)     // 1*QUERY_OP + 1*GET_MORE_OP + 1*KILL_CURSORS_OP
1789		c.Assert(stats.ReceivedOps, Equals, 2) // and its REPLY_OPs
1790		c.Assert(stats.ReceivedDocs, Equals, 3)
1791	}
1792	c.Assert(stats.SocketsInUse, Equals, 0)
1793}
1794
1795func (s *S) TestFindIterSortWithBatch(c *C) {
1796	session, err := mgo.Dial("localhost:40001")
1797	c.Assert(err, IsNil)
1798	defer session.Close()
1799
1800	coll := session.DB("mydb").C("mycoll")
1801
1802	ns := []int{40, 41, 42, 43, 44, 45, 46}
1803	for _, n := range ns {
1804		coll.Insert(M{"n": n})
1805	}
1806
1807	// Without this, the logic above breaks because Mongo refuses to
1808	// return a cursor with an in-memory sort.
1809	coll.EnsureIndexKey("n")
1810
1811	// Ping the database to ensure the nonce has been received already.
1812	c.Assert(session.Ping(), IsNil)
1813
1814	session.Refresh() // Release socket.
1815
1816	mgo.ResetStats()
1817
1818	query := coll.Find(M{"n": M{"$lte": 44}}).Sort("-n").Batch(2)
1819	iter := query.Iter()
1820	ns = []int{46, 45, 44, 43, 42, 41, 40}
1821	result := struct{ N int }{}
1822	for i := 2; i < len(ns); i++ {
1823		c.Logf("i=%d", i)
1824		ok := iter.Next(&result)
1825		c.Assert(ok, Equals, true)
1826		c.Assert(result.N, Equals, ns[i])
1827		if i == 3 {
1828			stats := mgo.GetStats()
1829			if s.versionAtLeast(3, 2) {
1830				// Find command in 3.2+ bundles batches in a single document.
1831				c.Assert(stats.ReceivedDocs, Equals, 1)
1832			} else {
1833				c.Assert(stats.ReceivedDocs, Equals, 2)
1834			}
1835		}
1836	}
1837
1838	ok := iter.Next(&result)
1839	c.Assert(ok, Equals, false)
1840	c.Assert(iter.Close(), IsNil)
1841
1842	session.Refresh() // Release socket.
1843
1844	stats := mgo.GetStats()
1845	c.Assert(stats.SentOps, Equals, 3)     // 1*QUERY_OP + 2*GET_MORE_OP
1846	c.Assert(stats.ReceivedOps, Equals, 3) // and its REPLY_OPs
1847	if s.versionAtLeast(3, 2) {
1848		// Find command in 3.2+ bundles batches in a single document.
1849		c.Assert(stats.ReceivedDocs, Equals, 3)
1850	} else {
1851		c.Assert(stats.ReceivedDocs, Equals, 5)
1852	}
1853	c.Assert(stats.SocketsInUse, Equals, 0)
1854}
1855
1856// Test tailable cursors in a situation where Next has to sleep to
1857// respect the timeout requested on Tail.
1858func (s *S) TestFindTailTimeoutWithSleep(c *C) {
1859	if *fast {
1860		c.Skip("-fast")
1861	}
1862
1863	session, err := mgo.Dial("localhost:40001")
1864	c.Assert(err, IsNil)
1865	defer session.Close()
1866
1867	cresult := struct{ ErrMsg string }{}
1868
1869	db := session.DB("mydb")
1870	err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult)
1871	c.Assert(err, IsNil)
1872	c.Assert(cresult.ErrMsg, Equals, "")
1873	coll := db.C("mycoll")
1874
1875	ns := []int{40, 41, 42, 43, 44, 45, 46}
1876	for _, n := range ns {
1877		coll.Insert(M{"n": n})
1878	}
1879
1880	session.Refresh() // Release socket.
1881
1882	mgo.ResetStats()
1883
1884	timeout := 5 * time.Second
1885
1886	query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)
1887	iter := query.Tail(timeout)
1888
1889	n := len(ns)
1890	result := struct{ N int }{}
1891	for i := 2; i != n; i++ {
1892		ok := iter.Next(&result)
1893		c.Assert(ok, Equals, true)
1894		c.Assert(iter.Err(), IsNil)
1895		c.Assert(iter.Timeout(), Equals, false)
1896		c.Assert(result.N, Equals, ns[i])
1897		if i == 3 { // The batch boundary.
1898			stats := mgo.GetStats()
1899			c.Assert(stats.ReceivedDocs, Equals, 2)
1900		}
1901	}
1902
1903	mgo.ResetStats()
1904
1905	// The following call to Next will block.
1906	done := make(chan bool)
1907	defer func() { <-done }()
1908	go func() {
1909		// The internal AwaitData timing of MongoDB is around 2 seconds,
1910		// so this should force mgo to sleep at least once by itself to
1911		// respect the requested timeout.
1912		c.Logf("[GOROUTINE] Starting and sleeping...")
1913		time.Sleep(timeout - 2*time.Second)
1914		c.Logf("[GOROUTINE] Woke up...")
1915		session := session.New()
1916		c.Logf("[GOROUTINE] Session created and will insert...")
1917		err := coll.Insert(M{"n": 47})
1918		c.Logf("[GOROUTINE] Insert attempted, err=%v...", err)
1919		session.Close()
1920		c.Logf("[GOROUTINE] Session closed.")
1921		c.Check(err, IsNil)
1922		done <- true
1923	}()
1924
1925	c.Log("Will wait for Next with N=47...")
1926	ok := iter.Next(&result)
1927	c.Log("Next unblocked...")
1928	c.Assert(ok, Equals, true)
1929
1930	c.Assert(iter.Err(), IsNil)
1931	c.Assert(iter.Timeout(), Equals, false)
1932	c.Assert(result.N, Equals, 47)
1933	c.Log("Got Next with N=47!")
1934
1935	c.Log("Will wait for a result which will never come...")
1936
1937	started := time.Now()
1938	ok = iter.Next(&result)
1939	c.Assert(ok, Equals, false)
1940	c.Assert(iter.Err(), IsNil)
1941	c.Assert(iter.Timeout(), Equals, true)
1942	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
1943
1944	c.Log("Will now reuse the timed out tail cursor...")
1945
1946	coll.Insert(M{"n": 48})
1947	ok = iter.Next(&result)
1948	c.Assert(ok, Equals, true)
1949	c.Assert(iter.Close(), IsNil)
1950	c.Assert(iter.Timeout(), Equals, false)
1951	c.Assert(result.N, Equals, 48)
1952}
1953
1954// Test tailable cursors in a situation where Next never gets to sleep once
1955// to respect the timeout requested on Tail.
1956func (s *S) TestFindTailTimeoutNoSleep(c *C) {
1957	session, err := mgo.Dial("localhost:40001")
1958	c.Assert(err, IsNil)
1959	defer session.Close()
1960
1961	cresult := struct{ ErrMsg string }{}
1962
1963	db := session.DB("mydb")
1964	err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult)
1965	c.Assert(err, IsNil)
1966	c.Assert(cresult.ErrMsg, Equals, "")
1967	coll := db.C("mycoll")
1968
1969	ns := []int{40, 41, 42, 43, 44, 45, 46}
1970	for _, n := range ns {
1971		coll.Insert(M{"n": n})
1972	}
1973
1974	session.Refresh() // Release socket.
1975
1976	mgo.ResetStats()
1977
1978	timeout := 1 * time.Second
1979
1980	query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)
1981	iter := query.Tail(timeout)
1982
1983	n := len(ns)
1984	result := struct{ N int }{}
1985	for i := 2; i != n; i++ {
1986		ok := iter.Next(&result)
1987		c.Assert(ok, Equals, true)
1988		c.Assert(iter.Err(), IsNil)
1989		c.Assert(iter.Timeout(), Equals, false)
1990		c.Assert(result.N, Equals, ns[i])
1991		if i == 3 { // The batch boundary.
1992			stats := mgo.GetStats()
1993			c.Assert(stats.ReceivedDocs, Equals, 2)
1994		}
1995	}
1996
1997	// The following call to Next will block.
1998	go func() {
1999		// The internal AwaitData timing of MongoDB is around 2 seconds,
2000		// so this item should arrive within the AwaitData threshold.
2001		time.Sleep(500 * time.Millisecond)
2002		session := session.New()
2003		defer session.Close()
2004		coll := session.DB("mydb").C("mycoll")
2005		coll.Insert(M{"n": 47})
2006	}()
2007
2008	c.Log("Will wait for Next with N=47...")
2009	ok := iter.Next(&result)
2010	c.Assert(ok, Equals, true)
2011	c.Assert(iter.Err(), IsNil)
2012	c.Assert(iter.Timeout(), Equals, false)
2013	c.Assert(result.N, Equals, 47)
2014	c.Log("Got Next with N=47!")
2015
2016	c.Log("Will wait for a result which will never come...")
2017
2018	started := time.Now()
2019	ok = iter.Next(&result)
2020	c.Assert(ok, Equals, false)
2021	c.Assert(iter.Err(), IsNil)
2022	c.Assert(iter.Timeout(), Equals, true)
2023	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
2024
2025	c.Log("Will now reuse the timed out tail cursor...")
2026
2027	coll.Insert(M{"n": 48})
2028	ok = iter.Next(&result)
2029	c.Assert(ok, Equals, true)
2030	c.Assert(iter.Close(), IsNil)
2031	c.Assert(iter.Timeout(), Equals, false)
2032	c.Assert(result.N, Equals, 48)
2033}
2034
2035// Test tailable cursors in a situation where Next never gets to sleep once
2036// to respect the timeout requested on Tail.
2037func (s *S) TestFindTailNoTimeout(c *C) {
2038	if *fast {
2039		c.Skip("-fast")
2040	}
2041
2042	session, err := mgo.Dial("localhost:40001")
2043	c.Assert(err, IsNil)
2044	defer session.Close()
2045
2046	cresult := struct{ ErrMsg string }{}
2047
2048	db := session.DB("mydb")
2049	err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult)
2050	c.Assert(err, IsNil)
2051	c.Assert(cresult.ErrMsg, Equals, "")
2052	coll := db.C("mycoll")
2053
2054	ns := []int{40, 41, 42, 43, 44, 45, 46}
2055	for _, n := range ns {
2056		coll.Insert(M{"n": n})
2057	}
2058
2059	session.Refresh() // Release socket.
2060
2061	mgo.ResetStats()
2062
2063	query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)
2064	iter := query.Tail(-1)
2065	c.Assert(err, IsNil)
2066
2067	n := len(ns)
2068	result := struct{ N int }{}
2069	for i := 2; i != n; i++ {
2070		ok := iter.Next(&result)
2071		c.Assert(ok, Equals, true)
2072		c.Assert(result.N, Equals, ns[i])
2073		if i == 3 { // The batch boundary.
2074			stats := mgo.GetStats()
2075			c.Assert(stats.ReceivedDocs, Equals, 2)
2076		}
2077	}
2078
2079	mgo.ResetStats()
2080
2081	// The following call to Next will block.
2082	go func() {
2083		time.Sleep(5e8)
2084		session := session.New()
2085		defer session.Close()
2086		coll := session.DB("mydb").C("mycoll")
2087		coll.Insert(M{"n": 47})
2088	}()
2089
2090	c.Log("Will wait for Next with N=47...")
2091	ok := iter.Next(&result)
2092	c.Assert(ok, Equals, true)
2093	c.Assert(iter.Err(), IsNil)
2094	c.Assert(iter.Timeout(), Equals, false)
2095	c.Assert(result.N, Equals, 47)
2096	c.Log("Got Next with N=47!")
2097
2098	c.Log("Will wait for a result which will never come...")
2099
2100	gotNext := make(chan bool)
2101	go func() {
2102		ok := iter.Next(&result)
2103		gotNext <- ok
2104	}()
2105
2106	select {
2107	case ok := <-gotNext:
2108		c.Fatalf("Next returned: %v", ok)
2109	case <-time.After(3e9):
2110		// Good. Should still be sleeping at that point.
2111	}
2112
2113	// Closing the session should cause Next to return.
2114	session.Close()
2115
2116	select {
2117	case ok := <-gotNext:
2118		c.Assert(ok, Equals, false)
2119		c.Assert(iter.Err(), ErrorMatches, "Closed explicitly")
2120		c.Assert(iter.Timeout(), Equals, false)
2121	case <-time.After(1e9):
2122		c.Fatal("Closing the session did not unblock Next")
2123	}
2124}
2125
2126func (s *S) TestIterNextResetsResult(c *C) {
2127	session, err := mgo.Dial("localhost:40001")
2128	c.Assert(err, IsNil)
2129	defer session.Close()
2130
2131	coll := session.DB("mydb").C("mycoll")
2132
2133	ns := []int{1, 2, 3}
2134	for _, n := range ns {
2135		coll.Insert(M{"n" + strconv.Itoa(n): n})
2136	}
2137
2138	query := coll.Find(nil).Sort("$natural")
2139
2140	i := 0
2141	var sresult *struct{ N1, N2, N3 int }
2142	iter := query.Iter()
2143	for iter.Next(&sresult) {
2144		switch i {
2145		case 0:
2146			c.Assert(sresult.N1, Equals, 1)
2147			c.Assert(sresult.N2+sresult.N3, Equals, 0)
2148		case 1:
2149			c.Assert(sresult.N2, Equals, 2)
2150			c.Assert(sresult.N1+sresult.N3, Equals, 0)
2151		case 2:
2152			c.Assert(sresult.N3, Equals, 3)
2153			c.Assert(sresult.N1+sresult.N2, Equals, 0)
2154		}
2155		i++
2156	}
2157	c.Assert(iter.Close(), IsNil)
2158
2159	i = 0
2160	var mresult M
2161	iter = query.Iter()
2162	for iter.Next(&mresult) {
2163		delete(mresult, "_id")
2164		switch i {
2165		case 0:
2166			c.Assert(mresult, DeepEquals, M{"n1": 1})
2167		case 1:
2168			c.Assert(mresult, DeepEquals, M{"n2": 2})
2169		case 2:
2170			c.Assert(mresult, DeepEquals, M{"n3": 3})
2171		}
2172		i++
2173	}
2174	c.Assert(iter.Close(), IsNil)
2175
2176	i = 0
2177	var iresult interface{}
2178	iter = query.Iter()
2179	for iter.Next(&iresult) {
2180		mresult, ok := iresult.(bson.M)
2181		c.Assert(ok, Equals, true, Commentf("%#v", iresult))
2182		delete(mresult, "_id")
2183		switch i {
2184		case 0:
2185			c.Assert(mresult, DeepEquals, bson.M{"n1": 1})
2186		case 1:
2187			c.Assert(mresult, DeepEquals, bson.M{"n2": 2})
2188		case 2:
2189			c.Assert(mresult, DeepEquals, bson.M{"n3": 3})
2190		}
2191		i++
2192	}
2193	c.Assert(iter.Close(), IsNil)
2194}
2195
2196func (s *S) TestFindForOnIter(c *C) {
2197	session, err := mgo.Dial("localhost:40001")
2198	c.Assert(err, IsNil)
2199	defer session.Close()
2200
2201	coll := session.DB("mydb").C("mycoll")
2202
2203	ns := []int{40, 41, 42, 43, 44, 45, 46}
2204	for _, n := range ns {
2205		coll.Insert(M{"n": n})
2206	}
2207
2208	session.Refresh() // Release socket.
2209
2210	mgo.ResetStats()
2211
2212	query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)
2213	iter := query.Iter()
2214
2215	i := 2
2216	var result *struct{ N int }
2217	err = iter.For(&result, func() error {
2218		c.Assert(i < 7, Equals, true)
2219		c.Assert(result.N, Equals, ns[i])
2220		if i == 1 {
2221			stats := mgo.GetStats()
2222			if s.versionAtLeast(3, 2) {
2223				// Find command in 3.2+ bundles batches in a single document.
2224				c.Assert(stats.ReceivedDocs, Equals, 1)
2225			} else {
2226				c.Assert(stats.ReceivedDocs, Equals, 2)
2227			}
2228		}
2229		i++
2230		return nil
2231	})
2232	c.Assert(err, IsNil)
2233
2234	session.Refresh() // Release socket.
2235
2236	stats := mgo.GetStats()
2237	c.Assert(stats.SentOps, Equals, 3)     // 1*QUERY_OP + 2*GET_MORE_OP
2238	c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs.
2239	if s.versionAtLeast(3, 2) {
2240		// Find command in 3.2+ bundles batches in a single document.
2241		c.Assert(stats.ReceivedDocs, Equals, 3)
2242	} else {
2243		c.Assert(stats.ReceivedDocs, Equals, 5)
2244	}
2245	c.Assert(stats.SocketsInUse, Equals, 0)
2246}
2247
2248func (s *S) TestFindFor(c *C) {
2249	session, err := mgo.Dial("localhost:40001")
2250	c.Assert(err, IsNil)
2251	defer session.Close()
2252
2253	coll := session.DB("mydb").C("mycoll")
2254
2255	ns := []int{40, 41, 42, 43, 44, 45, 46}
2256	for _, n := range ns {
2257		coll.Insert(M{"n": n})
2258	}
2259
2260	session.Refresh() // Release socket.
2261
2262	mgo.ResetStats()
2263
2264	query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)
2265
2266	i := 2
2267	var result *struct{ N int }
2268	err = query.For(&result, func() error {
2269		c.Assert(i < 7, Equals, true)
2270		c.Assert(result.N, Equals, ns[i])
2271		if i == 1 {
2272			stats := mgo.GetStats()
2273			c.Assert(stats.ReceivedDocs, Equals, 2)
2274			if s.versionAtLeast(3, 2) {
2275				// Find command in 3.2+ bundles batches in a single document.
2276				c.Assert(stats.ReceivedDocs, Equals, 1)
2277			} else {
2278				c.Assert(stats.ReceivedDocs, Equals, 2)
2279			}
2280		}
2281		i++
2282		return nil
2283	})
2284	c.Assert(err, IsNil)
2285
2286	session.Refresh() // Release socket.
2287
2288	stats := mgo.GetStats()
2289	c.Assert(stats.SentOps, Equals, 3)     // 1*QUERY_OP + 2*GET_MORE_OP
2290	c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs.
2291	if s.versionAtLeast(3, 2) {
2292		// Find command in 3.2+ bundles batches in a single document.
2293		c.Assert(stats.ReceivedDocs, Equals, 3)
2294	} else {
2295		c.Assert(stats.ReceivedDocs, Equals, 5)
2296	}
2297	c.Assert(stats.SocketsInUse, Equals, 0)
2298}
2299
2300func (s *S) TestFindForStopOnError(c *C) {
2301	session, err := mgo.Dial("localhost:40001")
2302	c.Assert(err, IsNil)
2303	defer session.Close()
2304
2305	coll := session.DB("mydb").C("mycoll")
2306
2307	ns := []int{40, 41, 42, 43, 44, 45, 46}
2308	for _, n := range ns {
2309		coll.Insert(M{"n": n})
2310	}
2311
2312	query := coll.Find(M{"n": M{"$gte": 42}})
2313	i := 2
2314	var result *struct{ N int }
2315	err = query.For(&result, func() error {
2316		c.Assert(i < 4, Equals, true)
2317		c.Assert(result.N, Equals, ns[i])
2318		if i == 3 {
2319			return fmt.Errorf("stop!")
2320		}
2321		i++
2322		return nil
2323	})
2324	c.Assert(err, ErrorMatches, "stop!")
2325}
2326
2327func (s *S) TestFindForResetsResult(c *C) {
2328	session, err := mgo.Dial("localhost:40001")
2329	c.Assert(err, IsNil)
2330	defer session.Close()
2331
2332	coll := session.DB("mydb").C("mycoll")
2333
2334	ns := []int{1, 2, 3}
2335	for _, n := range ns {
2336		coll.Insert(M{"n" + strconv.Itoa(n): n})
2337	}
2338
2339	query := coll.Find(nil).Sort("$natural")
2340
2341	i := 0
2342	var sresult *struct{ N1, N2, N3 int }
2343	err = query.For(&sresult, func() error {
2344		switch i {
2345		case 0:
2346			c.Assert(sresult.N1, Equals, 1)
2347			c.Assert(sresult.N2+sresult.N3, Equals, 0)
2348		case 1:
2349			c.Assert(sresult.N2, Equals, 2)
2350			c.Assert(sresult.N1+sresult.N3, Equals, 0)
2351		case 2:
2352			c.Assert(sresult.N3, Equals, 3)
2353			c.Assert(sresult.N1+sresult.N2, Equals, 0)
2354		}
2355		i++
2356		return nil
2357	})
2358	c.Assert(err, IsNil)
2359
2360	i = 0
2361	var mresult M
2362	err = query.For(&mresult, func() error {
2363		delete(mresult, "_id")
2364		switch i {
2365		case 0:
2366			c.Assert(mresult, DeepEquals, M{"n1": 1})
2367		case 1:
2368			c.Assert(mresult, DeepEquals, M{"n2": 2})
2369		case 2:
2370			c.Assert(mresult, DeepEquals, M{"n3": 3})
2371		}
2372		i++
2373		return nil
2374	})
2375	c.Assert(err, IsNil)
2376
2377	i = 0
2378	var iresult interface{}
2379	err = query.For(&iresult, func() error {
2380		mresult, ok := iresult.(bson.M)
2381		c.Assert(ok, Equals, true, Commentf("%#v", iresult))
2382		delete(mresult, "_id")
2383		switch i {
2384		case 0:
2385			c.Assert(mresult, DeepEquals, bson.M{"n1": 1})
2386		case 1:
2387			c.Assert(mresult, DeepEquals, bson.M{"n2": 2})
2388		case 2:
2389			c.Assert(mresult, DeepEquals, bson.M{"n3": 3})
2390		}
2391		i++
2392		return nil
2393	})
2394	c.Assert(err, IsNil)
2395}
2396
2397func (s *S) TestFindIterSnapshot(c *C) {
2398	if s.versionAtLeast(3, 2) {
2399		c.Skip("Broken in 3.2: https://jira.mongodb.org/browse/SERVER-21403")
2400	}
2401
2402	session, err := mgo.Dial("localhost:40001")
2403	c.Assert(err, IsNil)
2404	defer session.Close()
2405
2406	// Insane amounts of logging otherwise due to the
2407	// amount of data being shuffled.
2408	mgo.SetDebug(false)
2409	defer mgo.SetDebug(true)
2410
2411	coll := session.DB("mydb").C("mycoll")
2412
2413	var a [1024000]byte
2414
2415	for n := 0; n < 10; n++ {
2416		err := coll.Insert(M{"_id": n, "n": n, "a1": &a})
2417		c.Assert(err, IsNil)
2418	}
2419
2420	query := coll.Find(M{"n": M{"$gt": -1}}).Batch(2).Prefetch(0)
2421	query.Snapshot()
2422	iter := query.Iter()
2423
2424	seen := map[int]bool{}
2425	result := struct {
2426		Id int "_id"
2427	}{}
2428	for iter.Next(&result) {
2429		if len(seen) == 2 {
2430			// Grow all entries so that they have to move.
2431			// Backwards so that the order is inverted.
2432			for n := 10; n >= 0; n-- {
2433				_, err := coll.Upsert(M{"_id": n}, M{"$set": M{"a2": &a}})
2434				c.Assert(err, IsNil)
2435			}
2436		}
2437		if seen[result.Id] {
2438			c.Fatalf("seen duplicated key: %d", result.Id)
2439		}
2440		seen[result.Id] = true
2441	}
2442	c.Assert(iter.Close(), IsNil)
2443}
2444
2445func (s *S) TestSort(c *C) {
2446	session, err := mgo.Dial("localhost:40001")
2447	c.Assert(err, IsNil)
2448	defer session.Close()
2449
2450	coll := session.DB("mydb").C("mycoll")
2451
2452	coll.Insert(M{"a": 1, "b": 1})
2453	coll.Insert(M{"a": 2, "b": 2})
2454	coll.Insert(M{"a": 2, "b": 1})
2455	coll.Insert(M{"a": 0, "b": 1})
2456	coll.Insert(M{"a": 2, "b": 0})
2457	coll.Insert(M{"a": 0, "b": 2})
2458	coll.Insert(M{"a": 1, "b": 2})
2459	coll.Insert(M{"a": 0, "b": 0})
2460	coll.Insert(M{"a": 1, "b": 0})
2461
2462	query := coll.Find(M{})
2463	query.Sort("-a") // Should be ignored.
2464	query.Sort("-b", "a")
2465	iter := query.Iter()
2466
2467	l := make([]int, 18)
2468	r := struct{ A, B int }{}
2469	for i := 0; i != len(l); i += 2 {
2470		ok := iter.Next(&r)
2471		c.Assert(ok, Equals, true)
2472		c.Assert(err, IsNil)
2473		l[i] = r.A
2474		l[i+1] = r.B
2475	}
2476
2477	c.Assert(l, DeepEquals, []int{0, 2, 1, 2, 2, 2, 0, 1, 1, 1, 2, 1, 0, 0, 1, 0, 2, 0})
2478}
2479
2480func (s *S) TestSortWithBadArgs(c *C) {
2481	session, err := mgo.Dial("localhost:40001")
2482	c.Assert(err, IsNil)
2483	defer session.Close()
2484
2485	coll := session.DB("mydb").C("mycoll")
2486
2487	f1 := func() { coll.Find(nil).Sort("") }
2488	f2 := func() { coll.Find(nil).Sort("+") }
2489	f3 := func() { coll.Find(nil).Sort("foo", "-") }
2490
2491	for _, f := range []func(){f1, f2, f3} {
2492		c.Assert(f, PanicMatches, "Sort: empty field name")
2493	}
2494}
2495
2496func (s *S) TestSortScoreText(c *C) {
2497	session, err := mgo.Dial("localhost:40001")
2498	c.Assert(err, IsNil)
2499	defer session.Close()
2500
2501	if !s.versionAtLeast(2, 4) {
2502		c.Skip("Text search depends on 2.4+")
2503	}
2504
2505	coll := session.DB("mydb").C("mycoll")
2506
2507	err = coll.EnsureIndex(mgo.Index{
2508		Key: []string{"$text:a", "$text:b"},
2509	})
2510	msg := "text search not enabled"
2511	if err != nil && strings.Contains(err.Error(), msg) {
2512		c.Skip(msg)
2513	}
2514	c.Assert(err, IsNil)
2515
2516	err = coll.Insert(M{
2517		"a": "none",
2518		"b": "twice: foo foo",
2519	})
2520	c.Assert(err, IsNil)
2521	err = coll.Insert(M{
2522		"a": "just once: foo",
2523		"b": "none",
2524	})
2525	c.Assert(err, IsNil)
2526	err = coll.Insert(M{
2527		"a": "many: foo foo foo",
2528		"b": "none",
2529	})
2530	c.Assert(err, IsNil)
2531	err = coll.Insert(M{
2532		"a": "none",
2533		"b": "none",
2534		"c": "ignore: foo",
2535	})
2536	c.Assert(err, IsNil)
2537
2538	query := coll.Find(M{"$text": M{"$search": "foo"}})
2539	query.Select(M{"score": M{"$meta": "textScore"}})
2540	query.Sort("$textScore:score")
2541	iter := query.Iter()
2542
2543	var r struct{ A, B string }
2544	var results []string
2545	for iter.Next(&r) {
2546		results = append(results, r.A, r.B)
2547	}
2548
2549	c.Assert(results, DeepEquals, []string{
2550		"many: foo foo foo", "none",
2551		"none", "twice: foo foo",
2552		"just once: foo", "none",
2553	})
2554}
2555
2556func (s *S) TestPrefetching(c *C) {
2557	session, err := mgo.Dial("localhost:40001")
2558	c.Assert(err, IsNil)
2559	defer session.Close()
2560
2561	coll := session.DB("mydb").C("mycoll")
2562
2563	const total = 600
2564	const batch = 100
2565	mgo.SetDebug(false)
2566	docs := make([]interface{}, total)
2567	for i := 0; i != total; i++ {
2568		docs[i] = bson.D{{"n", i}}
2569	}
2570	err = coll.Insert(docs...)
2571	c.Assert(err, IsNil)
2572
2573	for testi := 0; testi < 5; testi++ {
2574		mgo.ResetStats()
2575
2576		var iter *mgo.Iter
2577		var beforeMore int
2578
2579		switch testi {
2580		case 0: // The default session value.
2581			session.SetBatch(batch)
2582			iter = coll.Find(M{}).Iter()
2583			beforeMore = 75
2584
2585		case 2: // Changing the session value.
2586			session.SetBatch(batch)
2587			session.SetPrefetch(0.27)
2588			iter = coll.Find(M{}).Iter()
2589			beforeMore = 73
2590
2591		case 1: // Changing via query methods.
2592			iter = coll.Find(M{}).Prefetch(0.27).Batch(batch).Iter()
2593			beforeMore = 73
2594
2595		case 3: // With prefetch on first document.
2596			iter = coll.Find(M{}).Prefetch(1.0).Batch(batch).Iter()
2597			beforeMore = 0
2598
2599		case 4: // Without prefetch.
2600			iter = coll.Find(M{}).Prefetch(0).Batch(batch).Iter()
2601			beforeMore = 100
2602		}
2603
2604		pings := 0
2605		for batchi := 0; batchi < len(docs)/batch-1; batchi++ {
2606			c.Logf("Iterating over %d documents on batch %d", beforeMore, batchi)
2607			var result struct{ N int }
2608			for i := 0; i < beforeMore; i++ {
2609				ok := iter.Next(&result)
2610				c.Assert(ok, Equals, true, Commentf("iter.Err: %v", iter.Err()))
2611			}
2612			beforeMore = 99
2613			c.Logf("Done iterating.")
2614
2615			session.Run("ping", nil) // Roundtrip to settle down.
2616			pings++
2617
2618			stats := mgo.GetStats()
2619			if s.versionAtLeast(3, 2) {
2620				// Find command in 3.2+ bundles batches in a single document.
2621				c.Assert(stats.ReceivedDocs, Equals, (batchi+1)+pings)
2622			} else {
2623				c.Assert(stats.ReceivedDocs, Equals, (batchi+1)*batch+pings)
2624			}
2625
2626			c.Logf("Iterating over one more document on batch %d", batchi)
2627			ok := iter.Next(&result)
2628			c.Assert(ok, Equals, true, Commentf("iter.Err: %v", iter.Err()))
2629			c.Logf("Done iterating.")
2630
2631			session.Run("ping", nil) // Roundtrip to settle down.
2632			pings++
2633
2634			stats = mgo.GetStats()
2635			if s.versionAtLeast(3, 2) {
2636				// Find command in 3.2+ bundles batches in a single document.
2637				c.Assert(stats.ReceivedDocs, Equals, (batchi+2)+pings)
2638			} else {
2639				c.Assert(stats.ReceivedDocs, Equals, (batchi+2)*batch+pings)
2640			}
2641		}
2642	}
2643}
2644
2645func (s *S) TestSafeSetting(c *C) {
2646	session, err := mgo.Dial("localhost:40001")
2647	c.Assert(err, IsNil)
2648	defer session.Close()
2649
2650	// Check the default
2651	safe := session.Safe()
2652	c.Assert(safe.W, Equals, 0)
2653	c.Assert(safe.WMode, Equals, "")
2654	c.Assert(safe.WTimeout, Equals, 0)
2655	c.Assert(safe.FSync, Equals, false)
2656	c.Assert(safe.J, Equals, false)
2657
2658	// Tweak it
2659	session.SetSafe(&mgo.Safe{W: 1, WTimeout: 2, FSync: true})
2660	safe = session.Safe()
2661	c.Assert(safe.W, Equals, 1)
2662	c.Assert(safe.WMode, Equals, "")
2663	c.Assert(safe.WTimeout, Equals, 2)
2664	c.Assert(safe.FSync, Equals, true)
2665	c.Assert(safe.J, Equals, false)
2666
2667	// Reset it again.
2668	session.SetSafe(&mgo.Safe{})
2669	safe = session.Safe()
2670	c.Assert(safe.W, Equals, 0)
2671	c.Assert(safe.WMode, Equals, "")
2672	c.Assert(safe.WTimeout, Equals, 0)
2673	c.Assert(safe.FSync, Equals, false)
2674	c.Assert(safe.J, Equals, false)
2675
2676	// Ensure safety to something more conservative.
2677	session.SetSafe(&mgo.Safe{W: 5, WTimeout: 6, J: true})
2678	safe = session.Safe()
2679	c.Assert(safe.W, Equals, 5)
2680	c.Assert(safe.WMode, Equals, "")
2681	c.Assert(safe.WTimeout, Equals, 6)
2682	c.Assert(safe.FSync, Equals, false)
2683	c.Assert(safe.J, Equals, true)
2684
2685	// Ensure safety to something less conservative won't change it.
2686	session.EnsureSafe(&mgo.Safe{W: 4, WTimeout: 7})
2687	safe = session.Safe()
2688	c.Assert(safe.W, Equals, 5)
2689	c.Assert(safe.WMode, Equals, "")
2690	c.Assert(safe.WTimeout, Equals, 6)
2691	c.Assert(safe.FSync, Equals, false)
2692	c.Assert(safe.J, Equals, true)
2693
2694	// But to something more conservative will.
2695	session.EnsureSafe(&mgo.Safe{W: 6, WTimeout: 4, FSync: true})
2696	safe = session.Safe()
2697	c.Assert(safe.W, Equals, 6)
2698	c.Assert(safe.WMode, Equals, "")
2699	c.Assert(safe.WTimeout, Equals, 4)
2700	c.Assert(safe.FSync, Equals, true)
2701	c.Assert(safe.J, Equals, false)
2702
2703	// Even more conservative.
2704	session.EnsureSafe(&mgo.Safe{WMode: "majority", WTimeout: 2})
2705	safe = session.Safe()
2706	c.Assert(safe.W, Equals, 0)
2707	c.Assert(safe.WMode, Equals, "majority")
2708	c.Assert(safe.WTimeout, Equals, 2)
2709	c.Assert(safe.FSync, Equals, true)
2710	c.Assert(safe.J, Equals, false)
2711
2712	// WMode always overrides, whatever it is, but J doesn't.
2713	session.EnsureSafe(&mgo.Safe{WMode: "something", J: true})
2714	safe = session.Safe()
2715	c.Assert(safe.W, Equals, 0)
2716	c.Assert(safe.WMode, Equals, "something")
2717	c.Assert(safe.WTimeout, Equals, 2)
2718	c.Assert(safe.FSync, Equals, true)
2719	c.Assert(safe.J, Equals, false)
2720
2721	// EnsureSafe with nil does nothing.
2722	session.EnsureSafe(nil)
2723	safe = session.Safe()
2724	c.Assert(safe.W, Equals, 0)
2725	c.Assert(safe.WMode, Equals, "something")
2726	c.Assert(safe.WTimeout, Equals, 2)
2727	c.Assert(safe.FSync, Equals, true)
2728	c.Assert(safe.J, Equals, false)
2729
2730	// Changing the safety of a cloned session doesn't touch the original.
2731	clone := session.Clone()
2732	defer clone.Close()
2733	clone.EnsureSafe(&mgo.Safe{WMode: "foo"})
2734	safe = session.Safe()
2735	c.Assert(safe.WMode, Equals, "something")
2736}
2737
2738func (s *S) TestSafeInsert(c *C) {
2739	session, err := mgo.Dial("localhost:40001")
2740	c.Assert(err, IsNil)
2741	defer session.Close()
2742
2743	coll := session.DB("mydb").C("mycoll")
2744
2745	// Insert an element with a predefined key.
2746	err = coll.Insert(M{"_id": 1})
2747	c.Assert(err, IsNil)
2748
2749	mgo.ResetStats()
2750
2751	// Session should be safe by default, so inserting it again must fail.
2752	err = coll.Insert(M{"_id": 1})
2753	c.Assert(err, ErrorMatches, ".*E11000 duplicate.*")
2754	c.Assert(err.(*mgo.LastError).Code, Equals, 11000)
2755
2756	// It must have sent two operations (INSERT_OP + getLastError QUERY_OP)
2757	stats := mgo.GetStats()
2758
2759	if s.versionAtLeast(2, 6) {
2760		c.Assert(stats.SentOps, Equals, 1)
2761	} else {
2762		c.Assert(stats.SentOps, Equals, 2)
2763	}
2764
2765	mgo.ResetStats()
2766
2767	// If we disable safety, though, it won't complain.
2768	session.SetSafe(nil)
2769	err = coll.Insert(M{"_id": 1})
2770	c.Assert(err, IsNil)
2771
2772	// Must have sent a single operation this time (just the INSERT_OP)
2773	stats = mgo.GetStats()
2774	c.Assert(stats.SentOps, Equals, 1)
2775}
2776
2777func (s *S) TestSafeParameters(c *C) {
2778	session, err := mgo.Dial("localhost:40011")
2779	c.Assert(err, IsNil)
2780	defer session.Close()
2781
2782	coll := session.DB("mydb").C("mycoll")
2783
2784	// Tweak the safety parameters to something unachievable.
2785	session.SetSafe(&mgo.Safe{W: 4, WTimeout: 100})
2786	err = coll.Insert(M{"_id": 1})
2787	c.Assert(err, ErrorMatches, "timeout|timed out waiting for slaves|Not enough data-bearing nodes|waiting for replication timed out") // :-(
2788	if !s.versionAtLeast(2, 6) {
2789		// 2.6 turned it into a query error.
2790		c.Assert(err.(*mgo.LastError).WTimeout, Equals, true)
2791	}
2792}
2793
2794func (s *S) TestQueryErrorOne(c *C) {
2795	session, err := mgo.Dial("localhost:40001")
2796	c.Assert(err, IsNil)
2797	defer session.Close()
2798
2799	coll := session.DB("mydb").C("mycoll")
2800
2801	err = coll.Find(M{"a": 1}).Select(M{"a": M{"b": 1}}).One(nil)
2802	c.Assert(err, ErrorMatches, ".*Unsupported projection option:.*")
2803	c.Assert(err.(*mgo.QueryError).Message, Matches, ".*Unsupported projection option:.*")
2804	// Oh, the dance of error codes. :-(
2805	if s.versionAtLeast(3, 2) {
2806		c.Assert(err.(*mgo.QueryError).Code, Equals, 2)
2807	} else if s.versionAtLeast(2, 6) {
2808		c.Assert(err.(*mgo.QueryError).Code, Equals, 17287)
2809	} else {
2810		c.Assert(err.(*mgo.QueryError).Code, Equals, 13097)
2811	}
2812}
2813
2814func (s *S) TestQueryErrorNext(c *C) {
2815	session, err := mgo.Dial("localhost:40001")
2816	c.Assert(err, IsNil)
2817	defer session.Close()
2818
2819	coll := session.DB("mydb").C("mycoll")
2820
2821	iter := coll.Find(M{"a": 1}).Select(M{"a": M{"b": 1}}).Iter()
2822
2823	var result struct{}
2824	ok := iter.Next(&result)
2825	c.Assert(ok, Equals, false)
2826
2827	err = iter.Close()
2828	c.Assert(err, ErrorMatches, ".*Unsupported projection option:.*")
2829	c.Assert(err.(*mgo.QueryError).Message, Matches, ".*Unsupported projection option:.*")
2830	// Oh, the dance of error codes. :-(
2831	if s.versionAtLeast(3, 2) {
2832		c.Assert(err.(*mgo.QueryError).Code, Equals, 2)
2833	} else if s.versionAtLeast(2, 6) {
2834		c.Assert(err.(*mgo.QueryError).Code, Equals, 17287)
2835	} else {
2836		c.Assert(err.(*mgo.QueryError).Code, Equals, 13097)
2837	}
2838	c.Assert(iter.Err(), Equals, err)
2839}
2840
2841var indexTests = []struct {
2842	index    mgo.Index
2843	expected M
2844}{{
2845	mgo.Index{
2846		Key:        []string{"a"},
2847		Background: true,
2848	},
2849	M{
2850		"name":       "a_1",
2851		"key":        M{"a": 1},
2852		"ns":         "mydb.mycoll",
2853		"background": true,
2854	},
2855}, {
2856	mgo.Index{
2857		Key:      []string{"a", "-b"},
2858		Unique:   true,
2859		DropDups: true,
2860	},
2861	M{
2862		"name":     "a_1_b_-1",
2863		"key":      M{"a": 1, "b": -1},
2864		"ns":       "mydb.mycoll",
2865		"unique":   true,
2866		"dropDups": true,
2867	},
2868}, {
2869	mgo.Index{
2870		Key:  []string{"@loc_old"}, // Obsolete
2871		Min:  -500,
2872		Max:  500,
2873		Bits: 32,
2874	},
2875	M{
2876		"name": "loc_old_2d",
2877		"key":  M{"loc_old": "2d"},
2878		"ns":   "mydb.mycoll",
2879		"min":  -500.0,
2880		"max":  500.0,
2881		"bits": 32,
2882	},
2883}, {
2884	mgo.Index{
2885		Key:  []string{"$2d:loc"},
2886		Min:  -500,
2887		Max:  500,
2888		Bits: 32,
2889	},
2890	M{
2891		"name": "loc_2d",
2892		"key":  M{"loc": "2d"},
2893		"ns":   "mydb.mycoll",
2894		"min":  -500.0,
2895		"max":  500.0,
2896		"bits": 32,
2897	},
2898}, {
2899	mgo.Index{
2900		Key:  []string{"$2d:loc"},
2901		Minf: -500.1,
2902		Maxf: 500.1,
2903		Min:  1, // Should be ignored
2904		Max:  2,
2905		Bits: 32,
2906	},
2907	M{
2908		"name": "loc_2d",
2909		"key":  M{"loc": "2d"},
2910		"ns":   "mydb.mycoll",
2911		"min":  -500.1,
2912		"max":  500.1,
2913		"bits": 32,
2914	},
2915}, {
2916	mgo.Index{
2917		Key:        []string{"$geoHaystack:loc", "type"},
2918		BucketSize: 1,
2919	},
2920	M{
2921		"name":       "loc_geoHaystack_type_1",
2922		"key":        M{"loc": "geoHaystack", "type": 1},
2923		"ns":         "mydb.mycoll",
2924		"bucketSize": 1.0,
2925	},
2926}, {
2927	mgo.Index{
2928		Key:     []string{"$text:a", "$text:b"},
2929		Weights: map[string]int{"b": 42},
2930	},
2931	M{
2932		"name":              "a_text_b_text",
2933		"key":               M{"_fts": "text", "_ftsx": 1},
2934		"ns":                "mydb.mycoll",
2935		"weights":           M{"a": 1, "b": 42},
2936		"default_language":  "english",
2937		"language_override": "language",
2938		"textIndexVersion":  2,
2939	},
2940}, {
2941	mgo.Index{
2942		Key:              []string{"$text:a"},
2943		DefaultLanguage:  "portuguese",
2944		LanguageOverride: "idioma",
2945	},
2946	M{
2947		"name":              "a_text",
2948		"key":               M{"_fts": "text", "_ftsx": 1},
2949		"ns":                "mydb.mycoll",
2950		"weights":           M{"a": 1},
2951		"default_language":  "portuguese",
2952		"language_override": "idioma",
2953		"textIndexVersion":  2,
2954	},
2955}, {
2956	mgo.Index{
2957		Key: []string{"$text:$**"},
2958	},
2959	M{
2960		"name":              "$**_text",
2961		"key":               M{"_fts": "text", "_ftsx": 1},
2962		"ns":                "mydb.mycoll",
2963		"weights":           M{"$**": 1},
2964		"default_language":  "english",
2965		"language_override": "language",
2966		"textIndexVersion":  2,
2967	},
2968}, {
2969	mgo.Index{
2970		Key:  []string{"cn"},
2971		Name: "CustomName",
2972	},
2973	M{
2974		"name": "CustomName",
2975		"key":  M{"cn": 1},
2976		"ns":   "mydb.mycoll",
2977	},
2978}}
2979
2980func (s *S) TestEnsureIndex(c *C) {
2981	session, err := mgo.Dial("localhost:40001")
2982	c.Assert(err, IsNil)
2983	defer session.Close()
2984
2985	coll := session.DB("mydb").C("mycoll")
2986	idxs := session.DB("mydb").C("system.indexes")
2987
2988	for _, test := range indexTests {
2989		if !s.versionAtLeast(2, 4) && test.expected["textIndexVersion"] != nil {
2990			continue
2991		}
2992
2993		err = coll.EnsureIndex(test.index)
2994		msg := "text search not enabled"
2995		if err != nil && strings.Contains(err.Error(), msg) {
2996			continue
2997		}
2998		c.Assert(err, IsNil)
2999
3000		expectedName := test.index.Name
3001		if expectedName == "" {
3002			expectedName, _ = test.expected["name"].(string)
3003		}
3004
3005		obtained := M{}
3006		err = idxs.Find(M{"name": expectedName}).One(obtained)
3007		c.Assert(err, IsNil)
3008
3009		delete(obtained, "v")
3010
3011		if s.versionAtLeast(2, 7) {
3012			// Was deprecated in 2.6, and not being reported by 2.7+.
3013			delete(test.expected, "dropDups")
3014			test.index.DropDups = false
3015		}
3016		if s.versionAtLeast(3, 2) && test.expected["textIndexVersion"] != nil {
3017			test.expected["textIndexVersion"] = 3
3018		}
3019
3020		c.Assert(obtained, DeepEquals, test.expected)
3021
3022		// The result of Indexes must match closely what was used to create the index.
3023		indexes, err := coll.Indexes()
3024		c.Assert(err, IsNil)
3025		c.Assert(indexes, HasLen, 2)
3026		gotIndex := indexes[0]
3027		if gotIndex.Name == "_id_" {
3028			gotIndex = indexes[1]
3029		}
3030		wantIndex := test.index
3031		if wantIndex.Name == "" {
3032			wantIndex.Name = gotIndex.Name
3033		}
3034		if strings.HasPrefix(wantIndex.Key[0], "@") {
3035			wantIndex.Key[0] = "$2d:" + wantIndex.Key[0][1:]
3036		}
3037		if wantIndex.Minf == 0 && wantIndex.Maxf == 0 {
3038			wantIndex.Minf = float64(wantIndex.Min)
3039			wantIndex.Maxf = float64(wantIndex.Max)
3040		} else {
3041			wantIndex.Min = gotIndex.Min
3042			wantIndex.Max = gotIndex.Max
3043		}
3044		if wantIndex.DefaultLanguage == "" {
3045			wantIndex.DefaultLanguage = gotIndex.DefaultLanguage
3046		}
3047		if wantIndex.LanguageOverride == "" {
3048			wantIndex.LanguageOverride = gotIndex.LanguageOverride
3049		}
3050		for name, _ := range gotIndex.Weights {
3051			if _, ok := wantIndex.Weights[name]; !ok {
3052				if wantIndex.Weights == nil {
3053					wantIndex.Weights = make(map[string]int)
3054				}
3055				wantIndex.Weights[name] = 1
3056			}
3057		}
3058		c.Assert(gotIndex, DeepEquals, wantIndex)
3059
3060		// Drop created index by key or by name if a custom name was used.
3061		if test.index.Name == "" {
3062			err = coll.DropIndex(test.index.Key...)
3063			c.Assert(err, IsNil)
3064		} else {
3065			err = coll.DropIndexName(test.index.Name)
3066			c.Assert(err, IsNil)
3067		}
3068	}
3069}
3070
3071func (s *S) TestEnsureIndexWithBadInfo(c *C) {
3072	session, err := mgo.Dial("localhost:40001")
3073	c.Assert(err, IsNil)
3074	defer session.Close()
3075
3076	coll := session.DB("mydb").C("mycoll")
3077
3078	err = coll.EnsureIndex(mgo.Index{})
3079	c.Assert(err, ErrorMatches, "invalid index key:.*")
3080
3081	err = coll.EnsureIndex(mgo.Index{Key: []string{""}})
3082	c.Assert(err, ErrorMatches, "invalid index key:.*")
3083}
3084
3085func (s *S) TestEnsureIndexWithUnsafeSession(c *C) {
3086	session, err := mgo.Dial("localhost:40001")
3087	c.Assert(err, IsNil)
3088	defer session.Close()
3089
3090	session.SetSafe(nil)
3091
3092	coll := session.DB("mydb").C("mycoll")
3093
3094	err = coll.Insert(M{"a": 1})
3095	c.Assert(err, IsNil)
3096
3097	err = coll.Insert(M{"a": 1})
3098	c.Assert(err, IsNil)
3099
3100	// Should fail since there are duplicated entries.
3101	index := mgo.Index{
3102		Key:    []string{"a"},
3103		Unique: true,
3104	}
3105
3106	err = coll.EnsureIndex(index)
3107	c.Assert(err, ErrorMatches, ".*duplicate key error.*")
3108}
3109
3110func (s *S) TestEnsureIndexKey(c *C) {
3111	session, err := mgo.Dial("localhost:40001")
3112	c.Assert(err, IsNil)
3113	defer session.Close()
3114
3115	coll := session.DB("mydb").C("mycoll")
3116
3117	err = coll.EnsureIndexKey("a")
3118	c.Assert(err, IsNil)
3119
3120	err = coll.EnsureIndexKey("a", "-b")
3121	c.Assert(err, IsNil)
3122
3123	sysidx := session.DB("mydb").C("system.indexes")
3124
3125	result1 := M{}
3126	err = sysidx.Find(M{"name": "a_1"}).One(result1)
3127	c.Assert(err, IsNil)
3128
3129	result2 := M{}
3130	err = sysidx.Find(M{"name": "a_1_b_-1"}).One(result2)
3131	c.Assert(err, IsNil)
3132
3133	delete(result1, "v")
3134	expected1 := M{
3135		"name": "a_1",
3136		"key":  M{"a": 1},
3137		"ns":   "mydb.mycoll",
3138	}
3139	c.Assert(result1, DeepEquals, expected1)
3140
3141	delete(result2, "v")
3142	expected2 := M{
3143		"name": "a_1_b_-1",
3144		"key":  M{"a": 1, "b": -1},
3145		"ns":   "mydb.mycoll",
3146	}
3147	c.Assert(result2, DeepEquals, expected2)
3148}
3149
3150func (s *S) TestEnsureIndexDropIndex(c *C) {
3151	session, err := mgo.Dial("localhost:40001")
3152	c.Assert(err, IsNil)
3153	defer session.Close()
3154
3155	coll := session.DB("mydb").C("mycoll")
3156
3157	err = coll.EnsureIndexKey("a")
3158	c.Assert(err, IsNil)
3159
3160	err = coll.EnsureIndexKey("-b")
3161	c.Assert(err, IsNil)
3162
3163	err = coll.DropIndex("-b")
3164	c.Assert(err, IsNil)
3165
3166	sysidx := session.DB("mydb").C("system.indexes")
3167
3168	err = sysidx.Find(M{"name": "a_1"}).One(nil)
3169	c.Assert(err, IsNil)
3170
3171	err = sysidx.Find(M{"name": "b_1"}).One(nil)
3172	c.Assert(err, Equals, mgo.ErrNotFound)
3173
3174	err = coll.DropIndex("a")
3175	c.Assert(err, IsNil)
3176
3177	err = sysidx.Find(M{"name": "a_1"}).One(nil)
3178	c.Assert(err, Equals, mgo.ErrNotFound)
3179
3180	err = coll.DropIndex("a")
3181	c.Assert(err, ErrorMatches, "index not found.*")
3182}
3183
3184func (s *S) TestEnsureIndexDropIndexName(c *C) {
3185	session, err := mgo.Dial("localhost:40001")
3186	c.Assert(err, IsNil)
3187	defer session.Close()
3188
3189	coll := session.DB("mydb").C("mycoll")
3190
3191	err = coll.EnsureIndexKey("a")
3192	c.Assert(err, IsNil)
3193
3194	err = coll.EnsureIndex(mgo.Index{Key: []string{"b"}, Name: "a"})
3195	c.Assert(err, IsNil)
3196
3197	err = coll.DropIndexName("a")
3198	c.Assert(err, IsNil)
3199
3200	sysidx := session.DB("mydb").C("system.indexes")
3201
3202	err = sysidx.Find(M{"name": "a_1"}).One(nil)
3203	c.Assert(err, IsNil)
3204
3205	err = sysidx.Find(M{"name": "a"}).One(nil)
3206	c.Assert(err, Equals, mgo.ErrNotFound)
3207
3208	err = coll.DropIndexName("a_1")
3209	c.Assert(err, IsNil)
3210
3211	err = sysidx.Find(M{"name": "a_1"}).One(nil)
3212	c.Assert(err, Equals, mgo.ErrNotFound)
3213
3214	err = coll.DropIndexName("a_1")
3215	c.Assert(err, ErrorMatches, "index not found.*")
3216}
3217
3218func (s *S) TestEnsureIndexCaching(c *C) {
3219	session, err := mgo.Dial("localhost:40001")
3220	c.Assert(err, IsNil)
3221	defer session.Close()
3222
3223	coll := session.DB("mydb").C("mycoll")
3224
3225	err = coll.EnsureIndexKey("a")
3226	c.Assert(err, IsNil)
3227
3228	mgo.ResetStats()
3229
3230	// Second EnsureIndex should be cached and do nothing.
3231	err = coll.EnsureIndexKey("a")
3232	c.Assert(err, IsNil)
3233
3234	stats := mgo.GetStats()
3235	c.Assert(stats.SentOps, Equals, 0)
3236
3237	// Resetting the cache should make it contact the server again.
3238	session.ResetIndexCache()
3239
3240	err = coll.EnsureIndexKey("a")
3241	c.Assert(err, IsNil)
3242
3243	stats = mgo.GetStats()
3244	c.Assert(stats.SentOps > 0, Equals, true)
3245
3246	// Dropping the index should also drop the cached index key.
3247	err = coll.DropIndex("a")
3248	c.Assert(err, IsNil)
3249
3250	mgo.ResetStats()
3251
3252	err = coll.EnsureIndexKey("a")
3253	c.Assert(err, IsNil)
3254
3255	stats = mgo.GetStats()
3256	c.Assert(stats.SentOps > 0, Equals, true)
3257}
3258
3259func (s *S) TestEnsureIndexGetIndexes(c *C) {
3260	session, err := mgo.Dial("localhost:40001")
3261	c.Assert(err, IsNil)
3262	defer session.Close()
3263
3264	coll := session.DB("mydb").C("mycoll")
3265
3266	err = coll.EnsureIndexKey("-b")
3267	c.Assert(err, IsNil)
3268
3269	err = coll.EnsureIndexKey("a")
3270	c.Assert(err, IsNil)
3271
3272	// Obsolete.
3273	err = coll.EnsureIndexKey("@c")
3274	c.Assert(err, IsNil)
3275
3276	err = coll.EnsureIndexKey("$2d:d")
3277	c.Assert(err, IsNil)
3278
3279	// Try to exercise cursor logic. 2.8.0-rc3 still ignores this.
3280	session.SetBatch(2)
3281
3282	indexes, err := coll.Indexes()
3283	c.Assert(err, IsNil)
3284
3285	c.Assert(indexes[0].Name, Equals, "_id_")
3286	c.Assert(indexes[1].Name, Equals, "a_1")
3287	c.Assert(indexes[1].Key, DeepEquals, []string{"a"})
3288	c.Assert(indexes[2].Name, Equals, "b_-1")
3289	c.Assert(indexes[2].Key, DeepEquals, []string{"-b"})
3290	c.Assert(indexes[3].Name, Equals, "c_2d")
3291	c.Assert(indexes[3].Key, DeepEquals, []string{"$2d:c"})
3292	c.Assert(indexes[4].Name, Equals, "d_2d")
3293	c.Assert(indexes[4].Key, DeepEquals, []string{"$2d:d"})
3294}
3295
3296func (s *S) TestEnsureIndexNameCaching(c *C) {
3297	session, err := mgo.Dial("localhost:40001")
3298	c.Assert(err, IsNil)
3299	defer session.Close()
3300
3301	coll := session.DB("mydb").C("mycoll")
3302
3303	err = coll.EnsureIndex(mgo.Index{Key: []string{"a"}, Name: "custom"})
3304	c.Assert(err, IsNil)
3305
3306	mgo.ResetStats()
3307
3308	// Second EnsureIndex should be cached and do nothing.
3309	err = coll.EnsureIndexKey("a")
3310	c.Assert(err, IsNil)
3311
3312	err = coll.EnsureIndex(mgo.Index{Key: []string{"a"}, Name: "custom"})
3313	c.Assert(err, IsNil)
3314
3315	stats := mgo.GetStats()
3316	c.Assert(stats.SentOps, Equals, 0)
3317
3318	// Resetting the cache should make it contact the server again.
3319	session.ResetIndexCache()
3320
3321	err = coll.EnsureIndex(mgo.Index{Key: []string{"a"}, Name: "custom"})
3322	c.Assert(err, IsNil)
3323
3324	stats = mgo.GetStats()
3325	c.Assert(stats.SentOps > 0, Equals, true)
3326
3327	// Dropping the index should also drop the cached index key.
3328	err = coll.DropIndexName("custom")
3329	c.Assert(err, IsNil)
3330
3331	mgo.ResetStats()
3332
3333	err = coll.EnsureIndex(mgo.Index{Key: []string{"a"}, Name: "custom"})
3334	c.Assert(err, IsNil)
3335
3336	stats = mgo.GetStats()
3337	c.Assert(stats.SentOps > 0, Equals, true)
3338}
3339
3340func (s *S) TestEnsureIndexEvalGetIndexes(c *C) {
3341	session, err := mgo.Dial("localhost:40001")
3342	c.Assert(err, IsNil)
3343	defer session.Close()
3344
3345	coll := session.DB("mydb").C("mycoll")
3346
3347	err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({b: -1})"}}, nil)
3348	c.Assert(err, IsNil)
3349	err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({a: 1})"}}, nil)
3350	c.Assert(err, IsNil)
3351	err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({c: -1, e: 1})"}}, nil)
3352	c.Assert(err, IsNil)
3353	err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({d: '2d'})"}}, nil)
3354	c.Assert(err, IsNil)
3355
3356	indexes, err := coll.Indexes()
3357	c.Assert(err, IsNil)
3358
3359	c.Assert(indexes[0].Name, Equals, "_id_")
3360	c.Assert(indexes[1].Name, Equals, "a_1")
3361	c.Assert(indexes[1].Key, DeepEquals, []string{"a"})
3362	c.Assert(indexes[2].Name, Equals, "b_-1")
3363	c.Assert(indexes[2].Key, DeepEquals, []string{"-b"})
3364	c.Assert(indexes[3].Name, Equals, "c_-1_e_1")
3365	c.Assert(indexes[3].Key, DeepEquals, []string{"-c", "e"})
3366	if s.versionAtLeast(2, 2) {
3367		c.Assert(indexes[4].Name, Equals, "d_2d")
3368		c.Assert(indexes[4].Key, DeepEquals, []string{"$2d:d"})
3369	} else {
3370		c.Assert(indexes[4].Name, Equals, "d_")
3371		c.Assert(indexes[4].Key, DeepEquals, []string{"$2d:d"})
3372	}
3373}
3374
3375var testTTL = flag.Bool("test-ttl", false, "test TTL collections (may take 1 minute)")
3376
3377func (s *S) TestEnsureIndexExpireAfter(c *C) {
3378	session, err := mgo.Dial("localhost:40001")
3379	c.Assert(err, IsNil)
3380	defer session.Close()
3381
3382	session.SetSafe(nil)
3383
3384	coll := session.DB("mydb").C("mycoll")
3385
3386	err = coll.Insert(M{"n": 1, "t": time.Now().Add(-120 * time.Second)})
3387	c.Assert(err, IsNil)
3388	err = coll.Insert(M{"n": 2, "t": time.Now()})
3389	c.Assert(err, IsNil)
3390
3391	// Should fail since there are duplicated entries.
3392	index := mgo.Index{
3393		Key:         []string{"t"},
3394		ExpireAfter: 1 * time.Minute,
3395	}
3396
3397	err = coll.EnsureIndex(index)
3398	c.Assert(err, IsNil)
3399
3400	indexes, err := coll.Indexes()
3401	c.Assert(err, IsNil)
3402	c.Assert(indexes[1].Name, Equals, "t_1")
3403	c.Assert(indexes[1].ExpireAfter, Equals, 1*time.Minute)
3404
3405	if *testTTL {
3406		worked := false
3407		stop := time.Now().Add(70 * time.Second)
3408		for time.Now().Before(stop) {
3409			n, err := coll.Count()
3410			c.Assert(err, IsNil)
3411			if n == 1 {
3412				worked = true
3413				break
3414			}
3415			c.Assert(n, Equals, 2)
3416			c.Logf("Still has 2 entries...")
3417			time.Sleep(1 * time.Second)
3418		}
3419		if !worked {
3420			c.Fatalf("TTL index didn't work")
3421		}
3422	}
3423}
3424
3425func (s *S) TestDistinct(c *C) {
3426	session, err := mgo.Dial("localhost:40001")
3427	c.Assert(err, IsNil)
3428	defer session.Close()
3429
3430	coll := session.DB("mydb").C("mycoll")
3431
3432	for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {
3433		coll.Insert(M{"n": i})
3434	}
3435
3436	var result []int
3437	err = coll.Find(M{"n": M{"$gt": 2}}).Sort("n").Distinct("n", &result)
3438
3439	sort.IntSlice(result).Sort()
3440	c.Assert(result, DeepEquals, []int{3, 4, 6})
3441}
3442
3443func (s *S) TestMapReduce(c *C) {
3444	session, err := mgo.Dial("localhost:40001")
3445	c.Assert(err, IsNil)
3446	defer session.Close()
3447
3448	coll := session.DB("mydb").C("mycoll")
3449
3450	for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {
3451		coll.Insert(M{"n": i})
3452	}
3453
3454	job := &mgo.MapReduce{
3455		Map:    "function() { emit(this.n, 1); }",
3456		Reduce: "function(key, values) { return Array.sum(values); }",
3457	}
3458	var result []struct {
3459		Id    int "_id"
3460		Value int
3461	}
3462
3463	info, err := coll.Find(M{"n": M{"$gt": 2}}).MapReduce(job, &result)
3464	c.Assert(err, IsNil)
3465	c.Assert(info.InputCount, Equals, 4)
3466	c.Assert(info.EmitCount, Equals, 4)
3467	c.Assert(info.OutputCount, Equals, 3)
3468	c.Assert(info.VerboseTime, IsNil)
3469
3470	expected := map[int]int{3: 1, 4: 2, 6: 1}
3471	for _, item := range result {
3472		c.Logf("Item: %#v", &item)
3473		c.Assert(item.Value, Equals, expected[item.Id])
3474		expected[item.Id] = -1
3475	}
3476}
3477
3478func (s *S) TestMapReduceFinalize(c *C) {
3479	session, err := mgo.Dial("localhost:40001")
3480	c.Assert(err, IsNil)
3481	defer session.Close()
3482
3483	coll := session.DB("mydb").C("mycoll")
3484
3485	for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {
3486		coll.Insert(M{"n": i})
3487	}
3488
3489	job := &mgo.MapReduce{
3490		Map:      "function() { emit(this.n, 1) }",
3491		Reduce:   "function(key, values) { return Array.sum(values) }",
3492		Finalize: "function(key, count) { return {count: count} }",
3493	}
3494	var result []struct {
3495		Id    int "_id"
3496		Value struct{ Count int }
3497	}
3498	_, err = coll.Find(nil).MapReduce(job, &result)
3499	c.Assert(err, IsNil)
3500
3501	expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1}
3502	for _, item := range result {
3503		c.Logf("Item: %#v", &item)
3504		c.Assert(item.Value.Count, Equals, expected[item.Id])
3505		expected[item.Id] = -1
3506	}
3507}
3508
3509func (s *S) TestMapReduceToCollection(c *C) {
3510	session, err := mgo.Dial("localhost:40001")
3511	c.Assert(err, IsNil)
3512	defer session.Close()
3513
3514	coll := session.DB("mydb").C("mycoll")
3515
3516	for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {
3517		coll.Insert(M{"n": i})
3518	}
3519
3520	job := &mgo.MapReduce{
3521		Map:    "function() { emit(this.n, 1); }",
3522		Reduce: "function(key, values) { return Array.sum(values); }",
3523		Out:    "mr",
3524	}
3525
3526	info, err := coll.Find(nil).MapReduce(job, nil)
3527	c.Assert(err, IsNil)
3528	c.Assert(info.InputCount, Equals, 7)
3529	c.Assert(info.EmitCount, Equals, 7)
3530	c.Assert(info.OutputCount, Equals, 5)
3531	c.Assert(info.Collection, Equals, "mr")
3532	c.Assert(info.Database, Equals, "mydb")
3533
3534	expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1}
3535	var item *struct {
3536		Id    int "_id"
3537		Value int
3538	}
3539	mr := session.DB("mydb").C("mr")
3540	iter := mr.Find(nil).Iter()
3541	for iter.Next(&item) {
3542		c.Logf("Item: %#v", &item)
3543		c.Assert(item.Value, Equals, expected[item.Id])
3544		expected[item.Id] = -1
3545	}
3546	c.Assert(iter.Close(), IsNil)
3547}
3548
3549func (s *S) TestMapReduceToOtherDb(c *C) {
3550	session, err := mgo.Dial("localhost:40001")
3551	c.Assert(err, IsNil)
3552	defer session.Close()
3553
3554	coll := session.DB("mydb").C("mycoll")
3555
3556	for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {
3557		coll.Insert(M{"n": i})
3558	}
3559
3560	job := &mgo.MapReduce{
3561		Map:    "function() { emit(this.n, 1); }",
3562		Reduce: "function(key, values) { return Array.sum(values); }",
3563		Out:    bson.D{{"replace", "mr"}, {"db", "otherdb"}},
3564	}
3565
3566	info, err := coll.Find(nil).MapReduce(job, nil)
3567	c.Assert(err, IsNil)
3568	c.Assert(info.InputCount, Equals, 7)
3569	c.Assert(info.EmitCount, Equals, 7)
3570	c.Assert(info.OutputCount, Equals, 5)
3571	c.Assert(info.Collection, Equals, "mr")
3572	c.Assert(info.Database, Equals, "otherdb")
3573
3574	expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1}
3575	var item *struct {
3576		Id    int "_id"
3577		Value int
3578	}
3579	mr := session.DB("otherdb").C("mr")
3580	iter := mr.Find(nil).Iter()
3581	for iter.Next(&item) {
3582		c.Logf("Item: %#v", &item)
3583		c.Assert(item.Value, Equals, expected[item.Id])
3584		expected[item.Id] = -1
3585	}
3586	c.Assert(iter.Close(), IsNil)
3587}
3588
3589func (s *S) TestMapReduceOutOfOrder(c *C) {
3590	session, err := mgo.Dial("localhost:40001")
3591	c.Assert(err, IsNil)
3592	defer session.Close()
3593
3594	coll := session.DB("mydb").C("mycoll")
3595
3596	for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {
3597		coll.Insert(M{"n": i})
3598	}
3599
3600	job := &mgo.MapReduce{
3601		Map:    "function() { emit(this.n, 1); }",
3602		Reduce: "function(key, values) { return Array.sum(values); }",
3603		Out:    bson.M{"a": "a", "z": "z", "replace": "mr", "db": "otherdb", "b": "b", "y": "y"},
3604	}
3605
3606	info, err := coll.Find(nil).MapReduce(job, nil)
3607	c.Assert(err, IsNil)
3608	c.Assert(info.Collection, Equals, "mr")
3609	c.Assert(info.Database, Equals, "otherdb")
3610}
3611
3612func (s *S) TestMapReduceScope(c *C) {
3613	session, err := mgo.Dial("localhost:40001")
3614	c.Assert(err, IsNil)
3615	defer session.Close()
3616
3617	coll := session.DB("mydb").C("mycoll")
3618
3619	coll.Insert(M{"n": 1})
3620
3621	job := &mgo.MapReduce{
3622		Map:    "function() { emit(this.n, x); }",
3623		Reduce: "function(key, values) { return Array.sum(values); }",
3624		Scope:  M{"x": 42},
3625	}
3626
3627	var result []bson.M
3628	_, err = coll.Find(nil).MapReduce(job, &result)
3629	c.Assert(len(result), Equals, 1)
3630	c.Assert(result[0]["value"], Equals, 42.0)
3631}
3632
3633func (s *S) TestMapReduceVerbose(c *C) {
3634	session, err := mgo.Dial("localhost:40001")
3635	c.Assert(err, IsNil)
3636	defer session.Close()
3637
3638	coll := session.DB("mydb").C("mycoll")
3639
3640	for i := 0; i < 100; i++ {
3641		err = coll.Insert(M{"n": i})
3642		c.Assert(err, IsNil)
3643	}
3644
3645	job := &mgo.MapReduce{
3646		Map:     "function() { emit(this.n, 1); }",
3647		Reduce:  "function(key, values) { return Array.sum(values); }",
3648		Verbose: true,
3649	}
3650
3651	info, err := coll.Find(nil).MapReduce(job, nil)
3652	c.Assert(err, IsNil)
3653	c.Assert(info.VerboseTime, NotNil)
3654}
3655
3656func (s *S) TestMapReduceLimit(c *C) {
3657	session, err := mgo.Dial("localhost:40001")
3658	c.Assert(err, IsNil)
3659	defer session.Close()
3660
3661	coll := session.DB("mydb").C("mycoll")
3662
3663	for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {
3664		coll.Insert(M{"n": i})
3665	}
3666
3667	job := &mgo.MapReduce{
3668		Map:    "function() { emit(this.n, 1); }",
3669		Reduce: "function(key, values) { return Array.sum(values); }",
3670	}
3671
3672	var result []bson.M
3673	_, err = coll.Find(nil).Limit(3).MapReduce(job, &result)
3674	c.Assert(err, IsNil)
3675	c.Assert(len(result), Equals, 3)
3676}
3677
3678func (s *S) TestBuildInfo(c *C) {
3679	session, err := mgo.Dial("localhost:40001")
3680	c.Assert(err, IsNil)
3681	defer session.Close()
3682
3683	info, err := session.BuildInfo()
3684	c.Assert(err, IsNil)
3685
3686	var v []int
3687	for i, a := range strings.Split(info.Version, ".") {
3688		for _, token := range []string{"-rc", "-pre"} {
3689			if i == 2 && strings.Contains(a, token) {
3690				a = a[:strings.Index(a, token)]
3691				info.VersionArray[len(info.VersionArray)-1] = 0
3692			}
3693		}
3694		n, err := strconv.Atoi(a)
3695		c.Assert(err, IsNil)
3696		v = append(v, n)
3697	}
3698	for len(v) < 4 {
3699		v = append(v, 0)
3700	}
3701
3702	c.Assert(info.VersionArray, DeepEquals, v)
3703	c.Assert(info.GitVersion, Matches, "[a-z0-9]+")
3704
3705	if s.versionAtLeast(3, 2) {
3706		// It was deprecated in 3.2.
3707		c.Assert(info.SysInfo, Equals, "")
3708	} else {
3709		c.Assert(info.SysInfo, Matches, ".*[0-9:]+.*")
3710	}
3711	if info.Bits != 32 && info.Bits != 64 {
3712		c.Fatalf("info.Bits is %d", info.Bits)
3713	}
3714	if info.MaxObjectSize < 8192 {
3715		c.Fatalf("info.MaxObjectSize seems too small: %d", info.MaxObjectSize)
3716	}
3717}
3718
3719func (s *S) TestZeroTimeRoundtrip(c *C) {
3720	session, err := mgo.Dial("localhost:40001")
3721	c.Assert(err, IsNil)
3722	defer session.Close()
3723
3724	var d struct{ T time.Time }
3725	conn := session.DB("mydb").C("mycoll")
3726	err = conn.Insert(d)
3727	c.Assert(err, IsNil)
3728
3729	var result bson.M
3730	err = conn.Find(nil).One(&result)
3731	c.Assert(err, IsNil)
3732	t, isTime := result["t"].(time.Time)
3733	c.Assert(isTime, Equals, true)
3734	c.Assert(t, Equals, time.Time{})
3735}
3736
3737func (s *S) TestFsyncLock(c *C) {
3738	session, err := mgo.Dial("localhost:40001")
3739	c.Assert(err, IsNil)
3740	defer session.Close()
3741
3742	clone := session.Clone()
3743	defer clone.Close()
3744
3745	err = session.FsyncLock()
3746	c.Assert(err, IsNil)
3747
3748	done := make(chan time.Time)
3749	go func() {
3750		time.Sleep(3 * time.Second)
3751		now := time.Now()
3752		err := session.FsyncUnlock()
3753		c.Check(err, IsNil)
3754		done <- now
3755	}()
3756
3757	err = clone.DB("mydb").C("mycoll").Insert(bson.M{"n": 1})
3758	unlocked := time.Now()
3759	unlocking := <-done
3760	c.Assert(err, IsNil)
3761
3762	c.Assert(unlocked.After(unlocking), Equals, true)
3763}
3764
3765func (s *S) TestFsync(c *C) {
3766	session, err := mgo.Dial("localhost:40001")
3767	c.Assert(err, IsNil)
3768	defer session.Close()
3769
3770	// Not much to do here. Just a smoke check.
3771	err = session.Fsync(false)
3772	c.Assert(err, IsNil)
3773	err = session.Fsync(true)
3774	c.Assert(err, IsNil)
3775}
3776
3777func (s *S) TestRepairCursor(c *C) {
3778	if !s.versionAtLeast(2, 7) {
3779		c.Skip("RepairCursor only works on 2.7+")
3780	}
3781
3782	session, err := mgo.Dial("localhost:40001")
3783	c.Assert(err, IsNil)
3784	defer session.Close()
3785	session.SetBatch(2)
3786
3787	coll := session.DB("mydb").C("mycoll3")
3788	err = coll.DropCollection()
3789
3790	ns := []int{0, 10, 20, 30, 40, 50}
3791	for _, n := range ns {
3792		coll.Insert(M{"n": n})
3793	}
3794
3795	repairIter := coll.Repair()
3796
3797	c.Assert(repairIter.Err(), IsNil)
3798
3799	result := struct{ N int }{}
3800	resultCounts := map[int]int{}
3801	for repairIter.Next(&result) {
3802		resultCounts[result.N]++
3803	}
3804
3805	c.Assert(repairIter.Next(&result), Equals, false)
3806	c.Assert(repairIter.Err(), IsNil)
3807	c.Assert(repairIter.Close(), IsNil)
3808
3809	// Verify that the results of the repair cursor are valid.
3810	// The repair cursor can return multiple copies
3811	// of the same document, so to check correctness we only
3812	// need to verify that at least 1 of each document was returned.
3813
3814	for _, key := range ns {
3815		c.Assert(resultCounts[key] > 0, Equals, true)
3816	}
3817}
3818
3819func (s *S) TestPipeIter(c *C) {
3820	if !s.versionAtLeast(2, 1) {
3821		c.Skip("Pipe only works on 2.1+")
3822	}
3823
3824	session, err := mgo.Dial("localhost:40001")
3825	c.Assert(err, IsNil)
3826	defer session.Close()
3827
3828	coll := session.DB("mydb").C("mycoll")
3829
3830	ns := []int{40, 41, 42, 43, 44, 45, 46}
3831	for _, n := range ns {
3832		coll.Insert(M{"n": n})
3833	}
3834
3835	pipe := coll.Pipe([]M{{"$match": M{"n": M{"$gte": 42}}}})
3836
3837	// Ensure cursor logic is working by forcing a small batch.
3838	pipe.Batch(2)
3839
3840	// Smoke test for AllowDiskUse.
3841	pipe.AllowDiskUse()
3842
3843	iter := pipe.Iter()
3844	result := struct{ N int }{}
3845	for i := 2; i < 7; i++ {
3846		ok := iter.Next(&result)
3847		c.Assert(ok, Equals, true)
3848		c.Assert(result.N, Equals, ns[i])
3849	}
3850
3851	c.Assert(iter.Next(&result), Equals, false)
3852	c.Assert(iter.Close(), IsNil)
3853}
3854
3855func (s *S) TestPipeAll(c *C) {
3856	if !s.versionAtLeast(2, 1) {
3857		c.Skip("Pipe only works on 2.1+")
3858	}
3859
3860	session, err := mgo.Dial("localhost:40001")
3861	c.Assert(err, IsNil)
3862	defer session.Close()
3863
3864	coll := session.DB("mydb").C("mycoll")
3865
3866	ns := []int{40, 41, 42, 43, 44, 45, 46}
3867	for _, n := range ns {
3868		err := coll.Insert(M{"n": n})
3869		c.Assert(err, IsNil)
3870	}
3871
3872	var result []struct{ N int }
3873	err = coll.Pipe([]M{{"$match": M{"n": M{"$gte": 42}}}}).All(&result)
3874	c.Assert(err, IsNil)
3875	for i := 2; i < 7; i++ {
3876		c.Assert(result[i-2].N, Equals, ns[i])
3877	}
3878}
3879
3880func (s *S) TestPipeOne(c *C) {
3881	if !s.versionAtLeast(2, 1) {
3882		c.Skip("Pipe only works on 2.1+")
3883	}
3884
3885	session, err := mgo.Dial("localhost:40001")
3886	c.Assert(err, IsNil)
3887	defer session.Close()
3888
3889	coll := session.DB("mydb").C("mycoll")
3890	coll.Insert(M{"a": 1, "b": 2})
3891
3892	result := struct{ A, B int }{}
3893
3894	pipe := coll.Pipe([]M{{"$project": M{"a": 1, "b": M{"$add": []interface{}{"$b", 1}}}}})
3895	err = pipe.One(&result)
3896	c.Assert(err, IsNil)
3897	c.Assert(result.A, Equals, 1)
3898	c.Assert(result.B, Equals, 3)
3899
3900	pipe = coll.Pipe([]M{{"$match": M{"a": 2}}})
3901	err = pipe.One(&result)
3902	c.Assert(err, Equals, mgo.ErrNotFound)
3903}
3904
3905func (s *S) TestPipeExplain(c *C) {
3906	if !s.versionAtLeast(2, 1) {
3907		c.Skip("Pipe only works on 2.1+")
3908	}
3909
3910	session, err := mgo.Dial("localhost:40001")
3911	c.Assert(err, IsNil)
3912	defer session.Close()
3913
3914	coll := session.DB("mydb").C("mycoll")
3915	coll.Insert(M{"a": 1, "b": 2})
3916
3917	pipe := coll.Pipe([]M{{"$project": M{"a": 1, "b": M{"$add": []interface{}{"$b", 1}}}}})
3918
3919	// The explain command result changes across versions.
3920	var result struct{ Ok int }
3921	err = pipe.Explain(&result)
3922	c.Assert(err, IsNil)
3923	c.Assert(result.Ok, Equals, 1)
3924}
3925
3926func (s *S) TestBatch1Bug(c *C) {
3927	session, err := mgo.Dial("localhost:40001")
3928	c.Assert(err, IsNil)
3929	defer session.Close()
3930
3931	coll := session.DB("mydb").C("mycoll")
3932
3933	for i := 0; i < 3; i++ {
3934		err := coll.Insert(M{"n": i})
3935		c.Assert(err, IsNil)
3936	}
3937
3938	var ns []struct{ N int }
3939	err = coll.Find(nil).Batch(1).All(&ns)
3940	c.Assert(err, IsNil)
3941	c.Assert(len(ns), Equals, 3)
3942
3943	session.SetBatch(1)
3944	err = coll.Find(nil).All(&ns)
3945	c.Assert(err, IsNil)
3946	c.Assert(len(ns), Equals, 3)
3947}
3948
3949func (s *S) TestInterfaceIterBug(c *C) {
3950	session, err := mgo.Dial("localhost:40001")
3951	c.Assert(err, IsNil)
3952	defer session.Close()
3953
3954	coll := session.DB("mydb").C("mycoll")
3955
3956	for i := 0; i < 3; i++ {
3957		err := coll.Insert(M{"n": i})
3958		c.Assert(err, IsNil)
3959	}
3960
3961	var result interface{}
3962
3963	i := 0
3964	iter := coll.Find(nil).Sort("n").Iter()
3965	for iter.Next(&result) {
3966		c.Assert(result.(bson.M)["n"], Equals, i)
3967		i++
3968	}
3969	c.Assert(iter.Close(), IsNil)
3970}
3971
3972func (s *S) TestFindIterCloseKillsCursor(c *C) {
3973	session, err := mgo.Dial("localhost:40001")
3974	c.Assert(err, IsNil)
3975	defer session.Close()
3976
3977	cursors := serverCursorsOpen(session)
3978
3979	coll := session.DB("mydb").C("mycoll")
3980	ns := []int{40, 41, 42, 43, 44, 45, 46}
3981	for _, n := range ns {
3982		err = coll.Insert(M{"n": n})
3983		c.Assert(err, IsNil)
3984	}
3985
3986	iter := coll.Find(nil).Batch(2).Iter()
3987	c.Assert(iter.Next(bson.M{}), Equals, true)
3988
3989	c.Assert(iter.Close(), IsNil)
3990	c.Assert(serverCursorsOpen(session), Equals, cursors)
3991}
3992
3993func (s *S) TestFindIterDoneWithBatches(c *C) {
3994	session, err := mgo.Dial("localhost:40001")
3995	c.Assert(err, IsNil)
3996	defer session.Close()
3997
3998	coll := session.DB("mydb").C("mycoll")
3999
4000	ns := []int{40, 41, 42, 43, 44, 45, 46}
4001	for _, n := range ns {
4002		coll.Insert(M{"n": n})
4003	}
4004
4005	iter := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2).Iter()
4006	result := struct{ N int }{}
4007	for i := 2; i < 7; i++ {
4008		// first check will be with pending local record;
4009		// second will be with open cursor ID but no local
4010		// records
4011		c.Assert(iter.Done(), Equals, false)
4012		ok := iter.Next(&result)
4013		c.Assert(ok, Equals, true, Commentf("err=%v", err))
4014	}
4015
4016	c.Assert(iter.Done(), Equals, true)
4017	ok := iter.Next(&result)
4018	c.Assert(ok, Equals, false)
4019	c.Assert(iter.Close(), IsNil)
4020}
4021
4022func (s *S) TestFindIterDoneErr(c *C) {
4023	session, err := mgo.Dial("localhost:40002")
4024	c.Assert(err, IsNil)
4025	defer session.Close()
4026
4027	coll := session.DB("mydb").C("mycoll")
4028	iter := coll.Find(nil).Iter()
4029
4030	result := struct{}{}
4031	ok := iter.Next(&result)
4032	c.Assert(iter.Done(), Equals, true)
4033	c.Assert(ok, Equals, false)
4034	c.Assert(iter.Err(), ErrorMatches, "unauthorized.*|not authorized.*")
4035}
4036
4037func (s *S) TestFindIterDoneNotFound(c *C) {
4038	session, err := mgo.Dial("localhost:40001")
4039	c.Assert(err, IsNil)
4040	defer session.Close()
4041
4042	coll := session.DB("mydb").C("mycoll")
4043
4044	result := struct{ A, B int }{}
4045	iter := coll.Find(M{"a": 1}).Iter()
4046	ok := iter.Next(&result)
4047	c.Assert(ok, Equals, false)
4048	c.Assert(iter.Done(), Equals, true)
4049}
4050
4051func (s *S) TestLogReplay(c *C) {
4052	session, err := mgo.Dial("localhost:40001")
4053	c.Assert(err, IsNil)
4054	defer session.Close()
4055
4056	coll := session.DB("mydb").C("mycoll")
4057	for i := 0; i < 5; i++ {
4058		err = coll.Insert(M{"ts": time.Now()})
4059		c.Assert(err, IsNil)
4060	}
4061
4062	iter := coll.Find(nil).LogReplay().Iter()
4063	if s.versionAtLeast(2, 6) {
4064		// This used to fail in 2.4. Now it's just a smoke test.
4065		c.Assert(iter.Err(), IsNil)
4066	} else {
4067		c.Assert(iter.Next(bson.M{}), Equals, false)
4068		c.Assert(iter.Err(), ErrorMatches, "no ts field in query")
4069	}
4070}
4071
4072func (s *S) TestSetCursorTimeout(c *C) {
4073	session, err := mgo.Dial("localhost:40001")
4074	c.Assert(err, IsNil)
4075	defer session.Close()
4076
4077	coll := session.DB("mydb").C("mycoll")
4078	err = coll.Insert(M{"n": 42})
4079
4080	// This is just a smoke test. Won't wait 10 minutes for an actual timeout.
4081
4082	session.SetCursorTimeout(0)
4083
4084	var result struct{ N int }
4085	iter := coll.Find(nil).Iter()
4086	c.Assert(iter.Next(&result), Equals, true)
4087	c.Assert(result.N, Equals, 42)
4088	c.Assert(iter.Next(&result), Equals, false)
4089}
4090
4091func (s *S) TestNewIterNoServer(c *C) {
4092	session, err := mgo.Dial("localhost:40001")
4093	c.Assert(err, IsNil)
4094	defer session.Close()
4095
4096	data, err := bson.Marshal(bson.M{"a": 1})
4097
4098	coll := session.DB("mydb").C("mycoll")
4099	iter := coll.NewIter(nil, []bson.Raw{{3, data}}, 42, nil)
4100
4101	var result struct{ A int }
4102	ok := iter.Next(&result)
4103	c.Assert(ok, Equals, true)
4104	c.Assert(result.A, Equals, 1)
4105
4106	ok = iter.Next(&result)
4107	c.Assert(ok, Equals, false)
4108
4109	c.Assert(iter.Err(), ErrorMatches, "server not available")
4110}
4111
4112func (s *S) TestNewIterNoServerPresetErr(c *C) {
4113	session, err := mgo.Dial("localhost:40001")
4114	c.Assert(err, IsNil)
4115	defer session.Close()
4116
4117	data, err := bson.Marshal(bson.M{"a": 1})
4118
4119	coll := session.DB("mydb").C("mycoll")
4120	iter := coll.NewIter(nil, []bson.Raw{{3, data}}, 42, fmt.Errorf("my error"))
4121
4122	var result struct{ A int }
4123	ok := iter.Next(&result)
4124	c.Assert(ok, Equals, true)
4125	c.Assert(result.A, Equals, 1)
4126
4127	ok = iter.Next(&result)
4128	c.Assert(ok, Equals, false)
4129
4130	c.Assert(iter.Err(), ErrorMatches, "my error")
4131}
4132
4133func (s *S) TestBypassValidation(c *C) {
4134	if !s.versionAtLeast(3, 2) {
4135		c.Skip("validation supported on 3.2+")
4136	}
4137	session, err := mgo.Dial("localhost:40001")
4138	c.Assert(err, IsNil)
4139	defer session.Close()
4140
4141	coll := session.DB("mydb").C("mycoll")
4142	err = coll.Insert(M{"n": 1})
4143	c.Assert(err, IsNil)
4144
4145	err = coll.Database.Run(bson.D{
4146		{"collMod", "mycoll"},
4147		{"validator", M{"s": M{"$type": "string"}}},
4148	}, nil)
4149	c.Assert(err, IsNil)
4150
4151	err = coll.Insert(M{"n": 2})
4152	c.Assert(err, ErrorMatches, "Document failed validation")
4153
4154	err = coll.Update(M{"n": 1}, M{"n": 10})
4155	c.Assert(err, ErrorMatches, "Document failed validation")
4156
4157	session.SetBypassValidation(true)
4158
4159	err = coll.Insert(M{"n": 3})
4160	c.Assert(err, IsNil)
4161
4162	err = coll.Update(M{"n": 3}, M{"n": 4})
4163	c.Assert(err, IsNil)
4164
4165	// Ensure this still works. Shouldn't be affected.
4166	err = coll.Remove(M{"n": 1})
4167	c.Assert(err, IsNil)
4168
4169	var result struct{ N int }
4170	var ns []int
4171	iter := coll.Find(nil).Iter()
4172	for iter.Next(&result) {
4173		ns = append(ns, result.N)
4174	}
4175	c.Assert(iter.Err(), IsNil)
4176	sort.Ints(ns)
4177	c.Assert(ns, DeepEquals, []int{4})
4178}
4179
4180func (s *S) TestVersionAtLeast(c *C) {
4181	tests := [][][]int{
4182		{{3, 2, 1}, {3, 2, 0}},
4183		{{3, 2, 1}, {3, 2}},
4184		{{3, 2, 1}, {2, 5, 5, 5}},
4185		{{3, 2, 1}, {2, 5, 5}},
4186		{{3, 2, 1}, {2, 5}},
4187	}
4188	for _, pair := range tests {
4189		bi := mgo.BuildInfo{VersionArray: pair[0]}
4190		c.Assert(bi.VersionAtLeast(pair[1]...), Equals, true)
4191
4192		bi = mgo.BuildInfo{VersionArray: pair[0]}
4193		c.Assert(bi.VersionAtLeast(pair[0]...), Equals, true)
4194
4195		bi = mgo.BuildInfo{VersionArray: pair[1]}
4196		c.Assert(bi.VersionAtLeast(pair[1]...), Equals, true)
4197
4198		bi = mgo.BuildInfo{VersionArray: pair[1]}
4199		c.Assert(bi.VersionAtLeast(pair[0]...), Equals, false)
4200	}
4201}
4202
4203// --------------------------------------------------------------------------
4204// Some benchmarks that require a running database.
4205
4206func (s *S) BenchmarkFindIterRaw(c *C) {
4207	session, err := mgo.Dial("localhost:40001")
4208	c.Assert(err, IsNil)
4209	defer session.Close()
4210
4211	coll := session.DB("mydb").C("mycoll")
4212	doc := bson.D{
4213		{"f2", "a short string"},
4214		{"f3", bson.D{{"1", "one"}, {"2", 2.0}}},
4215		{"f4", []string{"a", "b", "c", "d", "e", "f", "g"}},
4216	}
4217
4218	for i := 0; i < c.N+1; i++ {
4219		err := coll.Insert(doc)
4220		c.Assert(err, IsNil)
4221	}
4222
4223	session.SetBatch(c.N)
4224
4225	var raw bson.Raw
4226	iter := coll.Find(nil).Iter()
4227	iter.Next(&raw)
4228	c.ResetTimer()
4229	i := 0
4230	for iter.Next(&raw) {
4231		i++
4232	}
4233	c.StopTimer()
4234	c.Assert(iter.Err(), IsNil)
4235	c.Assert(i, Equals, c.N)
4236}
4237