Fix collection driver upsert callbacks.

Run a bunch of upsert tests on the direct collections (LocalCollection and
MongoConnection). Revealed a weirdness with MongoConnection.upsert(); if there
is no id from the selector or modifier, then mongo ends up generating one and we
don't return it.
This commit is contained in:
Emily Stark
2013-10-02 23:00:23 -07:00
parent c20db8d328
commit d3ec00c3ef
3 changed files with 306 additions and 252 deletions

View File

@@ -637,7 +637,7 @@ LocalCollection.prototype.upsert = function (selector, mod, options, callback) {
return self.update(selector, mod, _.extend({}, options, {
upsert: true,
_returnObject: true
}, callback));
}), callback);
};
LocalCollection.prototype._modifyAndNotify = function (

View File

@@ -489,6 +489,9 @@ _.each(["insert", "update", "remove"], function (method) {
};
});
// XXX MongoConnection.upsert() does not return the id of the inserted document
// unless you set it explicitly in the selector or modifier (as a replacement
// doc).
MongoConnection.prototype.upsert = function (collectionName, selector, mod,
options, callback) {
var self = this;
@@ -501,7 +504,7 @@ MongoConnection.prototype.upsert = function (collectionName, selector, mod,
_.extend({}, options, {
upsert: true,
_returnObject: true
}, callback));
}), callback);
};
MongoConnection.prototype.find = function (collectionName, selector, options) {

View File

@@ -30,8 +30,8 @@ var stripId = function (obj) {
delete obj._id;
};
var compareResults = function (test, useUpdate, actual, expected) {
if (useUpdate) {
var compareResults = function (test, skipIds, actual, expected) {
if (skipIds) {
_.map(actual, stripId);
_.map(expected, stripId);
}
@@ -1057,291 +1057,343 @@ if (Meteor.isServer) {
// over the network.
_.each(Meteor.isServer ? [true, false] : [true], function (minimongo) {
_.each([true, false], function (useUpdate) {
Tinytest.add("mongo-livedata - " + (useUpdate ? "update " : "") + "upsert" + (minimongo ? " minimongo" : "") + ", " + idGeneration, function (test) {
var run = test.runId();
var options = collectionOptions;
if (minimongo)
options = _.extend({}, collectionOptions, { connection: null });
var coll = new Meteor.Collection("livedata_upsert_collection_"+run, options);
_.each([true, false], function (useDirectCollection) {
Tinytest.add("mongo-livedata - " + (useUpdate ? "update " : "") + "upsert" + (minimongo ? " minimongo" : "") + (useDirectCollection ? " direct collection " : "") + ", " + idGeneration, function (test) {
var run = test.runId();
var options = collectionOptions;
// We don't get ids back when we use update() to upsert, or when we are
// directly calling MongoConnection.upsert().
var skipIds = useUpdate || (! minimongo && useDirectCollection);
if (minimongo)
options = _.extend({}, collectionOptions, { connection: null });
var coll = new Meteor.Collection(
"livedata_upsert_collection_"+run+
(useUpdate ? "_update_" : "") +
(minimongo ? "_minimongo_" : "") +
(useDirectCollection ? "_direct_" : "") + "",
options
);
if (useDirectCollection)
coll = coll._collection;
var result1 = upsert(coll, useUpdate, {foo: 'bar'}, {foo: 'bar'});
test.equal(result1.numberAffected, 1);
if (! useUpdate)
test.isTrue(result1.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{foo: 'bar', _id: result1.insertedId}]);
var result1 = upsert(coll, useUpdate, {foo: 'bar'}, {foo: 'bar'});
test.equal(result1.numberAffected, 1);
if (! skipIds)
test.isTrue(result1.insertedId);
compareResults(test, skipIds, coll.find().fetch(), [{foo: 'bar', _id: result1.insertedId}]);
var result2 = upsert(coll, useUpdate, {foo: 'bar'}, {foo: 'baz'});
test.equal(result2.numberAffected, 1);
if (! useUpdate)
test.isFalse(result2.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{foo: 'baz', _id: result1.insertedId}]);
var result2 = upsert(coll, useUpdate, {foo: 'bar'}, {foo: 'baz'});
test.equal(result2.numberAffected, 1);
if (! skipIds)
test.isFalse(result2.insertedId);
compareResults(test, skipIds, coll.find().fetch(), [{foo: 'baz', _id: result1.insertedId}]);
coll.remove({});
coll.remove({});
// Test values that require transformation to go into Mongo:
// Test values that require transformation to go into Mongo:
var t1 = new Meteor.Collection.ObjectID();
var t2 = new Meteor.Collection.ObjectID();
var result3 = upsert(coll, useUpdate, {foo: t1}, {foo: t1});
test.equal(result3.numberAffected, 1);
if (! useUpdate)
test.isTrue(result3.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{foo: t1, _id: result3.insertedId}]);
var t1 = new Meteor.Collection.ObjectID();
var t2 = new Meteor.Collection.ObjectID();
var result3 = upsert(coll, useUpdate, {foo: t1}, {foo: t1});
test.equal(result3.numberAffected, 1);
if (! skipIds)
test.isTrue(result3.insertedId);
compareResults(test, skipIds, coll.find().fetch(), [{foo: t1, _id: result3.insertedId}]);
var result4 = upsert(coll, useUpdate, {foo: t1}, {foo: t2});
test.equal(result2.numberAffected, 1);
if (! useUpdate)
test.isFalse(result2.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{foo: t2, _id: result3.insertedId}]);
var result4 = upsert(coll, useUpdate, {foo: t1}, {foo: t2});
test.equal(result2.numberAffected, 1);
if (! skipIds)
test.isFalse(result2.insertedId);
compareResults(test, skipIds, coll.find().fetch(), [{foo: t2, _id: result3.insertedId}]);
coll.remove({});
coll.remove({});
// Test modification by upsert
// Test modification by upsert
var result5 = upsert(coll, useUpdate, {name: 'David'}, {$set: {foo: 1}});
test.equal(result5.numberAffected, 1);
if (! useUpdate)
test.isTrue(result5.insertedId);
var davidId = result5.insertedId;
compareResults(test, useUpdate, coll.find().fetch(), [{name: 'David', foo: 1, _id: davidId}]);
var result5 = upsert(coll, useUpdate, {name: 'David'}, {$set: {foo: 1}});
test.equal(result5.numberAffected, 1);
if (! skipIds)
test.isTrue(result5.insertedId);
var davidId = result5.insertedId;
compareResults(test, skipIds, coll.find().fetch(), [{name: 'David', foo: 1, _id: davidId}]);
test.throws(function () {
// test that bad modifier fails fast
upsert(coll, useUpdate, {name: 'David'}, {$blah: {foo: 2}});
test.throws(function () {
// test that bad modifier fails fast
upsert(coll, useUpdate, {name: 'David'}, {$blah: {foo: 2}});
});
var result6 = upsert(coll, useUpdate, {name: 'David'}, {$set: {foo: 2}});
test.equal(result6.numberAffected, 1);
if (! skipIds)
test.isFalse(result6.insertedId);
compareResults(test, skipIds, coll.find().fetch(), [{name: 'David', foo: 2,
_id: result5.insertedId}]);
var emilyId = coll.insert({name: 'Emily', foo: 2});
compareResults(test, skipIds, coll.find().fetch(), [{name: 'David', foo: 2, _id: davidId},
{name: 'Emily', foo: 2, _id: emilyId}]);
// multi update by upsert
var result7 = upsert(coll, useUpdate, {foo: 2},
{$set: {bar: 7},
$setOnInsert: {name: 'Fred', foo: 2}},
{multi: true});
test.equal(result7.numberAffected, 2);
if (! skipIds)
test.isFalse(result7.insertedId);
compareResults(test, skipIds, coll.find().fetch(), [{name: 'David', foo: 2, bar: 7, _id: davidId},
{name: 'Emily', foo: 2, bar: 7, _id: emilyId}]);
// insert by multi upsert
var result8 = upsert(coll, useUpdate, {foo: 3},
{$set: {bar: 7},
$setOnInsert: {name: 'Fred', foo: 2}},
{multi: true});
test.equal(result8.numberAffected, 1);
if (! skipIds)
test.isTrue(result8.insertedId);
var fredId = result8.insertedId;
compareResults(test, skipIds, coll.find().fetch(),
[{name: 'David', foo: 2, bar: 7, _id: davidId},
{name: 'Emily', foo: 2, bar: 7, _id: emilyId},
{name: 'Fred', foo: 2, bar: 7, _id: fredId}]);
// test `insertedId` option
var result9 = upsert(coll, useUpdate, {name: 'Steve'},
{name: 'Steve'},
{insertedId: 'steve'});
test.equal(result9.numberAffected, 1);
if (! skipIds)
test.equal(result9.insertedId, 'steve');
compareResults(test, skipIds, coll.find().fetch(),
[{name: 'David', foo: 2, bar: 7, _id: davidId},
{name: 'Emily', foo: 2, bar: 7, _id: emilyId},
{name: 'Fred', foo: 2, bar: 7, _id: fredId},
{name: 'Steve', _id: 'steve'}]);
test.isTrue(coll.findOne('steve'));
test.isFalse(coll.findOne('fred'));
// Test $ operator in selectors.
var result10 = upsert(coll, useUpdate,
{$or: [{name: 'David'}, {name: 'Emily'}]},
{$set: {foo: 3}}, {multi: true});
test.equal(result10.numberAffected, 2);
if (! skipIds)
test.isFalse(result10.insertedId);
compareResults(test, skipIds,
[coll.findOne({name: 'David'}), coll.findOne({name: 'Emily'})],
[{name: 'David', foo: 3, bar: 7, _id: davidId},
{name: 'Emily', foo: 3, bar: 7, _id: emilyId}]
);
var result11 = upsert(
coll, useUpdate,
{
name: 'Charlie',
$or: [{ foo: 2}, { bar: 7 }]
},
{ $set: { foo: 3 } }
);
test.equal(result11.numberAffected, 1);
if (! skipIds)
test.isTrue(result11.insertedId);
var charlieId = result11.insertedId;
compareResults(test, skipIds,
coll.find({ name: 'Charlie' }).fetch(),
[{name: 'Charlie', foo: 3, _id: charlieId}]);
});
var result6 = upsert(coll, useUpdate, {name: 'David'}, {$set: {foo: 2}});
test.equal(result6.numberAffected, 1);
if (! useUpdate)
test.isFalse(result6.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{name: 'David', foo: 2,
_id: result5.insertedId}]);
var emilyId = coll.insert({name: 'Emily', foo: 2});
compareResults(test, useUpdate, coll.find().fetch(), [{name: 'David', foo: 2, _id: davidId},
{name: 'Emily', foo: 2, _id: emilyId}]);
// multi update by upsert
var result7 = upsert(coll, useUpdate, {foo: 2},
{$set: {bar: 7},
$setOnInsert: {name: 'Fred', foo: 2}},
{multi: true});
test.equal(result7.numberAffected, 2);
if (! useUpdate)
test.isFalse(result7.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{name: 'David', foo: 2, bar: 7, _id: davidId},
{name: 'Emily', foo: 2, bar: 7, _id: emilyId}]);
// insert by multi upsert
var result8 = upsert(coll, useUpdate, {foo: 3},
{$set: {bar: 7},
$setOnInsert: {name: 'Fred', foo: 2}},
{multi: true});
test.equal(result8.numberAffected, 1);
if (! useUpdate)
test.isTrue(result8.insertedId);
var fredId = result8.insertedId;
compareResults(test, useUpdate, coll.find().fetch(),
[{name: 'David', foo: 2, bar: 7, _id: davidId},
{name: 'Emily', foo: 2, bar: 7, _id: emilyId},
{name: 'Fred', foo: 2, bar: 7, _id: fredId}]);
// test `insertedId` option
var result9 = upsert(coll, useUpdate, {name: 'Steve'},
{name: 'Steve'},
{insertedId: 'steve'});
test.equal(result9.numberAffected, 1);
if (! useUpdate)
test.equal(result9.insertedId, 'steve');
compareResults(test, useUpdate, coll.find().fetch(),
[{name: 'David', foo: 2, bar: 7, _id: davidId},
{name: 'Emily', foo: 2, bar: 7, _id: emilyId},
{name: 'Fred', foo: 2, bar: 7, _id: fredId},
{name: 'Steve', _id: 'steve'}]);
test.isTrue(coll.findOne('steve'));
test.isFalse(coll.findOne('fred'));
// Test $ operator in selectors.
var result10 = upsert(coll, useUpdate,
{$or: [{name: 'David'}, {name: 'Emily'}]},
{$set: {foo: 3}}, {multi: true});
test.equal(result10.numberAffected, 2);
if (! useUpdate)
test.isFalse(result10.insertedId);
compareResults(test, useUpdate,
[coll.findOne({name: 'David'}), coll.findOne({name: 'Emily'})],
[{name: 'David', foo: 3, bar: 7, _id: davidId},
{name: 'Emily', foo: 3, bar: 7, _id: emilyId}]
);
var result11 = upsert(
coll, useUpdate,
{
name: 'Charlie',
$or: [{ foo: 2}, { bar: 7 }]
},
{ $set: { foo: 3 } }
);
test.equal(result11.numberAffected, 1);
if (! useUpdate)
test.isTrue(result11.insertedId);
var charlieId = result11.insertedId;
compareResults(test, useUpdate,
coll.find({ name: 'Charlie' }).fetch(),
[{name: 'Charlie', foo: 3, _id: charlieId}]);
});
});
});
var asyncUpsertTestName = function (useNetwork, useDirectCollection,
useUpdate, idGeneration) {
return "mongo-livedata - async " +
(useUpdate ? "update " : "") +
"upsert " +
(useNetwork ? "over network " : "") +
(useDirectCollection ? ", direct collection " : "") +
idGeneration;
};
// This is a duplicate of the test above, with some changes to make it work for
// async upserts that go over the network.
if (Meteor.isClient) {
_.each([true, false], function (useUpdate) {
Tinytest.addAsync("mongo-livedata - async " + (useUpdate ? "update " : "") + "upsert" + ", " + idGeneration, function (test, onComplete) {
var coll;
var run = test.runId();
var collName = "livedata_upsert_collection_"+run;
Meteor.call("createInsecureCollection", collName, collectionOptions);
coll = new Meteor.Collection(collName, collectionOptions);
Meteor.subscribe("c-" + collName);
var result1;
var next1 = function (err, result) {
result1 = result;
test.equal(result1.numberAffected, 1);
if (! useUpdate) {
test.isTrue(result1.insertedId);
test.equal(result1.insertedId, 'foo');
// callback style. On the client, we test server-backed and in-memory
// collections, and run the tests for both the Meteor.Collection and the
// LocalCollection. On the server, we test mongo-backed collections, for both
// the Meteor.Collection and the MongoConnection.
_.each(Meteor.isServer ? [false] : [true, false], function (useNetwork) {
_.each(useNetwork ? [false] : [true, false], function (useDirectCollection) {
_.each([true, false], function (useUpdate) {
Tinytest.addAsync(asyncUpsertTestName(useNetwork, useDirectCollection, useUpdate, idGeneration), function (test, onComplete) {
var coll;
var run = test.runId();
var collName = "livedata_upsert_collection_"+run+
(useUpdate ? "_update_" : "") +
(useNetwork ? "_network_" : "") +
(useDirectCollection ? "_direct_" : "");
if (useNetwork) {
Meteor.call("createInsecureCollection", collName, collectionOptions);
coll = new Meteor.Collection(collName, collectionOptions);
Meteor.subscribe("c-" + collName);
} else {
var opts = _.clone(collectionOptions);
if (Meteor.isClient)
opts.connection = null;
coll = new Meteor.Collection(collName, opts);
if (useDirectCollection)
coll = coll._collection;
}
compareResults(test, useUpdate, coll.find().fetch(), [{foo: 'bar', _id: 'foo'}]);
upsert(coll, useUpdate, {_id: 'foo'}, {foo: 'baz'}, next2);
};
// Test starts here.
upsert(coll, useUpdate, {_id: 'foo'}, {_id: 'foo', foo: 'bar'}, next1);
var result1;
var next1 = function (err, result) {
result1 = result;
test.equal(result1.numberAffected, 1);
if (! useUpdate) {
test.isTrue(result1.insertedId);
test.equal(result1.insertedId, 'foo');
}
compareResults(test, useUpdate, coll.find().fetch(), [{foo: 'bar', _id: 'foo'}]);
upsert(coll, useUpdate, {_id: 'foo'}, {foo: 'baz'}, next2);
};
var t1, t2, result2;
var next2 = function (err, result) {
result2 = result;
test.equal(result2.numberAffected, 1);
if (! useUpdate)
test.isFalse(result2.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{foo: 'baz', _id: result1.insertedId}]);
coll.remove({_id: 'foo'});
compareResults(test, useUpdate, coll.find().fetch(), []);
// Test starts here.
upsert(coll, useUpdate, {_id: 'foo'}, {_id: 'foo', foo: 'bar'}, next1);
// Test values that require transformation to go into Mongo:
var t1, t2, result2;
var next2 = function (err, result) {
result2 = result;
test.equal(result2.numberAffected, 1);
if (! useUpdate)
test.isFalse(result2.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{foo: 'baz', _id: result1.insertedId}]);
coll.remove({_id: 'foo'});
compareResults(test, useUpdate, coll.find().fetch(), []);
t1 = new Meteor.Collection.ObjectID();
t2 = new Meteor.Collection.ObjectID();
upsert(coll, useUpdate, {_id: t1}, {_id: t1, foo: 'bar'}, next3);
};
// Test values that require transformation to go into Mongo:
var result3;
var next3 = function (err, result) {
result3 = result;
test.equal(result3.numberAffected, 1);
if (! useUpdate) {
test.isTrue(result3.insertedId);
test.equal(t1, result3.insertedId);
}
compareResults(test, useUpdate, coll.find().fetch(), [{_id: t1, foo: 'bar'}]);
t1 = new Meteor.Collection.ObjectID();
t2 = new Meteor.Collection.ObjectID();
upsert(coll, useUpdate, {_id: t1}, {_id: t1, foo: 'bar'}, next3);
};
upsert(coll, useUpdate, {_id: t1}, {foo: t2}, next4);
};
var result3;
var next3 = function (err, result) {
result3 = result;
test.equal(result3.numberAffected, 1);
if (! useUpdate) {
test.isTrue(result3.insertedId);
test.equal(t1, result3.insertedId);
}
compareResults(test, useUpdate, coll.find().fetch(), [{_id: t1, foo: 'bar'}]);
var next4 = function (err, result4) {
test.equal(result2.numberAffected, 1);
if (! useUpdate)
test.isFalse(result2.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{foo: t2, _id: result3.insertedId}]);
upsert(coll, useUpdate, {_id: t1}, {foo: t2}, next4);
};
coll.remove({_id: t1});
var next4 = function (err, result4) {
test.equal(result2.numberAffected, 1);
if (! useUpdate)
test.isFalse(result2.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{foo: t2, _id: result3.insertedId}]);
// Test modification by upsert
upsert(coll, useUpdate, {_id: 'David'}, {$set: {foo: 1}}, next5);
};
coll.remove({_id: t1});
var result5;
var next5 = function (err, result) {
result5 = result;
test.equal(result5.numberAffected, 1);
if (! useUpdate) {
test.isTrue(result5.insertedId);
test.equal(result5.insertedId, 'David');
}
var davidId = result5.insertedId;
compareResults(test, useUpdate, coll.find().fetch(), [{foo: 1, _id: davidId}]);
// Test modification by upsert
upsert(coll, useUpdate, {_id: 'David'}, {$set: {foo: 1}}, next5);
};
// test that bad modifier fails
// The stub throws an exception about the invalid modifier, which
// livedata logs (so we suppress it).
Meteor._suppress_log(1);
upsert(coll, useUpdate, {_id: 'David'}, {$blah: {foo: 2}}, function (err) {
test.isTrue(err);
upsert(coll, useUpdate, {_id: 'David'}, {$set: {foo: 2}}, next6);
});
};
var result5;
var next5 = function (err, result) {
result5 = result;
test.equal(result5.numberAffected, 1);
if (! useUpdate) {
test.isTrue(result5.insertedId);
test.equal(result5.insertedId, 'David');
}
var davidId = result5.insertedId;
compareResults(test, useUpdate, coll.find().fetch(), [{foo: 1, _id: davidId}]);
var result6;
var next6 = function (err, result) {
result6 = result;
test.equal(result6.numberAffected, 1);
if (! useUpdate)
test.isFalse(result6.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{_id: 'David', foo: 2}]);
if (! Meteor.isClient && useDirectCollection) {
// test that bad modifier fails
// The stub throws an exception about the invalid modifier, which
// livedata logs (so we suppress it).
Meteor._suppress_log(1);
upsert(coll, useUpdate, {_id: 'David'}, {$blah: {foo: 2}}, function (err) {
if (! (Meteor.isClient && useDirectCollection))
test.isTrue(err);
upsert(coll, useUpdate, {_id: 'David'}, {$set: {foo: 2}}, next6);
});
} else {
// XXX skip this test for now for LocalCollection; the fact that
// we're in a nested sequence of callbacks means we're inside a
// Meteor.defer, which means the exception just gets
// logged. Something should be done about this at some point? Maybe
// LocalCollection callbacks don't really have to be deferred.
upsert(coll, useUpdate, {_id: 'David'}, {$set: {foo: 2}}, next6);
}
};
var emilyId = coll.insert({_id: 'Emily', foo: 2});
compareResults(test, useUpdate, coll.find().fetch(), [{_id: 'David', foo: 2},
{_id: 'Emily', foo: 2}]);
var result6;
var next6 = function (err, result) {
result6 = result;
test.equal(result6.numberAffected, 1);
if (! useUpdate)
test.isFalse(result6.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{_id: 'David', foo: 2}]);
// multi update by upsert.
// We can't actually update multiple documents since we have to do it by
// id, but at least make sure the multi flag doesn't mess anything up.
upsert(coll, useUpdate, {_id: 'Emily'},
{$set: {bar: 7},
$setOnInsert: {name: 'Fred', foo: 2}},
{multi: true}, next7);
};
var emilyId = coll.insert({_id: 'Emily', foo: 2});
compareResults(test, useUpdate, coll.find().fetch(), [{_id: 'David', foo: 2},
{_id: 'Emily', foo: 2}]);
var result7;
var next7 = function (err, result) {
result7 = result;
test.equal(result7.numberAffected, 1);
if (! useUpdate)
test.isFalse(result7.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{_id: 'David', foo: 2},
{_id: 'Emily', foo: 2, bar: 7}]);
// multi update by upsert.
// We can't actually update multiple documents since we have to do it by
// id, but at least make sure the multi flag doesn't mess anything up.
upsert(coll, useUpdate, {_id: 'Emily'},
{$set: {bar: 7},
$setOnInsert: {name: 'Fred', foo: 2}},
{multi: true}, next7);
};
// insert by multi upsert
upsert(coll, useUpdate, {_id: 'Fred'},
{$set: {bar: 7},
$setOnInsert: {name: 'Fred', foo: 2}},
{multi: true}, next8);
var result7;
var next7 = function (err, result) {
result7 = result;
test.equal(result7.numberAffected, 1);
if (! useUpdate)
test.isFalse(result7.insertedId);
compareResults(test, useUpdate, coll.find().fetch(), [{_id: 'David', foo: 2},
{_id: 'Emily', foo: 2, bar: 7}]);
};
// insert by multi upsert
upsert(coll, useUpdate, {_id: 'Fred'},
{$set: {bar: 7},
$setOnInsert: {name: 'Fred', foo: 2}},
{multi: true}, next8);
var result8;
var next8 = function (err, result) {
result8 = result;
};
test.equal(result8.numberAffected, 1);
if (! useUpdate) {
test.isTrue(result8.insertedId);
test.equal(result8.insertedId, 'Fred');
}
var fredId = result8.insertedId;
compareResults(test, useUpdate, coll.find().fetch(),
[{_id: 'David', foo: 2},
{_id: 'Emily', foo: 2, bar: 7},
{name: 'Fred', foo: 2, bar: 7, _id: fredId}]);
onComplete();
};
var result8;
var next8 = function (err, result) {
result8 = result;
test.equal(result8.numberAffected, 1);
if (! useUpdate) {
test.isTrue(result8.insertedId);
test.equal(result8.insertedId, 'Fred');
}
var fredId = result8.insertedId;
compareResults(test, useUpdate, coll.find().fetch(),
[{_id: 'David', foo: 2},
{_id: 'Emily', foo: 2, bar: 7},
{name: 'Fred', foo: 2, bar: 7, _id: fredId}]);
onComplete();
};
});
});
});
});
if (Meteor.isClient) {
Tinytest.addAsync("mongo-livedata - async update/remove return values over network " + idGeneration, function (test, onComplete) {
var coll;
var run = test.runId();
@@ -1372,8 +1424,7 @@ if (Meteor.isClient) {
});
});
});
} // end isClient
}
// Runs a method and its stub which do some upserts. The method throws an error
// if we don't get the right return values.