summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/vendor/src/gopkg.in/mgo.v2/bulk_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/vendor/src/gopkg.in/mgo.v2/bulk_test.go')
-rw-r--r--src/mongo/gotools/vendor/src/gopkg.in/mgo.v2/bulk_test.go504
1 files changed, 504 insertions, 0 deletions
diff --git a/src/mongo/gotools/vendor/src/gopkg.in/mgo.v2/bulk_test.go b/src/mongo/gotools/vendor/src/gopkg.in/mgo.v2/bulk_test.go
new file mode 100644
index 00000000000..cb280bbfa40
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/gopkg.in/mgo.v2/bulk_test.go
@@ -0,0 +1,504 @@
+// mgo - MongoDB driver for Go
+//
+// Copyright (c) 2010-2015 - Gustavo Niemeyer <gustavo@niemeyer.net>
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package mgo_test
+
+import (
+ . "gopkg.in/check.v1"
+ "gopkg.in/mgo.v2"
+)
+
+func (s *S) TestBulkInsert(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+ bulk := coll.Bulk()
+ bulk.Insert(M{"n": 1})
+ bulk.Insert(M{"n": 2}, M{"n": 3})
+ r, err := bulk.Run()
+ c.Assert(err, IsNil)
+ c.Assert(r, FitsTypeOf, &mgo.BulkResult{})
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{1}, {2}, {3}})
+}
+
+func (s *S) TestBulkInsertError(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+ bulk := coll.Bulk()
+ bulk.Insert(M{"_id": 1}, M{"_id": 2}, M{"_id": 2}, M{"_id": 3})
+ _, err = bulk.Run()
+ c.Assert(err, ErrorMatches, ".*duplicate key.*")
+ c.Assert(mgo.IsDup(err), Equals, true)
+
+ type doc struct {
+ N int `_id`
+ }
+ var res []doc
+ err = coll.Find(nil).Sort("_id").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{1}, {2}})
+}
+
+func (s *S) TestBulkInsertErrorUnordered(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+ bulk := coll.Bulk()
+ bulk.Unordered()
+ bulk.Insert(M{"_id": 1}, M{"_id": 2}, M{"_id": 2}, M{"_id": 3})
+ _, err = bulk.Run()
+ c.Assert(err, ErrorMatches, ".*duplicate key.*")
+
+ type doc struct {
+ N int `_id`
+ }
+ var res []doc
+ err = coll.Find(nil).Sort("_id").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{1}, {2}, {3}})
+}
+
+func (s *S) TestBulkInsertErrorUnorderedSplitBatch(c *C) {
+ // The server has a batch limit of 1000 documents when using write commands.
+ // This artificial limit did not exist with the old wire protocol, so to
+ // avoid compatibility issues the implementation internally split batches
+ // into the proper size and delivers them one by one. This test ensures that
+ // the behavior of unordered (that is, continue on error) remains correct
+ // when errors happen and there are batches left.
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+ bulk := coll.Bulk()
+ bulk.Unordered()
+
+ const total = 4096
+ type doc struct {
+ Id int `_id`
+ }
+ docs := make([]interface{}, total)
+ for i := 0; i < total; i++ {
+ docs[i] = doc{i}
+ }
+ docs[1] = doc{0}
+ bulk.Insert(docs...)
+ _, err = bulk.Run()
+ c.Assert(err, ErrorMatches, ".*duplicate key.*")
+
+ n, err := coll.Count()
+ c.Assert(err, IsNil)
+ c.Assert(n, Equals, total-1)
+
+ var res doc
+ err = coll.FindId(1500).One(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res.Id, Equals, 1500)
+}
+
+func (s *S) TestBulkErrorString(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ // If it's just the same string multiple times, join it into a single message.
+ bulk := coll.Bulk()
+ bulk.Unordered()
+ bulk.Insert(M{"_id": 1}, M{"_id": 2}, M{"_id": 2})
+ _, err = bulk.Run()
+ c.Assert(err, ErrorMatches, ".*duplicate key.*")
+ c.Assert(err, Not(ErrorMatches), ".*duplicate key.*duplicate key")
+ c.Assert(mgo.IsDup(err), Equals, true)
+
+ // With matching errors but different messages, present them all.
+ bulk = coll.Bulk()
+ bulk.Unordered()
+ bulk.Insert(M{"_id": "dupone"}, M{"_id": "dupone"}, M{"_id": "duptwo"}, M{"_id": "duptwo"})
+ _, err = bulk.Run()
+ if s.versionAtLeast(2, 6) {
+ c.Assert(err, ErrorMatches, "multiple errors in bulk operation:\n( - .*duplicate.*\n){2}$")
+ c.Assert(err, ErrorMatches, "(?s).*dupone.*")
+ c.Assert(err, ErrorMatches, "(?s).*duptwo.*")
+ } else {
+ // Wire protocol query doesn't return all errors.
+ c.Assert(err, ErrorMatches, ".*duplicate.*")
+ }
+ c.Assert(mgo.IsDup(err), Equals, true)
+
+ // With mixed errors, present them all.
+ bulk = coll.Bulk()
+ bulk.Unordered()
+ bulk.Insert(M{"_id": 1}, M{"_id": []int{2}})
+ _, err = bulk.Run()
+ if s.versionAtLeast(2, 6) {
+ c.Assert(err, ErrorMatches, "multiple errors in bulk operation:\n - .*duplicate.*\n - .*array.*\n$")
+ } else {
+ // Wire protocol query doesn't return all errors.
+ c.Assert(err, ErrorMatches, ".*array.*")
+ }
+ c.Assert(mgo.IsDup(err), Equals, false)
+}
+
+func (s *S) TestBulkErrorCases_2_6(c *C) {
+ if !s.versionAtLeast(2, 6) {
+ c.Skip("2.4- has poor bulk reporting")
+ }
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ bulk := coll.Bulk()
+ bulk.Unordered()
+
+ // There's a limit of 1000 operations per command, so
+ // this forces the more complex indexing logic to act.
+ for i := 0; i < 1010; i++ {
+ switch i {
+ case 3, 14:
+ bulk.Insert(M{"_id": "dupone"})
+ case 5, 106:
+ bulk.Update(M{"_id": i - 1}, M{"$set": M{"_id": 4}})
+ case 7, 1008:
+ bulk.Insert(M{"_id": "duptwo"})
+ default:
+ bulk.Insert(M{"_id": i})
+ }
+ }
+
+ _, err = bulk.Run()
+ ecases := err.(*mgo.BulkError).Cases()
+
+ c.Check(ecases[0].Err, ErrorMatches, ".*duplicate.*dupone.*")
+ c.Check(ecases[0].Index, Equals, 14)
+ c.Check(ecases[1].Err, ErrorMatches, ".*update.*_id.*")
+ c.Check(ecases[1].Index, Equals, 106)
+ c.Check(ecases[2].Err, ErrorMatches, ".*duplicate.*duptwo.*")
+ c.Check(ecases[2].Index, Equals, 1008)
+}
+
+func (s *S) TestBulkErrorCases_2_4(c *C) {
+ if s.versionAtLeast(2, 6) {
+ c.Skip("2.6+ has better reporting")
+ }
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ bulk := coll.Bulk()
+ bulk.Unordered()
+
+ // There's a limit of 1000 operations per command, so
+ // this forces the more complex indexing logic to act.
+ for i := 0; i < 1010; i++ {
+ switch i {
+ case 3, 14:
+ bulk.Insert(M{"_id": "dupone"})
+ case 5:
+ bulk.Update(M{"_id": i - 1}, M{"$set": M{"n": 4}})
+ case 106:
+ bulk.Update(M{"_id": i - 1}, M{"$bogus": M{"n": 4}})
+ case 7, 1008:
+ bulk.Insert(M{"_id": "duptwo"})
+ default:
+ bulk.Insert(M{"_id": i})
+ }
+ }
+
+ _, err = bulk.Run()
+ ecases := err.(*mgo.BulkError).Cases()
+
+ c.Check(ecases[0].Err, ErrorMatches, ".*duplicate.*duptwo.*")
+ c.Check(ecases[0].Index, Equals, -1)
+ c.Check(ecases[1].Err, ErrorMatches, `.*\$bogus.*`)
+ c.Check(ecases[1].Index, Equals, 106)
+}
+
+func (s *S) TestBulkErrorCasesOrdered(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ bulk := coll.Bulk()
+
+ // There's a limit of 1000 operations per command, so
+ // this forces the more complex indexing logic to act.
+ for i := 0; i < 20; i++ {
+ switch i {
+ case 3, 14:
+ bulk.Insert(M{"_id": "dupone"})
+ case 7, 17:
+ bulk.Insert(M{"_id": "duptwo"})
+ default:
+ bulk.Insert(M{"_id": i})
+ }
+ }
+
+ _, err = bulk.Run()
+ ecases := err.(*mgo.BulkError).Cases()
+
+ c.Check(ecases[0].Err, ErrorMatches, ".*duplicate.*dupone.*")
+ if s.versionAtLeast(2, 6) {
+ c.Check(ecases[0].Index, Equals, 14)
+ } else {
+ c.Check(ecases[0].Index, Equals, -1)
+ }
+ c.Check(ecases, HasLen, 1)
+}
+
+func (s *S) TestBulkUpdate(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ err = coll.Insert(M{"n": 1}, M{"n": 2}, M{"n": 3})
+ c.Assert(err, IsNil)
+
+ bulk := coll.Bulk()
+ bulk.Update(M{"n": 1}, M{"$set": M{"n": 1}})
+ bulk.Update(M{"n": 2}, M{"$set": M{"n": 20}})
+ bulk.Update(M{"n": 5}, M{"$set": M{"n": 50}}) // Won't match.
+ bulk.Update(M{"n": 1}, M{"$set": M{"n": 10}}, M{"n": 3}, M{"$set": M{"n": 30}})
+ r, err := bulk.Run()
+ c.Assert(err, IsNil)
+ c.Assert(r.Matched, Equals, 4)
+ if s.versionAtLeast(2, 6) {
+ c.Assert(r.Modified, Equals, 3)
+ }
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{10}, {20}, {30}})
+}
+
+func (s *S) TestBulkUpdateError(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ err = coll.Insert(M{"n": 1}, M{"n": 2}, M{"n": 3})
+ c.Assert(err, IsNil)
+
+ bulk := coll.Bulk()
+ bulk.Update(
+ M{"n": 1}, M{"$set": M{"n": 10}},
+ M{"n": 2}, M{"$set": M{"n": 20, "_id": 20}},
+ M{"n": 3}, M{"$set": M{"n": 30}},
+ )
+ r, err := bulk.Run()
+ c.Assert(err, ErrorMatches, ".*_id.*")
+ c.Assert(r, FitsTypeOf, &mgo.BulkResult{})
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{2}, {3}, {10}})
+}
+
+func (s *S) TestBulkUpdateErrorUnordered(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ err = coll.Insert(M{"n": 1}, M{"n": 2}, M{"n": 3})
+ c.Assert(err, IsNil)
+
+ bulk := coll.Bulk()
+ bulk.Unordered()
+ bulk.Update(
+ M{"n": 1}, M{"$set": M{"n": 10}},
+ M{"n": 2}, M{"$set": M{"n": 20, "_id": 20}},
+ M{"n": 3}, M{"$set": M{"n": 30}},
+ )
+ r, err := bulk.Run()
+ c.Assert(err, ErrorMatches, ".*_id.*")
+ c.Assert(r, FitsTypeOf, &mgo.BulkResult{})
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{2}, {10}, {30}})
+}
+
+func (s *S) TestBulkUpdateAll(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ err = coll.Insert(M{"n": 1}, M{"n": 2}, M{"n": 3})
+ c.Assert(err, IsNil)
+
+ bulk := coll.Bulk()
+ bulk.UpdateAll(M{"n": 1}, M{"$set": M{"n": 10}})
+ bulk.UpdateAll(M{"n": 2}, M{"$set": M{"n": 2}}) // Won't change.
+ bulk.UpdateAll(M{"n": 5}, M{"$set": M{"n": 50}}) // Won't match.
+ bulk.UpdateAll(M{}, M{"$inc": M{"n": 1}}, M{"n": 11}, M{"$set": M{"n": 5}})
+ r, err := bulk.Run()
+ c.Assert(err, IsNil)
+ c.Assert(r.Matched, Equals, 6)
+ if s.versionAtLeast(2, 6) {
+ c.Assert(r.Modified, Equals, 5)
+ }
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{3}, {4}, {5}})
+}
+
+func (s *S) TestBulkMixedUnordered(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ // Abuse undefined behavior to ensure the desired implementation is in place.
+ bulk := coll.Bulk()
+ bulk.Unordered()
+ bulk.Insert(M{"n": 1})
+ bulk.Update(M{"n": 2}, M{"$inc": M{"n": 1}})
+ bulk.Insert(M{"n": 2})
+ bulk.Update(M{"n": 3}, M{"$inc": M{"n": 1}})
+ bulk.Update(M{"n": 1}, M{"$inc": M{"n": 1}})
+ bulk.Insert(M{"n": 3})
+ r, err := bulk.Run()
+ c.Assert(err, IsNil)
+ c.Assert(r.Matched, Equals, 3)
+ if s.versionAtLeast(2, 6) {
+ c.Assert(r.Modified, Equals, 3)
+ }
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{2}, {3}, {4}})
+}
+
+func (s *S) TestBulkUpsert(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ err = coll.Insert(M{"n": 1}, M{"n": 2}, M{"n": 3})
+ c.Assert(err, IsNil)
+
+ bulk := coll.Bulk()
+ bulk.Upsert(M{"n": 2}, M{"$set": M{"n": 20}})
+ bulk.Upsert(M{"n": 4}, M{"$set": M{"n": 40}}, M{"n": 3}, M{"$set": M{"n": 30}})
+ r, err := bulk.Run()
+ c.Assert(err, IsNil)
+ c.Assert(r, FitsTypeOf, &mgo.BulkResult{})
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{1}, {20}, {30}, {40}})
+}
+
+func (s *S) TestBulkRemove(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ err = coll.Insert(M{"n": 1}, M{"n": 2}, M{"n": 3}, M{"n": 4}, M{"n": 4})
+ c.Assert(err, IsNil)
+
+ bulk := coll.Bulk()
+ bulk.Remove(M{"n": 1})
+ bulk.Remove(M{"n": 2}, M{"n": 4})
+ r, err := bulk.Run()
+ c.Assert(err, IsNil)
+ c.Assert(r.Matched, Equals, 3)
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{3}, {4}})
+}
+
+func (s *S) TestBulkRemoveAll(c *C) {
+ session, err := mgo.Dial("localhost:40001")
+ c.Assert(err, IsNil)
+ defer session.Close()
+
+ coll := session.DB("mydb").C("mycoll")
+
+ err = coll.Insert(M{"n": 1}, M{"n": 2}, M{"n": 3}, M{"n": 4}, M{"n": 4})
+ c.Assert(err, IsNil)
+
+ bulk := coll.Bulk()
+ bulk.RemoveAll(M{"n": 1})
+ bulk.RemoveAll(M{"n": 2}, M{"n": 4})
+ r, err := bulk.Run()
+ c.Assert(err, IsNil)
+ c.Assert(r.Matched, Equals, 4)
+
+ type doc struct{ N int }
+ var res []doc
+ err = coll.Find(nil).Sort("n").All(&res)
+ c.Assert(err, IsNil)
+ c.Assert(res, DeepEquals, []doc{{3}})
+}