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