Merge fx-sync to mozilla-central (bug 597426)

This commit is contained in:
Philipp von Weitershausen 2010-09-24 00:19:31 +02:00
Родитель 8d4a2d48dd 8ced4676ca
Коммит 4a2ae4efbe
45 изменённых файлов: 930 добавлений и 133 удалений

Просмотреть файл

@ -28,6 +28,8 @@ error.sync.title = Error While Syncing
error.sync.description = Sync encountered an error while syncing: %1$S. Sync will automatically retry this action.
error.sync.no_node_found = The Sync server is a little busy right now, but you don't need to do anything about it. We'll start syncing your data as soon as we can!
error.sync.no_node_found.title = Sync Delay
error.sync.serverStatusButton.label = Server Status
error.sync.serverStatusButton.accesskey = V
error.sync.needUpdate.description = You need to update Firefox Sync to continue syncing your data.
error.sync.needUpdate.label = Update Firefox Sync
error.sync.needUpdate.accesskey = U

Просмотреть файл

@ -138,6 +138,12 @@ Collection.prototype = {
// Save this because onProgress is called with this as the ChannelListener
let coll = this;
// Prepare a dummyUri so that records can generate the correct
// relative URLs. The last bit will be replaced with record.id.
let dummyUri = this.uri.clone().QueryInterface(Ci.nsIURL);
dummyUri.filePath += "/replaceme";
dummyUri.query = "";
// Switch to newline separated records for incremental parsing
coll.setHeader("Accept", "application/newlines");
@ -149,9 +155,8 @@ Collection.prototype = {
this._data = this._data.slice(newline + 1);
// Deserialize a record from json and give it to the callback
let record = new coll._recordObj();
let record = new coll._recordObj(dummyUri);
record.deserialize(json);
record.baseUri = coll.uri;
onRecord(record);
}
};

Просмотреть файл

@ -49,13 +49,19 @@ Cu.import("resource://services-sync/util.js");
function CryptoWrapper(uri) {
this.cleartext = {};
WBORecord.call(this, uri);
this.encryption = "";
this.ciphertext = null;
}
CryptoWrapper.prototype = {
__proto__: WBORecord.prototype,
_logName: "Record.CryptoWrapper",
get encryption() {
return this.uri.resolve(this.payload.encryption);
},
set encryption(value) {
this.payload.encryption = this.uri.getRelativeSpec(Utils.makeURI(value));
},
encrypt: function CryptoWrapper_encrypt(passphrase) {
let pubkey = PubKeys.getDefaultKey();
let privkey = PrivKeys.get(pubkey.privateKeyUri);
@ -109,8 +115,7 @@ CryptoWrapper.prototype = {
},
};
Utils.deferGetSet(CryptoWrapper, "payload", ["ciphertext", "encryption", "IV",
"hmac"]);
Utils.deferGetSet(CryptoWrapper, "payload", ["ciphertext", "IV", "hmac"]);
Utils.deferGetSet(CryptoWrapper, "cleartext", "deleted");
function CryptoMeta(uri) {
@ -180,7 +185,7 @@ CryptoMeta.prototype = {
// Wrap the symmetric key and generate a HMAC for it
let wrapped = Svc.Crypto.wrapSymmetricKey(symkey, new_pubkey.keyData);
this.keyring[new_pubkey.uri.spec] = {
this.keyring[this.uri.getRelativeSpec(new_pubkey.uri)] = {
wrapped: wrapped,
hmac: Utils.sha256HMAC(wrapped, this.hmacKey)
};

Просмотреть файл

@ -52,7 +52,6 @@ function PubKey(uri) {
WBORecord.call(this, uri);
this.type = "pubkey";
this.keyData = null;
this.privateKeyUri = null;
}
PubKey.prototype = {
__proto__: WBORecord.prototype,
@ -66,13 +65,16 @@ PubKey.prototype = {
let key = this.payload.privateKeyUri;
return Utils.makeURI(this.uri.resolve(key) || key);
},
set privateKeyUri(value) {
this.payload.privateKeyUri = this.uri.getRelativeSpec(Utils.makeURI(value));
},
get publicKeyUri() {
throw "attempted to get public key url from a public key!";
}
};
Utils.deferGetSet(PubKey, "payload", ["keyData", "privateKeyUri", "type"]);
Utils.deferGetSet(PubKey, "payload", ["keyData", "type"]);
function PrivKey(uri) {
WBORecord.call(this, uri);
@ -80,7 +82,6 @@ function PrivKey(uri) {
this.salt = null;
this.iv = null;
this.keyData = null;
this.publicKeyUri = null;
}
PrivKey.prototype = {
__proto__: WBORecord.prototype,
@ -94,13 +95,16 @@ PrivKey.prototype = {
let key = this.payload.publicKeyUri;
return Utils.makeURI(this.uri.resolve(key) || key);
},
set publicKeyUri(value) {
this.payload.publicKeyUri = this.uri.getRelativeSpec(Utils.makeURI(value));
},
get privateKeyUri() {
throw "attempted to get private key url from a private key!";
}
};
Utils.deferGetSet(PrivKey, "payload", ["salt", "iv", "keyData", "publicKeyUri", "type"]);
Utils.deferGetSet(PrivKey, "payload", ["salt", "iv", "keyData", "type"]);
// XXX unused/unfinished
function SymKey(keyData, wrapped) {
@ -137,9 +141,14 @@ PubKeyManager.prototype = {
},
createKeypair: function KeyMgr_createKeypair(passphrase, pubkeyUri, privkeyUri) {
if (!pubkeyUri)
throw "Missing or null parameter 'pubkeyUri'.";
if (!privkeyUri)
throw "Missing or null parameter 'privkeyUri'.";
this._log.debug("Generating RSA keypair");
let pubkey = new PubKey();
let privkey = new PrivKey();
let pubkey = new PubKey(pubkeyUri);
let privkey = new PrivKey(privkeyUri);
privkey.salt = Svc.Crypto.generateRandomBytes(16);
privkey.iv = Svc.Crypto.generateRandomIV();
@ -148,14 +157,8 @@ PubKeyManager.prototype = {
privkey.iv, pub, priv);
[pubkey.keyData, privkey.keyData] = [pub.value, priv.value];
if (pubkeyUri) {
pubkey.uri = pubkeyUri;
privkey.publicKeyUri = pubkeyUri;
}
if (privkeyUri) {
privkey.uri = privkeyUri;
pubkey.privateKeyUri = privkeyUri;
}
pubkey.privateKeyUri = privkeyUri;
privkey.publicKeyUri = pubkeyUri;
this._log.debug("Generating RSA keypair... done");
return {pubkey: pubkey, privkey: privkey};

Просмотреть файл

@ -46,10 +46,12 @@ Cu.import("resource://services-sync/resource.js");
Cu.import("resource://services-sync/util.js");
function WBORecord(uri) {
if (uri == null)
throw "WBOs must have a URI!";
this.data = {};
this.payload = {};
if (uri)
this.uri = uri;
this.uri = uri;
}
WBORecord.prototype = {
_logName: "Record.WBO",
@ -57,14 +59,14 @@ WBORecord.prototype = {
// NOTE: baseUri must have a trailing slash, or baseUri.resolve() will omit
// the collection name
get uri() {
return Utils.makeURI(this.baseUri.resolve(encodeURI(this.id)));
return Utils.makeURL(this.baseUri.resolve(encodeURI(this.id)));
},
set uri(value) {
if (typeof(value) != "string")
value = value.spec;
let foo = value.split('/');
this.id = foo.pop();
this.baseUri = Utils.makeURI(foo.join('/') + '/');
let parts = value.split('/');
this.id = parts.pop();
this.baseUri = Utils.makeURI(parts.join('/') + '/');
},
get sortindex() {
@ -122,9 +124,8 @@ RecordManager.prototype = {
if (!this.response.success)
return null;
let record = new this._recordType();
let record = new this._recordType(url);
record.deserialize(this.response);
record.uri = url;
return this.set(url, record);
}

Просмотреть файл

@ -44,7 +44,7 @@ WEAVE_ID: "@weave_id@",
// Version of the data format this client supports. The data format describes
// how records are packaged; this is separate from the Server API version and
// the per-engine cleartext formats.
STORAGE_VERSION: 2,
STORAGE_VERSION: 3,
UPDATED_DEV_URL: "https://services.mozilla.com/sync/updated/?version=@weave_version@&channel=@xpi_type@",
UPDATED_REL_URL: "http://www.mozilla.com/firefox/sync/updated.html",

Просмотреть файл

@ -337,7 +337,7 @@ SyncEngine.prototype = {
// Create a new record using the store and add in crypto fields
_createRecord: function SyncEngine__createRecord(id) {
let record = this._store.createRecord(id);
let record = this._store.createRecord(id, this.engineURL + "/" + id);
record.id = id;
record.encryption = this.cryptoMetaURL;
return record;

Просмотреть файл

@ -756,11 +756,11 @@ BookmarksStore.prototype = {
},
// Create a record starting from the weave id (places guid)
createRecord: function createRecord(guid) {
createRecord: function createRecord(guid, uri) {
let placeId = idForGUID(guid);
let record;
if (placeId <= 0) { // deleted item
record = new PlacesItem();
record = new PlacesItem(uri);
record.deleted = true;
return record;
}
@ -770,14 +770,14 @@ BookmarksStore.prototype = {
case this._bms.TYPE_BOOKMARK:
let bmkUri = this._bms.getBookmarkURI(placeId).spec;
if (this._ms && this._ms.hasMicrosummary(placeId)) {
record = new BookmarkMicsum();
record = new BookmarkMicsum(uri);
let micsum = this._ms.getMicrosummary(placeId);
record.generatorUri = micsum.generator.uri.spec; // breaks local generators
record.staticTitle = this._getStaticTitle(placeId);
}
else {
if (bmkUri.search(/^place:/) == 0) {
record = new BookmarkQuery();
record = new BookmarkQuery(uri);
// Get the actual tag name instead of the local itemId
let folder = bmkUri.match(/[:&]folder=(\d+)/);
@ -792,7 +792,7 @@ BookmarksStore.prototype = {
catch(ex) {}
}
else
record = new Bookmark();
record = new Bookmark(uri);
record.title = this._bms.getItemTitle(placeId);
}
@ -806,7 +806,7 @@ BookmarksStore.prototype = {
case this._bms.TYPE_FOLDER:
if (this._ls.isLivemark(placeId)) {
record = new Livemark();
record = new Livemark(uri);
let siteURI = this._ls.getSiteURI(placeId);
if (siteURI != null)
@ -814,7 +814,7 @@ BookmarksStore.prototype = {
record.feedUri = this._ls.getFeedURI(placeId).spec;
} else {
record = new BookmarkFolder();
record = new BookmarkFolder(uri);
}
record.parentName = Svc.Bookmark.getItemTitle(parent);
@ -823,19 +823,19 @@ BookmarksStore.prototype = {
break;
case this._bms.TYPE_SEPARATOR:
record = new BookmarkSeparator();
record = new BookmarkSeparator(uri);
// Create a positioning identifier for the separator
record.parentName = Svc.Bookmark.getItemTitle(parent);
record.pos = Svc.Bookmark.getItemIndex(placeId);
break;
case this._bms.TYPE_DYNAMIC_CONTAINER:
record = new PlacesItem();
record = new PlacesItem(uri);
this._log.warn("Don't know how to serialize dynamic containers yet");
break;
default:
record = new PlacesItem();
record = new PlacesItem(uri);
this._log.warn("Unknown item type, cannot serialize: " +
this._bms.getItemType(placeId));
}

Просмотреть файл

@ -180,8 +180,8 @@ ClientStore.prototype = {
this._remoteClients[record.id] = record.cleartext;
},
createRecord: function createRecord(guid) {
let record = new ClientsRec();
createRecord: function createRecord(guid, uri) {
let record = new ClientsRec(uri);
// Package the individual components into a record for the local client
if (guid == Clients.localID) {

Просмотреть файл

@ -163,8 +163,8 @@ FormStore.prototype = {
return FormWrapper.hasGUID(id);
},
createRecord: function createRecord(guid) {
let record = new FormRec();
createRecord: function createRecord(guid, uri) {
let record = new FormRec(uri);
let entry = FormWrapper.getEntry(guid);
if (entry != null) {
record.name = entry.name;

Просмотреть файл

@ -279,9 +279,9 @@ HistoryStore.prototype = {
return url ? this._hsvc.isVisited(url) : false;
},
createRecord: function createRecord(guid) {
createRecord: function createRecord(guid, uri) {
let foo = this._findURLByGUID(guid);
let record = new HistoryRec();
let record = new HistoryRec(uri);
if (foo) {
record.histUri = foo.url;
record.title = foo.title;

Просмотреть файл

@ -169,8 +169,8 @@ PasswordStore.prototype = {
return false;
},
createRecord: function createRecord(guid) {
let record = new LoginRec();
createRecord: function createRecord(guid, uri) {
let record = new LoginRec(uri);
let login = this._getLoginFromGUID(guid);
if (login) {

Просмотреть файл

@ -199,8 +199,8 @@ PrefStore.prototype = {
return (id === WEAVE_PREFS_GUID);
},
createRecord: function createRecord(guid) {
let record = new PrefRec();
createRecord: function createRecord(guid, uri) {
let record = new PrefRec(uri);
if (guid == WEAVE_PREFS_GUID) {
record.value = this._getAllPrefs();

Просмотреть файл

@ -146,8 +146,8 @@ TabStore.prototype = {
return allTabs;
},
createRecord: function createRecord(guid) {
let record = new TabSetRecord();
createRecord: function createRecord(guid, uri) {
let record = new TabSetRecord(uri);
record.clientName = Clients.localName;
// Don't provide any tabs to compare against and ignore the update later.

Просмотреть файл

@ -86,7 +86,7 @@ Store.prototype = {
throw "override itemExists in a subclass";
},
createRecord: function Store_createRecord(id) {
createRecord: function Store_createRecord(id, uri) {
throw "override createRecord in a subclass";
},

Просмотреть файл

@ -830,6 +830,69 @@ let Utils = {
}
},
/**
* Generate 20 random characters a-z
*/
generatePassphrase: function() {
let rng = Cc["@mozilla.org/security/random-generator;1"]
.createInstance(Ci.nsIRandomGenerator);
let bytes = rng.generateRandomBytes(20);
return [String.fromCharCode(97 + Math.floor(byte * 26 / 256))
for each (byte in bytes)].join("");
},
/**
* Hyphenate a 20 character passphrase in 4 groups of 5.
*/
hyphenatePassphrase: function(passphrase) {
return passphrase.slice(0, 5) + '-'
+ passphrase.slice(5, 10) + '-'
+ passphrase.slice(10, 15) + '-'
+ passphrase.slice(15, 20);
},
/**
* Remove hyphens as inserted by hyphenatePassphrase().
*/
normalizePassphrase: function(pp) {
if (pp.length == 23 && pp[5] == '-' && pp[11] == '-' && pp[17] == '-')
return pp.slice(0, 5) + pp.slice(6, 11)
+ pp.slice(12, 17) + pp.slice(18, 23);
return pp;
},
/*
* Calculate the strength of a passphrase provided by the user
* according to the NIST algorithm (NIST 800-63 Appendix A.1).
*/
passphraseStrength: function passphraseStrength(value) {
let bits = 0;
// The entropy of the first character is taken to be 4 bits.
if (value.length)
bits = 4;
// The entropy of the next 7 characters are 2 bits per character.
if (value.length > 1)
bits += Math.min(value.length - 1, 7) * 2;
// For the 9th through the 20th character the entropy is taken to
// be 1.5 bits per character.
if (value.length > 8)
bits += Math.min(value.length - 8, 12) * 1.5;
// For characters 21 and above the entropy is taken to be 1 bit per character.
if (value.length > 20)
bits += value.length - 20;
// Bonus of 6 bits if we find non-alphabetic characters
if ([char.charCodeAt() for each (char in value.toLowerCase())]
.some(function(chr) chr < 97 || chr > 122))
bits += 6;
return bits;
},
/**
* Create an array like the first but without elements of the second
*/

Просмотреть файл

@ -4,6 +4,8 @@ pref("services.sync.userURL", "user/");
pref("services.sync.miscURL", "misc/");
pref("services.sync.termsURL", "https://services.mozilla.com/tos/");
pref("services.sync.privacyURL", "https://services.mozilla.com/privacy-policy/");
pref("services.sync.statusURL", "https://services.mozilla.com/status/");
pref("services.sync.syncKeyHelpURL", "https://services.mozilla.com/help/synckey");
pref("services.sync.lastversion", "firstrun");
pref("services.sync.autoconnect", true);

Просмотреть файл

@ -45,7 +45,7 @@ function run_test() {
check([]);
function $B(name, parent, pred) {
let bookmark = new Bookmark();
let bookmark = new Bookmark("http://weave.server/my-bookmark");
bookmark.id = name;
bookmark.title = name;
bookmark.bmkUri = "http://uri/";
@ -56,7 +56,7 @@ function run_test() {
}
function $F(name, parent, pred) {
let folder = new BookmarkFolder();
let folder = new BookmarkFolder("http://weave.server/my-bookmark-folder");
folder.id = name;
folder.title = name;
folder.parentid = parent || "unfiled";

Просмотреть файл

@ -3,6 +3,8 @@ Cu.import("resource://services-sync/engines/bookmarks.js");
Cu.import("resource://services-sync/util.js");
function run_test() {
let baseuri = "http://fake/uri/";
_("Starting with a clean slate of no bookmarks");
let store = new (new BookmarksEngine())._storeObj();
store.wipe();
@ -21,11 +23,11 @@ function run_test() {
let second = insert(10);
_("Making sure the record created for the first has no predecessor");
let pos5 = store.createRecord("pos5");
let pos5 = store.createRecord("pos5", baseuri + "pos5");
do_check_eq(pos5.predecessorid, undefined);
_("Making sure the second record has the first as its predecessor");
let pos10 = store.createRecord("pos10");
let pos10 = store.createRecord("pos10", baseuri + "pos10");
do_check_eq(pos10.predecessorid, "pos5");
_("Make sure the index of item gets fixed");
@ -35,6 +37,8 @@ function run_test() {
_("Make sure things that are in unsorted don't set the predecessor");
insert(0, Svc.Bookmark.unfiledBookmarksFolder);
insert(1, Svc.Bookmark.unfiledBookmarksFolder);
do_check_eq(store.createRecord("pos0").predecessorid, undefined);
do_check_eq(store.createRecord("pos1").predecessorid, undefined);
do_check_eq(store.createRecord("pos0", baseuri + "pos0").predecessorid,
undefined);
do_check_eq(store.createRecord("pos1", baseuri + "pos1").predecessorid,
undefined);
}

Просмотреть файл

@ -35,7 +35,7 @@ function run_test() {
do_check_eq(Svc.Bookmark.getKeywordForBookmark(id), fxrecord.keyword);
_("Have the store create a new record object. Verify that it has the same data.");
let newrecord = store.createRecord(fxrecord.id);
let newrecord = store.createRecord(fxrecord.id, "http://fake/uri");
for each (let property in ["type", "bmkUri", "title", "keyword",
"parentName", "parentid"])
do_check_eq(newrecord[property], fxrecord[property]);

Просмотреть файл

@ -1,58 +1,65 @@
Cu.import("resource://services-sync/base_records/crypto.js");
Cu.import("resource://services-sync/base_records/keys.js");
Cu.import("resource://services-sync/engines/clients.js");
Cu.import("resource://services-sync/identity.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/identity.js");
function run_test() {
let baseUri = "http://fakebase/";
let pubUri = baseUri + "pubkey";
let privUri = baseUri + "privkey";
let cryptoUri = baseUri + "crypto";
_("Set up test fixtures.");
ID.set('WeaveID', new Identity('Some Identity', 'foo'));
Svc.Prefs.set("clusterURL", "http://fakebase/");
let baseUri = "http://fakebase/1.0/foo/storage/";
let pubUri = baseUri + "keys/pubkey";
let privUri = baseUri + "keys/privkey";
let passphrase = ID.set("WeaveCryptoID", new Identity());
passphrase.password = "passphrase";
_("Setting up fake pub/priv keypair and symkey for encrypt/decrypt");
PubKeys.defaultKeyUri = baseUri + "pubkey";
PubKeys.defaultKeyUri = baseUri + "keys/pubkey";
let {pubkey, privkey} = PubKeys.createKeypair(passphrase, pubUri, privUri);
PubKeys.set(pubUri, pubkey);
PrivKeys.set(privUri, privkey);
let cryptoMeta = new CryptoMeta(cryptoUri);
let cryptoMeta = new CryptoMeta(Clients.cryptoMetaURL);
cryptoMeta.addUnwrappedKey(pubkey, Svc.Crypto.generateRandomKey());
CryptoMetas.set(cryptoUri, cryptoMeta);
CryptoMetas.set(Clients.cryptoMetaURL, cryptoMeta);
_("Test that serializing client records results in uploadable ascii");
Clients.__defineGetter__("cryptoMetaURL", function() cryptoUri);
Clients.localID = "ascii";
Clients.localName = "wéävê";
try {
_("Test that serializing client records results in uploadable ascii");
Clients.localID = "ascii";
Clients.localName = "wéävê";
_("Make sure we have the expected record");
let record = Clients._createRecord("ascii");
do_check_eq(record.id, "ascii");
do_check_eq(record.name, "wéävê");
_("Make sure we have the expected record");
let record = Clients._createRecord("ascii");
do_check_eq(record.id, "ascii");
do_check_eq(record.name, "wéävê");
record.encrypt(passphrase)
let serialized = JSON.stringify(record);
let checkCount = 0;
_("Checking for all ASCII:", serialized);
Array.forEach(serialized, function(ch) {
let code = ch.charCodeAt(0);
_("Checking asciiness of '", ch, "'=", code);
do_check_true(code < 128);
checkCount++;
});
record.encrypt(passphrase);
let serialized = JSON.stringify(record);
let checkCount = 0;
_("Checking for all ASCII:", serialized);
Array.forEach(serialized, function(ch) {
let code = ch.charCodeAt(0);
_("Checking asciiness of '", ch, "'=", code);
do_check_true(code < 128);
checkCount++;
});
_("Processed", checkCount, "characters out of", serialized.length);
do_check_eq(checkCount, serialized.length);
_("Processed", checkCount, "characters out of", serialized.length);
do_check_eq(checkCount, serialized.length);
_("Making sure the record still looks like it did before");
record.decrypt(passphrase)
do_check_eq(record.id, "ascii");
do_check_eq(record.name, "wéävê");
_("Making sure the record still looks like it did before");
record.decrypt(passphrase);
do_check_eq(record.id, "ascii");
do_check_eq(record.name, "wéävê");
_("Sanity check that creating the record also gives the same");
record = Clients._createRecord("ascii");
do_check_eq(record.id, "ascii");
do_check_eq(record.name, "wéävê");
_("Sanity check that creating the record also gives the same");
record = Clients._createRecord("ascii");
do_check_eq(record.id, "ascii");
do_check_eq(record.name, "wéävê");
} finally {
Svc.Prefs.resetBranch("");
}
}

Просмотреть файл

@ -3,17 +3,19 @@ Cu.import("resource://services-sync/base_records/collection.js");
Cu.import("resource://services-sync/base_records/wbo.js");
function run_test() {
let coll = new Collection("", WBORecord);
let coll = new Collection("http://fake/uri", WBORecord);
let stream = { _data: "" };
let called, recCount, sum;
_("Not-JSON, string payloads are strings");
called = false;
stream._data = '{"payload":"hello"}\n';
stream._data = '{"id":"hello","payload":"world"}\n';
coll.recordHandler = function(rec) {
called = true;
_("Got record:", JSON.stringify(rec));
do_check_eq(rec.payload, "hello");
do_check_eq(rec.id, "hello");
do_check_eq(rec.uri.spec, "http://fake/uri/hello");
do_check_eq(rec.payload, "world");
};
coll._onProgress.call(stream);
do_check_eq(stream._data, '');
@ -39,7 +41,7 @@ function run_test() {
called = false;
recCount = 0;
sum = 0;
stream._data = '{"payload":"{\\"value\\":100}"}\n{"payload":"{\\"value\\":10}"}\n{"payload":"{\\"value\\":1}"}\n';
stream._data = '{"id":"hundred","payload":"{\\"value\\":100}"}\n{"id":"ten","payload":"{\\"value\\":10}"}\n{"id":"one","payload":"{\\"value\\":1}"}\n';
coll.recordHandler = function(rec) {
called = true;
_("Got record:", JSON.stringify(rec));
@ -48,14 +50,20 @@ function run_test() {
_("Incremental status: count", recCount, "sum", sum);
switch (recCount) {
case 1:
do_check_eq(rec.id, "hundred");
do_check_eq(rec.uri.spec, "http://fake/uri/hundred");
do_check_eq(rec.payload.value, 100);
do_check_eq(sum, 100);
break;
case 2:
do_check_eq(rec.id, "ten");
do_check_eq(rec.uri.spec, "http://fake/uri/ten");
do_check_eq(rec.payload.value, 10);
do_check_eq(sum, 110);
break;
case 3:
do_check_eq(rec.id, "one");
do_check_eq(rec.uri.spec, "http://fake/uri/one");
do_check_eq(rec.payload.value, 1);
do_check_eq(sum, 111);
break;

Просмотреть файл

@ -3,6 +3,7 @@ Cu.import("resource://services-sync/engines/forms.js");
Cu.import("resource://services-sync/type_records/forms.js");
function run_test() {
let baseuri = "http://fake/uri/";
let store = new FormEngine()._store;
_("Remove any existing entries");
@ -27,13 +28,13 @@ function run_test() {
}
do_check_true(store.itemExists(id));
let rec = store.createRecord(id);
let rec = store.createRecord(id, baseuri + id);
_("Got record for id", id, rec);
do_check_eq(rec.name, "name!!");
do_check_eq(rec.value, "value??");
_("Create a non-existant id for delete");
do_check_true(store.createRecord("deleted!!").deleted);
_("Create a non-existent id for delete");
do_check_true(store.createRecord("deleted!!", baseuri + "deleted!!").deleted);
_("Try updating.. doesn't do anything yet");
store.update({});

Просмотреть файл

@ -71,11 +71,11 @@ function run_test() {
do_check_true(store.itemExists(fxguid));
_("If we query a non-existent record, it's marked as deleted.");
let record = store.createRecord("non-existent");
let record = store.createRecord("non-existent", "http://fake/uri");
do_check_true(record.deleted);
_("Verify createRecord() returns a complete record.");
record = store.createRecord(fxguid);
record = store.createRecord(fxguid, "http://fake/urk");
do_check_eq(record.histUri, fxuri.spec);
do_check_eq(record.title, "Get Firefox!");
do_check_eq(record.visits.length, 1);

Просмотреть файл

@ -8,28 +8,28 @@ Cu.import("resource://services-sync/util.js");
let keys, cryptoMeta, cryptoWrap;
function pubkey_handler(metadata, response) {
let obj = {id: "ignore-me",
let obj = {id: "pubkey",
modified: keys.pubkey.modified,
payload: JSON.stringify(keys.pubkey.payload)};
return httpd_basic_auth_handler(JSON.stringify(obj), metadata, response);
}
function privkey_handler(metadata, response) {
let obj = {id: "ignore-me-2",
let obj = {id: "privkey",
modified: keys.privkey.modified,
payload: JSON.stringify(keys.privkey.payload)};
return httpd_basic_auth_handler(JSON.stringify(obj), metadata, response);
}
function crypted_resource_handler(metadata, response) {
let obj = {id: "ignore-me-3",
let obj = {id: "resource",
modified: cryptoWrap.modified,
payload: JSON.stringify(cryptoWrap.payload)};
return httpd_basic_auth_handler(JSON.stringify(obj), metadata, response);
}
function crypto_meta_handler(metadata, response) {
let obj = {id: "ignore-me-4",
let obj = {id: "steam",
modified: cryptoMeta.modified,
payload: JSON.stringify(cryptoMeta.payload)};
return httpd_basic_auth_handler(JSON.stringify(obj), metadata, response);
@ -48,34 +48,39 @@ function run_test() {
log.info("Setting up server and authenticator");
server = httpd_setup({"/pubkey": pubkey_handler,
"/privkey": privkey_handler,
"/crypted-resource": crypted_resource_handler,
"/crypto-meta": crypto_meta_handler});
server = httpd_setup({"/keys/pubkey": pubkey_handler,
"/keys/privkey": privkey_handler,
"/steam/resource": crypted_resource_handler,
"/crypto/steam": crypto_meta_handler});
let auth = new BasicAuthenticator(new Identity("secret", "guest", "guest"));
Auth.defaultAuthenticator = auth;
log.info("Generating keypair + symmetric key");
PubKeys.defaultKeyUri = "http://localhost:8080/pubkey";
PubKeys.defaultKeyUri = "http://localhost:8080/keys/pubkey";
keys = PubKeys.createKeypair(passphrase,
"http://localhost:8080/pubkey",
"http://localhost:8080/privkey");
"http://localhost:8080/keys/pubkey",
"http://localhost:8080/keys/privkey");
let crypto = Svc.Crypto;
keys.symkey = crypto.generateRandomKey();
keys.wrappedkey = crypto.wrapSymmetricKey(keys.symkey, keys.pubkey.keyData);
log.info("Setting up keyring");
cryptoMeta = new CryptoMeta("http://localhost:8080/crypto-meta", auth);
cryptoMeta = new CryptoMeta("http://localhost:8080/crypto/steam", auth);
cryptoMeta.addUnwrappedKey(keys.pubkey, keys.symkey);
CryptoMetas.set(cryptoMeta.uri, cryptoMeta);
log.info("Creating and encrypting a record");
log.info("Creating a record");
cryptoWrap = new CryptoWrapper("http://localhost:8080/steam/resource");
cryptoWrap.encryption = "http://localhost:8080/crypto/steam";
do_check_eq(cryptoWrap.encryption, "http://localhost:8080/crypto/steam");
do_check_eq(cryptoWrap.payload.encryption, "../crypto/steam");
log.info("Encrypting a record");
cryptoWrap = new CryptoWrapper("http://localhost:8080/crypted-resource", auth);
cryptoWrap.encryption = "http://localhost:8080/crypto-meta";
cryptoWrap.cleartext.stuff = "my payload here";
cryptoWrap.encrypt(passphrase);
let firstIV = cryptoWrap.IV;
@ -107,7 +112,7 @@ function run_test() {
catch(ex) {
error = ex;
}
do_check_eq(error, "Record id mismatch: crypted-resource,other");
do_check_eq(error, "Record id mismatch: resource,other");
log.info("Make sure wrong hmacs cause failures");
cryptoWrap.encrypt(passphrase);

Просмотреть файл

@ -30,8 +30,9 @@ function run_test() {
crypto.addUnwrappedKey(pubkey, symkey);
_("Changing the HMAC to force a mismatch");
let goodHMAC = crypto.keyring[pubkey.uri.spec].hmac;
crypto.keyring[pubkey.uri.spec].hmac = "failme!";
let relUri = crypto.uri.getRelativeSpec(pubkey.uri);
let goodHMAC = crypto.keyring[relUri].hmac;
crypto.keyring[relUri].hmac = "failme!";
let error = "";
try {
crypto.getKey(privkey, passphrase);
@ -42,6 +43,6 @@ function run_test() {
do_check_eq(error, "Key SHA256 HMAC mismatch: failme!");
_("Switching back to the correct HMAC and trying again");
crypto.keyring[pubkey.uri.spec].hmac = goodHMAC;
crypto.keyring[relUri].hmac = goodHMAC;
crypto.getKey(privkey, passphrase);
}

Просмотреть файл

@ -52,8 +52,25 @@ function test_createKeypair() {
let id = ID.set('foo', new Identity('foo', 'luser'));
id.password = passphrase;
_("Key pair requires URIs for both keys.");
let error;
try {
let result = PubKeys.createKeypair(id);
} catch(ex) {
error = ex;
}
do_check_eq(error, "Missing or null parameter 'pubkeyUri'.");
error = undefined;
try {
let result = PubKeys.createKeypair(id, "http://host/pub/key");
} catch(ex) {
error = ex;
}
do_check_eq(error, "Missing or null parameter 'privkeyUri'.");
_("Generate a key pair.");
let result = PubKeys.createKeypair(id, "http://pub/key", "http://priv/key");
let result = PubKeys.createKeypair(id, "http://host/pub/key", "http://host/priv/key");
_("Check that salt and IV are of correct length.");
// 16 bytes = 24 base64 encoded characters
@ -61,10 +78,13 @@ function test_createKeypair() {
do_check_eq(result.privkey.iv.length, 24);
_("URIs are set.");
do_check_eq(result.pubkey.uri.spec, "http://pub/key");
do_check_eq(result.pubkey.privateKeyUri.spec, "http://priv/key");
do_check_eq(result.privkey.uri.spec, "http://priv/key");
do_check_eq(result.privkey.publicKeyUri.spec, "http://pub/key");
do_check_eq(result.pubkey.uri.spec, "http://host/pub/key");
do_check_eq(result.pubkey.privateKeyUri.spec, "http://host/priv/key");
do_check_eq(result.pubkey.payload.privateKeyUri, "../priv/key");
do_check_eq(result.privkey.uri.spec, "http://host/priv/key");
do_check_eq(result.privkey.publicKeyUri.spec, "http://host/pub/key");
do_check_eq(result.privkey.payload.publicKeyUri, "../pub/key");
_("UTF8 encoded passphrase was used.");
do_check_true(Svc.Crypto.verifyPassphrase(result.privkey.keyData,

Просмотреть файл

@ -51,7 +51,7 @@ function run_test() {
let res = new Resource("http://localhost:8080/record");
let resp = res.get();
let rec = new WBORecord();
let rec = new WBORecord("http://localhost:8080/record");
rec.deserialize(res.data);
do_check_eq(rec.id, "asdf-1234-asdf-1234"); // NOT "record"!

Просмотреть файл

@ -46,8 +46,8 @@ SteamStore.prototype = {
return (id in this.items);
},
createRecord: function(id) {
var record = new SteamRecord();
createRecord: function(id, uri) {
var record = new SteamRecord(uri);
record.id = id;
record.denomination = this.items[id] || "Data for new record: " + id;
return record;
@ -257,7 +257,7 @@ function test_syncStartup_metaGet404() {
do_check_eq(collection.wbos.scotsman.payload, undefined);
_("New bulk key was uploaded");
let key = crypto_steam.data.keyring["http://localhost:8080/1.0/foo/storage/keys/pubkey"];
let key = crypto_steam.data.keyring["../keys/pubkey"];
do_check_eq(key.wrapped, "fake-symmetric-key-0");
do_check_eq(key.hmac, "fake-symmetric-key-0 ");
@ -439,7 +439,7 @@ function test_syncStartup_badKeyWipesServerData() {
do_check_eq(collection.wbos.scotsman.payload, undefined);
// New bulk key was uploaded
key = crypto_steam.data.keyring["http://localhost:8080/1.0/foo/storage/keys/pubkey"];
key = crypto_steam.data.keyring["../keys/pubkey"];
do_check_eq(key.wrapped, "fake-symmetric-key-1");
do_check_eq(key.hmac, "fake-symmetric-key-1 ");

Просмотреть файл

@ -0,0 +1,47 @@
Cu.import("resource://services-sync/engines/tabs.js");
Cu.import("resource://services-sync/util.js");
function fakeSessionSvc() {
let tabs = [];
for(let i = 0; i < arguments.length; i++) {
tabs.push({
index: 1,
entries: [{
url: arguments[i],
title: "title"
}],
attributes: {
image: "image"
},
extData: {
weaveLastUsed: 1
}
});
}
let obj = {windows: [{tabs: tabs}]};
// delete the getter, or the previously created fake Session
delete Svc.Session;
Svc.Session = {
getBrowserState: function() JSON.stringify(obj)
};
}
function run_test() {
_("test locallyOpenTabMatchesURL");
let engine = new TabEngine();
// 3 tabs
fakeSessionSvc("http://bar.com", "http://foo.com", "http://foobar.com");
let matches;
_(" test matching works (true)");
matches = engine.locallyOpenTabMatchesURL("http://foo.com");
do_check_true(matches);
_(" test matching works (false)");
matches = engine.locallyOpenTabMatchesURL("http://barfoo.com");
do_check_false(matches);
}

Просмотреть файл

@ -0,0 +1,119 @@
Cu.import("resource://services-sync/engines/tabs.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/type_records/tabs.js");
function test_create() {
let store = new TabEngine()._store;
_("Create a first record");
let rec = {id: "id1",
clientName: "clientName1",
cleartext: "cleartext1",
modified: 1000};
store.applyIncoming(rec);
do_check_eq(store._remoteClients["id1"], "cleartext1");
do_check_eq(Svc.Prefs.get("notifyTabState"), 1);
_("Create a second record");
let rec = {id: "id2",
clientName: "clientName2",
cleartext: "cleartext2",
modified: 2000};
store.applyIncoming(rec);
do_check_eq(store._remoteClients["id2"], "cleartext2");
do_check_eq(Svc.Prefs.get("notifyTabState"), 0);
_("Create a third record");
let rec = {id: "id3",
clientName: "clientName3",
cleartext: "cleartext3",
modified: 3000};
store.applyIncoming(rec);
do_check_eq(store._remoteClients["id3"], "cleartext3");
do_check_eq(Svc.Prefs.get("notifyTabState"), 0);
// reset the notifyTabState
Svc.Prefs.reset("notifyTabState");
}
function fakeSessionSvc(url, numtabs) {
// first delete the getter, or the previously
// created fake Session
delete Svc.Session;
Svc.Session = {
getBrowserState: function() {
let obj = {
windows: [{
tabs: [{
index: 1,
entries: [{
url: url,
title: "title"
}],
attributes: {
image: "image"
},
extData: {
weaveLastUsed: 1
}
}]
}]
};
if (numtabs) {
let tabs = obj.windows[0].tabs;
for (let i = 0; i < numtabs-1; i++)
tabs.push(Utils.deepCopy(tabs[0]));
}
return JSON.stringify(obj);
}
};
};
function test_getAllTabs() {
let store = new TabEngine()._store, tabs;
_("get all tabs");
fakeSessionSvc("http://foo.com");
tabs = store.getAllTabs();
do_check_eq(tabs.length, 1);
do_check_eq(tabs[0].title, "title");
do_check_eq(tabs[0].urlHistory.length, 1);
do_check_eq(tabs[0].urlHistory[0], ["http://foo.com"]);
do_check_eq(tabs[0].icon, "image");
do_check_eq(tabs[0].lastUsed, 1);
_("get all tabs, and check that filtering works");
// we don't bother testing every URL type here, the
// filteredUrls regex really should have it own tests
fakeSessionSvc("about:foo");
tabs = store.getAllTabs(true);
do_check_eq(tabs.length, 0);
}
function test_createRecord() {
let store = new TabEngine()._store, record;
// get some values before testing
fakeSessionSvc("http://foo.com");
let tabs = store.getAllTabs();
let tabsize = JSON.stringify(tabs[0]).length;
let numtabs = Math.ceil(20000./77.);
_("create a record");
fakeSessionSvc("http://foo.com");
record = store.createRecord("fake-guid", "http://fake.uri/");
do_check_true(record instanceof TabSetRecord);
do_check_eq(record.tabs.length, 1);
_("create a big record");
fakeSessionSvc("http://foo.com", numtabs);
record = store.createRecord("fake-guid", "http://fake.uri/");
do_check_true(record instanceof TabSetRecord);
do_check_eq(record.tabs.length, 256);
}
function run_test() {
test_create();
test_getAllTabs();
test_createRecord();
}

Просмотреть файл

@ -0,0 +1,97 @@
Cu.import("resource://services-sync/engines/tabs.js");
Cu.import("resource://services-sync/engines/clients.js");
Cu.import("resource://services-sync/util.js");
function fakeSvcWinMediator() {
// actions on windows are captured in logs
let logs = [];
delete Svc.WinMediator;
Svc.WinMediator = {
getEnumerator: function() {
return {
cnt: 2,
hasMoreElements: function() this.cnt-- > 0,
getNext: function() {
let elt = {addTopics: [], remTopics: []};
logs.push(elt);
return {
addEventListener: function(topic) {
elt.addTopics.push(topic);
},
removeEventListener: function(topic) {
elt.remTopics.push(topic);
}
};
}
};
}
};
return logs;
}
function fakeSvcSession() {
// actions on Session are captured in logs
let logs = [];
delete Svc.Session;
Svc.Session = {
setTabValue: function(target, prop, value) {
logs.push({target: target, prop: prop, value: value});
}
};
return logs;
}
function run_test() {
let engine = new TabEngine();
engine._store.wipe();
_("Verify we have an empty tracker to work with");
let tracker = engine._tracker;
do_check_eq([id for (id in tracker.changedIDs)].length, 0);
let logs;
_("Test listeners are registered on windows");
logs = fakeSvcWinMediator();
Svc.Obs.notify("weave:engine:start-tracking");
do_check_eq(logs.length, 2);
for each (let log in logs) {
do_check_eq(log.addTopics.length, 5);
do_check_true(log.addTopics.indexOf("pageshow") >= 0);
do_check_true(log.addTopics.indexOf("TabOpen") >= 0);
do_check_true(log.addTopics.indexOf("TabClose") >= 0);
do_check_true(log.addTopics.indexOf("TabSelect") >= 0);
do_check_true(log.addTopics.indexOf("unload") >= 0);
do_check_eq(log.remTopics.length, 0);
}
_("Test listeners are unregistered on windows");
logs = fakeSvcWinMediator();
Svc.Obs.notify("weave:engine:stop-tracking");
do_check_eq(logs.length, 2);
for each (let log in logs) {
do_check_eq(log.addTopics.length, 0);
do_check_eq(log.remTopics.length, 5);
do_check_true(log.remTopics.indexOf("pageshow") >= 0);
do_check_true(log.remTopics.indexOf("TabOpen") >= 0);
do_check_true(log.remTopics.indexOf("TabClose") >= 0);
do_check_true(log.remTopics.indexOf("TabSelect") >= 0);
do_check_true(log.remTopics.indexOf("unload") >= 0);
}
_("Test tab listener");
logs = fakeSvcSession();
let idx = 0;
for each (let evttype in ["TabOpen", "TabClose", "TabSelect"]) {
tracker.onTab({type: evttype , originalTarget: evttype});
do_check_eq([id for (id in tracker.changedIDs)].length, 1);
do_check_eq(logs.length, idx+1);
do_check_eq(logs[idx].target, evttype);
do_check_eq(logs[idx].prop, "weaveLastUsed");
do_check_true(typeof logs[idx].value == "number");
idx++;
}
tracker.onTab({type: "pageshow", originalTarget: "pageshow"});
do_check_eq([id for (id in tracker.changedIDs)].length, 1);
do_check_eq(logs.length, idx); // test that setTabValue isn't called
}

Просмотреть файл

@ -0,0 +1,15 @@
Cu.import("resource://services-sync/util.js");
function run_test() {
let thing = {o: {foo: "foo", bar: ["bar"]}, a: ["foo", {bar: "bar"}]};
let ret = Utils.deepCopy(thing);
do_check_neq(ret, thing)
do_check_neq(ret.o, thing.o);
do_check_neq(ret.o.bar, thing.o.bar);
do_check_neq(ret.a, thing.a);
do_check_neq(ret.a[1], thing.a[1]);
do_check_eq(ret.o.foo, thing.o.foo);
do_check_eq(ret.o.bar[0], thing.o.bar[0]);
do_check_eq(ret.a[0], thing.a[0]);
do_check_eq(ret.a[1].bar, thing.a[1].bar);
}

Просмотреть файл

@ -0,0 +1,35 @@
Cu.import("resource://services-sync/util.js");
function WinMock(href) {
this.location = {href: href};
this._open = true;
};
WinMock.prototype = {
addEventListener: function(type, listener) {
this._listener = listener;
},
close: function() {
if (this._listener) {
this._listener();
}
this._open = false;
}
};
function run_test() {
let w1 = new WinMock("chrome://win/win.xul");
Utils.ensureOneOpen(w1);
do_check_true(w1._open);
let w2 = new WinMock("chrome://win/win.xul");
Utils.ensureOneOpen(w2);
do_check_false(w1._open);
// close w2 and test that ensureOneOpen doesn't
// close it again
w2.close();
w2._open = true;
let w3 = new WinMock("chrome://win/win.xul");
Utils.ensureOneOpen(w3);
do_check_true(w2._open);
}

Просмотреть файл

@ -0,0 +1,134 @@
_("Test file-related utility functions");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/constants.js");
function run_test() {
_test_getTmp();
_test_open();
}
function _test_getTmp() {
// as the setup phase remove the tmp directory from the
// filesystem
let svc = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
let tmp = svc.get("ProfD", Ci.nsIFile);
tmp.QueryInterface(Ci.nsILocalFile);
tmp.append("weave");
tmp.append("tmp");
if (tmp.exists())
tmp.remove(true);
// call getTmp with no argument. A ref to the tmp
// dir is returned
_("getTmp with no argument");
let tmpDir = Utils.getTmp();
do_check_true(tmpDir instanceof Ci.nsILocalFile);
do_check_true(tmpDir.isDirectory());
do_check_true(tmpDir.exists());
do_check_eq(tmpDir.leafName, "tmp");
// call getTmp with a string. A ref to the file
// named with this string and included in the
// tmp dir is returned
_("getTmp with a string");
let tmpFile = Utils.getTmp("name");
do_check_true(tmpFile instanceof Ci.nsILocalFile);
do_check_true(!tmpFile.exists()); // getTmp doesn't create the file!
do_check_eq(tmpFile.leafName, "name");
do_check_true(tmpDir.contains(tmpFile, false));
}
function _test_open() {
// we rely on Utils.getTmp to get a temporary file and
// test Utils.open on that file, that's ok Util.getTmp
// is also tested (test_getTmp)
function createFile() {
let f = Utils.getTmp("_test_");
f.create(f.NORMAL_FILE_TYPE, PERMS_FILE);
return f;
}
// we should probably test more things here, for example
// we should test that we cannot write to a stream that
// is created as a result of opening a file for reading
let s, f;
_("Open for reading, providing a file");
let f1 = createFile();
[s, f] = Utils.open(f1, "<");
do_check_eq(f.path, f1.path);
do_check_true(s instanceof Ci.nsIConverterInputStream);
f1.remove(false);
_("Open for reading, providing a file name");
let f2 = createFile();
let path2 = f2.path;
[s, f] = Utils.open(path2, "<");
do_check_eq(f.path, path2);
do_check_true(s instanceof Ci.nsIConverterInputStream);
f2.remove(false);
_("Open for writing with truncate mode, providing a file");
let f3 = createFile();
[s, f] = Utils.open(f3, ">");
do_check_eq(f.path, f3.path);
do_check_true(s instanceof Ci.nsIConverterOutputStream);
f3.remove(false);
_("Open for writing with truncate mode, providing a file name");
let f4 = createFile();
let path4 = f4.path;
[s, f] = Utils.open(path4, ">");
do_check_eq(f.path, path4);
do_check_true(s instanceof Ci.nsIConverterOutputStream);
f4.remove(false);
_("Open for writing with append mode, providing a file");
let f5 = createFile();
[s, f] = Utils.open(f5, ">>");
do_check_eq(f.path, f5.path);
do_check_true(s instanceof Ci.nsIConverterOutputStream);
f5.remove(false);
_("Open for writing with append mode, providing a file name");
let f6 = createFile();
let path6 = f6.path;
[s, f] = Utils.open(path6, ">>");
do_check_eq(f.path, path6);
do_check_true(s instanceof Ci.nsIConverterOutputStream);
f6.remove(false);
_("Open with illegal mode");
let f7 = createFile();
let except7;
try {
Utils.open(f7, "?!");
} catch(e) {
except7 = e;
}
do_check_true(!!except7);
f7.remove(false);
_("Open non-existing file for reading");
let f8 = createFile();
let path8 = f8.path;
f8.remove(false);
let except8;
try {
Utils.open(path8, "<");
} catch(e) {
except8 = e;
}
do_check_true(!!except8);
_("Open for reading, provide permissions");
let f9 = createFile();
[s, f] = Utils.open(f9, "<", 0644);
do_check_eq(f.path, f9.path);
do_check_true(s instanceof Ci.nsIConverterInputStream);
f9.remove(false);
}

Просмотреть файл

@ -0,0 +1,14 @@
Cu.import("resource://services-sync/util.js");
function run_test() {
let str;
// we just test whether the returned string includes the
// string "unknown", should be good enough
str = Utils.getErrorString("error.login.reason.password");
do_check_true(str.match(/unknown/i) == null);
str = Utils.getErrorString("foobar");
do_check_true(str.match(/unknown/i) != null);
}

Просмотреть файл

@ -0,0 +1,18 @@
Cu.import("resource://services-sync/util.js");
function run_test() {
_("Test with a valid icon URI");
let iconUri = "http://foo.bar/favicon.png";
let icon1 = Utils.getIcon(iconUri);
do_check_true(icon1.indexOf(iconUri) > 0);
_("Test with an invalid icon URI and default icon");
let icon2 = Utils.getIcon("foo", "bar");
do_check_eq(icon2, "bar");
_("Test with an invalid icon URI and no default icon");
let icon3 = Utils.getIcon("foo");
var defaultFavicon = Cc["@mozilla.org/browser/favicon-service;1"]
.getService(Ci.nsIFaviconService).defaultFavicon.spec;
do_check_eq(icon3, defaultFavicon);
}

Просмотреть файл

@ -0,0 +1,14 @@
Cu.import("resource://services-sync/util.js");
let undef;
function run_test() {
do_check_true(Utils.isArray([]));
do_check_true(Utils.isArray([1, 2]));
do_check_false(Utils.isArray({}));
do_check_false(Utils.isArray(1.0));
do_check_false(Utils.isArray("string"));
do_check_false(Utils.isArray(null));
do_check_false(Utils.isArray(undef));
do_check_false(Utils.isArray(new Date()));
}

Просмотреть файл

@ -43,4 +43,18 @@ function run_test() {
});
do_check_eq(typeof num, "number");
do_check_eq(num, 42);
_("Verify that things get logged");
let trace, debug;
Utils.jsonSave("str",
{_log: {trace: function(msg) { trace = msg; }}},
"hi");
do_check_true(!!trace);
trace = undefined;
Utils.jsonLoad("str",
{_log: {trace: function(msg) { trace = msg; },
debug: function(msg) { debug = msg; }}},
function(val) { throw "exception"; });
do_check_true(!!trace);
do_check_true(!!debug);
}

Просмотреть файл

@ -0,0 +1,11 @@
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/ext/StringBundle.js");
function run_test() {
let fn = Utils.lazyStrings("sync");
do_check_eq(typeof fn, "function");
let bundle = fn();
do_check_true(bundle instanceof StringBundle);
let url = bundle.url;
do_check_eq(url, "chrome://weave/locale/services/sync.properties");
}

Просмотреть файл

@ -1,7 +1,15 @@
_("Make sure uri strings are converted to nsIURIs");
Cu.import("resource://services-sync/util.js");
// both the makeURI and makeURL functions are tested
// in this file
function run_test() {
_test_makeURI();
_test_makeURL();
}
function _test_makeURI() {
_("Check http uris");
let uri1 = "http://mozillalabs.com/";
do_check_eq(Utils.makeURI(uri1).spec, uri1);
@ -57,3 +65,35 @@ function run_test() {
do_check_eq(Utils.makeURI("chrome://badstuff"), undefined);
do_check_eq(Utils.makeURI("this is a test"), undefined);
}
function _test_makeURL() {
_("Check http uri");
let uri = "http://mozillalabs.com/";
do_check_true(Utils.makeURL(uri) instanceof Ci.nsIURL);
_("Check https uri");
let uris = "https://mozillalabs.com/";
do_check_true(Utils.makeURL(uris) instanceof Ci.nsIURL);
let uric = "chrome://browser/content/browser.xul";
do_check_true(Utils.makeURL(uric) instanceof Ci.nsIURL);
_("Check about uri");
let uria = "about:weave";
let except1;
try {
Utils.makeURL(uria);
} catch(e) {
except1 = e;
}
do_check_true(!!except1);
_("Check invalid uri");
let except2;
try {
Utils.makeURL("mozillalabs.com");
} catch(e) {
except2 = e;
}
do_check_true(!!except2);
}

Просмотреть файл

@ -0,0 +1,41 @@
Cu.import("resource://services-sync/util.js");
function run_test() {
_("Generated passphrase has length 20.");
let pp = Utils.generatePassphrase();
do_check_eq(pp.length, 20);
_("Passphrase only contains a-z.");
let bytes = [chr.charCodeAt() for each (chr in pp)];
do_check_true(Math.min.apply(null, bytes) >= 97);
do_check_true(Math.max.apply(null, bytes) <= 122);
_("Hyphenated passphrase has 3 hyphens.");
let hyphenated = Utils.hyphenatePassphrase(pp);
do_check_eq(hyphenated.length, 23);
do_check_eq(hyphenated[5], '-');
do_check_eq(hyphenated[11], '-');
do_check_eq(hyphenated[17], '-');
do_check_eq(hyphenated.slice(0, 5) + hyphenated.slice(6, 11)
+ hyphenated.slice(12, 17) + hyphenated.slice(18, 23), pp);
_("Normalize passphrase recognizes hyphens.");
do_check_eq(Utils.normalizePassphrase(hyphenated), pp);
do_check_eq(pp, pp);
_("Passphrase strength calculated according to the NIST algorithm.");
do_check_eq(Utils.passphraseStrength(""), 0);
do_check_eq(Utils.passphraseStrength("a"), 4);
do_check_eq(Utils.passphraseStrength("ab"), 6);
do_check_eq(Utils.passphraseStrength("abc"), 8);
do_check_eq(Utils.passphraseStrength("abcdefgh"), 18);
do_check_eq(Utils.passphraseStrength("abcdefghi"), 19.5);
do_check_eq(Utils.passphraseStrength("abcdefghij"), 21);
do_check_eq(Utils.passphraseStrength("abcdefghijklmnopqrst"), 36);
do_check_eq(Utils.passphraseStrength("abcdefghijklmnopqrstu"), 37);
do_check_eq(Utils.passphraseStrength("abcdefghijklmnopqrstuvwxyz"), 42);
do_check_eq(Utils.passphraseStrength("abcdefghijklmnopqrstuvwxyz!"), 49);
do_check_eq(Utils.passphraseStrength("1"), 10);
do_check_eq(Utils.passphraseStrength("12"), 12);
do_check_eq(Utils.passphraseStrength("a1"), 12);
}

Просмотреть файл

@ -63,6 +63,16 @@ function run_test() {
let r10 = Utils.queryAsync(c("SELECT value, fieldname FROM moz_formhistory"), "fieldname");
do_check_eq(r10.length, 3);
_("Generate an execution error");
let r11, except, query = c("UPDATE moz_formhistory SET value = NULL WHERE fieldname = 'more'");
try {
r11 = Utils.queryAsync(query);
} catch(e) {
except = e;
}
do_check_true(!!except);
do_check_eq(except.result, 19); // constraint violation error
_("Cleaning up");
Utils.queryAsync(c("DELETE FROM moz_formhistory"));

Просмотреть файл

@ -0,0 +1,53 @@
Cu.import("resource://services-sync/util.js");
// both the checkStatus and ensureStatus functions are tested
// here.
function run_test() {
_test_checkStatus();
_test_ensureStatus();
}
function _test_checkStatus() {
let msg = "msg";
_("test with default range");
do_check_true(Utils.checkStatus(200, msg));
do_check_true(Utils.checkStatus(299, msg));
do_check_false(Utils.checkStatus(199, msg));
do_check_false(Utils.checkStatus(300, msg));
_("test with a number");
do_check_true(Utils.checkStatus(100, msg, [100]));
do_check_false(Utils.checkStatus(200, msg, [100]));
_("test with two numbers");
do_check_true(Utils.checkStatus(100, msg, [100, 200]));
do_check_true(Utils.checkStatus(200, msg, [100, 200]));
do_check_false(Utils.checkStatus(50, msg, [100, 200]));
do_check_false(Utils.checkStatus(150, msg, [100, 200]));
do_check_false(Utils.checkStatus(250, msg, [100, 200]));
_("test with a range and a number");
do_check_true(Utils.checkStatus(50, msg, [[50, 100], 100]));
do_check_true(Utils.checkStatus(75, msg, [[50, 100], 100]));
do_check_true(Utils.checkStatus(100, msg, [[50, 100], 100]));
do_check_false(Utils.checkStatus(200, msg, [[50, 100], 100]));
_("test with a number and a range");
do_check_true(Utils.checkStatus(50, msg, [100, [50, 100]]));
do_check_true(Utils.checkStatus(75, msg, [100, [50, 100]]));
do_check_true(Utils.checkStatus(100, msg, [100, [50, 100]]));
do_check_false(Utils.checkStatus(200, msg, [100, [50, 100]]));
}
function _test_ensureStatus() {
_("test that ensureStatus throws exception when it should");
let except;
try {
Utils.ensureStatus(400, "msg", [200]);
} catch(e) {
except = e;
}
do_check_true(!!except);
}

Просмотреть файл

@ -0,0 +1,8 @@
Cu.import("resource://services-sync/util.js");
function run_test() {
let str = "Umlaute: \u00FC \u00E4\n"; // Umlaute: ü ä
let encoded = Utils.encodeUTF8(str);
let decoded = Utils.decodeUTF8(encoded);
do_check_eq(decoded, str);
}