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