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