Best Keploy code snippet using mgo.Insert
session_test.go
Source:session_test.go
...111 }112 c.Assert(err, ErrorMatches, "unsupported connection URL option: (foo=1|bar=2)")113 }114}115func (s *S) TestInsertFindOne(c *C) {116 session, err := mgo.Dial("localhost:40001")117 c.Assert(err, IsNil)118 defer session.Close()119 coll := session.DB("mydb").C("mycoll")120 err = coll.Insert(M{"a": 1, "b": 2})121 c.Assert(err, IsNil)122 err = coll.Insert(M{"a": 1, "b": 3})123 c.Assert(err, IsNil)124 result := struct{ A, B int }{}125 err = coll.Find(M{"a": 1}).Sort("b").One(&result)126 c.Assert(err, IsNil)127 c.Assert(result.A, Equals, 1)128 c.Assert(result.B, Equals, 2)129 err = coll.Find(M{"a": 1}).Sort("-b").One(&result)130 c.Assert(err, IsNil)131 c.Assert(result.A, Equals, 1)132 c.Assert(result.B, Equals, 3)133}134func (s *S) TestInsertFindOneNil(c *C) {135 session, err := mgo.Dial("localhost:40002")136 c.Assert(err, IsNil)137 defer session.Close()138 coll := session.DB("mydb").C("mycoll")139 err = coll.Find(nil).One(nil)140 c.Assert(err, ErrorMatches, "unauthorized.*|not authorized.*")141}142func (s *S) TestInsertFindOneMap(c *C) {143 session, err := mgo.Dial("localhost:40001")144 c.Assert(err, IsNil)145 defer session.Close()146 coll := session.DB("mydb").C("mycoll")147 err = coll.Insert(M{"a": 1, "b": 2})148 c.Assert(err, IsNil)149 result := make(M)150 err = coll.Find(M{"a": 1}).One(result)151 c.Assert(err, IsNil)152 c.Assert(result["a"], Equals, 1)153 c.Assert(result["b"], Equals, 2)154}155func (s *S) TestInsertFindAll(c *C) {156 session, err := mgo.Dial("localhost:40001")157 c.Assert(err, IsNil)158 defer session.Close()159 coll := session.DB("mydb").C("mycoll")160 err = coll.Insert(M{"a": 1, "b": 2})161 c.Assert(err, IsNil)162 err = coll.Insert(M{"a": 3, "b": 4})163 c.Assert(err, IsNil)164 type R struct{ A, B int }165 var result []R166 assertResult := func() {167 c.Assert(len(result), Equals, 2)168 c.Assert(result[0].A, Equals, 1)169 c.Assert(result[0].B, Equals, 2)170 c.Assert(result[1].A, Equals, 3)171 c.Assert(result[1].B, Equals, 4)172 }173 // nil slice174 err = coll.Find(nil).Sort("a").All(&result)175 c.Assert(err, IsNil)176 assertResult()177 // Previously allocated slice178 allocd := make([]R, 5)179 result = allocd180 err = coll.Find(nil).Sort("a").All(&result)181 c.Assert(err, IsNil)182 assertResult()183 // Ensure result is backed by the originally allocated array184 c.Assert(&result[0], Equals, &allocd[0])185 // Non-pointer slice error186 f := func() { coll.Find(nil).All(result) }187 c.Assert(f, Panics, "result argument must be a slice address")188 // Non-slice error189 f = func() { coll.Find(nil).All(new(int)) }190 c.Assert(f, Panics, "result argument must be a slice address")191}192func (s *S) TestFindRef(c *C) {193 session, err := mgo.Dial("localhost:40001")194 c.Assert(err, IsNil)195 defer session.Close()196 db1 := session.DB("db1")197 db1col1 := db1.C("col1")198 db2 := session.DB("db2")199 db2col1 := db2.C("col1")200 err = db1col1.Insert(M{"_id": 1, "n": 1})201 c.Assert(err, IsNil)202 err = db1col1.Insert(M{"_id": 2, "n": 2})203 c.Assert(err, IsNil)204 err = db2col1.Insert(M{"_id": 2, "n": 3})205 c.Assert(err, IsNil)206 result := struct{ N int }{}207 ref1 := &mgo.DBRef{Collection: "col1", Id: 1}208 ref2 := &mgo.DBRef{Collection: "col1", Id: 2, Database: "db2"}209 err = db1.FindRef(ref1).One(&result)210 c.Assert(err, IsNil)211 c.Assert(result.N, Equals, 1)212 err = db1.FindRef(ref2).One(&result)213 c.Assert(err, IsNil)214 c.Assert(result.N, Equals, 3)215 err = db2.FindRef(ref1).One(&result)216 c.Assert(err, Equals, mgo.ErrNotFound)217 err = db2.FindRef(ref2).One(&result)218 c.Assert(err, IsNil)219 c.Assert(result.N, Equals, 3)220 err = session.FindRef(ref2).One(&result)221 c.Assert(err, IsNil)222 c.Assert(result.N, Equals, 3)223 f := func() { session.FindRef(ref1).One(&result) }224 c.Assert(f, PanicMatches, "Can't resolve database for &mgo.DBRef{Collection:\"col1\", Id:1, Database:\"\"}")225}226func (s *S) TestDatabaseAndCollectionNames(c *C) {227 session, err := mgo.Dial("localhost:40001")228 c.Assert(err, IsNil)229 defer session.Close()230 db1 := session.DB("db1")231 db1col1 := db1.C("col1")232 db1col2 := db1.C("col2")233 db2 := session.DB("db2")234 db2col1 := db2.C("col3")235 err = db1col1.Insert(M{"_id": 1})236 c.Assert(err, IsNil)237 err = db1col2.Insert(M{"_id": 1})238 c.Assert(err, IsNil)239 err = db2col1.Insert(M{"_id": 1})240 c.Assert(err, IsNil)241 names, err := session.DatabaseNames()242 c.Assert(err, IsNil)243 c.Assert(filterDBs(names), DeepEquals, []string{"db1", "db2"})244 // Try to exercise cursor logic. 2.8.0-rc3 still ignores this.245 session.SetBatch(2)246 names, err = db1.CollectionNames()247 c.Assert(err, IsNil)248 c.Assert(names, DeepEquals, []string{"col1", "col2", "system.indexes"})249 names, err = db2.CollectionNames()250 c.Assert(err, IsNil)251 c.Assert(names, DeepEquals, []string{"col3", "system.indexes"})252}253func (s *S) TestSelect(c *C) {254 session, err := mgo.Dial("localhost:40001")255 c.Assert(err, IsNil)256 defer session.Close()257 coll := session.DB("mydb").C("mycoll")258 coll.Insert(M{"a": 1, "b": 2})259 result := struct{ A, B int }{}260 err = coll.Find(M{"a": 1}).Select(M{"b": 1}).One(&result)261 c.Assert(err, IsNil)262 c.Assert(result.A, Equals, 0)263 c.Assert(result.B, Equals, 2)264}265func (s *S) TestInlineMap(c *C) {266 session, err := mgo.Dial("localhost:40001")267 c.Assert(err, IsNil)268 defer session.Close()269 coll := session.DB("mydb").C("mycoll")270 var v, result1 struct {271 A int272 M map[string]int ",inline"273 }274 v.A = 1275 v.M = map[string]int{"b": 2}276 err = coll.Insert(v)277 c.Assert(err, IsNil)278 noId := M{"_id": 0}279 err = coll.Find(nil).Select(noId).One(&result1)280 c.Assert(err, IsNil)281 c.Assert(result1.A, Equals, 1)282 c.Assert(result1.M, DeepEquals, map[string]int{"b": 2})283 var result2 M284 err = coll.Find(nil).Select(noId).One(&result2)285 c.Assert(err, IsNil)286 c.Assert(result2, DeepEquals, M{"a": 1, "b": 2})287}288func (s *S) TestUpdate(c *C) {289 session, err := mgo.Dial("localhost:40001")290 c.Assert(err, IsNil)291 defer session.Close()292 coll := session.DB("mydb").C("mycoll")293 ns := []int{40, 41, 42, 43, 44, 45, 46}294 for _, n := range ns {295 err := coll.Insert(M{"k": n, "n": n})296 c.Assert(err, IsNil)297 }298 // No changes is a no-op and shouldn't return an error.299 err = coll.Update(M{"k": 42}, M{"$set": M{"n": 42}})300 c.Assert(err, IsNil)301 err = coll.Update(M{"k": 42}, M{"$inc": M{"n": 1}})302 c.Assert(err, IsNil)303 result := make(M)304 err = coll.Find(M{"k": 42}).One(result)305 c.Assert(err, IsNil)306 c.Assert(result["n"], Equals, 43)307 err = coll.Update(M{"k": 47}, M{"k": 47, "n": 47})308 c.Assert(err, Equals, mgo.ErrNotFound)309 err = coll.Find(M{"k": 47}).One(result)310 c.Assert(err, Equals, mgo.ErrNotFound)311}312func (s *S) TestUpdateId(c *C) {313 session, err := mgo.Dial("localhost:40001")314 c.Assert(err, IsNil)315 defer session.Close()316 coll := session.DB("mydb").C("mycoll")317 ns := []int{40, 41, 42, 43, 44, 45, 46}318 for _, n := range ns {319 err := coll.Insert(M{"_id": n, "n": n})320 c.Assert(err, IsNil)321 }322 err = coll.UpdateId(42, M{"$inc": M{"n": 1}})323 c.Assert(err, IsNil)324 result := make(M)325 err = coll.FindId(42).One(result)326 c.Assert(err, IsNil)327 c.Assert(result["n"], Equals, 43)328 err = coll.UpdateId(47, M{"k": 47, "n": 47})329 c.Assert(err, Equals, mgo.ErrNotFound)330 err = coll.FindId(47).One(result)331 c.Assert(err, Equals, mgo.ErrNotFound)332}333func (s *S) TestUpdateNil(c *C) {334 session, err := mgo.Dial("localhost:40001")335 c.Assert(err, IsNil)336 defer session.Close()337 coll := session.DB("mydb").C("mycoll")338 err = coll.Insert(M{"k": 42, "n": 42})339 c.Assert(err, IsNil)340 err = coll.Update(nil, M{"$inc": M{"n": 1}})341 c.Assert(err, IsNil)342 result := make(M)343 err = coll.Find(M{"k": 42}).One(result)344 c.Assert(err, IsNil)345 c.Assert(result["n"], Equals, 43)346 err = coll.Insert(M{"k": 45, "n": 45})347 c.Assert(err, IsNil)348 _, err = coll.UpdateAll(nil, M{"$inc": M{"n": 1}})349 c.Assert(err, IsNil)350 err = coll.Find(M{"k": 42}).One(result)351 c.Assert(err, IsNil)352 c.Assert(result["n"], Equals, 44)353 err = coll.Find(M{"k": 45}).One(result)354 c.Assert(err, IsNil)355 c.Assert(result["n"], Equals, 46)356}357func (s *S) TestUpsert(c *C) {358 session, err := mgo.Dial("localhost:40001")359 c.Assert(err, IsNil)360 defer session.Close()361 coll := session.DB("mydb").C("mycoll")362 ns := []int{40, 41, 42, 43, 44, 45, 46}363 for _, n := range ns {364 err := coll.Insert(bson.D{{"k", n}, {"n", n}})365 c.Assert(err, IsNil)366 }367 info, err := coll.Upsert(M{"k": 42}, bson.D{{"k", 42}, {"n", 24}})368 c.Assert(err, IsNil)369 c.Assert(info.Updated, Equals, 1)370 c.Assert(info.Matched, Equals, 1)371 c.Assert(info.UpsertedId, IsNil)372 result := M{}373 err = coll.Find(M{"k": 42}).One(result)374 c.Assert(err, IsNil)375 c.Assert(result["n"], Equals, 24)376 // Match but do not change.377 info, err = coll.Upsert(M{"k": 42}, bson.D{{"k", 42}, {"n", 24}})378 c.Assert(err, IsNil)379 c.Assert(info.Updated, Equals, 1) // On 2.6+ this feels like a server mistake.380 c.Assert(info.Matched, Equals, 1)381 c.Assert(info.UpsertedId, IsNil)382 // Insert with internally created id.383 info, err = coll.Upsert(M{"k": 47}, M{"k": 47, "n": 47})384 c.Assert(err, IsNil)385 c.Assert(info.Updated, Equals, 0)386 c.Assert(info.Matched, Equals, 0)387 c.Assert(info.UpsertedId, NotNil)388 err = coll.Find(M{"k": 47}).One(result)389 c.Assert(err, IsNil)390 c.Assert(result["n"], Equals, 47)391 result = M{}392 err = coll.Find(M{"_id": info.UpsertedId}).One(result)393 c.Assert(err, IsNil)394 c.Assert(result["n"], Equals, 47)395 // Insert with provided id.396 info, err = coll.Upsert(M{"k": 48}, M{"k": 48, "n": 48, "_id": 48})397 c.Assert(err, IsNil)398 c.Assert(info.Updated, Equals, 0)399 c.Assert(info.Matched, Equals, 0)400 if s.versionAtLeast(2, 6) {401 c.Assert(info.UpsertedId, Equals, 48)402 } else {403 c.Assert(info.UpsertedId, IsNil) // Unfortunate, but that's what Mongo gave us.404 }405 err = coll.Find(M{"k": 48}).One(result)406 c.Assert(err, IsNil)407 c.Assert(result["n"], Equals, 48)408}409func (s *S) TestUpsertId(c *C) {410 session, err := mgo.Dial("localhost:40001")411 c.Assert(err, IsNil)412 defer session.Close()413 coll := session.DB("mydb").C("mycoll")414 ns := []int{40, 41, 42, 43, 44, 45, 46}415 for _, n := range ns {416 err := coll.Insert(M{"_id": n, "n": n})417 c.Assert(err, IsNil)418 }419 info, err := coll.UpsertId(42, M{"n": 24})420 c.Assert(err, IsNil)421 c.Assert(info.Updated, Equals, 1)422 c.Assert(info.UpsertedId, IsNil)423 result := M{}424 err = coll.FindId(42).One(result)425 c.Assert(err, IsNil)426 c.Assert(result["n"], Equals, 24)427 info, err = coll.UpsertId(47, M{"_id": 47, "n": 47})428 c.Assert(err, IsNil)429 c.Assert(info.Updated, Equals, 0)430 if s.versionAtLeast(2, 6) {431 c.Assert(info.UpsertedId, Equals, 47)432 } else {433 c.Assert(info.UpsertedId, IsNil)434 }435 err = coll.FindId(47).One(result)436 c.Assert(err, IsNil)437 c.Assert(result["n"], Equals, 47)438}439func (s *S) TestUpdateAll(c *C) {440 session, err := mgo.Dial("localhost:40001")441 c.Assert(err, IsNil)442 defer session.Close()443 coll := session.DB("mydb").C("mycoll")444 ns := []int{40, 41, 42, 43, 44, 45, 46}445 for _, n := range ns {446 err := coll.Insert(M{"k": n, "n": n})447 c.Assert(err, IsNil)448 }449 info, err := coll.UpdateAll(M{"k": M{"$gt": 42}}, M{"$unset": M{"missing": 1}})450 c.Assert(err, IsNil)451 if s.versionAtLeast(2, 6) {452 c.Assert(info.Updated, Equals, 0)453 c.Assert(info.Matched, Equals, 4)454 } else {455 c.Assert(info.Updated, Equals, 4)456 c.Assert(info.Matched, Equals, 4)457 }458 info, err = coll.UpdateAll(M{"k": M{"$gt": 42}}, M{"$inc": M{"n": 1}})459 c.Assert(err, IsNil)460 c.Assert(info.Updated, Equals, 4)461 c.Assert(info.Matched, Equals, 4)462 result := make(M)463 err = coll.Find(M{"k": 42}).One(result)464 c.Assert(err, IsNil)465 c.Assert(result["n"], Equals, 42)466 err = coll.Find(M{"k": 43}).One(result)467 c.Assert(err, IsNil)468 c.Assert(result["n"], Equals, 44)469 err = coll.Find(M{"k": 44}).One(result)470 c.Assert(err, IsNil)471 c.Assert(result["n"], Equals, 45)472 if !s.versionAtLeast(2, 6) {473 // 2.6 made this invalid.474 info, err = coll.UpdateAll(M{"k": 47}, M{"k": 47, "n": 47})475 c.Assert(err, Equals, nil)476 c.Assert(info.Updated, Equals, 0)477 }478}479func (s *S) TestRemove(c *C) {480 session, err := mgo.Dial("localhost:40001")481 c.Assert(err, IsNil)482 defer session.Close()483 coll := session.DB("mydb").C("mycoll")484 ns := []int{40, 41, 42, 43, 44, 45, 46}485 for _, n := range ns {486 err := coll.Insert(M{"n": n})487 c.Assert(err, IsNil)488 }489 err = coll.Remove(M{"n": M{"$gt": 42}})490 c.Assert(err, IsNil)491 result := &struct{ N int }{}492 err = coll.Find(M{"n": 42}).One(result)493 c.Assert(err, IsNil)494 c.Assert(result.N, Equals, 42)495 err = coll.Find(M{"n": 43}).One(result)496 c.Assert(err, Equals, mgo.ErrNotFound)497 err = coll.Find(M{"n": 44}).One(result)498 c.Assert(err, IsNil)499 c.Assert(result.N, Equals, 44)500}501func (s *S) TestRemoveId(c *C) {502 session, err := mgo.Dial("localhost:40001")503 c.Assert(err, IsNil)504 defer session.Close()505 coll := session.DB("mydb").C("mycoll")506 err = coll.Insert(M{"_id": 40}, M{"_id": 41}, M{"_id": 42})507 c.Assert(err, IsNil)508 err = coll.RemoveId(41)509 c.Assert(err, IsNil)510 c.Assert(coll.FindId(40).One(nil), IsNil)511 c.Assert(coll.FindId(41).One(nil), Equals, mgo.ErrNotFound)512 c.Assert(coll.FindId(42).One(nil), IsNil)513}514func (s *S) TestRemoveUnsafe(c *C) {515 session, err := mgo.Dial("localhost:40001")516 c.Assert(err, IsNil)517 defer session.Close()518 session.SetSafe(nil)519 coll := session.DB("mydb").C("mycoll")520 err = coll.Insert(M{"_id": 40}, M{"_id": 41}, M{"_id": 42})521 c.Assert(err, IsNil)522 err = coll.RemoveId(41)523 c.Assert(err, IsNil)524 c.Assert(coll.FindId(40).One(nil), IsNil)525 c.Assert(coll.FindId(41).One(nil), Equals, mgo.ErrNotFound)526 c.Assert(coll.FindId(42).One(nil), IsNil)527}528func (s *S) TestRemoveAll(c *C) {529 session, err := mgo.Dial("localhost:40001")530 c.Assert(err, IsNil)531 defer session.Close()532 coll := session.DB("mydb").C("mycoll")533 ns := []int{40, 41, 42, 43, 44, 45, 46}534 for _, n := range ns {535 err := coll.Insert(M{"n": n})536 c.Assert(err, IsNil)537 }538 info, err := coll.RemoveAll(M{"n": M{"$gt": 42}})539 c.Assert(err, IsNil)540 c.Assert(info.Updated, Equals, 0)541 c.Assert(info.Removed, Equals, 4)542 c.Assert(info.Matched, Equals, 4)543 c.Assert(info.UpsertedId, IsNil)544 result := &struct{ N int }{}545 err = coll.Find(M{"n": 42}).One(result)546 c.Assert(err, IsNil)547 c.Assert(result.N, Equals, 42)548 err = coll.Find(M{"n": 43}).One(result)549 c.Assert(err, Equals, mgo.ErrNotFound)550 err = coll.Find(M{"n": 44}).One(result)551 c.Assert(err, Equals, mgo.ErrNotFound)552 info, err = coll.RemoveAll(nil)553 c.Assert(err, IsNil)554 c.Assert(info.Updated, Equals, 0)555 c.Assert(info.Removed, Equals, 3)556 c.Assert(info.Matched, Equals, 3)557 c.Assert(info.UpsertedId, IsNil)558 n, err := coll.Find(nil).Count()559 c.Assert(err, IsNil)560 c.Assert(n, Equals, 0)561}562func (s *S) TestDropDatabase(c *C) {563 session, err := mgo.Dial("localhost:40001")564 c.Assert(err, IsNil)565 defer session.Close()566 db1 := session.DB("db1")567 db1.C("col").Insert(M{"_id": 1})568 db2 := session.DB("db2")569 db2.C("col").Insert(M{"_id": 1})570 err = db1.DropDatabase()571 c.Assert(err, IsNil)572 names, err := session.DatabaseNames()573 c.Assert(err, IsNil)574 c.Assert(filterDBs(names), DeepEquals, []string{"db2"})575 err = db2.DropDatabase()576 c.Assert(err, IsNil)577 names, err = session.DatabaseNames()578 c.Assert(err, IsNil)579 c.Assert(filterDBs(names), DeepEquals, []string{})580}581func filterDBs(dbs []string) []string {582 var i int583 for _, name := range dbs {584 switch name {585 case "admin", "local":586 default:587 dbs[i] = name588 i++589 }590 }591 if len(dbs) == 0 {592 return []string{}593 }594 return dbs[:i]595}596func (s *S) TestDropCollection(c *C) {597 session, err := mgo.Dial("localhost:40001")598 c.Assert(err, IsNil)599 defer session.Close()600 db := session.DB("db1")601 db.C("col1").Insert(M{"_id": 1})602 db.C("col2").Insert(M{"_id": 1})603 err = db.C("col1").DropCollection()604 c.Assert(err, IsNil)605 names, err := db.CollectionNames()606 c.Assert(err, IsNil)607 c.Assert(names, DeepEquals, []string{"col2", "system.indexes"})608 err = db.C("col2").DropCollection()609 c.Assert(err, IsNil)610 names, err = db.CollectionNames()611 c.Assert(err, IsNil)612 c.Assert(names, DeepEquals, []string{"system.indexes"})613}614func (s *S) TestCreateCollectionCapped(c *C) {615 session, err := mgo.Dial("localhost:40001")616 c.Assert(err, IsNil)617 defer session.Close()618 coll := session.DB("mydb").C("mycoll")619 info := &mgo.CollectionInfo{620 Capped: true,621 MaxBytes: 1024,622 MaxDocs: 3,623 }624 err = coll.Create(info)625 c.Assert(err, IsNil)626 ns := []int{1, 2, 3, 4, 5}627 for _, n := range ns {628 err := coll.Insert(M{"n": n})629 c.Assert(err, IsNil)630 }631 n, err := coll.Find(nil).Count()632 c.Assert(err, IsNil)633 c.Assert(n, Equals, 3)634}635func (s *S) TestCreateCollectionNoIndex(c *C) {636 session, err := mgo.Dial("localhost:40001")637 c.Assert(err, IsNil)638 defer session.Close()639 coll := session.DB("mydb").C("mycoll")640 info := &mgo.CollectionInfo{641 DisableIdIndex: true,642 }643 err = coll.Create(info)644 c.Assert(err, IsNil)645 err = coll.Insert(M{"n": 1})646 c.Assert(err, IsNil)647 indexes, err := coll.Indexes()648 c.Assert(indexes, HasLen, 0)649}650func (s *S) TestCreateCollectionForceIndex(c *C) {651 session, err := mgo.Dial("localhost:40001")652 c.Assert(err, IsNil)653 defer session.Close()654 coll := session.DB("mydb").C("mycoll")655 info := &mgo.CollectionInfo{656 ForceIdIndex: true,657 Capped: true,658 MaxBytes: 1024,659 }660 err = coll.Create(info)661 c.Assert(err, IsNil)662 err = coll.Insert(M{"n": 1})663 c.Assert(err, IsNil)664 indexes, err := coll.Indexes()665 c.Assert(indexes, HasLen, 1)666}667func (s *S) TestCreateCollectionValidator(c *C) {668 if !s.versionAtLeast(3, 2) {669 c.Skip("validation depends on MongoDB 3.2+")670 }671 session, err := mgo.Dial("localhost:40001")672 c.Assert(err, IsNil)673 defer session.Close()674 db := session.DB("mydb")675 coll := db.C("mycoll")676 // Test Validator.677 info := &mgo.CollectionInfo{678 Validator: M{"b": M{"$exists": true}},679 }680 err = coll.Create(info)681 c.Assert(err, IsNil)682 err = coll.Insert(M{"a": 1})683 c.Assert(err, ErrorMatches, "Document failed validation")684 err = coll.DropCollection()685 c.Assert(err, IsNil)686 // Test ValidatorAction.687 info = &mgo.CollectionInfo{688 Validator: M{"b": M{"$exists": true}},689 ValidationAction: "warn",690 }691 err = coll.Create(info)692 c.Assert(err, IsNil)693 err = coll.Insert(M{"a": 1})694 c.Assert(err, IsNil)695 err = coll.DropCollection()696 c.Assert(err, IsNil)697 // Test ValidationLevel.698 info = &mgo.CollectionInfo{699 Validator: M{"a": M{"$exists": true}},700 ValidationLevel: "moderate",701 }702 err = coll.Create(info)703 err = coll.Insert(M{"a": 1})704 c.Assert(err, IsNil)705 err = db.Run(bson.D{{"collMod", "mycoll"}, {"validator", M{"b": M{"$exists": true}}}}, nil)706 c.Assert(err, IsNil)707 err = coll.Insert(M{"a": 2})708 c.Assert(err, ErrorMatches, "Document failed validation")709 err = coll.Update(M{"a": 1}, M{"c": 1})710 c.Assert(err, IsNil)711 err = coll.DropCollection()712 c.Assert(err, IsNil)713}714func (s *S) TestCreateCollectionStorageEngine(c *C) {715 if !s.versionAtLeast(3, 0) {716 c.Skip("storageEngine option depends on MongoDB 3.0+")717 }718 session, err := mgo.Dial("localhost:40001")719 c.Assert(err, IsNil)720 defer session.Close()721 db := session.DB("mydb")722 coll := db.C("mycoll")723 info := &mgo.CollectionInfo{724 StorageEngine: M{"test": M{}},725 }726 err = coll.Create(info)727 c.Assert(err, ErrorMatches, "test is not a registered storage engine for this server")728}729func (s *S) TestIsDupValues(c *C) {730 c.Assert(mgo.IsDup(nil), Equals, false)731 c.Assert(mgo.IsDup(&mgo.LastError{Code: 1}), Equals, false)732 c.Assert(mgo.IsDup(&mgo.QueryError{Code: 1}), Equals, false)733 c.Assert(mgo.IsDup(&mgo.LastError{Code: 11000}), Equals, true)734 c.Assert(mgo.IsDup(&mgo.QueryError{Code: 11000}), Equals, true)735 c.Assert(mgo.IsDup(&mgo.LastError{Code: 11001}), Equals, true)736 c.Assert(mgo.IsDup(&mgo.QueryError{Code: 11001}), Equals, true)737 c.Assert(mgo.IsDup(&mgo.LastError{Code: 12582}), Equals, true)738 c.Assert(mgo.IsDup(&mgo.QueryError{Code: 12582}), Equals, true)739 lerr := &mgo.LastError{Code: 16460, Err: "error inserting 1 documents to shard ... caused by :: E11000 duplicate key error index: ..."}740 c.Assert(mgo.IsDup(lerr), Equals, true)741}742func (s *S) TestIsDupPrimary(c *C) {743 session, err := mgo.Dial("localhost:40001")744 c.Assert(err, IsNil)745 defer session.Close()746 coll := session.DB("mydb").C("mycoll")747 err = coll.Insert(M{"_id": 1})748 c.Assert(err, IsNil)749 err = coll.Insert(M{"_id": 1})750 c.Assert(err, ErrorMatches, ".*duplicate key error.*")751 c.Assert(mgo.IsDup(err), Equals, true)752}753func (s *S) TestIsDupUnique(c *C) {754 session, err := mgo.Dial("localhost:40001")755 c.Assert(err, IsNil)756 defer session.Close()757 index := mgo.Index{758 Key: []string{"a", "b"},759 Unique: true,760 }761 coll := session.DB("mydb").C("mycoll")762 err = coll.EnsureIndex(index)763 c.Assert(err, IsNil)764 err = coll.Insert(M{"a": 1, "b": 1})765 c.Assert(err, IsNil)766 err = coll.Insert(M{"a": 1, "b": 1})767 c.Assert(err, ErrorMatches, ".*duplicate key error.*")768 c.Assert(mgo.IsDup(err), Equals, true)769}770func (s *S) TestIsDupCapped(c *C) {771 session, err := mgo.Dial("localhost:40001")772 c.Assert(err, IsNil)773 defer session.Close()774 coll := session.DB("mydb").C("mycoll")775 info := &mgo.CollectionInfo{776 ForceIdIndex: true,777 Capped: true,778 MaxBytes: 1024,779 }780 err = coll.Create(info)781 c.Assert(err, IsNil)782 err = coll.Insert(M{"_id": 1})783 c.Assert(err, IsNil)784 err = coll.Insert(M{"_id": 1})785 // The error was different for capped collections before 2.6.786 c.Assert(err, ErrorMatches, ".*duplicate key.*")787 // The issue is reduced by using IsDup.788 c.Assert(mgo.IsDup(err), Equals, true)789}790func (s *S) TestIsDupFindAndModify(c *C) {791 session, err := mgo.Dial("localhost:40001")792 c.Assert(err, IsNil)793 defer session.Close()794 coll := session.DB("mydb").C("mycoll")795 err = coll.EnsureIndex(mgo.Index{Key: []string{"n"}, Unique: true})796 c.Assert(err, IsNil)797 err = coll.Insert(M{"n": 1})798 c.Assert(err, IsNil)799 err = coll.Insert(M{"n": 2})800 c.Assert(err, IsNil)801 _, err = coll.Find(M{"n": 1}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, bson.M{})802 c.Assert(err, ErrorMatches, ".*duplicate key error.*")803 c.Assert(mgo.IsDup(err), Equals, true)804}805func (s *S) TestIsDupRetryUpsert(c *C) {806 session, err := mgo.Dial("localhost:40001")807 c.Assert(err, IsNil)808 defer session.Close()809 coll := session.DB("mydb").C("mycoll")810 err = coll.Insert(bson.M{"_id": 1, "x": 1})811 c.Assert(err, IsNil)812 _, err = coll.Upsert(bson.M{"_id": 1, "x": 2}, bson.M{"$set": bson.M{"x": 3}})813 c.Assert(mgo.IsDup(err), Equals, true)814 _, err = coll.Find(bson.M{"_id": 1, "x": 2}).Apply(mgo.Change{815 Update: bson.M{"$set": bson.M{"x": 3}},816 Upsert: true,817 }, nil)818 c.Assert(mgo.IsDup(err), Equals, true)819}820func (s *S) TestFindAndModify(c *C) {821 session, err := mgo.Dial("localhost:40011")822 c.Assert(err, IsNil)823 defer session.Close()824 coll := session.DB("mydb").C("mycoll")825 err = coll.Insert(M{"n": 42})826 session.SetMode(mgo.Monotonic, true)827 result := M{}828 info, err := coll.Find(M{"n": 42}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, result)829 c.Assert(err, IsNil)830 c.Assert(result["n"], Equals, 42)831 c.Assert(info.Updated, Equals, 1)832 c.Assert(info.Matched, Equals, 1)833 c.Assert(info.Removed, Equals, 0)834 c.Assert(info.UpsertedId, IsNil)835 // A nil result parameter should be acceptable.836 info, err = coll.Find(M{"n": 43}).Apply(mgo.Change{Update: M{"$unset": M{"missing": 1}}}, nil)837 c.Assert(err, IsNil)838 c.Assert(info.Updated, Equals, 1) // On 2.6+ this feels like a server mistake.839 c.Assert(info.Matched, Equals, 1)840 c.Assert(info.Removed, Equals, 0)841 c.Assert(info.UpsertedId, IsNil)842 result = M{}843 info, err = coll.Find(M{"n": 43}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}, ReturnNew: true}, result)844 c.Assert(err, IsNil)845 c.Assert(result["n"], Equals, 44)846 c.Assert(info.Updated, Equals, 1)847 c.Assert(info.Removed, Equals, 0)848 c.Assert(info.UpsertedId, IsNil)849 result = M{}850 info, err = coll.Find(M{"n": 50}).Apply(mgo.Change{Upsert: true, Update: M{"n": 51, "o": 52}}, result)851 c.Assert(err, IsNil)852 c.Assert(result["n"], IsNil)853 c.Assert(info.Updated, Equals, 0)854 c.Assert(info.Removed, Equals, 0)855 c.Assert(info.UpsertedId, NotNil)856 result = M{}857 info, err = coll.Find(nil).Sort("-n").Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}, ReturnNew: true}, result)858 c.Assert(err, IsNil)859 c.Assert(result["n"], Equals, 52)860 c.Assert(info.Updated, Equals, 1)861 c.Assert(info.Removed, Equals, 0)862 c.Assert(info.UpsertedId, IsNil)863 result = M{}864 info, err = coll.Find(M{"n": 52}).Select(M{"o": 1}).Apply(mgo.Change{Remove: true}, result)865 c.Assert(err, IsNil)866 c.Assert(result["n"], IsNil)867 c.Assert(result["o"], Equals, 52)868 c.Assert(info.Updated, Equals, 0)869 c.Assert(info.Removed, Equals, 1)870 c.Assert(info.UpsertedId, IsNil)871 result = M{}872 info, err = coll.Find(M{"n": 60}).Apply(mgo.Change{Remove: true}, result)873 c.Assert(err, Equals, mgo.ErrNotFound)874 c.Assert(len(result), Equals, 0)875 c.Assert(info, IsNil)876}877func (s *S) TestFindAndModifyBug997828(c *C) {878 session, err := mgo.Dial("localhost:40001")879 c.Assert(err, IsNil)880 defer session.Close()881 coll := session.DB("mydb").C("mycoll")882 err = coll.Insert(M{"n": "not-a-number"})883 result := make(M)884 _, err = coll.Find(M{"n": "not-a-number"}).Apply(mgo.Change{Update: M{"$inc": M{"n": 1}}}, result)885 c.Assert(err, ErrorMatches, `(exception: )?Cannot apply \$inc .*`)886 if s.versionAtLeast(2, 1) {887 qerr, _ := err.(*mgo.QueryError)888 c.Assert(qerr, NotNil, Commentf("err: %#v", err))889 if s.versionAtLeast(2, 6) {890 // Oh, the dance of error codes. :-(891 c.Assert(qerr.Code, Equals, 16837)892 } else {893 c.Assert(qerr.Code, Equals, 10140)894 }895 } else {896 lerr, _ := err.(*mgo.LastError)897 c.Assert(lerr, NotNil, Commentf("err: %#v", err))898 c.Assert(lerr.Code, Equals, 10140)899 }900}901func (s *S) TestFindAndModifyErrmsgDoc(c *C) {902 session, err := mgo.Dial("localhost:40001")903 c.Assert(err, IsNil)904 defer session.Close()905 coll := session.DB("mydb").C("mycoll")906 err = coll.Insert(M{"errmsg": "an error"})907 var result M908 _, err = coll.Find(M{}).Apply(mgo.Change{Update: M{"$set": M{"n": 1}}}, &result)909 c.Assert(err, IsNil)910}911func (s *S) TestCountCollection(c *C) {912 session, err := mgo.Dial("localhost:40001")913 c.Assert(err, IsNil)914 defer session.Close()915 coll := session.DB("mydb").C("mycoll")916 ns := []int{40, 41, 42}917 for _, n := range ns {918 err := coll.Insert(M{"n": n})919 c.Assert(err, IsNil)920 }921 n, err := coll.Count()922 c.Assert(err, IsNil)923 c.Assert(n, Equals, 3)924}925func (s *S) TestCountQuery(c *C) {926 session, err := mgo.Dial("localhost:40001")927 c.Assert(err, IsNil)928 defer session.Close()929 coll := session.DB("mydb").C("mycoll")930 ns := []int{40, 41, 42}931 for _, n := range ns {932 err := coll.Insert(M{"n": n})933 c.Assert(err, IsNil)934 }935 n, err := coll.Find(M{"n": M{"$gt": 40}}).Count()936 c.Assert(err, IsNil)937 c.Assert(n, Equals, 2)938}939func (s *S) TestCountQuerySorted(c *C) {940 session, err := mgo.Dial("localhost:40001")941 c.Assert(err, IsNil)942 defer session.Close()943 coll := session.DB("mydb").C("mycoll")944 ns := []int{40, 41, 42}945 for _, n := range ns {946 err := coll.Insert(M{"n": n})947 c.Assert(err, IsNil)948 }949 n, err := coll.Find(M{"n": M{"$gt": 40}}).Sort("n").Count()950 c.Assert(err, IsNil)951 c.Assert(n, Equals, 2)952}953func (s *S) TestCountSkipLimit(c *C) {954 session, err := mgo.Dial("localhost:40001")955 c.Assert(err, IsNil)956 defer session.Close()957 coll := session.DB("mydb").C("mycoll")958 ns := []int{40, 41, 42, 43, 44}959 for _, n := range ns {960 err := coll.Insert(M{"n": n})961 c.Assert(err, IsNil)962 }963 n, err := coll.Find(nil).Skip(1).Limit(3).Count()964 c.Assert(err, IsNil)965 c.Assert(n, Equals, 3)966 n, err = coll.Find(nil).Skip(1).Limit(5).Count()967 c.Assert(err, IsNil)968 c.Assert(n, Equals, 4)969}970func (s *S) TestQueryExplain(c *C) {971 session, err := mgo.Dial("localhost:40001")972 c.Assert(err, IsNil)973 defer session.Close()974 coll := session.DB("mydb").C("mycoll")975 ns := []int{40, 41, 42}976 for _, n := range ns {977 err := coll.Insert(M{"n": n})978 c.Assert(err, IsNil)979 }980 m := M{}981 query := coll.Find(nil).Limit(2)982 err = query.Explain(m)983 c.Assert(err, IsNil)984 if m["queryPlanner"] != nil {985 c.Assert(m["executionStats"].(M)["totalDocsExamined"], Equals, 2)986 } else {987 c.Assert(m["cursor"], Equals, "BasicCursor")988 c.Assert(m["nscanned"], Equals, 2)989 c.Assert(m["n"], Equals, 2)990 }991 n := 0992 var result M993 iter := query.Iter()994 for iter.Next(&result) {995 n++996 }997 c.Assert(iter.Close(), IsNil)998 c.Assert(n, Equals, 2)999}1000func (s *S) TestQuerySetMaxScan(c *C) {1001 session, err := mgo.Dial("localhost:40001")1002 c.Assert(err, IsNil)1003 defer session.Close()1004 coll := session.DB("mydb").C("mycoll")1005 ns := []int{40, 41, 42}1006 for _, n := range ns {1007 err := coll.Insert(M{"n": n})1008 c.Assert(err, IsNil)1009 }1010 query := coll.Find(nil).SetMaxScan(2)1011 var result []M1012 err = query.All(&result)1013 c.Assert(err, IsNil)1014 c.Assert(result, HasLen, 2)1015}1016func (s *S) TestQuerySetMaxTime(c *C) {1017 if !s.versionAtLeast(2, 6) {1018 c.Skip("SetMaxTime only supported in 2.6+")1019 }1020 session, err := mgo.Dial("localhost:40001")1021 c.Assert(err, IsNil)1022 defer session.Close()1023 coll := session.DB("mydb").C("mycoll")1024 for i := 0; i < 1000; i++ {1025 err := coll.Insert(M{"n": i})1026 c.Assert(err, IsNil)1027 }1028 query := coll.Find(nil)1029 query.SetMaxTime(1 * time.Millisecond)1030 query.Batch(2)1031 var result []M1032 err = query.All(&result)1033 c.Assert(err, ErrorMatches, "operation exceeded time limit")1034}1035func (s *S) TestQueryHint(c *C) {1036 session, err := mgo.Dial("localhost:40001")1037 c.Assert(err, IsNil)1038 defer session.Close()1039 coll := session.DB("mydb").C("mycoll")1040 coll.EnsureIndexKey("a")1041 m := M{}1042 err = coll.Find(nil).Hint("a").Explain(m)1043 c.Assert(err, IsNil)1044 if m["queryPlanner"] != nil {1045 m = m["queryPlanner"].(M)1046 m = m["winningPlan"].(M)1047 m = m["inputStage"].(M)1048 c.Assert(m["indexName"], Equals, "a_1")1049 } else {1050 c.Assert(m["indexBounds"], NotNil)1051 c.Assert(m["indexBounds"].(M)["a"], NotNil)1052 }1053}1054func (s *S) TestQueryComment(c *C) {1055 session, err := mgo.Dial("localhost:40001")1056 c.Assert(err, IsNil)1057 defer session.Close()1058 db := session.DB("mydb")1059 coll := db.C("mycoll")1060 err = db.Run(bson.M{"profile": 2}, nil)1061 c.Assert(err, IsNil)1062 ns := []int{40, 41, 42}1063 for _, n := range ns {1064 err := coll.Insert(M{"n": n})1065 c.Assert(err, IsNil)1066 }1067 query := coll.Find(bson.M{"n": 41})1068 query.Comment("some comment")1069 err = query.One(nil)1070 c.Assert(err, IsNil)1071 query = coll.Find(bson.M{"n": 41})1072 query.Comment("another comment")1073 err = query.One(nil)1074 c.Assert(err, IsNil)1075 commentField := "query.$comment"1076 nField := "query.$query.n"1077 if s.versionAtLeast(3, 2) {1078 commentField = "query.comment"1079 nField = "query.filter.n"1080 }1081 n, err := session.DB("mydb").C("system.profile").Find(bson.M{nField: 41, commentField: "some comment"}).Count()1082 c.Assert(err, IsNil)1083 c.Assert(n, Equals, 1)1084}1085func (s *S) TestFindOneNotFound(c *C) {1086 session, err := mgo.Dial("localhost:40001")1087 c.Assert(err, IsNil)1088 defer session.Close()1089 coll := session.DB("mydb").C("mycoll")1090 result := struct{ A, B int }{}1091 err = coll.Find(M{"a": 1}).One(&result)1092 c.Assert(err, Equals, mgo.ErrNotFound)1093 c.Assert(err, ErrorMatches, "not found")1094 c.Assert(err == mgo.ErrNotFound, Equals, true)1095}1096func (s *S) TestFindIterNotFound(c *C) {1097 session, err := mgo.Dial("localhost:40001")1098 c.Assert(err, IsNil)1099 defer session.Close()1100 coll := session.DB("mydb").C("mycoll")1101 result := struct{ A, B int }{}1102 iter := coll.Find(M{"a": 1}).Iter()1103 ok := iter.Next(&result)1104 c.Assert(ok, Equals, false)1105 c.Assert(iter.Err(), IsNil)1106}1107func (s *S) TestFindNil(c *C) {1108 session, err := mgo.Dial("localhost:40001")1109 c.Assert(err, IsNil)1110 defer session.Close()1111 coll := session.DB("mydb").C("mycoll")1112 err = coll.Insert(M{"n": 1})1113 c.Assert(err, IsNil)1114 result := struct{ N int }{}1115 err = coll.Find(nil).One(&result)1116 c.Assert(err, IsNil)1117 c.Assert(result.N, Equals, 1)1118}1119func (s *S) TestFindId(c *C) {1120 session, err := mgo.Dial("localhost:40001")1121 c.Assert(err, IsNil)1122 defer session.Close()1123 coll := session.DB("mydb").C("mycoll")1124 err = coll.Insert(M{"_id": 41, "n": 41})1125 c.Assert(err, IsNil)1126 err = coll.Insert(M{"_id": 42, "n": 42})1127 c.Assert(err, IsNil)1128 result := struct{ N int }{}1129 err = coll.FindId(42).One(&result)1130 c.Assert(err, IsNil)1131 c.Assert(result.N, Equals, 42)1132}1133func (s *S) TestFindIterAll(c *C) {1134 session, err := mgo.Dial("localhost:40001")1135 c.Assert(err, IsNil)1136 defer session.Close()1137 coll := session.DB("mydb").C("mycoll")1138 ns := []int{40, 41, 42, 43, 44, 45, 46}1139 for _, n := range ns {1140 coll.Insert(M{"n": n})1141 }1142 session.Refresh() // Release socket.1143 mgo.ResetStats()1144 iter := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2).Iter()1145 result := struct{ N int }{}1146 for i := 2; i < 7; i++ {1147 ok := iter.Next(&result)1148 c.Assert(ok, Equals, true, Commentf("err=%v", err))1149 c.Assert(result.N, Equals, ns[i])1150 if i == 1 {1151 stats := mgo.GetStats()1152 c.Assert(stats.ReceivedDocs, Equals, 2)1153 }1154 }1155 ok := iter.Next(&result)1156 c.Assert(ok, Equals, false)1157 c.Assert(iter.Close(), IsNil)1158 session.Refresh() // Release socket.1159 stats := mgo.GetStats()1160 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 2*GET_MORE_OP1161 c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs.1162 if s.versionAtLeast(3, 2) {1163 // In 3.2+ responses come in batches inside the op reply docs.1164 c.Assert(stats.ReceivedDocs, Equals, 3)1165 } else {1166 c.Assert(stats.ReceivedDocs, Equals, 5)1167 }1168 c.Assert(stats.SocketsInUse, Equals, 0)1169}1170func (s *S) TestFindIterTwiceWithSameQuery(c *C) {1171 session, err := mgo.Dial("localhost:40001")1172 c.Assert(err, IsNil)1173 defer session.Close()1174 coll := session.DB("mydb").C("mycoll")1175 for i := 40; i != 47; i++ {1176 err := coll.Insert(M{"n": i})1177 c.Assert(err, IsNil)1178 }1179 query := coll.Find(M{}).Sort("n")1180 iter1 := query.Skip(1).Iter()1181 iter2 := query.Skip(2).Iter()1182 var result struct{ N int }1183 ok := iter2.Next(&result)1184 c.Assert(ok, Equals, true)1185 c.Assert(result.N, Equals, 42)1186 ok = iter1.Next(&result)1187 c.Assert(ok, Equals, true)1188 c.Assert(result.N, Equals, 41)1189}1190func (s *S) TestFindIterWithoutResults(c *C) {1191 session, err := mgo.Dial("localhost:40001")1192 c.Assert(err, IsNil)1193 defer session.Close()1194 coll := session.DB("mydb").C("mycoll")1195 coll.Insert(M{"n": 42})1196 iter := coll.Find(M{"n": 0}).Iter()1197 result := struct{ N int }{}1198 ok := iter.Next(&result)1199 c.Assert(ok, Equals, false)1200 c.Assert(iter.Close(), IsNil)1201 c.Assert(result.N, Equals, 0)1202}1203func (s *S) TestFindIterLimit(c *C) {1204 session, err := mgo.Dial("localhost:40001")1205 c.Assert(err, IsNil)1206 defer session.Close()1207 coll := session.DB("mydb").C("mycoll")1208 ns := []int{40, 41, 42, 43, 44, 45, 46}1209 for _, n := range ns {1210 err := coll.Insert(M{"n": n})1211 c.Assert(err, IsNil)1212 }1213 session.Refresh() // Release socket.1214 mgo.ResetStats()1215 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Limit(3)1216 iter := query.Iter()1217 result := struct{ N int }{}1218 for i := 2; i < 5; i++ {1219 ok := iter.Next(&result)1220 c.Assert(ok, Equals, true)1221 c.Assert(result.N, Equals, ns[i])1222 }1223 ok := iter.Next(&result)1224 c.Assert(ok, Equals, false)1225 c.Assert(iter.Close(), IsNil)1226 session.Refresh() // Release socket.1227 stats := mgo.GetStats()1228 if s.versionAtLeast(3, 2) {1229 // Limit works properly in 3.2+, and results are batched in single doc.1230 c.Assert(stats.SentOps, Equals, 1) // 1*QUERY_OP1231 c.Assert(stats.ReceivedOps, Equals, 1) // and its REPLY_OP1232 c.Assert(stats.ReceivedDocs, Equals, 1)1233 } else {1234 c.Assert(stats.SentOps, Equals, 2) // 1*QUERY_OP + 1*KILL_CURSORS_OP1235 c.Assert(stats.ReceivedOps, Equals, 1) // and its REPLY_OP1236 c.Assert(stats.ReceivedDocs, Equals, 3)1237 }1238 c.Assert(stats.SocketsInUse, Equals, 0)1239}1240var cursorTimeout = flag.Bool("cursor-timeout", false, "Enable cursor timeout test")1241func (s *S) TestFindIterCursorTimeout(c *C) {1242 if !*cursorTimeout {1243 c.Skip("-cursor-timeout")1244 }1245 session, err := mgo.Dial("localhost:40001")1246 c.Assert(err, IsNil)1247 defer session.Close()1248 type Doc struct {1249 Id int "_id"1250 }1251 coll := session.DB("test").C("test")1252 coll.Remove(nil)1253 for i := 0; i < 100; i++ {1254 err = coll.Insert(Doc{i})1255 c.Assert(err, IsNil)1256 }1257 session.SetBatch(1)1258 iter := coll.Find(nil).Iter()1259 var doc Doc1260 if !iter.Next(&doc) {1261 c.Fatalf("iterator failed to return any documents")1262 }1263 for i := 10; i > 0; i-- {1264 c.Logf("Sleeping... %d minutes to go...", i)1265 time.Sleep(1*time.Minute + 2*time.Second)1266 }1267 // Drain any existing documents that were fetched.1268 if !iter.Next(&doc) {1269 c.Fatalf("iterator with timed out cursor failed to return previously cached document")1270 }1271 if iter.Next(&doc) {1272 c.Fatalf("timed out cursor returned document")1273 }1274 c.Assert(iter.Err(), Equals, mgo.ErrCursor)1275}1276func (s *S) TestTooManyItemsLimitBug(c *C) {1277 if *fast {1278 c.Skip("-fast")1279 }1280 session, err := mgo.Dial("localhost:40001")1281 c.Assert(err, IsNil)1282 defer session.Close()1283 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))1284 mgo.SetDebug(false)1285 coll := session.DB("mydb").C("mycoll")1286 words := strings.Split("foo bar baz", " ")1287 for i := 0; i < 5; i++ {1288 words = append(words, words...)1289 }1290 doc := bson.D{{"words", words}}1291 inserts := 100001292 limit := 50001293 iters := 01294 c.Assert(inserts > limit, Equals, true)1295 for i := 0; i < inserts; i++ {1296 err := coll.Insert(&doc)1297 c.Assert(err, IsNil)1298 }1299 iter := coll.Find(nil).Limit(limit).Iter()1300 for iter.Next(&doc) {1301 if iters%100 == 0 {1302 c.Logf("Seen %d docments", iters)1303 }1304 iters++1305 }1306 c.Assert(iter.Close(), IsNil)1307 c.Assert(iters, Equals, limit)1308}1309func (s *S) TestBatchSizeZeroGetMore(c *C) {1310 if *fast {1311 c.Skip("-fast")1312 }1313 session, err := mgo.Dial("localhost:40001")1314 c.Assert(err, IsNil)1315 defer session.Close()1316 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))1317 mgo.SetDebug(false)1318 coll := session.DB("mydb").C("mycoll")1319 words := strings.Split("foo bar baz", " ")1320 for i := 0; i < 5; i++ {1321 words = append(words, words...)1322 }1323 doc := bson.D{{"words", words}}1324 inserts := 100001325 iters := 01326 for i := 0; i < inserts; i++ {1327 err := coll.Insert(&doc)1328 c.Assert(err, IsNil)1329 }1330 iter := coll.Find(nil).Iter()1331 for iter.Next(&doc) {1332 if iters%100 == 0 {1333 c.Logf("Seen %d docments", iters)1334 }1335 iters++1336 }1337 c.Assert(iter.Close(), IsNil)1338}1339func serverCursorsOpen(session *mgo.Session) int {1340 var result struct {1341 Cursors struct {1342 TotalOpen int `bson:"totalOpen"`1343 TimedOut int `bson:"timedOut"`1344 }1345 }1346 err := session.Run("serverStatus", &result)1347 if err != nil {1348 panic(err)1349 }1350 return result.Cursors.TotalOpen1351}1352func (s *S) TestFindIterLimitWithMore(c *C) {1353 session, err := mgo.Dial("localhost:40001")1354 c.Assert(err, IsNil)1355 defer session.Close()1356 coll := session.DB("mydb").C("mycoll")1357 // Insane amounts of logging otherwise due to the1358 // amount of data being shuffled.1359 mgo.SetDebug(false)1360 defer mgo.SetDebug(true)1361 // Should amount to more than 4MB bson payload,1362 // the default limit per result chunk.1363 const total = 40961364 var d struct{ A [1024]byte }1365 docs := make([]interface{}, total)1366 for i := 0; i < total; i++ {1367 docs[i] = &d1368 }1369 err = coll.Insert(docs...)1370 c.Assert(err, IsNil)1371 n, err := coll.Count()1372 c.Assert(err, IsNil)1373 c.Assert(n, Equals, total)1374 // First, try restricting to a single chunk with a negative limit.1375 nresults := 01376 iter := coll.Find(nil).Limit(-total).Iter()1377 var discard struct{}1378 for iter.Next(&discard) {1379 nresults++1380 }1381 if nresults < total/2 || nresults >= total {1382 c.Fatalf("Bad result size with negative limit: %d", nresults)1383 }1384 cursorsOpen := serverCursorsOpen(session)1385 // Try again, with a positive limit. Should reach the end now,1386 // using multiple chunks.1387 nresults = 01388 iter = coll.Find(nil).Limit(total).Iter()1389 for iter.Next(&discard) {1390 nresults++1391 }1392 c.Assert(nresults, Equals, total)1393 // Ensure the cursor used is properly killed.1394 c.Assert(serverCursorsOpen(session), Equals, cursorsOpen)1395 // Edge case, -MinInt == -MinInt.1396 nresults = 01397 iter = coll.Find(nil).Limit(math.MinInt32).Iter()1398 for iter.Next(&discard) {1399 nresults++1400 }1401 if nresults < total/2 || nresults >= total {1402 c.Fatalf("Bad result size with MinInt32 limit: %d", nresults)1403 }1404}1405func (s *S) TestFindIterLimitWithBatch(c *C) {1406 session, err := mgo.Dial("localhost:40001")1407 c.Assert(err, IsNil)1408 defer session.Close()1409 coll := session.DB("mydb").C("mycoll")1410 ns := []int{40, 41, 42, 43, 44, 45, 46}1411 for _, n := range ns {1412 coll.Insert(M{"n": n})1413 }1414 // Ping the database to ensure the nonce has been received already.1415 c.Assert(session.Ping(), IsNil)1416 session.Refresh() // Release socket.1417 mgo.ResetStats()1418 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Limit(3).Batch(2)1419 iter := query.Iter()1420 result := struct{ N int }{}1421 for i := 2; i < 5; i++ {1422 ok := iter.Next(&result)1423 c.Assert(ok, Equals, true)1424 c.Assert(result.N, Equals, ns[i])1425 if i == 3 {1426 stats := mgo.GetStats()1427 if s.versionAtLeast(3, 2) {1428 // In 3.2+ responses come in batches inside the op reply docs.1429 c.Assert(stats.ReceivedDocs, Equals, 1)1430 } else {1431 c.Assert(stats.ReceivedDocs, Equals, 2)1432 }1433 }1434 }1435 ok := iter.Next(&result)1436 c.Assert(ok, Equals, false)1437 c.Assert(iter.Close(), IsNil)1438 session.Refresh() // Release socket.1439 stats := mgo.GetStats()1440 if s.versionAtLeast(3, 2) {1441 // In 3.2+ limit works properly even with multiple batches..1442 c.Assert(stats.SentOps, Equals, 2) // 1*QUERY_OP + 1*GET_MORE_OP1443 c.Assert(stats.ReceivedOps, Equals, 2) // and its REPLY_OPs1444 // In 3.2+ responses come in batches inside the op reply docs.1445 c.Assert(stats.ReceivedDocs, Equals, 2)1446 } else {1447 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 1*GET_MORE_OP + 1*KILL_CURSORS_OP1448 c.Assert(stats.ReceivedOps, Equals, 2) // and its REPLY_OPs1449 c.Assert(stats.ReceivedDocs, Equals, 3)1450 }1451 c.Assert(stats.SocketsInUse, Equals, 0)1452}1453func (s *S) TestFindIterSortWithBatch(c *C) {1454 session, err := mgo.Dial("localhost:40001")1455 c.Assert(err, IsNil)1456 defer session.Close()1457 coll := session.DB("mydb").C("mycoll")1458 ns := []int{40, 41, 42, 43, 44, 45, 46}1459 for _, n := range ns {1460 coll.Insert(M{"n": n})1461 }1462 // Without this, the logic above breaks because Mongo refuses to1463 // return a cursor with an in-memory sort.1464 coll.EnsureIndexKey("n")1465 // Ping the database to ensure the nonce has been received already.1466 c.Assert(session.Ping(), IsNil)1467 session.Refresh() // Release socket.1468 mgo.ResetStats()1469 query := coll.Find(M{"n": M{"$lte": 44}}).Sort("-n").Batch(2)1470 iter := query.Iter()1471 ns = []int{46, 45, 44, 43, 42, 41, 40}1472 result := struct{ N int }{}1473 for i := 2; i < len(ns); i++ {1474 c.Logf("i=%d", i)1475 ok := iter.Next(&result)1476 c.Assert(ok, Equals, true)1477 c.Assert(result.N, Equals, ns[i])1478 if i == 3 {1479 stats := mgo.GetStats()1480 if s.versionAtLeast(3, 2) {1481 // Find command in 3.2+ bundles batches in a single document.1482 c.Assert(stats.ReceivedDocs, Equals, 1)1483 } else {1484 c.Assert(stats.ReceivedDocs, Equals, 2)1485 }1486 }1487 }1488 ok := iter.Next(&result)1489 c.Assert(ok, Equals, false)1490 c.Assert(iter.Close(), IsNil)1491 session.Refresh() // Release socket.1492 stats := mgo.GetStats()1493 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 2*GET_MORE_OP1494 c.Assert(stats.ReceivedOps, Equals, 3) // and its REPLY_OPs1495 if s.versionAtLeast(3, 2) {1496 // Find command in 3.2+ bundles batches in a single document.1497 c.Assert(stats.ReceivedDocs, Equals, 3)1498 } else {1499 c.Assert(stats.ReceivedDocs, Equals, 5)1500 }1501 c.Assert(stats.SocketsInUse, Equals, 0)1502}1503// Test tailable cursors in a situation where Next has to sleep to1504// respect the timeout requested on Tail.1505func (s *S) TestFindTailTimeoutWithSleep(c *C) {1506 if *fast {1507 c.Skip("-fast")1508 }1509 session, err := mgo.Dial("localhost:40001")1510 c.Assert(err, IsNil)1511 defer session.Close()1512 cresult := struct{ ErrMsg string }{}1513 db := session.DB("mydb")1514 err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult)1515 c.Assert(err, IsNil)1516 c.Assert(cresult.ErrMsg, Equals, "")1517 coll := db.C("mycoll")1518 ns := []int{40, 41, 42, 43, 44, 45, 46}1519 for _, n := range ns {1520 coll.Insert(M{"n": n})1521 }1522 session.Refresh() // Release socket.1523 mgo.ResetStats()1524 timeout := 5 * time.Second1525 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)1526 iter := query.Tail(timeout)1527 n := len(ns)1528 result := struct{ N int }{}1529 for i := 2; i != n; i++ {1530 ok := iter.Next(&result)1531 c.Assert(ok, Equals, true)1532 c.Assert(iter.Err(), IsNil)1533 c.Assert(iter.Timeout(), Equals, false)1534 c.Assert(result.N, Equals, ns[i])1535 if i == 3 { // The batch boundary.1536 stats := mgo.GetStats()1537 c.Assert(stats.ReceivedDocs, Equals, 2)1538 }1539 }1540 mgo.ResetStats()1541 // The following call to Next will block.1542 done := make(chan bool)1543 defer func() { <-done }()1544 go func() {1545 // The internal AwaitData timing of MongoDB is around 2 seconds,1546 // so this should force mgo to sleep at least once by itself to1547 // respect the requested timeout.1548 c.Logf("[GOROUTINE] Starting and sleeping...")1549 time.Sleep(timeout - 2*time.Second)1550 c.Logf("[GOROUTINE] Woke up...")1551 session := session.New()1552 c.Logf("[GOROUTINE] Session created and will insert...")1553 err := coll.Insert(M{"n": 47})1554 c.Logf("[GOROUTINE] Insert attempted, err=%v...", err)1555 session.Close()1556 c.Logf("[GOROUTINE] Session closed.")1557 c.Check(err, IsNil)1558 done <- true1559 }()1560 c.Log("Will wait for Next with N=47...")1561 ok := iter.Next(&result)1562 c.Log("Next unblocked...")1563 c.Assert(ok, Equals, true)1564 c.Assert(iter.Err(), IsNil)1565 c.Assert(iter.Timeout(), Equals, false)1566 c.Assert(result.N, Equals, 47)1567 c.Log("Got Next with N=47!")1568 c.Log("Will wait for a result which will never come...")1569 started := time.Now()1570 ok = iter.Next(&result)1571 c.Assert(ok, Equals, false)1572 c.Assert(iter.Err(), IsNil)1573 c.Assert(iter.Timeout(), Equals, true)1574 c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)1575 c.Log("Will now reuse the timed out tail cursor...")1576 coll.Insert(M{"n": 48})1577 ok = iter.Next(&result)1578 c.Assert(ok, Equals, true)1579 c.Assert(iter.Close(), IsNil)1580 c.Assert(iter.Timeout(), Equals, false)1581 c.Assert(result.N, Equals, 48)1582}1583// Test tailable cursors in a situation where Next never gets to sleep once1584// to respect the timeout requested on Tail.1585func (s *S) TestFindTailTimeoutNoSleep(c *C) {1586 session, err := mgo.Dial("localhost:40001")1587 c.Assert(err, IsNil)1588 defer session.Close()1589 cresult := struct{ ErrMsg string }{}1590 db := session.DB("mydb")1591 err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult)1592 c.Assert(err, IsNil)1593 c.Assert(cresult.ErrMsg, Equals, "")1594 coll := db.C("mycoll")1595 ns := []int{40, 41, 42, 43, 44, 45, 46}1596 for _, n := range ns {1597 coll.Insert(M{"n": n})1598 }1599 session.Refresh() // Release socket.1600 mgo.ResetStats()1601 timeout := 1 * time.Second1602 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)1603 iter := query.Tail(timeout)1604 n := len(ns)1605 result := struct{ N int }{}1606 for i := 2; i != n; i++ {1607 ok := iter.Next(&result)1608 c.Assert(ok, Equals, true)1609 c.Assert(iter.Err(), IsNil)1610 c.Assert(iter.Timeout(), Equals, false)1611 c.Assert(result.N, Equals, ns[i])1612 if i == 3 { // The batch boundary.1613 stats := mgo.GetStats()1614 c.Assert(stats.ReceivedDocs, Equals, 2)1615 }1616 }1617 // The following call to Next will block.1618 go func() {1619 // The internal AwaitData timing of MongoDB is around 2 seconds,1620 // so this item should arrive within the AwaitData threshold.1621 time.Sleep(500 * time.Millisecond)1622 session := session.New()1623 defer session.Close()1624 coll := session.DB("mydb").C("mycoll")1625 coll.Insert(M{"n": 47})1626 }()1627 c.Log("Will wait for Next with N=47...")1628 ok := iter.Next(&result)1629 c.Assert(ok, Equals, true)1630 c.Assert(iter.Err(), IsNil)1631 c.Assert(iter.Timeout(), Equals, false)1632 c.Assert(result.N, Equals, 47)1633 c.Log("Got Next with N=47!")1634 c.Log("Will wait for a result which will never come...")1635 started := time.Now()1636 ok = iter.Next(&result)1637 c.Assert(ok, Equals, false)1638 c.Assert(iter.Err(), IsNil)1639 c.Assert(iter.Timeout(), Equals, true)1640 c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)1641 c.Log("Will now reuse the timed out tail cursor...")1642 coll.Insert(M{"n": 48})1643 ok = iter.Next(&result)1644 c.Assert(ok, Equals, true)1645 c.Assert(iter.Close(), IsNil)1646 c.Assert(iter.Timeout(), Equals, false)1647 c.Assert(result.N, Equals, 48)1648}1649// Test tailable cursors in a situation where Next never gets to sleep once1650// to respect the timeout requested on Tail.1651func (s *S) TestFindTailNoTimeout(c *C) {1652 if *fast {1653 c.Skip("-fast")1654 }1655 session, err := mgo.Dial("localhost:40001")1656 c.Assert(err, IsNil)1657 defer session.Close()1658 cresult := struct{ ErrMsg string }{}1659 db := session.DB("mydb")1660 err = db.Run(bson.D{{"create", "mycoll"}, {"capped", true}, {"size", 1024}}, &cresult)1661 c.Assert(err, IsNil)1662 c.Assert(cresult.ErrMsg, Equals, "")1663 coll := db.C("mycoll")1664 ns := []int{40, 41, 42, 43, 44, 45, 46}1665 for _, n := range ns {1666 coll.Insert(M{"n": n})1667 }1668 session.Refresh() // Release socket.1669 mgo.ResetStats()1670 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)1671 iter := query.Tail(-1)1672 c.Assert(err, IsNil)1673 n := len(ns)1674 result := struct{ N int }{}1675 for i := 2; i != n; i++ {1676 ok := iter.Next(&result)1677 c.Assert(ok, Equals, true)1678 c.Assert(result.N, Equals, ns[i])1679 if i == 3 { // The batch boundary.1680 stats := mgo.GetStats()1681 c.Assert(stats.ReceivedDocs, Equals, 2)1682 }1683 }1684 mgo.ResetStats()1685 // The following call to Next will block.1686 go func() {1687 time.Sleep(5e8)1688 session := session.New()1689 defer session.Close()1690 coll := session.DB("mydb").C("mycoll")1691 coll.Insert(M{"n": 47})1692 }()1693 c.Log("Will wait for Next with N=47...")1694 ok := iter.Next(&result)1695 c.Assert(ok, Equals, true)1696 c.Assert(iter.Err(), IsNil)1697 c.Assert(iter.Timeout(), Equals, false)1698 c.Assert(result.N, Equals, 47)1699 c.Log("Got Next with N=47!")1700 c.Log("Will wait for a result which will never come...")1701 gotNext := make(chan bool)1702 go func() {1703 ok := iter.Next(&result)1704 gotNext <- ok1705 }()1706 select {1707 case ok := <-gotNext:1708 c.Fatalf("Next returned: %v", ok)1709 case <-time.After(3e9):1710 // Good. Should still be sleeping at that point.1711 }1712 // Closing the session should cause Next to return.1713 session.Close()1714 select {1715 case ok := <-gotNext:1716 c.Assert(ok, Equals, false)1717 c.Assert(iter.Err(), ErrorMatches, "Closed explicitly")1718 c.Assert(iter.Timeout(), Equals, false)1719 case <-time.After(1e9):1720 c.Fatal("Closing the session did not unblock Next")1721 }1722}1723func (s *S) TestIterNextResetsResult(c *C) {1724 session, err := mgo.Dial("localhost:40001")1725 c.Assert(err, IsNil)1726 defer session.Close()1727 coll := session.DB("mydb").C("mycoll")1728 ns := []int{1, 2, 3}1729 for _, n := range ns {1730 coll.Insert(M{"n" + strconv.Itoa(n): n})1731 }1732 query := coll.Find(nil).Sort("$natural")1733 i := 01734 var sresult *struct{ N1, N2, N3 int }1735 iter := query.Iter()1736 for iter.Next(&sresult) {1737 switch i {1738 case 0:1739 c.Assert(sresult.N1, Equals, 1)1740 c.Assert(sresult.N2+sresult.N3, Equals, 0)1741 case 1:1742 c.Assert(sresult.N2, Equals, 2)1743 c.Assert(sresult.N1+sresult.N3, Equals, 0)1744 case 2:1745 c.Assert(sresult.N3, Equals, 3)1746 c.Assert(sresult.N1+sresult.N2, Equals, 0)1747 }1748 i++1749 }1750 c.Assert(iter.Close(), IsNil)1751 i = 01752 var mresult M1753 iter = query.Iter()1754 for iter.Next(&mresult) {1755 delete(mresult, "_id")1756 switch i {1757 case 0:1758 c.Assert(mresult, DeepEquals, M{"n1": 1})1759 case 1:1760 c.Assert(mresult, DeepEquals, M{"n2": 2})1761 case 2:1762 c.Assert(mresult, DeepEquals, M{"n3": 3})1763 }1764 i++1765 }1766 c.Assert(iter.Close(), IsNil)1767 i = 01768 var iresult interface{}1769 iter = query.Iter()1770 for iter.Next(&iresult) {1771 mresult, ok := iresult.(bson.M)1772 c.Assert(ok, Equals, true, Commentf("%#v", iresult))1773 delete(mresult, "_id")1774 switch i {1775 case 0:1776 c.Assert(mresult, DeepEquals, bson.M{"n1": 1})1777 case 1:1778 c.Assert(mresult, DeepEquals, bson.M{"n2": 2})1779 case 2:1780 c.Assert(mresult, DeepEquals, bson.M{"n3": 3})1781 }1782 i++1783 }1784 c.Assert(iter.Close(), IsNil)1785}1786func (s *S) TestFindForOnIter(c *C) {1787 session, err := mgo.Dial("localhost:40001")1788 c.Assert(err, IsNil)1789 defer session.Close()1790 coll := session.DB("mydb").C("mycoll")1791 ns := []int{40, 41, 42, 43, 44, 45, 46}1792 for _, n := range ns {1793 coll.Insert(M{"n": n})1794 }1795 session.Refresh() // Release socket.1796 mgo.ResetStats()1797 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)1798 iter := query.Iter()1799 i := 21800 var result *struct{ N int }1801 err = iter.For(&result, func() error {1802 c.Assert(i < 7, Equals, true)1803 c.Assert(result.N, Equals, ns[i])1804 if i == 1 {1805 stats := mgo.GetStats()1806 if s.versionAtLeast(3, 2) {1807 // Find command in 3.2+ bundles batches in a single document.1808 c.Assert(stats.ReceivedDocs, Equals, 1)1809 } else {1810 c.Assert(stats.ReceivedDocs, Equals, 2)1811 }1812 }1813 i++1814 return nil1815 })1816 c.Assert(err, IsNil)1817 session.Refresh() // Release socket.1818 stats := mgo.GetStats()1819 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 2*GET_MORE_OP1820 c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs.1821 if s.versionAtLeast(3, 2) {1822 // Find command in 3.2+ bundles batches in a single document.1823 c.Assert(stats.ReceivedDocs, Equals, 3)1824 } else {1825 c.Assert(stats.ReceivedDocs, Equals, 5)1826 }1827 c.Assert(stats.SocketsInUse, Equals, 0)1828}1829func (s *S) TestFindFor(c *C) {1830 session, err := mgo.Dial("localhost:40001")1831 c.Assert(err, IsNil)1832 defer session.Close()1833 coll := session.DB("mydb").C("mycoll")1834 ns := []int{40, 41, 42, 43, 44, 45, 46}1835 for _, n := range ns {1836 coll.Insert(M{"n": n})1837 }1838 session.Refresh() // Release socket.1839 mgo.ResetStats()1840 query := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2)1841 i := 21842 var result *struct{ N int }1843 err = query.For(&result, func() error {1844 c.Assert(i < 7, Equals, true)1845 c.Assert(result.N, Equals, ns[i])1846 if i == 1 {1847 stats := mgo.GetStats()1848 c.Assert(stats.ReceivedDocs, Equals, 2)1849 if s.versionAtLeast(3, 2) {1850 // Find command in 3.2+ bundles batches in a single document.1851 c.Assert(stats.ReceivedDocs, Equals, 1)1852 } else {1853 c.Assert(stats.ReceivedDocs, Equals, 2)1854 }1855 }1856 i++1857 return nil1858 })1859 c.Assert(err, IsNil)1860 session.Refresh() // Release socket.1861 stats := mgo.GetStats()1862 c.Assert(stats.SentOps, Equals, 3) // 1*QUERY_OP + 2*GET_MORE_OP1863 c.Assert(stats.ReceivedOps, Equals, 3) // and their REPLY_OPs.1864 if s.versionAtLeast(3, 2) {1865 // Find command in 3.2+ bundles batches in a single document.1866 c.Assert(stats.ReceivedDocs, Equals, 3)1867 } else {1868 c.Assert(stats.ReceivedDocs, Equals, 5)1869 }1870 c.Assert(stats.SocketsInUse, Equals, 0)1871}1872func (s *S) TestFindForStopOnError(c *C) {1873 session, err := mgo.Dial("localhost:40001")1874 c.Assert(err, IsNil)1875 defer session.Close()1876 coll := session.DB("mydb").C("mycoll")1877 ns := []int{40, 41, 42, 43, 44, 45, 46}1878 for _, n := range ns {1879 coll.Insert(M{"n": n})1880 }1881 query := coll.Find(M{"n": M{"$gte": 42}})1882 i := 21883 var result *struct{ N int }1884 err = query.For(&result, func() error {1885 c.Assert(i < 4, Equals, true)1886 c.Assert(result.N, Equals, ns[i])1887 if i == 3 {1888 return fmt.Errorf("stop!")1889 }1890 i++1891 return nil1892 })1893 c.Assert(err, ErrorMatches, "stop!")1894}1895func (s *S) TestFindForResetsResult(c *C) {1896 session, err := mgo.Dial("localhost:40001")1897 c.Assert(err, IsNil)1898 defer session.Close()1899 coll := session.DB("mydb").C("mycoll")1900 ns := []int{1, 2, 3}1901 for _, n := range ns {1902 coll.Insert(M{"n" + strconv.Itoa(n): n})1903 }1904 query := coll.Find(nil).Sort("$natural")1905 i := 01906 var sresult *struct{ N1, N2, N3 int }1907 err = query.For(&sresult, func() error {1908 switch i {1909 case 0:1910 c.Assert(sresult.N1, Equals, 1)1911 c.Assert(sresult.N2+sresult.N3, Equals, 0)1912 case 1:1913 c.Assert(sresult.N2, Equals, 2)1914 c.Assert(sresult.N1+sresult.N3, Equals, 0)1915 case 2:1916 c.Assert(sresult.N3, Equals, 3)1917 c.Assert(sresult.N1+sresult.N2, Equals, 0)1918 }1919 i++1920 return nil1921 })1922 c.Assert(err, IsNil)1923 i = 01924 var mresult M1925 err = query.For(&mresult, func() error {1926 delete(mresult, "_id")1927 switch i {1928 case 0:1929 c.Assert(mresult, DeepEquals, M{"n1": 1})1930 case 1:1931 c.Assert(mresult, DeepEquals, M{"n2": 2})1932 case 2:1933 c.Assert(mresult, DeepEquals, M{"n3": 3})1934 }1935 i++1936 return nil1937 })1938 c.Assert(err, IsNil)1939 i = 01940 var iresult interface{}1941 err = query.For(&iresult, func() error {1942 mresult, ok := iresult.(bson.M)1943 c.Assert(ok, Equals, true, Commentf("%#v", iresult))1944 delete(mresult, "_id")1945 switch i {1946 case 0:1947 c.Assert(mresult, DeepEquals, bson.M{"n1": 1})1948 case 1:1949 c.Assert(mresult, DeepEquals, bson.M{"n2": 2})1950 case 2:1951 c.Assert(mresult, DeepEquals, bson.M{"n3": 3})1952 }1953 i++1954 return nil1955 })1956 c.Assert(err, IsNil)1957}1958func (s *S) TestFindIterSnapshot(c *C) {1959 if s.versionAtLeast(3, 2) {1960 c.Skip("Broken in 3.2: https://jira.mongodb.org/browse/SERVER-21403")1961 }1962 session, err := mgo.Dial("localhost:40001")1963 c.Assert(err, IsNil)1964 defer session.Close()1965 // Insane amounts of logging otherwise due to the1966 // amount of data being shuffled.1967 mgo.SetDebug(false)1968 defer mgo.SetDebug(true)1969 coll := session.DB("mydb").C("mycoll")1970 var a [1024000]byte1971 for n := 0; n < 10; n++ {1972 err := coll.Insert(M{"_id": n, "n": n, "a1": &a})1973 c.Assert(err, IsNil)1974 }1975 query := coll.Find(M{"n": M{"$gt": -1}}).Batch(2).Prefetch(0)1976 query.Snapshot()1977 iter := query.Iter()1978 seen := map[int]bool{}1979 result := struct {1980 Id int "_id"1981 }{}1982 for iter.Next(&result) {1983 if len(seen) == 2 {1984 // Grow all entries so that they have to move.1985 // Backwards so that the order is inverted.1986 for n := 10; n >= 0; n-- {1987 _, err := coll.Upsert(M{"_id": n}, M{"$set": M{"a2": &a}})1988 c.Assert(err, IsNil)1989 }1990 }1991 if seen[result.Id] {1992 c.Fatalf("seen duplicated key: %d", result.Id)1993 }1994 seen[result.Id] = true1995 }1996 c.Assert(iter.Close(), IsNil)1997}1998func (s *S) TestSort(c *C) {1999 session, err := mgo.Dial("localhost:40001")2000 c.Assert(err, IsNil)2001 defer session.Close()2002 coll := session.DB("mydb").C("mycoll")2003 coll.Insert(M{"a": 1, "b": 1})2004 coll.Insert(M{"a": 2, "b": 2})2005 coll.Insert(M{"a": 2, "b": 1})2006 coll.Insert(M{"a": 0, "b": 1})2007 coll.Insert(M{"a": 2, "b": 0})2008 coll.Insert(M{"a": 0, "b": 2})2009 coll.Insert(M{"a": 1, "b": 2})2010 coll.Insert(M{"a": 0, "b": 0})2011 coll.Insert(M{"a": 1, "b": 0})2012 query := coll.Find(M{})2013 query.Sort("-a") // Should be ignored.2014 query.Sort("-b", "a")2015 iter := query.Iter()2016 l := make([]int, 18)2017 r := struct{ A, B int }{}2018 for i := 0; i != len(l); i += 2 {2019 ok := iter.Next(&r)2020 c.Assert(ok, Equals, true)2021 c.Assert(err, IsNil)2022 l[i] = r.A2023 l[i+1] = r.B2024 }2025 c.Assert(l, DeepEquals, []int{0, 2, 1, 2, 2, 2, 0, 1, 1, 1, 2, 1, 0, 0, 1, 0, 2, 0})2026}2027func (s *S) TestSortWithBadArgs(c *C) {2028 session, err := mgo.Dial("localhost:40001")2029 c.Assert(err, IsNil)2030 defer session.Close()2031 coll := session.DB("mydb").C("mycoll")2032 f1 := func() { coll.Find(nil).Sort("") }2033 f2 := func() { coll.Find(nil).Sort("+") }2034 f3 := func() { coll.Find(nil).Sort("foo", "-") }2035 for _, f := range []func(){f1, f2, f3} {2036 c.Assert(f, PanicMatches, "Sort: empty field name")2037 }2038}2039func (s *S) TestSortScoreText(c *C) {2040 session, err := mgo.Dial("localhost:40001")2041 c.Assert(err, IsNil)2042 defer session.Close()2043 if !s.versionAtLeast(2, 4) {2044 c.Skip("Text search depends on 2.4+")2045 }2046 coll := session.DB("mydb").C("mycoll")2047 err = coll.EnsureIndex(mgo.Index{2048 Key: []string{"$text:a", "$text:b"},2049 })2050 msg := "text search not enabled"2051 if err != nil && strings.Contains(err.Error(), msg) {2052 c.Skip(msg)2053 }2054 c.Assert(err, IsNil)2055 err = coll.Insert(M{2056 "a": "none",2057 "b": "twice: foo foo",2058 })2059 c.Assert(err, IsNil)2060 err = coll.Insert(M{2061 "a": "just once: foo",2062 "b": "none",2063 })2064 c.Assert(err, IsNil)2065 err = coll.Insert(M{2066 "a": "many: foo foo foo",2067 "b": "none",2068 })2069 c.Assert(err, IsNil)2070 err = coll.Insert(M{2071 "a": "none",2072 "b": "none",2073 "c": "ignore: foo",2074 })2075 c.Assert(err, IsNil)2076 query := coll.Find(M{"$text": M{"$search": "foo"}})2077 query.Select(M{"score": M{"$meta": "textScore"}})2078 query.Sort("$textScore:score")2079 iter := query.Iter()2080 var r struct{ A, B string }2081 var results []string2082 for iter.Next(&r) {2083 results = append(results, r.A, r.B)2084 }2085 c.Assert(results, DeepEquals, []string{2086 "many: foo foo foo", "none",2087 "none", "twice: foo foo",2088 "just once: foo", "none",2089 })2090}2091func (s *S) TestPrefetching(c *C) {2092 session, err := mgo.Dial("localhost:40001")2093 c.Assert(err, IsNil)2094 defer session.Close()2095 coll := session.DB("mydb").C("mycoll")2096 const total = 6002097 const batch = 1002098 mgo.SetDebug(false)2099 docs := make([]interface{}, total)2100 for i := 0; i != total; i++ {2101 docs[i] = bson.D{{"n", i}}2102 }2103 err = coll.Insert(docs...)2104 c.Assert(err, IsNil)2105 for testi := 0; testi < 5; testi++ {2106 mgo.ResetStats()2107 var iter *mgo.Iter2108 var beforeMore int2109 switch testi {2110 case 0: // The default session value.2111 session.SetBatch(batch)2112 iter = coll.Find(M{}).Iter()2113 beforeMore = 752114 case 2: // Changing the session value.2115 session.SetBatch(batch)2116 session.SetPrefetch(0.27)2117 iter = coll.Find(M{}).Iter()2118 beforeMore = 732119 case 1: // Changing via query methods.2120 iter = coll.Find(M{}).Prefetch(0.27).Batch(batch).Iter()2121 beforeMore = 732122 case 3: // With prefetch on first document.2123 iter = coll.Find(M{}).Prefetch(1.0).Batch(batch).Iter()2124 beforeMore = 02125 case 4: // Without prefetch.2126 iter = coll.Find(M{}).Prefetch(0).Batch(batch).Iter()2127 beforeMore = 1002128 }2129 pings := 02130 for batchi := 0; batchi < len(docs)/batch-1; batchi++ {2131 c.Logf("Iterating over %d documents on batch %d", beforeMore, batchi)2132 var result struct{ N int }2133 for i := 0; i < beforeMore; i++ {2134 ok := iter.Next(&result)2135 c.Assert(ok, Equals, true, Commentf("iter.Err: %v", iter.Err()))2136 }2137 beforeMore = 992138 c.Logf("Done iterating.")2139 session.Run("ping", nil) // Roundtrip to settle down.2140 pings++2141 stats := mgo.GetStats()2142 if s.versionAtLeast(3, 2) {2143 // Find command in 3.2+ bundles batches in a single document.2144 c.Assert(stats.ReceivedDocs, Equals, (batchi+1)+pings)2145 } else {2146 c.Assert(stats.ReceivedDocs, Equals, (batchi+1)*batch+pings)2147 }2148 c.Logf("Iterating over one more document on batch %d", batchi)2149 ok := iter.Next(&result)2150 c.Assert(ok, Equals, true, Commentf("iter.Err: %v", iter.Err()))2151 c.Logf("Done iterating.")2152 session.Run("ping", nil) // Roundtrip to settle down.2153 pings++2154 stats = mgo.GetStats()2155 if s.versionAtLeast(3, 2) {2156 // Find command in 3.2+ bundles batches in a single document.2157 c.Assert(stats.ReceivedDocs, Equals, (batchi+2)+pings)2158 } else {2159 c.Assert(stats.ReceivedDocs, Equals, (batchi+2)*batch+pings)2160 }2161 }2162 }2163}2164func (s *S) TestSafeSetting(c *C) {2165 session, err := mgo.Dial("localhost:40001")2166 c.Assert(err, IsNil)2167 defer session.Close()2168 // Check the default2169 safe := session.Safe()2170 c.Assert(safe.W, Equals, 0)2171 c.Assert(safe.WMode, Equals, "")2172 c.Assert(safe.WTimeout, Equals, 0)2173 c.Assert(safe.FSync, Equals, false)2174 c.Assert(safe.J, Equals, false)2175 // Tweak it2176 session.SetSafe(&mgo.Safe{W: 1, WTimeout: 2, FSync: true})2177 safe = session.Safe()2178 c.Assert(safe.W, Equals, 1)2179 c.Assert(safe.WMode, Equals, "")2180 c.Assert(safe.WTimeout, Equals, 2)2181 c.Assert(safe.FSync, Equals, true)2182 c.Assert(safe.J, Equals, false)2183 // Reset it again.2184 session.SetSafe(&mgo.Safe{})2185 safe = session.Safe()2186 c.Assert(safe.W, Equals, 0)2187 c.Assert(safe.WMode, Equals, "")2188 c.Assert(safe.WTimeout, Equals, 0)2189 c.Assert(safe.FSync, Equals, false)2190 c.Assert(safe.J, Equals, false)2191 // Ensure safety to something more conservative.2192 session.SetSafe(&mgo.Safe{W: 5, WTimeout: 6, J: true})2193 safe = session.Safe()2194 c.Assert(safe.W, Equals, 5)2195 c.Assert(safe.WMode, Equals, "")2196 c.Assert(safe.WTimeout, Equals, 6)2197 c.Assert(safe.FSync, Equals, false)2198 c.Assert(safe.J, Equals, true)2199 // Ensure safety to something less conservative won't change it.2200 session.EnsureSafe(&mgo.Safe{W: 4, WTimeout: 7})2201 safe = session.Safe()2202 c.Assert(safe.W, Equals, 5)2203 c.Assert(safe.WMode, Equals, "")2204 c.Assert(safe.WTimeout, Equals, 6)2205 c.Assert(safe.FSync, Equals, false)2206 c.Assert(safe.J, Equals, true)2207 // But to something more conservative will.2208 session.EnsureSafe(&mgo.Safe{W: 6, WTimeout: 4, FSync: true})2209 safe = session.Safe()2210 c.Assert(safe.W, Equals, 6)2211 c.Assert(safe.WMode, Equals, "")2212 c.Assert(safe.WTimeout, Equals, 4)2213 c.Assert(safe.FSync, Equals, true)2214 c.Assert(safe.J, Equals, false)2215 // Even more conservative.2216 session.EnsureSafe(&mgo.Safe{WMode: "majority", WTimeout: 2})2217 safe = session.Safe()2218 c.Assert(safe.W, Equals, 0)2219 c.Assert(safe.WMode, Equals, "majority")2220 c.Assert(safe.WTimeout, Equals, 2)2221 c.Assert(safe.FSync, Equals, true)2222 c.Assert(safe.J, Equals, false)2223 // WMode always overrides, whatever it is, but J doesn't.2224 session.EnsureSafe(&mgo.Safe{WMode: "something", J: true})2225 safe = session.Safe()2226 c.Assert(safe.W, Equals, 0)2227 c.Assert(safe.WMode, Equals, "something")2228 c.Assert(safe.WTimeout, Equals, 2)2229 c.Assert(safe.FSync, Equals, true)2230 c.Assert(safe.J, Equals, false)2231 // EnsureSafe with nil does nothing.2232 session.EnsureSafe(nil)2233 safe = session.Safe()2234 c.Assert(safe.W, Equals, 0)2235 c.Assert(safe.WMode, Equals, "something")2236 c.Assert(safe.WTimeout, Equals, 2)2237 c.Assert(safe.FSync, Equals, true)2238 c.Assert(safe.J, Equals, false)2239 // Changing the safety of a cloned session doesn't touch the original.2240 clone := session.Clone()2241 defer clone.Close()2242 clone.EnsureSafe(&mgo.Safe{WMode: "foo"})2243 safe = session.Safe()2244 c.Assert(safe.WMode, Equals, "something")2245}2246func (s *S) TestSafeInsert(c *C) {2247 session, err := mgo.Dial("localhost:40001")2248 c.Assert(err, IsNil)2249 defer session.Close()2250 coll := session.DB("mydb").C("mycoll")2251 // Insert an element with a predefined key.2252 err = coll.Insert(M{"_id": 1})2253 c.Assert(err, IsNil)2254 mgo.ResetStats()2255 // Session should be safe by default, so inserting it again must fail.2256 err = coll.Insert(M{"_id": 1})2257 c.Assert(err, ErrorMatches, ".*E11000 duplicate.*")2258 c.Assert(err.(*mgo.LastError).Code, Equals, 11000)2259 // It must have sent two operations (INSERT_OP + getLastError QUERY_OP)2260 stats := mgo.GetStats()2261 if s.versionAtLeast(2, 6) {2262 c.Assert(stats.SentOps, Equals, 1)2263 } else {2264 c.Assert(stats.SentOps, Equals, 2)2265 }2266 mgo.ResetStats()2267 // If we disable safety, though, it won't complain.2268 session.SetSafe(nil)2269 err = coll.Insert(M{"_id": 1})2270 c.Assert(err, IsNil)2271 // Must have sent a single operation this time (just the INSERT_OP)2272 stats = mgo.GetStats()2273 c.Assert(stats.SentOps, Equals, 1)2274}2275func (s *S) TestSafeParameters(c *C) {2276 session, err := mgo.Dial("localhost:40011")2277 c.Assert(err, IsNil)2278 defer session.Close()2279 coll := session.DB("mydb").C("mycoll")2280 // Tweak the safety parameters to something unachievable.2281 session.SetSafe(&mgo.Safe{W: 4, WTimeout: 100})2282 err = coll.Insert(M{"_id": 1})2283 c.Assert(err, ErrorMatches, "timeout|timed out waiting for slaves|Not enough data-bearing nodes|waiting for replication timed out") // :-(2284 if !s.versionAtLeast(2, 6) {2285 // 2.6 turned it into a query error.2286 c.Assert(err.(*mgo.LastError).WTimeout, Equals, true)2287 }2288}2289func (s *S) TestQueryErrorOne(c *C) {2290 session, err := mgo.Dial("localhost:40001")2291 c.Assert(err, IsNil)2292 defer session.Close()2293 coll := session.DB("mydb").C("mycoll")2294 err = coll.Find(M{"a": 1}).Select(M{"a": M{"b": 1}}).One(nil)2295 c.Assert(err, ErrorMatches, ".*Unsupported projection option:.*")2296 c.Assert(err.(*mgo.QueryError).Message, Matches, ".*Unsupported projection option:.*")2297 // Oh, the dance of error codes. :-(2298 if s.versionAtLeast(3, 2) {2299 c.Assert(err.(*mgo.QueryError).Code, Equals, 2)2300 } else if s.versionAtLeast(2, 6) {2301 c.Assert(err.(*mgo.QueryError).Code, Equals, 17287)2302 } else {2303 c.Assert(err.(*mgo.QueryError).Code, Equals, 13097)2304 }2305}2306func (s *S) TestQueryErrorNext(c *C) {2307 session, err := mgo.Dial("localhost:40001")2308 c.Assert(err, IsNil)2309 defer session.Close()2310 coll := session.DB("mydb").C("mycoll")2311 iter := coll.Find(M{"a": 1}).Select(M{"a": M{"b": 1}}).Iter()2312 var result struct{}2313 ok := iter.Next(&result)2314 c.Assert(ok, Equals, false)2315 err = iter.Close()2316 c.Assert(err, ErrorMatches, ".*Unsupported projection option:.*")2317 c.Assert(err.(*mgo.QueryError).Message, Matches, ".*Unsupported projection option:.*")2318 // Oh, the dance of error codes. :-(2319 if s.versionAtLeast(3, 2) {2320 c.Assert(err.(*mgo.QueryError).Code, Equals, 2)2321 } else if s.versionAtLeast(2, 6) {2322 c.Assert(err.(*mgo.QueryError).Code, Equals, 17287)2323 } else {2324 c.Assert(err.(*mgo.QueryError).Code, Equals, 13097)2325 }2326 c.Assert(iter.Err(), Equals, err)2327}2328var indexTests = []struct {2329 index mgo.Index2330 expected M2331}{{2332 mgo.Index{2333 Key: []string{"a"},2334 Background: true,2335 },2336 M{2337 "name": "a_1",2338 "key": M{"a": 1},2339 "ns": "mydb.mycoll",2340 "background": true,2341 },2342}, {2343 mgo.Index{2344 Key: []string{"a", "-b"},2345 Unique: true,2346 DropDups: true,2347 },2348 M{2349 "name": "a_1_b_-1",2350 "key": M{"a": 1, "b": -1},2351 "ns": "mydb.mycoll",2352 "unique": true,2353 "dropDups": true,2354 },2355}, {2356 mgo.Index{2357 Key: []string{"@loc_old"}, // Obsolete2358 Min: -500,2359 Max: 500,2360 Bits: 32,2361 },2362 M{2363 "name": "loc_old_2d",2364 "key": M{"loc_old": "2d"},2365 "ns": "mydb.mycoll",2366 "min": -500.0,2367 "max": 500.0,2368 "bits": 32,2369 },2370}, {2371 mgo.Index{2372 Key: []string{"$2d:loc"},2373 Min: -500,2374 Max: 500,2375 Bits: 32,2376 },2377 M{2378 "name": "loc_2d",2379 "key": M{"loc": "2d"},2380 "ns": "mydb.mycoll",2381 "min": -500.0,2382 "max": 500.0,2383 "bits": 32,2384 },2385}, {2386 mgo.Index{2387 Key: []string{"$2d:loc"},2388 Minf: -500.1,2389 Maxf: 500.1,2390 Min: 1, // Should be ignored2391 Max: 2,2392 Bits: 32,2393 },2394 M{2395 "name": "loc_2d",2396 "key": M{"loc": "2d"},2397 "ns": "mydb.mycoll",2398 "min": -500.1,2399 "max": 500.1,2400 "bits": 32,2401 },2402}, {2403 mgo.Index{2404 Key: []string{"$geoHaystack:loc", "type"},2405 BucketSize: 1,2406 },2407 M{2408 "name": "loc_geoHaystack_type_1",2409 "key": M{"loc": "geoHaystack", "type": 1},2410 "ns": "mydb.mycoll",2411 "bucketSize": 1.0,2412 },2413}, {2414 mgo.Index{2415 Key: []string{"$text:a", "$text:b"},2416 Weights: map[string]int{"b": 42},2417 },2418 M{2419 "name": "a_text_b_text",2420 "key": M{"_fts": "text", "_ftsx": 1},2421 "ns": "mydb.mycoll",2422 "weights": M{"a": 1, "b": 42},2423 "default_language": "english",2424 "language_override": "language",2425 "textIndexVersion": 2,2426 },2427}, {2428 mgo.Index{2429 Key: []string{"$text:a"},2430 DefaultLanguage: "portuguese",2431 LanguageOverride: "idioma",2432 },2433 M{2434 "name": "a_text",2435 "key": M{"_fts": "text", "_ftsx": 1},2436 "ns": "mydb.mycoll",2437 "weights": M{"a": 1},2438 "default_language": "portuguese",2439 "language_override": "idioma",2440 "textIndexVersion": 2,2441 },2442}, {2443 mgo.Index{2444 Key: []string{"$text:$**"},2445 },2446 M{2447 "name": "$**_text",2448 "key": M{"_fts": "text", "_ftsx": 1},2449 "ns": "mydb.mycoll",2450 "weights": M{"$**": 1},2451 "default_language": "english",2452 "language_override": "language",2453 "textIndexVersion": 2,2454 },2455}, {2456 mgo.Index{2457 Key: []string{"cn"},2458 Name: "CustomName",2459 },2460 M{2461 "name": "CustomName",2462 "key": M{"cn": 1},2463 "ns": "mydb.mycoll",2464 },2465}}2466func (s *S) TestEnsureIndex(c *C) {2467 session, err := mgo.Dial("localhost:40001")2468 c.Assert(err, IsNil)2469 defer session.Close()2470 coll := session.DB("mydb").C("mycoll")2471 idxs := session.DB("mydb").C("system.indexes")2472 for _, test := range indexTests {2473 if !s.versionAtLeast(2, 4) && test.expected["textIndexVersion"] != nil {2474 continue2475 }2476 err = coll.EnsureIndex(test.index)2477 msg := "text search not enabled"2478 if err != nil && strings.Contains(err.Error(), msg) {2479 continue2480 }2481 c.Assert(err, IsNil)2482 expectedName := test.index.Name2483 if expectedName == "" {2484 expectedName, _ = test.expected["name"].(string)2485 }2486 obtained := M{}2487 err = idxs.Find(M{"name": expectedName}).One(obtained)2488 c.Assert(err, IsNil)2489 delete(obtained, "v")2490 if s.versionAtLeast(2, 7) {2491 // Was deprecated in 2.6, and not being reported by 2.7+.2492 delete(test.expected, "dropDups")2493 test.index.DropDups = false2494 }2495 if s.versionAtLeast(3, 2) && test.expected["textIndexVersion"] != nil {2496 test.expected["textIndexVersion"] = 32497 }2498 c.Assert(obtained, DeepEquals, test.expected)2499 // The result of Indexes must match closely what was used to create the index.2500 indexes, err := coll.Indexes()2501 c.Assert(err, IsNil)2502 c.Assert(indexes, HasLen, 2)2503 gotIndex := indexes[0]2504 if gotIndex.Name == "_id_" {2505 gotIndex = indexes[1]2506 }2507 wantIndex := test.index2508 if wantIndex.Name == "" {2509 wantIndex.Name = gotIndex.Name2510 }2511 if strings.HasPrefix(wantIndex.Key[0], "@") {2512 wantIndex.Key[0] = "$2d:" + wantIndex.Key[0][1:]2513 }2514 if wantIndex.Minf == 0 && wantIndex.Maxf == 0 {2515 wantIndex.Minf = float64(wantIndex.Min)2516 wantIndex.Maxf = float64(wantIndex.Max)2517 } else {2518 wantIndex.Min = gotIndex.Min2519 wantIndex.Max = gotIndex.Max2520 }2521 if wantIndex.DefaultLanguage == "" {2522 wantIndex.DefaultLanguage = gotIndex.DefaultLanguage2523 }2524 if wantIndex.LanguageOverride == "" {2525 wantIndex.LanguageOverride = gotIndex.LanguageOverride2526 }2527 for name, _ := range gotIndex.Weights {2528 if _, ok := wantIndex.Weights[name]; !ok {2529 if wantIndex.Weights == nil {2530 wantIndex.Weights = make(map[string]int)2531 }2532 wantIndex.Weights[name] = 12533 }2534 }2535 c.Assert(gotIndex, DeepEquals, wantIndex)2536 // Drop created index by key or by name if a custom name was used.2537 if test.index.Name == "" {2538 err = coll.DropIndex(test.index.Key...)2539 c.Assert(err, IsNil)2540 } else {2541 err = coll.DropIndexName(test.index.Name)2542 c.Assert(err, IsNil)2543 }2544 }2545}2546func (s *S) TestEnsureIndexWithBadInfo(c *C) {2547 session, err := mgo.Dial("localhost:40001")2548 c.Assert(err, IsNil)2549 defer session.Close()2550 coll := session.DB("mydb").C("mycoll")2551 err = coll.EnsureIndex(mgo.Index{})2552 c.Assert(err, ErrorMatches, "invalid index key:.*")2553 err = coll.EnsureIndex(mgo.Index{Key: []string{""}})2554 c.Assert(err, ErrorMatches, "invalid index key:.*")2555}2556func (s *S) TestEnsureIndexWithUnsafeSession(c *C) {2557 session, err := mgo.Dial("localhost:40001")2558 c.Assert(err, IsNil)2559 defer session.Close()2560 session.SetSafe(nil)2561 coll := session.DB("mydb").C("mycoll")2562 err = coll.Insert(M{"a": 1})2563 c.Assert(err, IsNil)2564 err = coll.Insert(M{"a": 1})2565 c.Assert(err, IsNil)2566 // Should fail since there are duplicated entries.2567 index := mgo.Index{2568 Key: []string{"a"},2569 Unique: true,2570 }2571 err = coll.EnsureIndex(index)2572 c.Assert(err, ErrorMatches, ".*duplicate key error.*")2573}2574func (s *S) TestEnsureIndexKey(c *C) {2575 session, err := mgo.Dial("localhost:40001")2576 c.Assert(err, IsNil)2577 defer session.Close()2578 coll := session.DB("mydb").C("mycoll")2579 err = coll.EnsureIndexKey("a")2580 c.Assert(err, IsNil)2581 err = coll.EnsureIndexKey("a", "-b")2582 c.Assert(err, IsNil)2583 sysidx := session.DB("mydb").C("system.indexes")2584 result1 := M{}2585 err = sysidx.Find(M{"name": "a_1"}).One(result1)2586 c.Assert(err, IsNil)2587 result2 := M{}2588 err = sysidx.Find(M{"name": "a_1_b_-1"}).One(result2)2589 c.Assert(err, IsNil)2590 delete(result1, "v")2591 expected1 := M{2592 "name": "a_1",2593 "key": M{"a": 1},2594 "ns": "mydb.mycoll",2595 }2596 c.Assert(result1, DeepEquals, expected1)2597 delete(result2, "v")2598 expected2 := M{2599 "name": "a_1_b_-1",2600 "key": M{"a": 1, "b": -1},2601 "ns": "mydb.mycoll",2602 }2603 c.Assert(result2, DeepEquals, expected2)2604}2605func (s *S) TestEnsureIndexDropIndex(c *C) {2606 session, err := mgo.Dial("localhost:40001")2607 c.Assert(err, IsNil)2608 defer session.Close()2609 coll := session.DB("mydb").C("mycoll")2610 err = coll.EnsureIndexKey("a")2611 c.Assert(err, IsNil)2612 err = coll.EnsureIndexKey("-b")2613 c.Assert(err, IsNil)2614 err = coll.DropIndex("-b")2615 c.Assert(err, IsNil)2616 sysidx := session.DB("mydb").C("system.indexes")2617 err = sysidx.Find(M{"name": "a_1"}).One(nil)2618 c.Assert(err, IsNil)2619 err = sysidx.Find(M{"name": "b_1"}).One(nil)2620 c.Assert(err, Equals, mgo.ErrNotFound)2621 err = coll.DropIndex("a")2622 c.Assert(err, IsNil)2623 err = sysidx.Find(M{"name": "a_1"}).One(nil)2624 c.Assert(err, Equals, mgo.ErrNotFound)2625 err = coll.DropIndex("a")2626 c.Assert(err, ErrorMatches, "index not found.*")2627}2628func (s *S) TestEnsureIndexDropIndexName(c *C) {2629 session, err := mgo.Dial("localhost:40001")2630 c.Assert(err, IsNil)2631 defer session.Close()2632 coll := session.DB("mydb").C("mycoll")2633 err = coll.EnsureIndexKey("a")2634 c.Assert(err, IsNil)2635 err = coll.EnsureIndex(mgo.Index{Key: []string{"b"}, Name: "a"})2636 c.Assert(err, IsNil)2637 err = coll.DropIndexName("a")2638 c.Assert(err, IsNil)2639 sysidx := session.DB("mydb").C("system.indexes")2640 err = sysidx.Find(M{"name": "a_1"}).One(nil)2641 c.Assert(err, IsNil)2642 err = sysidx.Find(M{"name": "a"}).One(nil)2643 c.Assert(err, Equals, mgo.ErrNotFound)2644 err = coll.DropIndexName("a_1")2645 c.Assert(err, IsNil)2646 err = sysidx.Find(M{"name": "a_1"}).One(nil)2647 c.Assert(err, Equals, mgo.ErrNotFound)2648 err = coll.DropIndexName("a_1")2649 c.Assert(err, ErrorMatches, "index not found.*")2650}2651func (s *S) TestEnsureIndexCaching(c *C) {2652 session, err := mgo.Dial("localhost:40001")2653 c.Assert(err, IsNil)2654 defer session.Close()2655 coll := session.DB("mydb").C("mycoll")2656 err = coll.EnsureIndexKey("a")2657 c.Assert(err, IsNil)2658 mgo.ResetStats()2659 // Second EnsureIndex should be cached and do nothing.2660 err = coll.EnsureIndexKey("a")2661 c.Assert(err, IsNil)2662 stats := mgo.GetStats()2663 c.Assert(stats.SentOps, Equals, 0)2664 // Resetting the cache should make it contact the server again.2665 session.ResetIndexCache()2666 err = coll.EnsureIndexKey("a")2667 c.Assert(err, IsNil)2668 stats = mgo.GetStats()2669 c.Assert(stats.SentOps > 0, Equals, true)2670 // Dropping the index should also drop the cached index key.2671 err = coll.DropIndex("a")2672 c.Assert(err, IsNil)2673 mgo.ResetStats()2674 err = coll.EnsureIndexKey("a")2675 c.Assert(err, IsNil)2676 stats = mgo.GetStats()2677 c.Assert(stats.SentOps > 0, Equals, true)2678}2679func (s *S) TestEnsureIndexGetIndexes(c *C) {2680 session, err := mgo.Dial("localhost:40001")2681 c.Assert(err, IsNil)2682 defer session.Close()2683 coll := session.DB("mydb").C("mycoll")2684 err = coll.EnsureIndexKey("-b")2685 c.Assert(err, IsNil)2686 err = coll.EnsureIndexKey("a")2687 c.Assert(err, IsNil)2688 // Obsolete.2689 err = coll.EnsureIndexKey("@c")2690 c.Assert(err, IsNil)2691 err = coll.EnsureIndexKey("$2d:d")2692 c.Assert(err, IsNil)2693 // Try to exercise cursor logic. 2.8.0-rc3 still ignores this.2694 session.SetBatch(2)2695 indexes, err := coll.Indexes()2696 c.Assert(err, IsNil)2697 c.Assert(indexes[0].Name, Equals, "_id_")2698 c.Assert(indexes[1].Name, Equals, "a_1")2699 c.Assert(indexes[1].Key, DeepEquals, []string{"a"})2700 c.Assert(indexes[2].Name, Equals, "b_-1")2701 c.Assert(indexes[2].Key, DeepEquals, []string{"-b"})2702 c.Assert(indexes[3].Name, Equals, "c_2d")2703 c.Assert(indexes[3].Key, DeepEquals, []string{"$2d:c"})2704 c.Assert(indexes[4].Name, Equals, "d_2d")2705 c.Assert(indexes[4].Key, DeepEquals, []string{"$2d:d"})2706}2707func (s *S) TestEnsureIndexNameCaching(c *C) {2708 session, err := mgo.Dial("localhost:40001")2709 c.Assert(err, IsNil)2710 defer session.Close()2711 coll := session.DB("mydb").C("mycoll")2712 err = coll.EnsureIndex(mgo.Index{Key: []string{"a"}, Name: "custom"})2713 c.Assert(err, IsNil)2714 mgo.ResetStats()2715 // Second EnsureIndex should be cached and do nothing.2716 err = coll.EnsureIndexKey("a")2717 c.Assert(err, IsNil)2718 err = coll.EnsureIndex(mgo.Index{Key: []string{"a"}, Name: "custom"})2719 c.Assert(err, IsNil)2720 stats := mgo.GetStats()2721 c.Assert(stats.SentOps, Equals, 0)2722 // Resetting the cache should make it contact the server again.2723 session.ResetIndexCache()2724 err = coll.EnsureIndex(mgo.Index{Key: []string{"a"}, Name: "custom"})2725 c.Assert(err, IsNil)2726 stats = mgo.GetStats()2727 c.Assert(stats.SentOps > 0, Equals, true)2728 // Dropping the index should also drop the cached index key.2729 err = coll.DropIndexName("custom")2730 c.Assert(err, IsNil)2731 mgo.ResetStats()2732 err = coll.EnsureIndex(mgo.Index{Key: []string{"a"}, Name: "custom"})2733 c.Assert(err, IsNil)2734 stats = mgo.GetStats()2735 c.Assert(stats.SentOps > 0, Equals, true)2736}2737func (s *S) TestEnsureIndexEvalGetIndexes(c *C) {2738 session, err := mgo.Dial("localhost:40001")2739 c.Assert(err, IsNil)2740 defer session.Close()2741 coll := session.DB("mydb").C("mycoll")2742 err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({b: -1})"}}, nil)2743 c.Assert(err, IsNil)2744 err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({a: 1})"}}, nil)2745 c.Assert(err, IsNil)2746 err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({c: -1, e: 1})"}}, nil)2747 c.Assert(err, IsNil)2748 err = session.Run(bson.D{{"eval", "db.getSiblingDB('mydb').mycoll.ensureIndex({d: '2d'})"}}, nil)2749 c.Assert(err, IsNil)2750 indexes, err := coll.Indexes()2751 c.Assert(err, IsNil)2752 c.Assert(indexes[0].Name, Equals, "_id_")2753 c.Assert(indexes[1].Name, Equals, "a_1")2754 c.Assert(indexes[1].Key, DeepEquals, []string{"a"})2755 c.Assert(indexes[2].Name, Equals, "b_-1")2756 c.Assert(indexes[2].Key, DeepEquals, []string{"-b"})2757 c.Assert(indexes[3].Name, Equals, "c_-1_e_1")2758 c.Assert(indexes[3].Key, DeepEquals, []string{"-c", "e"})2759 if s.versionAtLeast(2, 2) {2760 c.Assert(indexes[4].Name, Equals, "d_2d")2761 c.Assert(indexes[4].Key, DeepEquals, []string{"$2d:d"})2762 } else {2763 c.Assert(indexes[4].Name, Equals, "d_")2764 c.Assert(indexes[4].Key, DeepEquals, []string{"$2d:d"})2765 }2766}2767var testTTL = flag.Bool("test-ttl", false, "test TTL collections (may take 1 minute)")2768func (s *S) TestEnsureIndexExpireAfter(c *C) {2769 session, err := mgo.Dial("localhost:40001")2770 c.Assert(err, IsNil)2771 defer session.Close()2772 session.SetSafe(nil)2773 coll := session.DB("mydb").C("mycoll")2774 err = coll.Insert(M{"n": 1, "t": time.Now().Add(-120 * time.Second)})2775 c.Assert(err, IsNil)2776 err = coll.Insert(M{"n": 2, "t": time.Now()})2777 c.Assert(err, IsNil)2778 // Should fail since there are duplicated entries.2779 index := mgo.Index{2780 Key: []string{"t"},2781 ExpireAfter: 1 * time.Minute,2782 }2783 err = coll.EnsureIndex(index)2784 c.Assert(err, IsNil)2785 indexes, err := coll.Indexes()2786 c.Assert(err, IsNil)2787 c.Assert(indexes[1].Name, Equals, "t_1")2788 c.Assert(indexes[1].ExpireAfter, Equals, 1*time.Minute)2789 if *testTTL {2790 worked := false2791 stop := time.Now().Add(70 * time.Second)2792 for time.Now().Before(stop) {2793 n, err := coll.Count()2794 c.Assert(err, IsNil)2795 if n == 1 {2796 worked = true2797 break2798 }2799 c.Assert(n, Equals, 2)2800 c.Logf("Still has 2 entries...")2801 time.Sleep(1 * time.Second)2802 }2803 if !worked {2804 c.Fatalf("TTL index didn't work")2805 }2806 }2807}2808func (s *S) TestDistinct(c *C) {2809 session, err := mgo.Dial("localhost:40001")2810 c.Assert(err, IsNil)2811 defer session.Close()2812 coll := session.DB("mydb").C("mycoll")2813 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {2814 coll.Insert(M{"n": i})2815 }2816 var result []int2817 err = coll.Find(M{"n": M{"$gt": 2}}).Sort("n").Distinct("n", &result)2818 sort.IntSlice(result).Sort()2819 c.Assert(result, DeepEquals, []int{3, 4, 6})2820}2821func (s *S) TestMapReduce(c *C) {2822 session, err := mgo.Dial("localhost:40001")2823 c.Assert(err, IsNil)2824 defer session.Close()2825 coll := session.DB("mydb").C("mycoll")2826 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {2827 coll.Insert(M{"n": i})2828 }2829 job := &mgo.MapReduce{2830 Map: "function() { emit(this.n, 1); }",2831 Reduce: "function(key, values) { return Array.sum(values); }",2832 }2833 var result []struct {2834 Id int "_id"2835 Value int2836 }2837 info, err := coll.Find(M{"n": M{"$gt": 2}}).MapReduce(job, &result)2838 c.Assert(err, IsNil)2839 c.Assert(info.InputCount, Equals, 4)2840 c.Assert(info.EmitCount, Equals, 4)2841 c.Assert(info.OutputCount, Equals, 3)2842 c.Assert(info.VerboseTime, IsNil)2843 expected := map[int]int{3: 1, 4: 2, 6: 1}2844 for _, item := range result {2845 c.Logf("Item: %#v", &item)2846 c.Assert(item.Value, Equals, expected[item.Id])2847 expected[item.Id] = -12848 }2849}2850func (s *S) TestMapReduceFinalize(c *C) {2851 session, err := mgo.Dial("localhost:40001")2852 c.Assert(err, IsNil)2853 defer session.Close()2854 coll := session.DB("mydb").C("mycoll")2855 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {2856 coll.Insert(M{"n": i})2857 }2858 job := &mgo.MapReduce{2859 Map: "function() { emit(this.n, 1) }",2860 Reduce: "function(key, values) { return Array.sum(values) }",2861 Finalize: "function(key, count) { return {count: count} }",2862 }2863 var result []struct {2864 Id int "_id"2865 Value struct{ Count int }2866 }2867 _, err = coll.Find(nil).MapReduce(job, &result)2868 c.Assert(err, IsNil)2869 expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1}2870 for _, item := range result {2871 c.Logf("Item: %#v", &item)2872 c.Assert(item.Value.Count, Equals, expected[item.Id])2873 expected[item.Id] = -12874 }2875}2876func (s *S) TestMapReduceToCollection(c *C) {2877 session, err := mgo.Dial("localhost:40001")2878 c.Assert(err, IsNil)2879 defer session.Close()2880 coll := session.DB("mydb").C("mycoll")2881 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {2882 coll.Insert(M{"n": i})2883 }2884 job := &mgo.MapReduce{2885 Map: "function() { emit(this.n, 1); }",2886 Reduce: "function(key, values) { return Array.sum(values); }",2887 Out: "mr",2888 }2889 info, err := coll.Find(nil).MapReduce(job, nil)2890 c.Assert(err, IsNil)2891 c.Assert(info.InputCount, Equals, 7)2892 c.Assert(info.EmitCount, Equals, 7)2893 c.Assert(info.OutputCount, Equals, 5)2894 c.Assert(info.Collection, Equals, "mr")2895 c.Assert(info.Database, Equals, "mydb")2896 expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1}2897 var item *struct {2898 Id int "_id"2899 Value int2900 }2901 mr := session.DB("mydb").C("mr")2902 iter := mr.Find(nil).Iter()2903 for iter.Next(&item) {2904 c.Logf("Item: %#v", &item)2905 c.Assert(item.Value, Equals, expected[item.Id])2906 expected[item.Id] = -12907 }2908 c.Assert(iter.Close(), IsNil)2909}2910func (s *S) TestMapReduceToOtherDb(c *C) {2911 session, err := mgo.Dial("localhost:40001")2912 c.Assert(err, IsNil)2913 defer session.Close()2914 coll := session.DB("mydb").C("mycoll")2915 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {2916 coll.Insert(M{"n": i})2917 }2918 job := &mgo.MapReduce{2919 Map: "function() { emit(this.n, 1); }",2920 Reduce: "function(key, values) { return Array.sum(values); }",2921 Out: bson.D{{"replace", "mr"}, {"db", "otherdb"}},2922 }2923 info, err := coll.Find(nil).MapReduce(job, nil)2924 c.Assert(err, IsNil)2925 c.Assert(info.InputCount, Equals, 7)2926 c.Assert(info.EmitCount, Equals, 7)2927 c.Assert(info.OutputCount, Equals, 5)2928 c.Assert(info.Collection, Equals, "mr")2929 c.Assert(info.Database, Equals, "otherdb")2930 expected := map[int]int{1: 1, 2: 2, 3: 1, 4: 2, 6: 1}2931 var item *struct {2932 Id int "_id"2933 Value int2934 }2935 mr := session.DB("otherdb").C("mr")2936 iter := mr.Find(nil).Iter()2937 for iter.Next(&item) {2938 c.Logf("Item: %#v", &item)2939 c.Assert(item.Value, Equals, expected[item.Id])2940 expected[item.Id] = -12941 }2942 c.Assert(iter.Close(), IsNil)2943}2944func (s *S) TestMapReduceOutOfOrder(c *C) {2945 session, err := mgo.Dial("localhost:40001")2946 c.Assert(err, IsNil)2947 defer session.Close()2948 coll := session.DB("mydb").C("mycoll")2949 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {2950 coll.Insert(M{"n": i})2951 }2952 job := &mgo.MapReduce{2953 Map: "function() { emit(this.n, 1); }",2954 Reduce: "function(key, values) { return Array.sum(values); }",2955 Out: bson.M{"a": "a", "z": "z", "replace": "mr", "db": "otherdb", "b": "b", "y": "y"},2956 }2957 info, err := coll.Find(nil).MapReduce(job, nil)2958 c.Assert(err, IsNil)2959 c.Assert(info.Collection, Equals, "mr")2960 c.Assert(info.Database, Equals, "otherdb")2961}2962func (s *S) TestMapReduceScope(c *C) {2963 session, err := mgo.Dial("localhost:40001")2964 c.Assert(err, IsNil)2965 defer session.Close()2966 coll := session.DB("mydb").C("mycoll")2967 coll.Insert(M{"n": 1})2968 job := &mgo.MapReduce{2969 Map: "function() { emit(this.n, x); }",2970 Reduce: "function(key, values) { return Array.sum(values); }",2971 Scope: M{"x": 42},2972 }2973 var result []bson.M2974 _, err = coll.Find(nil).MapReduce(job, &result)2975 c.Assert(len(result), Equals, 1)2976 c.Assert(result[0]["value"], Equals, 42.0)2977}2978func (s *S) TestMapReduceVerbose(c *C) {2979 session, err := mgo.Dial("localhost:40001")2980 c.Assert(err, IsNil)2981 defer session.Close()2982 coll := session.DB("mydb").C("mycoll")2983 for i := 0; i < 100; i++ {2984 err = coll.Insert(M{"n": i})2985 c.Assert(err, IsNil)2986 }2987 job := &mgo.MapReduce{2988 Map: "function() { emit(this.n, 1); }",2989 Reduce: "function(key, values) { return Array.sum(values); }",2990 Verbose: true,2991 }2992 info, err := coll.Find(nil).MapReduce(job, nil)2993 c.Assert(err, IsNil)2994 c.Assert(info.VerboseTime, NotNil)2995}2996func (s *S) TestMapReduceLimit(c *C) {2997 session, err := mgo.Dial("localhost:40001")2998 c.Assert(err, IsNil)2999 defer session.Close()3000 coll := session.DB("mydb").C("mycoll")3001 for _, i := range []int{1, 4, 6, 2, 2, 3, 4} {3002 coll.Insert(M{"n": i})3003 }3004 job := &mgo.MapReduce{3005 Map: "function() { emit(this.n, 1); }",3006 Reduce: "function(key, values) { return Array.sum(values); }",3007 }3008 var result []bson.M3009 _, err = coll.Find(nil).Limit(3).MapReduce(job, &result)3010 c.Assert(err, IsNil)3011 c.Assert(len(result), Equals, 3)3012}3013func (s *S) TestBuildInfo(c *C) {3014 session, err := mgo.Dial("localhost:40001")3015 c.Assert(err, IsNil)3016 defer session.Close()3017 info, err := session.BuildInfo()3018 c.Assert(err, IsNil)3019 var v []int3020 for i, a := range strings.Split(info.Version, ".") {3021 for _, token := range []string{"-rc", "-pre"} {3022 if i == 2 && strings.Contains(a, token) {3023 a = a[:strings.Index(a, token)]3024 info.VersionArray[len(info.VersionArray)-1] = 03025 }3026 }3027 n, err := strconv.Atoi(a)3028 c.Assert(err, IsNil)3029 v = append(v, n)3030 }3031 for len(v) < 4 {3032 v = append(v, 0)3033 }3034 c.Assert(info.VersionArray, DeepEquals, v)3035 c.Assert(info.GitVersion, Matches, "[a-z0-9]+")3036 if s.versionAtLeast(3, 2) {3037 // It was deprecated in 3.2.3038 c.Assert(info.SysInfo, Equals, "")3039 } else {3040 c.Assert(info.SysInfo, Matches, ".*[0-9:]+.*")3041 }3042 if info.Bits != 32 && info.Bits != 64 {3043 c.Fatalf("info.Bits is %d", info.Bits)3044 }3045 if info.MaxObjectSize < 8192 {3046 c.Fatalf("info.MaxObjectSize seems too small: %d", info.MaxObjectSize)3047 }3048}3049func (s *S) TestZeroTimeRoundtrip(c *C) {3050 session, err := mgo.Dial("localhost:40001")3051 c.Assert(err, IsNil)3052 defer session.Close()3053 var d struct{ T time.Time }3054 conn := session.DB("mydb").C("mycoll")3055 err = conn.Insert(d)3056 c.Assert(err, IsNil)3057 var result bson.M3058 err = conn.Find(nil).One(&result)3059 c.Assert(err, IsNil)3060 t, isTime := result["t"].(time.Time)3061 c.Assert(isTime, Equals, true)3062 c.Assert(t, Equals, time.Time{})3063}3064func (s *S) TestFsyncLock(c *C) {3065 session, err := mgo.Dial("localhost:40001")3066 c.Assert(err, IsNil)3067 defer session.Close()3068 clone := session.Clone()3069 defer clone.Close()3070 err = session.FsyncLock()3071 c.Assert(err, IsNil)3072 done := make(chan time.Time)3073 go func() {3074 time.Sleep(3 * time.Second)3075 now := time.Now()3076 err := session.FsyncUnlock()3077 c.Check(err, IsNil)3078 done <- now3079 }()3080 err = clone.DB("mydb").C("mycoll").Insert(bson.M{"n": 1})3081 unlocked := time.Now()3082 unlocking := <-done3083 c.Assert(err, IsNil)3084 c.Assert(unlocked.After(unlocking), Equals, true)3085}3086func (s *S) TestFsync(c *C) {3087 session, err := mgo.Dial("localhost:40001")3088 c.Assert(err, IsNil)3089 defer session.Close()3090 // Not much to do here. Just a smoke check.3091 err = session.Fsync(false)3092 c.Assert(err, IsNil)3093 err = session.Fsync(true)3094 c.Assert(err, IsNil)3095}3096func (s *S) TestRepairCursor(c *C) {3097 if !s.versionAtLeast(2, 7) {3098 c.Skip("RepairCursor only works on 2.7+")3099 }3100 session, err := mgo.Dial("localhost:40001")3101 c.Assert(err, IsNil)3102 defer session.Close()3103 session.SetBatch(2)3104 coll := session.DB("mydb").C("mycoll3")3105 err = coll.DropCollection()3106 ns := []int{0, 10, 20, 30, 40, 50}3107 for _, n := range ns {3108 coll.Insert(M{"n": n})3109 }3110 repairIter := coll.Repair()3111 c.Assert(repairIter.Err(), IsNil)3112 result := struct{ N int }{}3113 resultCounts := map[int]int{}3114 for repairIter.Next(&result) {3115 resultCounts[result.N]++3116 }3117 c.Assert(repairIter.Next(&result), Equals, false)3118 c.Assert(repairIter.Err(), IsNil)3119 c.Assert(repairIter.Close(), IsNil)3120 // Verify that the results of the repair cursor are valid.3121 // The repair cursor can return multiple copies3122 // of the same document, so to check correctness we only3123 // need to verify that at least 1 of each document was returned.3124 for _, key := range ns {3125 c.Assert(resultCounts[key] > 0, Equals, true)3126 }3127}3128func (s *S) TestPipeIter(c *C) {3129 if !s.versionAtLeast(2, 1) {3130 c.Skip("Pipe only works on 2.1+")3131 }3132 session, err := mgo.Dial("localhost:40001")3133 c.Assert(err, IsNil)3134 defer session.Close()3135 coll := session.DB("mydb").C("mycoll")3136 ns := []int{40, 41, 42, 43, 44, 45, 46}3137 for _, n := range ns {3138 coll.Insert(M{"n": n})3139 }3140 pipe := coll.Pipe([]M{{"$match": M{"n": M{"$gte": 42}}}})3141 // Ensure cursor logic is working by forcing a small batch.3142 pipe.Batch(2)3143 // Smoke test for AllowDiskUse.3144 pipe.AllowDiskUse()3145 iter := pipe.Iter()3146 result := struct{ N int }{}3147 for i := 2; i < 7; i++ {3148 ok := iter.Next(&result)3149 c.Assert(ok, Equals, true)3150 c.Assert(result.N, Equals, ns[i])3151 }3152 c.Assert(iter.Next(&result), Equals, false)3153 c.Assert(iter.Close(), IsNil)3154}3155func (s *S) TestPipeAll(c *C) {3156 if !s.versionAtLeast(2, 1) {3157 c.Skip("Pipe only works on 2.1+")3158 }3159 session, err := mgo.Dial("localhost:40001")3160 c.Assert(err, IsNil)3161 defer session.Close()3162 coll := session.DB("mydb").C("mycoll")3163 ns := []int{40, 41, 42, 43, 44, 45, 46}3164 for _, n := range ns {3165 err := coll.Insert(M{"n": n})3166 c.Assert(err, IsNil)3167 }3168 var result []struct{ N int }3169 err = coll.Pipe([]M{{"$match": M{"n": M{"$gte": 42}}}}).All(&result)3170 c.Assert(err, IsNil)3171 for i := 2; i < 7; i++ {3172 c.Assert(result[i-2].N, Equals, ns[i])3173 }3174}3175func (s *S) TestPipeOne(c *C) {3176 if !s.versionAtLeast(2, 1) {3177 c.Skip("Pipe only works on 2.1+")3178 }3179 session, err := mgo.Dial("localhost:40001")3180 c.Assert(err, IsNil)3181 defer session.Close()3182 coll := session.DB("mydb").C("mycoll")3183 coll.Insert(M{"a": 1, "b": 2})3184 result := struct{ A, B int }{}3185 pipe := coll.Pipe([]M{{"$project": M{"a": 1, "b": M{"$add": []interface{}{"$b", 1}}}}})3186 err = pipe.One(&result)3187 c.Assert(err, IsNil)3188 c.Assert(result.A, Equals, 1)3189 c.Assert(result.B, Equals, 3)3190 pipe = coll.Pipe([]M{{"$match": M{"a": 2}}})3191 err = pipe.One(&result)3192 c.Assert(err, Equals, mgo.ErrNotFound)3193}3194func (s *S) TestPipeExplain(c *C) {3195 if !s.versionAtLeast(2, 1) {3196 c.Skip("Pipe only works on 2.1+")3197 }3198 session, err := mgo.Dial("localhost:40001")3199 c.Assert(err, IsNil)3200 defer session.Close()3201 coll := session.DB("mydb").C("mycoll")3202 coll.Insert(M{"a": 1, "b": 2})3203 pipe := coll.Pipe([]M{{"$project": M{"a": 1, "b": M{"$add": []interface{}{"$b", 1}}}}})3204 // The explain command result changes across versions.3205 var result struct{ Ok int }3206 err = pipe.Explain(&result)3207 c.Assert(err, IsNil)3208 c.Assert(result.Ok, Equals, 1)3209}3210func (s *S) TestBatch1Bug(c *C) {3211 session, err := mgo.Dial("localhost:40001")3212 c.Assert(err, IsNil)3213 defer session.Close()3214 coll := session.DB("mydb").C("mycoll")3215 for i := 0; i < 3; i++ {3216 err := coll.Insert(M{"n": i})3217 c.Assert(err, IsNil)3218 }3219 var ns []struct{ N int }3220 err = coll.Find(nil).Batch(1).All(&ns)3221 c.Assert(err, IsNil)3222 c.Assert(len(ns), Equals, 3)3223 session.SetBatch(1)3224 err = coll.Find(nil).All(&ns)3225 c.Assert(err, IsNil)3226 c.Assert(len(ns), Equals, 3)3227}3228func (s *S) TestInterfaceIterBug(c *C) {3229 session, err := mgo.Dial("localhost:40001")3230 c.Assert(err, IsNil)3231 defer session.Close()3232 coll := session.DB("mydb").C("mycoll")3233 for i := 0; i < 3; i++ {3234 err := coll.Insert(M{"n": i})3235 c.Assert(err, IsNil)3236 }3237 var result interface{}3238 i := 03239 iter := coll.Find(nil).Sort("n").Iter()3240 for iter.Next(&result) {3241 c.Assert(result.(bson.M)["n"], Equals, i)3242 i++3243 }3244 c.Assert(iter.Close(), IsNil)3245}3246func (s *S) TestFindIterCloseKillsCursor(c *C) {3247 session, err := mgo.Dial("localhost:40001")3248 c.Assert(err, IsNil)3249 defer session.Close()3250 cursors := serverCursorsOpen(session)3251 coll := session.DB("mydb").C("mycoll")3252 ns := []int{40, 41, 42, 43, 44, 45, 46}3253 for _, n := range ns {3254 err = coll.Insert(M{"n": n})3255 c.Assert(err, IsNil)3256 }3257 iter := coll.Find(nil).Batch(2).Iter()3258 c.Assert(iter.Next(bson.M{}), Equals, true)3259 c.Assert(iter.Close(), IsNil)3260 c.Assert(serverCursorsOpen(session), Equals, cursors)3261}3262func (s *S) TestFindIterDoneWithBatches(c *C) {3263 session, err := mgo.Dial("localhost:40001")3264 c.Assert(err, IsNil)3265 defer session.Close()3266 coll := session.DB("mydb").C("mycoll")3267 ns := []int{40, 41, 42, 43, 44, 45, 46}3268 for _, n := range ns {3269 coll.Insert(M{"n": n})3270 }3271 iter := coll.Find(M{"n": M{"$gte": 42}}).Sort("$natural").Prefetch(0).Batch(2).Iter()3272 result := struct{ N int }{}3273 for i := 2; i < 7; i++ {3274 // first check will be with pending local record;3275 // second will be with open cursor ID but no local3276 // records3277 c.Assert(iter.Done(), Equals, false)3278 ok := iter.Next(&result)3279 c.Assert(ok, Equals, true, Commentf("err=%v", err))3280 }3281 c.Assert(iter.Done(), Equals, true)3282 ok := iter.Next(&result)3283 c.Assert(ok, Equals, false)3284 c.Assert(iter.Close(), IsNil)3285}3286func (s *S) TestFindIterDoneErr(c *C) {3287 session, err := mgo.Dial("localhost:40002")3288 c.Assert(err, IsNil)3289 defer session.Close()3290 coll := session.DB("mydb").C("mycoll")3291 iter := coll.Find(nil).Iter()3292 result := struct{}{}3293 ok := iter.Next(&result)3294 c.Assert(iter.Done(), Equals, true)3295 c.Assert(ok, Equals, false)3296 c.Assert(iter.Err(), ErrorMatches, "unauthorized.*|not authorized.*")3297}3298func (s *S) TestFindIterDoneNotFound(c *C) {3299 session, err := mgo.Dial("localhost:40001")3300 c.Assert(err, IsNil)3301 defer session.Close()3302 coll := session.DB("mydb").C("mycoll")3303 result := struct{ A, B int }{}3304 iter := coll.Find(M{"a": 1}).Iter()3305 ok := iter.Next(&result)3306 c.Assert(ok, Equals, false)3307 c.Assert(iter.Done(), Equals, true)3308}3309func (s *S) TestLogReplay(c *C) {3310 session, err := mgo.Dial("localhost:40001")3311 c.Assert(err, IsNil)3312 defer session.Close()3313 coll := session.DB("mydb").C("mycoll")3314 for i := 0; i < 5; i++ {3315 err = coll.Insert(M{"ts": time.Now()})3316 c.Assert(err, IsNil)3317 }3318 iter := coll.Find(nil).LogReplay().Iter()3319 if s.versionAtLeast(2, 6) {3320 // This used to fail in 2.4. Now it's just a smoke test.3321 c.Assert(iter.Err(), IsNil)3322 } else {3323 c.Assert(iter.Next(bson.M{}), Equals, false)3324 c.Assert(iter.Err(), ErrorMatches, "no ts field in query")3325 }3326}3327func (s *S) TestSetCursorTimeout(c *C) {3328 session, err := mgo.Dial("localhost:40001")3329 c.Assert(err, IsNil)3330 defer session.Close()3331 coll := session.DB("mydb").C("mycoll")3332 err = coll.Insert(M{"n": 42})3333 // This is just a smoke test. Won't wait 10 minutes for an actual timeout.3334 session.SetCursorTimeout(0)3335 var result struct{ N int }3336 iter := coll.Find(nil).Iter()3337 c.Assert(iter.Next(&result), Equals, true)3338 c.Assert(result.N, Equals, 42)3339 c.Assert(iter.Next(&result), Equals, false)3340}3341func (s *S) TestNewIterNoServer(c *C) {3342 session, err := mgo.Dial("localhost:40001")3343 c.Assert(err, IsNil)3344 defer session.Close()3345 data, err := bson.Marshal(bson.M{"a": 1})3346 coll := session.DB("mydb").C("mycoll")3347 iter := coll.NewIter(nil, []bson.Raw{{3, data}}, 42, nil)3348 var result struct{ A int }3349 ok := iter.Next(&result)3350 c.Assert(ok, Equals, true)3351 c.Assert(result.A, Equals, 1)3352 ok = iter.Next(&result)3353 c.Assert(ok, Equals, false)3354 c.Assert(iter.Err(), ErrorMatches, "server not available")3355}3356func (s *S) TestNewIterNoServerPresetErr(c *C) {3357 session, err := mgo.Dial("localhost:40001")3358 c.Assert(err, IsNil)3359 defer session.Close()3360 data, err := bson.Marshal(bson.M{"a": 1})3361 coll := session.DB("mydb").C("mycoll")3362 iter := coll.NewIter(nil, []bson.Raw{{3, data}}, 42, fmt.Errorf("my error"))3363 var result struct{ A int }3364 ok := iter.Next(&result)3365 c.Assert(ok, Equals, true)3366 c.Assert(result.A, Equals, 1)3367 ok = iter.Next(&result)3368 c.Assert(ok, Equals, false)3369 c.Assert(iter.Err(), ErrorMatches, "my error")3370}3371func (s *S) TestBypassValidation(c *C) {3372 if !s.versionAtLeast(3, 2) {3373 c.Skip("validation supported on 3.2+")3374 }3375 session, err := mgo.Dial("localhost:40001")3376 c.Assert(err, IsNil)3377 defer session.Close()3378 coll := session.DB("mydb").C("mycoll")3379 err = coll.Insert(M{"n": 1})3380 c.Assert(err, IsNil)3381 err = coll.Database.Run(bson.D{3382 {"collMod", "mycoll"},3383 {"validator", M{"s": M{"$type": "string"}}},3384 }, nil)3385 c.Assert(err, IsNil)3386 err = coll.Insert(M{"n": 2})3387 c.Assert(err, ErrorMatches, "Document failed validation")3388 err = coll.Update(M{"n": 1}, M{"n": 10})3389 c.Assert(err, ErrorMatches, "Document failed validation")3390 session.SetBypassValidation(true)3391 err = coll.Insert(M{"n": 3})3392 c.Assert(err, IsNil)3393 err = coll.Update(M{"n": 3}, M{"n": 4})3394 c.Assert(err, IsNil)3395 // Ensure this still works. Shouldn't be affected.3396 err = coll.Remove(M{"n": 1})3397 c.Assert(err, IsNil)3398 var result struct{ N int }3399 var ns []int3400 iter := coll.Find(nil).Iter()3401 for iter.Next(&result) {3402 ns = append(ns, result.N)3403 }3404 c.Assert(iter.Err(), IsNil)3405 sort.Ints(ns)3406 c.Assert(ns, DeepEquals, []int{4})3407}3408func (s *S) TestVersionAtLeast(c *C) {3409 tests := [][][]int{3410 {{3, 2, 1}, {3, 2, 0}},3411 {{3, 2, 1}, {3, 2}},3412 {{3, 2, 1}, {2, 5, 5, 5}},3413 {{3, 2, 1}, {2, 5, 5}},3414 {{3, 2, 1}, {2, 5}},3415 }3416 for _, pair := range tests {3417 bi := mgo.BuildInfo{VersionArray: pair[0]}3418 c.Assert(bi.VersionAtLeast(pair[1]...), Equals, true)3419 bi = mgo.BuildInfo{VersionArray: pair[0]}3420 c.Assert(bi.VersionAtLeast(pair[0]...), Equals, true)3421 bi = mgo.BuildInfo{VersionArray: pair[1]}3422 c.Assert(bi.VersionAtLeast(pair[1]...), Equals, true)3423 bi = mgo.BuildInfo{VersionArray: pair[1]}3424 c.Assert(bi.VersionAtLeast(pair[0]...), Equals, false)3425 }3426}3427// --------------------------------------------------------------------------3428// Some benchmarks that require a running database.3429func (s *S) BenchmarkFindIterRaw(c *C) {3430 session, err := mgo.Dial("localhost:40001")3431 c.Assert(err, IsNil)3432 defer session.Close()3433 coll := session.DB("mydb").C("mycoll")3434 doc := bson.D{3435 {"f2", "a short string"},3436 {"f3", bson.D{{"1", "one"}, {"2", 2.0}}},3437 {"f4", []string{"a", "b", "c", "d", "e", "f", "g"}},3438 }3439 for i := 0; i < c.N+1; i++ {3440 err := coll.Insert(doc)3441 c.Assert(err, IsNil)3442 }3443 session.SetBatch(c.N)3444 var raw bson.Raw3445 iter := coll.Find(nil).Iter()3446 iter.Next(&raw)3447 c.ResetTimer()3448 i := 03449 for iter.Next(&raw) {3450 i++3451 }3452 c.StopTimer()3453 c.Assert(iter.Err(), IsNil)3454 c.Assert(i, Equals, c.N)...
auth_test.go
Source:auth_test.go
...44 session, err := mgo.Dial(addr)45 c.Assert(err, IsNil)46 defer session.Close()47 coll := session.DB("mydb").C("mycoll")48 err = coll.Insert(M{"n": 1})49 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*")50 admindb := session.DB("admin")51 err = admindb.Login("root", "wrong")52 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.")53 err = admindb.Login("root", "rapadura")54 c.Assert(err, IsNil)55 err = coll.Insert(M{"n": 1})56 c.Assert(err, IsNil)57 }58}59func (s *S) TestAuthLoginSession(c *C) {60 // Test both with a normal database and with an authenticated shard.61 for _, addr := range []string{"localhost:40002", "localhost:40203"} {62 session, err := mgo.Dial(addr)63 c.Assert(err, IsNil)64 defer session.Close()65 coll := session.DB("mydb").C("mycoll")66 err = coll.Insert(M{"n": 1})67 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*")68 cred := mgo.Credential{69 Username: "root",70 Password: "wrong",71 }72 err = session.Login(&cred)73 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.")74 cred.Password = "rapadura"75 err = session.Login(&cred)76 c.Assert(err, IsNil)77 err = coll.Insert(M{"n": 1})78 c.Assert(err, IsNil)79 }80}81func (s *S) TestAuthLoginLogout(c *C) {82 // Test both with a normal database and with an authenticated shard.83 for _, addr := range []string{"localhost:40002", "localhost:40203"} {84 session, err := mgo.Dial(addr)85 c.Assert(err, IsNil)86 defer session.Close()87 admindb := session.DB("admin")88 err = admindb.Login("root", "rapadura")89 c.Assert(err, IsNil)90 admindb.Logout()91 coll := session.DB("mydb").C("mycoll")92 err = coll.Insert(M{"n": 1})93 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*")94 // Must have dropped auth from the session too.95 session = session.Copy()96 defer session.Close()97 coll = session.DB("mydb").C("mycoll")98 err = coll.Insert(M{"n": 1})99 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*")100 }101}102func (s *S) TestAuthLoginLogoutAll(c *C) {103 session, err := mgo.Dial("localhost:40002")104 c.Assert(err, IsNil)105 defer session.Close()106 admindb := session.DB("admin")107 err = admindb.Login("root", "rapadura")108 c.Assert(err, IsNil)109 session.LogoutAll()110 coll := session.DB("mydb").C("mycoll")111 err = coll.Insert(M{"n": 1})112 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*")113 // Must have dropped auth from the session too.114 session = session.Copy()115 defer session.Close()116 coll = session.DB("mydb").C("mycoll")117 err = coll.Insert(M{"n": 1})118 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*")119}120func (s *S) TestAuthUpsertUserErrors(c *C) {121 session, err := mgo.Dial("localhost:40002")122 c.Assert(err, IsNil)123 defer session.Close()124 admindb := session.DB("admin")125 err = admindb.Login("root", "rapadura")126 c.Assert(err, IsNil)127 mydb := session.DB("mydb")128 err = mydb.UpsertUser(&mgo.User{})129 c.Assert(err, ErrorMatches, "user has no Username")130 err = mydb.UpsertUser(&mgo.User{Username: "user", Password: "pass", UserSource: "source"})131 c.Assert(err, ErrorMatches, "user has both Password/PasswordHash and UserSource set")132 err = mydb.UpsertUser(&mgo.User{Username: "user", Password: "pass", OtherDBRoles: map[string][]mgo.Role{"db": nil}})133 c.Assert(err, ErrorMatches, "user with OtherDBRoles is only supported in the admin or \\$external databases")134}135func (s *S) TestAuthUpsertUser(c *C) {136 if !s.versionAtLeast(2, 4) {137 c.Skip("UpsertUser only works on 2.4+")138 }139 session, err := mgo.Dial("localhost:40002")140 c.Assert(err, IsNil)141 defer session.Close()142 admindb := session.DB("admin")143 err = admindb.Login("root", "rapadura")144 c.Assert(err, IsNil)145 mydb := session.DB("mydb")146 ruser := &mgo.User{147 Username: "myruser",148 Password: "mypass",149 Roles: []mgo.Role{mgo.RoleRead},150 }151 rwuser := &mgo.User{152 Username: "myrwuser",153 Password: "mypass",154 Roles: []mgo.Role{mgo.RoleReadWrite},155 }156 err = mydb.UpsertUser(ruser)157 c.Assert(err, IsNil)158 err = mydb.UpsertUser(rwuser)159 c.Assert(err, IsNil)160 err = mydb.Login("myruser", "mypass")161 c.Assert(err, IsNil)162 admindb.Logout()163 coll := session.DB("mydb").C("mycoll")164 err = coll.Insert(M{"n": 1})165 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")166 err = mydb.Login("myrwuser", "mypass")167 c.Assert(err, IsNil)168 err = coll.Insert(M{"n": 1})169 c.Assert(err, IsNil)170 myotherdb := session.DB("myotherdb")171 err = admindb.Login("root", "rapadura")172 c.Assert(err, IsNil)173 // Test UserSource.174 rwuserother := &mgo.User{175 Username: "myrwuser",176 UserSource: "mydb",177 Roles: []mgo.Role{mgo.RoleRead},178 }179 err = myotherdb.UpsertUser(rwuserother)180 if s.versionAtLeast(2, 6) {181 c.Assert(err, ErrorMatches, `MongoDB 2.6\+ does not support the UserSource setting`)182 return183 }184 c.Assert(err, IsNil)185 admindb.Logout()186 // Test indirection via UserSource: we can't write to it, because187 // the roles for myrwuser are different there.188 othercoll := myotherdb.C("myothercoll")189 err = othercoll.Insert(M{"n": 1})190 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")191 // Reading works, though.192 err = othercoll.Find(nil).One(nil)193 c.Assert(err, Equals, mgo.ErrNotFound)194 // Can't login directly into the database using UserSource, though.195 err = myotherdb.Login("myrwuser", "mypass")196 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.")197}198func (s *S) TestAuthUpsertUserOtherDBRoles(c *C) {199 if !s.versionAtLeast(2, 4) {200 c.Skip("UpsertUser only works on 2.4+")201 }202 session, err := mgo.Dial("localhost:40002")203 c.Assert(err, IsNil)204 defer session.Close()205 admindb := session.DB("admin")206 err = admindb.Login("root", "rapadura")207 c.Assert(err, IsNil)208 ruser := &mgo.User{209 Username: "myruser",210 Password: "mypass",211 OtherDBRoles: map[string][]mgo.Role{"mydb": []mgo.Role{mgo.RoleRead}},212 }213 err = admindb.UpsertUser(ruser)214 c.Assert(err, IsNil)215 defer admindb.RemoveUser("myruser")216 admindb.Logout()217 err = admindb.Login("myruser", "mypass")218 coll := session.DB("mydb").C("mycoll")219 err = coll.Insert(M{"n": 1})220 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")221 err = coll.Find(nil).One(nil)222 c.Assert(err, Equals, mgo.ErrNotFound)223}224func (s *S) TestAuthUpsertUserUpdates(c *C) {225 if !s.versionAtLeast(2, 4) {226 c.Skip("UpsertUser only works on 2.4+")227 }228 session, err := mgo.Dial("localhost:40002")229 c.Assert(err, IsNil)230 defer session.Close()231 admindb := session.DB("admin")232 err = admindb.Login("root", "rapadura")233 c.Assert(err, IsNil)234 mydb := session.DB("mydb")235 // Insert a user that can read.236 user := &mgo.User{237 Username: "myruser",238 Password: "mypass",239 Roles: []mgo.Role{mgo.RoleRead},240 }241 err = mydb.UpsertUser(user)242 c.Assert(err, IsNil)243 // Now update the user password.244 user = &mgo.User{245 Username: "myruser",246 Password: "mynewpass",247 }248 err = mydb.UpsertUser(user)249 c.Assert(err, IsNil)250 // Login with the new user.251 usession, err := mgo.Dial("myruser:mynewpass@localhost:40002/mydb")252 c.Assert(err, IsNil)253 defer usession.Close()254 // Can read, but not write.255 err = usession.DB("mydb").C("mycoll").Find(nil).One(nil)256 c.Assert(err, Equals, mgo.ErrNotFound)257 err = usession.DB("mydb").C("mycoll").Insert(M{"ok": 1})258 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")259 // Update the user role.260 user = &mgo.User{261 Username: "myruser",262 Roles: []mgo.Role{mgo.RoleReadWrite},263 }264 err = mydb.UpsertUser(user)265 c.Assert(err, IsNil)266 // Dial again to ensure the password hasn't changed.267 usession, err = mgo.Dial("myruser:mynewpass@localhost:40002/mydb")268 c.Assert(err, IsNil)269 defer usession.Close()270 // Now it can write.271 err = usession.DB("mydb").C("mycoll").Insert(M{"ok": 1})272 c.Assert(err, IsNil)273}274func (s *S) TestAuthAddUser(c *C) {275 session, err := mgo.Dial("localhost:40002")276 c.Assert(err, IsNil)277 defer session.Close()278 admindb := session.DB("admin")279 err = admindb.Login("root", "rapadura")280 c.Assert(err, IsNil)281 mydb := session.DB("mydb")282 err = mydb.AddUser("myruser", "mypass", true)283 c.Assert(err, IsNil)284 err = mydb.AddUser("mywuser", "mypass", false)285 c.Assert(err, IsNil)286 err = mydb.Login("myruser", "mypass")287 c.Assert(err, IsNil)288 admindb.Logout()289 coll := session.DB("mydb").C("mycoll")290 err = coll.Insert(M{"n": 1})291 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")292 err = mydb.Login("mywuser", "mypass")293 c.Assert(err, IsNil)294 err = coll.Insert(M{"n": 1})295 c.Assert(err, IsNil)296}297func (s *S) TestAuthAddUserReplaces(c *C) {298 session, err := mgo.Dial("localhost:40002")299 c.Assert(err, IsNil)300 defer session.Close()301 admindb := session.DB("admin")302 err = admindb.Login("root", "rapadura")303 c.Assert(err, IsNil)304 mydb := session.DB("mydb")305 err = mydb.AddUser("myuser", "myoldpass", false)306 c.Assert(err, IsNil)307 err = mydb.AddUser("myuser", "mynewpass", true)308 c.Assert(err, IsNil)309 admindb.Logout()310 err = mydb.Login("myuser", "myoldpass")311 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.")312 err = mydb.Login("myuser", "mynewpass")313 c.Assert(err, IsNil)314 // ReadOnly flag was changed too.315 err = mydb.C("mycoll").Insert(M{"n": 1})316 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")317}318func (s *S) TestAuthRemoveUser(c *C) {319 session, err := mgo.Dial("localhost:40002")320 c.Assert(err, IsNil)321 defer session.Close()322 admindb := session.DB("admin")323 err = admindb.Login("root", "rapadura")324 c.Assert(err, IsNil)325 mydb := session.DB("mydb")326 err = mydb.AddUser("myuser", "mypass", true)327 c.Assert(err, IsNil)328 err = mydb.RemoveUser("myuser")329 c.Assert(err, IsNil)330 err = mydb.RemoveUser("myuser")331 c.Assert(err, Equals, mgo.ErrNotFound)332 err = mydb.Login("myuser", "mypass")333 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.")334}335func (s *S) TestAuthLoginTwiceDoesNothing(c *C) {336 session, err := mgo.Dial("localhost:40002")337 c.Assert(err, IsNil)338 defer session.Close()339 admindb := session.DB("admin")340 err = admindb.Login("root", "rapadura")341 c.Assert(err, IsNil)342 oldStats := mgo.GetStats()343 err = admindb.Login("root", "rapadura")344 c.Assert(err, IsNil)345 newStats := mgo.GetStats()346 c.Assert(newStats.SentOps, Equals, oldStats.SentOps)347}348func (s *S) TestAuthLoginLogoutLoginDoesNothing(c *C) {349 session, err := mgo.Dial("localhost:40002")350 c.Assert(err, IsNil)351 defer session.Close()352 admindb := session.DB("admin")353 err = admindb.Login("root", "rapadura")354 c.Assert(err, IsNil)355 oldStats := mgo.GetStats()356 admindb.Logout()357 err = admindb.Login("root", "rapadura")358 c.Assert(err, IsNil)359 newStats := mgo.GetStats()360 c.Assert(newStats.SentOps, Equals, oldStats.SentOps)361}362func (s *S) TestAuthLoginSwitchUser(c *C) {363 session, err := mgo.Dial("localhost:40002")364 c.Assert(err, IsNil)365 defer session.Close()366 admindb := session.DB("admin")367 err = admindb.Login("root", "rapadura")368 c.Assert(err, IsNil)369 coll := session.DB("mydb").C("mycoll")370 err = coll.Insert(M{"n": 1})371 c.Assert(err, IsNil)372 err = admindb.Login("reader", "rapadura")373 c.Assert(err, IsNil)374 // Can't write.375 err = coll.Insert(M{"n": 1})376 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")377 // But can read.378 result := struct{ N int }{}379 err = coll.Find(nil).One(&result)380 c.Assert(err, IsNil)381 c.Assert(result.N, Equals, 1)382}383func (s *S) TestAuthLoginChangePassword(c *C) {384 session, err := mgo.Dial("localhost:40002")385 c.Assert(err, IsNil)386 defer session.Close()387 admindb := session.DB("admin")388 err = admindb.Login("root", "rapadura")389 c.Assert(err, IsNil)390 mydb := session.DB("mydb")391 err = mydb.AddUser("myuser", "myoldpass", false)392 c.Assert(err, IsNil)393 err = mydb.Login("myuser", "myoldpass")394 c.Assert(err, IsNil)395 err = mydb.AddUser("myuser", "mynewpass", true)396 c.Assert(err, IsNil)397 err = mydb.Login("myuser", "mynewpass")398 c.Assert(err, IsNil)399 admindb.Logout()400 // The second login must be in effect, which means read-only.401 err = mydb.C("mycoll").Insert(M{"n": 1})402 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")403}404func (s *S) TestAuthLoginCachingWithSessionRefresh(c *C) {405 session, err := mgo.Dial("localhost:40002")406 c.Assert(err, IsNil)407 defer session.Close()408 admindb := session.DB("admin")409 err = admindb.Login("root", "rapadura")410 c.Assert(err, IsNil)411 session.Refresh()412 coll := session.DB("mydb").C("mycoll")413 err = coll.Insert(M{"n": 1})414 c.Assert(err, IsNil)415}416func (s *S) TestAuthLoginCachingWithSessionCopy(c *C) {417 session, err := mgo.Dial("localhost:40002")418 c.Assert(err, IsNil)419 defer session.Close()420 admindb := session.DB("admin")421 err = admindb.Login("root", "rapadura")422 c.Assert(err, IsNil)423 session = session.Copy()424 defer session.Close()425 coll := session.DB("mydb").C("mycoll")426 err = coll.Insert(M{"n": 1})427 c.Assert(err, IsNil)428}429func (s *S) TestAuthLoginCachingWithSessionClone(c *C) {430 session, err := mgo.Dial("localhost:40002")431 c.Assert(err, IsNil)432 defer session.Close()433 admindb := session.DB("admin")434 err = admindb.Login("root", "rapadura")435 c.Assert(err, IsNil)436 session = session.Clone()437 defer session.Close()438 coll := session.DB("mydb").C("mycoll")439 err = coll.Insert(M{"n": 1})440 c.Assert(err, IsNil)441}442func (s *S) TestAuthLoginCachingWithNewSession(c *C) {443 session, err := mgo.Dial("localhost:40002")444 c.Assert(err, IsNil)445 defer session.Close()446 admindb := session.DB("admin")447 err = admindb.Login("root", "rapadura")448 c.Assert(err, IsNil)449 session = session.New()450 defer session.Close()451 coll := session.DB("mydb").C("mycoll")452 err = coll.Insert(M{"n": 1})453 c.Assert(err, ErrorMatches, "unauthorized|need to login|not authorized .*")454}455func (s *S) TestAuthLoginCachingAcrossPool(c *C) {456 // Logins are cached even when the conenction goes back457 // into the pool.458 session, err := mgo.Dial("localhost:40002")459 c.Assert(err, IsNil)460 defer session.Close()461 admindb := session.DB("admin")462 err = admindb.Login("root", "rapadura")463 c.Assert(err, IsNil)464 // Add another user to test the logout case at the same time.465 mydb := session.DB("mydb")466 err = mydb.AddUser("myuser", "mypass", false)467 c.Assert(err, IsNil)468 err = mydb.Login("myuser", "mypass")469 c.Assert(err, IsNil)470 // Logout root explicitly, to test both cases.471 admindb.Logout()472 // Give socket back to pool.473 session.Refresh()474 // Brand new session, should use socket from the pool.475 other := session.New()476 defer other.Close()477 oldStats := mgo.GetStats()478 err = other.DB("admin").Login("root", "rapadura")479 c.Assert(err, IsNil)480 err = other.DB("mydb").Login("myuser", "mypass")481 c.Assert(err, IsNil)482 // Both logins were cached, so no ops.483 newStats := mgo.GetStats()484 c.Assert(newStats.SentOps, Equals, oldStats.SentOps)485 // And they actually worked.486 err = other.DB("mydb").C("mycoll").Insert(M{"n": 1})487 c.Assert(err, IsNil)488 other.DB("admin").Logout()489 err = other.DB("mydb").C("mycoll").Insert(M{"n": 1})490 c.Assert(err, IsNil)491}492func (s *S) TestAuthLoginCachingAcrossPoolWithLogout(c *C) {493 // Now verify that logouts are properly flushed if they494 // are not revalidated after leaving the pool.495 session, err := mgo.Dial("localhost:40002")496 c.Assert(err, IsNil)497 defer session.Close()498 admindb := session.DB("admin")499 err = admindb.Login("root", "rapadura")500 c.Assert(err, IsNil)501 // Add another user to test the logout case at the same time.502 mydb := session.DB("mydb")503 err = mydb.AddUser("myuser", "mypass", true)504 c.Assert(err, IsNil)505 err = mydb.Login("myuser", "mypass")506 c.Assert(err, IsNil)507 // Just some data to query later.508 err = session.DB("mydb").C("mycoll").Insert(M{"n": 1})509 c.Assert(err, IsNil)510 // Give socket back to pool.511 session.Refresh()512 // Brand new session, should use socket from the pool.513 other := session.New()514 defer other.Close()515 oldStats := mgo.GetStats()516 err = other.DB("mydb").Login("myuser", "mypass")517 c.Assert(err, IsNil)518 // Login was cached, so no ops.519 newStats := mgo.GetStats()520 c.Assert(newStats.SentOps, Equals, oldStats.SentOps)521 // Can't write, since root has been implicitly logged out522 // when the collection went into the pool, and not revalidated.523 err = other.DB("mydb").C("mycoll").Insert(M{"n": 1})524 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")525 // But can read due to the revalidated myuser login.526 result := struct{ N int }{}527 err = other.DB("mydb").C("mycoll").Find(nil).One(&result)528 c.Assert(err, IsNil)529 c.Assert(result.N, Equals, 1)530}531func (s *S) TestAuthEventual(c *C) {532 // Eventual sessions don't keep sockets around, so they are533 // an interesting test case.534 session, err := mgo.Dial("localhost:40002")535 c.Assert(err, IsNil)536 defer session.Close()537 admindb := session.DB("admin")538 err = admindb.Login("root", "rapadura")539 c.Assert(err, IsNil)540 err = session.DB("mydb").C("mycoll").Insert(M{"n": 1})541 c.Assert(err, IsNil)542 var wg sync.WaitGroup543 wg.Add(20)544 for i := 0; i != 10; i++ {545 go func() {546 defer wg.Done()547 var result struct{ N int }548 err := session.DB("mydb").C("mycoll").Find(nil).One(&result)549 c.Assert(err, IsNil)550 c.Assert(result.N, Equals, 1)551 }()552 }553 for i := 0; i != 10; i++ {554 go func() {555 defer wg.Done()556 err := session.DB("mydb").C("mycoll").Insert(M{"n": 1})557 c.Assert(err, IsNil)558 }()559 }560 wg.Wait()561}562func (s *S) TestAuthURL(c *C) {563 session, err := mgo.Dial("mongodb://root:rapadura@localhost:40002/")564 c.Assert(err, IsNil)565 defer session.Close()566 err = session.DB("mydb").C("mycoll").Insert(M{"n": 1})567 c.Assert(err, IsNil)568}569func (s *S) TestAuthURLWrongCredentials(c *C) {570 session, err := mgo.Dial("mongodb://root:wrong@localhost:40002/")571 if session != nil {572 session.Close()573 }574 c.Assert(err, ErrorMatches, "auth fail(s|ed)|.*Authentication failed.")575 c.Assert(session, IsNil)576}577func (s *S) TestAuthURLWithNewSession(c *C) {578 // When authentication is in the URL, the new session will579 // actually carry it on as well, even if logged out explicitly.580 session, err := mgo.Dial("mongodb://root:rapadura@localhost:40002/")581 c.Assert(err, IsNil)582 defer session.Close()583 session.DB("admin").Logout()584 // Do it twice to ensure it passes the needed data on.585 session = session.New()586 defer session.Close()587 session = session.New()588 defer session.Close()589 err = session.DB("mydb").C("mycoll").Insert(M{"n": 1})590 c.Assert(err, IsNil)591}592func (s *S) TestAuthURLWithDatabase(c *C) {593 session, err := mgo.Dial("mongodb://root:rapadura@localhost:40002")594 c.Assert(err, IsNil)595 defer session.Close()596 mydb := session.DB("mydb")597 err = mydb.AddUser("myruser", "mypass", true)598 c.Assert(err, IsNil)599 // Test once with database, and once with source.600 for i := 0; i < 2; i++ {601 var url string602 if i == 0 {603 url = "mongodb://myruser:mypass@localhost:40002/mydb"604 } else {605 url = "mongodb://myruser:mypass@localhost:40002/admin?authSource=mydb"606 }607 usession, err := mgo.Dial(url)608 c.Assert(err, IsNil)609 defer usession.Close()610 ucoll := usession.DB("mydb").C("mycoll")611 err = ucoll.FindId(0).One(nil)612 c.Assert(err, Equals, mgo.ErrNotFound)613 err = ucoll.Insert(M{"n": 1})614 c.Assert(err, ErrorMatches, "unauthorized|not authorized .*")615 }616}617func (s *S) TestDefaultDatabase(c *C) {618 tests := []struct{ url, db string }{619 {"mongodb://root:rapadura@localhost:40002", "test"},620 {"mongodb://root:rapadura@localhost:40002/admin", "admin"},621 {"mongodb://localhost:40001", "test"},622 {"mongodb://localhost:40001/", "test"},623 {"mongodb://localhost:40001/mydb", "mydb"},624 }625 for _, test := range tests {626 session, err := mgo.Dial(test.url)627 c.Assert(err, IsNil)...
Insert
Using AI Code Generation
1import (2type Person struct {3}4func main() {5 session, err := mgo.Dial("localhost")6 if err != nil {7 panic(err)8 }9 defer session.Close()10 session.SetMode(mgo.Monotonic, true)11 c := session.DB("test").C("people")12 err = c.Insert(&Person{"Ale", "+55 53 8116 9639"}, &Person{"Cla", "+55 53 8402 8510"})13 if err != nil {14 fmt.Println("Insertion failed", err)15 }16 result := Person{}17 err = c.Find(bson.M{"name": "Ale"}).One(&result)18 if err != nil {19 fmt.Println("Error in finding the record", err)20 }21 fmt.Println("Phone:", result.Phone)22}23import (24type Person struct {25}26func main() {27 session, err := mgo.Dial("localhost")28 if err != nil {29 panic(err)30 }31 defer session.Close()32 session.SetMode(mgo.Monotonic, true)33 c := session.DB("test").C("people")34 result := Person{}35 err = c.Find(bson.M{"name": "Ale"}).One(&result)36 if err != nil {37 fmt.Println("Error in finding the record", err)38 }39 fmt.Println("Phone:", result.Phone)40}41import (
Insert
Using AI Code Generation
1import (2func main() {3 session, err := mgo.Dial("localhost")4 if err != nil {5 panic(err)6 }7 defer session.Close()8 session.SetMode(mgo.Monotonic, true)9 c := session.DB("test").C("people")10 err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},11 &Person{"Cla", "+55 53 8402 8510"})12 if err != nil {13 panic(err)14 }15 result := Person{}16 err = c.Find(bson.M{"name": "Ale"}).One(&result)17 if err != nil {18 panic(err)19 }20 fmt.Println("Phone:", result.Phone)21}22import (23func main() {24 session, err := mgo.Dial("localhost")25 if err != nil {26 panic(err)27 }28 defer session.Close()29 session.SetMode(mgo.Monotonic, true)30 c := session.DB("test").C("people")31 result := Person{}32 err = c.Find(bson.M{"name": "Ale"}).One(&result)33 if err != nil {34 panic(err)35 }36 fmt.Println("Phone:", result.Phone)37}38import (39func main() {40 session, err := mgo.Dial("localhost")41 if err != nil {42 panic(err)43 }44 defer session.Close()45 session.SetMode(mgo.Monotonic, true)46 c := session.DB("test").C("people")47 err = c.Find(bson.M{"name": "Ale"}).All(&result)48 if err != nil {49 panic(err)50 }51 fmt.Println("Phone:", result[0].Phone)52}53import (
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!