github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/labix.org/v2/mgo/session_test.go (about) 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 27 package mgo_test 28 29 import ( 30 "camlistore.org/third_party/labix.org/v2/mgo" 31 "camlistore.org/third_party/labix.org/v2/mgo/bson" 32 . "camlistore.org/third_party/launchpad.net/gocheck" 33 "flag" 34 "fmt" 35 "math" 36 "reflect" 37 "runtime" 38 "sort" 39 "strconv" 40 "strings" 41 "time" 42 ) 43 44 func (s *S) TestRunString(c *C) { 45 session, err := mgo.Dial("localhost:40001") 46 c.Assert(err, IsNil) 47 defer session.Close() 48 49 result := struct{ Ok int }{} 50 err = session.Run("ping", &result) 51 c.Assert(err, IsNil) 52 c.Assert(result.Ok, Equals, 1) 53 } 54 55 func (s *S) TestRunValue(c *C) { 56 session, err := mgo.Dial("localhost:40001") 57 c.Assert(err, IsNil) 58 defer session.Close() 59 60 result := struct{ Ok int }{} 61 err = session.Run(M{"ping": 1}, &result) 62 c.Assert(err, IsNil) 63 c.Assert(result.Ok, Equals, 1) 64 } 65 66 func (s *S) TestPing(c *C) { 67 session, err := mgo.Dial("localhost:40001") 68 c.Assert(err, IsNil) 69 defer session.Close() 70 71 // Just ensure the nonce has been received. 72 result := struct{}{} 73 err = session.Run("ping", &result) 74 75 mgo.ResetStats() 76 77 err = session.Ping() 78 c.Assert(err, IsNil) 79 80 // Pretty boring. 81 stats := mgo.GetStats() 82 c.Assert(stats.SentOps, Equals, 1) 83 c.Assert(stats.ReceivedOps, Equals, 1) 84 } 85 86 func (s *S) TestURLSingle(c *C) { 87 session, err := mgo.Dial("mongodb://localhost:40001/") 88 c.Assert(err, IsNil) 89 defer session.Close() 90 91 result := struct{ Ok int }{} 92 err = session.Run("ping", &result) 93 c.Assert(err, IsNil) 94 c.Assert(result.Ok, Equals, 1) 95 } 96 97 func (s *S) TestURLMany(c *C) { 98 session, err := mgo.Dial("mongodb://localhost:40011,localhost:40012/") 99 c.Assert(err, IsNil) 100 defer session.Close() 101 102 result := struct{ Ok int }{} 103 err = session.Run("ping", &result) 104 c.Assert(err, IsNil) 105 c.Assert(result.Ok, Equals, 1) 106 } 107 108 func (s *S) TestURLParsing(c *C) { 109 urls := []string{ 110 "localhost:40001?foo=1&bar=2", 111 "localhost:40001?foo=1;bar=2", 112 } 113 for _, url := range urls { 114 session, err := mgo.Dial(url) 115 if session != nil { 116 session.Close() 117 } 118 c.Assert(err, ErrorMatches, "Unsupported connection URL option: (foo=1|bar=2)") 119 } 120 } 121 122 func (s *S) TestInsertFindOne(c *C) { 123 session, err := mgo.Dial("localhost:40001") 124 c.Assert(err, IsNil) 125 defer session.Close() 126 127 coll := session.DB("mydb").C("mycoll") 128 coll.Insert(M{"a": 1, "b": 2}) 129 130 result := struct{ A, B int }{} 131 132 err = coll.Find(M{"a": 1}).One(&result) 133 c.Assert(err, IsNil) 134 c.Assert(result.A, Equals, 1) 135 c.Assert(result.B, Equals, 2) 136 } 137 138 func (s *S) TestInsertFindOneNil(c *C) { 139 session, err := mgo.Dial("localhost:40002") 140 c.Assert(err, IsNil) 141 defer session.Close() 142 143 coll := session.DB("mydb").C("mycoll") 144 err = coll.Find(nil).One(nil) 145 c.Assert(err, ErrorMatches, "unauthorized.*|not authorized.*") 146 } 147 148 func (s *S) TestInsertFindOneMap(c *C) { 149 session, err := mgo.Dial("localhost:40001") 150 c.Assert(err, IsNil) 151 defer session.Close() 152 153 coll := session.DB("mydb").C("mycoll") 154 coll.Insert(M{"a": 1, "b": 2}) 155 result := make(M) 156 err = coll.Find(M{"a": 1}).One(result) 157 c.Assert(err, IsNil) 158 c.Assert(result["a"], Equals, 1) 159 c.Assert(result["b"], Equals, 2) 160 } 161 162 func (s *S) TestInsertFindAll(c *C) { 163 session, err := mgo.Dial("localhost:40001") 164 c.Assert(err, IsNil) 165 defer session.Close() 166 167 coll := session.DB("mydb").C("mycoll") 168 coll.Insert(M{"a": 1, "b": 2}) 169 coll.Insert(M{"a": 3, "b": 4}) 170 171 type R struct{ A, B int } 172 var result []R 173 174 assertResult := func() { 175 c.Assert(len(result), Equals, 2) 176 c.Assert(result[0].A, Equals, 1) 177 c.Assert(result[0].B, Equals, 2) 178 c.Assert(result[1].A, Equals, 3) 179 c.Assert(result[1].B, Equals, 4) 180 } 181 182 // nil slice 183 err = coll.Find(nil).Sort("a").All(&result) 184 c.Assert(err, IsNil) 185 assertResult() 186 187 // Previously allocated slice 188 allocd := make([]R, 5) 189 result = allocd 190 err = coll.Find(nil).Sort("a").All(&result) 191 c.Assert(err, IsNil) 192 assertResult() 193 194 // Ensure result is backed by the originally allocated array 195 c.Assert(&result[0], Equals, &allocd[0]) 196 197 // Non-pointer slice error 198 f := func() { coll.Find(nil).All(result) } 199 c.Assert(f, Panics, "result argument must be a slice address") 200 201 // Non-slice error 202 f = func() { coll.Find(nil).All(new(int)) } 203 c.Assert(f, Panics, "result argument must be a slice address") 204 } 205 206 func (s *S) TestFindRef(c *C) { 207 session, err := mgo.Dial("localhost:40001") 208 c.Assert(err, IsNil) 209 defer session.Close() 210 211 db1 := session.DB("db1") 212 db1col1 := db1.C("col1") 213 214 db2 := session.DB("db2") 215 db2col1 := db2.C("col1") 216 217 db1col1.Insert(M{"_id": 1, "n": 1}) 218 db1col1.Insert(M{"_id": 2, "n": 2}) 219 db2col1.Insert(M{"_id": 2, "n": 3}) 220 221 result := struct{ N int }{} 222 223 ref1 := &mgo.DBRef{Collection: "col1", Id: 1} 224 ref2 := &mgo.DBRef{Collection: "col1", Id: 2, Database: "db2"} 225 226 err = db1.FindRef(ref1).One(&result) 227 c.Assert(err, IsNil) 228 c.Assert(result.N, Equals, 1) 229 230 err = db1.FindRef(ref2).One(&result) 231 c.Assert(err, IsNil) 232 c.Assert(result.N, Equals, 3) 233 234 err = db2.FindRef(ref1).One(&result) 235 c.Assert(err, Equals, mgo.ErrNotFound) 236 237 err = db2.FindRef(ref2).One(&result) 238 c.Assert(err, IsNil) 239 c.Assert(result.N, Equals, 3) 240 241 err = session.FindRef(ref2).One(&result) 242 c.Assert(err, IsNil) 243 c.Assert(result.N, Equals, 3) 244 245 f := func() { session.FindRef(ref1).One(&result) } 246 c.Assert(f, PanicMatches, "Can't resolve database for &mgo.DBRef{Collection:\"col1\", Id:1, Database:\"\"}") 247 } 248 249 func (s *S) TestDatabaseAndCollectionNames(c *C) { 250 session, err := mgo.Dial("localhost:40001") 251 c.Assert(err, IsNil) 252 defer session.Close() 253 254 db1 := session.DB("db1") 255 db1col1 := db1.C("col1") 256 db1col2 := db1.C("col2") 257 258 db2 := session.DB("db2") 259 db2col1 := db2.C("col3") 260 261 db1col1.Insert(M{"_id": 1}) 262 db1col2.Insert(M{"_id": 1}) 263 db2col1.Insert(M{"_id": 1}) 264 265 names, err := session.DatabaseNames() 266 c.Assert(err, IsNil) 267 if !reflect.DeepEqual(names, []string{"db1", "db2"}) { 268 // 2.4+ has "local" as well. 269 c.Assert(names, DeepEquals, []string{"db1", "db2", "local"}) 270 } 271 272 names, err = db1.CollectionNames() 273 c.Assert(err, IsNil) 274 c.Assert(names, DeepEquals, []string{"col1", "col2", "system.indexes"}) 275 276 names, err = db2.CollectionNames() 277 c.Assert(err, IsNil) 278 c.Assert(names, DeepEquals, []string{"col3", "system.indexes"}) 279 } 280 281 func (s *S) TestSelect(c *C) { 282 session, err := mgo.Dial("localhost:40001") 283 c.Assert(err, IsNil) 284 defer session.Close() 285 286 coll := session.DB("mydb").C("mycoll") 287 coll.Insert(M{"a": 1, "b": 2}) 288 289 result := struct{ A, B int }{} 290 291 err = coll.Find(M{"a": 1}).Select(M{"b": 1}).One(&result) 292 c.Assert(err, IsNil) 293 c.Assert(result.A, Equals, 0) 294 c.Assert(result.B, Equals, 2) 295 } 296 297 func (s *S) TestInlineMap(c *C) { 298 session, err := mgo.Dial("localhost:40001") 299 c.Assert(err, IsNil) 300 defer session.Close() 301 302 coll := session.DB("mydb").C("mycoll") 303 304 var v, result1 struct { 305 A int 306 M map[string]int ",inline" 307 } 308 309 v.A = 1 310 v.M = map[string]int{"b": 2} 311 err = coll.Insert(v) 312 c.Assert(err, IsNil) 313 314 noId := M{"_id": 0} 315 316 err = coll.Find(nil).Select(noId).One(&result1) 317 c.Assert(err, IsNil) 318 c.Assert(result1.A, Equals, 1) 319 c.Assert(result1.M, DeepEquals, map[string]int{"b": 2}) 320 321 var result2 M 322 err = coll.Find(nil).Select(noId).One(&result2) 323 c.Assert(err, IsNil) 324 c.Assert(result2, DeepEquals, M{"a": 1, "b": 2}) 325 326 } 327 328 func (s *S) TestUpdate(c *C) { 329 session, err := mgo.Dial("localhost:40001") 330 c.Assert(err, IsNil) 331 defer session.Close() 332 333 coll := session.DB("mydb").C("mycoll") 334 335 ns := []int{40, 41, 42, 43, 44, 45, 46} 336 for _, n := range ns { 337 err := coll.Insert(M{"k": n, "n": n}) 338 c.Assert(err, IsNil) 339 } 340 341 err = coll.Update(M{"k": 42}, M{"$inc": M{"n": 1}}) 342 c.Assert(err, IsNil) 343 344 result := make(M) 345 err = coll.Find(M{"k": 42}).One(result) 346 c.Assert(err, IsNil) 347 c.Assert(result["n"], Equals, 43) 348 349 err = coll.Update(M{"k": 47}, M{"k": 47, "n": 47}) 350 c.Assert(err, Equals, mgo.ErrNotFound) 351 352 err = coll.Find(M{"k": 47}).One(result) 353 c.Assert(err, Equals, mgo.ErrNotFound) 354 } 355 356 func (s *S) TestUpdateId(c *C) { 357 session, err := mgo.Dial("localhost:40001") 358 c.Assert(err, IsNil) 359 defer session.Close() 360 361 coll := session.DB("mydb").C("mycoll") 362 363 ns := []int{40, 41, 42, 43, 44, 45, 46} 364 for _, n := range ns { 365 err := coll.Insert(M{"_id": n, "n": n}) 366 c.Assert(err, IsNil) 367 } 368 369 err = coll.UpdateId(42, M{"$inc": M{"n": 1}}) 370 c.Assert(err, IsNil) 371 372 result := make(M) 373 err = coll.FindId(42).One(result) 374 c.Assert(err, IsNil) 375 c.Assert(result["n"], Equals, 43) 376 377 err = coll.UpdateId(47, M{"k": 47, "n": 47}) 378 c.Assert(err, Equals, mgo.ErrNotFound) 379 380 err = coll.FindId(47).One(result) 381 c.Assert(err, Equals, mgo.ErrNotFound) 382 } 383 384 func (s *S) TestUpdateNil(c *C) { 385 session, err := mgo.Dial("localhost:40001") 386 c.Assert(err, IsNil) 387 defer session.Close() 388 389 coll := session.DB("mydb").C("mycoll") 390 391 err = coll.Insert(M{"k": 42, "n": 42}) 392 c.Assert(err, IsNil) 393 err = coll.Update(nil, M{"$inc": M{"n": 1}}) 394 c.Assert(err, IsNil) 395 396 result := make(M) 397 err = coll.Find(M{"k": 42}).One(result) 398 c.Assert(err, IsNil) 399 c.Assert(result["n"], Equals, 43) 400 401 err = coll.Insert(M{"k": 45, "n": 45}) 402 c.Assert(err, IsNil) 403 _, err = coll.UpdateAll(nil, M{"$inc": M{"n": 1}}) 404 c.Assert(err, IsNil) 405 406 err = coll.Find(M{"k": 42}).One(result) 407 c.Assert(err, IsNil) 408 c.Assert(result["n"], Equals, 44) 409 err = coll.Find(M{"k": 45}).One(result) 410 c.Assert(err, IsNil) 411 c.Assert(result["n"], Equals, 46) 412 413 } 414 415 func (s *S) TestUpsert(c *C) { 416 session, err := mgo.Dial("localhost:40001") 417 c.Assert(err, IsNil) 418 defer session.Close() 419 420 coll := session.DB("mydb").C("mycoll") 421 422 ns := []int{40, 41, 42, 43, 44, 45, 46} 423 for _, n := range ns { 424 err := coll.Insert(M{"k": n, "n": n}) 425 c.Assert(err, IsNil) 426 } 427 428 info, err := coll.Upsert(M{"k": 42}, M{"k": 42, "n": 24}) 429 c.Assert(err, IsNil) 430 c.Assert(info.Updated, Equals, 1) 431 c.Assert(info.UpsertedId, IsNil) 432 433 result := M{} 434 err = coll.Find(M{"k": 42}).One(result) 435 c.Assert(err, IsNil) 436 c.Assert(result["n"], Equals, 24) 437 438 // Insert with internally created id. 439 info, err = coll.Upsert(M{"k": 47}, M{"k": 47, "n": 47}) 440 c.Assert(err, IsNil) 441 c.Assert(info.Updated, Equals, 0) 442 c.Assert(info.UpsertedId, NotNil) 443 444 err = coll.Find(M{"k": 47}).One(result) 445 c.Assert(err, IsNil) 446 c.Assert(result["n"], Equals, 47) 447 448 result = M{} 449 err = coll.Find(M{"_id": info.UpsertedId}).One(result) 450 c.Assert(err, IsNil) 451 c.Assert(result["n"], Equals, 47) 452 453 // Insert with provided id. 454 info, err = coll.Upsert(M{"k": 48}, M{"k": 48, "n": 48, "_id": 48}) 455 c.Assert(err, IsNil) 456 c.Assert(info.Updated, Equals, 0) 457 c.Assert(info.UpsertedId, IsNil) // Unfortunate, but that's what Mongo gives us. 458 459 err = coll.Find(M{"k": 48}).One(result) 460 c.Assert(err, IsNil) 461 c.Assert(result["n"], Equals, 48) 462 } 463 464 func (s *S) TestUpsertId(c *C) { 465 session, err := mgo.Dial("localhost:40001") 466 c.Assert(err, IsNil) 467 defer session.Close() 468 469 coll := session.DB("mydb").C("mycoll") 470 471 ns := []int{40, 41, 42, 43, 44, 45, 46} 472 for _, n := range ns { 473 err := coll.Insert(M{"_id": n, "n": n}) 474 c.Assert(err, IsNil) 475 } 476 477 info, err := coll.UpsertId(42, M{"n": 24}) 478 c.Assert(err, IsNil) 479 c.Assert(info.Updated, Equals, 1) 480 c.Assert(info.UpsertedId, IsNil) 481 482 result := M{} 483 err = coll.FindId(42).One(result) 484 c.Assert(err, IsNil) 485 c.Assert(result["n"], Equals, 24) 486 487 info, err = coll.UpsertId(47, M{"_id": 47, "n": 47}) 488 c.Assert(err, IsNil) 489 c.Assert(info.Updated, Equals, 0) 490 c.Assert(info.UpsertedId, IsNil) 491 492 err = coll.FindId(47).One(result) 493 c.Assert(err, IsNil) 494 c.Assert(result["n"], Equals, 47) 495 } 496 497 func (s *S) TestUpdateAll(c *C) { 498 session, err := mgo.Dial("localhost:40001") 499 c.Assert(err, IsNil) 500 defer session.Close() 501 502 coll := session.DB("mydb").C("mycoll") 503 504 ns := []int{40, 41, 42, 43, 44, 45, 46} 505 for _, n := range ns { 506 err := coll.Insert(M{"k": n, "n": n}) 507 c.Assert(err, IsNil) 508 } 509 510 info, err := coll.UpdateAll(M{"k": M{"$gt": 42}}, M{"$inc": M{"n": 1}}) 511 c.Assert(err, IsNil) 512 c.Assert(info.Updated, Equals, 4) 513 514 result := make(M) 515 err = coll.Find(M{"k": 42}).One(result) 516 c.Assert(err, IsNil) 517 c.Assert(result["n"], Equals, 42) 518 519 err = coll.Find(M{"k": 43}).One(result) 520 c.Assert(err, IsNil) 521 c.Assert(result["n"], Equals, 44) 522 523 err = coll.Find(M{"k": 44}).One(result) 524 c.Assert(err, IsNil) 525 c.Assert(result["n"], Equals, 45) 526 527 info, err = coll.UpdateAll(M{"k": 47}, M{"k": 47, "n": 47}) 528 c.Assert(err, Equals, nil) 529 c.Assert(info.Updated, Equals, 0) 530 } 531 532 func (s *S) TestRemove(c *C) { 533 session, err := mgo.Dial("localhost:40001") 534 c.Assert(err, IsNil) 535 defer session.Close() 536 537 coll := session.DB("mydb").C("mycoll") 538 539 ns := []int{40, 41, 42, 43, 44, 45, 46} 540 for _, n := range ns { 541 err := coll.Insert(M{"n": n}) 542 c.Assert(err, IsNil) 543 } 544 545 err = coll.Remove(M{"n": M{"$gt": 42}}) 546 c.Assert(err, IsNil) 547 548 result := &struct{ N int }{} 549 err = coll.Find(M{"n": 42}).One(result) 550 c.Assert(err, IsNil) 551 c.Assert(result.N, Equals, 42) 552 553 err = coll.Find(M{"n": 43}).One(result) 554 c.Assert(err, Equals, mgo.ErrNotFound) 555 556 err = coll.Find(M{"n": 44}).One(result) 557 c.Assert(err, IsNil) 558 c.Assert(result.N, Equals, 44) 559 } 560 561 func (s *S) TestRemoveId(c *C) { 562 session, err := mgo.Dial("localhost:40001") 563 c.Assert(err, IsNil) 564 defer session.Close() 565 566 coll := session.DB("mydb").C("mycoll") 567 568 err = coll.Insert(M{"_id": 40}, M{"_id": 41}, M{"_id": 42}) 569 c.Assert(err, IsNil) 570 571 err = coll.RemoveId(41) 572 c.Assert(err, IsNil) 573 574 c.Assert(coll.FindId(40).One(nil), IsNil) 575 c.Assert(coll.FindId(41).One(nil), Equals, mgo.ErrNotFound) 576 c.Assert(coll.FindId(42).One(nil), IsNil) 577 } 578 579 func (s *S) TestRemoveAll(c *C) { 580 session, err := mgo.Dial("localhost:40001") 581 c.Assert(err, IsNil) 582 defer session.Close() 583 584 coll := session.DB("mydb").C("mycoll") 585 586 ns := []int{40, 41, 42, 43, 44, 45, 46} 587 for _, n := range ns { 588 err := coll.Insert(M{"n": n}) 589 c.Assert(err, IsNil) 590 } 591 592 info, err := coll.RemoveAll(M{"n": M{"$gt": 42}}) 593 c.Assert(err, IsNil) 594 c.Assert(info.Updated, Equals, 0) 595 c.Assert(info.Removed, Equals, 4) 596 c.Assert(info.UpsertedId, IsNil) 597 598 result := &struct{ N int }{} 599 err = coll.Find(M{"n": 42}).One(result) 600 c.Assert(err, IsNil) 601 c.Assert(result.N, Equals, 42) 602 603 err = coll.Find(M{"n": 43}).One(result) 604 c.Assert(err, Equals, mgo.ErrNotFound) 605 606 err = coll.Find(M{"n": 44}).One(result) 607 c.Assert(err, Equals, mgo.ErrNotFound) 608 } 609 610 func (s *S) TestDropDatabase(c *C) { 611 session, err := mgo.Dial("localhost:40001") 612 c.Assert(err, IsNil) 613 defer session.Close() 614 615 db1 := session.DB("db1") 616 db1.C("col").Insert(M{"_id": 1}) 617 618 db2 := session.DB("db2") 619 db2.C("col").Insert(M{"_id": 1}) 620 621 err = db1.DropDatabase() 622 c.Assert(err, IsNil) 623 624 names, err := session.DatabaseNames() 625 c.Assert(err, IsNil) 626 if !reflect.DeepEqual(names, []string{"db2"}) { 627 // 2.4+ has "local" as well. 628 c.Assert(names, DeepEquals, []string{"db2", "local"}) 629 } 630 631 err = db2.DropDatabase() 632 c.Assert(err, IsNil) 633 634 names, err = session.DatabaseNames() 635 c.Assert(err, IsNil) 636 if !reflect.DeepEqual(names, []string(nil)) { 637 // 2.4+ has "local" as well. 638 c.Assert(names, DeepEquals, []string{"local"}) 639 } 640 } 641 642 func (s *S) TestDropCollection(c *C) { 643 session, err := mgo.Dial("localhost:40001") 644 c.Assert(err, IsNil) 645 defer session.Close() 646 647 db := session.DB("db1") 648 db.C("col1").Insert(M{"_id": 1}) 649 db.C("col2").Insert(M{"_id": 1}) 650 651 err = db.C("col1").DropCollection() 652 c.Assert(err, IsNil) 653 654 names, err := db.CollectionNames() 655 c.Assert(err, IsNil) 656 c.Assert(names, DeepEquals, []string{"col2", "system.indexes"}) 657 658 err = db.C("col2").DropCollection() 659 c.Assert(err, IsNil) 660 661 names, err = db.CollectionNames() 662 c.Assert(err, IsNil) 663 c.Assert(names, DeepEquals, []string{"system.indexes"}) 664 } 665 666 func (s *S) TestCreateCollectionCapped(c *C) { 667 session, err := mgo.Dial("localhost:40001") 668 c.Assert(err, IsNil) 669 defer session.Close() 670 671 coll := session.DB("mydb").C("mycoll") 672 673 info := &mgo.CollectionInfo{ 674 Capped: true, 675 MaxBytes: 1024, 676 MaxDocs: 3, 677 } 678 err = coll.Create(info) 679 c.Assert(err, IsNil) 680 681 ns := []int{1, 2, 3, 4, 5} 682 for _, n := range ns { 683 err := coll.Insert(M{"n": n}) 684 c.Assert(err, IsNil) 685 } 686 687 n, err := coll.Find(nil).Count() 688 c.Assert(err, IsNil) 689 c.Assert(n, Equals, 3) 690 } 691 692 func (s *S) TestCreateCollectionNoIndex(c *C) { 693 session, err := mgo.Dial("localhost:40001") 694 c.Assert(err, IsNil) 695 defer session.Close() 696 697 coll := session.DB("mydb").C("mycoll") 698 699 info := &mgo.CollectionInfo{ 700 DisableIdIndex: true, 701 } 702 err = coll.Create(info) 703 c.Assert(err, IsNil) 704 705 err = coll.Insert(M{"n": 1}) 706 c.Assert(err, IsNil) 707 708 indexes, err := coll.Indexes() 709 c.Assert(indexes, HasLen, 0) 710 } 711 712 func (s *S) TestCreateCollectionForceIndex(c *C) { 713 session, err := mgo.Dial("localhost:40001") 714 c.Assert(err, IsNil) 715 defer session.Close() 716 717 coll := session.DB("mydb").C("mycoll") 718 719 info := &mgo.CollectionInfo{ 720 ForceIdIndex: true, 721 Capped: true, 722 MaxBytes: 1024, 723 } 724 err = coll.Create(info) 725 c.Assert(err, IsNil) 726 727 err = coll.Insert(M{"n": 1}) 728 c.Assert(err, IsNil) 729 730 indexes, err := coll.Indexes() 731 c.Assert(indexes, HasLen, 1) 732 } 733 734 func (s *S) TestIsDupValues(c *C) { 735 c.Assert(mgo.IsDup(nil), Equals, false) 736 c.Assert(mgo.IsDup(&mgo.LastError{Code: 1}), Equals, false) 737 c.Assert(mgo.IsDup(&mgo.QueryError{Code: 1}), Equals, false) 738 c.Assert(mgo.IsDup(&mgo.LastError{Code: 11000}), Equals, true) 739 c.Assert(mgo.IsDup(&mgo.QueryError{Code: 11000}), Equals, true) 740 c.Assert(mgo.IsDup(&mgo.LastError{Code: 11001}), Equals, true) 741 c.Assert(mgo.IsDup(&mgo.QueryError{Code: 11001}), Equals, true) 742 c.Assert(mgo.IsDup(&mgo.LastError{Code: 12582}), Equals, true) 743 c.Assert(mgo.IsDup(&mgo.QueryError{Code: 12582}), Equals, true) 744 } 745 746 func (s *S) TestIsDupPrimary(c *C) { 747 session, err := mgo.Dial("localhost:40001") 748 c.Assert(err, IsNil) 749 defer session.Close() 750 751 coll := session.DB("mydb").C("mycoll") 752 753 err = coll.Insert(M{"_id": 1}) 754 c.Assert(err, IsNil) 755 err = coll.Insert(M{"_id": 1}) 756 c.Assert(err, ErrorMatches, ".*duplicate key error.*") 757 c.Assert(mgo.IsDup(err), Equals, true) 758 } 759 760 func (s *S) TestIsDupUnique(c *C) { 761 session, err := mgo.Dial("localhost:40001") 762 c.Assert(err, IsNil) 763 defer session.Close() 764 765 index := mgo.Index{ 766 Key: []string{"a", "b"}, 767 Unique: true, 768 } 769 770 coll := session.DB("mydb").C("mycoll") 771 772 err = coll.EnsureIndex(index) 773 c.Assert(err, IsNil) 774 775 err = coll.Insert(M{"a": 1, "b": 1}) 776 c.Assert(err, IsNil) 777 err = coll.Insert(M{"a": 1, "b": 1}) 778 c.Assert(err, ErrorMatches, ".*duplicate key error.*") 779 c.Assert(mgo.IsDup(err), Equals, true) 780 } 781 782 func (s *S) TestIsDupCapped(c *C) { 783 session, err := mgo.Dial("localhost:40001") 784 c.Assert(err, IsNil) 785 defer session.Close() 786 787 coll := session.DB("mydb").C("mycoll") 788 789 info := &mgo.CollectionInfo{ 790 ForceIdIndex: true, 791 Capped: true, 792 MaxBytes: 1024, 793 } 794 err = coll.Create(info) 795 c.Assert(err, IsNil) 796 797 err = coll.Insert(M{"_id": 1}) 798 c.Assert(err, IsNil) 799 err = coll.Insert(M{"_id": 1}) 800 // Quite unfortunate that the error is different for capped collections. 801 c.Assert(err, ErrorMatches, "duplicate key.*capped collection") 802 // The issue is reduced by using IsDup. 803 c.Assert(mgo.IsDup(err), Equals, true) 804 } 805 806 func (s *S) TestIsDupFindAndModify(c *C) { 807 session, err := mgo.Dial("localhost:40001") 808 c.Assert(err, IsNil) 809 defer session.Close() 810 811 coll := session.DB("mydb").C("mycoll") 812 813 err = coll.EnsureIndex(mgo.Index{Key: []string{"n"}, Unique: true}) 814 c.Assert(err, IsNil) 815 816 err = coll.Insert(M{"n": 1}) 817 c.Assert(err, IsNil) 818 err = coll.Insert(M{"n": 2}) 819 c.Assert(err, IsNil) 820 _, err = coll.Find(M{"n": 1}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, bson.M{}) 821 c.Assert(err, ErrorMatches, ".*duplicate key error.*") 822 c.Assert(mgo.IsDup(err), Equals, true) 823 } 824 825 func (s *S) TestFindAndModify(c *C) { 826 session, err := mgo.Dial("localhost:40011") 827 c.Assert(err, IsNil) 828 defer session.Close() 829 830 coll := session.DB("mydb").C("mycoll") 831 832 err = coll.Insert(M{"n": 42}) 833 834 session.SetMode(mgo.Monotonic, true) 835 836 result := M{} 837 info, err := coll.Find(M{"n": 42}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, result) 838 c.Assert(err, IsNil) 839 c.Assert(result["n"], Equals, 42) 840 c.Assert(info.Updated, Equals, 1) 841 c.Assert(info.Removed, Equals, 0) 842 c.Assert(info.UpsertedId, IsNil) 843 844 result = M{} 845 info, err = coll.Find(M{"n": 43}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}, ReturnNew: true}, result) 846 c.Assert(err, IsNil) 847 c.Assert(result["n"], Equals, 44) 848 c.Assert(info.Updated, Equals, 1) 849 c.Assert(info.Removed, Equals, 0) 850 c.Assert(info.UpsertedId, IsNil) 851 852 result = M{} 853 info, err = coll.Find(M{"n": 50}).Apply(mgo.Change{Upsert: true, Update: M{"n": 51, "o": 52}}, result) 854 c.Assert(err, IsNil) 855 c.Assert(result["n"], IsNil) 856 c.Assert(info.Updated, Equals, 0) 857 c.Assert(info.Removed, Equals, 0) 858 c.Assert(info.UpsertedId, NotNil) 859 860 result = M{} 861 info, err = coll.Find(nil).Sort("-n").Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}, ReturnNew: true}, result) 862 c.Assert(err, IsNil) 863 c.Assert(result["n"], Equals, 52) 864 c.Assert(info.Updated, Equals, 1) 865 c.Assert(info.Removed, Equals, 0) 866 c.Assert(info.UpsertedId, IsNil) 867 868 result = M{} 869 info, err = coll.Find(M{"n": 52}).Select(M{"o": 1}).Apply(mgo.Change{Remove: true}, result) 870 c.Assert(err, IsNil) 871 c.Assert(result["n"], IsNil) 872 c.Assert(result["o"], Equals, 52) 873 c.Assert(info.Updated, Equals, 0) 874 c.Assert(info.Removed, Equals, 1) 875 c.Assert(info.UpsertedId, IsNil) 876 877 result = M{} 878 info, err = coll.Find(M{"n": 60}).Apply(mgo.Change{Remove: true}, result) 879 c.Assert(err, Equals, mgo.ErrNotFound) 880 c.Assert(len(result), Equals, 0) 881 c.Assert(info, IsNil) 882 } 883 884 func (s *S) TestFindAndModifyBug997828(c *C) { 885 session, err := mgo.Dial("localhost:40001") 886 c.Assert(err, IsNil) 887 defer session.Close() 888 889 coll := session.DB("mydb").C("mycoll") 890 891 err = coll.Insert(M{"n": "not-a-number"}) 892 893 result := make(M) 894 _, err = coll.Find(M{"n": "not-a-number"}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, result) 895 c.Assert(err, ErrorMatches, `(exception: )?Cannot apply \$inc modifier to non-number`) 896 if s.versionAtLeast(2, 1) { 897 qerr, _ := err.(*mgo.QueryError) 898 c.Assert(qerr, NotNil, Commentf("err: %#v", err)) 899 c.Assert(qerr.Code, Equals, 10140) 900 } else { 901 lerr, _ := err.(*mgo.LastError) 902 c.Assert(lerr, NotNil, Commentf("err: %#v", err)) 903 c.Assert(lerr.Code, Equals, 10140) 904 } 905 } 906 907 func (s *S) TestCountCollection(c *C) { 908 session, err := mgo.Dial("localhost:40001") 909 c.Assert(err, IsNil) 910 defer session.Close() 911 912 coll := session.DB("mydb").C("mycoll") 913 914 ns := []int{40, 41, 42} 915 for _, n := range ns { 916 err := coll.Insert(M{"n": n}) 917 c.Assert(err, IsNil) 918 } 919 920 n, err := coll.Count() 921 c.Assert(err, IsNil) 922 c.Assert(n, Equals, 3) 923 } 924 925 func (s *S) TestCountQuery(c *C) { 926 session, err := mgo.Dial("localhost:40001") 927 c.Assert(err, IsNil) 928 defer session.Close() 929 930 coll := session.DB("mydb").C("mycoll") 931 932 ns := []int{40, 41, 42} 933 for _, n := range ns { 934 err := coll.Insert(M{"n": n}) 935 c.Assert(err, IsNil) 936 } 937 938 n, err := coll.Find(M{"n": M{"$gt": 40}}).Count() 939 c.Assert(err, IsNil) 940 c.Assert(n, Equals, 2) 941 } 942 943 func (s *S) TestCountQuerySorted(c *C) { 944 session, err := mgo.Dial("localhost:40001") 945 c.Assert(err, IsNil) 946 defer session.Close() 947 948 coll := session.DB("mydb").C("mycoll") 949 950 ns := []int{40, 41, 42} 951 for _, n := range ns { 952 err := coll.Insert(M{"n": n}) 953 c.Assert(err, IsNil) 954 } 955 956 n, err := coll.Find(M{"n": M{"$gt": 40}}).Sort("n").Count() 957 c.Assert(err, IsNil) 958 c.Assert(n, Equals, 2) 959 } 960 961 func (s *S) TestCountSkipLimit(c *C) { 962 session, err := mgo.Dial("localhost:40001") 963 c.Assert(err, IsNil) 964 defer session.Close() 965 966 coll := session.DB("mydb").C("mycoll") 967 968 ns := []int{40, 41, 42, 43, 44} 969 for _, n := range ns { 970 err := coll.Insert(M{"n": n}) 971 c.Assert(err, IsNil) 972 } 973 974 n, err := coll.Find(nil).Skip(1).Limit(3).Count() 975 c.Assert(err, IsNil) 976 c.Assert(n, Equals, 3) 977 978 n, err = coll.Find(nil).Skip(1).Limit(5).Count() 979 c.Assert(err, IsNil) 980 c.Assert(n, Equals, 4) 981 } 982 983 func (s *S) TestQueryExplain(c *C) { 984 session, err := mgo.Dial("localhost:40001") 985 c.Assert(err, IsNil) 986 defer session.Close() 987 988 coll := session.DB("mydb").C("mycoll") 989 990 ns := []int{40, 41, 42} 991 for _, n := range ns { 992 err := coll.Insert(M{"n": n}) 993 c.Assert(err, IsNil) 994 } 995 996 m := M{} 997 query := coll.Find(nil).Limit(2) 998 err = query.Explain(m) 999 c.Assert(err, IsNil) 1000 c.Assert(m["cursor"], Equals, "BasicCursor") 1001 c.Assert(m["nscanned"], Equals, 2) 1002 c.Assert(m["n"], Equals, 2) 1003 1004 n := 0 1005 var result M 1006 iter := query.Iter() 1007 for iter.Next(&result) { 1008 n++ 1009 } 1010 c.Assert(iter.Close(), IsNil) 1011 c.Assert(n, Equals, 2) 1012 } 1013 1014 func (s *S) TestQueryHint(c *C) { 1015 session, err := mgo.Dial("localhost:40001") 1016 c.Assert(err, IsNil) 1017 defer session.Close() 1018 1019 coll := session.DB("mydb").C("mycoll") 1020 coll.EnsureIndexKey("a") 1021 1022 m := M{} 1023 err = coll.Find(nil).Hint("a").Explain(m) 1024 c.Assert(err, IsNil) 1025 c.Assert(m["indexBounds"], NotNil) 1026 c.Assert(m["indexBounds"].(M)["a"], NotNil) 1027 } 1028 1029 func (s *S) TestFindOneNotFound(c *C) { 1030 session, err := mgo.Dial("localhost:40001") 1031 c.Assert(err, IsNil) 1032 defer session.Close() 1033 1034 coll := session.DB("mydb").C("mycoll") 1035 1036 result := struct{ A, B int }{} 1037 err = coll.Find(M{"a": 1}).One(&result) 1038 c.Assert(err, Equals, mgo.ErrNotFound) 1039 c.Assert(err, ErrorMatches, "not found") 1040 c.Assert(err == mgo.ErrNotFound, Equals, true) 1041 } 1042 1043 func (s *S) TestFindNil(c *C) { 1044 session, err := mgo.Dial("localhost:40001") 1045 c.Assert(err, IsNil) 1046 defer session.Close() 1047 1048 coll := session.DB("mydb").C("mycoll") 1049 err = coll.Insert(M{"n": 1}) 1050 c.Assert(err, IsNil) 1051 1052 result := struct{ N int }{} 1053 1054 err = coll.Find(nil).One(&result) 1055 c.Assert(err, IsNil) 1056 c.Assert(result.N, Equals, 1) 1057 } 1058 1059 func (s *S) TestFindId(c *C) { 1060 session, err := mgo.Dial("localhost:40001") 1061 c.Assert(err, IsNil) 1062 defer session.Close() 1063 1064 coll := session.DB("mydb").C("mycoll") 1065 err = coll.Insert(M{"_id": 41, "n": 41}) 1066 c.Assert(err, IsNil) 1067 err = coll.Insert(M{"_id": 42, "n": 42}) 1068 c.Assert(err, IsNil) 1069 1070 result := struct{ N int }{} 1071 1072 err = coll.FindId(42).One(&result) 1073 c.Assert(err, IsNil) 1074 c.Assert(result.N, Equals, 42) 1075 } 1076 1077 func (s *S) TestFindIterAll(c *C) { 1078 session, err := mgo.Dial("localhost:40001") 1079 c.Assert(err, IsNil) 1080 defer session.Close() 1081 1082 coll := session.DB("mydb").C("mycoll") 1083 1084 ns := []int{40, 41, 42, 43, 44, 45, 46} 1085 for _, n := range ns { 1086 coll.Insert(M{"n": n}) 1087 } 1088 1089 session.Refresh() // Release socket. 1090 1091 mgo.ResetStats() 1092 1093 iter := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2).Iter() 1094 result := struct{ N int }{} 1095 for i := 2; i < 7; i++ { 1096 ok := iter.Next(&result) 1097 c.Assert(ok, Equals, true) 1098 c.Assert(result.N, Equals, ns[i]) 1099 if i == 1 { 1100 stats := mgo.GetStats() 1101 c.Assert(stats.ReceivedDocs, Equals, 2) 1102 } 1103 } 1104 1105 ok := iter.Next(&result) 1106 c.Assert(ok, Equals, false) 1107 c.Assert(iter.Close(), IsNil) 1108 1109 session.Refresh() // Release socket. 1110 1111 stats := mgo.GetStats() 1112 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 2*GET_MORE_OP 1113 c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs. 1114 c.Assert(stats.ReceivedDocs, Equals, 5) 1115 c.Assert(stats.SocketsInUse, Equals, 0) 1116 } 1117 1118 func (s *S) TestFindIterTwiceWithSameQuery(c *C) { 1119 session, err := mgo.Dial("localhost:40001") 1120 c.Assert(err, IsNil) 1121 defer session.Close() 1122 1123 coll := session.DB("mydb").C("mycoll") 1124 1125 for i := 40; i != 47; i++ { 1126 coll.Insert(M{"n": i}) 1127 } 1128 1129 query := coll.Find(M{}).Sort("n") 1130 1131 result1 := query.Skip(1).Iter() 1132 result2 := query.Skip(2).Iter() 1133 1134 result := struct{ N int }{} 1135 ok := result2.Next(&result) 1136 c.Assert(ok, Equals, true) 1137 c.Assert(result.N, Equals, 42) 1138 ok = result1.Next(&result) 1139 c.Assert(ok, Equals, true) 1140 c.Assert(result.N, Equals, 41) 1141 } 1142 1143 func (s *S) TestFindIterWithoutResults(c *C) { 1144 session, err := mgo.Dial("localhost:40001") 1145 c.Assert(err, IsNil) 1146 defer session.Close() 1147 1148 coll := session.DB("mydb").C("mycoll") 1149 coll.Insert(M{"n": 42}) 1150 1151 iter := coll.Find(M{"n": 0}).Iter() 1152 1153 result := struct{ N int }{} 1154 ok := iter.Next(&result) 1155 c.Assert(ok, Equals, false) 1156 c.Assert(iter.Close(), IsNil) 1157 c.Assert(result.N, Equals, 0) 1158 } 1159 1160 func (s *S) TestFindIterLimit(c *C) { 1161 session, err := mgo.Dial("localhost:40001") 1162 c.Assert(err, IsNil) 1163 defer session.Close() 1164 1165 coll := session.DB("mydb").C("mycoll") 1166 1167 ns := []int{40, 41, 42, 43, 44, 45, 46} 1168 for _, n := range ns { 1169 coll.Insert(M{"n": n}) 1170 } 1171 1172 session.Refresh() // Release socket. 1173 1174 mgo.ResetStats() 1175 1176 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Limit(3) 1177 iter := query.Iter() 1178 1179 result := struct{ N int }{} 1180 for i := 2; i < 5; i++ { 1181 ok := iter.Next(&result) 1182 c.Assert(ok, Equals, true) 1183 c.Assert(result.N, Equals, ns[i]) 1184 } 1185 1186 ok := iter.Next(&result) 1187 c.Assert(ok, Equals, false) 1188 c.Assert(iter.Close(), IsNil) 1189 1190 session.Refresh() // Release socket. 1191 1192 stats := mgo.GetStats() 1193 c.Assert(stats.SentOps, Equals, 2) // 1*QUERY_OP + 1*KILL_CURSORS_OP 1194 c.Assert(stats.ReceivedOps, Equals, 1) // and its REPLY_OP 1195 c.Assert(stats.ReceivedDocs, Equals, 3) 1196 c.Assert(stats.SocketsInUse, Equals, 0) 1197 } 1198 1199 func (s *S) TestTooManyItemsLimitBug(c *C) { 1200 session, err := mgo.Dial("localhost:40001") 1201 c.Assert(err, IsNil) 1202 defer session.Close() 1203 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU())) 1204 1205 mgo.SetDebug(false) 1206 coll := session.DB("mydb").C("mycoll") 1207 words := strings.Split("foo bar baz", " ") 1208 for i := 0; i < 5; i++ { 1209 words = append(words, words...) 1210 } 1211 doc := bson.D{{"words", words}} 1212 inserts := 10000 1213 limit := 5000 1214 iters := 0 1215 c.Assert(inserts > limit, Equals, true) 1216 for i := 0; i < inserts; i++ { 1217 err := coll.Insert(&doc) 1218 c.Assert(err, IsNil) 1219 } 1220 iter := coll.Find(nil).Limit(limit).Iter() 1221 for iter.Next(&doc) { 1222 if iters%100 == 0 { 1223 c.Logf("Seen %d docments", iters) 1224 } 1225 iters++ 1226 } 1227 c.Assert(iter.Close(), IsNil) 1228 c.Assert(iters, Equals, limit) 1229 } 1230 1231 func serverCursorsOpen(session *mgo.Session) int { 1232 var result struct { 1233 Cursors struct { 1234 TotalOpen int `bson:"totalOpen"` 1235 TimedOut int `bson:"timedOut"` 1236 } 1237 } 1238 err := session.Run("serverStatus", &result) 1239 if err != nil { 1240 panic(err) 1241 } 1242 return result.Cursors.TotalOpen 1243 } 1244 1245 func (s *S) TestFindIterLimitWithMore(c *C) { 1246 session, err := mgo.Dial("localhost:40001") 1247 c.Assert(err, IsNil) 1248 defer session.Close() 1249 1250 coll := session.DB("mydb").C("mycoll") 1251 1252 // Insane amounts of logging otherwise due to the 1253 // amount of data being shuffled. 1254 mgo.SetDebug(false) 1255 defer mgo.SetDebug(true) 1256 1257 // Should amount to more than 4MB bson payload, 1258 // the default limit per result chunk. 1259 const total = 4096 1260 var d struct{ A [1024]byte } 1261 docs := make([]interface{}, total) 1262 for i := 0; i < total; i++ { 1263 docs[i] = &d 1264 } 1265 err = coll.Insert(docs...) 1266 c.Assert(err, IsNil) 1267 1268 n, err := coll.Count() 1269 c.Assert(err, IsNil) 1270 c.Assert(n, Equals, total) 1271 1272 // First, try restricting to a single chunk with a negative limit. 1273 nresults := 0 1274 iter := coll.Find(nil).Limit(-total).Iter() 1275 var discard struct{} 1276 for iter.Next(&discard) { 1277 nresults++ 1278 } 1279 if nresults < total/2 || nresults >= total { 1280 c.Fatalf("Bad result size with negative limit: %d", nresults) 1281 } 1282 1283 cursorsOpen := serverCursorsOpen(session) 1284 1285 // Try again, with a positive limit. Should reach the end now, 1286 // using multiple chunks. 1287 nresults = 0 1288 iter = coll.Find(nil).Limit(total).Iter() 1289 for iter.Next(&discard) { 1290 nresults++ 1291 } 1292 c.Assert(nresults, Equals, total) 1293 1294 // Ensure the cursor used is properly killed. 1295 c.Assert(serverCursorsOpen(session), Equals, cursorsOpen) 1296 1297 // Edge case, -MinInt == -MinInt. 1298 nresults = 0 1299 iter = coll.Find(nil).Limit(math.MinInt32).Iter() 1300 for iter.Next(&discard) { 1301 nresults++ 1302 } 1303 if nresults < total/2 || nresults >= total { 1304 c.Fatalf("Bad result size with MinInt32 limit: %d", nresults) 1305 } 1306 } 1307 1308 func (s *S) TestFindIterLimitWithBatch(c *C) { 1309 session, err := mgo.Dial("localhost:40001") 1310 c.Assert(err, IsNil) 1311 defer session.Close() 1312 1313 coll := session.DB("mydb").C("mycoll") 1314 1315 ns := []int{40, 41, 42, 43, 44, 45, 46} 1316 for _, n := range ns { 1317 coll.Insert(M{"n": n}) 1318 } 1319 1320 // Ping the database to ensure the nonce has been received already. 1321 c.Assert(session.Ping(), IsNil) 1322 1323 session.Refresh() // Release socket. 1324 1325 mgo.ResetStats() 1326 1327 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Limit(3).Batch(2) 1328 iter := query.Iter() 1329 result := struct{ N int }{} 1330 for i := 2; i < 5; i++ { 1331 ok := iter.Next(&result) 1332 c.Assert(ok, Equals, true) 1333 c.Assert(result.N, Equals, ns[i]) 1334 if i == 3 { 1335 stats := mgo.GetStats() 1336 c.Assert(stats.ReceivedDocs, Equals, 2) 1337 } 1338 } 1339 1340 ok := iter.Next(&result) 1341 c.Assert(ok, Equals, false) 1342 c.Assert(iter.Close(), IsNil) 1343 1344 session.Refresh() // Release socket. 1345 1346 stats := mgo.GetStats() 1347 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 1*GET_MORE_OP + 1*KILL_CURSORS_OP 1348 c.Assert(stats.ReceivedOps, Equals, 2) // and its REPLY_OPs 1349 c.Assert(stats.ReceivedDocs, Equals, 3) 1350 c.Assert(stats.SocketsInUse, Equals, 0) 1351 } 1352 1353 func (s *S) TestFindIterSortWithBatch(c *C) { 1354 session, err := mgo.Dial("localhost:40001") 1355 c.Assert(err, IsNil) 1356 defer session.Close() 1357 1358 coll := session.DB("mydb").C("mycoll") 1359 1360 ns := []int{40, 41, 42, 43, 44, 45, 46} 1361 for _, n := range ns { 1362 coll.Insert(M{"n": n}) 1363 } 1364 1365 // Without this, the logic above breaks because Mongo refuses to 1366 // return a cursor with an in-memory sort. 1367 coll.EnsureIndexKey("n") 1368 1369 // Ping the database to ensure the nonce has been received already. 1370 c.Assert(session.Ping(), IsNil) 1371 1372 session.Refresh() // Release socket. 1373 1374 mgo.ResetStats() 1375 1376 query := coll.Find(M{"n": M{"$lte": 44}}).Sort("-n").Batch(2) 1377 iter := query.Iter() 1378 ns = []int{46, 45, 44, 43, 42, 41, 40} 1379 result := struct{ N int }{} 1380 for i := 2; i < len(ns); i++ { 1381 c.Logf("i=%d", i) 1382 ok := iter.Next(&result) 1383 c.Assert(ok, Equals, true) 1384 c.Assert(result.N, Equals, ns[i]) 1385 if i == 3 { 1386 stats := mgo.GetStats() 1387 c.Assert(stats.ReceivedDocs, Equals, 2) 1388 } 1389 } 1390 1391 ok := iter.Next(&result) 1392 c.Assert(ok, Equals, false) 1393 c.Assert(iter.Close(), IsNil) 1394 1395 session.Refresh() // Release socket. 1396 1397 stats := mgo.GetStats() 1398 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 2*GET_MORE_OP 1399 c.Assert(stats.ReceivedOps, Equals, 3) // and its REPLY_OPs 1400 c.Assert(stats.ReceivedDocs, Equals, 5) 1401 c.Assert(stats.SocketsInUse, Equals, 0) 1402 } 1403 1404 // Test tailable cursors in a situation where Next has to sleep to 1405 // respect the timeout requested on Tail. 1406 func (s *S) TestFindTailTimeoutWithSleep(c *C) { 1407 if *fast { 1408 c.Skip("-fast") 1409 } 1410 1411 session, err := mgo.Dial("localhost:40001") 1412 c.Assert(err, IsNil) 1413 defer session.Close() 1414 1415 cresult := struct{ ErrMsg string }{} 1416 1417 db := session.DB("mydb") 1418 err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult) 1419 c.Assert(err, IsNil) 1420 c.Assert(cresult.ErrMsg, Equals, "") 1421 coll := db.C("mycoll") 1422 1423 ns := []int{40, 41, 42, 43, 44, 45, 46} 1424 for _, n := range ns { 1425 coll.Insert(M{"n": n}) 1426 } 1427 1428 session.Refresh() // Release socket. 1429 1430 mgo.ResetStats() 1431 1432 timeout := 3 * time.Second 1433 1434 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2) 1435 iter := query.Tail(timeout) 1436 1437 n := len(ns) 1438 result := struct{ N int }{} 1439 for i := 2; i != n; i++ { 1440 ok := iter.Next(&result) 1441 c.Assert(ok, Equals, true) 1442 c.Assert(iter.Err(), IsNil) 1443 c.Assert(iter.Timeout(), Equals, false) 1444 c.Assert(result.N, Equals, ns[i]) 1445 if i == 3 { // The batch boundary. 1446 stats := mgo.GetStats() 1447 c.Assert(stats.ReceivedDocs, Equals, 2) 1448 } 1449 } 1450 1451 mgo.ResetStats() 1452 1453 // The following call to Next will block. 1454 go func() { 1455 // The internal AwaitData timing of MongoDB is around 2 seconds, 1456 // so this should force mgo to sleep at least once by itself to 1457 // respect the requested timeout. 1458 time.Sleep(timeout + 5e8*time.Nanosecond) 1459 session := session.New() 1460 defer session.Close() 1461 coll := session.DB("mydb").C("mycoll") 1462 coll.Insert(M{"n": 47}) 1463 }() 1464 1465 c.Log("Will wait for Next with N=47...") 1466 ok := iter.Next(&result) 1467 c.Assert(ok, Equals, true) 1468 c.Assert(iter.Err(), IsNil) 1469 c.Assert(iter.Timeout(), Equals, false) 1470 c.Assert(result.N, Equals, 47) 1471 c.Log("Got Next with N=47!") 1472 1473 // The following may break because it depends a bit on the internal 1474 // timing used by MongoDB's AwaitData logic. If it does, the problem 1475 // will be observed as more GET_MORE_OPs than predicted: 1476 // 1*QUERY for nonce + 1*GET_MORE_OP on Next + 1*GET_MORE_OP on Next after sleep + 1477 // 1*INSERT_OP + 1*QUERY_OP for getLastError on insert of 47 1478 stats := mgo.GetStats() 1479 c.Assert(stats.SentOps, Equals, 5) 1480 c.Assert(stats.ReceivedOps, Equals, 4) // REPLY_OPs for 1*QUERY_OP for nonce + 2*GET_MORE_OPs + 1*QUERY_OP 1481 c.Assert(stats.ReceivedDocs, Equals, 3) // nonce + N=47 result + getLastError response 1482 1483 c.Log("Will wait for a result which will never come...") 1484 1485 started := time.Now() 1486 ok = iter.Next(&result) 1487 c.Assert(ok, Equals, false) 1488 c.Assert(iter.Err(), IsNil) 1489 c.Assert(iter.Timeout(), Equals, true) 1490 c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true) 1491 1492 c.Log("Will now reuse the timed out tail cursor...") 1493 1494 coll.Insert(M{"n": 48}) 1495 ok = iter.Next(&result) 1496 c.Assert(ok, Equals, true) 1497 c.Assert(iter.Close(), IsNil) 1498 c.Assert(iter.Timeout(), Equals, false) 1499 c.Assert(result.N, Equals, 48) 1500 } 1501 1502 // Test tailable cursors in a situation where Next never gets to sleep once 1503 // to respect the timeout requested on Tail. 1504 func (s *S) TestFindTailTimeoutNoSleep(c *C) { 1505 session, err := mgo.Dial("localhost:40001") 1506 c.Assert(err, IsNil) 1507 defer session.Close() 1508 1509 cresult := struct{ ErrMsg string }{} 1510 1511 db := session.DB("mydb") 1512 err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult) 1513 c.Assert(err, IsNil) 1514 c.Assert(cresult.ErrMsg, Equals, "") 1515 coll := db.C("mycoll") 1516 1517 ns := []int{40, 41, 42, 43, 44, 45, 46} 1518 for _, n := range ns { 1519 coll.Insert(M{"n": n}) 1520 } 1521 1522 session.Refresh() // Release socket. 1523 1524 mgo.ResetStats() 1525 1526 timeout := 1 * time.Second 1527 1528 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2) 1529 iter := query.Tail(timeout) 1530 1531 n := len(ns) 1532 result := struct{ N int }{} 1533 for i := 2; i != n; i++ { 1534 ok := iter.Next(&result) 1535 c.Assert(ok, Equals, true) 1536 c.Assert(iter.Err(), IsNil) 1537 c.Assert(iter.Timeout(), Equals, false) 1538 c.Assert(result.N, Equals, ns[i]) 1539 if i == 3 { // The batch boundary. 1540 stats := mgo.GetStats() 1541 c.Assert(stats.ReceivedDocs, Equals, 2) 1542 } 1543 } 1544 1545 mgo.ResetStats() 1546 1547 // The following call to Next will block. 1548 go func() { 1549 // The internal AwaitData timing of MongoDB is around 2 seconds, 1550 // so this item should arrive within the AwaitData threshold. 1551 time.Sleep(5e8) 1552 session := session.New() 1553 defer session.Close() 1554 coll := session.DB("mydb").C("mycoll") 1555 coll.Insert(M{"n": 47}) 1556 }() 1557 1558 c.Log("Will wait for Next with N=47...") 1559 ok := iter.Next(&result) 1560 c.Assert(ok, Equals, true) 1561 c.Assert(iter.Err(), IsNil) 1562 c.Assert(iter.Timeout(), Equals, false) 1563 c.Assert(result.N, Equals, 47) 1564 c.Log("Got Next with N=47!") 1565 1566 // The following may break because it depends a bit on the internal 1567 // timing used by MongoDB's AwaitData logic. If it does, the problem 1568 // will be observed as more GET_MORE_OPs than predicted: 1569 // 1*QUERY_OP for nonce + 1*GET_MORE_OP on Next + 1570 // 1*INSERT_OP + 1*QUERY_OP for getLastError on insert of 47 1571 stats := mgo.GetStats() 1572 c.Assert(stats.SentOps, Equals, 4) 1573 c.Assert(stats.ReceivedOps, Equals, 3) // REPLY_OPs for 1*QUERY_OP for nonce + 1*GET_MORE_OPs and 1*QUERY_OP 1574 c.Assert(stats.ReceivedDocs, Equals, 3) // nonce + N=47 result + getLastError response 1575 1576 c.Log("Will wait for a result which will never come...") 1577 1578 started := time.Now() 1579 ok = iter.Next(&result) 1580 c.Assert(ok, Equals, false) 1581 c.Assert(iter.Err(), IsNil) 1582 c.Assert(iter.Timeout(), Equals, true) 1583 c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true) 1584 1585 c.Log("Will now reuse the timed out tail cursor...") 1586 1587 coll.Insert(M{"n": 48}) 1588 ok = iter.Next(&result) 1589 c.Assert(ok, Equals, true) 1590 c.Assert(iter.Close(), IsNil) 1591 c.Assert(iter.Timeout(), Equals, false) 1592 c.Assert(result.N, Equals, 48) 1593 } 1594 1595 // Test tailable cursors in a situation where Next never gets to sleep once 1596 // to respect the timeout requested on Tail. 1597 func (s *S) TestFindTailNoTimeout(c *C) { 1598 if *fast { 1599 c.Skip("-fast") 1600 } 1601 1602 session, err := mgo.Dial("localhost:40001") 1603 c.Assert(err, IsNil) 1604 defer session.Close() 1605 1606 cresult := struct{ ErrMsg string }{} 1607 1608 db := session.DB("mydb") 1609 err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult) 1610 c.Assert(err, IsNil) 1611 c.Assert(cresult.ErrMsg, Equals, "") 1612 coll := db.C("mycoll") 1613 1614 ns := []int{40, 41, 42, 43, 44, 45, 46} 1615 for _, n := range ns { 1616 coll.Insert(M{"n": n}) 1617 } 1618 1619 session.Refresh() // Release socket. 1620 1621 mgo.ResetStats() 1622 1623 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2) 1624 iter := query.Tail(-1) 1625 c.Assert(err, IsNil) 1626 1627 n := len(ns) 1628 result := struct{ N int }{} 1629 for i := 2; i != n; i++ { 1630 ok := iter.Next(&result) 1631 c.Assert(ok, Equals, true) 1632 c.Assert(result.N, Equals, ns[i]) 1633 if i == 3 { // The batch boundary. 1634 stats := mgo.GetStats() 1635 c.Assert(stats.ReceivedDocs, Equals, 2) 1636 } 1637 } 1638 1639 mgo.ResetStats() 1640 1641 // The following call to Next will block. 1642 go func() { 1643 time.Sleep(5e8) 1644 session := session.New() 1645 defer session.Close() 1646 coll := session.DB("mydb").C("mycoll") 1647 coll.Insert(M{"n": 47}) 1648 }() 1649 1650 c.Log("Will wait for Next with N=47...") 1651 ok := iter.Next(&result) 1652 c.Assert(ok, Equals, true) 1653 c.Assert(iter.Err(), IsNil) 1654 c.Assert(iter.Timeout(), Equals, false) 1655 c.Assert(result.N, Equals, 47) 1656 c.Log("Got Next with N=47!") 1657 1658 // The following may break because it depends a bit on the internal 1659 // timing used by MongoDB's AwaitData logic. If it does, the problem 1660 // will be observed as more GET_MORE_OPs than predicted: 1661 // 1*QUERY_OP for nonce + 1*GET_MORE_OP on Next + 1662 // 1*INSERT_OP + 1*QUERY_OP for getLastError on insert of 47 1663 stats := mgo.GetStats() 1664 c.Assert(stats.SentOps, Equals, 4) 1665 c.Assert(stats.ReceivedOps, Equals, 3) // REPLY_OPs for 1*QUERY_OP for nonce + 1*GET_MORE_OPs and 1*QUERY_OP 1666 c.Assert(stats.ReceivedDocs, Equals, 3) // nonce + N=47 result + getLastError response 1667 1668 c.Log("Will wait for a result which will never come...") 1669 1670 gotNext := make(chan bool) 1671 go func() { 1672 ok := iter.Next(&result) 1673 gotNext <- ok 1674 }() 1675 1676 select { 1677 case ok := <-gotNext: 1678 c.Fatalf("Next returned: %v", ok) 1679 case <-time.After(3e9): 1680 // Good. Should still be sleeping at that point. 1681 } 1682 1683 // Closing the session should cause Next to return. 1684 session.Close() 1685 1686 select { 1687 case ok := <-gotNext: 1688 c.Assert(ok, Equals, false) 1689 c.Assert(iter.Err(), ErrorMatches, "Closed explicitly") 1690 c.Assert(iter.Timeout(), Equals, false) 1691 case <-time.After(1e9): 1692 c.Fatal("Closing the session did not unblock Next") 1693 } 1694 } 1695 1696 func (s *S) TestIterNextResetsResult(c *C) { 1697 session, err := mgo.Dial("localhost:40001") 1698 c.Assert(err, IsNil) 1699 defer session.Close() 1700 1701 coll := session.DB("mydb").C("mycoll") 1702 1703 ns := []int{1, 2, 3} 1704 for _, n := range ns { 1705 coll.Insert(M{"n" + strconv.Itoa(n): n}) 1706 } 1707 1708 query := coll.Find(nil).Sort("$natural") 1709 1710 i := 0 1711 var sresult *struct{ N1, N2, N3 int } 1712 iter := query.Iter() 1713 for iter.Next(&sresult) { 1714 switch i { 1715 case 0: 1716 c.Assert(sresult.N1, Equals, 1) 1717 c.Assert(sresult.N2+sresult.N3, Equals, 0) 1718 case 1: 1719 c.Assert(sresult.N2, Equals, 2) 1720 c.Assert(sresult.N1+sresult.N3, Equals, 0) 1721 case 2: 1722 c.Assert(sresult.N3, Equals, 3) 1723 c.Assert(sresult.N1+sresult.N2, Equals, 0) 1724 } 1725 i++ 1726 } 1727 c.Assert(iter.Close(), IsNil) 1728 1729 i = 0 1730 var mresult M 1731 iter = query.Iter() 1732 for iter.Next(&mresult) { 1733 delete(mresult, "_id") 1734 switch i { 1735 case 0: 1736 c.Assert(mresult, DeepEquals, M{"n1": 1}) 1737 case 1: 1738 c.Assert(mresult, DeepEquals, M{"n2": 2}) 1739 case 2: 1740 c.Assert(mresult, DeepEquals, M{"n3": 3}) 1741 } 1742 i++ 1743 } 1744 c.Assert(iter.Close(), IsNil) 1745 1746 i = 0 1747 var iresult interface{} 1748 iter = query.Iter() 1749 for iter.Next(&iresult) { 1750 mresult, ok := iresult.(bson.M) 1751 c.Assert(ok, Equals, true, Commentf("%#v", iresult)) 1752 delete(mresult, "_id") 1753 switch i { 1754 case 0: 1755 c.Assert(mresult, DeepEquals, bson.M{"n1": 1}) 1756 case 1: 1757 c.Assert(mresult, DeepEquals, bson.M{"n2": 2}) 1758 case 2: 1759 c.Assert(mresult, DeepEquals, bson.M{"n3": 3}) 1760 } 1761 i++ 1762 } 1763 c.Assert(iter.Close(), IsNil) 1764 } 1765 1766 func (s *S) TestFindForOnIter(c *C) { 1767 session, err := mgo.Dial("localhost:40001") 1768 c.Assert(err, IsNil) 1769 defer session.Close() 1770 1771 coll := session.DB("mydb").C("mycoll") 1772 1773 ns := []int{40, 41, 42, 43, 44, 45, 46} 1774 for _, n := range ns { 1775 coll.Insert(M{"n": n}) 1776 } 1777 1778 session.Refresh() // Release socket. 1779 1780 mgo.ResetStats() 1781 1782 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2) 1783 iter := query.Iter() 1784 1785 i := 2 1786 var result *struct{ N int } 1787 err = iter.For(&result, func() error { 1788 c.Assert(i < 7, Equals, true) 1789 c.Assert(result.N, Equals, ns[i]) 1790 if i == 1 { 1791 stats := mgo.GetStats() 1792 c.Assert(stats.ReceivedDocs, Equals, 2) 1793 } 1794 i++ 1795 return nil 1796 }) 1797 c.Assert(err, IsNil) 1798 1799 session.Refresh() // Release socket. 1800 1801 stats := mgo.GetStats() 1802 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 2*GET_MORE_OP 1803 c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs. 1804 c.Assert(stats.ReceivedDocs, Equals, 5) 1805 c.Assert(stats.SocketsInUse, Equals, 0) 1806 } 1807 1808 func (s *S) TestFindFor(c *C) { 1809 session, err := mgo.Dial("localhost:40001") 1810 c.Assert(err, IsNil) 1811 defer session.Close() 1812 1813 coll := session.DB("mydb").C("mycoll") 1814 1815 ns := []int{40, 41, 42, 43, 44, 45, 46} 1816 for _, n := range ns { 1817 coll.Insert(M{"n": n}) 1818 } 1819 1820 session.Refresh() // Release socket. 1821 1822 mgo.ResetStats() 1823 1824 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2) 1825 1826 i := 2 1827 var result *struct{ N int } 1828 err = query.For(&result, func() error { 1829 c.Assert(i < 7, Equals, true) 1830 c.Assert(result.N, Equals, ns[i]) 1831 if i == 1 { 1832 stats := mgo.GetStats() 1833 c.Assert(stats.ReceivedDocs, Equals, 2) 1834 } 1835 i++ 1836 return nil 1837 }) 1838 c.Assert(err, IsNil) 1839 1840 session.Refresh() // Release socket. 1841 1842 stats := mgo.GetStats() 1843 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 2*GET_MORE_OP 1844 c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs. 1845 c.Assert(stats.ReceivedDocs, Equals, 5) 1846 c.Assert(stats.SocketsInUse, Equals, 0) 1847 } 1848 1849 func (s *S) TestFindForStopOnError(c *C) { 1850 session, err := mgo.Dial("localhost:40001") 1851 c.Assert(err, IsNil) 1852 defer session.Close() 1853 1854 coll := session.DB("mydb").C("mycoll") 1855 1856 ns := []int{40, 41, 42, 43, 44, 45, 46} 1857 for _, n := range ns { 1858 coll.Insert(M{"n": n}) 1859 } 1860 1861 query := coll.Find(M{"n": M{"$gte": 42}}) 1862 i := 2 1863 var result *struct{ N int } 1864 err = query.For(&result, func() error { 1865 c.Assert(i < 4, Equals, true) 1866 c.Assert(result.N, Equals, ns[i]) 1867 if i == 3 { 1868 return fmt.Errorf("stop!") 1869 } 1870 i++ 1871 return nil 1872 }) 1873 c.Assert(err, ErrorMatches, "stop!") 1874 } 1875 1876 func (s *S) TestFindForResetsResult(c *C) { 1877 session, err := mgo.Dial("localhost:40001") 1878 c.Assert(err, IsNil) 1879 defer session.Close() 1880 1881 coll := session.DB("mydb").C("mycoll") 1882 1883 ns := []int{1, 2, 3} 1884 for _, n := range ns { 1885 coll.Insert(M{"n" + strconv.Itoa(n): n}) 1886 } 1887 1888 query := coll.Find(nil).Sort("$natural") 1889 1890 i := 0 1891 var sresult *struct{ N1, N2, N3 int } 1892 err = query.For(&sresult, func() error { 1893 switch i { 1894 case 0: 1895 c.Assert(sresult.N1, Equals, 1) 1896 c.Assert(sresult.N2+sresult.N3, Equals, 0) 1897 case 1: 1898 c.Assert(sresult.N2, Equals, 2) 1899 c.Assert(sresult.N1+sresult.N3, Equals, 0) 1900 case 2: 1901 c.Assert(sresult.N3, Equals, 3) 1902 c.Assert(sresult.N1+sresult.N2, Equals, 0) 1903 } 1904 i++ 1905 return nil 1906 }) 1907 c.Assert(err, IsNil) 1908 1909 i = 0 1910 var mresult M 1911 err = query.For(&mresult, func() error { 1912 delete(mresult, "_id") 1913 switch i { 1914 case 0: 1915 c.Assert(mresult, DeepEquals, M{"n1": 1}) 1916 case 1: 1917 c.Assert(mresult, DeepEquals, M{"n2": 2}) 1918 case 2: 1919 c.Assert(mresult, DeepEquals, M{"n3": 3}) 1920 } 1921 i++ 1922 return nil 1923 }) 1924 c.Assert(err, IsNil) 1925 1926 i = 0 1927 var iresult interface{} 1928 err = query.For(&iresult, func() error { 1929 mresult, ok := iresult.(bson.M) 1930 c.Assert(ok, Equals, true, Commentf("%#v", iresult)) 1931 delete(mresult, "_id") 1932 switch i { 1933 case 0: 1934 c.Assert(mresult, DeepEquals, bson.M{"n1": 1}) 1935 case 1: 1936 c.Assert(mresult, DeepEquals, bson.M{"n2": 2}) 1937 case 2: 1938 c.Assert(mresult, DeepEquals, bson.M{"n3": 3}) 1939 } 1940 i++ 1941 return nil 1942 }) 1943 c.Assert(err, IsNil) 1944 } 1945 1946 func (s *S) TestFindIterSnapshot(c *C) { 1947 session, err := mgo.Dial("localhost:40001") 1948 c.Assert(err, IsNil) 1949 defer session.Close() 1950 1951 // Insane amounts of logging otherwise due to the 1952 // amount of data being shuffled. 1953 mgo.SetDebug(false) 1954 defer mgo.SetDebug(true) 1955 1956 coll := session.DB("mydb").C("mycoll") 1957 1958 var a [1024000]byte 1959 1960 for n := 0; n < 10; n++ { 1961 err := coll.Insert(M{"_id": n, "n": n, "a1": &a}) 1962 c.Assert(err, IsNil) 1963 } 1964 1965 query := coll.Find(M{"n": M{"$gt": -1}}).Batch(2).Prefetch(0) 1966 query.Snapshot() 1967 iter := query.Iter() 1968 1969 seen := map[int]bool{} 1970 result := struct { 1971 Id int "_id" 1972 }{} 1973 for iter.Next(&result) { 1974 if len(seen) == 2 { 1975 // Grow all entries so that they have to move. 1976 // Backwards so that the order is inverted. 1977 for n := 10; n >= 0; n-- { 1978 _, err := coll.Upsert(M{"_id": n}, M{"$set": M{"a2": &a}}) 1979 c.Assert(err, IsNil) 1980 } 1981 } 1982 if seen[result.Id] { 1983 c.Fatalf("seen duplicated key: %d", result.Id) 1984 } 1985 seen[result.Id] = true 1986 } 1987 c.Assert(iter.Close(), IsNil) 1988 } 1989 1990 func (s *S) TestSort(c *C) { 1991 session, err := mgo.Dial("localhost:40001") 1992 c.Assert(err, IsNil) 1993 defer session.Close() 1994 1995 coll := session.DB("mydb").C("mycoll") 1996 1997 coll.Insert(M{"a": 1, "b": 1}) 1998 coll.Insert(M{"a": 2, "b": 2}) 1999 coll.Insert(M{"a": 2, "b": 1}) 2000 coll.Insert(M{"a": 0, "b": 1}) 2001 coll.Insert(M{"a": 2, "b": 0}) 2002 coll.Insert(M{"a": 0, "b": 2}) 2003 coll.Insert(M{"a": 1, "b": 2}) 2004 coll.Insert(M{"a": 0, "b": 0}) 2005 coll.Insert(M{"a": 1, "b": 0}) 2006 2007 query := coll.Find(M{}) 2008 query.Sort("-a") // Should be ignored. 2009 query.Sort("-b", "a") 2010 iter := query.Iter() 2011 2012 l := make([]int, 18) 2013 r := struct{ A, B int }{} 2014 for i := 0; i != len(l); i += 2 { 2015 ok := iter.Next(&r) 2016 c.Assert(ok, Equals, true) 2017 c.Assert(err, IsNil) 2018 l[i] = r.A 2019 l[i+1] = r.B 2020 } 2021 2022 c.Assert(l, DeepEquals, []int{0, 2, 1, 2, 2, 2, 0, 1, 1, 1, 2, 1, 0, 0, 1, 0, 2, 0}) 2023 } 2024 2025 func (s *S) TestSortWithBadArgs(c *C) { 2026 session, err := mgo.Dial("localhost:40001") 2027 c.Assert(err, IsNil) 2028 defer session.Close() 2029 2030 coll := session.DB("mydb").C("mycoll") 2031 2032 f1 := func() { coll.Find(nil).Sort("") } 2033 f2 := func() { coll.Find(nil).Sort("+") } 2034 f3 := func() { coll.Find(nil).Sort("foo", "-") } 2035 2036 for _, f := range []func(){f1, f2, f3} { 2037 c.Assert(f, PanicMatches, "Sort: empty field name") 2038 } 2039 } 2040 2041 func (s *S) TestPrefetching(c *C) { 2042 session, err := mgo.Dial("localhost:40001") 2043 c.Assert(err, IsNil) 2044 defer session.Close() 2045 2046 coll := session.DB("mydb").C("mycoll") 2047 2048 mgo.SetDebug(false) 2049 docs := make([]interface{}, 800) 2050 for i := 0; i != 600; i++ { 2051 docs[i] = bson.D{{"n", i}} 2052 } 2053 coll.Insert(docs...) 2054 2055 for testi := 0; testi < 5; testi++ { 2056 mgo.ResetStats() 2057 2058 var iter *mgo.Iter 2059 var beforeMore int 2060 2061 switch testi { 2062 case 0: // The default session value. 2063 session.SetBatch(100) 2064 iter = coll.Find(M{}).Iter() 2065 beforeMore = 75 2066 2067 case 2: // Changing the session value. 2068 session.SetBatch(100) 2069 session.SetPrefetch(0.27) 2070 iter = coll.Find(M{}).Iter() 2071 beforeMore = 73 2072 2073 case 1: // Changing via query methods. 2074 iter = coll.Find(M{}).Prefetch(0.27).Batch(100).Iter() 2075 beforeMore = 73 2076 2077 case 3: // With prefetch on first document. 2078 iter = coll.Find(M{}).Prefetch(1.0).Batch(100).Iter() 2079 beforeMore = 0 2080 2081 case 4: // Without prefetch. 2082 iter = coll.Find(M{}).Prefetch(0).Batch(100).Iter() 2083 beforeMore = 100 2084 } 2085 2086 pings := 0 2087 for batchi := 0; batchi < len(docs)/100-1; batchi++ { 2088 c.Logf("Iterating over %d documents on batch %d", beforeMore, batchi) 2089 var result struct{ N int } 2090 for i := 0; i < beforeMore; i++ { 2091 ok := iter.Next(&result) 2092 c.Assert(ok, Equals, true, Commentf("iter.Err: %v", iter.Err())) 2093 } 2094 beforeMore = 99 2095 c.Logf("Done iterating.") 2096 2097 session.Run("ping", nil) // Roundtrip to settle down. 2098 pings++ 2099 2100 stats := mgo.GetStats() 2101 c.Assert(stats.ReceivedDocs, Equals, (batchi+1)*100+pings) 2102 2103 c.Logf("Iterating over one more document on batch %d", batchi) 2104 ok := iter.Next(&result) 2105 c.Assert(ok, Equals, true, Commentf("iter.Err: %v", iter.Err())) 2106 c.Logf("Done iterating.") 2107 2108 session.Run("ping", nil) // Roundtrip to settle down. 2109 pings++ 2110 2111 stats = mgo.GetStats() 2112 c.Assert(stats.ReceivedDocs, Equals, (batchi+2)*100+pings) 2113 } 2114 } 2115 } 2116 2117 func (s *S) TestSafeSetting(c *C) { 2118 session, err := mgo.Dial("localhost:40001") 2119 c.Assert(err, IsNil) 2120 defer session.Close() 2121 2122 // Check the default 2123 safe := session.Safe() 2124 c.Assert(safe.W, Equals, 0) 2125 c.Assert(safe.WMode, Equals, "") 2126 c.Assert(safe.WTimeout, Equals, 0) 2127 c.Assert(safe.FSync, Equals, false) 2128 c.Assert(safe.J, Equals, false) 2129 2130 // Tweak it 2131 session.SetSafe(&mgo.Safe{W: 1, WTimeout: 2, FSync: true}) 2132 safe = session.Safe() 2133 c.Assert(safe.W, Equals, 1) 2134 c.Assert(safe.WMode, Equals, "") 2135 c.Assert(safe.WTimeout, Equals, 2) 2136 c.Assert(safe.FSync, Equals, true) 2137 c.Assert(safe.J, Equals, false) 2138 2139 // Reset it again. 2140 session.SetSafe(&mgo.Safe{}) 2141 safe = session.Safe() 2142 c.Assert(safe.W, Equals, 0) 2143 c.Assert(safe.WMode, Equals, "") 2144 c.Assert(safe.WTimeout, Equals, 0) 2145 c.Assert(safe.FSync, Equals, false) 2146 c.Assert(safe.J, Equals, false) 2147 2148 // Ensure safety to something more conservative. 2149 session.SetSafe(&mgo.Safe{W: 5, WTimeout: 6, J: true}) 2150 safe = session.Safe() 2151 c.Assert(safe.W, Equals, 5) 2152 c.Assert(safe.WMode, Equals, "") 2153 c.Assert(safe.WTimeout, Equals, 6) 2154 c.Assert(safe.FSync, Equals, false) 2155 c.Assert(safe.J, Equals, true) 2156 2157 // Ensure safety to something less conservative won't change it. 2158 session.EnsureSafe(&mgo.Safe{W: 4, WTimeout: 7}) 2159 safe = session.Safe() 2160 c.Assert(safe.W, Equals, 5) 2161 c.Assert(safe.WMode, Equals, "") 2162 c.Assert(safe.WTimeout, Equals, 6) 2163 c.Assert(safe.FSync, Equals, false) 2164 c.Assert(safe.J, Equals, true) 2165 2166 // But to something more conservative will. 2167 session.EnsureSafe(&mgo.Safe{W: 6, WTimeout: 4, FSync: true}) 2168 safe = session.Safe() 2169 c.Assert(safe.W, Equals, 6) 2170 c.Assert(safe.WMode, Equals, "") 2171 c.Assert(safe.WTimeout, Equals, 4) 2172 c.Assert(safe.FSync, Equals, true) 2173 c.Assert(safe.J, Equals, false) 2174 2175 // Even more conservative. 2176 session.EnsureSafe(&mgo.Safe{WMode: "majority", WTimeout: 2}) 2177 safe = session.Safe() 2178 c.Assert(safe.W, Equals, 0) 2179 c.Assert(safe.WMode, Equals, "majority") 2180 c.Assert(safe.WTimeout, Equals, 2) 2181 c.Assert(safe.FSync, Equals, true) 2182 c.Assert(safe.J, Equals, false) 2183 2184 // WMode always overrides, whatever it is, but J doesn't. 2185 session.EnsureSafe(&mgo.Safe{WMode: "something", J: true}) 2186 safe = session.Safe() 2187 c.Assert(safe.W, Equals, 0) 2188 c.Assert(safe.WMode, Equals, "something") 2189 c.Assert(safe.WTimeout, Equals, 2) 2190 c.Assert(safe.FSync, Equals, true) 2191 c.Assert(safe.J, Equals, false) 2192 2193 // EnsureSafe with nil does nothing. 2194 session.EnsureSafe(nil) 2195 safe = session.Safe() 2196 c.Assert(safe.W, Equals, 0) 2197 c.Assert(safe.WMode, Equals, "something") 2198 c.Assert(safe.WTimeout, Equals, 2) 2199 c.Assert(safe.FSync, Equals, true) 2200 c.Assert(safe.J, Equals, false) 2201 2202 // Changing the safety of a cloned session doesn't touch the original. 2203 clone := session.Clone() 2204 defer clone.Close() 2205 clone.EnsureSafe(&mgo.Safe{WMode: "foo"}) 2206 safe = session.Safe() 2207 c.Assert(safe.WMode, Equals, "something") 2208 } 2209 2210 func (s *S) TestSafeInsert(c *C) { 2211 session, err := mgo.Dial("localhost:40001") 2212 c.Assert(err, IsNil) 2213 defer session.Close() 2214 2215 coll := session.DB("mydb").C("mycoll") 2216 2217 // Insert an element with a predefined key. 2218 err = coll.Insert(M{"_id": 1}) 2219 c.Assert(err, IsNil) 2220 2221 mgo.ResetStats() 2222 2223 // Session should be safe by default, so inserting it again must fail. 2224 err = coll.Insert(M{"_id": 1}) 2225 c.Assert(err, ErrorMatches, "E11000 duplicate.*") 2226 c.Assert(err.(*mgo.LastError).Code, Equals, 11000) 2227 2228 // It must have sent two operations (INSERT_OP + getLastError QUERY_OP) 2229 stats := mgo.GetStats() 2230 c.Assert(stats.SentOps, Equals, 2) 2231 2232 mgo.ResetStats() 2233 2234 // If we disable safety, though, it won't complain. 2235 session.SetSafe(nil) 2236 err = coll.Insert(M{"_id": 1}) 2237 c.Assert(err, IsNil) 2238 2239 // Must have sent a single operation this time (just the INSERT_OP) 2240 stats = mgo.GetStats() 2241 c.Assert(stats.SentOps, Equals, 1) 2242 } 2243 2244 func (s *S) TestSafeParameters(c *C) { 2245 session, err := mgo.Dial("localhost:40011") 2246 c.Assert(err, IsNil) 2247 defer session.Close() 2248 2249 coll := session.DB("mydb").C("mycoll") 2250 2251 // Tweak the safety parameters to something unachievable. 2252 session.SetSafe(&mgo.Safe{W: 4, WTimeout: 100}) 2253 err = coll.Insert(M{"_id": 1}) 2254 c.Assert(err, ErrorMatches, "timeout") 2255 c.Assert(err.(*mgo.LastError).WTimeout, Equals, true) 2256 } 2257 2258 func (s *S) TestQueryErrorOne(c *C) { 2259 session, err := mgo.Dial("localhost:40001") 2260 c.Assert(err, IsNil) 2261 defer session.Close() 2262 2263 coll := session.DB("mydb").C("mycoll") 2264 2265 result := struct { 2266 Err string "$err" 2267 }{} 2268 2269 err = coll.Find(M{"a": 1}).Select(M{"a": M{"b": 1}}).One(&result) 2270 c.Assert(err, ErrorMatches, "Unsupported projection option: b") 2271 c.Assert(err.(*mgo.QueryError).Message, Matches, "Unsupported projection option: b") 2272 c.Assert(err.(*mgo.QueryError).Code, Equals, 13097) 2273 2274 // The result should be properly unmarshalled with QueryError 2275 c.Assert(result.Err, Matches, "Unsupported projection option: b") 2276 } 2277 2278 func (s *S) TestQueryErrorNext(c *C) { 2279 session, err := mgo.Dial("localhost:40001") 2280 c.Assert(err, IsNil) 2281 defer session.Close() 2282 2283 coll := session.DB("mydb").C("mycoll") 2284 2285 result := struct { 2286 Err string "$err" 2287 }{} 2288 2289 iter := coll.Find(M{"a": 1}).Select(M{"a": M{"b": 1}}).Iter() 2290 2291 ok := iter.Next(&result) 2292 c.Assert(ok, Equals, false) 2293 2294 err = iter.Close() 2295 c.Assert(err, ErrorMatches, "Unsupported projection option: b") 2296 c.Assert(err.(*mgo.QueryError).Message, Matches, "Unsupported projection option: b") 2297 c.Assert(err.(*mgo.QueryError).Code, Equals, 13097) 2298 c.Assert(iter.Err(), Equals, err) 2299 2300 // The result should be properly unmarshalled with QueryError 2301 c.Assert(result.Err, Matches, "Unsupported projection option: b") 2302 } 2303 2304 func (s *S) TestEnsureIndex(c *C) { 2305 session, err := mgo.Dial("localhost:40001") 2306 c.Assert(err, IsNil) 2307 defer session.Close() 2308 2309 index1 := mgo.Index{ 2310 Key: []string{"a"}, 2311 Background: true, 2312 } 2313 2314 index2 := mgo.Index{ 2315 Key: []string{"a", "-b"}, 2316 Unique: true, 2317 DropDups: true, 2318 } 2319 2320 // Obsolete: 2321 index3 := mgo.Index{ 2322 Key: []string{"@loc_old"}, 2323 Min: -500, 2324 Max: 500, 2325 Bits: 32, 2326 } 2327 2328 index4 := mgo.Index{ 2329 Key: []string{"$2d:loc"}, 2330 Min: -500, 2331 Max: 500, 2332 Bits: 32, 2333 } 2334 2335 coll := session.DB("mydb").C("mycoll") 2336 2337 for _, index := range []mgo.Index{index1, index2, index3, index4} { 2338 err = coll.EnsureIndex(index) 2339 c.Assert(err, IsNil) 2340 } 2341 2342 sysidx := session.DB("mydb").C("system.indexes") 2343 2344 result1 := M{} 2345 err = sysidx.Find(M{"name": "a_1"}).One(result1) 2346 c.Assert(err, IsNil) 2347 2348 result2 := M{} 2349 err = sysidx.Find(M{"name": "a_1_b_-1"}).One(result2) 2350 c.Assert(err, IsNil) 2351 2352 result3 := M{} 2353 err = sysidx.Find(M{"name": "loc_old_2d"}).One(result3) 2354 c.Assert(err, IsNil) 2355 2356 result4 := M{} 2357 err = sysidx.Find(M{"name": "loc_2d"}).One(result4) 2358 c.Assert(err, IsNil) 2359 2360 delete(result1, "v") 2361 expected1 := M{ 2362 "name": "a_1", 2363 "key": M{"a": 1}, 2364 "ns": "mydb.mycoll", 2365 "background": true, 2366 } 2367 c.Assert(result1, DeepEquals, expected1) 2368 2369 delete(result2, "v") 2370 expected2 := M{ 2371 "name": "a_1_b_-1", 2372 "key": M{"a": 1, "b": -1}, 2373 "ns": "mydb.mycoll", 2374 "unique": true, 2375 "dropDups": true, 2376 } 2377 c.Assert(result2, DeepEquals, expected2) 2378 2379 delete(result3, "v") 2380 expected3 := M{ 2381 "name": "loc_old_2d", 2382 "key": M{"loc_old": "2d"}, 2383 "ns": "mydb.mycoll", 2384 "min": -500, 2385 "max": 500, 2386 "bits": 32, 2387 } 2388 c.Assert(result3, DeepEquals, expected3) 2389 2390 delete(result4, "v") 2391 expected4 := M{ 2392 "name": "loc_2d", 2393 "key": M{"loc": "2d"}, 2394 "ns": "mydb.mycoll", 2395 "min": -500, 2396 "max": 500, 2397 "bits": 32, 2398 } 2399 c.Assert(result4, DeepEquals, expected4) 2400 2401 // Ensure the index actually works for real. 2402 err = coll.Insert(M{"a": 1, "b": 1}) 2403 c.Assert(err, IsNil) 2404 err = coll.Insert(M{"a": 1, "b": 1}) 2405 c.Assert(err, ErrorMatches, ".*duplicate key error.*") 2406 c.Assert(mgo.IsDup(err), Equals, true) 2407 } 2408 2409 func (s *S) TestEnsureIndexWithBadInfo(c *C) { 2410 session, err := mgo.Dial("localhost:40001") 2411 c.Assert(err, IsNil) 2412 defer session.Close() 2413 2414 coll := session.DB("mydb").C("mycoll") 2415 2416 err = coll.EnsureIndex(mgo.Index{}) 2417 c.Assert(err, ErrorMatches, "Invalid index key:.*") 2418 2419 err = coll.EnsureIndex(mgo.Index{Key: []string{""}}) 2420 c.Assert(err, ErrorMatches, "Invalid index key:.*") 2421 } 2422 2423 func (s *S) TestEnsureIndexWithUnsafeSession(c *C) { 2424 session, err := mgo.Dial("localhost:40001") 2425 c.Assert(err, IsNil) 2426 defer session.Close() 2427 2428 session.SetSafe(nil) 2429 2430 coll := session.DB("mydb").C("mycoll") 2431 2432 err = coll.Insert(M{"a": 1}) 2433 c.Assert(err, IsNil) 2434 2435 err = coll.Insert(M{"a": 1}) 2436 c.Assert(err, IsNil) 2437 2438 // Should fail since there are duplicated entries. 2439 index := mgo.Index{ 2440 Key: []string{"a"}, 2441 Unique: true, 2442 } 2443 2444 err = coll.EnsureIndex(index) 2445 c.Assert(err, ErrorMatches, ".*duplicate key error.*") 2446 } 2447 2448 func (s *S) TestEnsureIndexKey(c *C) { 2449 session, err := mgo.Dial("localhost:40001") 2450 c.Assert(err, IsNil) 2451 defer session.Close() 2452 2453 coll := session.DB("mydb").C("mycoll") 2454 2455 err = coll.EnsureIndexKey("a") 2456 c.Assert(err, IsNil) 2457 2458 err = coll.EnsureIndexKey("a", "-b") 2459 c.Assert(err, IsNil) 2460 2461 sysidx := session.DB("mydb").C("system.indexes") 2462 2463 result1 := M{} 2464 err = sysidx.Find(M{"name": "a_1"}).One(result1) 2465 c.Assert(err, IsNil) 2466 2467 result2 := M{} 2468 err = sysidx.Find(M{"name": "a_1_b_-1"}).One(result2) 2469 c.Assert(err, IsNil) 2470 2471 delete(result1, "v") 2472 expected1 := M{ 2473 "name": "a_1", 2474 "key": M{"a": 1}, 2475 "ns": "mydb.mycoll", 2476 } 2477 c.Assert(result1, DeepEquals, expected1) 2478 2479 delete(result2, "v") 2480 expected2 := M{ 2481 "name": "a_1_b_-1", 2482 "key": M{"a": 1, "b": -1}, 2483 "ns": "mydb.mycoll", 2484 } 2485 c.Assert(result2, DeepEquals, expected2) 2486 } 2487 2488 func (s *S) TestEnsureIndexDropIndex(c *C) { 2489 session, err := mgo.Dial("localhost:40001") 2490 c.Assert(err, IsNil) 2491 defer session.Close() 2492 2493 coll := session.DB("mydb").C("mycoll") 2494 2495 err = coll.EnsureIndexKey("a") 2496 c.Assert(err, IsNil) 2497 2498 err = coll.EnsureIndexKey("-b") 2499 c.Assert(err, IsNil) 2500 2501 err = coll.DropIndex("-b") 2502 c.Assert(err, IsNil) 2503 2504 sysidx := session.DB("mydb").C("system.indexes") 2505 dummy := &struct{}{} 2506 2507 err = sysidx.Find(M{"name": "a_1"}).One(dummy) 2508 c.Assert(err, IsNil) 2509 2510 err = sysidx.Find(M{"name": "b_1"}).One(dummy) 2511 c.Assert(err, Equals, mgo.ErrNotFound) 2512 2513 err = coll.DropIndex("a") 2514 c.Assert(err, IsNil) 2515 2516 err = sysidx.Find(M{"name": "a_1"}).One(dummy) 2517 c.Assert(err, Equals, mgo.ErrNotFound) 2518 2519 err = coll.DropIndex("a") 2520 c.Assert(err, ErrorMatches, "index not found") 2521 } 2522 2523 func (s *S) TestEnsureIndexCaching(c *C) { 2524 session, err := mgo.Dial("localhost:40001") 2525 c.Assert(err, IsNil) 2526 defer session.Close() 2527 2528 coll := session.DB("mydb").C("mycoll") 2529 2530 err = coll.EnsureIndexKey("a") 2531 c.Assert(err, IsNil) 2532 2533 mgo.ResetStats() 2534 2535 // Second EnsureIndex should be cached and do nothing. 2536 err = coll.EnsureIndexKey("a") 2537 c.Assert(err, IsNil) 2538 2539 stats := mgo.GetStats() 2540 c.Assert(stats.SentOps, Equals, 0) 2541 2542 // Resetting the cache should make it contact the server again. 2543 session.ResetIndexCache() 2544 2545 err = coll.EnsureIndexKey("a") 2546 c.Assert(err, IsNil) 2547 2548 stats = mgo.GetStats() 2549 c.Assert(stats.SentOps, Equals, 2) 2550 2551 // Dropping the index should also drop the cached index key. 2552 err = coll.DropIndex("a") 2553 c.Assert(err, IsNil) 2554 2555 mgo.ResetStats() 2556 2557 err = coll.EnsureIndexKey("a") 2558 c.Assert(err, IsNil) 2559 2560 stats = mgo.GetStats() 2561 c.Assert(stats.SentOps, Equals, 2) 2562 } 2563 2564 func (s *S) TestEnsureIndexGetIndexes(c *C) { 2565 session, err := mgo.Dial("localhost:40001") 2566 c.Assert(err, IsNil) 2567 defer session.Close() 2568 2569 coll := session.DB("mydb").C("mycoll") 2570 2571 err = coll.EnsureIndexKey("-b") 2572 c.Assert(err, IsNil) 2573 2574 err = coll.EnsureIndexKey("a") 2575 c.Assert(err, IsNil) 2576 2577 // Obsolete. 2578 err = coll.EnsureIndexKey("@c") 2579 c.Assert(err, IsNil) 2580 2581 err = coll.EnsureIndexKey("$2d:d") 2582 c.Assert(err, IsNil) 2583 2584 indexes, err := coll.Indexes() 2585 c.Assert(err, IsNil) 2586 2587 c.Assert(indexes[0].Name, Equals, "_id_") 2588 c.Assert(indexes[1].Name, Equals, "a_1") 2589 c.Assert(indexes[1].Key, DeepEquals, []string{"a"}) 2590 c.Assert(indexes[2].Name, Equals, "b_-1") 2591 c.Assert(indexes[2].Key, DeepEquals, []string{"-b"}) 2592 c.Assert(indexes[3].Name, Equals, "c_2d") 2593 c.Assert(indexes[3].Key, DeepEquals, []string{"$2d:c"}) 2594 c.Assert(indexes[4].Name, Equals, "d_2d") 2595 c.Assert(indexes[4].Key, DeepEquals, []string{"$2d:d"}) 2596 } 2597 2598 func (s *S) TestEnsureIndexEvalGetIndexes(c *C) { 2599 session, err := mgo.Dial("localhost:40001") 2600 c.Assert(err, IsNil) 2601 defer session.Close() 2602 2603 coll := session.DB("mydb").C("mycoll") 2604 2605 err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({b: -1})"}}, nil) 2606 c.Assert(err, IsNil) 2607 err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({a: 1})"}}, nil) 2608 c.Assert(err, IsNil) 2609 err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({c: '2d'})"}}, nil) 2610 c.Assert(err, IsNil) 2611 err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({d: -1, e: 1})"}}, nil) 2612 c.Assert(err, IsNil) 2613 2614 indexes, err := coll.Indexes() 2615 c.Assert(err, IsNil) 2616 2617 c.Assert(indexes[0].Name, Equals, "_id_") 2618 c.Assert(indexes[1].Name, Equals, "a_1") 2619 c.Assert(indexes[1].Key, DeepEquals, []string{"a"}) 2620 c.Assert(indexes[2].Name, Equals, "b_-1") 2621 c.Assert(indexes[2].Key, DeepEquals, []string{"-b"}) 2622 c.Assert(indexes[3].Name, Equals, "c_2d") 2623 c.Assert(indexes[3].Key, DeepEquals, []string{"$2d:c"}) 2624 c.Assert(indexes[4].Name, Equals, "d_-1_e_1") 2625 c.Assert(indexes[4].Key, DeepEquals, []string{"-d", "e"}) 2626 } 2627 2628 var testTTL = flag.Bool("test-ttl", false, "test TTL collections (may take 1 minute)") 2629 2630 func (s *S) TestEnsureIndexExpireAfter(c *C) { 2631 session, err := mgo.Dial("localhost:40001") 2632 c.Assert(err, IsNil) 2633 defer session.Close() 2634 2635 session.SetSafe(nil) 2636 2637 coll := session.DB("mydb").C("mycoll") 2638 2639 err = coll.Insert(M{"n": 1, "t": time.Now().Add(-120 * time.Second)}) 2640 c.Assert(err, IsNil) 2641 err = coll.Insert(M{"n": 2, "t": time.Now()}) 2642 c.Assert(err, IsNil) 2643 2644 // Should fail since there are duplicated entries. 2645 index := mgo.Index{ 2646 Key: []string{"t"}, 2647 ExpireAfter: 1 * time.Minute, 2648 } 2649 2650 err = coll.EnsureIndex(index) 2651 c.Assert(err, IsNil) 2652 2653 indexes, err := coll.Indexes() 2654 c.Assert(err, IsNil) 2655 c.Assert(indexes[1].Name, Equals, "t_1") 2656 c.Assert(indexes[1].ExpireAfter, Equals, 1*time.Minute) 2657 2658 if *testTTL { 2659 worked := false 2660 stop := time.Now().Add(70 * time.Second) 2661 for time.Now().Before(stop) { 2662 n, err := coll.Count() 2663 c.Assert(err, IsNil) 2664 if n == 1 { 2665 worked = true 2666 break 2667 } 2668 c.Assert(n, Equals, 2) 2669 c.Logf("Still has 2 entries...") 2670 time.Sleep(1 * time.Second) 2671 } 2672 if !worked { 2673 c.Fatalf("TTL index didn't work") 2674 } 2675 } 2676 } 2677 2678 func (s *S) TestDistinct(c *C) { 2679 session, err := mgo.Dial("localhost:40001") 2680 c.Assert(err, IsNil) 2681 defer session.Close() 2682 2683 coll := session.DB("mydb").C("mycoll") 2684 2685 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} { 2686 coll.Insert(M{"n": i}) 2687 } 2688 2689 var result []int 2690 err = coll.Find(M{"n": M{"$gt": 2}}).Sort("n").Distinct("n", &result) 2691 2692 sort.IntSlice(result).Sort() 2693 c.Assert(result, DeepEquals, []int{3, 4, 6}) 2694 } 2695 2696 func (s *S) TestMapReduce(c *C) { 2697 session, err := mgo.Dial("localhost:40001") 2698 c.Assert(err, IsNil) 2699 defer session.Close() 2700 2701 coll := session.DB("mydb").C("mycoll") 2702 2703 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} { 2704 coll.Insert(M{"n": i}) 2705 } 2706 2707 job := &mgo.MapReduce{ 2708 Map: "function() { emit(this.n, 1); }", 2709 Reduce: "function(key, values) { return Array.sum(values); }", 2710 } 2711 var result []struct { 2712 Id int "_id" 2713 Value int 2714 } 2715 2716 info, err := coll.Find(M{"n": M{"$gt": 2}}).MapReduce(job, &result) 2717 c.Assert(err, IsNil) 2718 c.Assert(info.InputCount, Equals, 4) 2719 c.Assert(info.EmitCount, Equals, 4) 2720 c.Assert(info.OutputCount, Equals, 3) 2721 c.Assert(info.Time > 1e6, Equals, true) 2722 c.Assert(info.Time < 1e9, Equals, true) 2723 c.Assert(info.VerboseTime, IsNil) 2724 2725 expected := map[int]int{3: 1, 4: 2, 6: 1} 2726 for _, item := range result { 2727 c.Logf("Item: %#v", &item) 2728 c.Assert(item.Value, Equals, expected[item.Id]) 2729 expected[item.Id] = -1 2730 } 2731 2732 // Weak attempt of testing that Sort gets delivered. 2733 _, err = coll.Find(nil).Sort("-n").MapReduce(job, &result) 2734 _, isQueryError := err.(*mgo.QueryError) 2735 c.Assert(isQueryError, Equals, true) 2736 } 2737 2738 func (s *S) TestMapReduceFinalize(c *C) { 2739 session, err := mgo.Dial("localhost:40001") 2740 c.Assert(err, IsNil) 2741 defer session.Close() 2742 2743 coll := session.DB("mydb").C("mycoll") 2744 2745 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} { 2746 coll.Insert(M{"n": i}) 2747 } 2748 2749 job := &mgo.MapReduce{ 2750 Map: "function() { emit(this.n, 1) }", 2751 Reduce: "function(key, values) { return Array.sum(values) }", 2752 Finalize: "function(key, count) { return {count: count} }", 2753 } 2754 var result []struct { 2755 Id int "_id" 2756 Value struct{ Count int } 2757 } 2758 _, err = coll.Find(nil).MapReduce(job, &result) 2759 c.Assert(err, IsNil) 2760 2761 expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1} 2762 for _, item := range result { 2763 c.Logf("Item: %#v", &item) 2764 c.Assert(item.Value.Count, Equals, expected[item.Id]) 2765 expected[item.Id] = -1 2766 } 2767 } 2768 2769 func (s *S) TestMapReduceToCollection(c *C) { 2770 session, err := mgo.Dial("localhost:40001") 2771 c.Assert(err, IsNil) 2772 defer session.Close() 2773 2774 coll := session.DB("mydb").C("mycoll") 2775 2776 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} { 2777 coll.Insert(M{"n": i}) 2778 } 2779 2780 job := &mgo.MapReduce{ 2781 Map: "function() { emit(this.n, 1); }", 2782 Reduce: "function(key, values) { return Array.sum(values); }", 2783 Out: "mr", 2784 } 2785 2786 info, err := coll.Find(nil).MapReduce(job, nil) 2787 c.Assert(err, IsNil) 2788 c.Assert(info.InputCount, Equals, 7) 2789 c.Assert(info.EmitCount, Equals, 7) 2790 c.Assert(info.OutputCount, Equals, 5) 2791 c.Assert(info.Time > 1e6, Equals, true) 2792 c.Assert(info.Time < 1e9, Equals, true) 2793 c.Assert(info.Collection, Equals, "mr") 2794 c.Assert(info.Database, Equals, "mydb") 2795 2796 expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1} 2797 var item *struct { 2798 Id int "_id" 2799 Value int 2800 } 2801 mr := session.DB("mydb").C("mr") 2802 iter := mr.Find(nil).Iter() 2803 for iter.Next(&item) { 2804 c.Logf("Item: %#v", &item) 2805 c.Assert(item.Value, Equals, expected[item.Id]) 2806 expected[item.Id] = -1 2807 } 2808 c.Assert(iter.Close(), IsNil) 2809 } 2810 2811 func (s *S) TestMapReduceToOtherDb(c *C) { 2812 session, err := mgo.Dial("localhost:40001") 2813 c.Assert(err, IsNil) 2814 defer session.Close() 2815 2816 coll := session.DB("mydb").C("mycoll") 2817 2818 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} { 2819 coll.Insert(M{"n": i}) 2820 } 2821 2822 job := &mgo.MapReduce{ 2823 Map: "function() { emit(this.n, 1); }", 2824 Reduce: "function(key, values) { return Array.sum(values); }", 2825 Out: bson.D{{"replace", "mr"}, {"db", "otherdb"}}, 2826 } 2827 2828 info, err := coll.Find(nil).MapReduce(job, nil) 2829 c.Assert(err, IsNil) 2830 c.Assert(info.InputCount, Equals, 7) 2831 c.Assert(info.EmitCount, Equals, 7) 2832 c.Assert(info.OutputCount, Equals, 5) 2833 c.Assert(info.Time > 1e6, Equals, true) 2834 c.Assert(info.Time < 2e9, Equals, true) 2835 c.Assert(info.Collection, Equals, "mr") 2836 c.Assert(info.Database, Equals, "otherdb") 2837 2838 expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1} 2839 var item *struct { 2840 Id int "_id" 2841 Value int 2842 } 2843 mr := session.DB("otherdb").C("mr") 2844 iter := mr.Find(nil).Iter() 2845 for iter.Next(&item) { 2846 c.Logf("Item: %#v", &item) 2847 c.Assert(item.Value, Equals, expected[item.Id]) 2848 expected[item.Id] = -1 2849 } 2850 c.Assert(iter.Close(), IsNil) 2851 } 2852 2853 func (s *S) TestMapReduceOutOfOrder(c *C) { 2854 session, err := mgo.Dial("localhost:40001") 2855 c.Assert(err, IsNil) 2856 defer session.Close() 2857 2858 coll := session.DB("mydb").C("mycoll") 2859 2860 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} { 2861 coll.Insert(M{"n": i}) 2862 } 2863 2864 job := &mgo.MapReduce{ 2865 Map: "function() { emit(this.n, 1); }", 2866 Reduce: "function(key, values) { return Array.sum(values); }", 2867 Out: bson.M{"a": "a", "z": "z", "replace": "mr", "db": "otherdb", "b": "b", "y": "y"}, 2868 } 2869 2870 info, err := coll.Find(nil).MapReduce(job, nil) 2871 c.Assert(err, IsNil) 2872 c.Assert(info.Collection, Equals, "mr") 2873 c.Assert(info.Database, Equals, "otherdb") 2874 } 2875 2876 func (s *S) TestMapReduceScope(c *C) { 2877 session, err := mgo.Dial("localhost:40001") 2878 c.Assert(err, IsNil) 2879 defer session.Close() 2880 2881 coll := session.DB("mydb").C("mycoll") 2882 2883 coll.Insert(M{"n": 1}) 2884 2885 job := &mgo.MapReduce{ 2886 Map: "function() { emit(this.n, x); }", 2887 Reduce: "function(key, values) { return Array.sum(values); }", 2888 Scope: M{"x": 42}, 2889 } 2890 2891 var result []bson.M 2892 _, err = coll.Find(nil).MapReduce(job, &result) 2893 c.Assert(len(result), Equals, 1) 2894 c.Assert(result[0]["value"], Equals, 42.0) 2895 } 2896 2897 func (s *S) TestMapReduceVerbose(c *C) { 2898 session, err := mgo.Dial("localhost:40001") 2899 c.Assert(err, IsNil) 2900 defer session.Close() 2901 2902 coll := session.DB("mydb").C("mycoll") 2903 2904 coll.Insert(M{"n": 1}) 2905 2906 job := &mgo.MapReduce{ 2907 Map: "function() { emit(this.n, 1); }", 2908 Reduce: "function(key, values) { return Array.sum(values); }", 2909 Verbose: true, 2910 } 2911 2912 info, err := coll.Find(nil).MapReduce(job, nil) 2913 c.Assert(err, IsNil) 2914 c.Assert(info.VerboseTime, NotNil) 2915 c.Assert(info.VerboseTime.Total > 1e6, Equals, true) 2916 c.Assert(info.VerboseTime.Total < 1e9, Equals, true) 2917 } 2918 2919 func (s *S) TestMapReduceLimit(c *C) { 2920 session, err := mgo.Dial("localhost:40001") 2921 c.Assert(err, IsNil) 2922 defer session.Close() 2923 2924 coll := session.DB("mydb").C("mycoll") 2925 2926 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} { 2927 coll.Insert(M{"n": i}) 2928 } 2929 2930 job := &mgo.MapReduce{ 2931 Map: "function() { emit(this.n, 1); }", 2932 Reduce: "function(key, values) { return Array.sum(values); }", 2933 } 2934 2935 var result []bson.M 2936 _, err = coll.Find(nil).Limit(3).MapReduce(job, &result) 2937 c.Assert(err, IsNil) 2938 c.Assert(len(result), Equals, 3) 2939 } 2940 2941 func (s *S) TestBuildInfo(c *C) { 2942 session, err := mgo.Dial("localhost:40001") 2943 c.Assert(err, IsNil) 2944 defer session.Close() 2945 2946 info, err := session.BuildInfo() 2947 c.Assert(err, IsNil) 2948 2949 var v []int 2950 for i, a := range strings.Split(info.Version, ".") { 2951 for _, token := range []string{"-rc", "-pre"} { 2952 if i == 2 && strings.Contains(a, token) { 2953 a = a[:strings.Index(a, token)] 2954 info.VersionArray[len(info.VersionArray)-1] = 0 2955 } 2956 } 2957 n, err := strconv.Atoi(a) 2958 c.Assert(err, IsNil) 2959 v = append(v, n) 2960 } 2961 for len(v) < 4 { 2962 v = append(v, 0) 2963 } 2964 2965 c.Assert(info.VersionArray, DeepEquals, v) 2966 c.Assert(info.GitVersion, Matches, "[a-z0-9]+") 2967 c.Assert(info.SysInfo, Matches, ".*[0-9:]+.*") 2968 if info.Bits != 32 && info.Bits != 64 { 2969 c.Fatalf("info.Bits is %d", info.Bits) 2970 } 2971 if info.MaxObjectSize < 8192 { 2972 c.Fatalf("info.MaxObjectSize seems too small: %d", info.MaxObjectSize) 2973 } 2974 } 2975 2976 func (s *S) TestZeroTimeRoundtrip(c *C) { 2977 session, err := mgo.Dial("localhost:40001") 2978 c.Assert(err, IsNil) 2979 defer session.Close() 2980 2981 var d struct{ T time.Time } 2982 conn := session.DB("mydb").C("mycoll") 2983 err = conn.Insert(d) 2984 c.Assert(err, IsNil) 2985 2986 var result bson.M 2987 err = conn.Find(nil).One(&result) 2988 c.Assert(err, IsNil) 2989 t, isTime := result["t"].(time.Time) 2990 c.Assert(isTime, Equals, true) 2991 c.Assert(t, Equals, time.Time{}) 2992 } 2993 2994 func (s *S) TestFsyncLock(c *C) { 2995 session, err := mgo.Dial("localhost:40001") 2996 c.Assert(err, IsNil) 2997 defer session.Close() 2998 2999 clone := session.Clone() 3000 defer clone.Close() 3001 3002 err = session.FsyncLock() 3003 c.Assert(err, IsNil) 3004 3005 done := make(chan time.Time) 3006 go func() { 3007 time.Sleep(3e9) 3008 now := time.Now() 3009 err := session.FsyncUnlock() 3010 c.Check(err, IsNil) 3011 done <- now 3012 }() 3013 3014 err = clone.DB("mydb").C("mycoll").Insert(bson.M{"n": 1}) 3015 unlocked := time.Now() 3016 unlocking := <-done 3017 c.Assert(err, IsNil) 3018 3019 c.Assert(unlocked.After(unlocking), Equals, true) 3020 c.Assert(unlocked.Sub(unlocking) < 1e9, Equals, true) 3021 } 3022 3023 func (s *S) TestFsync(c *C) { 3024 session, err := mgo.Dial("localhost:40001") 3025 c.Assert(err, IsNil) 3026 defer session.Close() 3027 3028 // Not much to do here. Just a smoke check. 3029 err = session.Fsync(false) 3030 c.Assert(err, IsNil) 3031 err = session.Fsync(true) 3032 c.Assert(err, IsNil) 3033 } 3034 3035 func (s *S) TestPipeIter(c *C) { 3036 if !s.versionAtLeast(2, 1) { 3037 c.Skip("Pipe only works on 2.1+") 3038 } 3039 3040 session, err := mgo.Dial("localhost:40001") 3041 c.Assert(err, IsNil) 3042 defer session.Close() 3043 3044 coll := session.DB("mydb").C("mycoll") 3045 3046 ns := []int{40, 41, 42, 43, 44, 45, 46} 3047 for _, n := range ns { 3048 coll.Insert(M{"n": n}) 3049 } 3050 3051 iter := coll.Pipe([]M{{"$match": M{"n": M{"$gte": 42}}}}).Iter() 3052 result := struct{ N int }{} 3053 for i := 2; i < 7; i++ { 3054 ok := iter.Next(&result) 3055 c.Assert(ok, Equals, true) 3056 c.Assert(result.N, Equals, ns[i]) 3057 } 3058 3059 c.Assert(iter.Next(&result), Equals, false) 3060 c.Assert(iter.Close(), IsNil) 3061 } 3062 3063 func (s *S) TestPipeAll(c *C) { 3064 if !s.versionAtLeast(2, 1) { 3065 c.Skip("Pipe only works on 2.1+") 3066 } 3067 3068 session, err := mgo.Dial("localhost:40001") 3069 c.Assert(err, IsNil) 3070 defer session.Close() 3071 3072 coll := session.DB("mydb").C("mycoll") 3073 3074 ns := []int{40, 41, 42, 43, 44, 45, 46} 3075 for _, n := range ns { 3076 err := coll.Insert(M{"n": n}) 3077 c.Assert(err, IsNil) 3078 } 3079 3080 var result []struct{ N int } 3081 err = coll.Pipe([]M{{"$match": M{"n": M{"$gte": 42}}}}).All(&result) 3082 c.Assert(err, IsNil) 3083 for i := 2; i < 7; i++ { 3084 c.Assert(result[i-2].N, Equals, ns[i]) 3085 } 3086 } 3087 3088 func (s *S) TestPipeOne(c *C) { 3089 if !s.versionAtLeast(2, 1) { 3090 c.Skip("Pipe only works on 2.1+") 3091 } 3092 3093 session, err := mgo.Dial("localhost:40001") 3094 c.Assert(err, IsNil) 3095 defer session.Close() 3096 3097 coll := session.DB("mydb").C("mycoll") 3098 coll.Insert(M{"a": 1, "b": 2}) 3099 3100 result := struct{ A, B int }{} 3101 3102 pipe := coll.Pipe([]M{{"$project": M{"a": 1, "b": M{"$add": []interface{}{"$b", 1}}}}}) 3103 err = pipe.One(&result) 3104 c.Assert(err, IsNil) 3105 c.Assert(result.A, Equals, 1) 3106 c.Assert(result.B, Equals, 3) 3107 3108 pipe = coll.Pipe([]M{{"$match": M{"a": 2}}}) 3109 err = pipe.One(&result) 3110 c.Assert(err, Equals, mgo.ErrNotFound) 3111 } 3112 3113 func (s *S) TestBatch1Bug(c *C) { 3114 session, err := mgo.Dial("localhost:40001") 3115 c.Assert(err, IsNil) 3116 defer session.Close() 3117 3118 coll := session.DB("mydb").C("mycoll") 3119 3120 for i := 0; i < 3; i++ { 3121 err := coll.Insert(M{"n": i}) 3122 c.Assert(err, IsNil) 3123 } 3124 3125 var ns []struct{ N int } 3126 err = coll.Find(nil).Batch(1).All(&ns) 3127 c.Assert(err, IsNil) 3128 c.Assert(len(ns), Equals, 3) 3129 3130 session.SetBatch(1) 3131 err = coll.Find(nil).All(&ns) 3132 c.Assert(err, IsNil) 3133 c.Assert(len(ns), Equals, 3) 3134 } 3135 3136 func (s *S) TestInterfaceIterBug(c *C) { 3137 session, err := mgo.Dial("localhost:40001") 3138 c.Assert(err, IsNil) 3139 defer session.Close() 3140 3141 coll := session.DB("mydb").C("mycoll") 3142 3143 for i := 0; i < 3; i++ { 3144 err := coll.Insert(M{"n": i}) 3145 c.Assert(err, IsNil) 3146 } 3147 3148 var result interface{} 3149 3150 i := 0 3151 iter := coll.Find(nil).Sort("n").Iter() 3152 for iter.Next(&result) { 3153 c.Assert(result.(bson.M)["n"], Equals, i) 3154 i++ 3155 } 3156 c.Assert(iter.Close(), IsNil) 3157 } 3158 3159 func (s *S) TestFindIterCloseKillsCursor(c *C) { 3160 session, err := mgo.Dial("localhost:40001") 3161 c.Assert(err, IsNil) 3162 defer session.Close() 3163 3164 cursors := serverCursorsOpen(session) 3165 3166 coll := session.DB("mydb").C("mycoll") 3167 ns := []int{40, 41, 42, 43, 44, 45, 46} 3168 for _, n := range ns { 3169 err = coll.Insert(M{"n": n}) 3170 c.Assert(err, IsNil) 3171 } 3172 3173 iter := coll.Find(nil).Batch(2).Iter() 3174 c.Assert(iter.Next(bson.M{}), Equals, true) 3175 3176 c.Assert(iter.Close(), IsNil) 3177 c.Assert(serverCursorsOpen(session), Equals, cursors) 3178 } 3179 3180 func (s *S) TestLogReplay(c *C) { 3181 session, err := mgo.Dial("localhost:40001") 3182 c.Assert(err, IsNil) 3183 defer session.Close() 3184 3185 coll := session.DB("mydb").C("mycoll") 3186 for i := 0; i < 5; i++ { 3187 err = coll.Insert(M{"ts": time.Now()}) 3188 c.Assert(err, IsNil) 3189 } 3190 3191 iter := coll.Find(nil).LogReplay().Iter() 3192 c.Assert(iter.Next(bson.M{}), Equals, false) 3193 c.Assert(iter.Err(), ErrorMatches, "no ts field in query") 3194 } 3195 3196 func (s *S) TestSetCursorTimeout(c *C) { 3197 session, err := mgo.Dial("localhost:40001") 3198 c.Assert(err, IsNil) 3199 defer session.Close() 3200 3201 coll := session.DB("mydb").C("mycoll") 3202 err = coll.Insert(M{"n": 42}) 3203 3204 // This is just a smoke test. Won't wait 10 minutes for an actual timeout. 3205 3206 session.SetCursorTimeout(0) 3207 3208 var result struct{ N int } 3209 iter := coll.Find(nil).Iter() 3210 c.Assert(iter.Next(&result), Equals, true) 3211 c.Assert(result.N, Equals, 42) 3212 c.Assert(iter.Next(&result), Equals, false) 3213 }