summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Studer <greg@10gen.com>2014-03-14 15:21:49 -0400
committerGreg Studer <greg@10gen.com>2014-03-18 15:26:54 -0400
commit43be3d5a87c70a82a36f4116b733d35a514564ae (patch)
tree03629c1b91eec4b09896c61269f7930cf419c1c4
parent510e2dda4e8e2e229adb9aec5f077050ebfae1da (diff)
downloadmongo-43be3d5a87c70a82a36f4116b733d35a514564ae.tar.gz
SERVER-13057 push shell write errors more in line with other drivers
(cherry picked from commit 6ee3a36bdb672e0e7b893a77334e932d8d1eab8c)
-rw-r--r--jstests/core/big_object1.js2
-rw-r--r--jstests/core/bulk_api_ordered.js7
-rw-r--r--jstests/core/bulk_api_unordered.js6
-rw-r--r--jstests/core/bulk_insert.js4
-rw-r--r--jstests/core/bulk_legacy_enforce_gle.js14
-rw-r--r--jstests/core/cappeda.js2
-rw-r--r--jstests/core/geo_borders.js2
-rw-r--r--jstests/core/geo_multinest0.js2
-rw-r--r--jstests/core/geo_polygon2.js2
-rwxr-xr-xjstests/core/geo_s2index.js4
-rw-r--r--jstests/core/indexOtherNamespace.js14
-rw-r--r--jstests/core/index_big1.js2
-rw-r--r--jstests/core/indexapi.js10
-rw-r--r--jstests/core/indexi.js15
-rw-r--r--jstests/core/ns_length.js2
-rw-r--r--jstests/core/push2.js2
-rw-r--r--jstests/core/remove6.js2
-rw-r--r--jstests/core/removeb.js2
-rw-r--r--jstests/core/rename4.js2
-rw-r--r--jstests/core/storefunc.js2
-rw-r--r--jstests/core/update_dbref.js10
-rw-r--r--jstests/core/update_replace.js18
-rw-r--r--jstests/core/update_setOnInsert.js6
-rw-r--r--jstests/core/updatel.js8
-rw-r--r--jstests/core/upsert1.js2
-rw-r--r--jstests/core/write_result.js11
-rw-r--r--jstests/replsets/bulk_api_wc.js8
-rw-r--r--jstests/replsets/localhostAuthBypass.js16
-rw-r--r--jstests/replsets/replset7.js2
-rw-r--r--jstests/shell_writeconcern.js16
-rw-r--r--src/mongo/shell/assert.js137
-rw-r--r--src/mongo/shell/bulk_api.js463
-rw-r--r--src/mongo/shell/collection.js65
33 files changed, 521 insertions, 339 deletions
diff --git a/jstests/core/big_object1.js b/jstests/core/big_object1.js
index be61dbd3041..e567cf8ce93 100644
--- a/jstests/core/big_object1.js
+++ b/jstests/core/big_object1.js
@@ -23,7 +23,7 @@ if ( db.adminCommand( "buildinfo" ).bits == 64 ){
break;
}
- if ( result.hasWriteErrors() )
+ if ( result.hasWriteError() )
break;
x++;
}
diff --git a/jstests/core/bulk_api_ordered.js b/jstests/core/bulk_api_ordered.js
index fd0f528cb9c..beef9d24411 100644
--- a/jstests/core/bulk_api_ordered.js
+++ b/jstests/core/bulk_api_ordered.js
@@ -80,8 +80,9 @@ var executeTests = function() {
bulkOp.insert({b:1, a:1});
bulkOp.find({b:2}).upsert().updateOne({$set: {a:1}});
bulkOp.insert({b:3, a:2});
- var result = bulkOp.execute();
-
+ var result = assert.throws( function() { bulkOp.execute(); } );
+ assert(result instanceof BulkWriteError);
+ assert(result instanceof Error);
// Basic properties check
assert.eq(1, result.nInserted);
assert.eq(true, result.hasWriteErrors());
@@ -118,7 +119,7 @@ var executeTests = function() {
bulkOp.find({b:2}).upsert().updateOne({$set: {a:1}});
bulkOp.insert({b:4, a:3});
bulkOp.insert({b:5, a:1});
- var result = bulkOp.execute();
+ var result = assert.throws( function() { bulkOp.execute(); } );
// Basic properties check
assert.eq(1, result.nInserted);
diff --git a/jstests/core/bulk_api_unordered.js b/jstests/core/bulk_api_unordered.js
index db6c372fb76..1c8607dec37 100644
--- a/jstests/core/bulk_api_unordered.js
+++ b/jstests/core/bulk_api_unordered.js
@@ -83,7 +83,8 @@ var executeTests = function() {
bulkOp.insert({b:1, a:1});
bulkOp.find({b:2}).upsert().updateOne({$set: {a:1}});
bulkOp.insert({b:3, a:2});
- var result = bulkOp.execute();
+ var result = assert.throws( function() { bulkOp.execute(); } );
+
// Basic properties check
assert.eq(2, result.nInserted);
assert.eq(true, result.hasWriteErrors());
@@ -116,7 +117,8 @@ var executeTests = function() {
bulkOp.find({b:2}).upsert().updateOne({$set: {a:1}});
bulkOp.insert({b:4, a:3});
bulkOp.insert({b:5, a:1});
- var result = bulkOp.execute();
+ var result = assert.throws( function() { bulkOp.execute(); } );
+
// Basic properties check
assert.eq(2, result.nInserted);
assert.eq(1, result.nUpserted);
diff --git a/jstests/core/bulk_insert.js b/jstests/core/bulk_insert.js
index e26b323c6d9..e2e625e0a3c 100644
--- a/jstests/core/bulk_insert.js
+++ b/jstests/core/bulk_insert.js
@@ -3,7 +3,9 @@
var coll = db.bulkInsertTest
coll.drop()
-Random.srand( new Date().getTime() )
+var seed = new Date().getTime();
+Random.srand( seed );
+print("Seed for randomized test is " + seed);
var bulkSize = Math.floor( Random.rand() * 200 ) + 1
var numInserts = Math.floor( Random.rand() * 300 ) + 1
diff --git a/jstests/core/bulk_legacy_enforce_gle.js b/jstests/core/bulk_legacy_enforce_gle.js
index bec11749274..4efc280ab37 100644
--- a/jstests/core/bulk_legacy_enforce_gle.js
+++ b/jstests/core/bulk_legacy_enforce_gle.js
@@ -10,7 +10,7 @@ var coll = db.bulk_legacy_enforce_gle;
coll.drop();
var bulk = coll.initializeUnorderedBulkOp();
bulk.find({ none: 1 }).upsert().updateOne({ _id: 1 });
-assert.writeOK(bulk.execute());
+assert( bulk.execute() instanceof BulkWriteResult );
var gle = db.runCommand({ getLastError: 1 });
assert(gle.ok, tojson(gle));
@@ -21,7 +21,7 @@ coll.drop();
coll.insert({ _id: 1 });
bulk = coll.initializeUnorderedBulkOp();
bulk.find({ none: 1 }).upsert().updateOne({ _id: 1 });
-assert.writeError(bulk.execute());
+assert.throws( function() { bulk.execute(); } );
gle = db.runCommand({ getLastError: 1 });
assert(gle.ok, tojson(gle));
@@ -34,7 +34,7 @@ bulk = coll.initializeUnorderedBulkOp();
bulk.find({ none: 1 }).upsert().updateOne({ _id: 1 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 1 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 0 });
-var res = assert.writeError(bulk.execute());
+var res = assert.throws( function() { bulk.execute(); } );
assert.eq(2, res.getWriteErrors().length);
gle = db.runCommand({ getLastError: 1 });
@@ -48,7 +48,7 @@ bulk = coll.initializeUnorderedBulkOp();
bulk.find({ none: 1 }).upsert().updateOne({ _id: 0 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 1 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 2 });
-res = assert.writeError(bulk.execute());
+var res = assert.throws( function() { bulk.execute(); } );
assert.eq(1, res.getWriteErrors().length);
gle = db.runCommand({ getLastError: 1 });
@@ -63,7 +63,7 @@ bulk = coll.initializeUnorderedBulkOp();
bulk.find({ none: 1 }).upsert().updateOne({ _id: 0 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 1 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 2 });
-res = assert.writeError(bulk.execute());
+res = assert.throws( function() { bulk.execute(); } );
assert.eq(1, res.getWriteErrors().length);
gle = db.runCommand({ getLastError: 1 });
@@ -77,7 +77,7 @@ bulk = coll.initializeUnorderedBulkOp();
bulk.find({ none: 1 }).upsert().updateOne({ _id: 0 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 1 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 2 });
-res = assert.writeError(bulk.execute());
+res = assert.throws( function() { bulk.execute(); } );
assert.eq(1, res.getWriteErrors().length);
gle = db.runCommand({ getLastError: 1, w: 1 });
@@ -91,7 +91,7 @@ bulk = coll.initializeUnorderedBulkOp();
bulk.find({ none: 1 }).upsert().updateOne({ _id: 0 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 1 });
bulk.find({ none: 1 }).upsert().updateOne({ _id: 2 });
-res = assert.writeError(bulk.execute());
+res = assert.throws( function() { bulk.execute(); } );
assert.eq(1, res.getWriteErrors().length);
gle = db.runCommand({ getLastError: 1, w: 0 });
diff --git a/jstests/core/cappeda.js b/jstests/core/cappeda.js
index 3244ffae84f..4292a989511 100644
--- a/jstests/core/cappeda.js
+++ b/jstests/core/cappeda.js
@@ -14,7 +14,7 @@ function q() {
function u() {
var res = t.update( { _id : 5 } , { $set : { x : 2 } } );
- if ( res.hasWriteErrors() )
+ if ( res.hasWriteError() )
throw res;
}
diff --git a/jstests/core/geo_borders.js b/jstests/core/geo_borders.js
index 20781409b1e..32c4889eccd 100644
--- a/jstests/core/geo_borders.js
+++ b/jstests/core/geo_borders.js
@@ -27,7 +27,7 @@ assert.neq(null, res);
// Create a point index only slightly bigger than the points we have
res = t.ensureIndex( { loc : "2d" }, { max : overallMax + epsilon, min : overallMin - epsilon } );
-assert.writeOK(res);
+assert.commandWorked(res);
// ************
// Box Tests
diff --git a/jstests/core/geo_multinest0.js b/jstests/core/geo_multinest0.js
index 634d581589c..7cde4f87280 100644
--- a/jstests/core/geo_multinest0.js
+++ b/jstests/core/geo_multinest0.js
@@ -39,7 +39,7 @@ t.insert( { zip : "10001", data : [ { loc : [ [ 10, 10 ], { lat : 50, long : 50
t.insert( { zip : "10002", data : [ { loc : [ 20, 20 ], type : "home" },
{ loc : [ 50, 50 ], type : "work" } ] } )
res = t.insert({ zip: "10003", data: [{ loc: [{ x: 30, y: 30 }, [ 50, 50 ]], type: "home" }]});
-assert( !res.hasWriteErrors() );
+assert( !res.hasWriteError() );
assert.commandWorked(t.ensureIndex( { "data.loc" : "2d", zip : 1 } ));
assert.eq( 2, t.getIndexKeys().length )
diff --git a/jstests/core/geo_polygon2.js b/jstests/core/geo_polygon2.js
index c626064f153..26477651a06 100644
--- a/jstests/core/geo_polygon2.js
+++ b/jstests/core/geo_polygon2.js
@@ -247,7 +247,7 @@ for ( var test = 0; test < numTests; test++ ) {
}
var res = t.ensureIndex({ loc: "2d" }, { bits: 1 + bits, max: bounds[1], min: bounds[0] });
- assert.writeOK( res );
+ assert.commandWorked( res );
t.insert( { loc : allPointsIn } );
t.insert( { loc : allPointsOut } );
diff --git a/jstests/core/geo_s2index.js b/jstests/core/geo_s2index.js
index fea45dbb901..11d86a3bf2f 100755
--- a/jstests/core/geo_s2index.js
+++ b/jstests/core/geo_s2index.js
@@ -35,7 +35,7 @@ t.insert( {geo : somepoly, nonGeo: "somepoly" })
var res = t.ensureIndex( { geo : "2dsphere", nonGeo: 1 } );
// We have a point without any geo data. Don't error.
-assert.writeOK(res);
+assert.commandWorked(res);
res = t.find({ "geo" : { "$geoIntersects" : { "$geometry" : pointA} } });
assert.eq(res.itcount(), 3);
@@ -96,7 +96,7 @@ assert.writeOK(res);
t.drop();
t.save({loc: [0,0]})
res = t.ensureIndex({ loc: "2dsphere" }, { finestIndexedLevel: 17, coarsestIndexedLevel: 5 });
-assert.writeOK(res);
+assert.commandWorked(res);
t.drop();
t.save({loc: [0,0]})
diff --git a/jstests/core/indexOtherNamespace.js b/jstests/core/indexOtherNamespace.js
index 7df55188606..da026616cc6 100644
--- a/jstests/core/indexOtherNamespace.js
+++ b/jstests/core/indexOtherNamespace.js
@@ -7,18 +7,8 @@ otherDB.foo.insert({a:1})
assert.eq(1, otherDB.system.indexes.count());
assert.eq("BasicCursor", otherDB.foo.find({a:1}).explain().cursor);
-if (db.getMongo().writeMode() == 'commands') {
- assert.throws(function() {
- otherDB.randomNS.system.indexes.insert({ ns: "indexOtherNS.foo",
- key: { a: 1}, name: "a_1" });
- });
-}
-else {
- assert.writeError(otherDB.randomNS.system.indexes.insert({ ns: "indexOtherNS.foo",
- key: { a: 1 }, name: "a_1"}));
-}
-
-
+assert.writeError(otherDB.randomNS.system.indexes.insert({ ns: "indexOtherNS.foo",
+ key: { a: 1 }, name: "a_1"}));
// Assert that index didn't actually get built
assert.eq(1, otherDB.system.indexes.count());
diff --git a/jstests/core/index_big1.js b/jstests/core/index_big1.js
index 6fbffa4415e..dffebc351cf 100644
--- a/jstests/core/index_big1.js
+++ b/jstests/core/index_big1.js
@@ -14,7 +14,7 @@ for ( i=0; i<N; i++ ) {
bulk.insert( { a : i + .5 , x : s } );
s += "x";
}
-assert.writeError(bulk.execute());
+assert.throws( function() { bulk.execute(); } );
assert.eq( 2 , t.getIndexes().length );
diff --git a/jstests/core/indexapi.js b/jstests/core/indexapi.js
index 3e0b70ff15f..911e58e980c 100644
--- a/jstests/core/indexapi.js
+++ b/jstests/core/indexapi.js
@@ -37,12 +37,6 @@ assert( idx[1].unique , "M3" );
//printjson( idx );
// Test that attempting to create index in an invalid namespace fails.
-if (db.getMongo().writeMode() == 'commands') {
- assert.throws(function() {
- db.system.indexes.insert( { ns : "test" , key : { x : 1 } , name : "x" } );
- });
-}
-else {
- assert.writeError(db.system.indexes.insert( { ns : "test" , key : { x : 1 } , name : "x" } ));
-}
+assert.writeError(db.system.indexes.insert( { ns : "test" , key : { x : 1 } , name : "x" } ));
+
diff --git a/jstests/core/indexi.js b/jstests/core/indexi.js
index d0e77471fda..06f185fb689 100644
--- a/jstests/core/indexi.js
+++ b/jstests/core/indexi.js
@@ -5,21 +5,12 @@ t.drop();
idx = db.jstests_indexi.$_id_;
-var expectWriteError = function(func) {
- if (db.getMongo().writeMode() == 'commands') {
- assert.throws(func);
- }
- else {
- assert.writeError(func());
- }
-};
-
// Test that accessing the index namespace fails.
function checkFailingOperations() {
assert.throws(function() { idx.find().itcount(); });
- expectWriteError(function() { return idx.insert({ x: 1 }); });
- expectWriteError(function() { return idx.update({ x: 1 }, { x: 2 }); });
- expectWriteError(function() { return idx.remove({ x: 1 }); });
+ assert.writeError( idx.insert({ x: 1 }) );
+ assert.writeError( idx.update({ x: 1 }, { x: 2 }) );
+ assert.writeError( idx.remove({ x: 1 }) );
assert.commandFailed( idx.runCommand( 'compact' ) );
assert.commandFailed( idx.ensureIndex({ x: 1 }));
}
diff --git a/jstests/core/ns_length.js b/jstests/core/ns_length.js
index 203e68ead58..557e3110195 100644
--- a/jstests/core/ns_length.js
+++ b/jstests/core/ns_length.js
@@ -21,7 +21,7 @@ function canMakeCollectionWithName(name) {
var success = false;
try {
// may either throw or return an error
- success = !(myDb[name].insert({}).hasWriteErrors());
+ success = !(myDb[name].insert({}).hasWriteError());
} catch (e) {
success = false;
}
diff --git a/jstests/core/push2.js b/jstests/core/push2.js
index ae09b20fb30..2ce34b7bf9a 100644
--- a/jstests/core/push2.js
+++ b/jstests/core/push2.js
@@ -11,7 +11,7 @@ gotError = null;
for ( x=0; x<100; x++ ){
print (x + " pushes");
var res = t.update( {} , { $push : { a : s } } );
- gotError = res.hasWriteErrors();
+ gotError = res.hasWriteError();
if ( gotError )
break;
}
diff --git a/jstests/core/remove6.js b/jstests/core/remove6.js
index 838ca1c5bfd..96c5481c813 100644
--- a/jstests/core/remove6.js
+++ b/jstests/core/remove6.js
@@ -21,7 +21,7 @@ function test( n , idx ){
if ( idx )
t.ensureIndex( idx );
var res = del();
- assert( !res.hasWriteErrors() , "error deleting: " + res.toString() );
+ assert( !res.hasWriteError() , "error deleting: " + res.toString() );
assert.eq( 0 , t.count() , n + " B " + idx );
}
diff --git a/jstests/core/removeb.js b/jstests/core/removeb.js
index 230a8de012f..1e6658bd7a9 100644
--- a/jstests/core/removeb.js
+++ b/jstests/core/removeb.js
@@ -30,7 +30,7 @@ p = startParallelShell(
// Remove using the a:1 index in ascending direction.
var res = t.remove( { a:{ $gte:0 } } );
-assert( !res.hasWriteErrors(), 'The remove operation failed.' );
+assert( !res.hasWriteError(), 'The remove operation failed.' );
p();
diff --git a/jstests/core/rename4.js b/jstests/core/rename4.js
index d6ded8cbee4..85cd5e882b5 100644
--- a/jstests/core/rename4.js
+++ b/jstests/core/rename4.js
@@ -6,7 +6,7 @@ function bad( f ) {
var res = eval( f );
//Ensure error
- if (!res.hasWriteErrors()) {
+ if (!res.hasWriteError()) {
print("Error:" + res.toString());
print("Existing docs (before)")
printjson(docsBeforeUpdate);
diff --git a/jstests/core/storefunc.js b/jstests/core/storefunc.js
index b4cda6f52f0..3b5fc1ab9ab 100644
--- a/jstests/core/storefunc.js
+++ b/jstests/core/storefunc.js
@@ -7,7 +7,7 @@ s.remove({});
assert.eq( 0 , s.count() , "setup - A" );
res = s.save( { _id : "x" , value : "3" } );
-assert( !res.hasWriteErrors() , "setup - B" );
+assert( !res.hasWriteError() , "setup - B" );
assert.eq( 1 , s.count() , "setup - C" );
s.remove( { _id : "x" } );
diff --git a/jstests/core/update_dbref.js b/jstests/core/update_dbref.js
index e978a4888c5..d4c9ed7354f 100644
--- a/jstests/core/update_dbref.js
+++ b/jstests/core/update_dbref.js
@@ -5,15 +5,15 @@ t = db.jstests_update_dbref;
t.drop();
res = t.save({_id:1, a: new DBRef("a", "b")});
-assert(!res.hasWriteErrors(), "failed to save dbref");
+assert(!res.hasWriteError(), "failed to save dbref");
assert.docEq({_id:1, a: new DBRef("a", "b")}, t.findOne());
res = t.update({}, {$set: {"a.$id": 2}});
-assert(!res.hasWriteErrors(), "a.$id update");
+assert(!res.hasWriteError(), "a.$id update");
assert.docEq({_id:1, a: new DBRef("a", 2)}, t.findOne());
res = t.update({}, {$set: {"a.$ref": "b"}});
-assert(!res.hasWriteErrors(), "a.$ref update");
+assert(!res.hasWriteError(), "a.$ref update");
assert.docEq({_id:1, a: new DBRef("b", 2)}, t.findOne());
@@ -34,7 +34,7 @@ assert(/\$db/.test(res.getWriteError()), "expected bad update because of $db");
assert.docEq({_id:1, a: new DBRef("b", 2)}, t.findOne());
res = t.update({}, {$set: {"b.$id": 2}});
-assert(res.hasWriteErrors(), "b.$id update should fail -- doc:" + tojson(t.findOne()) + " result:" + res.toString());
+assert(res.hasWriteError(), "b.$id update should fail -- doc:" + tojson(t.findOne()) + " result:" + res.toString());
res = t.update({}, {$set: {"b.$ref": 2}});
-assert(res.hasWriteErrors(), "b.$ref update should fail -- doc:" + tojson(t.findOne()) + " result:" + res.toString());
+assert(res.hasWriteError(), "b.$ref update should fail -- doc:" + tojson(t.findOne()) + " result:" + res.toString());
diff --git a/jstests/core/update_replace.js b/jstests/core/update_replace.js
index ff9312baa95..ebfe2a0bd6f 100644
--- a/jstests/core/update_replace.js
+++ b/jstests/core/update_replace.js
@@ -15,38 +15,38 @@ conn._skipValidation = true;
// Should not allow "." in field names
res = t.save({_id:1, "a.a":1})
-assert(res.hasWriteErrors(), "a.a");
+assert(res.hasWriteError(), "a.a");
// Should not allow "." in field names, embedded
res = t.save({_id:1, a :{"a.a":1}})
-assert(res.hasWriteErrors(), "a: a.a");
+assert(res.hasWriteError(), "a: a.a");
// Should not allow "$"-prefixed field names, caught before "." check
res = t.save({_id:1, $a :{"a.a":1}})
-assert(res.hasWriteErrors(), "$a: a.a");
+assert(res.hasWriteError(), "$a: a.a");
// Should not allow "$"-prefixed field names
res = t.save({_id:1, $a: 1})
-assert(res.hasWriteErrors(), "$a");
+assert(res.hasWriteError(), "$a");
// _id validation checks
// Should not allow regex _id
res = t.save({_id: /a/})
-assert(res.hasWriteErrors(), "_id regex");
+assert(res.hasWriteError(), "_id regex");
// Should not allow regex _id, even if not first
res = t.save({a:2, _id: /a/})
-assert(res.hasWriteErrors(), "a _id regex");
+assert(res.hasWriteError(), "a _id regex");
// Should not allow array _id
res = t.save({_id: [9]})
-assert(res.hasWriteErrors(), "_id array");
+assert(res.hasWriteError(), "_id array");
// This is fine since _id isn't a top level field
res = t.save({a :{ _id: [9]}})
-assert(!res.hasWriteErrors(), "embedded _id array");
+assert(!res.hasWriteError(), "embedded _id array");
// This is fine since _id isn't a top level field
res = t.save({b:1, a :{ _id: [9]}})
-assert(!res.hasWriteErrors(), "b embedded _id array");
+assert(!res.hasWriteError(), "b embedded _id array");
diff --git a/jstests/core/update_setOnInsert.js b/jstests/core/update_setOnInsert.js
index 105e3493bb7..9656ac9b48d 100644
--- a/jstests/core/update_setOnInsert.js
+++ b/jstests/core/update_setOnInsert.js
@@ -36,10 +36,10 @@ dotest( true );
t.drop();
res = t.update( {_id: 1} , { $setOnInsert: { "_id.a": new Date() } } , true );
-assert(res.hasWriteErrors(), "$setOnInsert _id.a - " + res.toString() + tojson(t.findOne()));
+assert(res.hasWriteError(), "$setOnInsert _id.a - " + res.toString() + tojson(t.findOne()));
res = t.update( {"_id.a": 4} , { $setOnInsert: { "_id.b": 1 } } , true );
-assert(res.hasWriteErrors(), "$setOnInsert _id.b - " + res.toString() + tojson(t.findOne()));
+assert(res.hasWriteError(), "$setOnInsert _id.b - " + res.toString() + tojson(t.findOne()));
res = t.update( {"_id.a": 4} , { $setOnInsert: { "_id": {a:4, b:1} } } , true );
-assert(res.hasWriteErrors(), "$setOnInsert _id 3 - " + res.toString() + tojson(t.findOne()));
+assert(res.hasWriteError(), "$setOnInsert _id 3 - " + res.toString() + tojson(t.findOne()));
diff --git a/jstests/core/updatel.js b/jstests/core/updatel.js
index 7253872232c..4f7ba0cee7b 100644
--- a/jstests/core/updatel.js
+++ b/jstests/core/updatel.js
@@ -14,7 +14,7 @@ t.drop();
// The collection is empty, forcing an upsert. In this case the query has no array position match
// to substiture for the positional operator. SERVER-4713
res = t.update( {}, { $set:{ 'a.$.b':1 } }, true );
-assert( res.hasWriteErrors(), "An error is reported." );
+assert( res.hasWriteError(), "An error is reported." );
assert.eq( 0, t.count(), "No upsert occurred." );
@@ -25,14 +25,14 @@ t.save( { _id:0 } );
// Now, with an existing document, trigger an update rather than an upsert. The query has no array
// position match to substiture for the positional operator. SERVER-6669
res = t.update( {}, { $set:{ 'a.$.b':1 } } );
-assert( res.hasWriteErrors(), "An error is reported." );
+assert( res.hasWriteError(), "An error is reported." );
assert.eq( [ { _id:0 } ], t.find().toArray(), "No update occurred." );
// Now, try with an update by _id (without a query array match).
res = t.update( { _id:0 }, { $set:{ 'a.$.b':1 } } );
-assert( res.hasWriteErrors(), "An error is reported." );
+assert( res.hasWriteError(), "An error is reported." );
assert.eq( [ { _id:0 } ], t.find().toArray(), "No update occurred." );
@@ -45,5 +45,5 @@ t.save( { _id:0, a:[ { b:{ c:1 } } ] } );
// query match for the first positional operator but not the second. Note that dollar sign
// substitution for multiple positional opertors is not implemented (SERVER-831).
res = t.update( { 'a.b.c':1 }, { $set:{ 'a.$.b.$.c':2 } } );
-assert( res.hasWriteErrors(), "An error is reported" );
+assert( res.hasWriteError(), "An error is reported" );
assert.eq( [ { _id:0, a:[ { b:{ c:1 } } ] } ], t.find().toArray(), "No update occurred." );
diff --git a/jstests/core/upsert1.js b/jstests/core/upsert1.js
index 85999a189f5..f8c97e41c84 100644
--- a/jstests/core/upsert1.js
+++ b/jstests/core/upsert1.js
@@ -44,7 +44,7 @@ db.no_id.drop();
db.createCollection("no_id", {autoIndexId:false})
l = db.no_id.update({foo:1}, {$set:{a:1}}, true)
assert( l.getUpsertedId() , "H1 - " + tojson(l) );
-assert( !l.hasWriteErrors(), "H1.5 No error expected - " + tojson(l) )
+assert( !l.hasWriteError(), "H1.5 No error expected - " + tojson(l) )
assert.eq( 0, db.no_id.getIndexes().length, "H2" );
assert.eq( 1, db.no_id.count(), "H3" );
var newDoc = db.no_id.findOne();
diff --git a/jstests/core/write_result.js b/jstests/core/write_result.js
index 47f04f00b8c..c008c5ae404 100644
--- a/jstests/core/write_result.js
+++ b/jstests/core/write_result.js
@@ -143,7 +143,7 @@ coll.remove({});
printjson( result = coll.insert([{ foo : "bar" }, { foo : "baz" }]) );
assert.eq(result.nInserted, 2);
assert(!result.hasWriteErrors());
-assert(!result.getWriteConcernError());
+assert(!result.hasWriteConcernError());
assert.eq(coll.count(), 2);
//
@@ -155,7 +155,7 @@ printjson( result = coll.insert([{ _id : id, foo : "bar" },
{ _id : id, foo : "baz" }]) );
assert.eq(result.nInserted, 1);
assert(result.hasWriteErrors());
-assert(!result.getWriteConcernError());
+assert(!result.hasWriteConcernError());
assert.eq(coll.count(), 1);
//
@@ -174,16 +174,11 @@ coll.unsetWriteConcern();
// Write concern error
// NOTE: Non-throwing write concern failures require replication to trigger
coll.remove({});
-coll.setWriteConcern({ w : "invalid" });
-assert.throws( function() {
- printjson( coll.insert({ foo : "bar" }) );
-});
+assert.writeError( coll.insert({ foo : "bar" }, { writeConcern : { w : "invalid" } }) );
if (coll.getMongo().writeMode() == "commands")
assert.eq(coll.count(), 0);
else
assert.eq(coll.count(), 1);
-coll.unsetWriteConcern();
-
diff --git a/jstests/replsets/bulk_api_wc.js b/jstests/replsets/bulk_api_wc.js
index de6be1b8d4d..e05f01cead0 100644
--- a/jstests/replsets/bulk_api_wc.js
+++ b/jstests/replsets/bulk_api_wc.js
@@ -37,7 +37,7 @@ var executeTests = function() {
bulk.insert({a:1});
bulk.insert({a:2});
bulk.insert({a:2});
- var result = bulk.execute({ w : 'invalid' });
+ var result = assert.throws( function() { bulk.execute({ w : 'invalid' }); } );
assert.eq(result.nInserted, 2);
assert.eq(result.getWriteErrors()[0].index, 2);
assert(!result.getWriteConcernError());
@@ -54,7 +54,7 @@ var executeTests = function() {
bulk.insert({a:1});
bulk.insert({a:2});
bulk.insert({a:2});
- var result = bulk.execute({ w : 'invalid' });
+ var result = assert.throws( function(){ bulk.execute({ w : 'invalid' }); } );
assert.eq(result.nInserted, 2);
assert.eq(result.getWriteErrors()[0].index, 2);
assert(result.getWriteConcernError());
@@ -69,7 +69,7 @@ var executeTests = function() {
bulk.insert({a:1});
bulk.insert({a:2});
bulk.insert({a:2});
- var result = bulk.execute({ w : 3, wtimeout : 1 });
+ var result = assert.throws( function() { bulk.execute({ w : 3, wtimeout : 1 }); } );
assert.eq(result.nInserted, 2);
assert.eq(result.getWriteErrors()[0].index, 2);
assert(result.getWriteConcernError().errInfo.wtimeout);
@@ -83,7 +83,7 @@ var executeTests = function() {
bulk.insert({a:2});
bulk.find({a:3}).upsert().updateOne({a:3});
bulk.insert({a:3});
- var result = bulk.execute({ w : 'invalid' });
+ var result = assert.throws( function(){ bulk.execute({ w : 'invalid' }); } );
assert.eq(result.nInserted, 2);
assert.eq(result.nUpserted, 1);
assert.eq(result.getUpsertedIds()[0].index, 2);
diff --git a/jstests/replsets/localhostAuthBypass.js b/jstests/replsets/localhostAuthBypass.js
index 6f00002a61b..720c77b4b00 100644
--- a/jstests/replsets/localhostAuthBypass.js
+++ b/jstests/replsets/localhostAuthBypass.js
@@ -20,18 +20,10 @@ var assertCannotRunCommands = function(mongo) {
var test = mongo.getDB("test");
assert.throws( function() { test.system.users.findOne(); });
assert.throws( function() { test.foo.findOne({ _id: 0 }); });
-
- assert.throws(function() {
- test.foo.save({ _id: 0 })
- });
-
- assert.throws(function() {
- test.foo.update({ _id: 0 }, { $set: { x: 20 }})
- });
-
- assert.throws(function() {
- test.foo.remove({ _id: 0 })
- });
+
+ assert.writeError(test.foo.save({ _id: 0 }));
+ assert.writeError(test.foo.update({ _id: 0 }, { $set: { x: 20 }}));
+ assert.writeError(test.foo.remove({ _id: 0 }));
assert.throws(function() {
test.foo.mapReduce(
diff --git a/jstests/replsets/replset7.js b/jstests/replsets/replset7.js
index c6ee3d6f943..dec1832ad58 100644
--- a/jstests/replsets/replset7.js
+++ b/jstests/replsets/replset7.js
@@ -18,7 +18,7 @@ for( i = 0; i < doccount; ++i ) {
}
assert.writeOK(bulk.execute());
-assert.writeOK(mdc.ensureIndex( { x : 1 }, { unique: true } ));
+assert.commandWorked(mdc.ensureIndex( { x : 1 }, { unique: true } ));
// add a secondary
var slave = rt.add();
diff --git a/jstests/shell_writeconcern.js b/jstests/shell_writeconcern.js
index 74247026b31..e59bd471294 100644
--- a/jstests/shell_writeconcern.js
+++ b/jstests/shell_writeconcern.js
@@ -24,7 +24,7 @@ assert.eq(undefined, collB.getWriteConcern())
assert.eq(undefined, db.getWriteConcern())
// test methods, by generating an error
-var res = assert.writeOK(collA.save({_id:1}, {writeConcern:{w:1}}));
+var res = assert.gleOK(collA.save({_id:1}, {writeConcern:{w:1}}));
if (!db.getMongo().useWriteCommands() ) {
assert.eq(1, res.n, tojson(res));
assert.eq(1, res.upserted, tojson(res));
@@ -32,41 +32,41 @@ if (!db.getMongo().useWriteCommands() ) {
assert.eq(1, res.nUpserted, tojson(res));
}
-var res = assert.writeOK(collA.update({_id:1}, {_id:1}, {writeConcern:{w:1}}));
+var res = assert.gleOK(collA.update({_id:1}, {_id:1}, {writeConcern:{w:1}}));
if (!db.getMongo().useWriteCommands() ) {
assert.eq(1, res.n, tojson(res));
} else {
assert.eq(1, res.nMatched, tojson(res));
}
-var res = assert.writeOK(collA.update({_id:1}, {_id:1}, {writeConcern:{w:1}}));
+var res = assert.gleOK(collA.update({_id:1}, {_id:1}, {writeConcern:{w:1}}));
if (!db.getMongo().useWriteCommands() ) {
assert.eq(1, res.n, tojson(res));
} else {
assert.eq(1, res.nMatched, tojson(res));
}
-var res = assert.writeOK(collA.insert({_id:2}, {writeConcern:{w:1}}));
+var res = assert.gleOK(collA.insert({_id:2}, {writeConcern:{w:1}}));
if (!db.getMongo().useWriteCommands() ) {
assert.eq(0, res.n, tojson(res));
} else {
assert.eq(1, res.nInserted, tojson(res));
}
-var res = assert.writeOK(collA.remove({_id:3}, {writeConcern:{w:1}}));
+var res = assert.gleOK(collA.remove({_id:3}, {writeConcern:{w:1}}));
if (!db.getMongo().useWriteCommands() ) {
assert.eq(0, res.n, tojson(res));
} else {
assert.eq(0, res.nRemoved, tojson(res));
}
-var res = assert.writeOK(collA.remove({}, {justOne:true, writeConcern:{w:1}}));
+var res = assert.gleOK(collA.remove({}, {justOne:true, writeConcern:{w:1}}));
if (!db.getMongo().useWriteCommands() ) {
assert.eq(1, res.n, tojson(res));
} else {
assert.eq(1, res.nRemoved, tojson(res));
}
-assert.writeError(collA.insert([{_id:1}, {_id:1}], {ordered:true, writeConcern:{w:1}}));
-assert.writeError(collA.insert([{_id:1}, {_id:1}], {ordered:false, writeConcern:{w:1}}));
+assert.gleError(collA.insert([{_id:1}, {_id:1}], {ordered:true, writeConcern:{w:1}}));
+assert.gleError(collA.insert([{_id:1}, {_id:1}], {ordered:false, writeConcern:{w:1}}));
diff --git a/src/mongo/shell/assert.js b/src/mongo/shell/assert.js
index 25bc108febd..fcd7b4e59bb 100644
--- a/src/mongo/shell/assert.js
+++ b/src/mongo/shell/assert.js
@@ -343,70 +343,103 @@ assert.closeWithinMS = function(a, b, msg, deltaMS) {
};
assert.writeOK = function(res, msg) {
- var errMsg = "";
+
+ var errMsg = null;
- if (!res)
- errMsg = "missing first argument, no response to check"
- else if (!res.getWriteConcernError) // not BulkWriteResult/SingleWriteResult.
- assert.gleOK(res, msg)
- else {
+ if (res instanceof WriteResult) {
+ if (res.hasWriteError()) {
+ errMsg = "write failed with error: " + tojson(res);
+ }
+ else if(res.hasWriteConcernError()) {
+ errMsg = "write concern failed with errors: " + tojson(res);
+ }
+ }
+ else if (res instanceof BulkWriteResult) {
+ // Can only happen with bulk inserts
if (res.hasWriteErrors()) {
- errMsg = "write failed with errors: " + tojson(res)
- } else if (res.getWriteConcernError()) {
- errMsg = "write concern failed with errors: " + tojson(res)
+ errMsg = "write failed with errors: " + tojson(res);
+ }
+ else if(res.hasWriteConcernError()) {
+ errMsg = "write concern failed with errors: " + tojson(res);
}
-
- if (errMsg != "" && msg)
- errMsg = errMsg + " : " + msg;
-
- if (errMsg)
- doassert(errMsg);
}
-
+ else if (res instanceof WriteCommandError) {
+ // Can only happen with bulk inserts
+ errMsg = "write command failed: " + tojson(res);
+ }
+ else {
+ errMsg = "unknown type of write result, cannot check ok: "
+ + tojson(res);
+ }
+
+ if (errMsg) {
+ if (msg)
+ errMsg = errMsg + ": " + msg;
+ doassert(errMsg);
+ }
+
return res;
}
-assert.gleOK = function(res, msg) {
- var errMsg = "";
-
- if (!res)
- errMsg = "missing first argument, no response to check"
- else if (!res.ok)
- errMsg = "command failed: " + tojson(res);
-
- if ('code' in res || 'errMsg' in res || 'errInfo' in res || 'writeErrors' in res)
- errMsg = "write failed: " + tojson(res);
-
- if (errMsg != "" && msg)
- errMsg = errMsg + " : " + msg;
+assert.writeError = function(res, msg) {
+
+ var errMsg = null;
- if (errMsg)
+ if (res instanceof WriteResult) {
+ if (!res.hasWriteError() && !res.hasWriteConcernError()) {
+ errMsg = "no write error: " + tojson(res);
+ }
+ }
+ else if (res instanceof BulkWriteResult) {
+ // Can only happen with bulk inserts
+ if (!res.hasWriteErrors() && !res.hasWriteConcernError()) {
+ errMsg = "no write errors: " + tojson(res);
+ }
+ }
+ else if (res instanceof WriteCommandError) {
+ // Can only happen with bulk inserts
+ // No-op since we're expecting an error
+ }
+ else {
+ errMsg = "unknown type of write result, cannot check error: "
+ + tojson(res);
+ }
+
+ if (errMsg) {
+ if (msg)
+ errMsg = errMsg + ": " + msg;
doassert(errMsg);
-
+ }
+
return res;
}
-assert.writeError = function(res, msg) {
- var errMsg = "";
+assert.gleOK = function(res, msg) {
+
+ var errMsg = null;
- if (!res)
- errMsg = "The response arg was missing or undefined! -- " + res
- else if (!res.getWriteConcernError) {
- if (!res.err)
- errMsg = "no error" + tojson(res);
- } else {
- if (!(res.hasWriteErrors() || res.getWriteConcernError()))
- errMsg = "no write errors : " + tojson(res);
+ if (!res) {
+ errMsg = "missing first argument, no response to check"
+ }
+ else if (!res.ok) {
+ errMsg = "getLastError failed: " + tojson(res);
}
- if (errMsg != "" && msg)
- errMsg = errMsg + " : " + msg;
- if (errMsg)
+ else if ('code' in res || 'errmsg' in res
+ || ('err' in res && res['err'] != null)) {
+ errMsg = "write or write concern failed: " + tojson(res);
+ }
+
+ if (errMsg) {
+ if (msg)
+ errMsg = errMsg + ": " + msg;
doassert(errMsg);
+ }
+
return res;
}
-assert.gleSuccess = function(db, msg) {
- var gle = db.getLastErrorObj();
+assert.gleSuccess = function(dbOrGLEDoc, msg) {
+ var gle = dbOrGLEDoc instanceof DB ? dbOrGLEDoc.getLastErrorObj() : dbOrGLEDoc;
if (gle.err) {
if (typeof(msg) == "function")
msg = msg(gle);
@@ -415,8 +448,8 @@ assert.gleSuccess = function(db, msg) {
return gle;
}
-assert.gleError = function(db, msg) {
- var gle = db.getLastErrorObj();
+assert.gleError = function(dbOrGLEDoc, msg) {
+ var gle = dbOrGLEDoc instanceof DB ? dbOrGLEDoc.getLastErrorObj() : dbOrGLEDoc;
if (!gle.err) {
if (typeof(msg) == "function")
msg = msg(gle);
@@ -424,8 +457,8 @@ assert.gleError = function(db, msg) {
}
}
-assert.gleErrorCode = function(db, code, msg) {
- var gle = db.getLastErrorObj();
+assert.gleErrorCode = function(dbOrGLEDoc, code, msg) {
+ var gle = dbOrGLEDoc instanceof DB ? dbOrGLEDoc.getLastErrorObj() : dbOrGLEDoc;
if (!gle.err || gle.code != code) {
if (typeof(msg) == "function")
msg = msg(gle);
@@ -434,8 +467,8 @@ assert.gleErrorCode = function(db, code, msg) {
}
}
-assert.gleErrorRegex = function(db, regex, msg) {
- var gle = db.getLastErrorObj();
+assert.gleErrorRegex = function(dbOrGLEDoc, regex, msg) {
+ var gle = dbOrGLEDoc instanceof DB ? dbOrGLEDoc.getLastErrorObj() : dbOrGLEDoc;
if (!gle.err || !regex.test(gle.err)) {
if (typeof(msg) == "function")
msg = msg(gle);
diff --git a/src/mongo/shell/bulk_api.js b/src/mongo/shell/bulk_api.js
index 2dd2bb94ff2..c99f43e7868 100644
--- a/src/mongo/shell/bulk_api.js
+++ b/src/mongo/shell/bulk_api.js
@@ -2,6 +2,7 @@
// Scope for the function
//
var _bulk_api_module = (function() {
+
// Batch types
var NONE = 0;
var INSERT = 1;
@@ -30,29 +31,84 @@ var _bulk_api_module = (function() {
}
/**
- * getLastErrorMethod that supports all write concerns
+ * Shell representation of WriteConcern, possibly includes:
+ * j: write waits for journal
+ * w: write waits until replicated to number of servers (including primary), or mode (string)
+ * wtimeout: how long to wait for "w" replication
+ * fsync: waits for data flush (either journal, nor database files depending on server conf)
+ *
+ * Accepts { w : x, j : x, wtimeout : x, fsync: x } or w, wtimeout, j
*/
- var executeGetLastError = function(db, options) {
- var cmd = { getlasterror : 1 };
- options = options || {};
-
- // Add write concern options to the command
- if(typeof(options.w) != 'undefined') cmd.w = options.w;
- if(typeof(options.wtimeout) != 'undefined') cmd.wtimeout = options.wtimeout;
- if(options.j) cmd.j = options.j;
- if(options.fsync) cmd.fsync = options.fsync;
-
- // Execute the getLastErrorCommand
- return db.runCommand( cmd );
- };
+ var WriteConcern = function(wValue, wTimeout, jValue) {
+
+ if(!(this instanceof WriteConcern))
+ return new WriteConcern(wValue, wTimeout, jValue);
+
+ var opts = {};
+ if (typeof wValue == 'object') {
+ if (arguments.length == 1)
+ opts = Object.merge(wValue);
+ else
+ throw Error("If the first arg is an Object then no additional args are allowed!")
+ } else {
+ if (typeof wValue != 'undefined')
+ opts.w = wValue;
+ if (typeof wTimeout != 'undefined')
+ opts.wtimeout = wTimeout;
+ if (typeof jValue != 'undefined')
+ opts.j = jValue;
+ }
+ // Do basic validation.
+ if (typeof opts.w != 'undefined' && typeof opts.w != 'number' && typeof opts.w != 'string')
+ throw Error("w value must be a number or string but was found to be a " + typeof opts.w)
+ if (typeof opts.w == 'number' && NumberInt( opts.w ).toNumber() < 0)
+ throw Error("Numeric w value must be equal to or larger than 0, not " + opts.w);
+
+ if (typeof opts.wtimeout != 'undefined') {
+ if (typeof opts.wtimeout != 'number')
+ throw Error("wtimeout must be a number, not " + opts.wtimeout);
+ if (NumberInt( opts.wtimeout ).toNumber() < 0)
+ throw Error("wtimeout must be a number greater than 0, not " + opts.wtimeout);
+ }
+
+ if (typeof opts.j != 'undefined' && typeof opts.j != 'boolean')
+ throw Error("j value must either true or false if defined, not " + opts.j);
+
+ this._wc = opts;
+
+ this.toJSON = function() {
+ return Object.merge({}, this._wc);
+ };
+
+ /**
+ * @return {string}
+ */
+ this.tojson = function(indent, nolint) {
+ return tojson(this.toJSON(), indent, nolint);
+ };
+
+ this.toString = function() {
+ return "WriteConcern(" + this.tojson() + ")";
+ };
+
+ this.shellPrint = function() {
+ return this.toString();
+ };
+
+ };
+
/**
* Wraps the result for write commands and presents a convenient api for accessing
* single results & errors (returns the last one if there are multiple).
- * singleBatch is passed in on bulk operations consisting of a single batch and
- * are used to filter the SingleWriteResult to only include relevant result fields.
+ * singleBatchType is passed in on bulk operations consisting of a single batch and
+ * are used to filter the WriteResult to only include relevant result fields.
*/
- var SingleWriteResult = function(bulkResult, singleBatch, writeConcern) {
+ var WriteResult = function(bulkResult, singleBatchType, writeConcern) {
+
+ if(!(this instanceof WriteResult))
+ return new WriteResult(bulkResult, singleBatchType, writeConcern);
+
// Define properties
defineReadOnlyProperty(this, "ok", bulkResult.ok);
defineReadOnlyProperty(this, "nInserted", bulkResult.nInserted);
@@ -75,14 +131,18 @@ var _bulk_api_module = (function() {
return bulkResult;
};
- this.hasWriteErrors = function() {
- return bulkResult.writeErrors.length > 0;
- };
-
this.getWriteError = function() {
- return bulkResult.writeErrors[bulkResult.writeErrors.length - 1];
+ if (bulkResult.writeErrors.length == 0) {
+ return null;
+ } else {
+ return bulkResult.writeErrors[bulkResult.writeErrors.length - 1];
+ }
};
+ this.hasWriteError = function() {
+ return this.getWriteError() != null;
+ };
+
this.getWriteConcernError = function() {
if (bulkResult.writeConcernErrors.length == 0) {
return null;
@@ -90,6 +150,10 @@ var _bulk_api_module = (function() {
return bulkResult.writeConcernErrors[0];
}
};
+
+ this.hasWriteConcernError = function() {
+ return this.getWriteConcernError() != null;
+ };
/**
* @return {string}
@@ -97,24 +161,24 @@ var _bulk_api_module = (function() {
this.tojson = function(indent, nolint) {
var result = {}
- if(singleBatch && singleBatch.batchType == INSERT) {
+ if(singleBatchType == INSERT) {
result.nInserted = this.nInserted;
}
- if(singleBatch && singleBatch.batchType == UPDATE) {
+ if(singleBatchType == UPDATE) {
result.nMatched = this.nMatched;
result.nUpserted = this.nUpserted;
-
+
if(this.nModified != undefined)
result.nModified = this.nModified;
-
+
if(Array.isArray(bulkResult.upserted)
&& bulkResult.upserted.length == 1) {
result._id = bulkResult.upserted[0]._id;
}
}
- if(singleBatch && singleBatch.batchType == REMOVE) {
+ if(singleBatchType == REMOVE) {
result.nRemoved = bulkResult.nRemoved;
}
@@ -142,16 +206,16 @@ var _bulk_api_module = (function() {
this.shellPrint = function() {
return this.toString();
};
-
- this.isOK = function() {
- return bulkResult.ok == 1;
- };
};
/**
* Wraps the result for the commands
*/
- var BulkWriteResult = function(bulkResult, singleBatch, writeConcern) {
+ var BulkWriteResult = function(bulkResult, singleBatchType, writeConcern) {
+
+ if(!(this instanceof BulkWriteResult) && !(this instanceof BulkWriteError))
+ return new BulkWriteResult(bulkResult, singleBatchType, writeConcern);
+
// Define properties
defineReadOnlyProperty(this, "ok", bulkResult.ok);
defineReadOnlyProperty(this, "nInserted", bulkResult.nInserted);
@@ -195,6 +259,10 @@ var _bulk_api_module = (function() {
return bulkResult.writeErrors;
}
+ this.hasWriteConcernError = function() {
+ return bulkResult.writeConcernErrors.length > 0;
+ }
+
this.getWriteConcernError = function() {
if(bulkResult.writeConcernErrors.length == 0) {
return null;
@@ -237,22 +305,137 @@ var _bulk_api_module = (function() {
return this.toString();
}
- this.isOK = function() {
- return bulkResult.ok == 1;
- };
+ this.hasErrors = function() {
+ return this.hasWriteErrors() || this.hasWriteConcernError();
+ }
+
+ this.toError = function() {
+ if (this.hasErrors()) {
+
+ // Create a combined error message
+ var message = "";
+ var numWriteErrors = this.getWriteErrorCount();
+ if (numWriteErrors == 1) {
+ message += "write error at item " + this.getWriteErrors()[0].index;
+ }
+ else if (numWriteErrors > 1) {
+ message += numWriteErrors + " write errors";
+ }
+
+ var hasWCError = this.hasWriteConcernError();
+ if (numWriteErrors > 0 && hasWCError) {
+ message += " and ";
+ }
+
+ if (hasWCError) {
+ message += "problem enforcing write concern";
+ }
+ message += " in bulk operation";
+
+ return new BulkWriteError(bulkResult, singleBatchType, writeConcern, message);
+ }
+ else {
+ throw Error("batch was successful, cannot create BulkWriteError");
+ }
+ }
/**
- * @return {SingleWriteResult} the simplified results condensed into one.
+ * @return {WriteResult} the simplified results condensed into one.
*/
this.toSingleResult = function() {
- if(singleBatch == null) throw Error(
- "Cannot output SingleWriteResult from multiple batch result");
- return new SingleWriteResult(bulkResult, singleBatch, writeConcern);
+ if(singleBatchType == null) throw Error(
+ "Cannot output single WriteResult from multiple batch result");
+ return new WriteResult(bulkResult, singleBatchType, writeConcern);
}
};
/**
- * Wraps the error
+ * Represents a bulk write error, identical to a BulkWriteResult but thrown
+ */
+ var BulkWriteError = function(bulkResult, singleBatchType, writeConcern, message) {
+
+ if(!(this instanceof BulkWriteError))
+ return new BulkWriteError(bulkResult, singleBatchType, writeConcern, message);
+
+ Error.captureStackTrace(this, this.constructor);
+ this.name = 'BulkWriteError';
+ this.message = message || 'unknown bulk write error';
+
+ // Bulk errors are basically bulk results with additional error information
+ BulkWriteResult.apply(this, arguments);
+
+ // Override some particular methods
+ delete this.toError;
+
+ this.toString = function() {
+ return "BulkWriteError(" + this.tojson() + ")";
+ }
+
+ this.toResult = function() {
+ return new BulkWriteResult(bulkResult, singleBatchType, writeConcern);
+ }
+ }
+
+ BulkWriteError.prototype = new Error();
+ BulkWriteError.prototype.constructor = BulkWriteError;
+
+ var getEmptyBulkResult = function() {
+ return {
+ writeErrors: []
+ , writeConcernErrors: []
+ , nInserted: 0
+ , nUpserted: 0
+ , nMatched: 0
+ , nModified: 0
+ , nRemoved: 0
+ , upserted: []
+ };
+ }
+
+ /**
+ * Wraps a command error
+ */
+ var WriteCommandError = function(commandError) {
+
+ if(!(this instanceof WriteCommandError)) return new WriteCommandError(commandError);
+
+ // Define properties
+ defineReadOnlyProperty(this, "code", commandError.code);
+ defineReadOnlyProperty(this, "errmsg", commandError.errmsg);
+
+ Error.captureStackTrace(this, this.constructor);
+ this.name = 'WriteCommandError';
+ this.message = this.errmsg;
+
+ /**
+ * @return {string}
+ */
+ this.tojson = function(indent, nolint) {
+ return tojson(commandError, indent, nolint);
+ }
+
+ this.toString = function() {
+ return "WriteCommandError(" + this.tojson() + ")";
+ }
+
+ this.shellPrint = function() {
+ return this.toString();
+ }
+
+ this.toSingleResult = function() {
+ // This is *only* safe to do with a WriteCommandError from the bulk api when the bulk is
+ // known to be of size == 1
+ var bulkResult = getEmptyBulkResult();
+ bulkResult.writeErrors.push({ code : this.code, index : 0, errmsg : this.errmsg });
+ return new BulkWriteResult(bulkResult, NONE).toSingleResult();
+ }
+ }
+
+ WriteCommandError.prototype = new Error();
+ WriteCommandError.prototype.constructor = WriteCommandError;
+
+ /**
+ * Wraps an error for a single write
*/
var WriteError = function(err) {
if(!(this instanceof WriteError)) return new WriteError(err);
@@ -329,18 +512,7 @@ var _bulk_api_module = (function() {
this.index = index;
this.operation = operation;
}
-
- /***********************************************************
- * Adds the initializers of bulk operations to the db collection
- ***********************************************************/
- DBCollection.prototype.initializeUnorderedBulkOp = function() {
- return new Bulk(this, false);
- }
-
- DBCollection.prototype.initializeOrderedBulkOp = function() {
- return new Bulk(this, true);
- }
-
+
/***********************************************************
* Wraps the operations done for the batch
***********************************************************/
@@ -356,16 +528,7 @@ var _bulk_api_module = (function() {
var currentOp;
// Final results
- var bulkResult = {
- writeErrors: []
- , writeConcernErrors: []
- , nInserted: 0
- , nUpserted: 0
- , nMatched: 0
- , nModified: 0
- , nRemoved: 0
- , upserted: []
- };
+ var bulkResult = getEmptyBulkResult();
// Current batch
var currentBatch = null;
@@ -584,17 +747,6 @@ var _bulk_api_module = (function() {
//
// Merge write command result into aggregated results object
var mergeBatchResults = function(batch, bulkResult, result) {
- //
- // NEEDED to pass tests as some write errors are
- // returned as write concern errors (j write on non journal mongod)
- // also internal error code 75 is still making it out as a write concern error
- //
- if(ordered && result && result.writeConcernError
- && (result.writeConcernError.code == 2 || result.writeConcernError.code == 75)) {
- throw Error(
- "legacy batch failed, cannot aggregate results: "
- + result.writeConcernError.errmsg);
- }
// If we have an insert Batch type
if(batch.batchType == INSERT) {
@@ -658,7 +810,7 @@ var _bulk_api_module = (function() {
bulkResult.writeConcernErrors.push(new WriteConcernError(result.writeConcernError));
}
}
-
+
//
// Execute the batch
var executeBatch = function(batch) {
@@ -696,14 +848,13 @@ var _bulk_api_module = (function() {
0 /* flags */).next();
if(result.ok == 0) {
- throw Error(
- "batch failed, cannot aggregate results: " + result.errmsg);
+ throw new WriteCommandError(result);
}
// Merge the results
mergeBatchResults(batch, bulkResult, result);
}
-
+
// Execute a single legacy op
var executeLegacyOp = function(_legacyOp) {
// Handle the different types of operation types
@@ -758,7 +909,7 @@ var _bulk_api_module = (function() {
var code = gleResponse.code;
var timeout = gleResponse.wtimeout? true : false;
- var extractedErr = { writeError: null, wcError: null };
+ var extractedErr = { writeError: null, wcError: null, unknownError: null };
if (err == 'norepl' || err == 'noreplset') {
// Know this is legacy gle and the repl not enforced - write concern error in 2.4.
@@ -802,7 +953,11 @@ var _bulk_api_module = (function() {
};
}
else if (!isOK) {
- throw Error('Unexpected error from getLastError: ' + tojson(gleResponse));
+ // This is a GLE failure we don't understand
+ extractedErr.unknownError = {
+ code: code
+ , errmsg: errMsg
+ }
}
else if (err != '') {
extractedErr.writeError = {
@@ -821,6 +976,16 @@ var _bulk_api_module = (function() {
return extractedErr;
};
+ /**
+ * getLastErrorMethod that supports all write concerns
+ */
+ var executeGetLastError = function(db, options) {
+ var cmd = { getlasterror : 1 };
+ cmd = Object.extend(cmd, options);
+ // Execute the getLastErrorCommand
+ return db.runCommand( cmd );
+ };
+
// Execute the operations, serially
var executeBatchWithLegacyOps = function(batch) {
@@ -830,7 +995,7 @@ var _bulk_api_module = (function() {
, upserted: []
};
- var extractedError = null;
+ var extractedErr = null;
var totalToExecute = batch.operations.length;
// Run over all the operations
@@ -842,14 +1007,22 @@ var _bulk_api_module = (function() {
executeLegacyOp(_legacyOp);
var result = executeGetLastError(collection.getDB(), { w: 1 });
- extractedError = extractGLEErrors(result);
+ extractedErr = extractGLEErrors(result);
+
+ if (extractedErr.unknownError) {
+ throw new WriteCommandError({
+ ok : 0.0
+ , code : extractedErr.unknownError.code
+ , errmsg : extractedErr.unknownError.errmsg
+ });
+ }
- if (extractedError.writeError != null) {
+ if (extractedErr.writeError != null) {
// Create the emulated result set
var errResult = {
index: _legacyOp.index
- , code: extractedError.writeError.code
- , errmsg: extractedError.writeError.errmsg
+ , code: extractedErr.writeError.code
+ , errmsg: extractedErr.writeError.errmsg
, op: batch.operations[_legacyOp.index]
};
@@ -881,6 +1054,7 @@ var _bulk_api_module = (function() {
bsonWoCompare(writeConcern, { w: 1 }) != 0 &&
bsonWoCompare(writeConcern, { w: 0 }) != 0;
+ extractedErr = null;
if (needToEnforceWC &&
(batchResult.writeErrors.length == 0 ||
(!ordered &&
@@ -897,11 +1071,16 @@ var _bulk_api_module = (function() {
}
result = executeGetLastError(collection.getDB(), writeConcern);
- extractedError = extractGLEErrors(result);
+ extractedErr = extractGLEErrors(result);
+
+ if (extractedErr.unknownError) {
+ // Report as a wc failure
+ extractedErr.wcError = extractedErr.unknownError;
+ }
}
- if (extractedError != null && extractedError.wcError != null) {
- bulkResult.writeConcernErrors.push(extractedError.wcError);
+ if (extractedErr != null && extractedErr.wcError != null) {
+ bulkResult.writeConcernErrors.push(extractedErr.wcError);
}
// Merge the results
@@ -930,7 +1109,7 @@ var _bulk_api_module = (function() {
for(var i = 0; i < batches.length; i++) {
// Execute the batch
- if(collection.getMongo().hasWriteCommands() &&
+ if(collection.getMongo().hasWriteCommands() &&
collection.getMongo().writeMode() == "commands") {
executeBatch(batches[i]);
} else {
@@ -949,84 +1128,50 @@ var _bulk_api_module = (function() {
// Set as executed
executed = true;
- if(batches.length == 1) {
- return new BulkWriteResult(bulkResult, batches[0], writeConcern);
+ // Create final result object
+ typedResult = new BulkWriteResult(bulkResult,
+ batches.length == 1 ? batches[0].batchType : null,
+ writeConcern);
+ // Throw on error
+ if (typedResult.hasErrors()) {
+ throw typedResult.toError();
}
- // Execute the batch and return the final results
- return new BulkWriteResult(bulkResult, null, writeConcern);
+ return typedResult;
}
}
-})();
-
-if ( ( typeof WriteConcern ) == 'undefined' ){
- /**
- * Shell representation of WriteConcern, possibly includes:
- * j: write waits for journal
- * w: write waits for replicated to number of servers (including primary), or mode (string)
- * wtimeout: how long to wait for "w" replication
- * fsync: waits for data flush (either journal, nor database files depending on server conf)
- *
- * Accepts { w : x, j : x, wtimeout : x, fsync: x } or w, wtimeout, j
- */
- WriteConcern = function(wValue, wTimeout, jValue) {
-
- var opts = {};
- if (typeof wValue == 'object') {
- if (typeof jValue == 'undefined' && typeof wTimeout == 'undefined')
- opts = Object.merge(wValue);
- else
- throw Error("If the first arg is an Object then no additional args are allowed!")
- } else {
- if (typeof wValue != 'undefined')
- opts.w = wValue;
- if (typeof wTimeout != 'undefined')
- opts.wtimeout = wTimeout;
- if (typeof jValue != 'undefined')
- opts.j = jValue;
- }
+ //
+ // Exports
+ //
+
+ module = {};
+ module.WriteConcern = WriteConcern;
+ module.WriteResult = WriteResult;
+ module.BulkWriteResult = BulkWriteResult;
+ module.BulkWriteError = BulkWriteError;
+ module.WriteCommandError = WriteCommandError;
+ module.initializeUnorderedBulkOp = function() {
+ return new Bulk(this, false);
+ };
+ module.initializeOrderedBulkOp = function() {
+ return new Bulk(this, true);
+ };
- // Do basic validation.
- if (typeof opts.w != 'undefined' && typeof opts.w != 'number' && typeof opts.w != 'string')
- throw Error("w value must be a number or string but was found to be a " + typeof opts.w)
- if (typeof opts.w == 'number' && NumberInt( opts.w ).toNumber() < 0)
- throw Error("Numeric w value must be equal to or larger than 0, not " + opts.w);
-
- if (typeof opts.wtimeout != 'undefined') {
- if (typeof opts.wtimeout != 'number')
- throw Error("wtimeout must be a number, not " + opts.wtimeout);
- if (NumberInt( opts.wtimeout ).toNumber() < 0)
- throw Error("wtimeout must be a number greater than 0, not " + opts.wtimeout);
- }
-
- if (typeof opts.j != 'undefined' && typeof opts.j != 'boolean')
- throw Error("j value must either true or false if defined, not " + opts.j);
-
- this._wc = opts;
- };
+ return module;
- /**
- * @return {object} the object representation of this object. Use tojson (small caps) to get
- * the string representation instead.
- */
- WriteConcern.prototype.toJSON = function() {
- return Object.merge({}, this._wc);
- };
+})();
- /**
- * @return {string} the string representation of this object. Use toJSON (capitalized) to get
- * the object representation instead.
- */
- WriteConcern.prototype.tojson = function(indent, nolint) {
- return tojson(this.toJSON(), indent, nolint);
- };
+// Globals
+WriteConcern = _bulk_api_module.WriteConcern;
+WriteResult = _bulk_api_module.WriteResult;
+BulkWriteResult = _bulk_api_module.BulkWriteResult;
+BulkWriteError = _bulk_api_module.BulkWriteError;
+WriteCommandError = _bulk_api_module.WriteCommandError;
- WriteConcern.prototype.toString = function() {
- return "WriteConcern(" + this.tojson() + ")";
- };
+/***********************************************************
+ * Adds the initializers of bulk operations to the db collection
+ ***********************************************************/
+DBCollection.prototype.initializeUnorderedBulkOp = _bulk_api_module.initializeUnorderedBulkOp;
+DBCollection.prototype.initializeOrderedBulkOp = _bulk_api_module.initializeOrderedBulkOp;
- WriteConcern.prototype.shellPrint = function() {
- return this.toString();
- };
-}
diff --git a/src/mongo/shell/collection.js b/src/mongo/shell/collection.js
index f112325744c..dc6248a5111 100644
--- a/src/mongo/shell/collection.js
+++ b/src/mongo/shell/collection.js
@@ -229,20 +229,35 @@ DBCollection.prototype.insert = function( obj , options, _allow_dot ){
if ( this.getMongo().writeMode() != "legacy" ) {
// Bit 1 of option flag is continueOnError. Bit 0 (stop on error) is the default.
- var batch = ordered ? this.initializeOrderedBulkOp() : this.initializeUnorderedBulkOp();
+ var bulk = ordered ? this.initializeOrderedBulkOp() : this.initializeUnorderedBulkOp();
+ var isMultiInsert = Array.isArray(obj);
- if (Array.isArray(obj)) {
+ if (isMultiInsert) {
obj.forEach(function(doc) {
- batch.insert(doc);
+ bulk.insert(doc);
});
- // Do not return a SingleWriteResult if inserting an array
- result = batch.execute(wc);
}
else {
- batch.insert(obj);
- result = batch.execute(wc).toSingleResult();
+ bulk.insert(obj);
}
+ try {
+ result = bulk.execute(wc);
+ if (!isMultiInsert)
+ result = result.toSingleResult();
+ }
+ catch( ex ) {
+ if ( ex instanceof BulkWriteError ) {
+ result = isMultiInsert ? ex.toResult() : ex.toSingleResult();
+ }
+ else if ( ex instanceof WriteCommandError ) {
+ result = isMultiInsert ? ex : ex.toSingleResult();
+ }
+ else {
+ // Other exceptions thrown
+ throw ex;
+ }
+ }
}
else {
if ( ! _allow_dot ) {
@@ -292,14 +307,14 @@ DBCollection.prototype.remove = function( t , justOne ){
wc = opts.writeConcern;
justOne = opts.justOne;
}
-
+
if (!wc)
wc = this.getWriteConcern();
if ( this.getMongo().writeMode() != "legacy" ) {
var query = (typeof(t) == 'undefined')? {} : this._massageObject(t);
- var batch = this.initializeOrderedBulkOp();
- var removeOp = batch.find(query);
+ var bulk = this.initializeOrderedBulkOp();
+ var removeOp = bulk.find(query);
if (justOne) {
removeOp.removeOne();
@@ -308,7 +323,18 @@ DBCollection.prototype.remove = function( t , justOne ){
removeOp.remove();
}
- result = batch.execute(wc).toSingleResult();
+ try {
+ result = bulk.execute(wc).toSingleResult();
+ }
+ catch( ex ) {
+ if ( ex instanceof BulkWriteError || ex instanceof WriteCommandError ) {
+ result = ex.toSingleResult();
+ }
+ else {
+ // Other exceptions thrown
+ throw ex;
+ }
+ }
}
else {
this._validateRemoveDoc(t);
@@ -364,8 +390,8 @@ DBCollection.prototype.update = function( query , obj , upsert , multi ){
wc = this.getWriteConcern();
if ( this.getMongo().writeMode() != "legacy" ) {
- var batch = this.initializeOrderedBulkOp();
- var updateOp = batch.find(query);
+ var bulk = this.initializeOrderedBulkOp();
+ var updateOp = bulk.find(query);
if (upsert) {
updateOp = updateOp.upsert();
@@ -378,7 +404,18 @@ DBCollection.prototype.update = function( query , obj , upsert , multi ){
updateOp.updateOne(obj);
}
- result = batch.execute(wc).toSingleResult();
+ try {
+ result = bulk.execute(wc).toSingleResult();
+ }
+ catch( ex ) {
+ if ( ex instanceof BulkWriteError || ex instanceof WriteCommandError ) {
+ result = ex.toSingleResult();
+ }
+ else {
+ // Other exceptions thrown
+ throw ex;
+ }
+ }
}
else {
this._validateUpdateDoc(obj);