Move random generation code from minimongo and uuid packages to new random

package.

The new API is Random.id(), Random.fraction(), Random.choice(arrayOrString), and
Random.hexString(digits).

Meteor.uuid is kept around for backwards compatibility.
This commit is contained in:
David Glasser
2013-02-13 00:42:25 -08:00
60 changed files with 208 additions and 378 deletions

View File

@@ -9,7 +9,7 @@ PACKAGES_DIR=`dirname $0`/../packages
echo 'Meteor = {};'
cat $PACKAGES_DIR/underscore/underscore.js
cat $PACKAGES_DIR/logging/logging.js
cat $PACKAGES_DIR/uuid/uuid.js
cat $PACKAGES_DIR/random/random.js
cat $PACKAGES_DIR/deps/deps.js
cat $PACKAGES_DIR/deps/deps-utils.js
cat $PACKAGES_DIR/liverange/liverange.js

View File

@@ -1034,25 +1034,6 @@ Example:
// After five seconds, stop keeping the count.
setTimeout(function () {handle.stop();}, 5000);
{{> api_box id}}
This returns a random text string such as ``"Jjwjg6gouWLXhMGKW"``
that is likely to be unique in the whole world.
Currently Meteor uses this function to generate `_id` fields for new Mongo
documents by default. If your database requires native binary Mongo IDs instead,
pass `"MONGO"` as the `idGeneration` option to
[`Meteor.Collection`](#meteor_collection).
{{#note}}
In the current implementation, the returned string is derived from a
pseudorandom number generator. The IDs generated definitely are not random
enough to be used for cryptographic or security purposes.
{{/note}}
{{> api_box collection_object_id}}
`Meteor.Collection.ObjectID` follows the same API as the [Node MongoDB driver
@@ -1500,7 +1481,7 @@ Example:
// Support for playing D&D: Roll 3d6 for dexterity
Accounts.onCreateUser(function(options, user) {
var d6 = function () { return Math.floor(Math.random() * 6) + 1; };
var d6 = function () { return Math.floor(Random.fraction() * 6) + 1; };
user.dexterity = d6() + d6() + d6();
// We still want the default hook's 'profile' behavior.
if (options.profile)

View File

@@ -684,7 +684,7 @@ Template.api.cursor_observe_changes = {
Template.api.id = {
id: "meteor_id",
name: "Meteor.id()",
name: "Random.id()",
locus: "Anywhere",
descr: ["Return a unique identifier."],
args: [ ]

View File

@@ -151,7 +151,6 @@ var toc = [
{instance: "cursor", name: "observeChanges", id: "observe_changes"}
],
{type: "spacer"},
"Meteor.id",
{name: "Meteor.Collection.ObjectID", id: "collection_object_id"},
{type: "spacer"},
{name: "Selectors", style: "noncode"},
@@ -295,6 +294,7 @@ var toc = [
"force-ssl",
"jquery",
"less",
"random",
"spiderable",
"stylus",
"showdown",

View File

@@ -25,6 +25,7 @@ and removed with:
{{> pkg_force_ssl}}
{{> pkg_jquery}}
{{> pkg_less}}
{{> pkg_random}}
{{> pkg_spiderable}}
{{> pkg_stylus}}
{{> pkg_showdown}}

View File

@@ -0,0 +1,34 @@
<template name="pkg_random">
{{#better_markdown}}
## `random`
The `random` package provides several random-number utilities, using a
random-number generator whose implementation does not depend on the particular
browser.
<dl class="callbacks">
{{#dtdd "Random.id()"}}
Returns a unique identifier, such as `"Jjwjg6gouWLXhMGKW"`, that is likely to
be unique in the whole world.
{{/dtdd}}
{{#dtdd "Random.fraction()"}}
Returns a number between 0 and 1, like `Math.random`.
{{/dtdd}}
{{#dtdd "Random.choice(arrayOrString)"}}
Returns a random element of the given array or string.
{{/dtdd}}
{{#dtdd "Random.hexString(n)"}}
Returns a random string of `n` hexadecimal digits.
{{/dtdd}}
</dl>
{{#note}}
In the current implementation, random values do not come from a
cryptographically strong pseudorandom number generator. Future releases will
improve this, particularly on the server.
{{/note}}
{{/better_markdown}}
</template>

View File

@@ -6,3 +6,4 @@
autopublish
insecure
preserve-inputs
random

View File

@@ -41,7 +41,7 @@ if (Meteor.isServer) {
"Nikola Tesla",
"Claude Shannon"];
for (var i = 0; i < names.length; i++)
Players.insert({name: names[i], score: Math.floor(Math.random()*10)*5});
Players.insert({name: names[i], score: Math.floor(Random.fraction()*10)*5});
}
});
}

View File

@@ -5,3 +5,4 @@
insecure
preserve-inputs
random

View File

@@ -69,7 +69,7 @@ if (Meteor.isServer) {
};
Template.updated.events({
'click #update-button': function () {
var num = Math.round(Math.random()*100);
var num = Math.round(Random.fraction()*100);
Meteor.call('setMagic', num);
}
});

View File

@@ -150,12 +150,12 @@ Template.circles.events({
Session.set("selectedCircle:" + this.group, evt.currentTarget.id);
},
'click .add': function () {
Circles.insert({x: Meteor.random(), y: Meteor.random(),
r: Meteor.random() * .1 + .02,
Circles.insert({x: Random.fraction(), y: Random.fraction(),
r: Random.fraction() * .1 + .02,
color: {
r: Meteor.random(),
g: Meteor.random(),
b: Meteor.random()
r: Random.fraction(),
g: Random.fraction(),
b: Random.fraction()
},
group: this.group
});
@@ -171,7 +171,7 @@ Template.circles.events({
Circles.find({group: this.group}).forEach(function (r) {
Circles.update(r._id, {
$set: {
x: Meteor.random(), y: Meteor.random(), r: Meteor.random() * .1 + .02
x: Random.fraction(), y: Random.fraction(), r: Random.fraction() * .1 + .02
}
});
});

View File

@@ -26,7 +26,7 @@ if (Meteor.isClient) {
} else {
// make sure we have a username
Meteor.users.update(Meteor.userId(),
{ $set: { username: Meteor.uuid() }});
{ $set: { username: Random.id() }});
}
}
} else if (key === "signupFields") {
@@ -116,7 +116,7 @@ if (Meteor.isClient) {
var fakeLogin = function (callback) {
Accounts.createUser(
{username: Meteor.uuid(),
{username: Random.id(),
password: "password",
profile: { name: "Joe Schmoe" }},
function () {

View File

@@ -6,3 +6,4 @@
insecure
preserve-inputs
bootstrap
random

View File

@@ -16,7 +16,7 @@ if (Meteor.isServer) {
//////////////////////////////
var random = function (n) {
return Math.floor(Math.random() * n);
return Math.floor(Random.fraction() * n);
};
var randomChars =
@@ -25,13 +25,13 @@ var randomString = function (length) {
// XXX make more efficient
var ret = '';
_.times(length, function () {
ret += randomChars[random(randomChars.length)];
ret += Random.choice(randomChars);
});
return ret;
};
var pickCollection = function () {
return Collections[random(Collections.length)];
return Random.choice(Collections);
};
var generateDoc = function () {
@@ -123,7 +123,7 @@ if (Meteor.isClient) {
Meteor.setInterval(function () {
var C = pickCollection();
var docs = C.find({}).fetch();
var doc = docs[random(docs.length)];
var doc = Random.choice(docs);
if (doc)
C.remove(doc._id);
}, 1000 / PARAMS.removesPerSecond);
@@ -133,7 +133,7 @@ if (Meteor.isClient) {
Meteor.setInterval(function () {
var C = pickCollection();
var docs = C.find({}).fetch();
var doc = docs[random(docs.length)];
var doc = Random.choice(docs);
if (doc) {
var field = 'Field' + random(PARAMS.documentNumFields);
var modifer = {};

View File

@@ -44,7 +44,7 @@ var new_board = function () {
// pick random letter from each die
for (i = 0; i < 16; i += 1) {
board[i] = DICE[i].split('')[Math.floor(Math.random() * 6)];
board[i] = Random.choice(DICE[i]);
}
// knuth shuffle

View File

@@ -57,7 +57,7 @@
// support reconnecting using a meteor login token
Accounts._generateStampedLoginToken = function () {
return {token: Meteor.uuid(), when: +(new Date)};
return {token: Random.id(), when: +(new Date)};
};
Accounts.registerLoginHandler(function(options) {

View File

@@ -8,7 +8,7 @@ Tinytest.add('accounts - config validates keys', function (test) {
});
Tinytest.add('accounts - updateOrCreateUserFromExternalService - Facebook', function (test) {
var facebookId = Meteor.uuid();
var facebookId = Random.id();
// create an account with facebook
var uid1 = Accounts.updateOrCreateUserFromExternalService(
@@ -38,8 +38,8 @@ Tinytest.add('accounts - updateOrCreateUserFromExternalService - Facebook', func
});
Tinytest.add('accounts - updateOrCreateUserFromExternalService - Weibo', function (test) {
var weiboId1 = Meteor.uuid();
var weiboId2 = Meteor.uuid();
var weiboId1 = Random.id();
var weiboId2 = Random.id();
// users that have different service ids get different users
uid1 = Accounts.updateOrCreateUserFromExternalService(
@@ -85,7 +85,7 @@ Tinytest.add('accounts - updateOrCreateUserFromExternalService - Twitter', funct
Tinytest.add('accounts - insertUserDoc username', function (test) {
var userIn = {
username: Meteor.uuid()
username: Random.id()
};
// user does not already exist. create a user object with fields set.
@@ -113,9 +113,9 @@ Tinytest.add('accounts - insertUserDoc username', function (test) {
});
Tinytest.add('accounts - insertUserDoc email', function (test) {
var email1 = Meteor.uuid();
var email2 = Meteor.uuid();
var email3 = Meteor.uuid();
var email1 = Random.id();
var email2 = Random.id();
var email3 = Random.id();
var userIn = {
emails: [{address: email1, verified: false},
{address: email2, verified: true}]

View File

@@ -7,8 +7,8 @@
// logging in and out, to protect multiple tabs running the same tests
// simultaneously from interfering with each others' localStorage.
Accounts._isolateLoginTokenForTest = function () {
loginTokenKey = loginTokenKey + Meteor.uuid();
userIdKey = userIdKey + Meteor.uuid();
loginTokenKey = loginTokenKey + Random.id();
userIdKey = userIdKey + Random.id();
};
Accounts._storeLoginToken = function(userId, token) {

View File

@@ -12,7 +12,7 @@
return;
}
var state = Meteor.uuid();
var state = Random.id();
var mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var display = mobile ? 'touch' : 'popup';

View File

@@ -11,7 +11,7 @@
callback && callback(new Accounts.ConfigError("Service not configured"));
return;
}
var state = Meteor.uuid();
var state = Random.id();
var scope = (options && options.requestPermissions) || [];
var flatScope = _.map(scope, encodeURIComponent).join('+');

View File

@@ -12,7 +12,7 @@
return;
}
var state = Meteor.uuid();
var state = Random.id();
// always need this to get user id from google.
var requiredScope = ['https://www.googleapis.com/auth/userinfo.profile'];

View File

@@ -78,7 +78,7 @@ OAuth1Binding.prototype._buildHeader = function(headers) {
var self = this;
return _.extend({
oauth_consumer_key: self._consumerKey,
oauth_nonce: Meteor.uuid().replace(/\W/g, ''),
oauth_nonce: Random.id().replace(/\W/g, ''),
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: (new Date().valueOf()/1000).toFixed().toString(),
oauth_version: '1.0'

View File

@@ -1,11 +1,11 @@
Tinytest.add("oauth1 - loginResultForState is stored", function (test) {
var http = __meteor_bootstrap__.require('http');
var twitterfooId = Meteor.uuid();
var twitterfooName = 'nickname' + Meteor.uuid();
var twitterfooAccessToken = Meteor.uuid();
var twitterfooAccessTokenSecret = Meteor.uuid();
var state = Meteor.uuid();
var twitterfooId = Random.id();
var twitterfooName = 'nickname' + Random.id();
var twitterfooAccessToken = Random.id();
var twitterfooAccessTokenSecret = Random.id();
var state = Random.id();
OAuth1Binding.prototype.prepareRequestToken = function() {};
OAuth1Binding.prototype.prepareAccessToken = function() {
@@ -70,11 +70,11 @@ Tinytest.add("oauth1 - loginResultForState is stored", function (test) {
Tinytest.add("oauth1 - error in user creation", function (test) {
var http = __meteor_bootstrap__.require('http');
var state = Meteor.uuid();
var twitterfailId = Meteor.uuid();
var twitterfailName = 'nickname' + Meteor.uuid();
var twitterfailAccessToken = Meteor.uuid();
var twitterfailAccessTokenSecret = Meteor.uuid();
var state = Random.id();
var twitterfailId = Random.id();
var twitterfailName = 'nickname' + Random.id();
var twitterfailAccessToken = Random.id();
var twitterfailAccessTokenSecret = Random.id();
if (!Accounts.loginServiceConfiguration.findOne({service: 'twitterfail'}))
Accounts.loginServiceConfiguration.insert({service: 'twitterfail'});

View File

@@ -1,7 +1,7 @@
Tinytest.add("oauth2 - loginResultForState is stored", function (test) {
var http = __meteor_bootstrap__.require('http');
var foobookId = Meteor.uuid();
var state = Meteor.uuid();
var foobookId = Random.id();
var state = Random.id();
if (!Accounts.loginServiceConfiguration.findOne({service: 'foobook'}))
Accounts.loginServiceConfiguration.insert({service: 'foobook'});
@@ -42,8 +42,8 @@ Tinytest.add("oauth2 - loginResultForState is stored", function (test) {
Tinytest.add("oauth2 - error in user creation", function (test) {
var http = __meteor_bootstrap__.require('http');
var state = Meteor.uuid();
var failbookId = Meteor.uuid();
var state = Random.id();
var failbookId = Random.id();
if (!Accounts.loginServiceConfiguration.findOne({service: 'failbook'}))
Accounts.loginServiceConfiguration.insert({service: 'failbook'});

View File

@@ -15,7 +15,7 @@
testAsyncMulti("accounts emails - reset password flow", [
function (test, expect) {
email1 = Meteor.uuid() + "-intercept@example.com";
email1 = Random.id() + "-intercept@example.com";
Accounts.createUser({email: email1, password: 'foobar'},
expect(function (error) {
test.equal(error, undefined);
@@ -87,8 +87,8 @@
testAsyncMulti("accounts emails - verify email flow", [
function (test, expect) {
email2 = Meteor.uuid() + "-intercept@example.com";
email3 = Meteor.uuid() + "-intercept@example.com";
email2 = Random.id() + "-intercept@example.com";
email3 = Random.id() + "-intercept@example.com";
Accounts.createUser(
{email: email2, password: 'foobar'},
loggedIn(test, expect));
@@ -171,7 +171,7 @@
testAsyncMulti("accounts emails - enroll account flow", [
function (test, expect) {
email4 = Meteor.uuid() + "-intercept@example.com";
email4 = Random.id() + "-intercept@example.com";
Meteor.call("createUserOnServer", email4,
expect(function (error, result) {
test.isFalse(error);

View File

@@ -23,8 +23,8 @@
// user: either {username: (username)}, {email: (email)}, or {id: (userId)}
// A: hex encoded int. the client's public key for this exchange
// @returns {Object} with fields:
// identiy: string uuid
// salt: string uuid
// identity: random string ID
// salt: random string ID
// B: hex encoded int. server's public key for this exchange
beginPasswordExchange: function (request) {
var selector = selectorFromUserQuery(request.user);
@@ -191,7 +191,7 @@
if (!email || !_.contains(_.pluck(user.emails || [], 'address'), email))
throw new Error("No such email for user.");
var token = Meteor.uuid();
var token = Random.id();
var when = +(new Date);
Meteor.users.update(userId, {$set: {
"services.password.reset": {
@@ -233,7 +233,7 @@
var tokenRecord = {
token: Meteor.uuid(),
token: Random.id(),
address: address,
when: +(new Date)};
Meteor.users.update(
@@ -268,7 +268,7 @@
throw new Error("No such email for user.");
var token = Meteor.uuid();
var token = Random.id();
var when = +(new Date);
Meteor.users.update(userId, {$set: {
"services.password.reset": {

View File

@@ -28,11 +28,11 @@ if (Meteor.isClient) (function () {
testAsyncMulti("passwords - long series", [
function (test, expect) {
username = Meteor.uuid();
username2 = Meteor.uuid();
username3 = Meteor.uuid();
username = Random.id();
username2 = Random.id();
username3 = Random.id();
// use -intercept so that we don't print to the console
email = Meteor.uuid() + '-intercept@example.com';
email = Random.id() + '-intercept@example.com';
password = 'password';
password2 = 'password2';
password3 = 'password3';
@@ -227,7 +227,7 @@ if (Meteor.isServer) (function () {
Tinytest.add(
'passwords - createUser hooks',
function (test) {
var email = Meteor.uuid() + '@example.com';
var email = Random.id() + '@example.com';
test.throws(function () {
// should fail the new user validators
Accounts.createUser({email: email, profile: {invalid: true}});
@@ -249,7 +249,7 @@ if (Meteor.isServer) (function () {
Tinytest.add(
'passwords - setPassword',
function (test) {
var username = Meteor.uuid();
var username = Random.id();
var userId = Accounts.createUser({username: username});

View File

@@ -13,7 +13,7 @@
return;
}
var state = Meteor.uuid();
var state = Random.id();
// We need to keep state across the next two 'steps' so we're adding
// a state parameter to the url and the callback url that we'll be returned
// to by oauth provider

View File

@@ -13,7 +13,7 @@
return;
}
var state = Meteor.uuid();
var state = Random.id();
// XXX need to support configuring access_type and scope
var loginUrl =
'https://api.weibo.com/oauth2/authorize' +

View File

@@ -98,7 +98,7 @@ testAsyncMulti("httpcall - timeout", [
// Should time out
Meteor.http.call(
"GET", url_prefix()+"/slow-"+Meteor.uuid(),
"GET", url_prefix()+"/slow-"+Random.id(),
{ timeout: 500 },
expect(function(error, result) {
test.isTrue(error);
@@ -107,7 +107,7 @@ testAsyncMulti("httpcall - timeout", [
// Should not time out
Meteor.http.call(
"GET", url_prefix()+"/foo-"+Meteor.uuid(),
"GET", url_prefix()+"/foo-"+Random.id(),
{ timeout: 2000 },
expect(function(error, result) {
test.isFalse(error);
@@ -254,7 +254,7 @@ testAsyncMulti("httpcall - http auth", [
// uses cached credentials even if we supply different ones:
// https://bugzilla.mozilla.org/show_bug.cgi?id=654348
var password = 'rocks';
//var password = Meteor.uuid().replace(/[^0-9a-zA-Z]/g, '');
//var password = Random.id().replace(/[^0-9a-zA-Z]/g, '');
Meteor.http.call(
"GET", url_prefix()+"/login?"+password,
{ auth: "meteor:"+password },

View File

@@ -469,7 +469,7 @@ _.extend(Meteor._LivedataConnection.prototype, {
}
} else {
// New sub! Generate an id, save it locally, and send message.
id = Meteor.uuid();
id = Random.id();
self._subscriptions[id] = {
id: id,
name: name,

View File

@@ -74,7 +74,7 @@ Tinytest.add("livedata stub - receive data", function (test) {
startAndConnect(test, stream);
// data comes in for unknown collection.
var coll_name = Meteor.uuid();
var coll_name = Random.id();
stream.receive({msg: 'added', collection: coll_name, id: '1234',
fields: {a: 1}});
// break throught the black box and test internal state
@@ -294,7 +294,7 @@ Tinytest.add("livedata stub - methods", function (test) {
startAndConnect(test, stream);
var collName = Meteor.uuid();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
// setup method
@@ -436,7 +436,7 @@ Tinytest.add("livedata stub - methods calling methods", function (test) {
startAndConnect(test, stream);
var coll_name = Meteor.uuid();
var coll_name = Random.id();
var coll = new Meteor.Collection(coll_name, {manager: conn});
// setup methods
@@ -521,7 +521,7 @@ Tinytest.add("livedata stub - reconnect", function (test) {
startAndConnect(test, stream);
var collName = Meteor.uuid();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
var o = observeCursor(test, coll.find());
@@ -646,7 +646,7 @@ Tinytest.add("livedata stub - reconnect method which only got result", function
var conn = newConnection(stream);
startAndConnect(test, stream);
var collName = Meteor.uuid();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
var o = observeCursor(test, coll.find());
@@ -819,7 +819,7 @@ Tinytest.add("livedata stub - reconnect method which only got data", function (t
var conn = newConnection(stream);
startAndConnect(test, stream);
var collName = Meteor.uuid();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
var o = observeCursor(test, coll.find());
@@ -906,7 +906,7 @@ Tinytest.add("livedata stub - multiple stubs same doc", function (test) {
var conn = newConnection(stream);
startAndConnect(test, stream);
var collName = Meteor.uuid();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
var o = observeCursor(test, coll.find());
@@ -991,7 +991,7 @@ Tinytest.add("livedata stub - unsent methods don't block quiescence", function (
var conn = newConnection(stream);
startAndConnect(test, stream);
var collName = Meteor.uuid();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
conn.methods({
@@ -1067,7 +1067,7 @@ Tinytest.add("livedata connection - two wait methods", function (test) {
var conn = newConnection(stream);
startAndConnect(test, stream);
var collName = Meteor.uuid();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
// setup method
@@ -1320,7 +1320,7 @@ Tinytest.add("livedata connection - onReconnect with sent messages", function(te
params: ['login'], id: '*'});
// we connect.
stream.receive({msg: 'connected', session: Meteor.uuid()});
stream.receive({msg: 'connected', session: Random.id()});
test.length(stream.sent, 0);
// login got result (but not yet data)
@@ -1446,7 +1446,7 @@ Tinytest.add("livedata stub - stubs before connected", function (test) {
var stream = new Meteor._StubStream();
var conn = newConnection(stream);
var collName = Meteor.uuid();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
// Start and send "connect", but DON'T get 'connected' quite yet.

View File

@@ -201,7 +201,7 @@ _.extend(Meteor._SessionCollectionView.prototype, {
Meteor._LivedataSession = function (server, version) {
var self = this;
self.id = Meteor.uuid();
self.id = Random.id();
self.server = server;
self.version = version;
@@ -772,7 +772,7 @@ Meteor._LivedataSubscription = function (
if (self._subscriptionId) {
self._subscriptionHandle = 'N' + self._subscriptionId;
} else {
self._subscriptionHandle = 'U' + Meteor.id();
self._subscriptionHandle = 'U' + Random.id();
}
// has _deactivate been called?

View File

@@ -244,7 +244,7 @@ if (Meteor.isServer) {
// First add a random item, which should be cleaned up. We use ready/onReady
// to make sure that the second test block is only called after the added is
// processed, so that there's any chance of the coll.find().count() failing.
sub.added(collName, Meteor.id(), {foo: 42});
sub.added(collName, Random.id(), {foo: 42});
sub.ready();
if (options.stopInHandler) {

View File

@@ -45,7 +45,7 @@ if (Meteor.isServer) {
}
Tinytest.add("livedata - methods with colliding names", function (test) {
var x = LocalCollection.uuid();
var x = Random.id();
var m = {};
m[x] = function () {};
Meteor.methods(m);
@@ -137,7 +137,7 @@ testAsyncMulti("livedata - basic method invocation", [
function (test, expect) {
if (Meteor.isClient) {
// For test isolation
var token = Meteor.uuid();
var token = Random.id();
Meteor.apply(
"delayedTrue", [token], {wait: false}, expect(function(err, res) {
test.equal(res, false);
@@ -149,7 +149,7 @@ testAsyncMulti("livedata - basic method invocation", [
// test that `wait: true` is respected
function(test, expect) {
if (Meteor.isClient) {
var token = Meteor.uuid();
var token = Random.id();
Meteor.apply(
"delayedTrue", [token], {wait: true}, expect(function(err, res) {
test.equal(res, true);
@@ -378,7 +378,7 @@ if (Meteor.isClient) {
undoEavesdrop();
});
}, function(test, expect) {
var key = Meteor.uuid();
var key = Random.id();
Meteor.subscribe("recordUserIdOnStop", key);
Meteor.apply("setUserId", [100], {wait: true}, expect(function () {}));
Meteor.apply("setUserId", [101], {wait: true}, expect(function () {}));
@@ -401,7 +401,7 @@ if (Meteor.isClient) {
testAsyncMulti("livedata - overlapping universal subs", [
function (test, expect) {
var coll = new Meteor.Collection("overlappingUniversalSubs");
var token = Meteor.uuid();
var token = Random.id();
test.isFalse(coll.findOne(token));
Meteor.call("testOverlappingSubs", token, expect(function (err) {
test.isFalse(err);
@@ -413,7 +413,7 @@ if (Meteor.isClient) {
testAsyncMulti("livedata - runtime universal sub creation", [
function (test, expect) {
var coll = new Meteor.Collection("runtimeSubCreation");
var token = Meteor.uuid();
var token = Random.id();
test.isFalse(coll.findOne(token));
Meteor.call("runtimeUniversalSubCreation", token, expect(function (err) {
test.isFalse(err);
@@ -436,7 +436,7 @@ if (Meteor.isClient) {
// conn._subscriptions is empty.
var conn = new Meteor._LivedataConnection('/',
{reloadWithOutstanding: true});
var collName = Meteor.id();
var collName = Random.id();
var coll = new Meteor.Collection(collName, {manager: conn});
var errorFromRerun;
var gotErrorFromStopper = false;

View File

@@ -4,7 +4,7 @@ Package.describe({
});
Package.on_use(function (api) {
api.use(['stream', 'uuid']);
api.use(['stream', 'random']);
api.use(['ejson', 'json', 'underscore', 'deps', 'logging'], ['client', 'server']);
// livedata_connection.js uses a Minimongo collection internally to

View File

@@ -375,7 +375,7 @@ LocalCollection.prototype.insert = function (doc) {
// if you really want to use ObjectIDs, set this global.
// Meteor.Collection specifies its own ids and does not use this code.
doc._id = LocalCollection._useOID ? new LocalCollection._ObjectID()
: LocalCollection.id();
: Random.id();
}
var id = LocalCollection._idStringify(doc._id);

View File

@@ -1208,7 +1208,7 @@ Tinytest.add("minimongo - observe ordered", function (test) {
// test stop
handle.stop();
var idA2 = LocalCollection.id();
var idA2 = Random.id();
c.insert({_id: idA2, a:2});
test.equal(operations.shift(), undefined);

View File

@@ -18,7 +18,7 @@ LocalCollection._ObjectID = function (hexString) {
// meant to work with _.isEqual(), which relies on structural equality
self._str = hexString;
} else {
self._str = LocalCollection._randomHexString(24);
self._str = Random.hexString(24);
}
};

View File

@@ -8,11 +8,10 @@ Package.on_use(function (api, where) {
// It would be sort of nice if minimongo didn't depend on
// underscore, so we could ship it separately.
api.use(['underscore', 'json', 'ejson', 'ordered-dict'], where);
api.use(['underscore', 'json', 'ejson', 'ordered-dict', 'random'], where);
api.add_files([
'minimongo.js',
'selector.js',
'uuid.js',
'modify.js',
'diff.js',
'objectid.js'

View File

@@ -1,171 +0,0 @@
// XXX dups packages/uuid/uuid.js
// LocalCollection.random() -- known good PRNG, replaces Math.random()
// LocalCollection.uuid() -- returns RFC 4122 v4 UUID.
// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript
// for a full discussion and Alea implementation.
// Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
(function() {
var HEX_DIGITS = "0123456789abcdef";
var UNMISTAKABLE_CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz";
LocalCollection._Alea = function () {
function Mash() {
var n = 0xefc8249d;
var mash = function(data) {
data = data.toString();
for (var i = 0; i < data.length; i++) {
n += data.charCodeAt(i);
var h = 0.02519603282416938 * n;
n = h >>> 0;
h -= n;
h *= n;
n = h >>> 0;
h -= n;
n += h * 0x100000000; // 2^32
}
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
};
mash.version = 'Mash 0.9';
return mash;
}
return (function (args) {
var s0 = 0;
var s1 = 0;
var s2 = 0;
var c = 1;
if (args.length == 0) {
args = [+new Date];
}
var mash = Mash();
s0 = mash(' ');
s1 = mash(' ');
s2 = mash(' ');
for (var i = 0; i < args.length; i++) {
s0 -= mash(args[i]);
if (s0 < 0) {
s0 += 1;
}
s1 -= mash(args[i]);
if (s1 < 0) {
s1 += 1;
}
s2 -= mash(args[i]);
if (s2 < 0) {
s2 += 1;
}
}
mash = null;
var random = function() {
var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
s0 = s1;
s1 = s2;
return s2 = t - (c = t | 0);
};
random.uint32 = function() {
return random() * 0x100000000; // 2^32
};
random.fract53 = function() {
return random() +
(random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
};
random.version = 'Alea 0.9';
random.args = args;
return random;
} (Array.prototype.slice.call(arguments)));
}
// instantiate RNG. Heuristically collect entropy from various sources
// client sources
var height = (typeof window !== 'undefined' && window.innerHeight) ||
(typeof document !== 'undefined'
&& document.documentElement
&& document.documentElement.clientHeight) ||
(typeof document !== 'undefined'
&& document.body
&& document.body.clientHeight) ||
1;
var width = (typeof window !== 'undefined' && window.innerWidth) ||
(typeof document !== 'undefined'
&& document.documentElement
&& document.documentElement.clientWidth) ||
(typeof document !== 'undefined'
&& document.body
&& document.body.clientWidth) ||
1;
var agent = (typeof navigator !== 'undefined' && navigator.userAgent) || "";
// server sources
var pid = (typeof process !== 'undefined' && process.pid) || 1;
LocalCollection.random = new LocalCollection._Alea([
new Date(), height, width, agent, pid, Math.random()]);
LocalCollection._randomHexString = function (len) {
var digits = [];
for (var i = 0; i < len; i++) {
digits[i] = HEX_DIGITS.substr(Math.floor(LocalCollection.random() * 0x10),
1);
}
return digits.join("");
};
// RFC 4122 v4 UUID.
LocalCollection.uuid = function () {
var s = [];
for (var i = 0; i < 36; i++) {
s[i] = HEX_DIGITS.substr(Math.floor(LocalCollection.random() * 0x10), 1);
}
s[14] = "4";
s[19] = HEX_DIGITS.substr((parseInt(s[19],16) & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
};
LocalCollection.id = function() {
var digits = [];
var base = UNMISTAKABLE_CHARS.length;
// Length of 17 preserves around 96 bits of entropy, which is the
// amount of state in our PRNG
for (var i = 0; i < 17; i++) {
digits[i] = UNMISTAKABLE_CHARS.substr(Math.floor(LocalCollection.random() * base), 1);
}
return digits.join("");
};
})();

View File

@@ -28,7 +28,7 @@ Meteor.Collection = function (name, options) {
case 'STRING':
default:
self._makeNewID = function () {
return LocalCollection.id();
return Random.id();
};
break;
}
@@ -201,7 +201,7 @@ Meteor.Collection._rewriteSelector = function (selector) {
if (!selector || (('_id' in selector) && !selector._id))
// can't match anything
return {_id: LocalCollection.id()};
return {_id: Random.id()};
var ret = {};
_.each(selector, function (value, key) {

View File

@@ -229,8 +229,8 @@ Tinytest.addAsync("mongo-livedata - fuzz test, " + idGeneration, function(test,
// Use non-deterministic randomness so we can have a shorter fuzz
// test (fewer iterations). For deterministic (fully seeded)
// randomness, remove the call to Math.random().
var seededRandom = new SeededRandom("foobard" + Math.random());
// randomness, remove the call to Random.fraction().
var seededRandom = new SeededRandom("foobard" + Random.fraction());
// Random integer in [0,n)
var rnd = function (n) {
return seededRandom.nextIntBetween(0, n-1);
@@ -545,7 +545,7 @@ if (Meteor.isServer) {
testAsyncMulti('mongo-livedata - rewrite selector, ' + idGeneration, [
function (test, expect) {
var collectionName = Meteor.uuid();
var collectionName = Random.id();
if (Meteor.isClient) {
Meteor.call('createInsecureCollection', collectionName, collectionOptions);
Meteor.subscribe('c-' + collectionName);
@@ -583,7 +583,7 @@ testAsyncMulti('mongo-livedata - rewrite selector, ' + idGeneration, [
testAsyncMulti('mongo-livedata - empty documents, ' + idGeneration, [
function (test, expect) {
var collectionName = Meteor.uuid();
var collectionName = Random.id();
if (Meteor.isClient) {
Meteor.call('createInsecureCollection', collectionName);
Meteor.subscribe('c-' + collectionName);
@@ -604,7 +604,7 @@ testAsyncMulti('mongo-livedata - empty documents, ' + idGeneration, [
testAsyncMulti('mongo-livedata - document with a date, ' + idGeneration, [
function (test, expect) {
var collectionName = Meteor.uuid();
var collectionName = Random.id();
if (Meteor.isClient) {
Meteor.call('createInsecureCollection', collectionName, collectionOptions);
Meteor.subscribe('c-' + collectionName);
@@ -633,7 +633,7 @@ testAsyncMulti('mongo-livedata - document with binary data, ' + idGeneration, [
"dCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdl" +
"bmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9y" +
"dCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=");
var collectionName = Meteor.uuid();
var collectionName = Random.id();
if (Meteor.isClient) {
Meteor.call('createInsecureCollection', collectionName, collectionOptions);
Meteor.subscribe('c-' + collectionName);
@@ -658,7 +658,7 @@ testAsyncMulti('mongo-livedata - document with binary data, ' + idGeneration, [
testAsyncMulti('mongo-livedata - specified _id', [
function (test, expect) {
var collectionName = Meteor.uuid();
var collectionName = Random.id();
if (Meteor.isClient) {
Meteor.call('createInsecureCollection', collectionName);
Meteor.subscribe('c-' + collectionName);

View File

@@ -2,7 +2,7 @@
var makeCollection = function () {
if (Meteor.isServer)
return new Meteor.Collection(Meteor.id());
return new Meteor.Collection(Random.id());
else
return new Meteor.Collection(null);
};

View File

@@ -13,7 +13,7 @@ Package.describe({
});
Package.on_use(function (api) {
api.use(['uuid', 'ejson', 'json', 'underscore', 'minimongo', 'logging', 'livedata'],
api.use(['random', 'ejson', 'json', 'underscore', 'minimongo', 'logging', 'livedata'],
['client', 'server']);
api.add_files('mongo_driver.js', 'server');

View File

@@ -11,3 +11,19 @@ Meteor.deps.Context.prototype.on_invalidate =
// We used to require a special "autosubscribe" call to reactively subscribe to
// things. Now, it works with autorun.
Meteor.autosubscribe = Meteor.autorun;
// Instead of the "random" package with Random.id(), we used to have this
// Meteor.uuid() implementing the RFC 4122 v4 UUID.
Meteor.uuid = function () {
var HEX_DIGITS = "0123456789abcdef";
var s = [];
for (var i = 0; i < 36; i++) {
s[i] = Random.choice(HEX_DIGITS);
}
s[14] = "4";
s[19] = HEX_DIGITS.substr((parseInt(s[19],16) & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
};

View File

@@ -1,9 +1,9 @@
Package.describe({
summary: "Better random number and UUIDv4 generators",
summary: "Random number generator and utilities",
internal: true
});
Package.on_use(function (api, where) {
where = where || ['client', 'server'];
api.add_files('uuid.js', where);
api.add_files('random.js', where);
});

View File

@@ -1,38 +1,10 @@
// XXX dups packages/minimongo/uuid.js
(function() {
// Meteor.random() -- known good PRNG, replaces Math.random()
// Meteor.uuid() -- returns RFC 4122 v4 UUID.
Random = {};
// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript
// for a full discussion and Alea implementation.
// Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
(function() {
var HEX_DIGITS = "0123456789abcdef";
var UNMISTAKABLE_CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz";
var Alea = Meteor._Alea = function () {
Random._Alea = function () {
function Mash() {
var n = 0xefc8249d;
@@ -103,7 +75,7 @@ var Alea = Meteor._Alea = function () {
return random;
} (Array.prototype.slice.call(arguments)));
}
};
// instantiate RNG. Heuristically collect entropy from various sources
@@ -131,32 +103,38 @@ var agent = (typeof navigator !== 'undefined' && navigator.userAgent) || "";
// server sources
var pid = (typeof process !== 'undefined' && process.pid) || 1;
Meteor.random = new Alea([
// XXX On the server, use the crypto module (OpenSSL) instead of this PRNG.
// (Make Random.fraction be generated from Random.hexString instead of the
// other way around, and generate Random.hexString from crypto.randomBytes.)
Random.fraction = new Random._Alea([
new Date(), height, width, agent, pid, Math.random()]);
// RFC 4122 v4 UUID.
Meteor.uuid = function () {
var s = [];
for (var i = 0; i < 36; i++) {
s[i] = HEX_DIGITS.substr(Math.floor(Meteor.random() * 0x10), 1);
}
s[14] = "4";
s[19] = HEX_DIGITS.substr((parseInt(s[19],16) & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
Random.choice = function (arrayOrString) {
var index = Math.floor(Random.fraction() * arrayOrString.length);
if (typeof arrayOrString === "string")
return arrayOrString.substr(index, 1);
else
return arrayOrString[index];
};
Meteor.id = function() {
var UNMISTAKABLE_CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz";
Random.id = function() {
var digits = [];
var base = UNMISTAKABLE_CHARS.length;
// Length of 17 preserves around 96 bits of entropy, which is the
// amount of state in our PRNG
for (var i = 0; i < 17; i++) {
digits[i] = UNMISTAKABLE_CHARS.substr(Math.floor(Meteor.random() * base), 1);
digits[i] = Random.choice(UNMISTAKABLE_CHARS);
}
return digits.join("");
};
var HEX_DIGITS = "0123456789abcdef";
Random.hexString = function (digits) {
var hexDigits = [];
for (var i = 0; i < digits; ++i) {
hexDigits.push(Random.choice("0123456789abcdef"));
}
return hexDigits.join('');
};
})();

View File

@@ -4,7 +4,7 @@ Package.describe({
});
Package.on_use(function (api) {
api.use(['underscore', 'uuid', 'domutils', 'liverange', 'universal-events'],
api.use(['underscore', 'random', 'domutils', 'liverange', 'universal-events'],
'client');
api.add_files(['spark.js', 'patch.js', 'convenience.js',

View File

@@ -44,7 +44,7 @@ Spark._currentRenderer = (function () {
};
})();
Spark._TAG = "_spark_" + Meteor.uuid();
Spark._TAG = "_spark_" + Random.id();
// XXX document contract for each type of annotation?
Spark._ANNOTATION_NOTIFY = "notify";
Spark._ANNOTATION_DATA = "data";
@@ -106,16 +106,6 @@ var withEventGuard = function (func) {
finally { eventGuardActive = previous; }
};
Spark._createId = function () {
// Chars can't include '-' to be safe inside HTML comments.
var chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_";
var id = "";
for (var i = 0; i < 8; i++)
id += chars.substr(Math.floor(Meteor.random() * 64), 1);
return id;
};
Spark._Renderer = function () {
// Map from annotation ID to an annotation function, which is called
// at render time and receives (startNode, endNode).
@@ -164,7 +154,7 @@ _.extend(Spark._Renderer.prototype, {
// unescaped < and > in HTML attribute values, where they are normally
// safe. We can't assume that a string like '<1>' came from us
// and not arbitrary user-entered data.
var id = (type || '') + ":" + Spark._createId();
var id = (type || '') + ":" + Random.id();
this.annotations[id] = function (start, end) {
if ((! start) || (! type)) {
// ! start: materialize called us with no args because this
@@ -1100,7 +1090,7 @@ Spark.labelBranch = function (label, htmlFunc) {
return htmlFunc();
if (label === Spark.UNIQUE_LABEL)
label = Spark._createId();
label = Random.id();
renderer.currentBranch.pushLabel(label);
var html = htmlFunc();

View File

@@ -1639,8 +1639,8 @@ Tinytest.add("spark - landmark patching", function(test) {
for(var i=0; i<5; i++) {
// Use non-deterministic randomness so we can have a shorter fuzz
// test (fewer iterations). For deterministic (fully seeded)
// randomness, remove the call to Math.random().
rand = new SeededRandom("preserved nodes "+i+" "+Math.random());
// randomness, remove the call to Random.fraction().
rand = new SeededRandom("preserved nodes "+i+" "+Random.fraction());
var R = ReactiveVar(false);
var structure = randomNodeList(null, 6);
@@ -1878,7 +1878,7 @@ Tinytest.add("spark - leaderboard, " + idGeneration, function(test) {
}));
var idGen;
if (idGeneration === 'STRING')
idGen = LocalCollection.id;
idGen = Random.id;
else
idGen = function () { return new LocalCollection._ObjectID(); };
@@ -2550,7 +2550,7 @@ testAsyncMulti(
// This is quite a tricky implementation.
var withIframe = function(onReady1, onReady2) {
var frameName = "submitframe"+String(Math.random()).slice(2);
var frameName = "submitframe"+String(Random.fraction()).slice(2);
var iframeDiv = OnscreenDiv(
Meteor.render(function() {
return '<iframe name="'+frameName+'" '+

View File

@@ -4,7 +4,7 @@ Package.describe({
});
Package.on_use(function (api) {
api.use('uuid', ['client', 'server']);
api.use('random', ['client', 'server']);
api.add_files(['biginteger.js', 'sha256.js', 'srp.js'],
['client', 'server']);
});

View File

@@ -19,8 +19,8 @@
Meteor._srp.generateVerifier = function (password, options) {
var params = paramsFromOptions(options);
var identity = (options && options.identity) || Meteor.uuid();
var salt = (options && options.salt) || Meteor.uuid();
var identity = (options && options.identity) || Random.id();
var salt = (options && options.salt) || Random.id();
var x = params.hash(salt + params.hash(identity + ":" + password));
var xi = new Meteor._srp.BigInteger(x, 16);
@@ -332,8 +332,7 @@
var randInt = function () {
// XXX XXX need a better implementation!
return new Meteor._srp.BigInteger(Meteor.uuid().replace(/-/g, ''), 16);
return new Meteor._srp.BigInteger(Random.hexString(36), 16);
};

View File

@@ -4,7 +4,7 @@ Package.describe({
});
Package.on_use(function (api) {
api.use(['underscore', 'logging', 'uuid', 'json'], ['client', 'server']);
api.use(['underscore', 'logging', 'random', 'json'], ['client', 'server']);
api.use('reload', 'client');
api.add_files('sockjs-0.3.4.js', 'client');

View File

@@ -94,7 +94,7 @@ _.extend(Meteor._Stream, {
// allows different stream connections to connect to different hostnames
// and avoid browser per-hostname connection limits.
host = host.replace(/\*/g, function () {
return Math.floor(Math.random()*10);
return Math.floor(Random.fraction()*10);
});
return newScheme + '://' + host + rest;
@@ -296,7 +296,7 @@ _.extend(Meteor._Stream.prototype, {
self.RETRY_BASE_TIMEOUT * Math.pow(self.RETRY_EXPONENT, count));
// fuzz the timeout randomly, to avoid reconnect storms when a
// server goes down.
timeout = timeout * ((Math.random() * self.RETRY_FUZZ) +
timeout = timeout * ((Random.fraction() * self.RETRY_FUZZ) +
(1 - self.RETRY_FUZZ/2));
return timeout;
},

View File

@@ -5,7 +5,7 @@
// custom serverId which you only change when something worth pushing
// to clients immediately happens.
__meteor_runtime_config__.serverId =
process.env.SERVER_ID ? process.env.SERVER_ID : Meteor.uuid();
process.env.SERVER_ID ? process.env.SERVER_ID : Random.id();
Meteor._StreamServer = function () {
var self = this;

View File

@@ -5,7 +5,7 @@ var SeededRandom = function(seed) { // seed may be a string or any type
return new SeededRandom(seed);
seed = seed || "seed";
this.gen = new Meteor._Alea(seed); // from uuid.js
this.gen = new Random._Alea(seed); // from random.js
};
SeededRandom.prototype.next = function() {
return this.gen();

View File

@@ -12,7 +12,7 @@ TestCaseResults = function (test_case, onEvent, onException, stop_at_offset) {
self.current_fail_count = 0;
self.stop_at_offset = stop_at_offset;
self.onException = onException;
self.id = Meteor.uuid();
self.id = Random.id();
};
_.extend(TestCaseResults.prototype, {

View File

@@ -2,7 +2,7 @@
// the server. Sets a 'server' flag on test results that came from the
// server.
Meteor._runTestsEverywhere = function (onReport, onComplete) {
var runId = LocalCollection.uuid();
var runId = Random.id();
var localComplete = false;
var remoteComplete = false;
var done = false;

View File

@@ -38,7 +38,7 @@
"You probably forgot to wrap a callback in bindEnvironment.");
console.trace();
}
var dummyKey = Meteor.uuid();
var dummyKey = Random.id();
var fields = {};
fields[dummyKey] = report;
_.each(handlesForRun[runId], function (handle) {