summaryrefslogtreecommitdiffstats
path: root/services/sync/tests/unit
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-10-06 06:57:51 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-10-06 06:57:51 +0200
commit0c47c83e1b3b7d95681a43fbb0de0e17b2cd5b25 (patch)
treec321601f04cbfd02fb6e12878e745dc49a612c86 /services/sync/tests/unit
parent8860eddcee1417483cafd114f3a9ec127e0f1f74 (diff)
downloadUXP-0c47c83e1b3b7d95681a43fbb0de0e17b2cd5b25.tar
UXP-0c47c83e1b3b7d95681a43fbb0de0e17b2cd5b25.tar.gz
UXP-0c47c83e1b3b7d95681a43fbb0de0e17b2cd5b25.tar.lz
UXP-0c47c83e1b3b7d95681a43fbb0de0e17b2cd5b25.tar.xz
UXP-0c47c83e1b3b7d95681a43fbb0de0e17b2cd5b25.zip
Import Tycho weave client
Diffstat (limited to 'services/sync/tests/unit')
-rw-r--r--services/sync/tests/unit/fake_login_manager.js2
-rw-r--r--services/sync/tests/unit/head_appinfo.js65
-rw-r--r--services/sync/tests/unit/head_errorhandler_common.js112
-rw-r--r--services/sync/tests/unit/head_helpers.js242
-rw-r--r--services/sync/tests/unit/head_http_server.js112
-rw-r--r--services/sync/tests/unit/prefs_test_prefs_store.js25
-rw-r--r--services/sync/tests/unit/sync_ping_schema.json198
-rw-r--r--services/sync/tests/unit/systemaddon-search.xml27
-rw-r--r--services/sync/tests/unit/test_addon_utils.js53
-rw-r--r--services/sync/tests/unit/test_addons_engine.js17
-rw-r--r--services/sync/tests/unit/test_addons_reconciler.js2
-rw-r--r--services/sync/tests/unit/test_addons_store.js127
-rw-r--r--services/sync/tests/unit/test_addons_tracker.js9
-rw-r--r--services/sync/tests/unit/test_block_sync.js37
-rw-r--r--services/sync/tests/unit/test_bookmark_duping.js644
-rw-r--r--services/sync/tests/unit/test_bookmark_engine.js321
-rw-r--r--services/sync/tests/unit/test_bookmark_invalid.js63
-rw-r--r--services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js4
-rw-r--r--services/sync/tests/unit/test_bookmark_livemarks.js19
-rw-r--r--services/sync/tests/unit/test_bookmark_order.js519
-rw-r--r--services/sync/tests/unit/test_bookmark_places_query_rewriting.js55
-rw-r--r--services/sync/tests/unit/test_bookmark_smart_bookmarks.js12
-rw-r--r--services/sync/tests/unit/test_bookmark_store.js128
-rw-r--r--services/sync/tests/unit/test_bookmark_tracker.js1499
-rw-r--r--services/sync/tests/unit/test_bookmark_validator.js347
-rw-r--r--services/sync/tests/unit/test_browserid_identity.js260
-rw-r--r--services/sync/tests/unit/test_clients_engine.js1027
-rw-r--r--services/sync/tests/unit/test_collection_getBatched.js195
-rw-r--r--services/sync/tests/unit/test_collections_recovery.js13
-rw-r--r--services/sync/tests/unit/test_corrupt_keys.js16
-rw-r--r--services/sync/tests/unit/test_engine.js24
-rw-r--r--services/sync/tests/unit/test_errorhandler.js1893
-rw-r--r--services/sync/tests/unit/test_errorhandler_1.js913
-rw-r--r--services/sync/tests/unit/test_errorhandler_2.js1012
-rw-r--r--services/sync/tests/unit/test_errorhandler_eol.js8
-rw-r--r--services/sync/tests/unit/test_errorhandler_filelog.js83
-rw-r--r--services/sync/tests/unit/test_errorhandler_sync_checkServerError.js21
-rw-r--r--services/sync/tests/unit/test_extension_storage_crypto.js93
-rw-r--r--services/sync/tests/unit/test_extension_storage_engine.js62
-rw-r--r--services/sync/tests/unit/test_extension_storage_tracker.js38
-rw-r--r--services/sync/tests/unit/test_forms_tracker.js14
-rw-r--r--services/sync/tests/unit/test_fxa_migration.js279
-rw-r--r--services/sync/tests/unit/test_fxa_migration_sentinel.js150
-rw-r--r--services/sync/tests/unit/test_fxa_node_reassignment.js689
-rw-r--r--services/sync/tests/unit/test_fxa_service_cluster.js136
-rw-r--r--services/sync/tests/unit/test_fxa_startOver.js126
-rw-r--r--services/sync/tests/unit/test_healthreport.js194
-rw-r--r--services/sync/tests/unit/test_healthreport_migration.js155
-rw-r--r--services/sync/tests/unit/test_history_store.js25
-rw-r--r--services/sync/tests/unit/test_history_tracker.js6
-rw-r--r--services/sync/tests/unit/test_hmac_error.js11
-rw-r--r--services/sync/tests/unit/test_identity_manager.js2
-rw-r--r--services/sync/tests/unit/test_interval_triggers.js21
-rw-r--r--services/sync/tests/unit/test_jpakeclient.js12
-rw-r--r--services/sync/tests/unit/test_keys.js2
-rw-r--r--services/sync/tests/unit/test_load_modules.js2
-rw-r--r--services/sync/tests/unit/test_node_reassignment.js23
-rw-r--r--services/sync/tests/unit/test_notifications.js32
-rw-r--r--services/sync/tests/unit/test_password_store.js148
-rw-r--r--services/sync/tests/unit/test_password_tracker.js6
-rw-r--r--services/sync/tests/unit/test_password_validator.js158
-rw-r--r--services/sync/tests/unit/test_postqueue.js455
-rw-r--r--services/sync/tests/unit/test_prefs_store.js85
-rw-r--r--services/sync/tests/unit/test_records_crypto.js28
-rw-r--r--services/sync/tests/unit/test_resource.js13
-rw-r--r--services/sync/tests/unit/test_resource_async.js14
-rw-r--r--services/sync/tests/unit/test_resource_header.js6
-rw-r--r--services/sync/tests/unit/test_resource_ua.js18
-rw-r--r--services/sync/tests/unit/test_score_triggers.js8
-rw-r--r--services/sync/tests/unit/test_service_attributes.js13
-rw-r--r--services/sync/tests/unit/test_service_detect_upgrade.js4
-rw-r--r--services/sync/tests/unit/test_service_getStorageInfo.js6
-rw-r--r--services/sync/tests/unit/test_service_login.js2
-rw-r--r--services/sync/tests/unit/test_service_passwordUTF8.js4
-rw-r--r--services/sync/tests/unit/test_service_startOver.js2
-rw-r--r--services/sync/tests/unit/test_service_startup.js11
-rw-r--r--services/sync/tests/unit/test_service_sync_locked.js13
-rw-r--r--services/sync/tests/unit/test_service_sync_remoteSetup.js77
-rw-r--r--services/sync/tests/unit/test_service_sync_specified.js160
-rw-r--r--services/sync/tests/unit/test_service_sync_updateEnabledEngines.js9
-rw-r--r--services/sync/tests/unit/test_service_wipeServer.js14
-rw-r--r--services/sync/tests/unit/test_status.js6
-rw-r--r--services/sync/tests/unit/test_syncedtabs.js221
-rw-r--r--services/sync/tests/unit/test_syncengine.js10
-rw-r--r--services/sync/tests/unit/test_syncengine_sync.js100
-rw-r--r--services/sync/tests/unit/test_syncscheduler.js113
-rw-r--r--services/sync/tests/unit/test_syncstoragerequest.js5
-rw-r--r--services/sync/tests/unit/test_tab_engine.js12
-rw-r--r--services/sync/tests/unit/test_tab_store.js50
-rw-r--r--services/sync/tests/unit/test_tab_tracker.js43
-rw-r--r--services/sync/tests/unit/test_telemetry.js564
-rw-r--r--services/sync/tests/unit/test_utils_catch.js54
-rw-r--r--services/sync/tests/unit/test_utils_deferGetSet.js8
-rw-r--r--services/sync/tests/unit/test_utils_deriveKey.js2
-rw-r--r--services/sync/tests/unit/test_utils_lock.js28
-rw-r--r--services/sync/tests/unit/test_utils_notify.js24
-rw-r--r--services/sync/tests/unit/test_warn_on_truncated_response.js4
-rw-r--r--services/sync/tests/unit/xpcshell.ini42
98 files changed, 4148 insertions, 10568 deletions
diff --git a/services/sync/tests/unit/fake_login_manager.js b/services/sync/tests/unit/fake_login_manager.js
index 6f3148c45..32adcbcb5 100644
--- a/services/sync/tests/unit/fake_login_manager.js
+++ b/services/sync/tests/unit/fake_login_manager.js
@@ -4,7 +4,7 @@ Cu.import("resource://services-sync/util.js");
// Fake Sample Data
// ----------------------------------------
-var fakeSampleLogins = [
+let fakeSampleLogins = [
// Fake nsILoginInfo object.
{hostname: "www.boogle.com",
formSubmitURL: "http://www.boogle.com/search",
diff --git a/services/sync/tests/unit/head_appinfo.js b/services/sync/tests/unit/head_appinfo.js
index d2a680df5..eea47905f 100644
--- a/services/sync/tests/unit/head_appinfo.js
+++ b/services/sync/tests/unit/head_appinfo.js
@@ -1,54 +1,65 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
-var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
-var gSyncProfile;
+let gSyncProfile;
gSyncProfile = do_get_profile();
// Init FormHistoryStartup and pretend we opened a profile.
-var fhs = Cc["@mozilla.org/satchel/form-history-startup;1"]
+let fhs = Cc["@mozilla.org/satchel/form-history-startup;1"]
.getService(Ci.nsIObserver);
fhs.observe(null, "profile-after-change", null);
-// An app is going to have some prefs set which xpcshell tests don't.
-Services.prefs.setCharPref("identity.sync.tokenserver.uri", "http://token-server");
-// Set the validation prefs to attempt validation every time to avoid non-determinism.
-Services.prefs.setIntPref("services.sync.validation.interval", 0);
-Services.prefs.setIntPref("services.sync.validation.percentageChance", 100);
-Services.prefs.setIntPref("services.sync.validation.maxRecords", -1);
-Services.prefs.setBoolPref("services.sync.validation.enabled", true);
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
// Make sure to provide the right OS so crypto loads the right binaries
-function getOS() {
- switch (mozinfo.os) {
- case "win":
- return "WINNT";
- case "mac":
- return "Darwin";
- default:
- return "Linux";
- }
-}
+let OS = "XPCShell";
+if ("@mozilla.org/windows-registry-key;1" in Cc)
+ OS = "WINNT";
+else if ("nsILocalFileMac" in Ci)
+ OS = "Darwin";
+else
+ OS = "Linux";
-Cu.import("resource://testing-common/AppInfo.jsm", this);
-updateAppInfo({
+let XULAppInfo = {
+ vendor: "Mozilla",
name: "XPCShell",
ID: "xpcshell@tests.mozilla.org",
version: "1",
+ appBuildID: "20100621",
platformVersion: "",
- OS: getOS(),
-});
+ platformBuildID: "20100621",
+ inSafeMode: false,
+ logConsoleErrors: true,
+ OS: OS,
+ XPCOMABI: "noarch-spidermonkey",
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, Ci.nsIXULRuntime]),
+ invalidateCachesOnRestart: function invalidateCachesOnRestart() { }
+};
+
+let XULAppInfoFactory = {
+ createInstance: function (outer, iid) {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return XULAppInfo.QueryInterface(iid);
+ }
+};
+
+let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
+ "XULAppInfo", "@mozilla.org/xre/app-info;1",
+ XULAppInfoFactory);
+
// Register resource aliases. Normally done in SyncComponents.manifest.
function addResourceAlias() {
+ Cu.import("resource://gre/modules/Services.jsm");
const resProt = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
- for (let s of ["common", "sync", "crypto"]) {
+ for each (let s in ["common", "sync", "crypto"]) {
let uri = Services.io.newURI("resource://gre/modules/services-" + s + "/", null,
null);
resProt.setSubstitution("services-" + s, uri);
diff --git a/services/sync/tests/unit/head_errorhandler_common.js b/services/sync/tests/unit/head_errorhandler_common.js
deleted file mode 100644
index f4af60d9d..000000000
--- a/services/sync/tests/unit/head_errorhandler_common.js
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/engines.js");
-
-// Common code for test_errorhandler_{1,2}.js -- pulled out to make it less
-// monolithic and take less time to execute.
-const EHTestsCommon = {
-
- service_unavailable(request, response) {
- let body = "Service Unavailable";
- response.setStatusLine(request.httpVersion, 503, "Service Unavailable");
- response.setHeader("Retry-After", "42");
- response.bodyOutputStream.write(body, body.length);
- },
-
- sync_httpd_setup() {
- let global = new ServerWBO("global", {
- syncID: Service.syncID,
- storageVersion: STORAGE_VERSION,
- engines: {clients: {version: Service.clientsEngine.version,
- syncID: Service.clientsEngine.syncID},
- catapult: {version: Service.engineManager.get("catapult").version,
- syncID: Service.engineManager.get("catapult").syncID}}
- });
- let clientsColl = new ServerCollection({}, true);
-
- // Tracking info/collections.
- let collectionsHelper = track_collections_helper();
- let upd = collectionsHelper.with_updated_collection;
-
- let handler_401 = httpd_handler(401, "Unauthorized");
- return httpd_setup({
- // Normal server behaviour.
- "/1.1/johndoe/storage/meta/global": upd("meta", global.handler()),
- "/1.1/johndoe/info/collections": collectionsHelper.handler,
- "/1.1/johndoe/storage/crypto/keys":
- upd("crypto", (new ServerWBO("keys")).handler()),
- "/1.1/johndoe/storage/clients": upd("clients", clientsColl.handler()),
-
- // Credentials are wrong or node reallocated.
- "/1.1/janedoe/storage/meta/global": handler_401,
- "/1.1/janedoe/info/collections": handler_401,
-
- // Maintenance or overloaded (503 + Retry-After) at info/collections.
- "/maintenance/1.1/broken.info/info/collections": EHTestsCommon.service_unavailable,
-
- // Maintenance or overloaded (503 + Retry-After) at meta/global.
- "/maintenance/1.1/broken.meta/storage/meta/global": EHTestsCommon.service_unavailable,
- "/maintenance/1.1/broken.meta/info/collections": collectionsHelper.handler,
-
- // Maintenance or overloaded (503 + Retry-After) at crypto/keys.
- "/maintenance/1.1/broken.keys/storage/meta/global": upd("meta", global.handler()),
- "/maintenance/1.1/broken.keys/info/collections": collectionsHelper.handler,
- "/maintenance/1.1/broken.keys/storage/crypto/keys": EHTestsCommon.service_unavailable,
-
- // Maintenance or overloaded (503 + Retry-After) at wiping collection.
- "/maintenance/1.1/broken.wipe/info/collections": collectionsHelper.handler,
- "/maintenance/1.1/broken.wipe/storage/meta/global": upd("meta", global.handler()),
- "/maintenance/1.1/broken.wipe/storage/crypto/keys":
- upd("crypto", (new ServerWBO("keys")).handler()),
- "/maintenance/1.1/broken.wipe/storage": EHTestsCommon.service_unavailable,
- "/maintenance/1.1/broken.wipe/storage/clients": upd("clients", clientsColl.handler()),
- "/maintenance/1.1/broken.wipe/storage/catapult": EHTestsCommon.service_unavailable
- });
- },
-
- CatapultEngine: (function() {
- function CatapultEngine() {
- SyncEngine.call(this, "Catapult", Service);
- }
- CatapultEngine.prototype = {
- __proto__: SyncEngine.prototype,
- exception: null, // tests fill this in
- _sync: function _sync() {
- if (this.exception) {
- throw this.exception;
- }
- }
- };
-
- return CatapultEngine;
- }()),
-
-
- generateCredentialsChangedFailure() {
- // Make sync fail due to changed credentials. We simply re-encrypt
- // the keys with a different Sync Key, without changing the local one.
- let newSyncKeyBundle = new SyncKeyBundle("johndoe", "23456234562345623456234562");
- let keys = Service.collectionKeys.asWBO();
- keys.encrypt(newSyncKeyBundle);
- keys.upload(Service.resource(Service.cryptoKeysURL));
- },
-
- setUp(server) {
- return configureIdentity({ username: "johndoe" }).then(
- () => {
- Service.serverURL = server.baseURI + "/";
- Service.clusterURL = server.baseURI + "/";
- }
- ).then(
- () => EHTestsCommon.generateAndUploadKeys()
- );
- },
-
- generateAndUploadKeys() {
- generateNewKeys(Service.collectionKeys);
- let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
- serverKeys.encrypt(Service.identity.syncKeyBundle);
- return serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success;
- }
-};
diff --git a/services/sync/tests/unit/head_helpers.js b/services/sync/tests/unit/head_helpers.js
index 3c59e1de5..04534dc8e 100644
--- a/services/sync/tests/unit/head_helpers.js
+++ b/services/sync/tests/unit/head_helpers.js
@@ -4,39 +4,8 @@
Cu.import("resource://services-common/async.js");
Cu.import("resource://testing-common/services/common/utils.js");
Cu.import("resource://testing-common/PlacesTestUtils.jsm");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-XPCOMUtils.defineLazyGetter(this, 'SyncPingSchema', function() {
- let ns = {};
- Cu.import("resource://gre/modules/FileUtils.jsm", ns);
- let stream = Cc["@mozilla.org/network/file-input-stream;1"]
- .createInstance(Ci.nsIFileInputStream);
- let jsonReader = Cc["@mozilla.org/dom/json;1"]
- .createInstance(Components.interfaces.nsIJSON);
- let schema;
- try {
- let schemaFile = do_get_file("sync_ping_schema.json");
- stream.init(schemaFile, ns.FileUtils.MODE_RDONLY, ns.FileUtils.PERMS_FILE, 0);
- schema = jsonReader.decodeFromStream(stream, stream.available());
- } finally {
- stream.close();
- }
-
- // Allow tests to make whatever engines they want, this shouldn't cause
- // validation failure.
- schema.definitions.engine.properties.name = { type: "string" };
- return schema;
-});
-
-XPCOMUtils.defineLazyGetter(this, 'SyncPingValidator', function() {
- let ns = {};
- Cu.import("resource://testing-common/ajv-4.1.1.js", ns);
- let ajv = new ns.Ajv({ async: "co*" });
- return ajv.compile(SyncPingSchema);
-});
-
-var provider = {
+let provider = {
getFile: function(prop, persistent) {
persistent.value = true;
switch (prop) {
@@ -51,7 +20,7 @@ var provider = {
Services.dirsvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
// This is needed for loadAddonTestFunctions().
-var gGlobalScope = this;
+let gGlobalScope = this;
function ExtensionsTestPath(path) {
if (path[0] != "/") {
@@ -76,24 +45,6 @@ function loadAddonTestFunctions() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
}
-function webExtensionsTestPath(path) {
- if (path[0] != "/") {
- throw Error("Path must begin with '/': " + path);
- }
-
- return "../../../../toolkit/components/extensions/test/xpcshell" + path;
-}
-
-/**
- * Loads the WebExtension test functions by importing its test file.
- */
-function loadWebExtensionTestFunctions() {
- const path = webExtensionsTestPath("/head_sync.js");
- let file = do_get_file(path);
- let uri = Services.io.newFileURI(file);
- Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
-}
-
function getAddonInstall(name) {
let f = do_get_file(ExtensionsTestPath("/addons/" + name + ".xpi"));
let cb = Async.makeSyncCallback();
@@ -255,192 +206,3 @@ function do_check_array_eq(a1, a2) {
do_check_eq(a1[i], a2[i]);
}
}
-
-// Helper function to get the sync telemetry and add the typically used test
-// engine names to its list of allowed engines.
-function get_sync_test_telemetry() {
- let ns = {};
- Cu.import("resource://services-sync/telemetry.js", ns);
- let testEngines = ["rotary", "steam", "sterling", "catapult"];
- for (let engineName of testEngines) {
- ns.SyncTelemetry.allowedEngines.add(engineName);
- }
- ns.SyncTelemetry.submissionInterval = -1;
- return ns.SyncTelemetry;
-}
-
-function assert_valid_ping(record) {
- // This is called as the test harness tears down due to shutdown. This
- // will typically have no recorded syncs, and the validator complains about
- // it. So ignore such records (but only ignore when *both* shutdown and
- // no Syncs - either of them not being true might be an actual problem)
- if (record && (record.why != "shutdown" || record.syncs.length != 0)) {
- if (!SyncPingValidator(record)) {
- deepEqual([], SyncPingValidator.errors, "Sync telemetry ping validation failed");
- }
- equal(record.version, 1);
- record.syncs.forEach(p => {
- lessOrEqual(p.when, Date.now());
- if (p.devices) {
- ok(!p.devices.some(device => device.id == p.deviceID));
- equal(new Set(p.devices.map(device => device.id)).size,
- p.devices.length, "Duplicate device ids in ping devices list");
- }
- });
- }
-}
-
-// Asserts that `ping` is a ping that doesn't contain any failure information
-function assert_success_ping(ping) {
- ok(!!ping);
- assert_valid_ping(ping);
- ping.syncs.forEach(record => {
- ok(!record.failureReason);
- equal(undefined, record.status);
- greater(record.engines.length, 0);
- for (let e of record.engines) {
- ok(!e.failureReason);
- equal(undefined, e.status);
- if (e.validation) {
- equal(undefined, e.validation.problems);
- equal(undefined, e.validation.failureReason);
- }
- if (e.outgoing) {
- for (let o of e.outgoing) {
- equal(undefined, o.failed);
- notEqual(undefined, o.sent);
- }
- }
- if (e.incoming) {
- equal(undefined, e.incoming.failed);
- equal(undefined, e.incoming.newFailed);
- notEqual(undefined, e.incoming.applied || e.incoming.reconciled);
- }
- }
- });
-}
-
-// Hooks into telemetry to validate all pings after calling.
-function validate_all_future_pings() {
- let telem = get_sync_test_telemetry();
- telem.submit = assert_valid_ping;
-}
-
-function wait_for_ping(callback, allowErrorPings, getFullPing = false) {
- return new Promise(resolve => {
- let telem = get_sync_test_telemetry();
- let oldSubmit = telem.submit;
- telem.submit = function(record) {
- telem.submit = oldSubmit;
- if (allowErrorPings) {
- assert_valid_ping(record);
- } else {
- assert_success_ping(record);
- }
- if (getFullPing) {
- resolve(record);
- } else {
- equal(record.syncs.length, 1);
- resolve(record.syncs[0]);
- }
- };
- callback();
- });
-}
-
-// Short helper for wait_for_ping
-function sync_and_validate_telem(allowErrorPings, getFullPing = false) {
- return wait_for_ping(() => Service.sync(), allowErrorPings, getFullPing);
-}
-
-// Used for the (many) cases where we do a 'partial' sync, where only a single
-// engine is actually synced, but we still want to ensure we're generating a
-// valid ping. Returns a promise that resolves to the ping, or rejects with the
-// thrown error after calling an optional callback.
-function sync_engine_and_validate_telem(engine, allowErrorPings, onError) {
- return new Promise((resolve, reject) => {
- let telem = get_sync_test_telemetry();
- let caughtError = null;
- // Clear out status, so failures from previous syncs won't show up in the
- // telemetry ping.
- let ns = {};
- Cu.import("resource://services-sync/status.js", ns);
- ns.Status._engines = {};
- ns.Status.partial = false;
- // Ideally we'd clear these out like we do with engines, (probably via
- // Status.resetSync()), but this causes *numerous* tests to fail, so we just
- // assume that if no failureReason or engine failures are set, and the
- // status properties are the same as they were initially, that it's just
- // a leftover.
- // This is only an issue since we're triggering the sync of just one engine,
- // without doing any other parts of the sync.
- let initialServiceStatus = ns.Status._service;
- let initialSyncStatus = ns.Status._sync;
-
- let oldSubmit = telem.submit;
- telem.submit = function(ping) {
- telem.submit = oldSubmit;
- ping.syncs.forEach(record => {
- if (record && record.status) {
- // did we see anything to lead us to believe that something bad actually happened
- let realProblem = record.failureReason || record.engines.some(e => {
- if (e.failureReason || e.status) {
- return true;
- }
- if (e.outgoing && e.outgoing.some(o => o.failed > 0)) {
- return true;
- }
- return e.incoming && e.incoming.failed;
- });
- if (!realProblem) {
- // no, so if the status is the same as it was initially, just assume
- // that its leftover and that we can ignore it.
- if (record.status.sync && record.status.sync == initialSyncStatus) {
- delete record.status.sync;
- }
- if (record.status.service && record.status.service == initialServiceStatus) {
- delete record.status.service;
- }
- if (!record.status.sync && !record.status.service) {
- delete record.status;
- }
- }
- }
- });
- if (allowErrorPings) {
- assert_valid_ping(ping);
- } else {
- assert_success_ping(ping);
- }
- equal(ping.syncs.length, 1);
- if (caughtError) {
- if (onError) {
- onError(ping.syncs[0]);
- }
- reject(caughtError);
- } else {
- resolve(ping.syncs[0]);
- }
- }
- Svc.Obs.notify("weave:service:sync:start");
- try {
- engine.sync();
- } catch (e) {
- caughtError = e;
- }
- if (caughtError) {
- Svc.Obs.notify("weave:service:sync:error", caughtError);
- } else {
- Svc.Obs.notify("weave:service:sync:finish");
- }
- });
-}
-
-// Avoid an issue where `client.name2` containing unicode characters causes
-// a number of tests to fail, due to them assuming that we do not need to utf-8
-// encode or decode data sent through the mocked server (see bug 1268912).
-Utils.getDefaultDeviceName = function() {
- return "Test device name";
-};
-
-
diff --git a/services/sync/tests/unit/head_http_server.js b/services/sync/tests/unit/head_http_server.js
index 26f62310c..c917c4988 100644
--- a/services/sync/tests/unit/head_http_server.js
+++ b/services/sync/tests/unit/head_http_server.js
@@ -1,4 +1,4 @@
-var Cm = Components.manager;
+const Cm = Components.manager;
// Shared logging for all HTTP server functions.
Cu.import("resource://gre/modules/Log.jsm");
@@ -178,13 +178,9 @@ ServerCollection.prototype = {
* @return an array of IDs.
*/
keys: function keys(filter) {
- let ids = [];
- for (let [id, wbo] of Object.entries(this._wbos)) {
- if (wbo.payload && (!filter || filter(id, wbo))) {
- ids.push(id);
- }
- }
- return ids;
+ return [id for ([id, wbo] in Iterator(this._wbos))
+ if (wbo.payload &&
+ (!filter || filter(id, wbo)))];
},
/**
@@ -198,13 +194,8 @@ ServerCollection.prototype = {
* @return an array of ServerWBOs.
*/
wbos: function wbos(filter) {
- let os = [];
- for (let [id, wbo] of Object.entries(this._wbos)) {
- if (wbo.payload) {
- os.push(wbo);
- }
- }
-
+ let os = [wbo for ([id, wbo] in Iterator(this._wbos))
+ if (wbo.payload)];
if (filter) {
return os.filter(filter);
}
@@ -276,7 +267,7 @@ ServerCollection.prototype = {
count: function(options) {
options = options || {};
let c = 0;
- for (let [id, wbo] of Object.entries(this._wbos)) {
+ for (let [id, wbo] in Iterator(this._wbos)) {
if (wbo.modified && this._inResultSet(wbo, options)) {
c++;
}
@@ -287,23 +278,12 @@ ServerCollection.prototype = {
get: function(options) {
let result;
if (options.full) {
- let data = [];
- for (let [id, wbo] of Object.entries(this._wbos)) {
- // Drop deleted.
- if (wbo.modified && this._inResultSet(wbo, options)) {
- data.push(wbo.get());
- }
- }
- let start = options.offset || 0;
+ let data = [wbo.get() for ([id, wbo] in Iterator(this._wbos))
+ // Drop deleted.
+ if (wbo.modified &&
+ this._inResultSet(wbo, options))];
if (options.limit) {
- let numItemsPastOffset = data.length - start;
- data = data.slice(start, start + options.limit);
- // use options as a backchannel to set x-weave-next-offset
- if (numItemsPastOffset > options.limit) {
- options.nextOffset = start + options.limit;
- }
- } else if (start) {
- data = data.slice(start);
+ data = data.slice(0, options.limit);
}
// Our implementation of application/newlines.
result = data.join("\n") + "\n";
@@ -311,18 +291,10 @@ ServerCollection.prototype = {
// Use options as a backchannel to report count.
options.recordCount = data.length;
} else {
- let data = [];
- for (let [id, wbo] of Object.entries(this._wbos)) {
- if (this._inResultSet(wbo, options)) {
- data.push(id);
- }
- }
- let start = options.offset || 0;
+ let data = [id for ([id, wbo] in Iterator(this._wbos))
+ if (this._inResultSet(wbo, options))];
if (options.limit) {
- data = data.slice(start, start + options.limit);
- options.nextOffset = start + options.limit;
- } else if (start) {
- data = data.slice(start);
+ data = data.slice(0, options.limit);
}
result = JSON.stringify(data);
options.recordCount = data.length;
@@ -337,8 +309,7 @@ ServerCollection.prototype = {
// This will count records where we have an existing ServerWBO
// registered with us as successful and all other records as failed.
- for (let key in input) {
- let record = input[key];
+ for each (let record in input) {
let wbo = this.wbo(record.id);
if (!wbo && this.acceptNew) {
this._log.debug("Creating WBO " + JSON.stringify(record.id) +
@@ -361,7 +332,7 @@ ServerCollection.prototype = {
delete: function(options) {
let deleted = [];
- for (let [id, wbo] of Object.entries(this._wbos)) {
+ for (let [id, wbo] in Iterator(this._wbos)) {
if (this._inResultSet(wbo, options)) {
this._log.debug("Deleting " + JSON.stringify(wbo));
deleted.push(wbo.id);
@@ -383,7 +354,7 @@ ServerCollection.prototype = {
// Parse queryString
let options = {};
- for (let chunk of request.queryString.split("&")) {
+ for each (let chunk in request.queryString.split("&")) {
if (!chunk) {
continue;
}
@@ -403,36 +374,29 @@ ServerCollection.prototype = {
if (options.limit) {
options.limit = parseInt(options.limit, 10);
}
- if (options.offset) {
- options.offset = parseInt(options.offset, 10);
- }
switch(request.method) {
case "GET":
- body = self.get(options, request);
- // see http://moz-services-docs.readthedocs.io/en/latest/storage/apis-1.5.html
- // for description of these headers.
- let { recordCount: records, nextOffset } = options;
-
- self._log.info("Records: " + records + ", nextOffset: " + nextOffset);
+ body = self.get(options);
+ // "If supported by the db, this header will return the number of
+ // records total in the request body of any multiple-record GET
+ // request."
+ let records = options.recordCount;
+ self._log.info("Records: " + records);
if (records != null) {
response.setHeader("X-Weave-Records", "" + records);
}
- if (nextOffset) {
- response.setHeader("X-Weave-Next-Offset", "" + nextOffset);
- }
- response.setHeader("X-Last-Modified", "" + this.timestamp);
break;
case "POST":
- let res = self.post(readBytesFromInputStream(request.bodyInputStream), request);
+ let res = self.post(readBytesFromInputStream(request.bodyInputStream));
body = JSON.stringify(res);
response.newModified = res.modified;
break;
case "DELETE":
self._log.debug("Invoking ServerCollection.DELETE.");
- let deleted = self.delete(options, request);
+ let deleted = self.delete(options);
let ts = new_timestamp();
body = JSON.stringify(ts);
response.newModified = ts;
@@ -541,7 +505,7 @@ function track_collections_helper() {
* find out what it needs without monkeypatching. Use this object as your
* prototype, and override as appropriate.
*/
-var SyncServerCallback = {
+let SyncServerCallback = {
onCollectionDeleted: function onCollectionDeleted(user, collection) {},
onItemDeleted: function onItemDeleted(user, collection, wboID) {},
@@ -581,13 +545,13 @@ SyncServer.prototype = {
* Start the SyncServer's underlying HTTP server.
*
* @param port
- * The numeric port on which to start. -1 implies the default, a
- * randomly chosen port.
+ * The numeric port on which to start. A falsy value implies the
+ * default, a randomly chosen port.
* @param cb
* A callback function (of no arguments) which is invoked after
* startup.
*/
- start: function start(port = -1, cb) {
+ start: function start(port, cb) {
if (this.started) {
this._log.warn("Warning: server already started on " + this.port);
return;
@@ -605,7 +569,7 @@ SyncServer.prototype = {
} catch (ex) {
_("==========================================");
_("Got exception starting Sync HTTP server.");
- _("Error: " + Log.exceptionStr(ex));
+ _("Error: " + Utils.exceptionStr(ex));
_("Is there a process already listening on port " + port + "?");
_("==========================================");
do_throw(ex);
@@ -703,10 +667,10 @@ SyncServer.prototype = {
throw new Error("Unknown user.");
}
let userCollections = this.users[username].collections;
- for (let [id, contents] of Object.entries(collections)) {
+ for (let [id, contents] in Iterator(collections)) {
let coll = userCollections[id] ||
this._insertCollection(userCollections, id);
- for (let [wboID, payload] of Object.entries(contents)) {
+ for (let [wboID, payload] in Iterator(contents)) {
coll.insert(wboID, payload);
}
}
@@ -740,8 +704,7 @@ SyncServer.prototype = {
throw new Error("Unknown user.");
}
let userCollections = this.users[username].collections;
- for (let name in userCollections) {
- let coll = userCollections[name];
+ for each (let [name, coll] in Iterator(userCollections)) {
this._log.trace("Bulk deleting " + name + " for " + username + "...");
coll.delete({});
}
@@ -805,10 +768,7 @@ SyncServer.prototype = {
*/
respond: function respond(req, resp, code, status, body, headers) {
resp.setStatusLine(req.httpVersion, code, status);
- if (!headers)
- headers = this.defaultHeaders;
- for (let header in headers) {
- let value = headers[header];
+ for each (let [header, value] in Iterator(headers || this.defaultHeaders)) {
resp.setHeader(header, value);
}
resp.setHeader("X-Weave-Timestamp", "" + this.timestamp(), false);
@@ -1035,7 +995,7 @@ SyncServer.prototype = {
*/
function serverForUsers(users, contents, callback) {
let server = new SyncServer(callback);
- for (let [user, pass] of Object.entries(users)) {
+ for (let [user, pass] in Iterator(users)) {
server.registerUser(user, pass);
server.createContents(user, contents);
}
diff --git a/services/sync/tests/unit/prefs_test_prefs_store.js b/services/sync/tests/unit/prefs_test_prefs_store.js
deleted file mode 100644
index 109757a35..000000000
--- a/services/sync/tests/unit/prefs_test_prefs_store.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// This is a "preferences" file used by test_prefs_store.js
-
-// The prefs that control what should be synced.
-// Most of these are "default" prefs, so the value itself will not sync.
-pref("services.sync.prefs.sync.testing.int", true);
-pref("services.sync.prefs.sync.testing.string", true);
-pref("services.sync.prefs.sync.testing.bool", true);
-pref("services.sync.prefs.sync.testing.dont.change", true);
-// this one is a user pref, so it *will* sync.
-user_pref("services.sync.prefs.sync.testing.turned.off", false);
-pref("services.sync.prefs.sync.testing.nonexistent", true);
-pref("services.sync.prefs.sync.testing.default", true);
-
-// The preference values - these are all user_prefs, otherwise their value
-// will not be synced.
-user_pref("testing.int", 123);
-user_pref("testing.string", "ohai");
-user_pref("testing.bool", true);
-user_pref("testing.dont.change", "Please don't change me.");
-user_pref("testing.turned.off", "I won't get synced.");
-user_pref("testing.not.turned.on", "I won't get synced either!");
-
-// A pref that exists but still has the default value - will be synced with
-// null as the value.
-pref("testing.default", "I'm the default value");
diff --git a/services/sync/tests/unit/sync_ping_schema.json b/services/sync/tests/unit/sync_ping_schema.json
deleted file mode 100644
index 56114fb93..000000000
--- a/services/sync/tests/unit/sync_ping_schema.json
+++ /dev/null
@@ -1,198 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "schema for Sync pings, documentation avaliable in toolkit/components/telemetry/docs/sync-ping.rst",
- "type": "object",
- "additionalProperties": false,
- "required": ["version", "syncs", "why"],
- "properties": {
- "version": { "type": "integer", "minimum": 0 },
- "discarded": { "type": "integer", "minimum": 1 },
- "why": { "enum": ["shutdown", "schedule"] },
- "syncs": {
- "type": "array",
- "minItems": 1,
- "items": { "$ref": "#/definitions/payload" }
- }
- },
- "definitions": {
- "payload": {
- "type": "object",
- "additionalProperties": false,
- "required": ["when", "uid", "took"],
- "properties": {
- "didLogin": { "type": "boolean" },
- "when": { "type": "integer" },
- "uid": {
- "type": "string",
- "pattern": "^[0-9a-f]{32}$"
- },
- "devices": {
- "type": "array",
- "items": { "$ref": "#/definitions/device" }
- },
- "deviceID": {
- "type": "string",
- "pattern": "^[0-9a-f]{64}$"
- },
- "status": {
- "type": "object",
- "anyOf": [
- { "required": ["sync"] },
- { "required": ["service"] }
- ],
- "additionalProperties": false,
- "properties": {
- "sync": { "type": "string" },
- "service": { "type": "string" }
- }
- },
- "why": { "enum": ["startup", "schedule", "score", "user", "tabs"] },
- "took": { "type": "integer", "minimum": -1 },
- "failureReason": { "$ref": "#/definitions/error" },
- "engines": {
- "type": "array",
- "minItems": 1,
- "items": { "$ref": "#/definitions/engine" }
- }
- }
- },
- "device": {
- "required": ["os", "id", "version"],
- "additionalProperties": false,
- "type": "object",
- "properties": {
- "id": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
- "os": { "type": "string" },
- "version": { "type": "string" }
- }
- },
- "engine": {
- "required": ["name"],
- "additionalProperties": false,
- "properties": {
- "failureReason": { "$ref": "#/definitions/error" },
- "name": { "enum": ["addons", "bookmarks", "clients", "forms", "history", "passwords", "prefs", "tabs"] },
- "took": { "type": "integer", "minimum": 1 },
- "status": { "type": "string" },
- "incoming": {
- "type": "object",
- "additionalProperties": false,
- "anyOf": [
- {"required": ["applied"]},
- {"required": ["failed"]},
- {"required": ["newFailed"]},
- {"required": ["reconciled"]}
- ],
- "properties": {
- "applied": { "type": "integer", "minimum": 1 },
- "failed": { "type": "integer", "minimum": 1 },
- "newFailed": { "type": "integer", "minimum": 1 },
- "reconciled": { "type": "integer", "minimum": 1 }
- }
- },
- "outgoing": {
- "type": "array",
- "minItems": 1,
- "items": { "$ref": "#/definitions/outgoingBatch" }
- },
- "validation": {
- "type": "object",
- "additionalProperties": false,
- "anyOf": [
- { "required": ["checked"] },
- { "required": ["failureReason"] }
- ],
- "properties": {
- "checked": { "type": "integer", "minimum": 0 },
- "failureReason": { "$ref": "#/definitions/error" },
- "took": { "type": "integer" },
- "version": { "type": "integer" },
- "problems": {
- "type": "array",
- "minItems": 1,
- "$ref": "#/definitions/validationProblem"
- }
- }
- }
- }
- },
- "outgoingBatch": {
- "type": "object",
- "additionalProperties": false,
- "anyOf": [
- {"required": ["sent"]},
- {"required": ["failed"]}
- ],
- "properties": {
- "sent": { "type": "integer", "minimum": 1 },
- "failed": { "type": "integer", "minimum": 1 }
- }
- },
- "error": {
- "oneOf": [
- { "$ref": "#/definitions/httpError" },
- { "$ref": "#/definitions/nsError" },
- { "$ref": "#/definitions/shutdownError" },
- { "$ref": "#/definitions/authError" },
- { "$ref": "#/definitions/otherError" },
- { "$ref": "#/definitions/unexpectedError" },
- { "$ref": "#/definitions/sqlError" }
- ]
- },
- "httpError": {
- "required": ["name", "code"],
- "properties": {
- "name": { "enum": ["httperror"] },
- "code": { "type": "integer" }
- }
- },
- "nsError": {
- "required": ["name", "code"],
- "properties": {
- "name": { "enum": ["nserror"] },
- "code": { "type": "integer" }
- }
- },
- "shutdownError": {
- "required": ["name"],
- "properties": {
- "name": { "enum": ["shutdownerror"] }
- }
- },
- "authError": {
- "required": ["name"],
- "properties": {
- "name": { "enum": ["autherror"] },
- "from": { "enum": ["tokenserver", "fxaccounts", "hawkclient"] }
- }
- },
- "otherError": {
- "required": ["name"],
- "properties": {
- "name": { "enum": ["othererror"] },
- "error": { "type": "string" }
- }
- },
- "unexpectedError": {
- "required": ["name"],
- "properties": {
- "name": { "enum": ["unexpectederror"] },
- "error": { "type": "string" }
- }
- },
- "sqlError": {
- "required": ["name"],
- "properties": {
- "name": { "enum": ["sqlerror"] },
- "code": { "type": "integer" }
- }
- },
- "validationProblem": {
- "required": ["name", "count"],
- "properties": {
- "name": { "type": "string" },
- "count": { "type": "integer" }
- }
- }
- }
-} \ No newline at end of file
diff --git a/services/sync/tests/unit/systemaddon-search.xml b/services/sync/tests/unit/systemaddon-search.xml
deleted file mode 100644
index d34e3937c..000000000
--- a/services/sync/tests/unit/systemaddon-search.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<searchresults total_results="1">
- <addon id="5618">
- <name>System Add-on Test</name>
- <type id="1">Extension</type>
- <guid>system1@tests.mozilla.org</guid>
- <slug>addon11</slug>
- <version>1.0</version>
-
- <compatible_applications><application>
- <name>Firefox</name>
- <application_id>1</application_id>
- <min_version>3.6</min_version>
- <max_version>*</max_version>
- <appID>xpcshell@tests.mozilla.org</appID>
- </application></compatible_applications>
- <all_compatible_os><os>ALL</os></all_compatible_os>
-
- <install os="ALL" size="999">http://127.0.0.1:8888/system.xpi</install>
- <created epoch="1252903662">
- 2009-09-14T04:47:42Z
- </created>
- <last_updated epoch="1315255329">
- 2011-09-05T20:42:09Z
- </last_updated>
- </addon>
-</searchresults>
diff --git a/services/sync/tests/unit/test_addon_utils.js b/services/sync/tests/unit/test_addon_utils.js
index bbbd81d0d..49824cd4c 100644
--- a/services/sync/tests/unit/test_addon_utils.js
+++ b/services/sync/tests/unit/test_addon_utils.js
@@ -3,7 +3,6 @@
"use strict";
-Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://services-sync/addonutils.js");
Cu.import("resource://services-sync/util.js");
@@ -11,7 +10,7 @@ Cu.import("resource://services-sync/util.js");
const HTTP_PORT = 8888;
const SERVER_ADDRESS = "http://127.0.0.1:8888";
-var prefs = new Preferences();
+let prefs = new Preferences();
prefs.set("extensions.getAddons.get.url",
SERVER_ADDRESS + "/search/guid:%IDS%");
@@ -36,7 +35,7 @@ function createAndStartHTTPServer(port=HTTP_PORT) {
return server;
} catch (ex) {
_("Got exception starting HTTP server on port " + port);
- _("Error: " + Log.exceptionStr(ex));
+ _("Error: " + Utils.exceptionStr(ex));
do_throw(ex);
}
}
@@ -61,9 +60,6 @@ add_test(function test_handle_empty_source_uri() {
do_check_true("installedIDs" in result);
do_check_eq(0, result.installedIDs.length);
- do_check_true("skipped" in result);
- do_check_true(result.skipped.includes(ID));
-
server.stop(run_next_test);
});
@@ -83,18 +79,44 @@ add_test(function test_ignore_untrusted_source_uris() {
let sourceURI = ioService.newURI(s, null, null);
let addon = {sourceURI: sourceURI, name: "bad", id: "bad"};
- let canInstall = AddonUtils.canInstallAddon(addon);
- do_check_false(canInstall, "Correctly rejected a bad URL");
+ try {
+ let cb = Async.makeSpinningCallback();
+ AddonUtils.getInstallFromSearchResult(addon, cb, true);
+ cb.wait();
+ } catch (ex) {
+ do_check_neq(null, ex);
+ do_check_eq(0, ex.message.indexOf("Insecure source URI"));
+ continue;
+ }
+
+ // We should never get here if an exception is thrown.
+ do_check_true(false);
}
+ let count = 0;
for (let s of good) {
let sourceURI = ioService.newURI(s, null, null);
let addon = {sourceURI: sourceURI, name: "good", id: "good"};
- let canInstall = AddonUtils.canInstallAddon(addon);
- do_check_true(canInstall, "Correctly accepted a good URL");
+ // Despite what you might think, we don't get an error in the callback.
+ // The install won't work because the underlying Addon instance wasn't
+ // proper. But, that just results in an AddonInstall that is missing
+ // certain values. We really just care that the callback is being invoked
+ // anyway.
+ let callback = function onInstall(error, install) {
+ do_check_null(error);
+ do_check_neq(null, install);
+ do_check_eq(sourceURI.spec, install.sourceURI.spec);
+
+ count += 1;
+
+ if (count >= good.length) {
+ run_next_test();
+ }
+ };
+
+ AddonUtils.getInstallFromSearchResult(addon, callback, true);
}
- run_next_test();
});
add_test(function test_source_uri_rewrite() {
@@ -103,6 +125,8 @@ add_test(function test_source_uri_rewrite() {
// This tests for conformance with bug 708134 so server-side metrics aren't
// skewed.
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
+
// We resort to monkeypatching because of the API design.
let oldFunction = AddonUtils.__proto__.installAddonFromSearchResult;
@@ -127,15 +151,12 @@ add_test(function test_source_uri_rewrite() {
let server = createAndStartHTTPServer();
let installCallback = Async.makeSpinningCallback();
- let installOptions = {
- id: "rewrite@tests.mozilla.org",
- requireSecureURI: false,
- }
- AddonUtils.installAddons([installOptions], installCallback);
+ AddonUtils.installAddons([{id: "rewrite@tests.mozilla.org"}], installCallback);
installCallback.wait();
do_check_true(installCalled);
AddonUtils.__proto__.installAddonFromSearchResult = oldFunction;
+ Svc.Prefs.reset("addons.ignoreRepositoryChecking");
server.stop(run_next_test);
});
diff --git a/services/sync/tests/unit/test_addons_engine.js b/services/sync/tests/unit/test_addons_engine.js
index 64e4e32e8..ca2e4bd96 100644
--- a/services/sync/tests/unit/test_addons_engine.js
+++ b/services/sync/tests/unit/test_addons_engine.js
@@ -13,20 +13,19 @@ Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
-var prefs = new Preferences();
+let prefs = new Preferences();
prefs.set("extensions.getAddons.get.url",
"http://localhost:8888/search/guid:%IDS%");
-prefs.set("extensions.install.requireSecureOrigin", false);
loadAddonTestFunctions();
startupManager();
-var engineManager = Service.engineManager;
+let engineManager = Service.engineManager;
engineManager.register(AddonsEngine);
-var engine = engineManager.get("addons");
-var reconciler = engine._reconciler;
-var tracker = engine._tracker;
+let engine = engineManager.get("addons");
+let reconciler = engine._reconciler;
+let tracker = engine._tracker;
function advance_test() {
reconciler._addons = {};
@@ -36,6 +35,8 @@ function advance_test() {
reconciler.saveState(null, cb);
cb.wait();
+ Svc.Prefs.reset("addons.ignoreRepositoryChecking");
+
run_next_test();
}
@@ -103,6 +104,7 @@ add_test(function test_get_changed_ids() {
tracker.clearChangedIDs();
_("Ensure reconciler changes are populated.");
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
let addon = installAddon("test_bootstrap1_1");
tracker.clearChangedIDs(); // Just in case.
changes = engine.getChangedIDs();
@@ -149,6 +151,9 @@ add_test(function test_disabled_install_semantics() {
// This is essentially a test for bug 712542, which snuck into the original
// add-on sync drop. It ensures that when an add-on is installed that the
// disabled state and incoming syncGUID is preserved, even on the next sync.
+
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
+
const USER = "foo";
const PASSWORD = "password";
const PASSPHRASE = "abcdeabcdeabcdeabcdeabcdea";
diff --git a/services/sync/tests/unit/test_addons_reconciler.js b/services/sync/tests/unit/test_addons_reconciler.js
index d93bdfc03..8cfa37d78 100644
--- a/services/sync/tests/unit/test_addons_reconciler.js
+++ b/services/sync/tests/unit/test_addons_reconciler.js
@@ -71,7 +71,7 @@ add_test(function test_install_detection() {
const KEYS = ["id", "guid", "enabled", "installed", "modified", "type",
"scope", "foreignInstall"];
- for (let key of KEYS) {
+ for each (let key in KEYS) {
do_check_true(key in record);
do_check_neq(null, record[key]);
}
diff --git a/services/sync/tests/unit/test_addons_store.js b/services/sync/tests/unit/test_addons_store.js
index b52cfab31..b21f6afe1 100644
--- a/services/sync/tests/unit/test_addons_store.js
+++ b/services/sync/tests/unit/test_addons_store.js
@@ -3,47 +3,25 @@
"use strict";
-Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://services-sync/addonutils.js");
Cu.import("resource://services-sync/engines/addons.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://gre/modules/FileUtils.jsm");
const HTTP_PORT = 8888;
-var prefs = new Preferences();
+let prefs = new Preferences();
prefs.set("extensions.getAddons.get.url", "http://localhost:8888/search/guid:%IDS%");
-prefs.set("extensions.install.requireSecureOrigin", false);
-
-const SYSTEM_ADDON_ID = "system1@tests.mozilla.org";
-let systemAddonFile;
-
-// The system add-on must be installed before AddonManager is started.
-function loadSystemAddon() {
- let addonFilename = SYSTEM_ADDON_ID + ".xpi";
- const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
- do_get_file(ExtensionsTestPath("/data/system_addons/system1_1.xpi")).copyTo(distroDir, addonFilename);
- systemAddonFile = FileUtils.File(distroDir.path);
- systemAddonFile.append(addonFilename);
- systemAddonFile.lastModifiedTime = Date.now();
- // As we're not running in application, we need to setup the features directory
- // used by system add-ons.
- registerDirectory("XREAppFeat", distroDir);
-}
-
loadAddonTestFunctions();
-loadSystemAddon();
startupManager();
Service.engineManager.register(AddonsEngine);
-var engine = Service.engineManager.get("addons");
-var tracker = engine._tracker;
-var store = engine._store;
-var reconciler = engine._reconciler;
+let engine = Service.engineManager.get("addons");
+let tracker = engine._tracker;
+let store = engine._store;
+let reconciler = engine._reconciler;
/**
* Create a AddonsRec for this application with the fields specified.
@@ -77,16 +55,12 @@ function createAndStartHTTPServer(port) {
server.registerFile("/search/guid:missing-xpi%40tests.mozilla.org",
do_get_file("missing-xpi-search.xml"));
- server.registerFile("/search/guid:system1%40tests.mozilla.org",
- do_get_file("systemaddon-search.xml"));
- server.registerFile("/system.xpi", systemAddonFile);
-
server.start(port);
return server;
} catch (ex) {
_("Got exception starting HTTP server on port " + port);
- _("Error: " + Log.exceptionStr(ex));
+ _("Error: " + Utils.exceptionStr(ex));
do_throw(ex);
}
}
@@ -94,7 +68,6 @@ function createAndStartHTTPServer(port) {
function run_test() {
initTestLogging("Trace");
Log.repository.getLogger("Sync.Engine.Addons").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.Tracker.Addons").level = Log.Level.Trace;
Log.repository.getLogger("Sync.AddonsRepository").level =
Log.Level.Trace;
@@ -219,6 +192,7 @@ add_test(function test_apply_uninstall() {
add_test(function test_addon_syncability() {
_("Ensure isAddonSyncable functions properly.");
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
Svc.Prefs.set("addons.trustedSourceHostnames",
"addons.mozilla.org,other.example.com");
@@ -228,8 +202,8 @@ add_test(function test_addon_syncability() {
do_check_true(store.isAddonSyncable(addon));
let dummy = {};
- const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall", "isSyncable"];
- for (let k of KEYS) {
+ const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"];
+ for each (let k in KEYS) {
dummy[k] = addon[k];
}
@@ -243,10 +217,6 @@ add_test(function test_addon_syncability() {
do_check_false(store.isAddonSyncable(dummy));
dummy.scope = addon.scope;
- dummy.isSyncable = false;
- do_check_false(store.isAddonSyncable(dummy));
- dummy.isSyncable = addon.isSyncable;
-
dummy.foreignInstall = true;
do_check_false(store.isAddonSyncable(dummy));
dummy.foreignInstall = false;
@@ -272,16 +242,16 @@ add_test(function test_addon_syncability() {
"https://untrusted.example.com/foo", // non-trusted hostname`
];
- for (let uri of trusted) {
+ for each (let uri in trusted) {
do_check_true(store.isSourceURITrusted(createURI(uri)));
}
- for (let uri of untrusted) {
+ for each (let uri in untrusted) {
do_check_false(store.isSourceURITrusted(createURI(uri)));
}
Svc.Prefs.set("addons.trustedSourceHostnames", "");
- for (let uri of trusted) {
+ for each (let uri in trusted) {
do_check_false(store.isSourceURITrusted(createURI(uri)));
}
@@ -296,6 +266,8 @@ add_test(function test_addon_syncability() {
add_test(function test_ignore_hotfixes() {
_("Ensure that hotfix extensions are ignored.");
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
+
// A hotfix extension is one that has the id the same as the
// extensions.hotfix.id pref.
let prefs = new Preferences("extensions.");
@@ -304,8 +276,8 @@ add_test(function test_ignore_hotfixes() {
do_check_true(store.isAddonSyncable(addon));
let dummy = {};
- const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall", "isSyncable"];
- for (let k of KEYS) {
+ const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"];
+ for each (let k in KEYS) {
dummy[k] = addon[k];
}
@@ -327,6 +299,7 @@ add_test(function test_ignore_hotfixes() {
uninstallAddon(addon);
+ Svc.Prefs.reset("addons.ignoreRepositoryChecking");
prefs.reset("hotfix.id");
run_next_test();
@@ -336,6 +309,8 @@ add_test(function test_ignore_hotfixes() {
add_test(function test_get_all_ids() {
_("Ensures that getAllIDs() returns an appropriate set.");
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
+
_("Installing two addons.");
let addon1 = installAddon("test_install1");
let addon2 = installAddon("test_bootstrap1_1");
@@ -354,6 +329,7 @@ add_test(function test_get_all_ids() {
addon1.install.cancel();
uninstallAddon(addon2);
+ Svc.Prefs.reset("addons.ignoreRepositoryChecking");
run_next_test();
});
@@ -379,6 +355,9 @@ add_test(function test_change_item_id() {
add_test(function test_create() {
_("Ensure creating/installing an add-on from a record works.");
+ // Set this so that getInstallFromSearchResult doesn't end up
+ // failing the install due to an insecure source URI scheme.
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
let server = createAndStartHTTPServer(HTTP_PORT);
let addon = installAddon("test_bootstrap1_1");
@@ -398,6 +377,7 @@ add_test(function test_create() {
uninstallAddon(newAddon);
+ Svc.Prefs.reset("addons.ignoreRepositoryChecking");
server.stop(run_next_test);
});
@@ -432,18 +412,8 @@ add_test(function test_create_bad_install() {
let record = createRecordForThisApp(guid, id, true, false);
let failed = store.applyIncomingBatch([record]);
- // This addon had no source URI so was skipped - but it's not treated as
- // failure.
- // XXX - this test isn't testing what we thought it was. Previously the addon
- // was not being installed due to requireSecureURL checking *before* we'd
- // attempted to get the XPI.
- // With requireSecureURL disabled we do see a download failure, but the addon
- // *does* get added to |failed|.
- // FTR: onDownloadFailed() is called with ERROR_NETWORK_FAILURE, so it's going
- // to be tricky to distinguish a 404 from other transient network errors
- // where we do want the addon to end up in |failed|.
- // This is being tracked in bug 1284778.
- //do_check_eq(0, failed.length);
+ do_check_eq(1, failed.length);
+ do_check_eq(guid, failed[0]);
let addon = getAddonFromAddonManagerByID(id);
do_check_eq(null, addon);
@@ -451,56 +421,19 @@ add_test(function test_create_bad_install() {
server.stop(run_next_test);
});
-add_test(function test_ignore_system() {
- _("Ensure we ignore system addons");
- // Our system addon should not appear in getAllIDs
- engine._refreshReconcilerState();
- let num = 0;
- for (let guid in store.getAllIDs()) {
- num += 1;
- let addon = reconciler.getAddonStateFromSyncGUID(guid);
- do_check_neq(addon.id, SYSTEM_ADDON_ID);
- }
- do_check_true(num > 1, "should have seen at least one.")
- run_next_test();
-});
-
-add_test(function test_incoming_system() {
- _("Ensure we handle incoming records that refer to a system addon");
- // eg, loop initially had a normal addon but it was then "promoted" to be a
- // system addon but wanted to keep the same ID. The server record exists due
- // to this.
-
- // before we start, ensure the system addon isn't disabled.
- do_check_false(getAddonFromAddonManagerByID(SYSTEM_ADDON_ID).userDisabled);
-
- // Now simulate an incoming record with the same ID as the system addon,
- // but flagged as disabled - it should not be applied.
- let server = createAndStartHTTPServer(HTTP_PORT);
- // We make the incoming record flag the system addon as disabled - it should
- // be ignored.
- let guid = Utils.makeGUID();
- let record = createRecordForThisApp(guid, SYSTEM_ADDON_ID, false, false);
-
- let failed = store.applyIncomingBatch([record]);
- do_check_eq(0, failed.length);
-
- // The system addon should still not be userDisabled.
- do_check_false(getAddonFromAddonManagerByID(SYSTEM_ADDON_ID).userDisabled);
-
- server.stop(run_next_test);
-});
-
add_test(function test_wipe() {
_("Ensures that wiping causes add-ons to be uninstalled.");
let addon1 = installAddon("test_bootstrap1_1");
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
store.wipe();
let addon = getAddonFromAddonManagerByID(addon1.id);
do_check_eq(null, addon);
+ Svc.Prefs.reset("addons.ignoreRepositoryChecking");
+
run_next_test();
});
@@ -515,6 +448,7 @@ add_test(function test_wipe_and_install() {
let record = createRecordForThisApp(installed.syncGUID, installed.id, true,
false);
+ Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
store.wipe();
let deleted = getAddonFromAddonManagerByID(installed.id);
@@ -528,6 +462,7 @@ add_test(function test_wipe_and_install() {
let fetched = getAddonFromAddonManagerByID(record.addonID);
do_check_true(!!fetched);
+ Svc.Prefs.reset("addons.ignoreRepositoryChecking");
server.stop(run_next_test);
});
diff --git a/services/sync/tests/unit/test_addons_tracker.js b/services/sync/tests/unit/test_addons_tracker.js
index 01bf37ab9..690a57d03 100644
--- a/services/sync/tests/unit/test_addons_tracker.js
+++ b/services/sync/tests/unit/test_addons_tracker.js
@@ -11,13 +11,14 @@ Cu.import("resource://services-sync/util.js");
loadAddonTestFunctions();
startupManager();
+Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
Svc.Prefs.set("engine.addons", true);
Service.engineManager.register(AddonsEngine);
-var engine = Service.engineManager.get("addons");
-var reconciler = engine._reconciler;
-var store = engine._store;
-var tracker = engine._tracker;
+let engine = Service.engineManager.get("addons");
+let reconciler = engine._reconciler;
+let store = engine._store;
+let tracker = engine._tracker;
// Don't write out by default.
tracker.persistChangedIDs = false;
diff --git a/services/sync/tests/unit/test_block_sync.js b/services/sync/tests/unit/test_block_sync.js
new file mode 100644
index 000000000..f83b7b740
--- /dev/null
+++ b/services/sync/tests/unit/test_block_sync.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+Cu.import("resource://services-sync/main.js");
+Cu.import("resource://services-sync/util.js");
+
+// Simple test for block/unblock.
+add_task(function *() {
+ Assert.ok(!Weave.Service.scheduler.isBlocked, "sync is not blocked.")
+ Assert.ok(!Svc.Prefs.has("scheduler.blocked-until"), "have no blocked pref");
+ Weave.Service.scheduler.blockSync();
+
+ Assert.ok(Weave.Service.scheduler.isBlocked, "sync is blocked.")
+ Assert.ok(Svc.Prefs.has("scheduler.blocked-until"), "have the blocked pref");
+
+ Weave.Service.scheduler.unblockSync();
+ Assert.ok(!Weave.Service.scheduler.isBlocked, "sync is not blocked.")
+ Assert.ok(!Svc.Prefs.has("scheduler.blocked-until"), "have no blocked pref");
+
+ // now check the "until" functionality.
+ let until = Date.now() + 1000;
+ Weave.Service.scheduler.blockSync(until);
+ Assert.ok(Weave.Service.scheduler.isBlocked, "sync is blocked.")
+ Assert.ok(Svc.Prefs.has("scheduler.blocked-until"), "have the blocked pref");
+
+ // wait for 'until' to pass.
+ yield new Promise((resolve, reject) => {
+ CommonUtils.namedTimer(resolve, 1000, {}, "timer");
+ });
+
+ // should have automagically unblocked and removed the pref.
+ Assert.ok(!Weave.Service.scheduler.isBlocked, "sync is not blocked.")
+ Assert.ok(!Svc.Prefs.has("scheduler.blocked-until"), "have no blocked pref");
+});
+
+function run_test() {
+ run_next_test();
+}
diff --git a/services/sync/tests/unit/test_bookmark_duping.js b/services/sync/tests/unit/test_bookmark_duping.js
deleted file mode 100644
index 1e6c6ed2e..000000000
--- a/services/sync/tests/unit/test_bookmark_duping.js
+++ /dev/null
@@ -1,644 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
-Cu.import("resource://services-common/async.js");
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://services-sync/engines/bookmarks.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://services-sync/bookmark_validator.js");
-
-
-initTestLogging("Trace");
-
-const bms = PlacesUtils.bookmarks;
-
-Service.engineManager.register(BookmarksEngine);
-
-const engine = new BookmarksEngine(Service);
-const store = engine._store;
-store._log.level = Log.Level.Trace;
-engine._log.level = Log.Level.Trace;
-
-function promiseOneObserver(topic) {
- return new Promise((resolve, reject) => {
- let observer = function(subject, topic, data) {
- Services.obs.removeObserver(observer, topic);
- resolve({ subject: subject, data: data });
- }
- Services.obs.addObserver(observer, topic, false);
- });
-}
-
-function setup() {
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {bookmarks: {version: engine.version,
- syncID: engine.syncID}}}},
- bookmarks: {},
- });
-
- generateNewKeys(Service.collectionKeys);
-
- new SyncTestingInfrastructure(server.server);
-
- let collection = server.user("foo").collection("bookmarks");
-
- Svc.Obs.notify("weave:engine:start-tracking"); // We skip usual startup...
-
- return { server, collection };
-}
-
-function* cleanup(server) {
- Svc.Obs.notify("weave:engine:stop-tracking");
- Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", true);
- let promiseStartOver = promiseOneObserver("weave:service:start-over:finish");
- Service.startOver();
- yield promiseStartOver;
- yield new Promise(resolve => server.stop(resolve));
- yield bms.eraseEverything();
-}
-
-function getFolderChildrenIDs(folderId) {
- let index = 0;
- let result = [];
- while (true) {
- let childId = bms.getIdForItemAt(folderId, index);
- if (childId == -1) {
- break;
- }
- result.push(childId);
- index++;
- }
- return result;
-}
-
-function createFolder(parentId, title) {
- let id = bms.createFolder(parentId, title, 0);
- let guid = store.GUIDForId(id);
- return { id, guid };
-}
-
-function createBookmark(parentId, url, title, index = bms.DEFAULT_INDEX) {
- let uri = Utils.makeURI(url);
- let id = bms.insertBookmark(parentId, uri, index, title)
- let guid = store.GUIDForId(id);
- return { id, guid };
-}
-
-function getServerRecord(collection, id) {
- let wbo = collection.get({ full: true, ids: [id] });
- // Whew - lots of json strings inside strings.
- return JSON.parse(JSON.parse(JSON.parse(wbo).payload).ciphertext);
-}
-
-function* promiseNoLocalItem(guid) {
- // Check there's no item with the specified guid.
- let got = yield bms.fetch({ guid });
- ok(!got, `No record remains with GUID ${guid}`);
- // and while we are here ensure the places cache doesn't still have it.
- yield Assert.rejects(PlacesUtils.promiseItemId(guid));
-}
-
-function* validate(collection, expectedFailures = []) {
- let validator = new BookmarkValidator();
- let records = collection.payloads();
-
- let problems = validator.inspectServerRecords(records).problemData;
- // all non-zero problems.
- let summary = problems.getSummary().filter(prob => prob.count != 0);
-
- // split into 2 arrays - expected and unexpected.
- let isInExpectedFailures = elt => {
- for (let i = 0; i < expectedFailures.length; i++) {
- if (elt.name == expectedFailures[i].name && elt.count == expectedFailures[i].count) {
- return true;
- }
- }
- return false;
- }
- let expected = [];
- let unexpected = [];
- for (let elt of summary) {
- (isInExpectedFailures(elt) ? expected : unexpected).push(elt);
- }
- if (unexpected.length || expected.length != expectedFailures.length) {
- do_print("Validation failed:");
- do_print(JSON.stringify(summary));
- // print the entire validator output as it has IDs etc.
- do_print(JSON.stringify(problems, undefined, 2));
- // All server records and the entire bookmark tree.
- do_print("Server records:\n" + JSON.stringify(collection.payloads(), undefined, 2));
- let tree = yield PlacesUtils.promiseBookmarksTree("", { includeItemIds: true });
- do_print("Local bookmark tree:\n" + JSON.stringify(tree, undefined, 2));
- ok(false);
- }
-}
-
-add_task(function* test_dupe_bookmark() {
- _("Ensure that a bookmark we consider a dupe is handled correctly.");
-
- let { server, collection } = this.setup();
-
- try {
- // The parent folder and one bookmark in it.
- let {id: folder1_id, guid: folder1_guid } = createFolder(bms.toolbarFolder, "Folder 1");
- let {id: bmk1_id, guid: bmk1_guid} = createBookmark(folder1_id, "http://getfirefox.com/", "Get Firefox!");
-
- engine.sync();
-
- // We've added the bookmark, its parent (folder1) plus "menu", "toolbar", "unfiled", and "mobile".
- equal(collection.count(), 6);
- equal(getFolderChildrenIDs(folder1_id).length, 1);
-
- // Now create a new incoming record that looks alot like a dupe.
- let newGUID = Utils.makeGUID();
- let to_apply = {
- id: newGUID,
- bmkUri: "http://getfirefox.com/",
- type: "bookmark",
- title: "Get Firefox!",
- parentName: "Folder 1",
- parentid: folder1_guid,
- };
-
- collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 10);
- _("Syncing so new dupe record is processed");
- engine.lastSync = engine.lastSync - 0.01;
- engine.sync();
-
- // We should have logically deleted the dupe record.
- equal(collection.count(), 7);
- ok(getServerRecord(collection, bmk1_guid).deleted);
- // and physically removed from the local store.
- yield promiseNoLocalItem(bmk1_guid);
- // Parent should still only have 1 item.
- equal(getFolderChildrenIDs(folder1_id).length, 1);
- // The parent record on the server should now reference the new GUID and not the old.
- let serverRecord = getServerRecord(collection, folder1_guid);
- ok(!serverRecord.children.includes(bmk1_guid));
- ok(serverRecord.children.includes(newGUID));
-
- // and a final sanity check - use the validator
- yield validate(collection);
- } finally {
- yield cleanup(server);
- }
-});
-
-add_task(function* test_dupe_reparented_bookmark() {
- _("Ensure that a bookmark we consider a dupe from a different parent is handled correctly");
-
- let { server, collection } = this.setup();
-
- try {
- // The parent folder and one bookmark in it.
- let {id: folder1_id, guid: folder1_guid } = createFolder(bms.toolbarFolder, "Folder 1");
- let {id: bmk1_id, guid: bmk1_guid} = createBookmark(folder1_id, "http://getfirefox.com/", "Get Firefox!");
- // Another parent folder *with the same name*
- let {id: folder2_id, guid: folder2_guid } = createFolder(bms.toolbarFolder, "Folder 1");
-
- do_print(`folder1_guid=${folder1_guid}, folder2_guid=${folder2_guid}, bmk1_guid=${bmk1_guid}`);
-
- engine.sync();
-
- // We've added the bookmark, 2 folders plus "menu", "toolbar", "unfiled", and "mobile".
- equal(collection.count(), 7);
- equal(getFolderChildrenIDs(folder1_id).length, 1);
- equal(getFolderChildrenIDs(folder2_id).length, 0);
-
- // Now create a new incoming record that looks alot like a dupe of the
- // item in folder1_guid, but with a record that points to folder2_guid.
- let newGUID = Utils.makeGUID();
- let to_apply = {
- id: newGUID,
- bmkUri: "http://getfirefox.com/",
- type: "bookmark",
- title: "Get Firefox!",
- parentName: "Folder 1",
- parentid: folder2_guid,
- };
-
- collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 10);
-
- _("Syncing so new dupe record is processed");
- engine.lastSync = engine.lastSync - 0.01;
- engine.sync();
-
- // We should have logically deleted the dupe record.
- equal(collection.count(), 8);
- ok(getServerRecord(collection, bmk1_guid).deleted);
- // and physically removed from the local store.
- yield promiseNoLocalItem(bmk1_guid);
- // The original folder no longer has the item
- equal(getFolderChildrenIDs(folder1_id).length, 0);
- // But the second dupe folder does.
- equal(getFolderChildrenIDs(folder2_id).length, 1);
-
- // The record for folder1 on the server should reference neither old or new GUIDs.
- let serverRecord1 = getServerRecord(collection, folder1_guid);
- ok(!serverRecord1.children.includes(bmk1_guid));
- ok(!serverRecord1.children.includes(newGUID));
-
- // The record for folder2 on the server should only reference the new new GUID.
- let serverRecord2 = getServerRecord(collection, folder2_guid);
- ok(!serverRecord2.children.includes(bmk1_guid));
- ok(serverRecord2.children.includes(newGUID));
-
- // and a final sanity check - use the validator
- yield validate(collection);
- } finally {
- yield cleanup(server);
- }
-});
-
-add_task(function* test_dupe_reparented_locally_changed_bookmark() {
- _("Ensure that a bookmark with local changes we consider a dupe from a different parent is handled correctly");
-
- let { server, collection } = this.setup();
-
- try {
- // The parent folder and one bookmark in it.
- let {id: folder1_id, guid: folder1_guid } = createFolder(bms.toolbarFolder, "Folder 1");
- let {id: bmk1_id, guid: bmk1_guid} = createBookmark(folder1_id, "http://getfirefox.com/", "Get Firefox!");
- // Another parent folder *with the same name*
- let {id: folder2_id, guid: folder2_guid } = createFolder(bms.toolbarFolder, "Folder 1");
-
- do_print(`folder1_guid=${folder1_guid}, folder2_guid=${folder2_guid}, bmk1_guid=${bmk1_guid}`);
-
- engine.sync();
-
- // We've added the bookmark, 2 folders plus "menu", "toolbar", "unfiled", and "mobile".
- equal(collection.count(), 7);
- equal(getFolderChildrenIDs(folder1_id).length, 1);
- equal(getFolderChildrenIDs(folder2_id).length, 0);
-
- // Now create a new incoming record that looks alot like a dupe of the
- // item in folder1_guid, but with a record that points to folder2_guid.
- let newGUID = Utils.makeGUID();
- let to_apply = {
- id: newGUID,
- bmkUri: "http://getfirefox.com/",
- type: "bookmark",
- title: "Get Firefox!",
- parentName: "Folder 1",
- parentid: folder2_guid,
- };
-
- collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 10);
-
- // Make a change to the bookmark that's a dupe, and set the modification
- // time further in the future than the incoming record. This will cause
- // us to issue the infamous "DATA LOSS" warning in the logs but cause us
- // to *not* apply the incoming record.
- engine._tracker.addChangedID(bmk1_guid, Date.now() / 1000 + 60);
-
- _("Syncing so new dupe record is processed");
- engine.lastSync = engine.lastSync - 0.01;
- engine.sync();
-
- // We should have logically deleted the dupe record.
- equal(collection.count(), 8);
- ok(getServerRecord(collection, bmk1_guid).deleted);
- // and physically removed from the local store.
- yield promiseNoLocalItem(bmk1_guid);
- // The original folder still longer has the item
- equal(getFolderChildrenIDs(folder1_id).length, 1);
- // The second folder does not.
- equal(getFolderChildrenIDs(folder2_id).length, 0);
-
- // The record for folder1 on the server should reference only the GUID.
- let serverRecord1 = getServerRecord(collection, folder1_guid);
- ok(!serverRecord1.children.includes(bmk1_guid));
- ok(serverRecord1.children.includes(newGUID));
-
- // The record for folder2 on the server should reference nothing.
- let serverRecord2 = getServerRecord(collection, folder2_guid);
- ok(!serverRecord2.children.includes(bmk1_guid));
- ok(!serverRecord2.children.includes(newGUID));
-
- // and a final sanity check - use the validator
- yield validate(collection);
- } finally {
- yield cleanup(server);
- }
-});
-
-add_task(function* test_dupe_reparented_to_earlier_appearing_parent_bookmark() {
- _("Ensure that a bookmark we consider a dupe from a different parent that " +
- "appears in the same sync before the dupe item");
-
- let { server, collection } = this.setup();
-
- try {
- // The parent folder and one bookmark in it.
- let {id: folder1_id, guid: folder1_guid } = createFolder(bms.toolbarFolder, "Folder 1");
- let {id: bmk1_id, guid: bmk1_guid} = createBookmark(folder1_id, "http://getfirefox.com/", "Get Firefox!");
- // One more folder we'll use later.
- let {id: folder2_id, guid: folder2_guid} = createFolder(bms.toolbarFolder, "A second folder");
-
- do_print(`folder1=${folder1_guid}, bmk1=${bmk1_guid} folder2=${folder2_guid}`);
-
- engine.sync();
-
- // We've added the bookmark, 2 folders plus "menu", "toolbar", "unfiled", and "mobile".
- equal(collection.count(), 7);
- equal(getFolderChildrenIDs(folder1_id).length, 1);
-
- let newGUID = Utils.makeGUID();
- let newParentGUID = Utils.makeGUID();
-
- // Have the new parent appear before the dupe item.
- collection.insert(newParentGUID, encryptPayload({
- id: newParentGUID,
- type: "folder",
- title: "Folder 1",
- parentName: "A second folder",
- parentid: folder2_guid,
- children: [newGUID],
- tags: [],
- }), Date.now() / 1000 + 10);
-
- // And also the update to "folder 2" that references the new parent.
- collection.insert(folder2_guid, encryptPayload({
- id: folder2_guid,
- type: "folder",
- title: "A second folder",
- parentName: "Bookmarks Toolbar",
- parentid: "toolbar",
- children: [newParentGUID],
- tags: [],
- }), Date.now() / 1000 + 10);
-
- // Now create a new incoming record that looks alot like a dupe of the
- // item in folder1_guid, with a record that points to a parent with the
- // same name which appeared earlier in this sync.
- collection.insert(newGUID, encryptPayload({
- id: newGUID,
- bmkUri: "http://getfirefox.com/",
- type: "bookmark",
- title: "Get Firefox!",
- parentName: "Folder 1",
- parentid: newParentGUID,
- tags: [],
- }), Date.now() / 1000 + 10);
-
-
- _("Syncing so new records are processed.");
- engine.lastSync = engine.lastSync - 0.01;
- engine.sync();
-
- // Everything should be parented correctly.
- equal(getFolderChildrenIDs(folder1_id).length, 0);
- let newParentID = store.idForGUID(newParentGUID);
- let newID = store.idForGUID(newGUID);
- deepEqual(getFolderChildrenIDs(newParentID), [newID]);
-
- // Make sure the validator thinks everything is hunky-dory.
- yield validate(collection);
- } finally {
- yield cleanup(server);
- }
-});
-
-add_task(function* test_dupe_reparented_to_later_appearing_parent_bookmark() {
- _("Ensure that a bookmark we consider a dupe from a different parent that " +
- "doesn't exist locally as we process the child, but does appear in the same sync");
-
- let { server, collection } = this.setup();
-
- try {
- // The parent folder and one bookmark in it.
- let {id: folder1_id, guid: folder1_guid } = createFolder(bms.toolbarFolder, "Folder 1");
- let {id: bmk1_id, guid: bmk1_guid} = createBookmark(folder1_id, "http://getfirefox.com/", "Get Firefox!");
- // One more folder we'll use later.
- let {id: folder2_id, guid: folder2_guid} = createFolder(bms.toolbarFolder, "A second folder");
-
- do_print(`folder1=${folder1_guid}, bmk1=${bmk1_guid} folder2=${folder2_guid}`);
-
- engine.sync();
-
- // We've added the bookmark, 2 folders plus "menu", "toolbar", "unfiled", and "mobile".
- equal(collection.count(), 7);
- equal(getFolderChildrenIDs(folder1_id).length, 1);
-
- // Now create a new incoming record that looks alot like a dupe of the
- // item in folder1_guid, but with a record that points to a parent with the
- // same name, but a non-existing local ID.
- let newGUID = Utils.makeGUID();
- let newParentGUID = Utils.makeGUID();
-
- collection.insert(newGUID, encryptPayload({
- id: newGUID,
- bmkUri: "http://getfirefox.com/",
- type: "bookmark",
- title: "Get Firefox!",
- parentName: "Folder 1",
- parentid: newParentGUID,
- tags: [],
- }), Date.now() / 1000 + 10);
-
- // Now have the parent appear after (so when the record above is processed
- // this is still unknown.)
- collection.insert(newParentGUID, encryptPayload({
- id: newParentGUID,
- type: "folder",
- title: "Folder 1",
- parentName: "A second folder",
- parentid: folder2_guid,
- children: [newGUID],
- tags: [],
- }), Date.now() / 1000 + 10);
- // And also the update to "folder 2" that references the new parent.
- collection.insert(folder2_guid, encryptPayload({
- id: folder2_guid,
- type: "folder",
- title: "A second folder",
- parentName: "Bookmarks Toolbar",
- parentid: "toolbar",
- children: [newParentGUID],
- tags: [],
- }), Date.now() / 1000 + 10);
-
- _("Syncing so out-of-order records are processed.");
- engine.lastSync = engine.lastSync - 0.01;
- engine.sync();
-
- // The intended parent did end up existing, so it should be parented
- // correctly after de-duplication.
- equal(getFolderChildrenIDs(folder1_id).length, 0);
- let newParentID = store.idForGUID(newParentGUID);
- let newID = store.idForGUID(newGUID);
- deepEqual(getFolderChildrenIDs(newParentID), [newID]);
-
- // Make sure the validator thinks everything is hunky-dory.
- yield validate(collection);
- } finally {
- yield cleanup(server);
- }
-});
-
-add_task(function* test_dupe_reparented_to_future_arriving_parent_bookmark() {
- _("Ensure that a bookmark we consider a dupe from a different parent that " +
- "doesn't exist locally and doesn't appear in this Sync is handled correctly");
-
- let { server, collection } = this.setup();
-
- try {
- // The parent folder and one bookmark in it.
- let {id: folder1_id, guid: folder1_guid } = createFolder(bms.toolbarFolder, "Folder 1");
- let {id: bmk1_id, guid: bmk1_guid} = createBookmark(folder1_id, "http://getfirefox.com/", "Get Firefox!");
- // One more folder we'll use later.
- let {id: folder2_id, guid: folder2_guid} = createFolder(bms.toolbarFolder, "A second folder");
-
- do_print(`folder1=${folder1_guid}, bmk1=${bmk1_guid} folder2=${folder2_guid}`);
-
- engine.sync();
-
- // We've added the bookmark, 2 folders plus "menu", "toolbar", "unfiled", and "mobile".
- equal(collection.count(), 7);
- equal(getFolderChildrenIDs(folder1_id).length, 1);
-
- // Now create a new incoming record that looks alot like a dupe of the
- // item in folder1_guid, but with a record that points to a parent with the
- // same name, but a non-existing local ID.
- let newGUID = Utils.makeGUID();
- let newParentGUID = Utils.makeGUID();
-
- collection.insert(newGUID, encryptPayload({
- id: newGUID,
- bmkUri: "http://getfirefox.com/",
- type: "bookmark",
- title: "Get Firefox!",
- parentName: "Folder 1",
- parentid: newParentGUID,
- tags: [],
- }), Date.now() / 1000 + 10);
-
- _("Syncing so new dupe record is processed");
- engine.lastSync = engine.lastSync - 0.01;
- engine.sync();
-
- // We should have logically deleted the dupe record.
- equal(collection.count(), 8);
- ok(getServerRecord(collection, bmk1_guid).deleted);
- // and physically removed from the local store.
- yield promiseNoLocalItem(bmk1_guid);
- // The intended parent doesn't exist, so it remains in the original folder
- equal(getFolderChildrenIDs(folder1_id).length, 1);
-
- // The record for folder1 on the server should reference the new GUID.
- let serverRecord1 = getServerRecord(collection, folder1_guid);
- ok(!serverRecord1.children.includes(bmk1_guid));
- ok(serverRecord1.children.includes(newGUID));
-
- // As the incoming parent is missing the item should have been annotated
- // with that missing parent.
- equal(PlacesUtils.annotations.getItemAnnotation(store.idForGUID(newGUID), "sync/parent"),
- newParentGUID);
-
- // Check the validator. Sadly, this is known to cause a mismatch between
- // the server and client views of the tree.
- let expected = [
- // We haven't fixed the incoming record that referenced the missing parent.
- { name: "orphans", count: 1 },
- ];
- yield validate(collection, expected);
-
- // Now have the parent magically appear in a later sync - but
- // it appears as being in a different parent from our existing "Folder 1",
- // so the folder itself isn't duped.
- collection.insert(newParentGUID, encryptPayload({
- id: newParentGUID,
- type: "folder",
- title: "Folder 1",
- parentName: "A second folder",
- parentid: folder2_guid,
- children: [newGUID],
- tags: [],
- }), Date.now() / 1000 + 10);
- // We also queue an update to "folder 2" that references the new parent.
- collection.insert(folder2_guid, encryptPayload({
- id: folder2_guid,
- type: "folder",
- title: "A second folder",
- parentName: "Bookmarks Toolbar",
- parentid: "toolbar",
- children: [newParentGUID],
- tags: [],
- }), Date.now() / 1000 + 10);
-
- _("Syncing so missing parent appears");
- engine.lastSync = engine.lastSync - 0.01;
- engine.sync();
-
- // The intended parent now does exist, so it should have been reparented.
- equal(getFolderChildrenIDs(folder1_id).length, 0);
- let newParentID = store.idForGUID(newParentGUID);
- let newID = store.idForGUID(newGUID);
- deepEqual(getFolderChildrenIDs(newParentID), [newID]);
-
- // validation now has different errors :(
- expected = [
- // The validator reports multipleParents because:
- // * The incoming record newParentGUID still (and correctly) references
- // newGUID as a child.
- // * Our original Folder1 was updated to include newGUID when it
- // originally de-deuped and couldn't find the parent.
- // * When the parent *did* eventually arrive we used the parent annotation
- // to correctly reparent - but that reparenting process does not change
- // the server record.
- // Hence, newGUID is a child of both those server records :(
- { name: "multipleParents", count: 1 },
- ];
- yield validate(collection, expected);
-
- } finally {
- yield cleanup(server);
- }
-});
-
-add_task(function* test_dupe_empty_folder() {
- _("Ensure that an empty folder we consider a dupe is handled correctly.");
- // Empty folders aren't particularly interesting in practice (as that seems
- // an edge-case) but duping folders with items is broken - bug 1293163.
- let { server, collection } = this.setup();
-
- try {
- // The folder we will end up duping away.
- let {id: folder1_id, guid: folder1_guid } = createFolder(bms.toolbarFolder, "Folder 1");
-
- engine.sync();
-
- // We've added 1 folder, "menu", "toolbar", "unfiled", and "mobile".
- equal(collection.count(), 5);
-
- // Now create new incoming records that looks alot like a dupe of "Folder 1".
- let newFolderGUID = Utils.makeGUID();
- collection.insert(newFolderGUID, encryptPayload({
- id: newFolderGUID,
- type: "folder",
- title: "Folder 1",
- parentName: "Bookmarks Toolbar",
- parentid: "toolbar",
- children: [],
- }), Date.now() / 1000 + 10);
-
- _("Syncing so new dupe records are processed");
- engine.lastSync = engine.lastSync - 0.01;
- engine.sync();
-
- yield validate(collection);
-
- // Collection now has one additional record - the logically deleted dupe.
- equal(collection.count(), 6);
- // original folder should be logically deleted.
- ok(getServerRecord(collection, folder1_guid).deleted);
- yield promiseNoLocalItem(folder1_guid);
- } finally {
- yield cleanup(server);
- }
-});
-// XXX - TODO - folders with children. Bug 1293163
diff --git a/services/sync/tests/unit/test_bookmark_engine.js b/services/sync/tests/unit/test_bookmark_engine.js
index 9de6c5c0d..bd4c740cb 100644
--- a/services/sync/tests/unit/test_bookmark_engine.js
+++ b/services/sync/tests/unit/test_bookmark_engine.js
@@ -2,10 +2,9 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://gre/modules/PlacesUtils.jsm");
-Cu.import("resource://gre/modules/PlacesSyncUtils.jsm");
Cu.import("resource://gre/modules/BookmarkJSONUtils.jsm");
+Cu.import("resource://services-common/async.js");
Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/engines/bookmarks.js");
Cu.import("resource://services-sync/service.js");
@@ -13,168 +12,9 @@ Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
Cu.import("resource://gre/modules/Promise.jsm");
-initTestLogging("Trace");
-
Service.engineManager.register(BookmarksEngine);
-function* assertChildGuids(folderGuid, expectedChildGuids, message) {
- let tree = yield PlacesUtils.promiseBookmarksTree(folderGuid);
- let childGuids = tree.children.map(child => child.guid);
- deepEqual(childGuids, expectedChildGuids, message);
-}
-
-add_task(function* test_change_during_sync() {
- _("Ensure that we track changes made during a sync.");
-
- let engine = new BookmarksEngine(Service);
- let store = engine._store;
- let tracker = engine._tracker;
- let server = serverForFoo(engine);
- new SyncTestingInfrastructure(server.server);
-
- let collection = server.user("foo").collection("bookmarks");
-
- let bz_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarksMenuFolderId, Utils.makeURI("https://bugzilla.mozilla.org/"),
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Bugzilla");
- let bz_guid = yield PlacesUtils.promiseItemGuid(bz_id);
- _(`Bugzilla GUID: ${bz_guid}`);
-
- Svc.Obs.notify("weave:engine:start-tracking");
-
- try {
- let folder1_id = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.toolbarFolder, "Folder 1", 0);
- let folder1_guid = store.GUIDForId(folder1_id);
- _(`Folder GUID: ${folder1_guid}`);
-
- let bmk1_id = PlacesUtils.bookmarks.insertBookmark(
- folder1_id, Utils.makeURI("http://getthunderbird.com/"),
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Thunderbird!");
- let bmk1_guid = store.GUIDForId(bmk1_id);
- _(`Thunderbird GUID: ${bmk1_guid}`);
-
- // Sync is synchronous, so, to simulate a bookmark change made during a
- // sync, we create a server record that adds a bookmark as a side effect.
- let bmk2_guid = "get-firefox1"; // New child of Folder 1, created remotely.
- let bmk3_id = -1; // New child of Folder 1, created locally during sync.
- let folder2_guid = "folder2-1111"; // New folder, created remotely.
- let tagQuery_guid = "tag-query111"; // New tag query child of Folder 2, created remotely.
- let bmk4_guid = "example-org1"; // New tagged child of Folder 2, created remotely.
- {
- // An existing record changed on the server that should not trigger
- // another sync when applied.
- let bzBmk = new Bookmark("bookmarks", bz_guid);
- bzBmk.bmkUri = "https://bugzilla.mozilla.org/";
- bzBmk.description = "New description";
- bzBmk.title = "Bugzilla";
- bzBmk.tags = ["new", "tags"];
- bzBmk.parentName = "Bookmarks Toolbar";
- bzBmk.parentid = "toolbar";
- collection.insert(bz_guid, encryptPayload(bzBmk.cleartext));
-
- let remoteFolder = new BookmarkFolder("bookmarks", folder2_guid);
- remoteFolder.title = "Folder 2";
- remoteFolder.children = [bmk4_guid, tagQuery_guid];
- remoteFolder.parentName = "Bookmarks Menu";
- remoteFolder.parentid = "menu";
- collection.insert(folder2_guid, encryptPayload(remoteFolder.cleartext));
-
- let localFxBmk = new Bookmark("bookmarks", bmk2_guid);
- localFxBmk.bmkUri = "http://getfirefox.com/";
- localFxBmk.description = "Firefox is awesome.";
- localFxBmk.title = "Get Firefox!";
- localFxBmk.tags = ["firefox", "awesome", "browser"];
- localFxBmk.keyword = "awesome";
- localFxBmk.loadInSidebar = false;
- localFxBmk.parentName = "Folder 1";
- localFxBmk.parentid = folder1_guid;
- let remoteFxBmk = collection.insert(bmk2_guid, encryptPayload(localFxBmk.cleartext));
- remoteFxBmk.get = function get() {
- _("Inserting bookmark into local store");
- bmk3_id = PlacesUtils.bookmarks.insertBookmark(
- folder1_id, Utils.makeURI("https://mozilla.org/"),
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Mozilla");
-
- return ServerWBO.prototype.get.apply(this, arguments);
- };
-
- // A tag query referencing a nonexistent tag folder, which we should
- // create locally when applying the record.
- let localTagQuery = new BookmarkQuery("bookmarks", tagQuery_guid);
- localTagQuery.bmkUri = "place:type=7&folder=999";
- localTagQuery.title = "Taggy tags";
- localTagQuery.folderName = "taggy";
- localTagQuery.parentName = "Folder 2";
- localTagQuery.parentid = folder2_guid;
- collection.insert(tagQuery_guid, encryptPayload(localTagQuery.cleartext));
-
- // A bookmark that should appear in the results for the tag query.
- let localTaggedBmk = new Bookmark("bookmarks", bmk4_guid);
- localTaggedBmk.bmkUri = "https://example.org";
- localTaggedBmk.title = "Tagged bookmark";
- localTaggedBmk.tags = ["taggy"];
- localTaggedBmk.parentName = "Folder 2";
- localTaggedBmk.parentid = folder2_guid;
- collection.insert(bmk4_guid, encryptPayload(localTaggedBmk.cleartext));
- }
-
- yield* assertChildGuids(folder1_guid, [bmk1_guid], "Folder should have 1 child before first sync");
-
- _("Perform first sync");
- {
- let changes = engine.pullNewChanges();
- deepEqual(changes.ids().sort(), [folder1_guid, bmk1_guid, "toolbar"].sort(),
- "Should track bookmark and folder created before first sync");
- yield sync_engine_and_validate_telem(engine, false);
- }
-
- let bmk2_id = store.idForGUID(bmk2_guid);
- let bmk3_guid = store.GUIDForId(bmk3_id);
- _(`Mozilla GUID: ${bmk3_guid}`);
- {
- equal(store.GUIDForId(bmk2_id), bmk2_guid,
- "Remote bookmark should be applied during first sync");
- ok(bmk3_id > -1,
- "Bookmark created during first sync should exist locally");
- ok(!collection.wbo(bmk3_guid),
- "Bookmark created during first sync shouldn't be uploaded yet");
-
- yield* assertChildGuids(folder1_guid, [bmk1_guid, bmk3_guid, bmk2_guid],
- "Folder 1 should have 3 children after first sync");
- yield* assertChildGuids(folder2_guid, [bmk4_guid, tagQuery_guid],
- "Folder 2 should have 2 children after first sync");
- let taggedURIs = PlacesUtils.tagging.getURIsForTag("taggy");
- equal(taggedURIs.length, 1, "Should have 1 tagged URI");
- equal(taggedURIs[0].spec, "https://example.org/",
- "Synced tagged bookmark should appear in tagged URI list");
- }
-
- _("Perform second sync");
- {
- let changes = engine.pullNewChanges();
- deepEqual(changes.ids().sort(), [bmk3_guid, folder1_guid].sort(),
- "Should track bookmark added during last sync and its parent");
- yield sync_engine_and_validate_telem(engine, false);
-
- ok(collection.wbo(bmk3_guid),
- "Bookmark created during first sync should be uploaded during second sync");
-
- yield* assertChildGuids(folder1_guid, [bmk1_guid, bmk3_guid, bmk2_guid],
- "Folder 1 should have same children after second sync");
- yield* assertChildGuids(folder2_guid, [bmk4_guid, tagQuery_guid],
- "Folder 2 should have same children after second sync");
- }
- } finally {
- store.wipe();
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- yield new Promise(resolve => server.stop(resolve));
- Svc.Obs.notify("weave:engine:stop-tracking");
- }
-});
-
-add_task(function* bad_record_allIDs() {
+add_test(function bad_record_allIDs() {
let server = new SyncServer();
server.start();
let syncTesting = new SyncTestingInfrastructure(server.server);
@@ -192,6 +32,9 @@ add_task(function* bad_record_allIDs() {
_("Record is " + badRecordID);
_("Type: " + PlacesUtils.bookmarks.getItemType(badRecordID));
+ _("Fetching children.");
+ store._getChildren("toolbar", {});
+
_("Fetching all IDs.");
let all = store.getAllIDs();
@@ -201,7 +44,49 @@ add_task(function* bad_record_allIDs() {
_("Clean up.");
PlacesUtils.bookmarks.removeItem(badRecordID);
- yield new Promise(r => server.stop(r));
+ server.stop(run_next_test);
+});
+
+add_test(function test_ID_caching() {
+ let server = new SyncServer();
+ server.start();
+ let syncTesting = new SyncTestingInfrastructure(server.server);
+
+ _("Ensure that Places IDs are not cached.");
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+ _("All IDs: " + JSON.stringify(store.getAllIDs()));
+
+ let mobileID = store.idForGUID("mobile");
+ _("Change the GUID for that item, and drop the mobile anno.");
+ store._setGUID(mobileID, "abcdefghijkl");
+ PlacesUtils.annotations.removeItemAnnotation(mobileID, "mobile/bookmarksRoot");
+
+ let err;
+ let newMobileID;
+
+ // With noCreate, we don't find an entry.
+ try {
+ newMobileID = store.idForGUID("mobile", true);
+ _("New mobile ID: " + newMobileID);
+ } catch (ex) {
+ err = ex;
+ _("Error: " + Utils.exceptionStr(err));
+ }
+
+ do_check_true(!err);
+
+ // With !noCreate, lookup works, and it's different.
+ newMobileID = store.idForGUID("mobile", false);
+ _("New mobile ID: " + newMobileID);
+ do_check_true(!!newMobileID);
+ do_check_neq(newMobileID, mobileID);
+
+ // And it's repeatable, even with creation enabled.
+ do_check_eq(newMobileID, store.idForGUID("mobile", false));
+
+ do_check_eq(store.GUIDForId(mobileID), "abcdefghijkl");
+ server.stop(run_next_test);
});
function serverForFoo(engine) {
@@ -212,7 +97,7 @@ function serverForFoo(engine) {
});
}
-add_task(function* test_processIncoming_error_orderChildren() {
+add_test(function test_processIncoming_error_orderChildren() {
_("Ensure that _orderChildren() is called even when _processIncoming() throws an error.");
let engine = new BookmarksEngine(Service);
@@ -259,11 +144,11 @@ add_task(function* test_processIncoming_error_orderChildren() {
let error;
try {
- yield sync_engine_and_validate_telem(engine, true)
+ engine.sync();
} catch(ex) {
error = ex;
}
- ok(!!error);
+ do_check_true(!!error);
// Verify that the bookmark order has been applied.
let new_children = store.createRecord(folder1_guid).children;
@@ -278,11 +163,11 @@ add_task(function* test_processIncoming_error_orderChildren() {
store.wipe();
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
- yield new Promise(resolve => server.stop(resolve));
+ server.stop(run_next_test);
}
});
-add_task(function* test_restorePromptsReupload() {
+add_task(function test_restorePromptsReupload() {
_("Ensure that restoring from a backup will reupload all records.");
let engine = new BookmarksEngine(Service);
let store = engine._store;
@@ -319,7 +204,8 @@ add_task(function* test_restorePromptsReupload() {
backupFile.append("t_b_e_" + Date.now() + ".json");
_("Backing up to file " + backupFile.path);
- yield BookmarkJSONUtils.exportToFile(backupFile.path);
+ backupFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
+ yield BookmarkJSONUtils.exportToFile(backupFile);
_("Create a different record and sync.");
let bmk2_id = PlacesUtils.bookmarks.insertBookmark(
@@ -331,17 +217,17 @@ add_task(function* test_restorePromptsReupload() {
let error;
try {
- yield sync_engine_and_validate_telem(engine, false);
+ engine.sync();
} catch(ex) {
error = ex;
- _("Got error: " + Log.exceptionStr(ex));
+ _("Got error: " + Utils.exceptionStr(ex));
}
do_check_true(!error);
_("Verify that there's only one bookmark on the server, and it's Thunderbird.");
// Of course, there's also the Bookmarks Toolbar and Bookmarks Menu...
let wbos = collection.keys(function (id) {
- return ["menu", "toolbar", "mobile", "unfiled", folder1_guid].indexOf(id) == -1;
+ return ["menu", "toolbar", "mobile", folder1_guid].indexOf(id) == -1;
});
do_check_eq(wbos.length, 1);
do_check_eq(wbos[0], bmk2_guid);
@@ -371,14 +257,14 @@ add_task(function* test_restorePromptsReupload() {
do_check_true(found);
_("Have the correct number of IDs locally, too.");
- do_check_eq(count, ["menu", "toolbar", "mobile", "unfiled", folder1_id, bmk1_id].length);
+ do_check_eq(count, ["menu", "toolbar", folder1_id, bmk1_id].length);
_("Sync again. This'll wipe bookmarks from the server.");
try {
- yield sync_engine_and_validate_telem(engine, false);
+ engine.sync();
} catch(ex) {
error = ex;
- _("Got error: " + Log.exceptionStr(ex));
+ _("Got error: " + Utils.exceptionStr(ex));
}
do_check_true(!error);
@@ -391,9 +277,7 @@ add_task(function* test_restorePromptsReupload() {
let folderWBOs = payloads.filter(function (wbo) {
return ((wbo.type == "folder") &&
(wbo.id != "menu") &&
- (wbo.id != "toolbar") &&
- (wbo.id != "unfiled") &&
- (wbo.id != "mobile"));
+ (wbo.id != "toolbar"));
});
do_check_eq(bookmarkWBOs.length, 1);
@@ -420,12 +304,10 @@ function FakeRecord(constructor, r) {
for (let x in r) {
this[x] = r[x];
}
- // Borrow the constructor's conversion functions.
- this.toSyncBookmark = constructor.prototype.toSyncBookmark;
}
// Bug 632287.
-add_task(function* test_mismatched_types() {
+add_test(function test_mismatched_types() {
_("Ensure that handling a record that changes type causes deletion " +
"then re-adding.");
@@ -437,7 +319,6 @@ add_task(function* test_mismatched_types() {
"description":null,
"parentid": "toolbar"
};
- oldRecord.cleartext = oldRecord;
let newRecord = {
"id": "l1nZZXfB8nC7",
@@ -453,7 +334,6 @@ add_task(function* test_mismatched_types() {
"oT74WwV8_j4P", "IztsItWVSo3-"],
"parentid": "toolbar"
};
- newRecord.cleartext = newRecord;
let engine = new BookmarksEngine(Service);
let store = engine._store;
@@ -466,8 +346,8 @@ add_task(function* test_mismatched_types() {
let bms = PlacesUtils.bookmarks;
let oldR = new FakeRecord(BookmarkFolder, oldRecord);
let newR = new FakeRecord(Livemark, newRecord);
- oldR.parentid = PlacesUtils.bookmarks.toolbarGuid;
- newR.parentid = PlacesUtils.bookmarks.toolbarGuid;
+ oldR._parent = PlacesUtils.bookmarks.toolbarFolder;
+ newR._parent = PlacesUtils.bookmarks.toolbarFolder;
store.applyIncoming(oldR);
_("Applied old. It's a folder.");
@@ -490,11 +370,11 @@ add_task(function* test_mismatched_types() {
store.wipe();
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
- yield new Promise(r => server.stop(r));
+ server.stop(run_next_test);
}
});
-add_task(function* test_bookmark_guidMap_fail() {
+add_test(function test_bookmark_guidMap_fail() {
_("Ensure that failures building the GUID map cause early death.");
let engine = new BookmarksEngine(Service);
@@ -514,9 +394,7 @@ add_task(function* test_bookmark_guidMap_fail() {
engine.lastSync = 1; // So we don't back up.
// Make building the GUID map fail.
-
- let pbt = PlacesUtils.promiseBookmarksTree;
- PlacesUtils.promiseBookmarksTree = function() { return Promise.reject("Nooo"); };
+ store.getAllIDs = function () { throw "Nooo"; };
// Ensure that we throw when accessing _guidMap.
engine._syncStartup();
@@ -542,11 +420,26 @@ add_task(function* test_bookmark_guidMap_fail() {
}
do_check_eq(err, "Nooo");
- PlacesUtils.promiseBookmarksTree = pbt;
- yield new Promise(r => server.stop(r));
+ server.stop(run_next_test);
+});
+
+add_test(function test_bookmark_is_taggable() {
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+
+ do_check_true(store.isTaggable("bookmark"));
+ do_check_true(store.isTaggable("microsummary"));
+ do_check_true(store.isTaggable("query"));
+ do_check_false(store.isTaggable("folder"));
+ do_check_false(store.isTaggable("livemark"));
+ do_check_false(store.isTaggable(null));
+ do_check_false(store.isTaggable(undefined));
+ do_check_false(store.isTaggable(""));
+
+ run_next_test();
});
-add_task(function* test_bookmark_tag_but_no_uri() {
+add_test(function test_bookmark_tag_but_no_uri() {
_("Ensure that a bookmark record with tags, but no URI, doesn't throw an exception.");
let engine = new BookmarksEngine(Service);
@@ -555,43 +448,30 @@ add_task(function* test_bookmark_tag_but_no_uri() {
// We're simply checking that no exception is thrown, so
// no actual checks in this test.
- yield PlacesSyncUtils.bookmarks.insert({
- kind: PlacesSyncUtils.bookmarks.KINDS.BOOKMARK,
- syncId: Utils.makeGUID(),
- parentSyncId: "toolbar",
- url: "http://example.com",
- tags: ["foo"],
- });
- yield PlacesSyncUtils.bookmarks.insert({
- kind: PlacesSyncUtils.bookmarks.KINDS.BOOKMARK,
- syncId: Utils.makeGUID(),
- parentSyncId: "toolbar",
- url: "http://example.org",
- tags: null,
- });
- yield PlacesSyncUtils.bookmarks.insert({
- kind: PlacesSyncUtils.bookmarks.KINDS.BOOKMARK,
- syncId: Utils.makeGUID(),
- url: "about:fake",
- parentSyncId: "toolbar",
- tags: null,
- });
+ store._tagURI(null, ["foo"]);
+ store._tagURI(null, null);
+ store._tagURI(Utils.makeURI("about:fake"), null);
- let record = new FakeRecord(BookmarkFolder, {
- parentid: "toolbar",
+ let record = {
+ _parent: PlacesUtils.bookmarks.toolbarFolder,
id: Utils.makeGUID(),
description: "",
tags: ["foo"],
title: "Taggy tag",
type: "folder"
- });
+ };
+
+ // Because update() walks the cleartext.
+ record.cleartext = record;
store.create(record);
record.tags = ["bar"];
store.update(record);
+
+ run_next_test();
});
-add_task(function* test_misreconciled_root() {
+add_test(function test_misreconciled_root() {
_("Ensure that we don't reconcile an arbitrary record with a root.");
let engine = new BookmarksEngine(Service);
@@ -636,9 +516,6 @@ add_task(function* test_misreconciled_root() {
_("Applying record.");
engine._processIncoming({
- getBatched() {
- return this.get();
- },
get: function () {
this.recordHandler(encrypted);
return {success: true}
@@ -655,7 +532,7 @@ add_task(function* test_misreconciled_root() {
do_check_eq(parentGUIDBefore, parentGUIDAfter);
do_check_eq(parentIDBefore, parentIDAfter);
- yield new Promise(r => server.stop(r));
+ server.stop(run_next_test);
});
function run_test() {
diff --git a/services/sync/tests/unit/test_bookmark_invalid.js b/services/sync/tests/unit/test_bookmark_invalid.js
deleted file mode 100644
index af476a7f9..000000000
--- a/services/sync/tests/unit/test_bookmark_invalid.js
+++ /dev/null
@@ -1,63 +0,0 @@
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://services-sync/engines/bookmarks.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/util.js");
-
-Service.engineManager.register(BookmarksEngine);
-
-var engine = Service.engineManager.get("bookmarks");
-var store = engine._store;
-var tracker = engine._tracker;
-
-add_task(function* test_ignore_invalid_uri() {
- _("Ensure that we don't die with invalid bookmarks.");
-
- // First create a valid bookmark.
- let bmid = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
- Services.io.newURI("http://example.com/", null, null),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "the title");
-
- // Now update moz_places with an invalid url.
- yield PlacesUtils.withConnectionWrapper("test_ignore_invalid_uri", Task.async(function* (db) {
- yield db.execute(
- `UPDATE moz_places SET url = :url, url_hash = hash(:url)
- WHERE id = (SELECT b.fk FROM moz_bookmarks b
- WHERE b.id = :id LIMIT 1)`,
- { id: bmid, url: "<invalid url>" });
- }));
-
- // Ensure that this doesn't throw even though the DB is now in a bad state (a
- // bookmark has an illegal url).
- engine._buildGUIDMap();
-});
-
-add_task(function* test_ignore_missing_uri() {
- _("Ensure that we don't die with a bookmark referencing an invalid bookmark id.");
-
- // First create a valid bookmark.
- let bmid = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
- Services.io.newURI("http://example.com/", null, null),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "the title");
-
- // Now update moz_bookmarks to reference a non-existing places ID
- yield PlacesUtils.withConnectionWrapper("test_ignore_missing_uri", Task.async(function* (db) {
- yield db.execute(
- `UPDATE moz_bookmarks SET fk = 999999
- WHERE id = :id`
- , { id: bmid });
- }));
-
- // Ensure that this doesn't throw even though the DB is now in a bad state (a
- // bookmark has an illegal url).
- engine._buildGUIDMap();
-});
-
-function run_test() {
- initTestLogging('Trace');
- run_next_test();
-}
diff --git a/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js b/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js
index 207372ed6..a7e3a4647 100644
--- a/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js
+++ b/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js
@@ -85,12 +85,12 @@ function run_test() {
do_check_eq(PlacesUtils.bookmarks.getKeywordForBookmark(id), null);
do_check_throws(
- () => PlacesUtils.annotations.getItemAnnotation(id, GENERATORURI_ANNO),
+ function () PlacesUtils.annotations.getItemAnnotation(id, GENERATORURI_ANNO),
Cr.NS_ERROR_NOT_AVAILABLE
);
do_check_throws(
- () => PlacesUtils.annotations.getItemAnnotation(id, STATICTITLE_ANNO),
+ function () PlacesUtils.annotations.getItemAnnotation(id, STATICTITLE_ANNO),
Cr.NS_ERROR_NOT_AVAILABLE
);
diff --git a/services/sync/tests/unit/test_bookmark_livemarks.js b/services/sync/tests/unit/test_bookmark_livemarks.js
index 8adde76d8..d7cda091b 100644
--- a/services/sync/tests/unit/test_bookmark_livemarks.js
+++ b/services/sync/tests/unit/test_bookmark_livemarks.js
@@ -12,11 +12,11 @@ Cu.import("resource://testing-common/services/common/utils.js");
const DESCRIPTION_ANNO = "bookmarkProperties/description";
-var engine = Service.engineManager.get("bookmarks");
-var store = engine._store;
+let engine = Service.engineManager.get("bookmarks");
+let store = engine._store;
// Record borrowed from Bug 631361.
-var record631361 = {
+let record631361 = {
id: "M5bwUKK8hPyF",
index: 150,
modified: 1296768176.49,
@@ -103,11 +103,20 @@ add_test(function test_livemark_descriptions() {
add_test(function test_livemark_invalid() {
_("Livemarks considered invalid by nsLivemarkService are skipped.");
+ _("Parent is 0, which is invalid. Will be set to unfiled.");
+ let noParentRec = makeLivemark(record631361.payload, true);
+ noParentRec._parent = 0;
+ store.create(noParentRec);
+ let recID = store.idForGUID(noParentRec.id, true);
+ do_check_true(recID > 0);
+ do_check_eq(PlacesUtils.bookmarks.getFolderIdForItem(recID), PlacesUtils.bookmarks.unfiledBookmarksFolder);
+
_("Parent is unknown. Will be set to unfiled.");
let lateParentRec = makeLivemark(record631361.payload, true);
let parentGUID = Utils.makeGUID();
lateParentRec.parentid = parentGUID;
- do_check_eq(-1, store.idForGUID(parentGUID));
+ lateParentRec._parent = store.idForGUID(parentGUID); // Usually done by applyIncoming.
+ do_check_eq(-1, lateParentRec._parent);
store.create(lateParentRec);
recID = store.idForGUID(lateParentRec.id, true);
@@ -124,7 +133,7 @@ add_test(function test_livemark_invalid() {
_("Parent is a Livemark. Will be skipped.");
let lmParentRec = makeLivemark(record631361.payload, true);
- lmParentRec.parentid = store.GUIDForId(recID);
+ lmParentRec._parent = recID;
store.create(lmParentRec);
// No exception, but no creation occurs.
do_check_eq(-1, store.idForGUID(lmParentRec.id, true));
diff --git a/services/sync/tests/unit/test_bookmark_order.js b/services/sync/tests/unit/test_bookmark_order.js
index 7625a813f..56806dba0 100644
--- a/services/sync/tests/unit/test_bookmark_order.js
+++ b/services/sync/tests/unit/test_bookmark_order.js
@@ -2,61 +2,53 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
_("Making sure after processing incoming bookmarks, they show up in the right order");
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/PlacesUtils.jsm", this);
Cu.import("resource://services-sync/engines/bookmarks.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
-var check = Task.async(function* (expected, message) {
- let root = yield PlacesUtils.promiseBookmarksTree();
+function getBookmarks(folderId) {
+ let bookmarks = [];
+
+ let pos = 0;
+ while (true) {
+ let itemId = PlacesUtils.bookmarks.getIdForItemAt(folderId, pos);
+ _("Got itemId", itemId, "under", folderId, "at", pos);
+ if (itemId == -1)
+ break;
+
+ switch (PlacesUtils.bookmarks.getItemType(itemId)) {
+ case PlacesUtils.bookmarks.TYPE_BOOKMARK:
+ bookmarks.push(PlacesUtils.bookmarks.getItemTitle(itemId));
+ break;
+ case PlacesUtils.bookmarks.TYPE_FOLDER:
+ bookmarks.push(getBookmarks(itemId));
+ break;
+ default:
+ _("Unsupported item type..");
+ }
+
+ pos++;
+ }
+
+ return bookmarks;
+}
- let bookmarks = (function mapTree(children) {
- return children.map(child => {
- let result = {
- guid: child.guid,
- index: child.index,
- };
- if (child.children) {
- result.children = mapTree(child.children);
- }
- if (child.annos) {
- let orphanAnno = child.annos.find(
- anno => anno.name == "sync/parent");
- if (orphanAnno) {
- result.requestedParent = orphanAnno.value;
- }
- }
- return result;
- });
- }(root.children));
+function check(expected) {
+ let bookmarks = getBookmarks(PlacesUtils.bookmarks.unfiledBookmarksFolder);
_("Checking if the bookmark structure is", JSON.stringify(expected));
_("Got bookmarks:", JSON.stringify(bookmarks));
- deepEqual(bookmarks, expected);
-});
+ do_check_true(Utils.deepEquals(bookmarks, expected));
+}
-add_task(function* test_bookmark_order() {
+function run_test() {
let store = new BookmarksEngine(Service)._store;
initTestLogging("Trace");
_("Starting with a clean slate of no bookmarks");
store.wipe();
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- // Index 2 is the tags root. (Root indices depend on the order of the
- // `CreateRoot` calls in `Database::CreateBookmarkRoots`).
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "clean slate");
+ check([]);
function bookmark(name, parent) {
let bookmark = new Bookmark("http://weave.server/my-bookmark");
@@ -83,447 +75,64 @@ add_task(function* test_bookmark_order() {
store._orderChildren();
delete store._childrenToOrder;
}
- let id10 = "10_aaaaaaaaa";
+
_("basic add first bookmark");
- apply(bookmark(id10, ""));
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "basic add first bookmark");
- let id20 = "20_aaaaaaaaa";
+ apply(bookmark("10", ""));
+ check(["10"]);
+
_("basic append behind 10");
- apply(bookmark(id20, ""));
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id20,
- index: 1,
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "basic append behind 10");
+ apply(bookmark("20", ""));
+ check(["10", "20"]);
- let id31 = "31_aaaaaaaaa";
- let id30 = "f30_aaaaaaaa";
_("basic create in folder");
- apply(bookmark(id31, id30));
- let f30 = folder(id30, "", [id31]);
+ apply(bookmark("31", "f30"));
+ let f30 = folder("f30", "", ["31"]);
apply(f30);
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id20,
- index: 1,
- }, {
- guid: id30,
- index: 2,
- children: [{
- guid: id31,
- index: 0,
- }],
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "basic create in folder");
+ check(["10", "20", ["31"]]);
- let id41 = "41_aaaaaaaaa";
- let id40 = "f40_aaaaaaaa";
_("insert missing parent -> append to unfiled");
- apply(bookmark(id41, id40));
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id20,
- index: 1,
- }, {
- guid: id30,
- index: 2,
- children: [{
- guid: id31,
- index: 0,
- }],
- }, {
- guid: id41,
- index: 3,
- requestedParent: id40,
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "insert missing parent -> append to unfiled");
-
- let id42 = "42_aaaaaaaaa";
+ apply(bookmark("41", "f40"));
+ check(["10", "20", ["31"], "41"]);
_("insert another missing parent -> append");
- apply(bookmark(id42, id40));
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id20,
- index: 1,
- }, {
- guid: id30,
- index: 2,
- children: [{
- guid: id31,
- index: 0,
- }],
- }, {
- guid: id41,
- index: 3,
- requestedParent: id40,
- }, {
- guid: id42,
- index: 4,
- requestedParent: id40,
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "insert another missing parent -> append");
+ apply(bookmark("42", "f40"));
+ check(["10", "20", ["31"], "41", "42"]);
_("insert folder -> move children and followers");
- let f40 = folder(id40, "", [id41, id42]);
+ let f40 = folder("f40", "", ["41", "42"]);
apply(f40);
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id20,
- index: 1,
- }, {
- guid: id30,
- index: 2,
- children: [{
- guid: id31,
- index: 0,
- }],
- }, {
- guid: id40,
- index: 3,
- children: [{
- guid: id41,
- index: 0,
- }, {
- guid: id42,
- index: 1,
- }]
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "insert folder -> move children and followers");
+ check(["10", "20", ["31"], ["41", "42"]]);
_("Moving 41 behind 42 -> update f40");
- f40.children = [id42, id41];
+ f40.children = ["42", "41"];
apply(f40);
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id20,
- index: 1,
- }, {
- guid: id30,
- index: 2,
- children: [{
- guid: id31,
- index: 0,
- }],
- }, {
- guid: id40,
- index: 3,
- children: [{
- guid: id42,
- index: 0,
- }, {
- guid: id41,
- index: 1,
- }]
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "Moving 41 behind 42 -> update f40");
+ check(["10", "20", ["31"], ["42", "41"]]);
_("Moving 10 back to front -> update 10, 20");
- f40.children = [id41, id42];
+ f40.children = ["41", "42"];
apply(f40);
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id20,
- index: 1,
- }, {
- guid: id30,
- index: 2,
- children: [{
- guid: id31,
- index: 0,
- }],
- }, {
- guid: id40,
- index: 3,
- children: [{
- guid: id41,
- index: 0,
- }, {
- guid: id42,
- index: 1,
- }]
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "Moving 10 back to front -> update 10, 20");
+ check(["10", "20", ["31"], ["41", "42"]]);
_("Moving 20 behind 42 in f40 -> update 50");
- apply(bookmark(id20, id40));
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id30,
- index: 1,
- children: [{
- guid: id31,
- index: 0,
- }],
- }, {
- guid: id40,
- index: 2,
- children: [{
- guid: id41,
- index: 0,
- }, {
- guid: id42,
- index: 1,
- }, {
- guid: id20,
- index: 2,
- }]
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "Moving 20 behind 42 in f40 -> update 50");
+ apply(bookmark("20", "f40"));
+ check(["10", ["31"], ["41", "42", "20"]]);
_("Moving 10 in front of 31 in f30 -> update 10, f30");
- apply(bookmark(id10, id30));
- f30.children = [id10, id31];
+ apply(bookmark("10", "f30"));
+ f30.children = ["10", "31"];
apply(f30);
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id30,
- index: 0,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id31,
- index: 1,
- }],
- }, {
- guid: id40,
- index: 1,
- children: [{
- guid: id41,
- index: 0,
- }, {
- guid: id42,
- index: 1,
- }, {
- guid: id20,
- index: 2,
- }]
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "Moving 10 in front of 31 in f30 -> update 10, f30");
+ check([["10", "31"], ["41", "42", "20"]]);
_("Moving 20 from f40 to f30 -> update 20, f30");
- apply(bookmark(id20, id30));
- f30.children = [id10, id20, id31];
+ apply(bookmark("20", "f30"));
+ f30.children = ["10", "20", "31"];
apply(f30);
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id30,
- index: 0,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id20,
- index: 1,
- }, {
- guid: id31,
- index: 2,
- }],
- }, {
- guid: id40,
- index: 1,
- children: [{
- guid: id41,
- index: 0,
- }, {
- guid: id42,
- index: 1,
- }]
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "Moving 20 from f40 to f30 -> update 20, f30");
+ check([["10", "20", "31"], ["41", "42"]]);
_("Move 20 back to front -> update 20, f30");
- apply(bookmark(id20, ""));
- f30.children = [id10, id31];
+ apply(bookmark("20", ""));
+ f30.children = ["10", "31"];
apply(f30);
- yield check([{
- guid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- }, {
- guid: PlacesUtils.bookmarks.toolbarGuid,
- index: 1,
- }, {
- guid: PlacesUtils.bookmarks.unfiledGuid,
- index: 3,
- children: [{
- guid: id30,
- index: 0,
- children: [{
- guid: id10,
- index: 0,
- }, {
- guid: id31,
- index: 1,
- }],
- }, {
- guid: id40,
- index: 1,
- children: [{
- guid: id41,
- index: 0,
- }, {
- guid: id42,
- index: 1,
- }],
- }, {
- guid: id20,
- index: 2,
- }],
- }, {
- guid: PlacesUtils.bookmarks.mobileGuid,
- index: 4,
- }], "Move 20 back to front -> update 20, f30");
+ check([["10", "31"], ["41", "42"], "20"]);
-});
+}
diff --git a/services/sync/tests/unit/test_bookmark_places_query_rewriting.js b/services/sync/tests/unit/test_bookmark_places_query_rewriting.js
index 0ddf81583..8b764d675 100644
--- a/services/sync/tests/unit/test_bookmark_places_query_rewriting.js
+++ b/services/sync/tests/unit/test_bookmark_places_query_rewriting.js
@@ -7,54 +7,45 @@ Cu.import("resource://services-sync/engines/bookmarks.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
-var engine = new BookmarksEngine(Service);
-var store = engine._store;
-
-function makeTagRecord(id, uri) {
- let tagRecord = new BookmarkQuery("bookmarks", id);
- tagRecord.queryId = "MagicTags";
- tagRecord.parentName = "Bookmarks Toolbar";
- tagRecord.bmkUri = uri;
- tagRecord.title = "tagtag";
- tagRecord.folderName = "bar";
- tagRecord.parentid = PlacesUtils.bookmarks.toolbarGuid;
- return tagRecord;
-}
+let engine = new BookmarksEngine(Service);
+let store = engine._store;
function run_test() {
initTestLogging("Trace");
Log.repository.getLogger("Sync.Engine.Bookmarks").level = Log.Level.Trace;
Log.repository.getLogger("Sync.Store.Bookmarks").level = Log.Level.Trace;
+ let tagRecord = new BookmarkQuery("bookmarks", "abcdefabcdef");
let uri = "place:folder=499&type=7&queryType=1";
- let tagRecord = makeTagRecord("abcdefabcdef", uri);
+ tagRecord.queryId = "MagicTags";
+ tagRecord.parentName = "Bookmarks Toolbar";
+ tagRecord.bmkUri = uri;
+ tagRecord.title = "tagtag";
+ tagRecord.folderName = "bar";
_("Type: " + tagRecord.type);
_("Folder name: " + tagRecord.folderName);
- store.applyIncoming(tagRecord);
+ store.preprocessTagQuery(tagRecord);
+
+ _("Verify that the URI has been rewritten.");
+ do_check_neq(tagRecord.bmkUri, uri);
- let tags = PlacesUtils.getFolderContents(PlacesUtils.tagsFolderId).root;
+ let tags = store._getNode(PlacesUtils.tagsFolderId);
+ tags.containerOpen = true;
let tagID;
- try {
- for (let i = 0; i < tags.childCount; ++i) {
- let child = tags.getChild(i);
- if (child.title == "bar") {
- tagID = child.itemId;
- }
- }
- } finally {
- tags.containerOpen = false;
+ for (let i = 0; i < tags.childCount; ++i) {
+ let child = tags.getChild(i);
+ if (child.title == "bar")
+ tagID = child.itemId;
}
+ tags.containerOpen = false;
_("Tag ID: " + tagID);
- let insertedRecord = store.createRecord("abcdefabcdef", "bookmarks");
- do_check_eq(insertedRecord.bmkUri, uri.replace("499", tagID));
+ do_check_eq(tagRecord.bmkUri, uri.replace("499", tagID));
_("... but not if the type is wrong.");
let wrongTypeURI = "place:folder=499&type=2&queryType=1";
- let wrongTypeRecord = makeTagRecord("fedcbafedcba", wrongTypeURI);
- store.applyIncoming(wrongTypeRecord);
-
- insertedRecord = store.createRecord("fedcbafedcba", "bookmarks");
- do_check_eq(insertedRecord.bmkUri, wrongTypeURI);
+ tagRecord.bmkUri = wrongTypeURI;
+ store.preprocessTagQuery(tagRecord);
+ do_check_eq(tagRecord.bmkUri, wrongTypeURI);
}
diff --git a/services/sync/tests/unit/test_bookmark_smart_bookmarks.js b/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
index 942cf2761..4e9b2834d 100644
--- a/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
+++ b/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
@@ -16,8 +16,8 @@ var IOService = Cc["@mozilla.org/network/io-service;1"]
Service.engineManager.register(BookmarksEngine);
-var engine = Service.engineManager.get("bookmarks");
-var store = engine._store;
+let engine = Service.engineManager.get("bookmarks");
+let store = engine._store;
// Clean up after other tests. Only necessary in XULRunner.
store.wipe();
@@ -57,7 +57,7 @@ function serverForFoo(engine) {
// Verify that Places smart bookmarks have their annotation uploaded and
// handled locally.
-add_task(function *test_annotation_uploaded() {
+add_test(function test_annotation_uploaded() {
let server = serverForFoo(engine);
new SyncTestingInfrastructure(server.server);
@@ -110,9 +110,9 @@ add_task(function *test_annotation_uploaded() {
let collection = server.user("foo").collection("bookmarks");
try {
- yield sync_engine_and_validate_telem(engine, false);
+ engine.sync();
let wbos = collection.keys(function (id) {
- return ["menu", "toolbar", "mobile", "unfiled"].indexOf(id) == -1;
+ return ["menu", "toolbar", "mobile"].indexOf(id) == -1;
});
do_check_eq(wbos.length, 1);
@@ -141,7 +141,7 @@ add_task(function *test_annotation_uploaded() {
do_check_eq(smartBookmarkCount(), startCount);
_("Sync. Verify that the downloaded record carries the annotation.");
- yield sync_engine_and_validate_telem(engine, false);
+ engine.sync();
_("Verify that the Places DB now has an annotated bookmark.");
_("Our count has increased again.");
diff --git a/services/sync/tests/unit/test_bookmark_store.js b/services/sync/tests/unit/test_bookmark_store.js
index 902206ba6..53ea433e6 100644
--- a/services/sync/tests/unit/test_bookmark_store.js
+++ b/services/sync/tests/unit/test_bookmark_store.js
@@ -11,17 +11,17 @@ const PARENT_ANNO = "sync/parent";
Service.engineManager.register(BookmarksEngine);
-var engine = Service.engineManager.get("bookmarks");
-var store = engine._store;
-var tracker = engine._tracker;
+let engine = Service.engineManager.get("bookmarks");
+let store = engine._store;
+let tracker = engine._tracker;
// Don't write some persistence files asynchronously.
tracker.persistChangedIDs = false;
-var fxuri = Utils.makeURI("http://getfirefox.com/");
-var tburi = Utils.makeURI("http://getthunderbird.com/");
+let fxuri = Utils.makeURI("http://getfirefox.com/");
+let tburi = Utils.makeURI("http://getthunderbird.com/");
-add_task(function* test_ignore_specials() {
+add_test(function test_ignore_specials() {
_("Ensure that we can't delete bookmark roots.");
// Belt...
@@ -30,7 +30,6 @@ add_task(function* test_ignore_specials() {
do_check_neq(null, store.idForGUID("toolbar"));
store.applyIncoming(record);
- yield store.deletePending();
// Ensure that the toolbar exists.
do_check_neq(null, store.idForGUID("toolbar"));
@@ -40,11 +39,11 @@ add_task(function* test_ignore_specials() {
// Braces...
store.remove(record);
- yield store.deletePending();
do_check_neq(null, store.idForGUID("toolbar"));
engine._buildGUIDMap();
store.wipe();
+ run_next_test();
});
add_test(function test_bookmark_create() {
@@ -81,8 +80,8 @@ add_test(function test_bookmark_create() {
_("Have the store create a new record object. Verify that it has the same data.");
let newrecord = store.createRecord(fxrecord.id);
do_check_true(newrecord instanceof Bookmark);
- for (let property of ["type", "bmkUri", "description", "title",
- "keyword", "parentName", "parentid"]) {
+ for each (let property in ["type", "bmkUri", "description", "title",
+ "keyword", "parentName", "parentid"]) {
do_check_eq(newrecord[property], fxrecord[property]);
}
do_check_true(Utils.deepEquals(newrecord.tags.sort(),
@@ -167,7 +166,7 @@ add_test(function test_bookmark_createRecord() {
_("Verify that the record is created accordingly.");
let record = store.createRecord(bmk1_guid);
- do_check_eq(record.title, "");
+ do_check_eq(record.title, null);
do_check_eq(record.description, null);
do_check_eq(record.keyword, null);
@@ -198,7 +197,7 @@ add_test(function test_folder_create() {
_("Have the store create a new record object. Verify that it has the same data.");
let newrecord = store.createRecord(folder.id);
do_check_true(newrecord instanceof BookmarkFolder);
- for (let property of ["title", "parentName", "parentid"])
+ for each (let property in ["title", "parentName", "parentid"])
do_check_eq(newrecord[property], folder[property]);
_("Folders have high sort index to ensure they're synced first.");
@@ -244,7 +243,7 @@ add_test(function test_folder_createRecord() {
}
});
-add_task(function* test_deleted() {
+add_test(function test_deleted() {
try {
_("Create a bookmark that will be deleted.");
let bmk1_id = PlacesUtils.bookmarks.insertBookmark(
@@ -256,7 +255,7 @@ add_task(function* test_deleted() {
let record = new PlacesItem("bookmarks", bmk1_guid);
record.deleted = true;
store.applyIncoming(record);
- yield store.deletePending();
+
_("Ensure it has been deleted.");
let error;
try {
@@ -272,6 +271,7 @@ add_task(function* test_deleted() {
} finally {
_("Clean up.");
store.wipe();
+ run_next_test();
}
});
@@ -428,106 +428,6 @@ add_test(function test_empty_query_doesnt_die() {
run_next_test();
});
-function assertDeleted(id) {
- let error;
- try {
- PlacesUtils.bookmarks.getItemType(id);
- } catch (e) {
- error = e;
- }
- equal(error.result, Cr.NS_ERROR_ILLEGAL_VALUE)
-}
-
-add_task(function* test_delete_buffering() {
- store.wipe();
- try {
- _("Create a folder with two bookmarks.");
- let folder = new BookmarkFolder("bookmarks", "testfolder-1");
- folder.parentName = "Bookmarks Toolbar";
- folder.parentid = "toolbar";
- folder.title = "Test Folder";
- store.applyIncoming(folder);
-
-
- let fxRecord = new Bookmark("bookmarks", "get-firefox1");
- fxRecord.bmkUri = fxuri.spec;
- fxRecord.title = "Get Firefox!";
- fxRecord.parentName = "Test Folder";
- fxRecord.parentid = "testfolder-1";
-
- let tbRecord = new Bookmark("bookmarks", "get-tndrbrd1");
- tbRecord.bmkUri = tburi.spec;
- tbRecord.title = "Get Thunderbird!";
- tbRecord.parentName = "Test Folder";
- tbRecord.parentid = "testfolder-1";
-
- store.applyIncoming(fxRecord);
- store.applyIncoming(tbRecord);
-
- let folderId = store.idForGUID(folder.id);
- let fxRecordId = store.idForGUID(fxRecord.id);
- let tbRecordId = store.idForGUID(tbRecord.id);
-
- _("Check everything was created correctly.");
-
- equal(PlacesUtils.bookmarks.getItemType(fxRecordId),
- PlacesUtils.bookmarks.TYPE_BOOKMARK);
- equal(PlacesUtils.bookmarks.getItemType(tbRecordId),
- PlacesUtils.bookmarks.TYPE_BOOKMARK);
- equal(PlacesUtils.bookmarks.getItemType(folderId),
- PlacesUtils.bookmarks.TYPE_FOLDER);
-
- equal(PlacesUtils.bookmarks.getFolderIdForItem(fxRecordId), folderId);
- equal(PlacesUtils.bookmarks.getFolderIdForItem(tbRecordId), folderId);
- equal(PlacesUtils.bookmarks.getFolderIdForItem(folderId),
- PlacesUtils.bookmarks.toolbarFolder);
-
- _("Delete the folder and one bookmark.");
-
- let deleteFolder = new PlacesItem("bookmarks", "testfolder-1");
- deleteFolder.deleted = true;
-
- let deleteFxRecord = new PlacesItem("bookmarks", "get-firefox1");
- deleteFxRecord.deleted = true;
-
- store.applyIncoming(deleteFolder);
- store.applyIncoming(deleteFxRecord);
-
- _("Check that we haven't deleted them yet, but that the deletions are queued");
- // these will throw if we've deleted them
- equal(PlacesUtils.bookmarks.getItemType(fxRecordId),
- PlacesUtils.bookmarks.TYPE_BOOKMARK);
-
- equal(PlacesUtils.bookmarks.getItemType(folderId),
- PlacesUtils.bookmarks.TYPE_FOLDER);
-
- equal(PlacesUtils.bookmarks.getFolderIdForItem(fxRecordId), folderId);
-
- ok(store._foldersToDelete.has(folder.id));
- ok(store._atomsToDelete.has(fxRecord.id));
- ok(!store._atomsToDelete.has(tbRecord.id));
-
- _("Process pending deletions and ensure that the right things are deleted.");
- let updatedGuids = yield store.deletePending();
-
- deepEqual(updatedGuids.sort(), ["get-tndrbrd1", "toolbar"]);
-
- assertDeleted(fxRecordId);
- assertDeleted(folderId);
-
- ok(!store._foldersToDelete.has(folder.id));
- ok(!store._atomsToDelete.has(fxRecord.id));
-
- equal(PlacesUtils.bookmarks.getFolderIdForItem(tbRecordId),
- PlacesUtils.bookmarks.toolbarFolder);
-
- } finally {
- _("Clean up.");
- store.wipe();
- }
-});
-
-
function run_test() {
initTestLogging('Trace');
run_next_test();
diff --git a/services/sync/tests/unit/test_bookmark_tracker.js b/services/sync/tests/unit/test_bookmark_tracker.js
index 9b9242579..6060fbae4 100644
--- a/services/sync/tests/unit/test_bookmark_tracker.js
+++ b/services/sync/tests/unit/test_bookmark_tracker.js
@@ -2,80 +2,24 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://gre/modules/PlacesUtils.jsm");
-Cu.import("resource://gre/modules/PlacesSyncUtils.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/engines/bookmarks.js");
Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
-Cu.import("resource:///modules/PlacesUIUtils.jsm");
Service.engineManager.register(BookmarksEngine);
-var engine = Service.engineManager.get("bookmarks");
-var store = engine._store;
-var tracker = engine._tracker;
+let engine = Service.engineManager.get("bookmarks");
+let store = engine._store;
+let tracker = engine._tracker;
store.wipe();
tracker.persistChangedIDs = false;
-const DAY_IN_MS = 24 * 60 * 60 * 1000;
-
-// Test helpers.
-function* verifyTrackerEmpty() {
- let changes = engine.pullNewChanges();
- equal(changes.count(), 0);
- equal(tracker.score, 0);
-}
-
-function* resetTracker() {
- tracker.clearChangedIDs();
- tracker.resetScore();
-}
-
-function* cleanup() {
- store.wipe();
- yield resetTracker();
- yield stopTracking();
-}
-
-// startTracking is a signal that the test wants to notice things that happen
-// after this is called (ie, things already tracked should be discarded.)
-function* startTracking() {
- Svc.Obs.notify("weave:engine:start-tracking");
-}
-
-function* stopTracking() {
- Svc.Obs.notify("weave:engine:stop-tracking");
-}
-
-function* verifyTrackedItems(tracked) {
- let changes = engine.pullNewChanges();
- let trackedIDs = new Set(changes.ids());
- for (let guid of tracked) {
- ok(changes.has(guid), `${guid} should be tracked`);
- ok(changes.getModifiedTimestamp(guid) > 0,
- `${guid} should have a modified time`);
- trackedIDs.delete(guid);
- }
- equal(trackedIDs.size, 0, `Unhandled tracked IDs: ${
- JSON.stringify(Array.from(trackedIDs))}`);
-}
-
-function* verifyTrackedCount(expected) {
- let changes = engine.pullNewChanges();
- equal(changes.count(), expected);
-}
-
-// Copied from PlacesSyncUtils.jsm.
-function findAnnoItems(anno, val) {
- let annos = PlacesUtils.annotations;
- return annos.getItemsWithAnnotation(anno, {}).filter(id =>
- annos.getItemAnnotation(id, anno) == val);
-}
-
-add_task(function* test_tracking() {
- _("Test starting and stopping the tracker");
+function test_tracking() {
+ _("Verify we've got an empty tracker to work with.");
+ let tracker = engine._tracker;
+ do_check_empty(tracker.changedIDs);
let folder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarks.bookmarksMenuFolder,
@@ -89,630 +33,60 @@ add_task(function* test_tracking() {
try {
_("Create bookmark. Won't show because we haven't started tracking yet");
createBmk();
- yield verifyTrackedCount(0);
+ do_check_empty(tracker.changedIDs);
do_check_eq(tracker.score, 0);
_("Tell the tracker to start tracking changes.");
- yield startTracking();
+ Svc.Obs.notify("weave:engine:start-tracking");
createBmk();
// We expect two changed items because the containing folder
// changed as well (new child).
- yield verifyTrackedCount(2);
+ do_check_attribute_count(tracker.changedIDs, 2);
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
_("Notifying twice won't do any harm.");
- yield startTracking();
+ Svc.Obs.notify("weave:engine:start-tracking");
createBmk();
- yield verifyTrackedCount(3);
+ do_check_attribute_count(tracker.changedIDs, 3);
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 4);
_("Let's stop tracking again.");
- yield resetTracker();
- yield stopTracking();
+ tracker.clearChangedIDs();
+ tracker.resetScore();
+ Svc.Obs.notify("weave:engine:stop-tracking");
createBmk();
- yield verifyTrackedCount(0);
+ do_check_empty(tracker.changedIDs);
do_check_eq(tracker.score, 0);
_("Notifying twice won't do any harm.");
- yield stopTracking();
+ Svc.Obs.notify("weave:engine:stop-tracking");
createBmk();
- yield verifyTrackedCount(0);
+ do_check_empty(tracker.changedIDs);
do_check_eq(tracker.score, 0);
} finally {
_("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_batch_tracking() {
- _("Test tracker does the correct thing during and after a places 'batch'");
-
- yield startTracking();
-
- PlacesUtils.bookmarks.runInBatchMode({
- runBatched: function() {
- let folder = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- "Test Folder", PlacesUtils.bookmarks.DEFAULT_INDEX);
- // We should be tracking the new folder and its parent (and need to jump
- // through blocking hoops...)
- Async.promiseSpinningly(Task.spawn(verifyTrackedCount(2)));
- // But not have bumped the score.
- do_check_eq(tracker.score, 0);
- }
- }, null);
-
- // Out of batch mode - tracker should be the same, but score should be up.
- yield verifyTrackedCount(2);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- yield cleanup();
-});
-
-add_task(function* test_nested_batch_tracking() {
- _("Test tracker does the correct thing if a places 'batch' is nested");
-
- yield startTracking();
-
- PlacesUtils.bookmarks.runInBatchMode({
- runBatched: function() {
-
- PlacesUtils.bookmarks.runInBatchMode({
- runBatched: function() {
- let folder = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- "Test Folder", PlacesUtils.bookmarks.DEFAULT_INDEX);
- // We should be tracking the new folder and its parent (and need to jump
- // through blocking hoops...)
- Async.promiseSpinningly(Task.spawn(verifyTrackedCount(2)));
- // But not have bumped the score.
- do_check_eq(tracker.score, 0);
- }
- }, null);
- _("inner batch complete.");
- // should still not have a score as the outer batch is pending.
- do_check_eq(tracker.score, 0);
- }
- }, null);
-
- // Out of both batches - tracker should be the same, but score should be up.
- yield verifyTrackedCount(2);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- yield cleanup();
-});
-
-add_task(function* test_tracker_sql_batching() {
- _("Test tracker does the correct thing when it is forced to batch SQL queries");
-
- const SQLITE_MAX_VARIABLE_NUMBER = 999;
- let numItems = SQLITE_MAX_VARIABLE_NUMBER * 2 + 10;
- let createdIDs = [];
-
- yield startTracking();
-
- PlacesUtils.bookmarks.runInBatchMode({
- runBatched: function() {
- for (let i = 0; i < numItems; i++) {
- let syncBmkID = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.unfiledBookmarksFolder,
- Utils.makeURI("https://example.org/" + i),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Sync Bookmark " + i);
- createdIDs.push(syncBmkID);
- }
- }
- }, null);
-
- do_check_eq(createdIDs.length, numItems);
- yield verifyTrackedCount(numItems + 1); // the folder is also tracked.
- yield cleanup();
-});
-
-add_task(function* test_onItemAdded() {
- _("Items inserted via the synchronous bookmarks API should be tracked");
-
- try {
- yield startTracking();
-
- _("Insert a folder using the sync API");
- let syncFolderID = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder, "Sync Folder",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let syncFolderGUID = engine._store.GUIDForId(syncFolderID);
- yield verifyTrackedItems(["menu", syncFolderGUID]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
-
- yield resetTracker();
- yield startTracking();
-
- _("Insert a bookmark using the sync API");
- let syncBmkID = PlacesUtils.bookmarks.insertBookmark(syncFolderID,
- Utils.makeURI("https://example.org/sync"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Sync Bookmark");
- let syncBmkGUID = engine._store.GUIDForId(syncBmkID);
- yield verifyTrackedItems([syncFolderGUID, syncBmkGUID]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
-
- yield resetTracker();
- yield startTracking();
-
- _("Insert a separator using the sync API");
- let syncSepID = PlacesUtils.bookmarks.insertSeparator(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- PlacesUtils.bookmarks.getItemIndex(syncFolderID));
- let syncSepGUID = engine._store.GUIDForId(syncSepID);
- yield verifyTrackedItems(["menu", syncSepGUID]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_async_onItemAdded() {
- _("Items inserted via the asynchronous bookmarks API should be tracked");
-
- try {
- yield startTracking();
-
- _("Insert a folder using the async API");
- let asyncFolder = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_FOLDER,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- title: "Async Folder",
- });
- yield verifyTrackedItems(["menu", asyncFolder.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
-
- yield resetTracker();
- yield startTracking();
-
- _("Insert a bookmark using the async API");
- let asyncBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: asyncFolder.guid,
- url: "https://example.org/async",
- title: "Async Bookmark",
- });
- yield verifyTrackedItems([asyncFolder.guid, asyncBmk.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
-
- yield resetTracker();
- yield startTracking();
-
- _("Insert a separator using the async API");
- let asyncSep = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_SEPARATOR,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- index: asyncFolder.index,
- });
- yield verifyTrackedItems(["menu", asyncSep.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_async_onItemChanged() {
- _("Items updated using the asynchronous bookmarks API should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert a bookmark");
- let fxBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- _(`Firefox GUID: ${fxBmk.guid}`);
-
- yield startTracking();
-
- _("Update the bookmark using the async API");
- yield PlacesUtils.bookmarks.update({
- guid: fxBmk.guid,
- title: "Download Firefox",
- url: "https://www.mozilla.org/firefox",
- // PlacesUtils.bookmarks.update rejects last modified dates older than
- // the added date.
- lastModified: new Date(Date.now() + DAY_IN_MS),
- });
-
- yield verifyTrackedItems([fxBmk.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemChanged_itemDates() {
- _("Changes to item dates should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert a bookmark");
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = engine._store.GUIDForId(fx_id);
- _(`Firefox GUID: ${fx_guid}`);
-
- yield startTracking();
-
- _("Reset the bookmark's added date");
- // Convert to microseconds for PRTime.
- let dateAdded = (Date.now() - DAY_IN_MS) * 1000;
- PlacesUtils.bookmarks.setItemDateAdded(fx_id, dateAdded);
- yield verifyTrackedItems([fx_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- yield resetTracker();
-
- _("Set the bookmark's last modified date");
- let dateModified = Date.now() * 1000;
- PlacesUtils.bookmarks.setItemLastModified(fx_id, dateModified);
- yield verifyTrackedItems([fx_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemChanged_changeBookmarkURI() {
- _("Changes to bookmark URIs should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert a bookmark");
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = engine._store.GUIDForId(fx_id);
- _(`Firefox GUID: ${fx_guid}`);
-
- _("Set a tracked annotation to make sure we only notify once");
- PlacesUtils.annotations.setItemAnnotation(
- fx_id, PlacesSyncUtils.bookmarks.DESCRIPTION_ANNO, "A test description", 0,
- PlacesUtils.annotations.EXPIRE_NEVER);
-
- yield startTracking();
-
- _("Change the bookmark's URI");
- PlacesUtils.bookmarks.changeBookmarkURI(fx_id,
- Utils.makeURI("https://www.mozilla.org/firefox"));
- yield verifyTrackedItems([fx_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemTagged() {
- _("Items tagged using the synchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- _("Create a folder");
- let folder = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folderGUID = engine._store.GUIDForId(folder);
- _("Folder ID: " + folder);
- _("Folder GUID: " + folderGUID);
-
- _("Track changes to tags");
- let uri = Utils.makeURI("http://getfirefox.com");
- let b = PlacesUtils.bookmarks.insertBookmark(
- folder, uri,
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
- let bGUID = engine._store.GUIDForId(b);
- _("New item is " + b);
- _("GUID: " + bGUID);
-
- yield startTracking();
-
- _("Tag the item");
- PlacesUtils.tagging.tagURI(uri, ["foo"]);
-
- // bookmark should be tracked, folder should not be.
- yield verifyTrackedItems([bGUID]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 5);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemUntagged() {
- _("Items untagged using the synchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert tagged bookmarks");
- let uri = Utils.makeURI("http://getfirefox.com");
- let fx1ID = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder, uri,
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
- let fx1GUID = engine._store.GUIDForId(fx1ID);
- // Different parent and title; same URL.
- let fx2ID = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.toolbarFolder, uri,
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Download Firefox");
- let fx2GUID = engine._store.GUIDForId(fx2ID);
- PlacesUtils.tagging.tagURI(uri, ["foo"]);
-
- yield startTracking();
-
- _("Remove the tag");
- PlacesUtils.tagging.untagURI(uri, ["foo"]);
-
- yield verifyTrackedItems([fx1GUID, fx2GUID]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_async_onItemUntagged() {
- _("Items untagged using the asynchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert tagged bookmarks");
- let fxBmk1 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- let fxBmk2 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.toolbarGuid,
- url: "http://getfirefox.com",
- title: "Download Firefox",
- });
- let tag = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_FOLDER,
- parentGuid: PlacesUtils.bookmarks.tagsGuid,
- title: "some tag",
- });
- let fxTag = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: tag.guid,
- url: "http://getfirefox.com",
- });
-
- yield startTracking();
-
- _("Remove the tag using the async bookmarks API");
- yield PlacesUtils.bookmarks.remove(fxTag.guid);
-
- yield verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_async_onItemTagged() {
- _("Items tagged using the asynchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert untagged bookmarks");
- let folder1 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_FOLDER,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- title: "Folder 1",
- });
- let fxBmk1 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: folder1.guid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- let folder2 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_FOLDER,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- title: "Folder 2",
- });
- // Different parent and title; same URL.
- let fxBmk2 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: folder2.guid,
- url: "http://getfirefox.com",
- title: "Download Firefox",
- });
-
- yield startTracking();
-
- // This will change once tags are moved into a separate table (bug 424160).
- // We specifically test this case because Bookmarks.jsm updates tagged
- // bookmarks and notifies observers.
- _("Insert a tag using the async bookmarks API");
- let tag = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_FOLDER,
- parentGuid: PlacesUtils.bookmarks.tagsGuid,
- title: "some tag",
- });
-
- _("Tag an item using the async bookmarks API");
- yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: tag.guid,
- url: "http://getfirefox.com",
- });
-
- yield verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 6);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemKeywordChanged() {
- _("Keyword changes via the synchronous API should be tracked");
-
- try {
- yield stopTracking();
- let folder = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folderGUID = engine._store.GUIDForId(folder);
- _("Track changes to keywords");
- let uri = Utils.makeURI("http://getfirefox.com");
- let b = PlacesUtils.bookmarks.insertBookmark(
- folder, uri,
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
- let bGUID = engine._store.GUIDForId(b);
- _("New item is " + b);
- _("GUID: " + bGUID);
-
- yield startTracking();
-
- _("Give the item a keyword");
- PlacesUtils.bookmarks.setKeywordForBookmark(b, "the_keyword");
-
- // bookmark should be tracked, folder should not be.
- yield verifyTrackedItems([bGUID]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
-
- } finally {
- _("Clean up.");
- yield cleanup();
+ store.wipe();
+ tracker.clearChangedIDs();
+ tracker.resetScore();
+ Svc.Obs.notify("weave:engine:stop-tracking");
}
-});
-
-add_task(function* test_async_onItemKeywordChanged() {
- _("Keyword changes via the asynchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert two bookmarks with the same URL");
- let fxBmk1 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- let fxBmk2 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.toolbarGuid,
- url: "http://getfirefox.com",
- title: "Download Firefox",
- });
-
- yield startTracking();
-
- _("Add a keyword for both items");
- yield PlacesUtils.keywords.insert({
- keyword: "the_keyword",
- url: "http://getfirefox.com",
- postData: "postData",
- });
-
- yield verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_async_onItemKeywordDeleted() {
- _("Keyword deletions via the asynchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert two bookmarks with the same URL and keywords");
- let fxBmk1 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- let fxBmk2 = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.toolbarGuid,
- url: "http://getfirefox.com",
- title: "Download Firefox",
- });
- yield PlacesUtils.keywords.insert({
- keyword: "the_keyword",
- url: "http://getfirefox.com",
- });
-
- yield startTracking();
-
- _("Remove the keyword");
- yield PlacesUtils.keywords.remove("the_keyword");
-
- yield verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemPostDataChanged() {
- _("Post data changes should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert a bookmark");
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = engine._store.GUIDForId(fx_id);
- _(`Firefox GUID: ${fx_guid}`);
-
- yield startTracking();
+}
- // PlacesUtils.setPostDataForBookmark is deprecated, but still used by
- // PlacesTransactions.NewBookmark.
- _("Post data for the bookmark should be ignored");
- yield PlacesUtils.setPostDataForBookmark(fx_id, "postData");
- yield verifyTrackerEmpty();
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
+function test_onItemChanged() {
+ // Anno that's in ANNOS_TO_TRACK.
+ const DESCRIPTION_ANNO = "bookmarkProperties/description";
-add_task(function* test_onItemAnnoChanged() {
- _("Item annotations should be tracked");
+ _("Verify we've got an empty tracker to work with.");
+ let tracker = engine._tracker;
+ do_check_empty(tracker.changedIDs);
+ do_check_eq(tracker.score, 0);
try {
- yield stopTracking();
+ Svc.Obs.notify("weave:engine:stop-tracking");
let folder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folderGUID = engine._store.GUIDForId(folder);
_("Track changes to annos.");
let b = PlacesUtils.bookmarks.insertBookmark(
folder, Utils.makeURI("http://getfirefox.com"),
@@ -721,225 +95,27 @@ add_task(function* test_onItemAnnoChanged() {
_("New item is " + b);
_("GUID: " + bGUID);
- yield startTracking();
+ Svc.Obs.notify("weave:engine:start-tracking");
PlacesUtils.annotations.setItemAnnotation(
- b, PlacesSyncUtils.bookmarks.DESCRIPTION_ANNO, "A test description", 0,
+ b, DESCRIPTION_ANNO, "A test description", 0,
PlacesUtils.annotations.EXPIRE_NEVER);
- // bookmark should be tracked, folder should not.
- yield verifyTrackedItems([bGUID]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- yield resetTracker();
-
- PlacesUtils.annotations.removeItemAnnotation(b,
- PlacesSyncUtils.bookmarks.DESCRIPTION_ANNO);
- yield verifyTrackedItems([bGUID]);
+ do_check_true(tracker.changedIDs[bGUID] > 0);
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemAdded_filtered_root() {
- _("Items outside the change roots should not be tracked");
-
- try {
- yield startTracking();
-
- _("Create a new root");
- let rootID = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.placesRoot,
- "New root",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let rootGUID = engine._store.GUIDForId(rootID);
- _(`New root GUID: ${rootGUID}`);
-
- _("Insert a bookmark underneath the new root");
- let untrackedBmkID = PlacesUtils.bookmarks.insertBookmark(
- rootID,
- Utils.makeURI("http://getthunderbird.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Thunderbird!");
- let untrackedBmkGUID = engine._store.GUIDForId(untrackedBmkID);
- _(`New untracked bookmark GUID: ${untrackedBmkGUID}`);
-
- _("Insert a bookmark underneath the Places root");
- let rootBmkID = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.placesRoot,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
- let rootBmkGUID = engine._store.GUIDForId(rootBmkID);
- _(`New Places root bookmark GUID: ${rootBmkGUID}`);
-
- _("New root and bookmark should be ignored");
- yield verifyTrackedItems([]);
- // ...But we'll still increment the score and filter out the changes at
- // sync time.
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 6);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemDeleted_filtered_root() {
- _("Deleted items outside the change roots should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert a bookmark underneath the Places root");
- let rootBmkID = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.placesRoot,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
- let rootBmkGUID = engine._store.GUIDForId(rootBmkID);
- _(`New Places root bookmark GUID: ${rootBmkGUID}`);
-
- yield startTracking();
-
- PlacesUtils.bookmarks.removeItem(rootBmkID);
-
- // We shouldn't upload tombstones for items in filtered roots, but the
- // `onItemRemoved` observer doesn't have enough context to determine
- // the root, so we'll end up uploading it.
- yield verifyTrackedItems([rootBmkGUID]);
- // We'll increment the counter twice (once for the removed item, and once
- // for the Places root), then filter out the root.
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-add_task(function* test_onPageAnnoChanged() {
- _("Page annotations should not be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert a bookmark without an annotation");
- let pageURI = Utils.makeURI("http://getfirefox.com");
- PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- pageURI,
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
-
- yield startTracking();
-
- _("Add a page annotation");
- PlacesUtils.annotations.setPageAnnotation(pageURI, "URIProperties/characterSet",
- "UTF-8", 0, PlacesUtils.annotations.EXPIRE_NEVER);
- yield verifyTrackerEmpty();
- yield resetTracker();
-
- _("Remove the page annotation");
- PlacesUtils.annotations.removePageAnnotation(pageURI,
- "URIProperties/characterSet");
- yield verifyTrackerEmpty();
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onFaviconChanged() {
- _("Favicon changes should not be tracked");
-
- try {
- yield stopTracking();
-
- let pageURI = Utils.makeURI("http://getfirefox.com");
- let iconURI = Utils.makeURI("http://getfirefox.com/icon");
- PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- pageURI,
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
-
- yield PlacesTestUtils.addVisits(pageURI);
-
- yield startTracking();
-
- _("Favicon annotations should be ignored");
- let iconURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAA" +
- "AAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==";
-
- PlacesUtils.favicons.replaceFaviconDataFromDataURL(iconURI, iconURL, 0,
- Services.scriptSecurityManager.getSystemPrincipal());
-
- yield new Promise(resolve => {
- PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, iconURI, true,
- PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, (iconURI, dataLen, data, mimeType) => {
- resolve();
- },
- Services.scriptSecurityManager.getSystemPrincipal());
- });
- yield verifyTrackerEmpty();
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onLivemarkAdded() {
- _("New livemarks should be tracked");
-
- try {
- yield startTracking();
-
- _("Insert a livemark");
- let livemark = yield PlacesUtils.livemarks.addLivemark({
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- // Use a local address just in case, to avoid potential aborts for
- // non-local connections.
- feedURI: Utils.makeURI("http://localhost:0"),
- });
- // Prevent the livemark refresh timer from requesting the URI.
- livemark.terminate();
-
- yield verifyTrackedItems(["menu", livemark.guid]);
- // Three changes: one for the parent, one for creating the livemark
- // folder, and one for setting the "livemark/feedURI" anno on the folder.
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onLivemarkDeleted() {
- _("Deleted livemarks should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert a livemark");
- let livemark = yield PlacesUtils.livemarks.addLivemark({
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- feedURI: Utils.makeURI("http://localhost:0"),
- });
- livemark.terminate();
-
- yield startTracking();
-
- _("Remove a livemark");
- yield PlacesUtils.livemarks.removeLivemark({
- guid: livemark.guid,
- });
-
- yield verifyTrackedItems(["menu", livemark.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
} finally {
_("Clean up.");
- yield cleanup();
+ store.wipe();
+ tracker.clearChangedIDs();
+ tracker.resetScore();
+ Svc.Obs.notify("weave:engine:stop-tracking");
}
-});
+}
-add_task(function* test_onItemMoved() {
- _("Items moved via the synchronous API should be tracked");
+function test_onItemMoved() {
+ _("Verify we've got an empty tracker to work with.");
+ let tracker = engine._tracker;
+ do_check_empty(tracker.changedIDs);
+ do_check_eq(tracker.score, 0);
try {
let fx_id = PlacesUtils.bookmarks.insertBookmark(
@@ -948,590 +124,55 @@ add_task(function* test_onItemMoved() {
PlacesUtils.bookmarks.DEFAULT_INDEX,
"Get Firefox!");
let fx_guid = engine._store.GUIDForId(fx_id);
- _("Firefox GUID: " + fx_guid);
let tb_id = PlacesUtils.bookmarks.insertBookmark(
PlacesUtils.bookmarks.bookmarksMenuFolder,
Utils.makeURI("http://getthunderbird.com"),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"Get Thunderbird!");
let tb_guid = engine._store.GUIDForId(tb_id);
- _("Thunderbird GUID: " + tb_guid);
- yield startTracking();
+ Svc.Obs.notify("weave:engine:start-tracking");
// Moving within the folder will just track the folder.
PlacesUtils.bookmarks.moveItem(
tb_id, PlacesUtils.bookmarks.bookmarksMenuFolder, 0);
- yield verifyTrackedItems(['menu']);
+ do_check_true(tracker.changedIDs['menu'] > 0);
+ do_check_eq(tracker.changedIDs['toolbar'], undefined);
+ do_check_eq(tracker.changedIDs[fx_guid], undefined);
+ do_check_eq(tracker.changedIDs[tb_guid], undefined);
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- yield resetTracker();
+ tracker.clearChangedIDs();
+ tracker.resetScore();
// Moving a bookmark to a different folder will track the old
// folder, the new folder and the bookmark.
- PlacesUtils.bookmarks.moveItem(fx_id, PlacesUtils.bookmarks.toolbarFolder,
+ PlacesUtils.bookmarks.moveItem(tb_id, PlacesUtils.bookmarks.toolbarFolder,
PlacesUtils.bookmarks.DEFAULT_INDEX);
- yield verifyTrackedItems(['menu', 'toolbar', fx_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
-
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_async_onItemMoved_update() {
- _("Items moved via the asynchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- let fxBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- let tbBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getthunderbird.com",
- title: "Get Thunderbird!",
- });
-
- yield startTracking();
-
- _("Repositioning a bookmark should track the folder");
- yield PlacesUtils.bookmarks.update({
- guid: tbBmk.guid,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- index: 0,
- });
- yield verifyTrackedItems(['menu']);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- yield resetTracker();
-
- _("Reparenting a bookmark should track both folders and the bookmark");
- yield PlacesUtils.bookmarks.update({
- guid: tbBmk.guid,
- parentGuid: PlacesUtils.bookmarks.toolbarGuid,
- index: PlacesUtils.bookmarks.DEFAULT_INDEX,
- });
- yield verifyTrackedItems(['menu', 'toolbar', tbBmk.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_async_onItemMoved_reorder() {
- _("Items reordered via the asynchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- _("Insert out-of-order bookmarks");
- let fxBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- _(`Firefox GUID: ${fxBmk.guid}`);
-
- let tbBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getthunderbird.com",
- title: "Get Thunderbird!",
- });
- _(`Thunderbird GUID: ${tbBmk.guid}`);
-
- let mozBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "https://mozilla.org",
- title: "Mozilla",
- });
- _(`Mozilla GUID: ${mozBmk.guid}`);
-
- yield startTracking();
-
- _("Reorder bookmarks");
- yield PlacesUtils.bookmarks.reorder(PlacesUtils.bookmarks.menuGuid,
- [mozBmk.guid, fxBmk.guid, tbBmk.guid]);
-
- // As with setItemIndex, we should only track the folder if we reorder
- // its children, but we should bump the score for every changed item.
- yield verifyTrackedItems(["menu"]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemMoved_setItemIndex() {
- _("Items with updated indices should be tracked");
-
- try {
- yield stopTracking();
-
- let folder_id = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- "Test folder",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folder_guid = engine._store.GUIDForId(folder_id);
- _(`Folder GUID: ${folder_guid}`);
-
- let tb_id = PlacesUtils.bookmarks.insertBookmark(
- folder_id,
- Utils.makeURI("http://getthunderbird.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Thunderbird");
- let tb_guid = engine._store.GUIDForId(tb_id);
- _(`Thunderbird GUID: ${tb_guid}`);
-
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- folder_id,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Firefox");
- let fx_guid = engine._store.GUIDForId(fx_id);
- _(`Firefox GUID: ${fx_guid}`);
-
- let moz_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- Utils.makeURI("https://mozilla.org"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Mozilla"
- );
- let moz_guid = engine._store.GUIDForId(moz_id);
- _(`Mozilla GUID: ${moz_guid}`);
-
- yield startTracking();
-
- // PlacesSortFolderByNameTransaction exercises
- // PlacesUtils.bookmarks.setItemIndex.
- let txn = new PlacesSortFolderByNameTransaction(folder_id);
-
- // We're reordering items within the same folder, so only the folder
- // should be tracked.
- _("Execute the sort folder transaction");
- txn.doTransaction();
- yield verifyTrackedItems([folder_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- yield resetTracker();
-
- _("Undo the sort folder transaction");
- txn.undoTransaction();
- yield verifyTrackedItems([folder_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemDeleted_removeFolderTransaction() {
- _("Folders removed in a transaction should be tracked");
-
- try {
- yield stopTracking();
-
- _("Create a folder with two children");
- let folder_id = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- "Test folder",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folder_guid = engine._store.GUIDForId(folder_id);
- _(`Folder GUID: ${folder_guid}`);
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- folder_id,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = engine._store.GUIDForId(fx_id);
- _(`Firefox GUID: ${fx_guid}`);
- let tb_id = PlacesUtils.bookmarks.insertBookmark(
- folder_id,
- Utils.makeURI("http://getthunderbird.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Thunderbird!");
- let tb_guid = engine._store.GUIDForId(tb_id);
- _(`Thunderbird GUID: ${tb_guid}`);
-
- yield startTracking();
-
- let txn = PlacesUtils.bookmarks.getRemoveFolderTransaction(folder_id);
- // We haven't executed the transaction yet.
- yield verifyTrackerEmpty();
-
- _("Execute the remove folder transaction");
- txn.doTransaction();
- yield verifyTrackedItems(["menu", folder_guid, fx_guid, tb_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 6);
- yield resetTracker();
-
- _("Undo the remove folder transaction");
- txn.undoTransaction();
-
- // At this point, the restored folder has the same ID, but a different GUID.
- let new_folder_guid = yield PlacesUtils.promiseItemGuid(folder_id);
-
- yield verifyTrackedItems(["menu", new_folder_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- yield resetTracker();
-
- _("Redo the transaction");
- txn.redoTransaction();
- yield verifyTrackedItems(["menu", new_folder_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_treeMoved() {
- _("Moving an entire tree of bookmarks should track the parents");
-
- try {
- // Create a couple of parent folders.
- let folder1_id = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- "First test folder",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folder1_guid = engine._store.GUIDForId(folder1_id);
-
- // A second folder in the first.
- let folder2_id = PlacesUtils.bookmarks.createFolder(
- folder1_id,
- "Second test folder",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folder2_guid = engine._store.GUIDForId(folder2_id);
-
- // Create a couple of bookmarks in the second folder.
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- folder2_id,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = engine._store.GUIDForId(fx_id);
- let tb_id = PlacesUtils.bookmarks.insertBookmark(
- folder2_id,
- Utils.makeURI("http://getthunderbird.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Thunderbird!");
- let tb_guid = engine._store.GUIDForId(tb_id);
-
- yield startTracking();
-
- // Move folder 2 to be a sibling of folder1.
- PlacesUtils.bookmarks.moveItem(
- folder2_id, PlacesUtils.bookmarks.bookmarksMenuFolder, 0);
- // the menu and both folders should be tracked, the children should not be.
- yield verifyTrackedItems(['menu', folder1_guid, folder2_guid]);
+ do_check_true(tracker.changedIDs['menu'] > 0);
+ do_check_true(tracker.changedIDs['toolbar'] > 0);
+ do_check_eq(tracker.changedIDs[fx_guid], undefined);
+ do_check_true(tracker.changedIDs[tb_guid] > 0);
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemDeleted() {
- _("Bookmarks deleted via the synchronous API should be tracked");
-
- try {
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = engine._store.GUIDForId(fx_id);
- let tb_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- Utils.makeURI("http://getthunderbird.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Thunderbird!");
- let tb_guid = engine._store.GUIDForId(tb_id);
-
- yield startTracking();
-
- // Delete the last item - the item and parent should be tracked.
- PlacesUtils.bookmarks.removeItem(tb_id);
-
- yield verifyTrackedItems(['menu', tb_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_async_onItemDeleted() {
- _("Bookmarks deleted via the asynchronous API should be tracked");
-
- try {
- yield stopTracking();
-
- let fxBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- let tbBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "http://getthunderbird.com",
- title: "Get Thunderbird!",
- });
-
- yield startTracking();
-
- _("Delete the first item");
- yield PlacesUtils.bookmarks.remove(fxBmk.guid);
- yield verifyTrackedItems(["menu", fxBmk.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
} finally {
_("Clean up.");
- yield cleanup();
+ store.wipe();
+ tracker.clearChangedIDs();
+ tracker.resetScore();
+ Svc.Obs.notify("weave:engine:stop-tracking");
}
-});
-
-add_task(function* test_async_onItemDeleted_eraseEverything() {
- _("Erasing everything should track all deleted items");
-
- try {
- yield stopTracking();
- let fxBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.mobileGuid,
- url: "http://getfirefox.com",
- title: "Get Firefox!",
- });
- _(`Firefox GUID: ${fxBmk.guid}`);
- let tbBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.mobileGuid,
- url: "http://getthunderbird.com",
- title: "Get Thunderbird!",
- });
- _(`Thunderbird GUID: ${tbBmk.guid}`);
- let mozBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "https://mozilla.org",
- title: "Mozilla",
- });
- _(`Mozilla GUID: ${mozBmk.guid}`);
- let mdnBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: PlacesUtils.bookmarks.menuGuid,
- url: "https://developer.mozilla.org",
- title: "MDN",
- });
- _(`MDN GUID: ${mdnBmk.guid}`);
- let bugsFolder = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_FOLDER,
- parentGuid: PlacesUtils.bookmarks.toolbarGuid,
- title: "Bugs",
- });
- _(`Bugs folder GUID: ${bugsFolder.guid}`);
- let bzBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: bugsFolder.guid,
- url: "https://bugzilla.mozilla.org",
- title: "Bugzilla",
- });
- _(`Bugzilla GUID: ${bzBmk.guid}`);
- let bugsChildFolder = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_FOLDER,
- parentGuid: bugsFolder.guid,
- title: "Bugs child",
- });
- _(`Bugs child GUID: ${bugsChildFolder.guid}`);
- let bugsGrandChildBmk = yield PlacesUtils.bookmarks.insert({
- type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
- parentGuid: bugsChildFolder.guid,
- url: "https://example.com",
- title: "Bugs grandchild",
- });
- _(`Bugs grandchild GUID: ${bugsGrandChildBmk.guid}`);
-
- yield startTracking();
-
- yield PlacesUtils.bookmarks.eraseEverything();
-
- // `eraseEverything` removes all items from the database before notifying
- // observers. Because of this, grandchild lookup in the tracker's
- // `onItemRemoved` observer will fail. That means we won't track
- // (bzBmk.guid, bugsGrandChildBmk.guid, bugsChildFolder.guid), even
- // though we should.
- yield verifyTrackedItems(["menu", mozBmk.guid, mdnBmk.guid, "toolbar",
- bugsFolder.guid, "mobile", fxBmk.guid,
- tbBmk.guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 10);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemDeleted_removeFolderChildren() {
- _("Removing a folder's children should track the folder and its children");
-
- try {
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.mobileFolderId,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = engine._store.GUIDForId(fx_id);
- _(`Firefox GUID: ${fx_guid}`);
-
- let tb_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.mobileFolderId,
- Utils.makeURI("http://getthunderbird.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Thunderbird!");
- let tb_guid = engine._store.GUIDForId(tb_id);
- _(`Thunderbird GUID: ${tb_guid}`);
-
- let moz_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- Utils.makeURI("https://mozilla.org"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Mozilla"
- );
- let moz_guid = engine._store.GUIDForId(moz_id);
- _(`Mozilla GUID: ${moz_guid}`);
-
- yield startTracking();
-
- _(`Mobile root ID: ${PlacesUtils.mobileFolderId}`);
- PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.mobileFolderId);
-
- yield verifyTrackedItems(["mobile", fx_guid, tb_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 4);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_onItemDeleted_tree() {
- _("Deleting a tree of bookmarks should track all items");
-
- try {
- // Create a couple of parent folders.
- let folder1_id = PlacesUtils.bookmarks.createFolder(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- "First test folder",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folder1_guid = engine._store.GUIDForId(folder1_id);
-
- // A second folder in the first.
- let folder2_id = PlacesUtils.bookmarks.createFolder(
- folder1_id,
- "Second test folder",
- PlacesUtils.bookmarks.DEFAULT_INDEX);
- let folder2_guid = engine._store.GUIDForId(folder2_id);
-
- // Create a couple of bookmarks in the second folder.
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- folder2_id,
- Utils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = engine._store.GUIDForId(fx_id);
- let tb_id = PlacesUtils.bookmarks.insertBookmark(
- folder2_id,
- Utils.makeURI("http://getthunderbird.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Thunderbird!");
- let tb_guid = engine._store.GUIDForId(tb_id);
-
- yield startTracking();
-
- // Delete folder2 - everything we created should be tracked.
- PlacesUtils.bookmarks.removeItem(folder2_id);
-
- yield verifyTrackedItems([fx_guid, tb_guid, folder1_guid, folder2_guid]);
- do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 6);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
-
-add_task(function* test_mobile_query() {
- _("Ensure we correctly create the mobile query");
-
- try {
- // Creates the organizer queries as a side effect.
- let leftPaneId = PlacesUIUtils.leftPaneFolderId;
- _(`Left pane root ID: ${leftPaneId}`);
-
- let allBookmarksIds = findAnnoItems("PlacesOrganizer/OrganizerQuery", "AllBookmarks");
- equal(allBookmarksIds.length, 1, "Should create folder with all bookmarks queries");
- let allBookmarkGuid = yield PlacesUtils.promiseItemGuid(allBookmarksIds[0]);
-
- _("Try creating query after organizer is ready");
- tracker._ensureMobileQuery();
- let queryIds = findAnnoItems("PlacesOrganizer/OrganizerQuery", "MobileBookmarks");
- equal(queryIds.length, 0, "Should not create query without any mobile bookmarks");
-
- _("Insert mobile bookmark, then create query");
- yield PlacesUtils.bookmarks.insert({
- parentGuid: PlacesUtils.bookmarks.mobileGuid,
- url: "https://mozilla.org",
- });
- tracker._ensureMobileQuery();
- queryIds = findAnnoItems("PlacesOrganizer/OrganizerQuery", "MobileBookmarks", {});
- equal(queryIds.length, 1, "Should create query once mobile bookmarks exist");
-
- let queryId = queryIds[0];
- let queryGuid = yield PlacesUtils.promiseItemGuid(queryId);
+}
- let queryInfo = yield PlacesUtils.bookmarks.fetch(queryGuid);
- equal(queryInfo.url, `place:folder=${PlacesUtils.mobileFolderId}`, "Query should point to mobile root");
- equal(queryInfo.title, "Mobile Bookmarks", "Query title should be localized");
- equal(queryInfo.parentGuid, allBookmarkGuid, "Should append mobile query to all bookmarks queries");
+function run_test() {
+ initTestLogging("Trace");
- _("Rename root and query, then recreate");
- yield PlacesUtils.bookmarks.update({
- guid: PlacesUtils.bookmarks.mobileGuid,
- title: "renamed root",
- });
- yield PlacesUtils.bookmarks.update({
- guid: queryGuid,
- title: "renamed query",
- });
- tracker._ensureMobileQuery();
- let rootInfo = yield PlacesUtils.bookmarks.fetch(PlacesUtils.bookmarks.mobileGuid);
- equal(rootInfo.title, "Mobile Bookmarks", "Should fix root title");
- queryInfo = yield PlacesUtils.bookmarks.fetch(queryGuid);
- equal(queryInfo.title, "Mobile Bookmarks", "Should fix query title");
+ Log.repository.getLogger("Sync.Engine.Bookmarks").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.Store.Bookmarks").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.Tracker.Bookmarks").level = Log.Level.Trace;
- _("Point query to different folder");
- yield PlacesUtils.bookmarks.update({
- guid: queryGuid,
- url: "place:folder=BOOKMARKS_MENU",
- });
- tracker._ensureMobileQuery();
- queryInfo = yield PlacesUtils.bookmarks.fetch(queryGuid);
- equal(queryInfo.url.href, `place:folder=${PlacesUtils.mobileFolderId}`,
- "Should fix query URL to point to mobile root");
+ test_tracking();
+ test_onItemChanged();
+ test_onItemMoved();
+}
- _("We shouldn't track the query or the left pane root");
- yield verifyTrackedCount(0);
- do_check_eq(tracker.score, 0);
- } finally {
- _("Clean up.");
- yield cleanup();
- }
-});
diff --git a/services/sync/tests/unit/test_bookmark_validator.js b/services/sync/tests/unit/test_bookmark_validator.js
deleted file mode 100644
index cc0b3b08f..000000000
--- a/services/sync/tests/unit/test_bookmark_validator.js
+++ /dev/null
@@ -1,347 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Components.utils.import("resource://services-sync/bookmark_validator.js");
-Components.utils.import("resource://services-sync/util.js");
-
-function inspectServerRecords(data) {
- return new BookmarkValidator().inspectServerRecords(data);
-}
-
-add_test(function test_isr_rootOnServer() {
- let c = inspectServerRecords([{
- id: 'places',
- type: 'folder',
- children: [],
- }]);
- ok(c.problemData.rootOnServer);
- run_next_test();
-});
-
-add_test(function test_isr_empty() {
- let c = inspectServerRecords([]);
- ok(!c.problemData.rootOnServer);
- notEqual(c.root, null);
- run_next_test();
-});
-
-add_test(function test_isr_cycles() {
- let c = inspectServerRecords([
- {id: 'C', type: 'folder', children: ['A', 'B'], parentid: 'places'},
- {id: 'A', type: 'folder', children: ['B'], parentid: 'B'},
- {id: 'B', type: 'folder', children: ['A'], parentid: 'A'},
- ]).problemData;
-
- equal(c.cycles.length, 1);
- ok(c.cycles[0].indexOf('A') >= 0);
- ok(c.cycles[0].indexOf('B') >= 0);
- run_next_test();
-});
-
-add_test(function test_isr_orphansMultiParents() {
- let c = inspectServerRecords([
- { id: 'A', type: 'bookmark', parentid: 'D' },
- { id: 'B', type: 'folder', parentid: 'places', children: ['A']},
- { id: 'C', type: 'folder', parentid: 'places', children: ['A']},
-
- ]).problemData;
- deepEqual(c.orphans, [{ id: "A", parent: "D" }]);
- equal(c.multipleParents.length, 1)
- ok(c.multipleParents[0].parents.indexOf('B') >= 0);
- ok(c.multipleParents[0].parents.indexOf('C') >= 0);
- run_next_test();
-});
-
-add_test(function test_isr_orphansMultiParents2() {
- let c = inspectServerRecords([
- { id: 'A', type: 'bookmark', parentid: 'D' },
- { id: 'B', type: 'folder', parentid: 'places', children: ['A']},
- ]).problemData;
- equal(c.orphans.length, 1);
- equal(c.orphans[0].id, 'A');
- equal(c.multipleParents.length, 0);
- run_next_test();
-});
-
-add_test(function test_isr_deletedParents() {
- let c = inspectServerRecords([
- { id: 'A', type: 'bookmark', parentid: 'B' },
- { id: 'B', type: 'folder', parentid: 'places', children: ['A']},
- { id: 'B', type: 'item', deleted: true},
- ]).problemData;
- deepEqual(c.deletedParents, ['A'])
- run_next_test();
-});
-
-add_test(function test_isr_badChildren() {
- let c = inspectServerRecords([
- { id: 'A', type: 'bookmark', parentid: 'places', children: ['B', 'C'] },
- { id: 'C', type: 'bookmark', parentid: 'A' }
- ]).problemData;
- deepEqual(c.childrenOnNonFolder, ['A'])
- deepEqual(c.missingChildren, [{parent: 'A', child: 'B'}]);
- deepEqual(c.parentNotFolder, ['C']);
- run_next_test();
-});
-
-
-add_test(function test_isr_parentChildMismatches() {
- let c = inspectServerRecords([
- { id: 'A', type: 'folder', parentid: 'places', children: [] },
- { id: 'B', type: 'bookmark', parentid: 'A' }
- ]).problemData;
- deepEqual(c.parentChildMismatches, [{parent: 'A', child: 'B'}]);
- run_next_test();
-});
-
-add_test(function test_isr_duplicatesAndMissingIDs() {
- let c = inspectServerRecords([
- {id: 'A', type: 'folder', parentid: 'places', children: []},
- {id: 'A', type: 'folder', parentid: 'places', children: []},
- {type: 'folder', parentid: 'places', children: []}
- ]).problemData;
- equal(c.missingIDs, 1);
- deepEqual(c.duplicates, ['A']);
- run_next_test();
-});
-
-add_test(function test_isr_duplicateChildren() {
- let c = inspectServerRecords([
- {id: 'A', type: 'folder', parentid: 'places', children: ['B', 'B']},
- {id: 'B', type: 'bookmark', parentid: 'A'},
- ]).problemData;
- deepEqual(c.duplicateChildren, ['A']);
- run_next_test();
-});
-
-// Each compareServerWithClient test mutates these, so we can't just keep them
-// global
-function getDummyServerAndClient() {
- let server = [
- {
- id: 'menu',
- parentid: 'places',
- type: 'folder',
- parentName: '',
- title: 'foo',
- children: ['bbbbbbbbbbbb', 'cccccccccccc']
- },
- {
- id: 'bbbbbbbbbbbb',
- type: 'bookmark',
- parentid: 'menu',
- parentName: 'foo',
- title: 'bar',
- bmkUri: 'http://baz.com'
- },
- {
- id: 'cccccccccccc',
- parentid: 'menu',
- parentName: 'foo',
- title: '',
- type: 'query',
- bmkUri: 'place:type=6&sort=14&maxResults=10'
- }
- ];
-
- let client = {
- "guid": "root________",
- "title": "",
- "id": 1,
- "type": "text/x-moz-place-container",
- "children": [
- {
- "guid": "menu________",
- "title": "foo",
- "id": 1000,
- "type": "text/x-moz-place-container",
- "children": [
- {
- "guid": "bbbbbbbbbbbb",
- "title": "bar",
- "id": 1001,
- "type": "text/x-moz-place",
- "uri": "http://baz.com"
- },
- {
- "guid": "cccccccccccc",
- "title": "",
- "id": 1002,
- "annos": [{
- "name": "Places/SmartBookmark",
- "flags": 0,
- "expires": 4,
- "value": "RecentTags"
- }],
- "type": "text/x-moz-place",
- "uri": "place:type=6&sort=14&maxResults=10"
- }
- ]
- }
- ]
- };
- return {server, client};
-}
-
-
-add_test(function test_cswc_valid() {
- let {server, client} = getDummyServerAndClient();
-
- let c = new BookmarkValidator().compareServerWithClient(server, client).problemData;
- equal(c.clientMissing.length, 0);
- equal(c.serverMissing.length, 0);
- equal(c.differences.length, 0);
- run_next_test();
-});
-
-add_test(function test_cswc_serverMissing() {
- let {server, client} = getDummyServerAndClient();
- // remove c
- server.pop();
- server[0].children.pop();
-
- let c = new BookmarkValidator().compareServerWithClient(server, client).problemData;
- deepEqual(c.serverMissing, ['cccccccccccc']);
- equal(c.clientMissing.length, 0);
- deepEqual(c.structuralDifferences, [{id: 'menu', differences: ['childGUIDs']}]);
- run_next_test();
-});
-
-add_test(function test_cswc_clientMissing() {
- let {server, client} = getDummyServerAndClient();
- client.children[0].children.pop();
-
- let c = new BookmarkValidator().compareServerWithClient(server, client).problemData;
- deepEqual(c.clientMissing, ['cccccccccccc']);
- equal(c.serverMissing.length, 0);
- deepEqual(c.structuralDifferences, [{id: 'menu', differences: ['childGUIDs']}]);
- run_next_test();
-});
-
-add_test(function test_cswc_differences() {
- {
- let {server, client} = getDummyServerAndClient();
- client.children[0].children[0].title = 'asdf';
- let c = new BookmarkValidator().compareServerWithClient(server, client).problemData;
- equal(c.clientMissing.length, 0);
- equal(c.serverMissing.length, 0);
- deepEqual(c.differences, [{id: 'bbbbbbbbbbbb', differences: ['title']}]);
- }
-
- {
- let {server, client} = getDummyServerAndClient();
- server[2].type = 'bookmark';
- let c = new BookmarkValidator().compareServerWithClient(server, client).problemData;
- equal(c.clientMissing.length, 0);
- equal(c.serverMissing.length, 0);
- deepEqual(c.differences, [{id: 'cccccccccccc', differences: ['type']}]);
- }
- run_next_test();
-});
-
-add_test(function test_cswc_serverUnexpected() {
- let {server, client} = getDummyServerAndClient();
- client.children.push({
- "guid": "dddddddddddd",
- "title": "",
- "id": 2000,
- "annos": [{
- "name": "places/excludeFromBackup",
- "flags": 0,
- "expires": 4,
- "value": 1
- }, {
- "name": "PlacesOrganizer/OrganizerFolder",
- "flags": 0,
- "expires": 4,
- "value": 7
- }],
- "type": "text/x-moz-place-container",
- "children": [{
- "guid": "eeeeeeeeeeee",
- "title": "History",
- "annos": [{
- "name": "places/excludeFromBackup",
- "flags": 0,
- "expires": 4,
- "value": 1
- }, {
- "name": "PlacesOrganizer/OrganizerQuery",
- "flags": 0,
- "expires": 4,
- "value": "History"
- }],
- "type": "text/x-moz-place",
- "uri": "place:type=3&sort=4"
- }]
- });
- server.push({
- id: 'dddddddddddd',
- parentid: 'places',
- parentName: '',
- title: '',
- type: 'folder',
- children: ['eeeeeeeeeeee']
- }, {
- id: 'eeeeeeeeeeee',
- parentid: 'dddddddddddd',
- parentName: '',
- title: 'History',
- type: 'query',
- bmkUri: 'place:type=3&sort=4'
- });
-
- let c = new BookmarkValidator().compareServerWithClient(server, client).problemData;
- equal(c.clientMissing.length, 0);
- equal(c.serverMissing.length, 0);
- equal(c.serverUnexpected.length, 2);
- deepEqual(c.serverUnexpected, ["dddddddddddd", "eeeeeeeeeeee"]);
- run_next_test();
-});
-
-function validationPing(server, client, duration) {
- return wait_for_ping(function() {
- // fake this entirely
- Svc.Obs.notify("weave:service:sync:start");
- Svc.Obs.notify("weave:engine:sync:start", null, "bookmarks");
- Svc.Obs.notify("weave:engine:sync:finish", null, "bookmarks");
- let validator = new BookmarkValidator();
- let data = {
- // We fake duration and version just so that we can verify they're passed through.
- duration,
- version: validator.version,
- recordCount: server.length,
- problems: validator.compareServerWithClient(server, client).problemData,
- };
- Svc.Obs.notify("weave:engine:validate:finish", data, "bookmarks");
- Svc.Obs.notify("weave:service:sync:finish");
- }, true); // Allow "failing" pings, since having validation info indicates failure.
-}
-
-add_task(function *test_telemetry_integration() {
- let {server, client} = getDummyServerAndClient();
- // remove "c"
- server.pop();
- server[0].children.pop();
- const duration = 50;
- let ping = yield validationPing(server, client, duration);
- ok(ping.engines);
- let bme = ping.engines.find(e => e.name === "bookmarks");
- ok(bme);
- ok(bme.validation);
- ok(bme.validation.problems)
- equal(bme.validation.checked, server.length);
- equal(bme.validation.took, duration);
- bme.validation.problems.sort((a, b) => String.localeCompare(a.name, b.name));
- equal(bme.validation.version, new BookmarkValidator().version);
- deepEqual(bme.validation.problems, [
- { name: "badClientRoots", count: 3 },
- { name: "sdiff:childGUIDs", count: 1 },
- { name: "serverMissing", count: 1 },
- { name: "structuralDifferences", count: 1 },
- ]);
-});
-
-function run_test() {
- run_next_test();
-}
diff --git a/services/sync/tests/unit/test_browserid_identity.js b/services/sync/tests/unit/test_browserid_identity.js
index 531c01bf6..f3cde9f8f 100644
--- a/services/sync/tests/unit/test_browserid_identity.js
+++ b/services/sync/tests/unit/test_browserid_identity.js
@@ -16,14 +16,13 @@ Cu.import("resource://gre/modules/FxAccountsCommon.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/status.js");
Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-common/tokenserverclient.js");
const SECOND_MS = 1000;
const MINUTE_MS = SECOND_MS * 60;
const HOUR_MS = MINUTE_MS * 60;
-var identityConfig = makeIdentityConfig();
-var browseridManager = new BrowserIDManager();
+let identityConfig = makeIdentityConfig();
+let browseridManager = new BrowserIDManager();
configureFxAccountIdentity(browseridManager, identityConfig);
/**
@@ -32,14 +31,11 @@ configureFxAccountIdentity(browseridManager, identityConfig);
* headers. We will use this to test clock skew compensation in these headers
* below.
*/
-var MockFxAccountsClient = function() {
+let MockFxAccountsClient = function() {
FxAccountsClient.apply(this);
};
MockFxAccountsClient.prototype = {
- __proto__: FxAccountsClient.prototype,
- accountStatus() {
- return Promise.resolve(true);
- }
+ __proto__: FxAccountsClient.prototype
};
function MockFxAccounts() {
@@ -77,7 +73,7 @@ add_test(function test_initial_state() {
}
);
-add_task(function* test_initialializeWithCurrentIdentity() {
+add_task(function test_initialializeWithCurrentIdentity() {
_("Verify start after initializeWithCurrentIdentity");
browseridManager.initializeWithCurrentIdentity();
yield browseridManager.whenReadyToAuthenticate.promise;
@@ -87,57 +83,7 @@ add_task(function* test_initialializeWithCurrentIdentity() {
}
);
-add_task(function* test_initialializeWithAuthErrorAndDeletedAccount() {
- _("Verify sync unpair after initializeWithCurrentIdentity with auth error + account deleted");
-
- var identityConfig = makeIdentityConfig();
- var browseridManager = new BrowserIDManager();
-
- // Use the real `_getAssertion` method that calls
- // `mockFxAClient.signCertificate`.
- let fxaInternal = makeFxAccountsInternalMock(identityConfig);
- delete fxaInternal._getAssertion;
-
- configureFxAccountIdentity(browseridManager, identityConfig, fxaInternal);
- browseridManager._fxaService.internal.initialize();
-
- let signCertificateCalled = false;
- let accountStatusCalled = false;
-
- let MockFxAccountsClient = function() {
- FxAccountsClient.apply(this);
- };
- MockFxAccountsClient.prototype = {
- __proto__: FxAccountsClient.prototype,
- signCertificate() {
- signCertificateCalled = true;
- return Promise.reject({
- code: 401,
- errno: ERRNO_INVALID_AUTH_TOKEN,
- });
- },
- accountStatus() {
- accountStatusCalled = true;
- return Promise.resolve(false);
- }
- };
-
- let mockFxAClient = new MockFxAccountsClient();
- browseridManager._fxaService.internal._fxAccountsClient = mockFxAClient;
-
- yield browseridManager.initializeWithCurrentIdentity();
- yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise,
- "should reject due to an auth error");
-
- do_check_true(signCertificateCalled);
- do_check_true(accountStatusCalled);
- do_check_false(browseridManager.account);
- do_check_false(browseridManager._token);
- do_check_false(browseridManager.hasValidToken());
- do_check_false(browseridManager.account);
-});
-
-add_task(function* test_initialializeWithNoKeys() {
+add_task(function test_initialializeWithNoKeys() {
_("Verify start after initializeWithCurrentIdentity without kA, kB or keyFetchToken");
let identityConfig = makeIdentityConfig();
delete identityConfig.fxaccount.user.kA;
@@ -306,7 +252,7 @@ add_test(function test_RESTResourceAuthenticatorSkew() {
run_next_test();
});
-add_task(function* test_ensureLoggedIn() {
+add_task(function test_ensureLoggedIn() {
configureFxAccountIdentity(browseridManager);
yield browseridManager.initializeWithCurrentIdentity();
yield browseridManager.whenReadyToAuthenticate.promise;
@@ -318,8 +264,8 @@ add_task(function* test_ensureLoggedIn() {
// arrange for no logged in user.
let fxa = browseridManager._fxaService
- let signedInUser = fxa.internal.currentAccountState.storageManager.accountData;
- fxa.internal.currentAccountState.storageManager.accountData = null;
+ let signedInUser = fxa.internal.currentAccountState.signedInUser;
+ fxa.internal.currentAccountState.signedInUser = null;
browseridManager.initializeWithCurrentIdentity();
Assert.ok(!browseridManager._shouldHaveSyncKeyBundle,
"_shouldHaveSyncKeyBundle should be false so we know we are testing what we think we are.");
@@ -327,8 +273,7 @@ add_task(function* test_ensureLoggedIn() {
yield Assert.rejects(browseridManager.ensureLoggedIn(), "expecting rejection due to no user");
Assert.ok(browseridManager._shouldHaveSyncKeyBundle,
"_shouldHaveSyncKeyBundle should always be true after ensureLogin completes.");
- // Restore the logged in user to what it was.
- fxa.internal.currentAccountState.storageManager.accountData = signedInUser;
+ fxa.internal.currentAccountState.signedInUser = signedInUser;
Status.login = LOGIN_FAILED_LOGIN_REJECTED;
yield Assert.rejects(browseridManager.ensureLoggedIn(),
"LOGIN_FAILED_LOGIN_REJECTED should have caused immediate rejection");
@@ -404,7 +349,7 @@ add_test(function test_computeXClientStateHeader() {
run_next_test();
});
-add_task(function* test_getTokenErrors() {
+add_task(function test_getTokenErrors() {
_("BrowserIDManager correctly handles various failures to get a token.");
_("Arrange for a 401 - Sync should reflect an auth error.");
@@ -437,75 +382,7 @@ add_task(function* test_getTokenErrors() {
Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login state is LOGIN_FAILED_NETWORK_ERROR");
});
-add_task(function* test_refreshCertificateOn401() {
- _("BrowserIDManager refreshes the FXA certificate after a 401.");
- var identityConfig = makeIdentityConfig();
- var browseridManager = new BrowserIDManager();
- // Use the real `_getAssertion` method that calls
- // `mockFxAClient.signCertificate`.
- let fxaInternal = makeFxAccountsInternalMock(identityConfig);
- delete fxaInternal._getAssertion;
- configureFxAccountIdentity(browseridManager, identityConfig, fxaInternal);
- browseridManager._fxaService.internal.initialize();
-
- let getCertCount = 0;
-
- let MockFxAccountsClient = function() {
- FxAccountsClient.apply(this);
- };
- MockFxAccountsClient.prototype = {
- __proto__: FxAccountsClient.prototype,
- signCertificate() {
- ++getCertCount;
- }
- };
-
- let mockFxAClient = new MockFxAccountsClient();
- browseridManager._fxaService.internal._fxAccountsClient = mockFxAClient;
-
- let didReturn401 = false;
- let didReturn200 = false;
- let mockTSC = mockTokenServer(() => {
- if (getCertCount <= 1) {
- didReturn401 = true;
- return {
- status: 401,
- headers: {"content-type": "application/json"},
- body: JSON.stringify({}),
- };
- } else {
- didReturn200 = true;
- return {
- status: 200,
- headers: {"content-type": "application/json"},
- body: JSON.stringify({
- id: "id",
- key: "key",
- api_endpoint: "http://example.com/",
- uid: "uid",
- duration: 300,
- })
- };
- }
- });
-
- browseridManager._tokenServerClient = mockTSC;
-
- yield browseridManager.initializeWithCurrentIdentity();
- yield browseridManager.whenReadyToAuthenticate.promise;
-
- do_check_eq(getCertCount, 2);
- do_check_true(didReturn401);
- do_check_true(didReturn200);
- do_check_true(browseridManager.account);
- do_check_true(browseridManager._token);
- do_check_true(browseridManager.hasValidToken());
- do_check_true(browseridManager.account);
-});
-
-
-
-add_task(function* test_getTokenErrorWithRetry() {
+add_task(function test_getTokenErrorWithRetry() {
_("tokenserver sends an observer notification on various backoff headers.");
// Set Sync's backoffInterval to zero - after we simulated the backoff header
@@ -547,7 +424,7 @@ add_task(function* test_getTokenErrorWithRetry() {
Assert.ok(Status.backoffInterval >= 200000);
});
-add_task(function* test_getKeysErrorWithBackoff() {
+add_task(function test_getKeysErrorWithBackoff() {
_("Auth server (via hawk) sends an observer notification on backoff headers.");
// Set Sync's backoffInterval to zero - after we simulated the backoff header
@@ -581,7 +458,7 @@ add_task(function* test_getKeysErrorWithBackoff() {
Assert.ok(Status.backoffInterval >= 100000);
});
-add_task(function* test_getKeysErrorWithRetry() {
+add_task(function test_getKeysErrorWithRetry() {
_("Auth server (via hawk) sends an observer notification on retry headers.");
// Set Sync's backoffInterval to zero - after we simulated the backoff header
@@ -615,7 +492,7 @@ add_task(function* test_getKeysErrorWithRetry() {
Assert.ok(Status.backoffInterval >= 100000);
});
-add_task(function* test_getHAWKErrors() {
+add_task(function test_getHAWKErrors() {
_("BrowserIDManager correctly handles various HAWK failures.");
_("Arrange for a 401 - Sync should reflect an auth error.");
@@ -648,7 +525,7 @@ add_task(function* test_getHAWKErrors() {
Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login state is LOGIN_FAILED_NETWORK_ERROR");
});
-add_task(function* test_getGetKeysFailing401() {
+add_task(function test_getGetKeysFailing401() {
_("BrowserIDManager correctly handles 401 responses fetching keys.");
_("Arrange for a 401 - Sync should reflect an auth error.");
@@ -669,7 +546,7 @@ add_task(function* test_getGetKeysFailing401() {
Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED, "login was rejected");
});
-add_task(function* test_getGetKeysFailing503() {
+add_task(function test_getGetKeysFailing503() {
_("BrowserIDManager correctly handles 5XX responses fetching keys.");
_("Arrange for a 503 - Sync should reflect a network error.");
@@ -690,7 +567,7 @@ add_task(function* test_getGetKeysFailing503() {
Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "state reflects network error");
});
-add_task(function* test_getKeysMissing() {
+add_task(function test_getKeysMissing() {
_("BrowserIDManager correctly handles getKeys succeeding but not returning keys.");
let browseridManager = new BrowserIDManager();
@@ -708,17 +585,7 @@ add_task(function* test_getKeysMissing() {
fetchAndUnwrapKeys: function () {
return Promise.resolve({});
},
- fxAccountsClient: new MockFxAccountsClient(),
- newAccountState(credentials) {
- // We only expect this to be called with null indicating the (mock)
- // storage should be read.
- if (credentials) {
- throw new Error("Not expecting to have credentials passed");
- }
- let storageManager = new MockFxaStorageManager();
- storageManager.initialize(identityConfig.fxaccount.user);
- return new AccountState(storageManager);
- },
+ fxAccountsClient: new MockFxAccountsClient()
});
// Add a mock to the currentAccountState object.
@@ -730,6 +597,9 @@ add_task(function* test_getKeysMissing() {
return Promise.resolve(this.cert.cert);
};
+ // Ensure the new FxAccounts mock has a signed-in user.
+ fxa.internal.currentAccountState.signedInUser = browseridManager._fxaService.internal.currentAccountState.signedInUser;
+
browseridManager._fxaService = fxa;
yield browseridManager.initializeWithCurrentIdentity();
@@ -744,41 +614,6 @@ add_task(function* test_getKeysMissing() {
Assert.ok(ex.message.indexOf("missing kA or kB") >= 0);
});
-add_task(function* test_signedInUserMissing() {
- _("BrowserIDManager detects getSignedInUser returning incomplete account data");
-
- let browseridManager = new BrowserIDManager();
- let config = makeIdentityConfig();
- // Delete stored keys and the key fetch token.
- delete identityConfig.fxaccount.user.kA;
- delete identityConfig.fxaccount.user.kB;
- delete identityConfig.fxaccount.user.keyFetchToken;
-
- configureFxAccountIdentity(browseridManager, identityConfig);
-
- let fxa = new FxAccounts({
- fetchAndUnwrapKeys: function () {
- return Promise.resolve({});
- },
- fxAccountsClient: new MockFxAccountsClient(),
- newAccountState(credentials) {
- // We only expect this to be called with null indicating the (mock)
- // storage should be read.
- if (credentials) {
- throw new Error("Not expecting to have credentials passed");
- }
- let storageManager = new MockFxaStorageManager();
- storageManager.initialize(identityConfig.fxaccount.user);
- return new AccountState(storageManager);
- },
- });
-
- browseridManager._fxaService = fxa;
-
- let status = yield browseridManager.unlockAndVerifyAuthState();
- Assert.equal(status, LOGIN_FAILED_LOGIN_REJECTED);
-});
-
// End of tests
// Utility functions follow
@@ -803,17 +638,7 @@ function* initializeIdentityWithHAWKResponseFactory(config, cbGetResponse) {
callback.call(this);
},
get: function(callback) {
- // Skip /status requests (browserid_identity checks if the account still
- // exists after an auth error)
- if (this._uri.startsWith("http://mockedserver:9999/account/status")) {
- this.response = {
- status: 200,
- headers: {"content-type": "application/json"},
- body: JSON.stringify({exists: true}),
- };
- } else {
- this.response = cbGetResponse("get", null, this._uri, this._credentials, this._extra);
- }
+ this.response = cbGetResponse("get", null, this._uri, this._credentials, this._extra);
callback.call(this);
}
}
@@ -833,18 +658,11 @@ function* initializeIdentityWithHAWKResponseFactory(config, cbGetResponse) {
fxaClient.hawk = new MockedHawkClient();
let internal = {
fxAccountsClient: fxaClient,
- newAccountState(credentials) {
- // We only expect this to be called with null indicating the (mock)
- // storage should be read.
- if (credentials) {
- throw new Error("Not expecting to have credentials passed");
- }
- let storageManager = new MockFxaStorageManager();
- storageManager.initialize(config.fxaccount.user);
- return new AccountState(storageManager);
- },
}
let fxa = new FxAccounts(internal);
+ fxa.internal.currentAccountState.signedInUser = {
+ accountData: config.fxaccount.user,
+ };
browseridManager._fxaService = fxa;
browseridManager._signedInUser = null;
@@ -862,29 +680,3 @@ function getTimestampDelta(hawkAuthHeader, now=Date.now()) {
return Math.abs(getTimestamp(hawkAuthHeader) - now);
}
-function mockTokenServer(func) {
- let requestLog = Log.repository.getLogger("testing.mock-rest");
- if (!requestLog.appenders.length) { // might as well see what it says :)
- requestLog.addAppender(new Log.DumpAppender());
- requestLog.level = Log.Level.Trace;
- }
- function MockRESTRequest(url) {};
- MockRESTRequest.prototype = {
- _log: requestLog,
- setHeader: function() {},
- get: function(callback) {
- this.response = func();
- callback.call(this);
- }
- }
- // The mocked TokenServer client which will get the response.
- function MockTSC() { }
- MockTSC.prototype = new TokenServerClient();
- MockTSC.prototype.constructor = MockTSC;
- MockTSC.prototype.newRESTRequest = function(url) {
- return new MockRESTRequest(url);
- }
- // Arrange for the same observerPrefix as browserid_identity uses.
- MockTSC.prototype.observerPrefix = "weave:service";
- return new MockTSC();
-}
diff --git a/services/sync/tests/unit/test_clients_engine.js b/services/sync/tests/unit/test_clients_engine.js
index d2123f80a..919913f82 100644
--- a/services/sync/tests/unit/test_clients_engine.js
+++ b/services/sync/tests/unit/test_clients_engine.js
@@ -12,7 +12,7 @@ Cu.import("resource://testing-common/services/sync/utils.js");
const MORE_THAN_CLIENTS_TTL_REFRESH = 691200; // 8 days
const LESS_THAN_CLIENTS_TTL_REFRESH = 86400; // 1 day
-var engine = Service.clientsEngine;
+let engine = Service.clientsEngine;
/**
* Unpack the record with this ID, and verify that it has the same version that
@@ -31,10 +31,10 @@ function check_record_version(user, id) {
let cleartext = rec.decrypt(Service.collectionKeys.keyForCollection("clients"));
_("Payload is " + JSON.stringify(cleartext));
- equal(Services.appinfo.version, cleartext.version);
- equal(2, cleartext.protocols.length);
- equal("1.1", cleartext.protocols[0]);
- equal("1.5", cleartext.protocols[1]);
+ do_check_eq(Services.appinfo.version, cleartext.version);
+ do_check_eq(2, cleartext.protocols.length);
+ do_check_eq("1.1", cleartext.protocols[0]);
+ do_check_eq("1.5", cleartext.protocols[1]);
}
add_test(function test_bad_hmac() {
@@ -64,7 +64,7 @@ add_test(function test_bad_hmac() {
let coll = user.collection("clients");
// Treat a non-existent collection as empty.
- equal(expectedCount, coll ? coll.count() : 0, stack);
+ do_check_eq(expectedCount, coll ? coll.count() : 0, stack);
}
function check_client_deleted(id) {
@@ -77,7 +77,7 @@ add_test(function test_bad_hmac() {
generateNewKeys(Service.collectionKeys);
let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
serverKeys.encrypt(Service.identity.syncKeyBundle);
- ok(serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success);
+ do_check_true(serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success);
}
try {
@@ -89,11 +89,11 @@ add_test(function test_bad_hmac() {
generateNewKeys(Service.collectionKeys);
_("First sync, client record is uploaded");
- equal(engine.lastRecordUpload, 0);
+ do_check_eq(engine.lastRecordUpload, 0);
check_clients_count(0);
engine._sync();
check_clients_count(1);
- ok(engine.lastRecordUpload > 0);
+ do_check_true(engine.lastRecordUpload > 0);
// Our uploaded record has a version.
check_record_version(user, engine.localID);
@@ -109,7 +109,7 @@ add_test(function test_bad_hmac() {
generateNewKeys(Service.collectionKeys);
let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
serverKeys.encrypt(Service.identity.syncKeyBundle);
- ok(serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success);
+ do_check_true(serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success);
_("Sync.");
engine._sync();
@@ -130,8 +130,8 @@ add_test(function test_bad_hmac() {
engine._sync();
_("Old record was not deleted, new one uploaded.");
- equal(deletedCollections.length, 0);
- equal(deletedItems.length, 0);
+ do_check_eq(deletedCollections.length, 0);
+ do_check_eq(deletedItems.length, 0);
check_clients_count(2);
_("Now try the scenario where our keys are wrong *and* there's a bad record.");
@@ -162,14 +162,14 @@ add_test(function test_bad_hmac() {
generateNewKeys(Service.collectionKeys);
let oldKey = Service.collectionKeys.keyForCollection();
- equal(deletedCollections.length, 0);
- equal(deletedItems.length, 0);
+ do_check_eq(deletedCollections.length, 0);
+ do_check_eq(deletedItems.length, 0);
engine._sync();
- equal(deletedItems.length, 1);
+ do_check_eq(deletedItems.length, 1);
check_client_deleted(oldLocalID);
check_clients_count(1);
let newKey = Service.collectionKeys.keyForCollection();
- ok(!oldKey.equals(newKey));
+ do_check_false(oldKey.equals(newKey));
} finally {
Svc.Prefs.resetBranch("");
@@ -181,91 +181,18 @@ add_test(function test_bad_hmac() {
add_test(function test_properties() {
_("Test lastRecordUpload property");
try {
- equal(Svc.Prefs.get("clients.lastRecordUpload"), undefined);
- equal(engine.lastRecordUpload, 0);
+ do_check_eq(Svc.Prefs.get("clients.lastRecordUpload"), undefined);
+ do_check_eq(engine.lastRecordUpload, 0);
let now = Date.now();
engine.lastRecordUpload = now / 1000;
- equal(engine.lastRecordUpload, Math.floor(now / 1000));
+ do_check_eq(engine.lastRecordUpload, Math.floor(now / 1000));
} finally {
Svc.Prefs.resetBranch("");
run_next_test();
}
});
-add_test(function test_full_sync() {
- _("Ensure that Clients engine fetches all records for each sync.");
-
- let now = Date.now() / 1000;
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- let user = server.user("foo");
-
- new SyncTestingInfrastructure(server.server);
- generateNewKeys(Service.collectionKeys);
-
- let activeID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(activeID, encryptPayload({
- id: activeID,
- name: "Active client",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- let deletedID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(deletedID, encryptPayload({
- id: deletedID,
- name: "Client to delete",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- try {
- let store = engine._store;
-
- _("First sync. 2 records downloaded; our record uploaded.");
- strictEqual(engine.lastRecordUpload, 0);
- engine._sync();
- ok(engine.lastRecordUpload > 0);
- deepEqual(user.collection("clients").keys().sort(),
- [activeID, deletedID, engine.localID].sort(),
- "Our record should be uploaded on first sync");
- deepEqual(Object.keys(store.getAllIDs()).sort(),
- [activeID, deletedID, engine.localID].sort(),
- "Other clients should be downloaded on first sync");
-
- _("Delete a record, then sync again");
- let collection = server.getCollection("foo", "clients");
- collection.remove(deletedID);
- // Simulate a timestamp update in info/collections.
- engine.lastModified = now;
- engine._sync();
-
- _("Record should be updated");
- deepEqual(Object.keys(store.getAllIDs()).sort(),
- [activeID, engine.localID].sort(),
- "Deleted client should be removed on next sync");
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
-});
-
add_test(function test_sync() {
_("Ensure that Clients engine uploads a new client record once a week.");
@@ -288,30 +215,30 @@ add_test(function test_sync() {
try {
_("First sync. Client record is uploaded.");
- equal(clientWBO(), undefined);
- equal(engine.lastRecordUpload, 0);
+ do_check_eq(clientWBO(), undefined);
+ do_check_eq(engine.lastRecordUpload, 0);
engine._sync();
- ok(!!clientWBO().payload);
- ok(engine.lastRecordUpload > 0);
+ do_check_true(!!clientWBO().payload);
+ do_check_true(engine.lastRecordUpload > 0);
_("Let's time travel more than a week back, new record should've been uploaded.");
engine.lastRecordUpload -= MORE_THAN_CLIENTS_TTL_REFRESH;
let lastweek = engine.lastRecordUpload;
clientWBO().payload = undefined;
engine._sync();
- ok(!!clientWBO().payload);
- ok(engine.lastRecordUpload > lastweek);
+ do_check_true(!!clientWBO().payload);
+ do_check_true(engine.lastRecordUpload > lastweek);
_("Remove client record.");
engine.removeClientData();
- equal(clientWBO().payload, undefined);
+ do_check_eq(clientWBO().payload, undefined);
_("Time travel one day back, no record uploaded.");
engine.lastRecordUpload -= LESS_THAN_CLIENTS_TTL_REFRESH;
let yesterday = engine.lastRecordUpload;
engine._sync();
- equal(clientWBO().payload, undefined);
- equal(engine.lastRecordUpload, yesterday);
+ do_check_eq(clientWBO().payload, undefined);
+ do_check_eq(engine.lastRecordUpload, yesterday);
} finally {
Svc.Prefs.resetBranch("");
@@ -336,16 +263,16 @@ add_test(function test_client_name_change() {
let initialScore = tracker.score;
- equal(Object.keys(tracker.changedIDs).length, 0);
+ do_check_eq(Object.keys(tracker.changedIDs).length, 0);
Svc.Prefs.set("client.name", "new name");
_("new name: " + engine.localName);
- notEqual(initialName, engine.localName);
- equal(Object.keys(tracker.changedIDs).length, 1);
- ok(engine.localID in tracker.changedIDs);
- ok(tracker.score > initialScore);
- ok(tracker.score >= SCORE_INCREMENT_XLARGE);
+ do_check_neq(initialName, engine.localName);
+ do_check_eq(Object.keys(tracker.changedIDs).length, 1);
+ do_check_true(engine.localID in tracker.changedIDs);
+ do_check_true(tracker.score > initialScore);
+ do_check_true(tracker.score >= SCORE_INCREMENT_XLARGE);
Svc.Obs.notify("weave:engine:stop-tracking");
@@ -369,16 +296,15 @@ add_test(function test_send_command() {
engine._sendCommandToClient(action, args, remoteId);
let newRecord = store._remoteClients[remoteId];
- let clientCommands = engine._readCommands()[remoteId];
- notEqual(newRecord, undefined);
- equal(clientCommands.length, 1);
+ do_check_neq(newRecord, undefined);
+ do_check_eq(newRecord.commands.length, 1);
- let command = clientCommands[0];
- equal(command.command, action);
- equal(command.args.length, 2);
- deepEqual(command.args, args);
+ let command = newRecord.commands[0];
+ do_check_eq(command.command, action);
+ do_check_eq(command.args.length, 2);
+ do_check_eq(command.args, args);
- notEqual(tracker.changedIDs[remoteId], undefined);
+ do_check_neq(tracker.changedIDs[remoteId], undefined);
run_next_test();
});
@@ -402,7 +328,7 @@ add_test(function test_command_validation() {
["__UNKNOWN__", [], false]
];
- for (let [action, args, expectedResult] of testCommands) {
+ for each (let [action, args, expectedResult] in testCommands) {
let remoteId = Utils.makeGUID();
let rec = new ClientsRec("clients", remoteId);
@@ -412,26 +338,24 @@ add_test(function test_command_validation() {
engine.sendCommand(action, args, remoteId);
let newRecord = store._remoteClients[remoteId];
- notEqual(newRecord, undefined);
-
- let clientCommands = engine._readCommands()[remoteId];
+ do_check_neq(newRecord, undefined);
if (expectedResult) {
_("Ensuring command is sent: " + action);
- equal(clientCommands.length, 1);
+ do_check_eq(newRecord.commands.length, 1);
- let command = clientCommands[0];
- equal(command.command, action);
- deepEqual(command.args, args);
+ let command = newRecord.commands[0];
+ do_check_eq(command.command, action);
+ do_check_eq(command.args, args);
- notEqual(engine._tracker, undefined);
- notEqual(engine._tracker.changedIDs[remoteId], undefined);
+ do_check_neq(engine._tracker, undefined);
+ do_check_neq(engine._tracker.changedIDs[remoteId], undefined);
} else {
_("Ensuring command is scrubbed: " + action);
- equal(clientCommands, undefined);
+ do_check_eq(newRecord.commands, undefined);
if (store._tracker) {
- equal(engine._tracker[remoteId], undefined);
+ do_check_eq(engine._tracker[remoteId], undefined);
}
}
@@ -455,11 +379,10 @@ add_test(function test_command_duplication() {
engine.sendCommand(action, args, remoteId);
let newRecord = store._remoteClients[remoteId];
- let clientCommands = engine._readCommands()[remoteId];
- equal(clientCommands.length, 1);
+ do_check_eq(newRecord.commands.length, 1);
_("Check variant args length");
- engine._saveCommands({});
+ newRecord.commands = [];
action = "resetEngine";
engine.sendCommand(action, [{ x: "foo" }], remoteId);
@@ -468,8 +391,7 @@ add_test(function test_command_duplication() {
_("Make sure we spot a real dupe argument.");
engine.sendCommand(action, [{ x: "bar" }], remoteId);
- clientCommands = engine._readCommands()[remoteId];
- equal(clientCommands.length, 2);
+ do_check_eq(newRecord.commands.length, 2);
run_next_test();
});
@@ -486,7 +408,7 @@ add_test(function test_command_invalid_client() {
error = ex;
}
- equal(error.message.indexOf("Unknown remote client ID: "), 0);
+ do_check_eq(error.message.indexOf("Unknown remote client ID: "), 0);
run_next_test();
});
@@ -500,174 +422,13 @@ add_test(function test_process_incoming_commands() {
var handler = function() {
Svc.Obs.remove(ev, handler);
-
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- engine._resetClient();
-
run_next_test();
};
Svc.Obs.add(ev, handler);
// logout command causes processIncomingCommands to return explicit false.
- ok(!engine.processIncomingCommands());
-});
-
-add_test(function test_filter_duplicate_names() {
- _("Ensure that we exclude clients with identical names that haven't synced in a week.");
-
- let now = Date.now() / 1000;
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- let user = server.user("foo");
-
- new SyncTestingInfrastructure(server.server);
- generateNewKeys(Service.collectionKeys);
-
- // Synced recently.
- let recentID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(recentID, encryptPayload({
- id: recentID,
- name: "My Phone",
- type: "mobile",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- // Dupe of our client, synced more than 1 week ago.
- let dupeID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(dupeID, encryptPayload({
- id: dupeID,
- name: engine.localName,
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 604810));
-
- // Synced more than 1 week ago, but not a dupe.
- let oldID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(oldID, encryptPayload({
- id: oldID,
- name: "My old desktop",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 604820));
-
- try {
- let store = engine._store;
-
- _("First sync");
- strictEqual(engine.lastRecordUpload, 0);
- engine._sync();
- ok(engine.lastRecordUpload > 0);
- deepEqual(user.collection("clients").keys().sort(),
- [recentID, dupeID, oldID, engine.localID].sort(),
- "Our record should be uploaded on first sync");
-
- deepEqual(Object.keys(store.getAllIDs()).sort(),
- [recentID, dupeID, oldID, engine.localID].sort(),
- "Duplicate ID should remain in getAllIDs");
- ok(engine._store.itemExists(dupeID), "Dupe ID should be considered as existing for Sync methods.");
- ok(!engine.remoteClientExists(dupeID), "Dupe ID should not be considered as existing for external methods.");
-
- // dupe desktop should not appear in .deviceTypes.
- equal(engine.deviceTypes.get("desktop"), 2);
- equal(engine.deviceTypes.get("mobile"), 1);
-
- // dupe desktop should not appear in stats
- deepEqual(engine.stats, {
- hasMobile: 1,
- names: [engine.localName, "My Phone", "My old desktop"],
- numClients: 3,
- });
-
- ok(engine.remoteClientExists(oldID), "non-dupe ID should exist.");
- ok(!engine.remoteClientExists(dupeID), "dupe ID should not exist");
- equal(engine.remoteClients.length, 2, "dupe should not be in remoteClients");
-
- // Check that a subsequent Sync doesn't report anything as being processed.
- let counts;
- Svc.Obs.add("weave:engine:sync:applied", function observe(subject, data) {
- Svc.Obs.remove("weave:engine:sync:applied", observe);
- counts = subject;
- });
-
- engine._sync();
- equal(counts.applied, 0); // We didn't report applying any records.
- equal(counts.reconciled, 4); // We reported reconcilliation for all records
- equal(counts.succeeded, 0);
- equal(counts.failed, 0);
- equal(counts.newFailed, 0);
-
- _("Broadcast logout to all clients");
- engine.sendCommand("logout", []);
- engine._sync();
-
- let collection = server.getCollection("foo", "clients");
- let recentPayload = JSON.parse(JSON.parse(collection.payload(recentID)).ciphertext);
- deepEqual(recentPayload.commands, [{ command: "logout", args: [] }],
- "Should send commands to the recent client");
-
- let oldPayload = JSON.parse(JSON.parse(collection.payload(oldID)).ciphertext);
- deepEqual(oldPayload.commands, [{ command: "logout", args: [] }],
- "Should send commands to the week-old client");
-
- let dupePayload = JSON.parse(JSON.parse(collection.payload(dupeID)).ciphertext);
- deepEqual(dupePayload.commands, [],
- "Should not send commands to the dupe client");
-
- _("Update the dupe client's modified time");
- server.insertWBO("foo", "clients", new ServerWBO(dupeID, encryptPayload({
- id: dupeID,
- name: engine.localName,
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- _("Second sync.");
- engine._sync();
-
- deepEqual(Object.keys(store.getAllIDs()).sort(),
- [recentID, oldID, dupeID, engine.localID].sort(),
- "Stale client synced, so it should no longer be marked as a dupe");
-
- ok(engine.remoteClientExists(dupeID), "Dupe ID should appear as it synced.");
-
- // Recently synced dupe desktop should appear in .deviceTypes.
- equal(engine.deviceTypes.get("desktop"), 3);
-
- // Recently synced dupe desktop should now appear in stats
- deepEqual(engine.stats, {
- hasMobile: 1,
- names: [engine.localName, "My Phone", engine.localName, "My old desktop"],
- numClients: 4,
- });
-
- ok(engine.remoteClientExists(dupeID), "recently synced dupe ID should now exist");
- equal(engine.remoteClients.length, 3, "recently synced dupe should now be in remoteClients");
-
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
+ do_check_false(engine.processIncomingCommands());
});
add_test(function test_command_sync() {
@@ -693,58 +454,40 @@ add_test(function test_command_sync() {
}
_("Create remote client record");
- server.insertWBO("foo", "clients", new ServerWBO(remoteId, encryptPayload({
- id: remoteId,
- name: "Remote client",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), Date.now() / 1000));
+ let rec = new ClientsRec("clients", remoteId);
+ engine._store.create(rec);
+ let remoteRecord = engine._store.createRecord(remoteId, "clients");
+ engine.sendCommand("wipeAll", []);
+
+ let clientRecord = engine._store._remoteClients[remoteId];
+ do_check_neq(clientRecord, undefined);
+ do_check_eq(clientRecord.commands.length, 1);
try {
_("Syncing.");
engine._sync();
-
- _("Checking remote record was downloaded.");
- let clientRecord = engine._store._remoteClients[remoteId];
- notEqual(clientRecord, undefined);
- equal(clientRecord.commands.length, 0);
-
- _("Send a command to the remote client.");
- engine.sendCommand("wipeAll", []);
- let clientCommands = engine._readCommands()[remoteId];
- equal(clientCommands.length, 1);
- engine._sync();
-
_("Checking record was uploaded.");
- notEqual(clientWBO(engine.localID).payload, undefined);
- ok(engine.lastRecordUpload > 0);
+ do_check_neq(clientWBO(engine.localID).payload, undefined);
+ do_check_true(engine.lastRecordUpload > 0);
- notEqual(clientWBO(remoteId).payload, undefined);
+ do_check_neq(clientWBO(remoteId).payload, undefined);
Svc.Prefs.set("client.GUID", remoteId);
engine._resetClient();
- equal(engine.localID, remoteId);
+ do_check_eq(engine.localID, remoteId);
_("Performing sync on resetted client.");
engine._sync();
- notEqual(engine.localCommands, undefined);
- equal(engine.localCommands.length, 1);
+ do_check_neq(engine.localCommands, undefined);
+ do_check_eq(engine.localCommands.length, 1);
let command = engine.localCommands[0];
- equal(command.command, "wipeAll");
- equal(command.args.length, 0);
+ do_check_eq(command.command, "wipeAll");
+ do_check_eq(command.args.length, 0);
} finally {
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
-
- try {
- let collection = server.getCollection("foo", "clients");
- collection.remove(remoteId);
- } finally {
- server.stop(run_next_test);
- }
+ server.stop(run_next_test);
}
});
@@ -769,19 +512,18 @@ add_test(function test_send_uri_to_client_for_display() {
let newRecord = store._remoteClients[remoteId];
- notEqual(newRecord, undefined);
- let clientCommands = engine._readCommands()[remoteId];
- equal(clientCommands.length, 1);
+ do_check_neq(newRecord, undefined);
+ do_check_eq(newRecord.commands.length, 1);
- let command = clientCommands[0];
- equal(command.command, "displayURI");
- equal(command.args.length, 3);
- equal(command.args[0], uri);
- equal(command.args[1], engine.localID);
- equal(command.args[2], title);
+ let command = newRecord.commands[0];
+ do_check_eq(command.command, "displayURI");
+ do_check_eq(command.args.length, 3);
+ do_check_eq(command.args[0], uri);
+ do_check_eq(command.args[1], engine.localID);
+ do_check_eq(command.args[2], title);
- ok(tracker.score > initialScore);
- ok(tracker.score - initialScore >= SCORE_INCREMENT_XLARGE);
+ do_check_true(tracker.score > initialScore);
+ do_check_true(tracker.score - initialScore >= SCORE_INCREMENT_XLARGE);
_("Ensure unknown client IDs result in exception.");
let unknownId = Utils.makeGUID();
@@ -793,11 +535,7 @@ add_test(function test_send_uri_to_client_for_display() {
error = ex;
}
- equal(error.message.indexOf("Unknown remote client ID: "), 0);
-
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- engine._resetClient();
+ do_check_eq(error.message.indexOf("Unknown remote client ID: "), 0);
run_next_test();
});
@@ -821,26 +559,22 @@ add_test(function test_receive_display_uri() {
// Received 'displayURI' command should result in the topic defined below
// being called.
- let ev = "weave:engine:clients:display-uris";
+ let ev = "weave:engine:clients:display-uri";
let handler = function(subject, data) {
Svc.Obs.remove(ev, handler);
- equal(subject[0].uri, uri);
- equal(subject[0].clientId, remoteId);
- equal(subject[0].title, title);
- equal(data, null);
+ do_check_eq(subject.uri, uri);
+ do_check_eq(subject.client, remoteId);
+ do_check_eq(subject.title, title);
+ do_check_eq(data, null);
run_next_test();
};
Svc.Obs.add(ev, handler);
- ok(engine.processIncomingCommands());
-
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- engine._resetClient();
+ do_check_true(engine.processIncomingCommands());
});
add_test(function test_optional_client_fields() {
@@ -848,590 +582,27 @@ add_test(function test_optional_client_fields() {
const SUPPORTED_PROTOCOL_VERSIONS = ["1.1", "1.5"];
let local = engine._store.createRecord(engine.localID, "clients");
- equal(local.name, engine.localName);
- equal(local.type, engine.localType);
- equal(local.version, Services.appinfo.version);
- deepEqual(local.protocols, SUPPORTED_PROTOCOL_VERSIONS);
+ do_check_eq(local.name, engine.localName);
+ do_check_eq(local.type, engine.localType);
+ do_check_eq(local.version, Services.appinfo.version);
+ do_check_array_eq(local.protocols, SUPPORTED_PROTOCOL_VERSIONS);
// Optional fields.
// Make sure they're what they ought to be...
- equal(local.os, Services.appinfo.OS);
- equal(local.appPackage, Services.appinfo.ID);
+ do_check_eq(local.os, Services.appinfo.OS);
+ do_check_eq(local.appPackage, Services.appinfo.ID);
// ... and also that they're non-empty.
- ok(!!local.os);
- ok(!!local.appPackage);
- ok(!!local.application);
+ do_check_true(!!local.os);
+ do_check_true(!!local.appPackage);
+ do_check_true(!!local.application);
// We don't currently populate device or formfactor.
// See Bug 1100722, Bug 1100723.
- engine._resetClient();
run_next_test();
});
-add_test(function test_merge_commands() {
- _("Verifies local commands for remote clients are merged with the server's");
-
- let now = Date.now() / 1000;
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- let user = server.user("foo");
-
- new SyncTestingInfrastructure(server.server);
- generateNewKeys(Service.collectionKeys);
-
- let desktopID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(desktopID, encryptPayload({
- id: desktopID,
- name: "Desktop client",
- type: "desktop",
- commands: [{
- command: "displayURI",
- args: ["https://example.com", engine.localID, "Yak Herders Anonymous"],
- }],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- let mobileID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(mobileID, encryptPayload({
- id: mobileID,
- name: "Mobile client",
- type: "mobile",
- commands: [{
- command: "logout",
- args: [],
- }],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- try {
- let store = engine._store;
-
- _("First sync. 2 records downloaded.");
- strictEqual(engine.lastRecordUpload, 0);
- engine._sync();
-
- _("Broadcast logout to all clients");
- engine.sendCommand("logout", []);
- engine._sync();
-
- let collection = server.getCollection("foo", "clients");
- let desktopPayload = JSON.parse(JSON.parse(collection.payload(desktopID)).ciphertext);
- deepEqual(desktopPayload.commands, [{
- command: "displayURI",
- args: ["https://example.com", engine.localID, "Yak Herders Anonymous"],
- }, {
- command: "logout",
- args: [],
- }], "Should send the logout command to the desktop client");
-
- let mobilePayload = JSON.parse(JSON.parse(collection.payload(mobileID)).ciphertext);
- deepEqual(mobilePayload.commands, [{ command: "logout", args: [] }],
- "Should not send a duplicate logout to the mobile client");
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- engine._resetClient();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
-});
-
-add_test(function test_duplicate_remote_commands() {
- _("Verifies local commands for remote clients are sent only once (bug 1289287)");
-
- let now = Date.now() / 1000;
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- let user = server.user("foo");
-
- new SyncTestingInfrastructure(server.server);
- generateNewKeys(Service.collectionKeys);
-
- let desktopID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(desktopID, encryptPayload({
- id: desktopID,
- name: "Desktop client",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- try {
- let store = engine._store;
-
- _("First sync. 1 record downloaded.");
- strictEqual(engine.lastRecordUpload, 0);
- engine._sync();
-
- _("Send tab to client");
- engine.sendCommand("displayURI", ["https://example.com", engine.localID, "Yak Herders Anonymous"]);
- engine._sync();
-
- _("Simulate the desktop client consuming the command and syncing to the server");
- server.insertWBO("foo", "clients", new ServerWBO(desktopID, encryptPayload({
- id: desktopID,
- name: "Desktop client",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- _("Send another tab to the desktop client");
- engine.sendCommand("displayURI", ["https://foobar.com", engine.localID, "Foo bar!"], desktopID);
- engine._sync();
-
- let collection = server.getCollection("foo", "clients");
- let desktopPayload = JSON.parse(JSON.parse(collection.payload(desktopID)).ciphertext);
- deepEqual(desktopPayload.commands, [{
- command: "displayURI",
- args: ["https://foobar.com", engine.localID, "Foo bar!"],
- }], "Should only send the second command to the desktop client");
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- engine._resetClient();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
-});
-
-add_test(function test_upload_after_reboot() {
- _("Multiple downloads, reboot, then upload (bug 1289287)");
-
- let now = Date.now() / 1000;
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- let user = server.user("foo");
-
- new SyncTestingInfrastructure(server.server);
- generateNewKeys(Service.collectionKeys);
-
- let deviceBID = Utils.makeGUID();
- let deviceCID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(deviceBID, encryptPayload({
- id: deviceBID,
- name: "Device B",
- type: "desktop",
- commands: [{
- command: "displayURI", args: ["https://deviceclink.com", deviceCID, "Device C link"]
- }],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
- server.insertWBO("foo", "clients", new ServerWBO(deviceCID, encryptPayload({
- id: deviceCID,
- name: "Device C",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- try {
- let store = engine._store;
-
- _("First sync. 2 records downloaded.");
- strictEqual(engine.lastRecordUpload, 0);
- engine._sync();
-
- _("Send tab to client");
- engine.sendCommand("displayURI", ["https://example.com", engine.localID, "Yak Herders Anonymous"], deviceBID);
-
- const oldUploadOutgoing = SyncEngine.prototype._uploadOutgoing;
- SyncEngine.prototype._uploadOutgoing = () => engine._onRecordsWritten.call(engine, [], [deviceBID]);
- engine._sync();
-
- let collection = server.getCollection("foo", "clients");
- let deviceBPayload = JSON.parse(JSON.parse(collection.payload(deviceBID)).ciphertext);
- deepEqual(deviceBPayload.commands, [{
- command: "displayURI", args: ["https://deviceclink.com", deviceCID, "Device C link"]
- }], "Should be the same because the upload failed");
-
- _("Simulate the client B consuming the command and syncing to the server");
- server.insertWBO("foo", "clients", new ServerWBO(deviceBID, encryptPayload({
- id: deviceBID,
- name: "Device B",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- // Simulate reboot
- SyncEngine.prototype._uploadOutgoing = oldUploadOutgoing;
- engine = Service.clientsEngine = new ClientEngine(Service);
-
- engine._sync();
-
- deviceBPayload = JSON.parse(JSON.parse(collection.payload(deviceBID)).ciphertext);
- deepEqual(deviceBPayload.commands, [{
- command: "displayURI",
- args: ["https://example.com", engine.localID, "Yak Herders Anonymous"],
- }], "Should only had written our outgoing command");
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- engine._resetClient();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
-});
-
-add_test(function test_keep_cleared_commands_after_reboot() {
- _("Download commands, fail upload, reboot, then apply new commands (bug 1289287)");
-
- let now = Date.now() / 1000;
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- let user = server.user("foo");
-
- new SyncTestingInfrastructure(server.server);
- generateNewKeys(Service.collectionKeys);
-
- let deviceBID = Utils.makeGUID();
- let deviceCID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(engine.localID, encryptPayload({
- id: engine.localID,
- name: "Device A",
- type: "desktop",
- commands: [{
- command: "displayURI", args: ["https://deviceblink.com", deviceBID, "Device B link"]
- },
- {
- command: "displayURI", args: ["https://deviceclink.com", deviceCID, "Device C link"]
- }],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
- server.insertWBO("foo", "clients", new ServerWBO(deviceBID, encryptPayload({
- id: deviceBID,
- name: "Device B",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
- server.insertWBO("foo", "clients", new ServerWBO(deviceCID, encryptPayload({
- id: deviceCID,
- name: "Device C",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- try {
- let store = engine._store;
-
- _("First sync. Download remote and our record.");
- strictEqual(engine.lastRecordUpload, 0);
-
- let collection = server.getCollection("foo", "clients");
- const oldUploadOutgoing = SyncEngine.prototype._uploadOutgoing;
- SyncEngine.prototype._uploadOutgoing = () => engine._onRecordsWritten.call(engine, [], [deviceBID]);
- let commandsProcessed = 0;
- engine._handleDisplayURIs = (uris) => { commandsProcessed = uris.length };
-
- engine._sync();
- engine.processIncomingCommands(); // Not called by the engine.sync(), gotta call it ourselves
- equal(commandsProcessed, 2, "We processed 2 commands");
-
- let localRemoteRecord = JSON.parse(JSON.parse(collection.payload(engine.localID)).ciphertext);
- deepEqual(localRemoteRecord.commands, [{
- command: "displayURI", args: ["https://deviceblink.com", deviceBID, "Device B link"]
- },
- {
- command: "displayURI", args: ["https://deviceclink.com", deviceCID, "Device C link"]
- }], "Should be the same because the upload failed");
-
- // Another client sends another link
- server.insertWBO("foo", "clients", new ServerWBO(engine.localID, encryptPayload({
- id: engine.localID,
- name: "Device A",
- type: "desktop",
- commands: [{
- command: "displayURI", args: ["https://deviceblink.com", deviceBID, "Device B link"]
- },
- {
- command: "displayURI", args: ["https://deviceclink.com", deviceCID, "Device C link"]
- },
- {
- command: "displayURI", args: ["https://deviceclink2.com", deviceCID, "Device C link 2"]
- }],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- // Simulate reboot
- SyncEngine.prototype._uploadOutgoing = oldUploadOutgoing;
- engine = Service.clientsEngine = new ClientEngine(Service);
-
- commandsProcessed = 0;
- engine._handleDisplayURIs = (uris) => { commandsProcessed = uris.length };
- engine._sync();
- engine.processIncomingCommands();
- equal(commandsProcessed, 1, "We processed one command (the other were cleared)");
-
- localRemoteRecord = JSON.parse(JSON.parse(collection.payload(deviceBID)).ciphertext);
- deepEqual(localRemoteRecord.commands, [], "Should be empty");
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
-
- // Reset service (remove mocks)
- engine = Service.clientsEngine = new ClientEngine(Service);
- engine._resetClient();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
-});
-
-add_test(function test_deleted_commands() {
- _("Verifies commands for a deleted client are discarded");
-
- let now = Date.now() / 1000;
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- let user = server.user("foo");
-
- new SyncTestingInfrastructure(server.server);
- generateNewKeys(Service.collectionKeys);
-
- let activeID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(activeID, encryptPayload({
- id: activeID,
- name: "Active client",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- let deletedID = Utils.makeGUID();
- server.insertWBO("foo", "clients", new ServerWBO(deletedID, encryptPayload({
- id: deletedID,
- name: "Client to delete",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"],
- }), now - 10));
-
- try {
- let store = engine._store;
-
- _("First sync. 2 records downloaded.");
- engine._sync();
-
- _("Delete a record on the server.");
- let collection = server.getCollection("foo", "clients");
- collection.remove(deletedID);
-
- _("Broadcast a command to all clients");
- engine.sendCommand("logout", []);
- engine._sync();
-
- deepEqual(collection.keys().sort(), [activeID, engine.localID].sort(),
- "Should not reupload deleted clients");
-
- let activePayload = JSON.parse(JSON.parse(collection.payload(activeID)).ciphertext);
- deepEqual(activePayload.commands, [{ command: "logout", args: [] }],
- "Should send the command to the active client");
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- engine._resetClient();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
-});
-
-add_test(function test_send_uri_ack() {
- _("Ensure a sent URI is deleted when the client syncs");
-
- let now = Date.now() / 1000;
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- let user = server.user("foo");
-
- new SyncTestingInfrastructure(server.server);
- generateNewKeys(Service.collectionKeys);
-
- try {
- let fakeSenderID = Utils.makeGUID();
-
- _("Initial sync for empty clients collection");
- engine._sync();
- let collection = server.getCollection("foo", "clients");
- let ourPayload = JSON.parse(JSON.parse(collection.payload(engine.localID)).ciphertext);
- ok(ourPayload, "Should upload our client record");
-
- _("Send a URL to the device on the server");
- ourPayload.commands = [{
- command: "displayURI",
- args: ["https://example.com", fakeSenderID, "Yak Herders Anonymous"],
- }];
- server.insertWBO("foo", "clients", new ServerWBO(engine.localID, encryptPayload(ourPayload), now));
-
- _("Sync again");
- engine._sync();
- deepEqual(engine.localCommands, [{
- command: "displayURI",
- args: ["https://example.com", fakeSenderID, "Yak Herders Anonymous"],
- }], "Should receive incoming URI");
- ok(engine.processIncomingCommands(), "Should process incoming commands");
- const clearedCommands = engine._readCommands()[engine.localID];
- deepEqual(clearedCommands, [{
- command: "displayURI",
- args: ["https://example.com", fakeSenderID, "Yak Herders Anonymous"],
- }], "Should mark the commands as cleared after processing");
-
- _("Check that the command was removed on the server");
- engine._sync();
- ourPayload = JSON.parse(JSON.parse(collection.payload(engine.localID)).ciphertext);
- ok(ourPayload, "Should upload the synced client record");
- deepEqual(ourPayload.commands, [], "Should not reupload cleared commands");
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
- engine._resetClient();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
-});
-
-add_test(function test_command_sync() {
- _("Notify other clients when writing their record.");
-
- engine._store.wipe();
- generateNewKeys(Service.collectionKeys);
-
- let contents = {
- meta: {global: {engines: {clients: {version: engine.version,
- syncID: engine.syncID}}}},
- clients: {},
- crypto: {}
- };
- let server = serverForUsers({"foo": "password"}, contents);
- new SyncTestingInfrastructure(server.server);
-
- let user = server.user("foo");
- let collection = server.getCollection("foo", "clients");
- let remoteId = Utils.makeGUID();
- let remoteId2 = Utils.makeGUID();
-
- function clientWBO(id) {
- return user.collection("clients").wbo(id);
- }
-
- _("Create remote client record 1");
- server.insertWBO("foo", "clients", new ServerWBO(remoteId, encryptPayload({
- id: remoteId,
- name: "Remote client",
- type: "desktop",
- commands: [],
- version: "48",
- protocols: ["1.5"]
- }), Date.now() / 1000));
-
- _("Create remote client record 2");
- server.insertWBO("foo", "clients", new ServerWBO(remoteId2, encryptPayload({
- id: remoteId2,
- name: "Remote client 2",
- type: "mobile",
- commands: [],
- version: "48",
- protocols: ["1.5"]
- }), Date.now() / 1000));
-
- try {
- equal(collection.count(), 2, "2 remote records written");
- engine._sync();
- equal(collection.count(), 3, "3 remote records written (+1 for the synced local record)");
-
- let notifiedIds;
- engine.sendCommand("wipeAll", []);
- engine._tracker.addChangedID(engine.localID);
- engine.getClientFxaDeviceId = (id) => "fxa-" + id;
- engine._notifyCollectionChanged = (ids) => (notifiedIds = ids);
- _("Syncing.");
- engine._sync();
- deepEqual(notifiedIds, ["fxa-fake-guid-00","fxa-fake-guid-01"]);
- ok(!notifiedIds.includes(engine.getClientFxaDeviceId(engine.localID)),
- "We never notify the local device");
-
- } finally {
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
-
- try {
- server.deleteCollections("foo");
- } finally {
- server.stop(run_next_test);
- }
- }
-});
-
function run_test() {
initTestLogging("Trace");
Log.repository.getLogger("Sync.Engine.Clients").level = Log.Level.Trace;
diff --git a/services/sync/tests/unit/test_collection_getBatched.js b/services/sync/tests/unit/test_collection_getBatched.js
deleted file mode 100644
index c6523d497..000000000
--- a/services/sync/tests/unit/test_collection_getBatched.js
+++ /dev/null
@@ -1,195 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/record.js");
-Cu.import("resource://services-sync/service.js");
-
-function run_test() {
- initTestLogging("Trace");
- Log.repository.getLogger("Sync.Collection").level = Log.Level.Trace;
- run_next_test();
-}
-
-function recordRange(lim, offset, total) {
- let res = [];
- for (let i = offset; i < Math.min(lim + offset, total); ++i) {
- res.push(JSON.stringify({ id: String(i), payload: "test:" + i }));
- }
- return res.join("\n") + "\n";
-}
-
-function get_test_collection_info({ totalRecords, batchSize, lastModified,
- throwAfter = Infinity,
- interruptedAfter = Infinity }) {
- let coll = new Collection("http://example.com/test/", WBORecord, Service);
- coll.full = true;
- let requests = [];
- let responses = [];
- let sawRecord = false;
- coll.get = function() {
- ok(!sawRecord); // make sure we call record handler after all requests.
- let limit = +this.limit;
- let offset = 0;
- if (this.offset) {
- equal(this.offset.slice(0, 6), "foobar");
- offset = +this.offset.slice(6);
- }
- requests.push({
- limit,
- offset,
- spec: this.spec,
- headers: Object.assign({}, this.headers)
- });
- if (--throwAfter === 0) {
- throw "Some Network Error";
- }
- let body = recordRange(limit, offset, totalRecords);
- this._onProgress.call({ _data: body });
- let response = {
- body,
- success: true,
- status: 200,
- headers: {}
- };
- if (--interruptedAfter === 0) {
- response.success = false;
- response.status = 412;
- response.body = "";
- } else if (offset + limit < totalRecords) {
- // Ensure we're treating this as an opaque string, since the docs say
- // it might not be numeric.
- response.headers["x-weave-next-offset"] = "foobar" + (offset + batchSize);
- }
- response.headers["x-last-modified"] = lastModified;
- responses.push(response);
- return response;
- };
-
- let records = [];
- coll.recordHandler = function(record) {
- sawRecord = true;
- // ensure records are coming in in the right order
- equal(record.id, String(records.length));
- equal(record.payload, "test:" + records.length);
- records.push(record);
- };
- return { records, responses, requests, coll };
-}
-
-add_test(function test_success() {
- const totalRecords = 11;
- const batchSize = 2;
- const lastModified = "111111";
- let { records, responses, requests, coll } = get_test_collection_info({
- totalRecords,
- batchSize,
- lastModified,
- });
- let response = coll.getBatched(batchSize);
-
- equal(requests.length, Math.ceil(totalRecords / batchSize));
-
- // records are mostly checked in recordHandler, we just care about the length
- equal(records.length, totalRecords);
-
- // ensure we're returning the last response
- equal(responses[responses.length - 1], response);
-
- // check first separately since its a bit of a special case
- ok(!requests[0].headers["x-if-unmodified-since"]);
- ok(!requests[0].offset);
- equal(requests[0].limit, batchSize);
- let expectedOffset = 2;
- for (let i = 1; i < requests.length; ++i) {
- let req = requests[i];
- equal(req.headers["x-if-unmodified-since"], lastModified);
- equal(req.limit, batchSize);
- if (i !== requests.length - 1) {
- equal(req.offset, expectedOffset);
- }
-
- expectedOffset += batchSize;
- }
-
- // ensure we cleaned up anything that would break further
- // use of this collection.
- ok(!coll._headers["x-if-unmodified-since"]);
- ok(!coll.offset);
- ok(!coll.limit || (coll.limit == Infinity));
-
- run_next_test();
-});
-
-add_test(function test_total_limit() {
- _("getBatched respects the (initial) value of the limit property");
- const totalRecords = 100;
- const recordLimit = 11;
- const batchSize = 2;
- const lastModified = "111111";
- let { records, responses, requests, coll } = get_test_collection_info({
- totalRecords,
- batchSize,
- lastModified,
- });
- coll.limit = recordLimit;
- let response = coll.getBatched(batchSize);
-
- equal(requests.length, Math.ceil(recordLimit / batchSize));
- equal(records.length, recordLimit);
-
- for (let i = 0; i < requests.length; ++i) {
- let req = requests[i];
- if (i !== requests.length - 1) {
- equal(req.limit, batchSize);
- } else {
- equal(req.limit, recordLimit % batchSize);
- }
- }
-
- equal(coll._limit, recordLimit);
-
- run_next_test();
-});
-
-add_test(function test_412() {
- _("We shouldn't record records if we get a 412 in the middle of a batch");
- const totalRecords = 11;
- const batchSize = 2;
- const lastModified = "111111";
- let { records, responses, requests, coll } = get_test_collection_info({
- totalRecords,
- batchSize,
- lastModified,
- interruptedAfter: 3
- });
- let response = coll.getBatched(batchSize);
-
- equal(requests.length, 3);
- equal(records.length, 0); // record handler shouldn't be called for anything
-
- // ensure we're returning the last response
- equal(responses[responses.length - 1], response);
-
- ok(!response.success);
- equal(response.status, 412);
- run_next_test();
-});
-
-add_test(function test_get_throws() {
- _("We shouldn't record records if get() throws for some reason");
- const totalRecords = 11;
- const batchSize = 2;
- const lastModified = "111111";
- let { records, responses, requests, coll } = get_test_collection_info({
- totalRecords,
- batchSize,
- lastModified,
- throwAfter: 3
- });
-
- throws(() => coll.getBatched(batchSize), "Some Network Error");
-
- equal(requests.length, 3);
- equal(records.length, 0);
- run_next_test();
-});
diff --git a/services/sync/tests/unit/test_collections_recovery.js b/services/sync/tests/unit/test_collections_recovery.js
index 0e7f54676..377a05383 100644
--- a/services/sync/tests/unit/test_collections_recovery.js
+++ b/services/sync/tests/unit/test_collections_recovery.js
@@ -6,7 +6,7 @@ Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
-add_identity_test(this, function* test_missing_crypto_collection() {
+add_identity_test(this, function test_missing_crypto_collection() {
let johnHelper = track_collections_helper();
let johnU = johnHelper.with_updated_collection;
let johnColls = johnHelper.collections;
@@ -33,10 +33,7 @@ add_identity_test(this, function* test_missing_crypto_collection() {
};
let collections = ["clients", "bookmarks", "forms", "history",
"passwords", "prefs", "tabs"];
- // Disable addon sync because AddonManager won't be initialized here.
- Service.engineManager.unregister("addons");
-
- for (let coll of collections) {
+ for each (let coll in collections) {
handlers["/1.1/johndoe/storage/" + coll] =
johnU(coll, new ServerCollection({}, true).handler());
}
@@ -53,7 +50,7 @@ add_identity_test(this, function* test_missing_crypto_collection() {
};
_("Startup, no meta/global: freshStart called once.");
- yield sync_and_validate_telem();
+ Service.sync();
do_check_eq(fresh, 1);
fresh = 0;
@@ -63,12 +60,12 @@ add_identity_test(this, function* test_missing_crypto_collection() {
_("Simulate a bad info/collections.");
delete johnColls.crypto;
- yield sync_and_validate_telem();
+ Service.sync();
do_check_eq(fresh, 1);
fresh = 0;
_("Regular sync: no need to freshStart.");
- yield sync_and_validate_telem();
+ Service.sync();
do_check_eq(fresh, 0);
} finally {
diff --git a/services/sync/tests/unit/test_corrupt_keys.js b/services/sync/tests/unit/test_corrupt_keys.js
index 009461c2a..2db080a8f 100644
--- a/services/sync/tests/unit/test_corrupt_keys.js
+++ b/services/sync/tests/unit/test_corrupt_keys.js
@@ -14,7 +14,7 @@ Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
Cu.import("resource://gre/modules/Promise.jsm");
-add_task(function* test_locally_changed_keys() {
+add_task(function test_locally_changed_keys() {
let passphrase = "abcdeabcdeabcdeabcdeabcdea";
let hmacErrorCount = 0;
@@ -51,7 +51,7 @@ add_task(function* test_locally_changed_keys() {
}]}]};
delete Svc.Session;
Svc.Session = {
- getBrowserState: () => JSON.stringify(myTabs)
+ getBrowserState: function () JSON.stringify(myTabs)
};
setBasicCredentials("johndoe", "password", passphrase);
@@ -59,7 +59,6 @@ add_task(function* test_locally_changed_keys() {
Service.clusterURL = server.baseURI;
Service.engineManager.register(HistoryEngine);
- Service.engineManager.unregister("addons");
function corrupt_local_keys() {
Service.collectionKeys._default.keyPair = [Svc.Crypto.generateRandomKey(),
@@ -87,7 +86,7 @@ add_task(function* test_locally_changed_keys() {
do_check_true(Service.isLoggedIn);
// Sync should upload records.
- yield sync_and_validate_telem();
+ Service.sync();
// Tabs exist.
_("Tabs modified: " + johndoe.modified("tabs"));
@@ -140,9 +139,7 @@ add_task(function* test_locally_changed_keys() {
_("HMAC error count: " + hmacErrorCount);
// Now syncing should succeed, after one HMAC error.
- let ping = yield wait_for_ping(() => Service.sync(), true);
- equal(ping.engines.find(e => e.name == "history").incoming.applied, 5);
-
+ Service.sync();
do_check_eq(hmacErrorCount, 1);
_("Keys now: " + Service.collectionKeys.keyForCollection("history").keyPair);
@@ -186,9 +183,7 @@ add_task(function* test_locally_changed_keys() {
Service.lastHMACEvent = 0;
_("Syncing...");
- ping = yield sync_and_validate_telem(true);
-
- do_check_eq(ping.engines.find(e => e.name == "history").incoming.failed, 5);
+ Service.sync();
_("Keys now: " + Service.collectionKeys.keyForCollection("history").keyPair);
_("Server keys have been updated, and we skipped over 5 more HMAC errors without adjusting history.");
do_check_true(johndoe.modified("crypto") > old_key_time);
@@ -209,7 +204,6 @@ add_task(function* test_locally_changed_keys() {
function run_test() {
let logger = Log.repository.rootLogger;
Log.repository.rootLogger.addAppender(new Log.DumpAppender());
- validate_all_future_pings();
ensureLegacyIdentityManager();
diff --git a/services/sync/tests/unit/test_engine.js b/services/sync/tests/unit/test_engine.js
index be637efc8..000cd5b4a 100644
--- a/services/sync/tests/unit/test_engine.js
+++ b/services/sync/tests/unit/test_engine.js
@@ -25,8 +25,8 @@ SteamTracker.prototype = {
__proto__: Tracker.prototype
};
-function SteamEngine(name, service) {
- Engine.call(this, name, service);
+function SteamEngine(service) {
+ Engine.call(this, "Steam", service);
this.wasReset = false;
this.wasSynced = false;
}
@@ -44,7 +44,7 @@ SteamEngine.prototype = {
}
};
-var engineObserver = {
+let engineObserver = {
topics: [],
observe: function(subject, topic, data) {
@@ -69,7 +69,7 @@ function run_test() {
add_test(function test_members() {
_("Engine object members");
- let engine = new SteamEngine("Steam", Service);
+ let engine = new SteamEngine(Service);
do_check_eq(engine.Name, "Steam");
do_check_eq(engine.prefName, "steam");
do_check_true(engine._store instanceof SteamStore);
@@ -79,7 +79,7 @@ add_test(function test_members() {
add_test(function test_score() {
_("Engine.score corresponds to tracker.score and is readonly");
- let engine = new SteamEngine("Steam", Service);
+ let engine = new SteamEngine(Service);
do_check_eq(engine.score, 0);
engine._tracker.score += 5;
do_check_eq(engine.score, 5);
@@ -97,7 +97,7 @@ add_test(function test_score() {
add_test(function test_resetClient() {
_("Engine.resetClient calls _resetClient");
- let engine = new SteamEngine("Steam", Service);
+ let engine = new SteamEngine(Service);
do_check_false(engine.wasReset);
engine.resetClient();
@@ -112,7 +112,7 @@ add_test(function test_resetClient() {
add_test(function test_invalidChangedIDs() {
_("Test that invalid changed IDs on disk don't end up live.");
- let engine = new SteamEngine("Steam", Service);
+ let engine = new SteamEngine(Service);
let tracker = engine._tracker;
tracker.changedIDs = 5;
tracker.saveChangedIDs(function onSaved() {
@@ -127,7 +127,7 @@ add_test(function test_invalidChangedIDs() {
add_test(function test_wipeClient() {
_("Engine.wipeClient calls resetClient, wipes store, clears changed IDs");
- let engine = new SteamEngine("Steam", Service);
+ let engine = new SteamEngine(Service);
do_check_false(engine.wasReset);
do_check_false(engine._store.wasWiped);
do_check_true(engine._tracker.addChangedID("a-changed-id"));
@@ -150,7 +150,7 @@ add_test(function test_wipeClient() {
add_test(function test_enabled() {
_("Engine.enabled corresponds to preference");
- let engine = new SteamEngine("Steam", Service);
+ let engine = new SteamEngine(Service);
try {
do_check_false(engine.enabled);
Svc.Prefs.set("engine.steam", true);
@@ -165,18 +165,16 @@ add_test(function test_enabled() {
});
add_test(function test_sync() {
- let engine = new SteamEngine("Steam", Service);
+ let engine = new SteamEngine(Service);
try {
_("Engine.sync doesn't call _sync if it's not enabled");
do_check_false(engine.enabled);
do_check_false(engine.wasSynced);
engine.sync();
-
do_check_false(engine.wasSynced);
_("Engine.sync calls _sync if it's enabled");
engine.enabled = true;
-
engine.sync();
do_check_true(engine.wasSynced);
do_check_eq(engineObserver.topics[0], "weave:engine:sync:start");
@@ -191,7 +189,7 @@ add_test(function test_sync() {
add_test(function test_disabled_no_track() {
_("When an engine is disabled, its tracker is not tracking.");
- let engine = new SteamEngine("Steam", Service);
+ let engine = new SteamEngine(Service);
let tracker = engine._tracker;
do_check_eq(engine, tracker.engine);
diff --git a/services/sync/tests/unit/test_errorhandler.js b/services/sync/tests/unit/test_errorhandler.js
new file mode 100644
index 000000000..c087acc9f
--- /dev/null
+++ b/services/sync/tests/unit/test_errorhandler.js
@@ -0,0 +1,1893 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource://services-sync/engines/clients.js");
+Cu.import("resource://services-sync/constants.js");
+Cu.import("resource://services-sync/engines.js");
+Cu.import("resource://services-sync/keys.js");
+Cu.import("resource://services-sync/policies.js");
+Cu.import("resource://services-sync/service.js");
+Cu.import("resource://services-sync/status.js");
+Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
+Cu.import("resource://gre/modules/FileUtils.jsm");
+
+const FAKE_SERVER_URL = "http://dummy:9000/";
+const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
+
+const PROLONGED_ERROR_DURATION =
+ (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000;
+
+const NON_PROLONGED_ERROR_DURATION =
+ (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') / 2) * 1000;
+
+Service.engineManager.clear();
+
+function setLastSync(lastSyncValue) {
+ Svc.Prefs.set("lastSync", (new Date(Date.now() - lastSyncValue)).toString());
+}
+
+function CatapultEngine() {
+ SyncEngine.call(this, "Catapult", Service);
+}
+CatapultEngine.prototype = {
+ __proto__: SyncEngine.prototype,
+ exception: null, // tests fill this in
+ _sync: function _sync() {
+ if (this.exception) {
+ throw this.exception;
+ }
+ }
+};
+
+let engineManager = Service.engineManager;
+engineManager.register(CatapultEngine);
+
+// This relies on Service/ErrorHandler being a singleton. Fixing this will take
+// a lot of work.
+let errorHandler = Service.errorHandler;
+
+function run_test() {
+ initTestLogging("Trace");
+
+ Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
+
+ ensureLegacyIdentityManager();
+
+ run_next_test();
+}
+
+function generateCredentialsChangedFailure() {
+ // Make sync fail due to changed credentials. We simply re-encrypt
+ // the keys with a different Sync Key, without changing the local one.
+ let newSyncKeyBundle = new SyncKeyBundle("johndoe", "23456234562345623456234562");
+ let keys = Service.collectionKeys.asWBO();
+ keys.encrypt(newSyncKeyBundle);
+ keys.upload(Service.resource(Service.cryptoKeysURL));
+}
+
+function service_unavailable(request, response) {
+ let body = "Service Unavailable";
+ response.setStatusLine(request.httpVersion, 503, "Service Unavailable");
+ response.setHeader("Retry-After", "42");
+ response.bodyOutputStream.write(body, body.length);
+}
+
+function sync_httpd_setup() {
+ let global = new ServerWBO("global", {
+ syncID: Service.syncID,
+ storageVersion: STORAGE_VERSION,
+ engines: {clients: {version: Service.clientsEngine.version,
+ syncID: Service.clientsEngine.syncID},
+ catapult: {version: engineManager.get("catapult").version,
+ syncID: engineManager.get("catapult").syncID}}
+ });
+ let clientsColl = new ServerCollection({}, true);
+
+ // Tracking info/collections.
+ let collectionsHelper = track_collections_helper();
+ let upd = collectionsHelper.with_updated_collection;
+
+ let handler_401 = httpd_handler(401, "Unauthorized");
+ return httpd_setup({
+ // Normal server behaviour.
+ "/1.1/johndoe/storage/meta/global": upd("meta", global.handler()),
+ "/1.1/johndoe/info/collections": collectionsHelper.handler,
+ "/1.1/johndoe/storage/crypto/keys":
+ upd("crypto", (new ServerWBO("keys")).handler()),
+ "/1.1/johndoe/storage/clients": upd("clients", clientsColl.handler()),
+
+ // Credentials are wrong or node reallocated.
+ "/1.1/janedoe/storage/meta/global": handler_401,
+ "/1.1/janedoe/info/collections": handler_401,
+
+ // Maintenance or overloaded (503 + Retry-After) at info/collections.
+ "/maintenance/1.1/broken.info/info/collections": service_unavailable,
+
+ // Maintenance or overloaded (503 + Retry-After) at meta/global.
+ "/maintenance/1.1/broken.meta/storage/meta/global": service_unavailable,
+ "/maintenance/1.1/broken.meta/info/collections": collectionsHelper.handler,
+
+ // Maintenance or overloaded (503 + Retry-After) at crypto/keys.
+ "/maintenance/1.1/broken.keys/storage/meta/global": upd("meta", global.handler()),
+ "/maintenance/1.1/broken.keys/info/collections": collectionsHelper.handler,
+ "/maintenance/1.1/broken.keys/storage/crypto/keys": service_unavailable,
+
+ // Maintenance or overloaded (503 + Retry-After) at wiping collection.
+ "/maintenance/1.1/broken.wipe/info/collections": collectionsHelper.handler,
+ "/maintenance/1.1/broken.wipe/storage/meta/global": upd("meta", global.handler()),
+ "/maintenance/1.1/broken.wipe/storage/crypto/keys":
+ upd("crypto", (new ServerWBO("keys")).handler()),
+ "/maintenance/1.1/broken.wipe/storage": service_unavailable,
+ "/maintenance/1.1/broken.wipe/storage/clients": upd("clients", clientsColl.handler()),
+ "/maintenance/1.1/broken.wipe/storage/catapult": service_unavailable
+ });
+}
+
+function setUp(server) {
+ return configureIdentity({username: "johndoe"}).then(
+ () => {
+ Service.serverURL = server.baseURI + "/";
+ Service.clusterURL = server.baseURI + "/";
+ }
+ ).then(
+ () => generateAndUploadKeys()
+ );
+}
+
+function generateAndUploadKeys() {
+ generateNewKeys(Service.collectionKeys);
+ let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
+ serverKeys.encrypt(Service.identity.syncKeyBundle);
+ return serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success;
+}
+
+function clean() {
+ Service.startOver();
+ Status.resetSync();
+ Status.resetBackoff();
+ errorHandler.didReportProlongedError = false;
+}
+
+add_identity_test(this, function test_401_logout() {
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ // By calling sync, we ensure we're logged in.
+ Service.sync();
+ do_check_eq(Status.sync, SYNC_SUCCEEDED);
+ do_check_true(Service.isLoggedIn);
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:service:sync:error", onSyncError);
+ function onSyncError() {
+ _("Got weave:service:sync:error in first sync.");
+ Svc.Obs.remove("weave:service:sync:error", onSyncError);
+
+ // Wait for the automatic next sync.
+ function onLoginError() {
+ _("Got weave:service:login:error in second sync.");
+ Svc.Obs.remove("weave:service:login:error", onLoginError);
+
+ do_check_eq(Status.login, LOGIN_FAILED_LOGIN_REJECTED);
+ do_check_false(Service.isLoggedIn);
+
+ // Clean up.
+ Utils.nextTick(function () {
+ Service.startOver();
+ server.stop(deferred.resolve);
+ });
+ }
+ Svc.Obs.add("weave:service:login:error", onLoginError);
+ }
+
+ // Make sync fail due to login rejected.
+ yield configureIdentity({username: "janedoe"});
+ Service._updateCachedURLs();
+
+ _("Starting first sync.");
+ Service.sync();
+ _("First sync done.");
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_credentials_changed_logout() {
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ // By calling sync, we ensure we're logged in.
+ Service.sync();
+ do_check_eq(Status.sync, SYNC_SUCCEEDED);
+ do_check_true(Service.isLoggedIn);
+
+ generateCredentialsChangedFailure();
+ Service.sync();
+
+ do_check_eq(Status.sync, CREDENTIALS_CHANGED);
+ do_check_false(Service.isLoggedIn);
+
+ // Clean up.
+ Service.startOver();
+ let deferred = Promise.defer();
+ server.stop(deferred.resolve);
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_no_lastSync_pref() {
+ // Test reported error.
+ Status.resetSync();
+ errorHandler.dontIgnoreErrors = true;
+ Status.sync = CREDENTIALS_CHANGED;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test unreported error.
+ Status.resetSync();
+ errorHandler.dontIgnoreErrors = true;
+ Status.login = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_true(errorHandler.shouldReportError());
+
+});
+
+add_identity_test(this, function test_shouldReportError() {
+ Status.login = MASTER_PASSWORD_LOCKED;
+ do_check_false(errorHandler.shouldReportError());
+
+ // Give ourselves a clusterURL so that the temporary 401 no-error situation
+ // doesn't come into play.
+ Service.serverURL = FAKE_SERVER_URL;
+ Service.clusterURL = FAKE_SERVER_URL;
+
+ // Test dontIgnoreErrors, non-network, non-prolonged, login error reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.login = LOGIN_FAILED_NO_PASSWORD;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test dontIgnoreErrors, non-network, non-prolonged, sync error reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.sync = CREDENTIALS_CHANGED;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test dontIgnoreErrors, non-network, prolonged, login error reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.login = LOGIN_FAILED_NO_PASSWORD;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test dontIgnoreErrors, non-network, prolonged, sync error reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.sync = CREDENTIALS_CHANGED;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test dontIgnoreErrors, network, non-prolonged, login error reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.login = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test dontIgnoreErrors, network, non-prolonged, sync error reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.sync = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test dontIgnoreErrors, network, prolonged, login error reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.login = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test dontIgnoreErrors, network, prolonged, sync error reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.sync = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_true(errorHandler.shouldReportError());
+
+ // Test non-network, prolonged, login error reported
+ do_check_false(errorHandler.didReportProlongedError);
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.login = LOGIN_FAILED_NO_PASSWORD;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_true(errorHandler.didReportProlongedError);
+
+ // Second time with prolonged error and without resetting
+ // didReportProlongedError, sync error should not be reported.
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.login = LOGIN_FAILED_NO_PASSWORD;
+ do_check_false(errorHandler.shouldReportError());
+ do_check_true(errorHandler.didReportProlongedError);
+
+ // Test non-network, prolonged, sync error reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ errorHandler.didReportProlongedError = false;
+ Status.sync = CREDENTIALS_CHANGED;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_true(errorHandler.didReportProlongedError);
+ errorHandler.didReportProlongedError = false;
+
+ // Test network, prolonged, login error reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.login = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_true(errorHandler.didReportProlongedError);
+ errorHandler.didReportProlongedError = false;
+
+ // Test network, prolonged, sync error reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.sync = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_true(errorHandler.didReportProlongedError);
+ errorHandler.didReportProlongedError = false;
+
+ // Test non-network, non-prolonged, login error reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.login = LOGIN_FAILED_NO_PASSWORD;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test non-network, non-prolonged, sync error reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.sync = CREDENTIALS_CHANGED;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test network, non-prolonged, login error reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.login = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_false(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test network, non-prolonged, sync error reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.sync = LOGIN_FAILED_NETWORK_ERROR;
+ do_check_false(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test server maintenance, sync errors are not reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.sync = SERVER_MAINTENANCE;
+ do_check_false(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test server maintenance, login errors are not reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.login = SERVER_MAINTENANCE;
+ do_check_false(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test prolonged, server maintenance, sync errors are reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.sync = SERVER_MAINTENANCE;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_true(errorHandler.didReportProlongedError);
+ errorHandler.didReportProlongedError = false;
+
+ // Test prolonged, server maintenance, login errors are reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = false;
+ Status.login = SERVER_MAINTENANCE;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_true(errorHandler.didReportProlongedError);
+ errorHandler.didReportProlongedError = false;
+
+ // Test dontIgnoreErrors, server maintenance, sync errors are reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.sync = SERVER_MAINTENANCE;
+ do_check_true(errorHandler.shouldReportError());
+ // dontIgnoreErrors means we don't set didReportProlongedError
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test dontIgnoreErrors, server maintenance, login errors are reported
+ Status.resetSync();
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.login = SERVER_MAINTENANCE;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test dontIgnoreErrors, prolonged, server maintenance,
+ // sync errors are reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.sync = SERVER_MAINTENANCE;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+
+ // Test dontIgnoreErrors, prolonged, server maintenance,
+ // login errors are reported
+ Status.resetSync();
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.dontIgnoreErrors = true;
+ Status.login = SERVER_MAINTENANCE;
+ do_check_true(errorHandler.shouldReportError());
+ do_check_false(errorHandler.didReportProlongedError);
+});
+
+add_identity_test(this, function test_shouldReportError_master_password() {
+ _("Test error ignored due to locked master password");
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ // Monkey patch Service.verifyLogin to imitate
+ // master password being locked.
+ Service._verifyLogin = Service.verifyLogin;
+ Service.verifyLogin = function () {
+ Status.login = MASTER_PASSWORD_LOCKED;
+ return false;
+ };
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+ do_check_false(errorHandler.shouldReportError());
+
+ // Clean up.
+ Service.verifyLogin = Service._verifyLogin;
+ clean();
+ let deferred = Promise.defer();
+ server.stop(deferred.resolve);
+ yield deferred.promise;
+});
+
+// Test that even if we don't have a cluster URL, a login failure due to
+// authentication errors is always reported.
+add_identity_test(this, function test_shouldReportLoginFailureWithNoCluster() {
+ // Ensure no clusterURL - any error not specific to login should not be reported.
+ Service.serverURL = "";
+ Service.clusterURL = "";
+
+ // Test explicit "login rejected" state.
+ Status.resetSync();
+ // If we have a LOGIN_REJECTED state, we always report the error.
+ Status.login = LOGIN_FAILED_LOGIN_REJECTED;
+ do_check_true(errorHandler.shouldReportError());
+ // But any other status with a missing clusterURL is treated as a mid-sync
+ // 401 (ie, should be treated as a node reassignment)
+ Status.login = LOGIN_SUCCEEDED;
+ do_check_false(errorHandler.shouldReportError());
+});
+
+// XXX - how to arrange for 'Service.identity.basicPassword = null;' in
+// an fxaccounts environment?
+add_task(function test_login_syncAndReportErrors_non_network_error() {
+ // Test non-network errors are reported
+ // when calling syncAndReportErrors
+ let server = sync_httpd_setup();
+ yield setUp(server);
+ Service.identity.basicPassword = null;
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:login:error", onSyncError);
+ do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_sync_syncAndReportErrors_non_network_error() {
+ // Test non-network errors are reported
+ // when calling syncAndReportErrors
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ // By calling sync, we ensure we're logged in.
+ Service.sync();
+ do_check_eq(Status.sync, SYNC_SUCCEEDED);
+ do_check_true(Service.isLoggedIn);
+
+ generateCredentialsChangedFailure();
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+ do_check_eq(Status.sync, CREDENTIALS_CHANGED);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+// XXX - how to arrange for 'Service.identity.basicPassword = null;' in
+// an fxaccounts environment?
+add_task(function test_login_syncAndReportErrors_prolonged_non_network_error() {
+ // Test prolonged, non-network errors are
+ // reported when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+ Service.identity.basicPassword = null;
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:login:error", onSyncError);
+ do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_sync_syncAndReportErrors_prolonged_non_network_error() {
+ // Test prolonged, non-network errors are
+ // reported when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ // By calling sync, we ensure we're logged in.
+ Service.sync();
+ do_check_eq(Status.sync, SYNC_SUCCEEDED);
+ do_check_true(Service.isLoggedIn);
+
+ generateCredentialsChangedFailure();
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+ do_check_eq(Status.sync, CREDENTIALS_CHANGED);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_login_syncAndReportErrors_network_error() {
+ // Test network errors are reported when calling syncAndReportErrors.
+ yield configureIdentity({username: "broken.wipe"});
+ Service.serverURL = FAKE_SERVER_URL;
+ Service.clusterURL = FAKE_SERVER_URL;
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:login:error", onSyncError);
+ do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
+
+ clean();
+ deferred.resolve();
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+
+add_test(function test_sync_syncAndReportErrors_network_error() {
+ // Test network errors are reported when calling syncAndReportErrors.
+ Services.io.offline = true;
+
+ Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+ do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
+
+ Services.io.offline = false;
+ clean();
+ run_next_test();
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+});
+
+add_identity_test(this, function test_login_syncAndReportErrors_prolonged_network_error() {
+ // Test prolonged, network errors are reported
+ // when calling syncAndReportErrors.
+ yield configureIdentity({username: "johndoe"});
+
+ Service.serverURL = FAKE_SERVER_URL;
+ Service.clusterURL = FAKE_SERVER_URL;
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:login:error", onSyncError);
+ do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
+
+ clean();
+ deferred.resolve();
+ });
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_test(function test_sync_syncAndReportErrors_prolonged_network_error() {
+ // Test prolonged, network errors are reported
+ // when calling syncAndReportErrors.
+ Services.io.offline = true;
+
+ Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+ do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
+
+ Services.io.offline = false;
+ clean();
+ run_next_test();
+ });
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+});
+
+add_task(function test_login_prolonged_non_network_error() {
+ // Test prolonged, non-network errors are reported
+ let server = sync_httpd_setup();
+ yield setUp(server);
+ Service.identity.basicPassword = null;
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:login:error", onSyncError);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_task(function test_sync_prolonged_non_network_error() {
+ // Test prolonged, non-network errors are reported
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ // By calling sync, we ensure we're logged in.
+ Service.sync();
+ do_check_eq(Status.sync, SYNC_SUCCEEDED);
+ do_check_true(Service.isLoggedIn);
+
+ generateCredentialsChangedFailure();
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_login_prolonged_network_error() {
+ // Test prolonged, network errors are reported
+ yield configureIdentity({username: "johndoe"});
+ Service.serverURL = FAKE_SERVER_URL;
+ Service.clusterURL = FAKE_SERVER_URL;
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:login:error", onSyncError);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ deferred.resolve();
+ });
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_test(function test_sync_prolonged_network_error() {
+ // Test prolonged, network errors are reported
+ Services.io.offline = true;
+
+ Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ Services.io.offline = false;
+ clean();
+ run_next_test();
+ });
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+});
+
+add_task(function test_login_non_network_error() {
+ // Test non-network errors are reported
+ let server = sync_httpd_setup();
+ yield setUp(server);
+ Service.identity.basicPassword = null;
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:login:error", onSyncError);
+ do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_task(function test_sync_non_network_error() {
+ // Test non-network errors are reported
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ // By calling sync, we ensure we're logged in.
+ Service.sync();
+ do_check_eq(Status.sync, SYNC_SUCCEEDED);
+ do_check_true(Service.isLoggedIn);
+
+ generateCredentialsChangedFailure();
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
+ Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+ do_check_eq(Status.sync, CREDENTIALS_CHANGED);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_login_network_error() {
+ yield configureIdentity({username: "johndoe"});
+ Service.serverURL = FAKE_SERVER_URL;
+ Service.clusterURL = FAKE_SERVER_URL;
+
+ let deferred = Promise.defer();
+ // Test network errors are not reported.
+ Svc.Obs.add("weave:ui:clear-error", function onClearError() {
+ Svc.Obs.remove("weave:ui:clear-error", onClearError);
+
+ do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ Services.io.offline = false;
+ clean();
+ deferred.resolve()
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_test(function test_sync_network_error() {
+ // Test network errors are not reported.
+ Services.io.offline = true;
+
+ Svc.Obs.add("weave:ui:sync:finish", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:sync:finish", onUIUpdate);
+ do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ Services.io.offline = false;
+ clean();
+ run_next_test();
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+});
+
+add_identity_test(this, function test_sync_server_maintenance_error() {
+ // Test server maintenance errors are not reported.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ const BACKOFF = 42;
+ let engine = engineManager.get("catapult");
+ engine.enabled = true;
+ engine.exception = {status: 503,
+ headers: {"retry-after": BACKOFF}};
+
+ function onSyncError() {
+ do_throw("Shouldn't get here!");
+ }
+ Svc.Obs.add("weave:ui:sync:error", onSyncError);
+
+ do_check_eq(Status.service, STATUS_OK);
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:finish", function onSyncFinish() {
+ Svc.Obs.remove("weave:ui:sync:finish", onSyncFinish);
+
+ do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
+ do_check_eq(Status.sync, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_info_collections_login_server_maintenance_error() {
+ // Test info/collections server maintenance errors are not reported.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ Service.username = "broken.info";
+ yield configureIdentity({username: "broken.info"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ function onUIUpdate() {
+ do_throw("Shouldn't experience UI update!");
+ }
+ Svc.Obs.add("weave:ui:login:error", onUIUpdate);
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
+ Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
+
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_meta_global_login_server_maintenance_error() {
+ // Test meta/global server maintenance errors are not reported.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.meta"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ function onUIUpdate() {
+ do_throw("Shouldn't get here!");
+ }
+ Svc.Obs.add("weave:ui:login:error", onUIUpdate);
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
+ Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
+
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_crypto_keys_login_server_maintenance_error() {
+ // Test crypto/keys server maintenance errors are not reported.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.keys"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ // Force re-download of keys
+ Service.collectionKeys.clear();
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ function onUIUpdate() {
+ do_throw("Shouldn't get here!");
+ }
+ Svc.Obs.add("weave:ui:login:error", onUIUpdate);
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
+ Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
+
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_task(function test_sync_prolonged_server_maintenance_error() {
+ // Test prolonged server maintenance errors are reported.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ const BACKOFF = 42;
+ let engine = engineManager.get("catapult");
+ engine.enabled = true;
+ engine.exception = {status: 503,
+ headers: {"retry-after": BACKOFF}};
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
+ do_check_eq(Status.service, SYNC_FAILED);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_info_collections_login_prolonged_server_maintenance_error(){
+ // Test info/collections prolonged server maintenance errors are reported.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.info"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, SYNC_FAILED);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_meta_global_login_prolonged_server_maintenance_error(){
+ // Test meta/global prolonged server maintenance errors are reported.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.meta"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, SYNC_FAILED);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_download_crypto_keys_login_prolonged_server_maintenance_error(){
+ // Test crypto/keys prolonged server maintenance errors are reported.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.keys"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+ // Force re-download of keys
+ Service.collectionKeys.clear();
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, SYNC_FAILED);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_upload_crypto_keys_login_prolonged_server_maintenance_error(){
+ // Test crypto/keys prolonged server maintenance errors are reported.
+ let server = sync_httpd_setup();
+
+ // Start off with an empty account, do not upload a key.
+ yield configureIdentity({username: "broken.keys"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, SYNC_FAILED);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_wipeServer_login_prolonged_server_maintenance_error(){
+ // Test that we report prolonged server maintenance errors that occur whilst
+ // wiping the server.
+ let server = sync_httpd_setup();
+
+ // Start off with an empty account, do not upload a key.
+ yield configureIdentity({username: "broken.wipe"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, SYNC_FAILED);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_wipeRemote_prolonged_server_maintenance_error(){
+ // Test that we report prolonged server maintenance errors that occur whilst
+ // wiping all remote devices.
+ let server = sync_httpd_setup();
+
+ server.registerPathHandler("/1.1/broken.wipe/storage/catapult", service_unavailable);
+ yield configureIdentity({username: "broken.wipe"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+ generateAndUploadKeys();
+
+ let engine = engineManager.get("catapult");
+ engine.exception = null;
+ engine.enabled = true;
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, SYNC_FAILED);
+ do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+ do_check_eq(Svc.Prefs.get("firstSync"), "wipeRemote");
+ do_check_true(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ Svc.Prefs.set("firstSync", "wipeRemote");
+ setLastSync(PROLONGED_ERROR_DURATION);
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_task(function test_sync_syncAndReportErrors_server_maintenance_error() {
+ // Test server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ const BACKOFF = 42;
+ let engine = engineManager.get("catapult");
+ engine.enabled = true;
+ engine.exception = {status: 503,
+ headers: {"retry-after": BACKOFF}};
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
+ do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
+ do_check_eq(Status.sync, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_info_collections_login_syncAndReportErrors_server_maintenance_error() {
+ // Test info/collections server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.info"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_meta_global_login_syncAndReportErrors_server_maintenance_error() {
+ // Test meta/global server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.meta"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_download_crypto_keys_login_syncAndReportErrors_server_maintenance_error() {
+ // Test crypto/keys server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.keys"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+ // Force re-download of keys
+ Service.collectionKeys.clear();
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_upload_crypto_keys_login_syncAndReportErrors_server_maintenance_error() {
+ // Test crypto/keys server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+
+ // Start off with an empty account, do not upload a key.
+ yield configureIdentity({username: "broken.keys"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_wipeServer_login_syncAndReportErrors_server_maintenance_error() {
+ // Test crypto/keys server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+
+ // Start off with an empty account, do not upload a key.
+ yield configureIdentity({username: "broken.wipe"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_wipeRemote_syncAndReportErrors_server_maintenance_error(){
+ // Test that we report prolonged server maintenance errors that occur whilst
+ // wiping all remote devices.
+ let server = sync_httpd_setup();
+
+ yield configureIdentity({username: "broken.wipe"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+ generateAndUploadKeys();
+
+ let engine = engineManager.get("catapult");
+ engine.exception = null;
+ engine.enabled = true;
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, SYNC_FAILED);
+ do_check_eq(Status.sync, SERVER_MAINTENANCE);
+ do_check_eq(Svc.Prefs.get("firstSync"), "wipeRemote");
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ Svc.Prefs.set("firstSync", "wipeRemote");
+ setLastSync(NON_PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_task(function test_sync_syncAndReportErrors_prolonged_server_maintenance_error() {
+ // Test prolonged server maintenance errors are
+ // reported when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ const BACKOFF = 42;
+ let engine = engineManager.get("catapult");
+ engine.enabled = true;
+ engine.exception = {status: 503,
+ headers: {"retry-after": BACKOFF}};
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
+ do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
+ do_check_eq(Status.sync, SERVER_MAINTENANCE);
+ // syncAndReportErrors means dontIgnoreErrors, which means
+ // didReportProlongedError not touched.
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_info_collections_login_syncAndReportErrors_prolonged_server_maintenance_error() {
+ // Test info/collections server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.info"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ // syncAndReportErrors means dontIgnoreErrors, which means
+ // didReportProlongedError not touched.
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_meta_global_login_syncAndReportErrors_prolonged_server_maintenance_error() {
+ // Test meta/global server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.meta"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ // syncAndReportErrors means dontIgnoreErrors, which means
+ // didReportProlongedError not touched.
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_download_crypto_keys_login_syncAndReportErrors_prolonged_server_maintenance_error() {
+ // Test crypto/keys server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+ yield setUp(server);
+
+ yield configureIdentity({username: "broken.keys"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+ // Force re-download of keys
+ Service.collectionKeys.clear();
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ // syncAndReportErrors means dontIgnoreErrors, which means
+ // didReportProlongedError not touched.
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_upload_crypto_keys_login_syncAndReportErrors_prolonged_server_maintenance_error() {
+ // Test crypto/keys server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+
+ // Start off with an empty account, do not upload a key.
+ yield configureIdentity({username: "broken.keys"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ // syncAndReportErrors means dontIgnoreErrors, which means
+ // didReportProlongedError not touched.
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_identity_test(this, function test_wipeServer_login_syncAndReportErrors_prolonged_server_maintenance_error() {
+ // Test crypto/keys server maintenance errors are reported
+ // when calling syncAndReportErrors.
+ let server = sync_httpd_setup();
+
+ // Start off with an empty account, do not upload a key.
+ yield configureIdentity({username: "broken.wipe"});
+ Service.serverURL = server.baseURI + "/maintenance/";
+ Service.clusterURL = server.baseURI + "/maintenance/";
+
+ let backoffInterval;
+ Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
+ Svc.Obs.remove("weave:service:backoff:interval", observe);
+ backoffInterval = subject;
+ });
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
+ Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
+ do_check_true(Status.enforceBackoff);
+ do_check_eq(backoffInterval, 42);
+ do_check_eq(Status.service, LOGIN_FAILED);
+ do_check_eq(Status.login, SERVER_MAINTENANCE);
+ // syncAndReportErrors means dontIgnoreErrors, which means
+ // didReportProlongedError not touched.
+ do_check_false(errorHandler.didReportProlongedError);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_false(Status.enforceBackoff);
+ do_check_eq(Status.service, STATUS_OK);
+
+ setLastSync(PROLONGED_ERROR_DURATION);
+ errorHandler.syncAndReportErrors();
+ yield deferred.promise;
+});
+
+add_task(function test_sync_engine_generic_fail() {
+ let server = sync_httpd_setup();
+
+ let engine = engineManager.get("catapult");
+ engine.enabled = true;
+ engine.sync = function sync() {
+ Svc.Obs.notify("weave:engine:sync:error", "", "catapult");
+ };
+
+ let log = Log.repository.getLogger("Sync.ErrorHandler");
+ Svc.Prefs.set("log.appender.file.logOnError", true);
+
+ do_check_eq(Status.engines["catapult"], undefined);
+
+ let deferred = Promise.defer();
+ // Don't wait for reset-file-log until the sync is underway.
+ // This avoids us catching a delayed notification from an earlier test.
+ Svc.Obs.add("weave:engine:sync:finish", function onEngineFinish() {
+ Svc.Obs.remove("weave:engine:sync:finish", onEngineFinish);
+
+ log.info("Adding reset-file-log observer.");
+ Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
+ Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
+
+ // Put these checks here, not after sync(), so that we aren't racing the
+ // log handler... which resets everything just a few lines below!
+ _("Status.engines: " + JSON.stringify(Status.engines));
+ do_check_eq(Status.engines["catapult"], ENGINE_UNKNOWN_FAIL);
+ do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
+
+ // Test Error log was written on SYNC_FAILED_PARTIAL.
+ let entries = logsdir.directoryEntries;
+ do_check_true(entries.hasMoreElements());
+ let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
+ do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+ });
+
+ do_check_true(yield setUp(server));
+ Service.sync();
+ yield deferred.promise;
+});
+
+add_test(function test_logs_on_sync_error_despite_shouldReportError() {
+ _("Ensure that an error is still logged when weave:service:sync:error " +
+ "is notified, despite shouldReportError returning false.");
+
+ let log = Log.repository.getLogger("Sync.ErrorHandler");
+ Svc.Prefs.set("log.appender.file.logOnError", true);
+ log.info("TESTING");
+
+ // Ensure that we report no error.
+ Status.login = MASTER_PASSWORD_LOCKED;
+ do_check_false(errorHandler.shouldReportError());
+
+ Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
+ Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
+
+ // Test that error log was written.
+ let entries = logsdir.directoryEntries;
+ do_check_true(entries.hasMoreElements());
+ let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
+ do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
+
+ clean();
+ run_next_test();
+ });
+ Svc.Obs.notify("weave:service:sync:error", {});
+});
+
+add_test(function test_logs_on_login_error_despite_shouldReportError() {
+ _("Ensure that an error is still logged when weave:service:login:error " +
+ "is notified, despite shouldReportError returning false.");
+
+ let log = Log.repository.getLogger("Sync.ErrorHandler");
+ Svc.Prefs.set("log.appender.file.logOnError", true);
+ log.info("TESTING");
+
+ // Ensure that we report no error.
+ Status.login = MASTER_PASSWORD_LOCKED;
+ do_check_false(errorHandler.shouldReportError());
+
+ Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
+ Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
+
+ // Test that error log was written.
+ let entries = logsdir.directoryEntries;
+ do_check_true(entries.hasMoreElements());
+ let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
+ do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
+
+ clean();
+ run_next_test();
+ });
+ Svc.Obs.notify("weave:service:login:error", {});
+});
+
+// This test should be the last one since it monkeypatches the engine object
+// and we should only have one engine object throughout the file (bug 629664).
+add_task(function test_engine_applyFailed() {
+ let server = sync_httpd_setup();
+
+ let engine = engineManager.get("catapult");
+ engine.enabled = true;
+ delete engine.exception;
+ engine.sync = function sync() {
+ Svc.Obs.notify("weave:engine:sync:applied", {newFailed:1}, "catapult");
+ };
+
+ let log = Log.repository.getLogger("Sync.ErrorHandler");
+ Svc.Prefs.set("log.appender.file.logOnError", true);
+
+ let deferred = Promise.defer();
+ Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
+ Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
+
+ do_check_eq(Status.engines["catapult"], ENGINE_APPLY_FAIL);
+ do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
+
+ // Test Error log was written on SYNC_FAILED_PARTIAL.
+ let entries = logsdir.directoryEntries;
+ do_check_true(entries.hasMoreElements());
+ let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
+ do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
+
+ clean();
+ server.stop(deferred.resolve);
+ });
+
+ do_check_eq(Status.engines["catapult"], undefined);
+ do_check_true(yield setUp(server));
+ Service.sync();
+ yield deferred.promise;
+});
diff --git a/services/sync/tests/unit/test_errorhandler_1.js b/services/sync/tests/unit/test_errorhandler_1.js
deleted file mode 100644
index ea2070b48..000000000
--- a/services/sync/tests/unit/test_errorhandler_1.js
+++ /dev/null
@@ -1,913 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/engines/clients.js");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://services-sync/keys.js");
-Cu.import("resource://services-sync/policies.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/status.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://gre/modules/FileUtils.jsm");
-
-var fakeServer = new SyncServer();
-fakeServer.start();
-
-do_register_cleanup(function() {
- return new Promise(resolve => {
- fakeServer.stop(resolve);
- });
-});
-
-var fakeServerUrl = "http://localhost:" + fakeServer.port;
-
-const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
-
-const PROLONGED_ERROR_DURATION =
- (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000;
-
-const NON_PROLONGED_ERROR_DURATION =
- (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') / 2) * 1000;
-
-Service.engineManager.clear();
-
-function setLastSync(lastSyncValue) {
- Svc.Prefs.set("lastSync", (new Date(Date.now() - lastSyncValue)).toString());
-}
-
-var engineManager = Service.engineManager;
-engineManager.register(EHTestsCommon.CatapultEngine);
-
-// This relies on Service/ErrorHandler being a singleton. Fixing this will take
-// a lot of work.
-var errorHandler = Service.errorHandler;
-
-function run_test() {
- initTestLogging("Trace");
-
- Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
-
- ensureLegacyIdentityManager();
-
- run_next_test();
-}
-
-
-function clean() {
- Service.startOver();
- Status.resetSync();
- Status.resetBackoff();
- errorHandler.didReportProlongedError = false;
-}
-
-add_identity_test(this, function* test_401_logout() {
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- // By calling sync, we ensure we're logged in.
- yield sync_and_validate_telem();
- do_check_eq(Status.sync, SYNC_SUCCEEDED);
- do_check_true(Service.isLoggedIn);
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:service:sync:error", onSyncError);
- function onSyncError() {
- _("Got weave:service:sync:error in first sync.");
- Svc.Obs.remove("weave:service:sync:error", onSyncError);
-
- // Wait for the automatic next sync.
- function onLoginError() {
- _("Got weave:service:login:error in second sync.");
- Svc.Obs.remove("weave:service:login:error", onLoginError);
-
- let expected = isConfiguredWithLegacyIdentity() ?
- LOGIN_FAILED_LOGIN_REJECTED : LOGIN_FAILED_NETWORK_ERROR;
-
- do_check_eq(Status.login, expected);
- do_check_false(Service.isLoggedIn);
-
- // Clean up.
- Utils.nextTick(function () {
- Service.startOver();
- server.stop(deferred.resolve);
- });
- }
- Svc.Obs.add("weave:service:login:error", onLoginError);
- }
-
- // Make sync fail due to login rejected.
- yield configureIdentity({username: "janedoe"});
- Service._updateCachedURLs();
-
- _("Starting first sync.");
- let ping = yield sync_and_validate_telem(true);
- deepEqual(ping.failureReason, { name: "httperror", code: 401 });
- _("First sync done.");
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_credentials_changed_logout() {
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- // By calling sync, we ensure we're logged in.
- yield sync_and_validate_telem();
- do_check_eq(Status.sync, SYNC_SUCCEEDED);
- do_check_true(Service.isLoggedIn);
-
- EHTestsCommon.generateCredentialsChangedFailure();
-
- let ping = yield sync_and_validate_telem(true);
- equal(ping.status.sync, CREDENTIALS_CHANGED);
- deepEqual(ping.failureReason, {
- name: "unexpectederror",
- error: "Error: Aborting sync, remote setup failed"
- });
-
- do_check_eq(Status.sync, CREDENTIALS_CHANGED);
- do_check_false(Service.isLoggedIn);
-
- // Clean up.
- Service.startOver();
- let deferred = Promise.defer();
- server.stop(deferred.resolve);
- yield deferred.promise;
-});
-
-add_identity_test(this, function test_no_lastSync_pref() {
- // Test reported error.
- Status.resetSync();
- errorHandler.dontIgnoreErrors = true;
- Status.sync = CREDENTIALS_CHANGED;
- do_check_true(errorHandler.shouldReportError());
-
- // Test unreported error.
- Status.resetSync();
- errorHandler.dontIgnoreErrors = true;
- Status.login = LOGIN_FAILED_NETWORK_ERROR;
- do_check_true(errorHandler.shouldReportError());
-
-});
-
-add_identity_test(this, function test_shouldReportError() {
- Status.login = MASTER_PASSWORD_LOCKED;
- do_check_false(errorHandler.shouldReportError());
-
- // Give ourselves a clusterURL so that the temporary 401 no-error situation
- // doesn't come into play.
- Service.serverURL = fakeServerUrl;
- Service.clusterURL = fakeServerUrl;
-
- // Test dontIgnoreErrors, non-network, non-prolonged, login error reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.login = LOGIN_FAILED_NO_PASSWORD;
- do_check_true(errorHandler.shouldReportError());
-
- // Test dontIgnoreErrors, non-network, non-prolonged, sync error reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.sync = CREDENTIALS_CHANGED;
- do_check_true(errorHandler.shouldReportError());
-
- // Test dontIgnoreErrors, non-network, prolonged, login error reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.login = LOGIN_FAILED_NO_PASSWORD;
- do_check_true(errorHandler.shouldReportError());
-
- // Test dontIgnoreErrors, non-network, prolonged, sync error reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.sync = CREDENTIALS_CHANGED;
- do_check_true(errorHandler.shouldReportError());
-
- // Test dontIgnoreErrors, network, non-prolonged, login error reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.login = LOGIN_FAILED_NETWORK_ERROR;
- do_check_true(errorHandler.shouldReportError());
-
- // Test dontIgnoreErrors, network, non-prolonged, sync error reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.sync = LOGIN_FAILED_NETWORK_ERROR;
- do_check_true(errorHandler.shouldReportError());
-
- // Test dontIgnoreErrors, network, prolonged, login error reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.login = LOGIN_FAILED_NETWORK_ERROR;
- do_check_true(errorHandler.shouldReportError());
-
- // Test dontIgnoreErrors, network, prolonged, sync error reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.sync = LOGIN_FAILED_NETWORK_ERROR;
- do_check_true(errorHandler.shouldReportError());
-
- // Test non-network, prolonged, login error reported
- do_check_false(errorHandler.didReportProlongedError);
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.login = LOGIN_FAILED_NO_PASSWORD;
- do_check_true(errorHandler.shouldReportError());
- do_check_true(errorHandler.didReportProlongedError);
-
- // Second time with prolonged error and without resetting
- // didReportProlongedError, sync error should not be reported.
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.login = LOGIN_FAILED_NO_PASSWORD;
- do_check_false(errorHandler.shouldReportError());
- do_check_true(errorHandler.didReportProlongedError);
-
- // Test non-network, prolonged, sync error reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- errorHandler.didReportProlongedError = false;
- Status.sync = CREDENTIALS_CHANGED;
- do_check_true(errorHandler.shouldReportError());
- do_check_true(errorHandler.didReportProlongedError);
- errorHandler.didReportProlongedError = false;
-
- // Test network, prolonged, login error reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.login = LOGIN_FAILED_NETWORK_ERROR;
- do_check_true(errorHandler.shouldReportError());
- do_check_true(errorHandler.didReportProlongedError);
- errorHandler.didReportProlongedError = false;
-
- // Test network, prolonged, sync error reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.sync = LOGIN_FAILED_NETWORK_ERROR;
- do_check_true(errorHandler.shouldReportError());
- do_check_true(errorHandler.didReportProlongedError);
- errorHandler.didReportProlongedError = false;
-
- // Test non-network, non-prolonged, login error reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.login = LOGIN_FAILED_NO_PASSWORD;
- do_check_true(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test non-network, non-prolonged, sync error reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.sync = CREDENTIALS_CHANGED;
- do_check_true(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test network, non-prolonged, login error reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.login = LOGIN_FAILED_NETWORK_ERROR;
- do_check_false(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test network, non-prolonged, sync error reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.sync = LOGIN_FAILED_NETWORK_ERROR;
- do_check_false(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test server maintenance, sync errors are not reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.sync = SERVER_MAINTENANCE;
- do_check_false(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test server maintenance, login errors are not reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.login = SERVER_MAINTENANCE;
- do_check_false(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test prolonged, server maintenance, sync errors are reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.sync = SERVER_MAINTENANCE;
- do_check_true(errorHandler.shouldReportError());
- do_check_true(errorHandler.didReportProlongedError);
- errorHandler.didReportProlongedError = false;
-
- // Test prolonged, server maintenance, login errors are reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = false;
- Status.login = SERVER_MAINTENANCE;
- do_check_true(errorHandler.shouldReportError());
- do_check_true(errorHandler.didReportProlongedError);
- errorHandler.didReportProlongedError = false;
-
- // Test dontIgnoreErrors, server maintenance, sync errors are reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.sync = SERVER_MAINTENANCE;
- do_check_true(errorHandler.shouldReportError());
- // dontIgnoreErrors means we don't set didReportProlongedError
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test dontIgnoreErrors, server maintenance, login errors are reported
- Status.resetSync();
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.login = SERVER_MAINTENANCE;
- do_check_true(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test dontIgnoreErrors, prolonged, server maintenance,
- // sync errors are reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.sync = SERVER_MAINTENANCE;
- do_check_true(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-
- // Test dontIgnoreErrors, prolonged, server maintenance,
- // login errors are reported
- Status.resetSync();
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.dontIgnoreErrors = true;
- Status.login = SERVER_MAINTENANCE;
- do_check_true(errorHandler.shouldReportError());
- do_check_false(errorHandler.didReportProlongedError);
-});
-
-add_identity_test(this, function* test_shouldReportError_master_password() {
- _("Test error ignored due to locked master password");
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- // Monkey patch Service.verifyLogin to imitate
- // master password being locked.
- Service._verifyLogin = Service.verifyLogin;
- Service.verifyLogin = function () {
- Status.login = MASTER_PASSWORD_LOCKED;
- return false;
- };
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- Service.sync();
- do_check_false(errorHandler.shouldReportError());
-
- // Clean up.
- Service.verifyLogin = Service._verifyLogin;
- clean();
- let deferred = Promise.defer();
- server.stop(deferred.resolve);
- yield deferred.promise;
-});
-
-// Test that even if we don't have a cluster URL, a login failure due to
-// authentication errors is always reported.
-add_identity_test(this, function test_shouldReportLoginFailureWithNoCluster() {
- // Ensure no clusterURL - any error not specific to login should not be reported.
- Service.serverURL = "";
- Service.clusterURL = "";
-
- // Test explicit "login rejected" state.
- Status.resetSync();
- // If we have a LOGIN_REJECTED state, we always report the error.
- Status.login = LOGIN_FAILED_LOGIN_REJECTED;
- do_check_true(errorHandler.shouldReportError());
- // But any other status with a missing clusterURL is treated as a mid-sync
- // 401 (ie, should be treated as a node reassignment)
- Status.login = LOGIN_SUCCEEDED;
- do_check_false(errorHandler.shouldReportError());
-});
-
-// XXX - how to arrange for 'Service.identity.basicPassword = null;' in
-// an fxaccounts environment?
-add_task(function* test_login_syncAndReportErrors_non_network_error() {
- // Test non-network errors are reported
- // when calling syncAndReportErrors
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
- Service.identity.basicPassword = null;
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:login:error", onSyncError);
- do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_sync_syncAndReportErrors_non_network_error() {
- // Test non-network errors are reported
- // when calling syncAndReportErrors
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- // By calling sync, we ensure we're logged in.
- Service.sync();
- do_check_eq(Status.sync, SYNC_SUCCEEDED);
- do_check_true(Service.isLoggedIn);
-
- EHTestsCommon.generateCredentialsChangedFailure();
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:sync:error", onSyncError);
- do_check_eq(Status.sync, CREDENTIALS_CHANGED);
- // If we clean this tick, telemetry won't get the right error
- server.stop(() => {
- clean();
- deferred.resolve();
- });
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- let ping = yield wait_for_ping(() => errorHandler.syncAndReportErrors(), true);
- equal(ping.status.sync, CREDENTIALS_CHANGED);
- deepEqual(ping.failureReason, {
- name: "unexpectederror",
- error: "Error: Aborting sync, remote setup failed"
- });
- yield deferred.promise;
-});
-
-// XXX - how to arrange for 'Service.identity.basicPassword = null;' in
-// an fxaccounts environment?
-add_task(function* test_login_syncAndReportErrors_prolonged_non_network_error() {
- // Test prolonged, non-network errors are
- // reported when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
- Service.identity.basicPassword = null;
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:login:error", onSyncError);
- do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_sync_syncAndReportErrors_prolonged_non_network_error() {
- // Test prolonged, non-network errors are
- // reported when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- // By calling sync, we ensure we're logged in.
- Service.sync();
- do_check_eq(Status.sync, SYNC_SUCCEEDED);
- do_check_true(Service.isLoggedIn);
-
- EHTestsCommon.generateCredentialsChangedFailure();
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:sync:error", onSyncError);
- do_check_eq(Status.sync, CREDENTIALS_CHANGED);
- // If we clean this tick, telemetry won't get the right error
- server.stop(() => {
- clean();
- deferred.resolve();
- });
- });
-
- setLastSync(PROLONGED_ERROR_DURATION);
- let ping = yield wait_for_ping(() => errorHandler.syncAndReportErrors(), true);
- equal(ping.status.sync, CREDENTIALS_CHANGED);
- deepEqual(ping.failureReason, {
- name: "unexpectederror",
- error: "Error: Aborting sync, remote setup failed"
- });
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_login_syncAndReportErrors_network_error() {
- // Test network errors are reported when calling syncAndReportErrors.
- yield configureIdentity({username: "broken.wipe"});
- Service.serverURL = fakeServerUrl;
- Service.clusterURL = fakeServerUrl;
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:login:error", onSyncError);
- do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
-
- clean();
- deferred.resolve();
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-
-add_test(function test_sync_syncAndReportErrors_network_error() {
- // Test network errors are reported when calling syncAndReportErrors.
- Services.io.offline = true;
-
- Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:sync:error", onSyncError);
- do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
-
- Services.io.offline = false;
- clean();
- run_next_test();
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
-});
-
-add_identity_test(this, function* test_login_syncAndReportErrors_prolonged_network_error() {
- // Test prolonged, network errors are reported
- // when calling syncAndReportErrors.
- yield configureIdentity({username: "johndoe"});
-
- Service.serverURL = fakeServerUrl;
- Service.clusterURL = fakeServerUrl;
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:login:error", onSyncError);
- do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
-
- clean();
- deferred.resolve();
- });
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_test(function test_sync_syncAndReportErrors_prolonged_network_error() {
- // Test prolonged, network errors are reported
- // when calling syncAndReportErrors.
- Services.io.offline = true;
-
- Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:sync:error", onSyncError);
- do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
-
- Services.io.offline = false;
- clean();
- run_next_test();
- });
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
-});
-
-add_task(function* test_login_prolonged_non_network_error() {
- // Test prolonged, non-network errors are reported
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
- Service.identity.basicPassword = null;
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:login:error", onSyncError);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- setLastSync(PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_task(function* test_sync_prolonged_non_network_error() {
- // Test prolonged, non-network errors are reported
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- // By calling sync, we ensure we're logged in.
- Service.sync();
- do_check_eq(Status.sync, SYNC_SUCCEEDED);
- do_check_true(Service.isLoggedIn);
-
- EHTestsCommon.generateCredentialsChangedFailure();
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:sync:error", onSyncError);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
- server.stop(() => {
- clean();
- deferred.resolve();
- });
- });
-
- setLastSync(PROLONGED_ERROR_DURATION);
-
- let ping = yield sync_and_validate_telem(true);
- equal(ping.status.sync, PROLONGED_SYNC_FAILURE);
- deepEqual(ping.failureReason, {
- name: "unexpectederror",
- error: "Error: Aborting sync, remote setup failed"
- });
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_login_prolonged_network_error() {
- // Test prolonged, network errors are reported
- yield configureIdentity({username: "johndoe"});
- Service.serverURL = fakeServerUrl;
- Service.clusterURL = fakeServerUrl;
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:login:error", onSyncError);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- clean();
- deferred.resolve();
- });
-
- setLastSync(PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_test(function test_sync_prolonged_network_error() {
- // Test prolonged, network errors are reported
- Services.io.offline = true;
-
- Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:sync:error", onSyncError);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- Services.io.offline = false;
- clean();
- run_next_test();
- });
-
- setLastSync(PROLONGED_ERROR_DURATION);
- Service.sync();
-});
-
-add_task(function* test_login_non_network_error() {
- // Test non-network errors are reported
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
- Service.identity.basicPassword = null;
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:login:error", onSyncError);
- do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_task(function* test_sync_non_network_error() {
- // Test non-network errors are reported
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- // By calling sync, we ensure we're logged in.
- Service.sync();
- do_check_eq(Status.sync, SYNC_SUCCEEDED);
- do_check_true(Service.isLoggedIn);
-
- EHTestsCommon.generateCredentialsChangedFailure();
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
- Svc.Obs.remove("weave:ui:sync:error", onSyncError);
- do_check_eq(Status.sync, CREDENTIALS_CHANGED);
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_login_network_error() {
- yield configureIdentity({username: "johndoe"});
- Service.serverURL = fakeServerUrl;
- Service.clusterURL = fakeServerUrl;
-
- let deferred = Promise.defer();
- // Test network errors are not reported.
- Svc.Obs.add("weave:ui:clear-error", function onClearError() {
- Svc.Obs.remove("weave:ui:clear-error", onClearError);
-
- do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
- do_check_false(errorHandler.didReportProlongedError);
-
- Services.io.offline = false;
- clean();
- deferred.resolve()
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_test(function test_sync_network_error() {
- // Test network errors are not reported.
- Services.io.offline = true;
-
- Svc.Obs.add("weave:ui:sync:finish", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:sync:finish", onUIUpdate);
- do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
- do_check_false(errorHandler.didReportProlongedError);
-
- Services.io.offline = false;
- clean();
- run_next_test();
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- Service.sync();
-});
-
-add_identity_test(this, function* test_sync_server_maintenance_error() {
- // Test server maintenance errors are not reported.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- const BACKOFF = 42;
- let engine = engineManager.get("catapult");
- engine.enabled = true;
- engine.exception = {status: 503,
- headers: {"retry-after": BACKOFF}};
-
- function onSyncError() {
- do_throw("Shouldn't get here!");
- }
- Svc.Obs.add("weave:ui:sync:error", onSyncError);
-
- do_check_eq(Status.service, STATUS_OK);
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:finish", function onSyncFinish() {
- Svc.Obs.remove("weave:ui:sync:finish", onSyncFinish);
-
- do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
- do_check_eq(Status.sync, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- Svc.Obs.remove("weave:ui:sync:error", onSyncError);
- server.stop(() => {
- clean();
- deferred.resolve();
- })
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- let ping = yield sync_and_validate_telem(true);
- equal(ping.status.sync, SERVER_MAINTENANCE);
- deepEqual(ping.engines.find(e => e.failureReason).failureReason, { name: "httperror", code: 503 })
-
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_info_collections_login_server_maintenance_error() {
- // Test info/collections server maintenance errors are not reported.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- Service.username = "broken.info";
- yield configureIdentity({username: "broken.info"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- function onUIUpdate() {
- do_throw("Shouldn't experience UI update!");
- }
- Svc.Obs.add("weave:ui:login:error", onUIUpdate);
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
- Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
-
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- clean();
- server.stop(deferred.resolve);
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_meta_global_login_server_maintenance_error() {
- // Test meta/global server maintenance errors are not reported.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.meta"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- function onUIUpdate() {
- do_throw("Shouldn't get here!");
- }
- Svc.Obs.add("weave:ui:login:error", onUIUpdate);
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
- Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
-
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- clean();
- server.stop(deferred.resolve);
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
diff --git a/services/sync/tests/unit/test_errorhandler_2.js b/services/sync/tests/unit/test_errorhandler_2.js
deleted file mode 100644
index 41f8ee727..000000000
--- a/services/sync/tests/unit/test_errorhandler_2.js
+++ /dev/null
@@ -1,1012 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/engines/clients.js");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://services-sync/keys.js");
-Cu.import("resource://services-sync/policies.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/status.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://gre/modules/FileUtils.jsm");
-
-var fakeServer = new SyncServer();
-fakeServer.start();
-
-do_register_cleanup(function() {
- return new Promise(resolve => {
- fakeServer.stop(resolve);
- });
-});
-
-var fakeServerUrl = "http://localhost:" + fakeServer.port;
-
-const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
-
-const PROLONGED_ERROR_DURATION =
- (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000;
-
-const NON_PROLONGED_ERROR_DURATION =
- (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') / 2) * 1000;
-
-Service.engineManager.clear();
-
-function setLastSync(lastSyncValue) {
- Svc.Prefs.set("lastSync", (new Date(Date.now() - lastSyncValue)).toString());
-}
-
-var engineManager = Service.engineManager;
-engineManager.register(EHTestsCommon.CatapultEngine);
-
-// This relies on Service/ErrorHandler being a singleton. Fixing this will take
-// a lot of work.
-var errorHandler = Service.errorHandler;
-
-function run_test() {
- initTestLogging("Trace");
-
- Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
-
- ensureLegacyIdentityManager();
-
- run_next_test();
-}
-
-
-function clean() {
- Service.startOver();
- Status.resetSync();
- Status.resetBackoff();
- errorHandler.didReportProlongedError = false;
-}
-
-add_identity_test(this, function* test_crypto_keys_login_server_maintenance_error() {
- Status.resetSync();
- // Test crypto/keys server maintenance errors are not reported.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.keys"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- // Force re-download of keys
- Service.collectionKeys.clear();
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- function onUIUpdate() {
- do_throw("Shouldn't get here!");
- }
- Svc.Obs.add("weave:ui:login:error", onUIUpdate);
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
- Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
-
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- clean();
- server.stop(deferred.resolve);
- });
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_task(function* test_sync_prolonged_server_maintenance_error() {
- // Test prolonged server maintenance errors are reported.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- const BACKOFF = 42;
- let engine = engineManager.get("catapult");
- engine.enabled = true;
- engine.exception = {status: 503,
- headers: {"retry-after": BACKOFF}};
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
- do_check_eq(Status.service, SYNC_FAILED);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- server.stop(() => {
- clean();
- deferred.resolve();
- });
- });
-
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- let ping = yield sync_and_validate_telem(true);
- deepEqual(ping.status.sync, PROLONGED_SYNC_FAILURE);
- deepEqual(ping.engines.find(e => e.failureReason).failureReason,
- { name: "httperror", code: 503 });
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_info_collections_login_prolonged_server_maintenance_error(){
- // Test info/collections prolonged server maintenance errors are reported.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.info"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, SYNC_FAILED);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_meta_global_login_prolonged_server_maintenance_error(){
- // Test meta/global prolonged server maintenance errors are reported.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.meta"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, SYNC_FAILED);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_download_crypto_keys_login_prolonged_server_maintenance_error(){
- // Test crypto/keys prolonged server maintenance errors are reported.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.keys"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
- // Force re-download of keys
- Service.collectionKeys.clear();
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, SYNC_FAILED);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_upload_crypto_keys_login_prolonged_server_maintenance_error(){
- // Test crypto/keys prolonged server maintenance errors are reported.
- let server = EHTestsCommon.sync_httpd_setup();
-
- // Start off with an empty account, do not upload a key.
- yield configureIdentity({username: "broken.keys"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, SYNC_FAILED);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_wipeServer_login_prolonged_server_maintenance_error(){
- // Test that we report prolonged server maintenance errors that occur whilst
- // wiping the server.
- let server = EHTestsCommon.sync_httpd_setup();
-
- // Start off with an empty account, do not upload a key.
- yield configureIdentity({username: "broken.wipe"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, SYNC_FAILED);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_true(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- Service.sync();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_wipeRemote_prolonged_server_maintenance_error(){
- // Test that we report prolonged server maintenance errors that occur whilst
- // wiping all remote devices.
- let server = EHTestsCommon.sync_httpd_setup();
-
- server.registerPathHandler("/1.1/broken.wipe/storage/catapult", EHTestsCommon.service_unavailable);
- yield configureIdentity({username: "broken.wipe"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
- EHTestsCommon.generateAndUploadKeys();
-
- let engine = engineManager.get("catapult");
- engine.exception = null;
- engine.enabled = true;
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, SYNC_FAILED);
- do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
- do_check_eq(Svc.Prefs.get("firstSync"), "wipeRemote");
- do_check_true(errorHandler.didReportProlongedError);
- server.stop(() => {
- clean();
- deferred.resolve();
- });
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- Svc.Prefs.set("firstSync", "wipeRemote");
- setLastSync(PROLONGED_ERROR_DURATION);
- let ping = yield sync_and_validate_telem(true);
- deepEqual(ping.failureReason, { name: "httperror", code: 503 });
- yield deferred.promise;
-});
-
-add_task(function* test_sync_syncAndReportErrors_server_maintenance_error() {
- // Test server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- const BACKOFF = 42;
- let engine = engineManager.get("catapult");
- engine.enabled = true;
- engine.exception = {status: 503,
- headers: {"retry-after": BACKOFF}};
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
- do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
- do_check_eq(Status.sync, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_info_collections_login_syncAndReportErrors_server_maintenance_error() {
- // Test info/collections server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.info"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_meta_global_login_syncAndReportErrors_server_maintenance_error() {
- // Test meta/global server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.meta"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_download_crypto_keys_login_syncAndReportErrors_server_maintenance_error() {
- // Test crypto/keys server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.keys"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
- // Force re-download of keys
- Service.collectionKeys.clear();
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_upload_crypto_keys_login_syncAndReportErrors_server_maintenance_error() {
- // Test crypto/keys server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
-
- // Start off with an empty account, do not upload a key.
- yield configureIdentity({username: "broken.keys"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_wipeServer_login_syncAndReportErrors_server_maintenance_error() {
- // Test crypto/keys server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
-
- // Start off with an empty account, do not upload a key.
- yield configureIdentity({username: "broken.wipe"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_wipeRemote_syncAndReportErrors_server_maintenance_error(){
- // Test that we report prolonged server maintenance errors that occur whilst
- // wiping all remote devices.
- let server = EHTestsCommon.sync_httpd_setup();
-
- yield configureIdentity({username: "broken.wipe"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
- EHTestsCommon.generateAndUploadKeys();
-
- let engine = engineManager.get("catapult");
- engine.exception = null;
- engine.enabled = true;
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, SYNC_FAILED);
- do_check_eq(Status.sync, SERVER_MAINTENANCE);
- do_check_eq(Svc.Prefs.get("firstSync"), "wipeRemote");
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- Svc.Prefs.set("firstSync", "wipeRemote");
- setLastSync(NON_PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_task(function* test_sync_syncAndReportErrors_prolonged_server_maintenance_error() {
- // Test prolonged server maintenance errors are
- // reported when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- const BACKOFF = 42;
- let engine = engineManager.get("catapult");
- engine.enabled = true;
- engine.exception = {status: 503,
- headers: {"retry-after": BACKOFF}};
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
- do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
- do_check_eq(Status.sync, SERVER_MAINTENANCE);
- // syncAndReportErrors means dontIgnoreErrors, which means
- // didReportProlongedError not touched.
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_info_collections_login_syncAndReportErrors_prolonged_server_maintenance_error() {
- // Test info/collections server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.info"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- // syncAndReportErrors means dontIgnoreErrors, which means
- // didReportProlongedError not touched.
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_meta_global_login_syncAndReportErrors_prolonged_server_maintenance_error() {
- // Test meta/global server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.meta"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- // syncAndReportErrors means dontIgnoreErrors, which means
- // didReportProlongedError not touched.
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_download_crypto_keys_login_syncAndReportErrors_prolonged_server_maintenance_error() {
- // Test crypto/keys server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
- yield EHTestsCommon.setUp(server);
-
- yield configureIdentity({username: "broken.keys"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
- // Force re-download of keys
- Service.collectionKeys.clear();
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- // syncAndReportErrors means dontIgnoreErrors, which means
- // didReportProlongedError not touched.
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_upload_crypto_keys_login_syncAndReportErrors_prolonged_server_maintenance_error() {
- // Test crypto/keys server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
-
- // Start off with an empty account, do not upload a key.
- yield configureIdentity({username: "broken.keys"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- // syncAndReportErrors means dontIgnoreErrors, which means
- // didReportProlongedError not touched.
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_identity_test(this, function* test_wipeServer_login_syncAndReportErrors_prolonged_server_maintenance_error() {
- // Test crypto/keys server maintenance errors are reported
- // when calling syncAndReportErrors.
- let server = EHTestsCommon.sync_httpd_setup();
-
- // Start off with an empty account, do not upload a key.
- yield configureIdentity({username: "broken.wipe"});
- Service.serverURL = server.baseURI + "/maintenance/";
- Service.clusterURL = server.baseURI + "/maintenance/";
-
- let backoffInterval;
- Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
- Svc.Obs.remove("weave:service:backoff:interval", observe);
- backoffInterval = subject;
- });
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
- Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
- do_check_true(Status.enforceBackoff);
- do_check_eq(backoffInterval, 42);
- do_check_eq(Status.service, LOGIN_FAILED);
- do_check_eq(Status.login, SERVER_MAINTENANCE);
- // syncAndReportErrors means dontIgnoreErrors, which means
- // didReportProlongedError not touched.
- do_check_false(errorHandler.didReportProlongedError);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_false(Status.enforceBackoff);
- do_check_eq(Status.service, STATUS_OK);
-
- setLastSync(PROLONGED_ERROR_DURATION);
- errorHandler.syncAndReportErrors();
- yield deferred.promise;
-});
-
-add_task(function* test_sync_engine_generic_fail() {
- let server = EHTestsCommon.sync_httpd_setup();
-
-let engine = engineManager.get("catapult");
- engine.enabled = true;
- engine.sync = function sync() {
- Svc.Obs.notify("weave:engine:sync:error", ENGINE_UNKNOWN_FAIL, "catapult");
- };
-
- let log = Log.repository.getLogger("Sync.ErrorHandler");
- Svc.Prefs.set("log.appender.file.logOnError", true);
-
- do_check_eq(Status.engines["catapult"], undefined);
-
- let deferred = Promise.defer();
- // Don't wait for reset-file-log until the sync is underway.
- // This avoids us catching a delayed notification from an earlier test.
- Svc.Obs.add("weave:engine:sync:finish", function onEngineFinish() {
- Svc.Obs.remove("weave:engine:sync:finish", onEngineFinish);
-
- log.info("Adding reset-file-log observer.");
- Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
- Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
-
- // Put these checks here, not after sync(), so that we aren't racing the
- // log handler... which resets everything just a few lines below!
- _("Status.engines: " + JSON.stringify(Status.engines));
- do_check_eq(Status.engines["catapult"], ENGINE_UNKNOWN_FAIL);
- do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
-
- // Test Error log was written on SYNC_FAILED_PARTIAL.
- let entries = logsdir.directoryEntries;
- do_check_true(entries.hasMoreElements());
- let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
- do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
-
- clean();
-
- let syncErrors = sumHistogram("WEAVE_ENGINE_SYNC_ERRORS", { key: "catapult" });
- do_check_true(syncErrors, 1);
-
- server.stop(() => {
- clean();
- deferred.resolve();
- });
- });
- });
-
- do_check_true(yield EHTestsCommon.setUp(server));
- let ping = yield sync_and_validate_telem(true);
- deepEqual(ping.status.service, SYNC_FAILED_PARTIAL);
- deepEqual(ping.engines.find(e => e.status).status, ENGINE_UNKNOWN_FAIL);
-
- yield deferred.promise;
-});
-
-add_test(function test_logs_on_sync_error_despite_shouldReportError() {
- _("Ensure that an error is still logged when weave:service:sync:error " +
- "is notified, despite shouldReportError returning false.");
-
- let log = Log.repository.getLogger("Sync.ErrorHandler");
- Svc.Prefs.set("log.appender.file.logOnError", true);
- log.info("TESTING");
-
- // Ensure that we report no error.
- Status.login = MASTER_PASSWORD_LOCKED;
- do_check_false(errorHandler.shouldReportError());
-
- Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
- Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
-
- // Test that error log was written.
- let entries = logsdir.directoryEntries;
- do_check_true(entries.hasMoreElements());
- let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
- do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
-
- clean();
- run_next_test();
- });
- Svc.Obs.notify("weave:service:sync:error", {});
-});
-
-add_test(function test_logs_on_login_error_despite_shouldReportError() {
- _("Ensure that an error is still logged when weave:service:login:error " +
- "is notified, despite shouldReportError returning false.");
-
- let log = Log.repository.getLogger("Sync.ErrorHandler");
- Svc.Prefs.set("log.appender.file.logOnError", true);
- log.info("TESTING");
-
- // Ensure that we report no error.
- Status.login = MASTER_PASSWORD_LOCKED;
- do_check_false(errorHandler.shouldReportError());
-
- Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
- Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
-
- // Test that error log was written.
- let entries = logsdir.directoryEntries;
- do_check_true(entries.hasMoreElements());
- let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
- do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
-
- clean();
- run_next_test();
- });
- Svc.Obs.notify("weave:service:login:error", {});
-});
-
-// This test should be the last one since it monkeypatches the engine object
-// and we should only have one engine object throughout the file (bug 629664).
-add_task(function* test_engine_applyFailed() {
- let server = EHTestsCommon.sync_httpd_setup();
-
- let engine = engineManager.get("catapult");
- engine.enabled = true;
- delete engine.exception;
- engine.sync = function sync() {
- Svc.Obs.notify("weave:engine:sync:applied", {newFailed:1}, "catapult");
- };
-
- let log = Log.repository.getLogger("Sync.ErrorHandler");
- Svc.Prefs.set("log.appender.file.logOnError", true);
-
- let deferred = Promise.defer();
- Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
- Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
-
- do_check_eq(Status.engines["catapult"], ENGINE_APPLY_FAIL);
- do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
-
- // Test Error log was written on SYNC_FAILED_PARTIAL.
- let entries = logsdir.directoryEntries;
- do_check_true(entries.hasMoreElements());
- let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
- do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
-
- clean();
- server.stop(deferred.resolve);
- });
-
- do_check_eq(Status.engines["catapult"], undefined);
- do_check_true(yield EHTestsCommon.setUp(server));
- Service.sync();
- yield deferred.promise;
-});
diff --git a/services/sync/tests/unit/test_errorhandler_eol.js b/services/sync/tests/unit/test_errorhandler_eol.js
index c8d2ff4be..381bc7268 100644
--- a/services/sync/tests/unit/test_errorhandler_eol.js
+++ b/services/sync/tests/unit/test_errorhandler_eol.js
@@ -43,7 +43,7 @@ function sync_httpd_setup(infoHandler) {
return httpd_setup(handlers);
}
-function* setUp(server) {
+function setUp(server) {
yield configureIdentity({username: "johndoe"});
Service.serverURL = server.baseURI + "/";
Service.clusterURL = server.baseURI + "/";
@@ -66,7 +66,7 @@ function do_check_hard_eol(eh, start) {
do_check_true(Status.eol);
}
-add_identity_test(this, function* test_200_hard() {
+add_identity_test(this, function test_200_hard() {
let eh = Service.errorHandler;
let start = Date.now();
let server = sync_httpd_setup(handler200("hard-eol"));
@@ -88,7 +88,7 @@ add_identity_test(this, function* test_200_hard() {
yield deferred.promise;
});
-add_identity_test(this, function* test_513_hard() {
+add_identity_test(this, function test_513_hard() {
let eh = Service.errorHandler;
let start = Date.now();
let server = sync_httpd_setup(handler513);
@@ -114,7 +114,7 @@ add_identity_test(this, function* test_513_hard() {
yield deferred.promise;
});
-add_identity_test(this, function* test_200_soft() {
+add_identity_test(this, function test_200_soft() {
let eh = Service.errorHandler;
let start = Date.now();
let server = sync_httpd_setup(handler200("soft-eol"));
diff --git a/services/sync/tests/unit/test_errorhandler_filelog.js b/services/sync/tests/unit/test_errorhandler_filelog.js
index 993a478fd..0ce82b170 100644
--- a/services/sync/tests/unit/test_errorhandler_filelog.js
+++ b/services/sync/tests/unit/test_errorhandler_filelog.js
@@ -21,7 +21,7 @@ const DELAY_BUFFER = 500; // Buffer for timers on different OS platforms.
const PROLONGED_ERROR_DURATION =
(Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000;
-var errorHandler = Service.errorHandler;
+let errorHandler = Service.errorHandler;
function setLastSync(lastSyncValue) {
Svc.Prefs.set("lastSync", (new Date(Date.now() - lastSyncValue)).toString());
@@ -35,8 +35,6 @@ function run_test() {
Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
- validate_all_future_pings();
-
run_next_test();
}
@@ -47,22 +45,20 @@ add_test(function test_noOutput() {
// Clear log output from startup.
Svc.Prefs.set("log.appender.file.logOnSuccess", false);
Svc.Obs.notify("weave:service:sync:finish");
- Svc.Obs.add("weave:service:reset-file-log", function onResetFileLogOuter() {
- Svc.Obs.remove("weave:service:reset-file-log", onResetFileLogOuter);
- // Clear again without having issued any output.
- Svc.Prefs.set("log.appender.file.logOnSuccess", true);
- Svc.Obs.add("weave:service:reset-file-log", function onResetFileLogInner() {
- Svc.Obs.remove("weave:service:reset-file-log", onResetFileLogInner);
+ // Clear again without having issued any output.
+ Svc.Prefs.set("log.appender.file.logOnSuccess", true);
- errorHandler._logManager._fileAppender.level = Log.Level.Trace;
- Svc.Prefs.resetBranch("");
- run_next_test();
- });
+ Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
+ Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
- // Fake a successful sync.
- Svc.Obs.notify("weave:service:sync:finish");
+ errorHandler._logManager._fileAppender.level = Log.Level.Trace;
+ Svc.Prefs.resetBranch("");
+ run_next_test();
});
+
+ // Fake a successful sync.
+ Svc.Obs.notify("weave:service:sync:finish");
});
add_test(function test_logOnSuccess_false() {
@@ -85,14 +81,16 @@ add_test(function test_logOnSuccess_false() {
});
function readFile(file, callback) {
- NetUtil.asyncFetch({
- uri: NetUtil.newURI(file),
- loadUsingSystemPrincipal: true
- }, function (inputStream, statusCode, request) {
+ NetUtil.asyncFetch2(file, function (inputStream, statusCode, request) {
let data = NetUtil.readInputStreamToString(inputStream,
inputStream.available());
callback(statusCode, data);
- });
+ },
+ null, // aLoadingNode
+ Services.scriptSecurityManager.getSystemPrincipal(),
+ null, // aTriggeringPrincipal
+ Ci.nsILoadInfo.SEC_NORMAL,
+ Ci.nsIContentPolicy.TYPE_OTHER);
}
add_test(function test_logOnSuccess_true() {
@@ -269,51 +267,6 @@ add_test(function test_login_error_logOnError_true() {
Svc.Obs.notify("weave:service:login:error");
});
-
-add_test(function test_errorLog_dumpAddons() {
- Svc.Prefs.set("log.appender.file.logOnError", true);
-
- let log = Log.repository.getLogger("Sync.Test.FileLog");
-
- // We need to wait until the log cleanup started by this test is complete
- // or the next test will fail as it is ongoing.
- Svc.Obs.add("services-tests:common:log-manager:cleanup-logs", function onCleanupLogs() {
- Svc.Obs.remove("services-tests:common:log-manager:cleanup-logs", onCleanupLogs);
- run_next_test();
- });
-
- Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() {
- Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog);
-
- let entries = logsdir.directoryEntries;
- do_check_true(entries.hasMoreElements());
- let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
- do_check_eq(logfile.leafName.slice(-4), ".txt");
- do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
- do_check_false(entries.hasMoreElements());
-
- // Ensure we logged some addon list (which is probably empty)
- readFile(logfile, function (error, data) {
- do_check_true(Components.isSuccessCode(error));
- do_check_neq(data.indexOf("Addons installed"), -1);
-
- // Clean up.
- try {
- logfile.remove(false);
- } catch(ex) {
- dump("Couldn't delete file: " + ex + "\n");
- // Stupid Windows box.
- }
-
- Svc.Prefs.resetBranch("");
- });
- });
-
- // Fake an unsuccessful sync due to prolonged failure.
- setLastSync(PROLONGED_ERROR_DURATION);
- Svc.Obs.notify("weave:service:sync:error");
-});
-
// Check that error log files are deleted above an age threshold.
add_test(function test_logErrorCleanup_age() {
_("Beginning test_logErrorCleanup_age.");
diff --git a/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js b/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js
index 953f59fcb..18cea2cce 100644
--- a/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js
+++ b/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js
@@ -13,7 +13,7 @@ Cu.import("resource://testing-common/services/sync/utils.js");
initTestLogging("Trace");
-var engineManager = Service.engineManager;
+let engineManager = Service.engineManager;
engineManager.clear();
function promiseStopServer(server) {
@@ -59,7 +59,7 @@ function sync_httpd_setup() {
return httpd_setup(handlers);
}
-function* setUp(server) {
+function setUp(server) {
yield configureIdentity({username: "johndoe"});
Service.serverURL = server.baseURI + "/";
Service.clusterURL = server.baseURI + "/";
@@ -75,7 +75,7 @@ function generateAndUploadKeys(server) {
}
-add_identity_test(this, function* test_backoff500() {
+add_identity_test(this, function test_backoff500() {
_("Test: HTTP 500 sets backoff status.");
let server = sync_httpd_setup();
yield setUp(server);
@@ -102,7 +102,7 @@ add_identity_test(this, function* test_backoff500() {
yield promiseStopServer(server);
});
-add_identity_test(this, function* test_backoff503() {
+add_identity_test(this, function test_backoff503() {
_("Test: HTTP 503 with Retry-After header leads to backoff notification and sets backoff status.");
let server = sync_httpd_setup();
yield setUp(server);
@@ -138,7 +138,7 @@ add_identity_test(this, function* test_backoff503() {
yield promiseStopServer(server);
});
-add_identity_test(this, function* test_overQuota() {
+add_identity_test(this, function test_overQuota() {
_("Test: HTTP 400 with body error code 14 means over quota.");
let server = sync_httpd_setup();
yield setUp(server);
@@ -167,7 +167,7 @@ add_identity_test(this, function* test_overQuota() {
yield promiseStopServer(server);
});
-add_identity_test(this, function* test_service_networkError() {
+add_identity_test(this, function test_service_networkError() {
_("Test: Connection refused error from Service.sync() leads to the right status code.");
let server = sync_httpd_setup();
yield setUp(server);
@@ -193,14 +193,13 @@ add_identity_test(this, function* test_service_networkError() {
yield deferred.promise;
});
-add_identity_test(this, function* test_service_offline() {
+add_identity_test(this, function test_service_offline() {
_("Test: Wanting to sync in offline mode leads to the right status code but does not increment the ignorable error count.");
let server = sync_httpd_setup();
yield setUp(server);
let deferred = Promise.defer();
server.stop(() => {
Services.io.offline = true;
- Services.prefs.setBoolPref("network.dns.offline-localhost", false);
try {
do_check_eq(Status.sync, SYNC_SUCCEEDED);
@@ -215,13 +214,12 @@ add_identity_test(this, function* test_service_offline() {
Service.startOver();
}
Services.io.offline = false;
- Services.prefs.clearUserPref("network.dns.offline-localhost");
deferred.resolve();
});
yield deferred.promise;
});
-add_identity_test(this, function* test_engine_networkError() {
+add_identity_test(this, function test_engine_networkError() {
_("Test: Network related exceptions from engine.sync() lead to the right status code.");
let server = sync_httpd_setup();
yield setUp(server);
@@ -248,7 +246,7 @@ add_identity_test(this, function* test_engine_networkError() {
yield promiseStopServer(server);
});
-add_identity_test(this, function* test_resource_timeout() {
+add_identity_test(this, function test_resource_timeout() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -276,7 +274,6 @@ add_identity_test(this, function* test_resource_timeout() {
});
function run_test() {
- validate_all_future_pings();
engineManager.register(CatapultEngine);
run_next_test();
}
diff --git a/services/sync/tests/unit/test_extension_storage_crypto.js b/services/sync/tests/unit/test_extension_storage_crypto.js
deleted file mode 100644
index f93e4970d..000000000
--- a/services/sync/tests/unit/test_extension_storage_crypto.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-Cu.import("resource://services-crypto/utils.js");
-Cu.import("resource://services-sync/engines/extension-storage.js");
-Cu.import("resource://services-sync/util.js");
-
-/**
- * Like Assert.throws, but for generators.
- *
- * @param {string | Object | function} constraint
- * What to use to check the exception.
- * @param {function} f
- * The function to call.
- */
-function* throwsGen(constraint, f) {
- let threw = false;
- let exception;
- try {
- yield* f();
- }
- catch (e) {
- threw = true;
- exception = e;
- }
-
- ok(threw, "did not throw an exception");
-
- const debuggingMessage = `got ${exception}, expected ${constraint}`;
- let message = exception;
- if (typeof exception === "object") {
- message = exception.message;
- }
-
- if (typeof constraint === "function") {
- ok(constraint(message), debuggingMessage);
- } else {
- ok(constraint === message, debuggingMessage);
- }
-
-}
-
-/**
- * An EncryptionRemoteTransformer that uses a fixed key bundle,
- * suitable for testing.
- */
-class StaticKeyEncryptionRemoteTransformer extends EncryptionRemoteTransformer {
- constructor(keyBundle) {
- super();
- this.keyBundle = keyBundle;
- }
-
- getKeys() {
- return Promise.resolve(this.keyBundle);
- }
-}
-const BORING_KB = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
-const STRETCHED_KEY = CryptoUtils.hkdf(BORING_KB, undefined, `testing storage.sync encryption`, 2*32);
-const KEY_BUNDLE = {
- sha256HMACHasher: Utils.makeHMACHasher(Ci.nsICryptoHMAC.SHA256, Utils.makeHMACKey(STRETCHED_KEY.slice(0, 32))),
- encryptionKeyB64: btoa(STRETCHED_KEY.slice(32, 64)),
-};
-const transformer = new StaticKeyEncryptionRemoteTransformer(KEY_BUNDLE);
-
-add_task(function* test_encryption_transformer_roundtrip() {
- const POSSIBLE_DATAS = [
- "string",
- 2, // number
- [1, 2, 3], // array
- {key: "value"}, // object
- ];
-
- for (let data of POSSIBLE_DATAS) {
- const record = {data: data, id: "key-some_2D_key", key: "some-key"};
-
- deepEqual(record, yield transformer.decode(yield transformer.encode(record)));
- }
-});
-
-add_task(function* test_refuses_to_decrypt_tampered() {
- const encryptedRecord = yield transformer.encode({data: [1, 2, 3], id: "key-some_2D_key", key: "some-key"});
- const tamperedHMAC = Object.assign({}, encryptedRecord, {hmac: "0000000000000000000000000000000000000000000000000000000000000001"});
- yield* throwsGen(Utils.isHMACMismatch, function*() {
- yield transformer.decode(tamperedHMAC);
- });
-
- const tamperedIV = Object.assign({}, encryptedRecord, {IV: "aaaaaaaaaaaaaaaaaaaaaa=="});
- yield* throwsGen(Utils.isHMACMismatch, function*() {
- yield transformer.decode(tamperedIV);
- });
-});
diff --git a/services/sync/tests/unit/test_extension_storage_engine.js b/services/sync/tests/unit/test_extension_storage_engine.js
deleted file mode 100644
index 1b2792703..000000000
--- a/services/sync/tests/unit/test_extension_storage_engine.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://services-sync/engines/extension-storage.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://gre/modules/ExtensionStorageSync.jsm");
-
-Service.engineManager.register(ExtensionStorageEngine);
-const engine = Service.engineManager.get("extension-storage");
-do_get_profile(); // so we can use FxAccounts
-loadWebExtensionTestFunctions();
-
-function mock(options) {
- let calls = [];
- let ret = function() {
- calls.push(arguments);
- return options.returns;
- }
- Object.setPrototypeOf(ret, {
- __proto__: Function.prototype,
- get calls() {
- return calls;
- }
- });
- return ret;
-}
-
-add_task(function* test_calling_sync_calls__sync() {
- let oldSync = ExtensionStorageEngine.prototype._sync;
- let syncMock = ExtensionStorageEngine.prototype._sync = mock({returns: true});
- try {
- // I wanted to call the main sync entry point for the entire
- // package, but that fails because it tries to sync ClientEngine
- // first, which fails.
- yield engine.sync();
- } finally {
- ExtensionStorageEngine.prototype._sync = oldSync;
- }
- equal(syncMock.calls.length, 1);
-});
-
-add_task(function* test_calling_sync_calls_ext_storage_sync() {
- const extension = {id: "my-extension"};
- let oldSync = ExtensionStorageSync.syncAll;
- let syncMock = ExtensionStorageSync.syncAll = mock({returns: Promise.resolve()});
- try {
- yield* withSyncContext(function* (context) {
- // Set something so that everyone knows that we're using storage.sync
- yield ExtensionStorageSync.set(extension, {"a": "b"}, context);
-
- yield engine._sync();
- });
- } finally {
- ExtensionStorageSync.syncAll = oldSync;
- }
- do_check_true(syncMock.calls.length >= 1);
-});
diff --git a/services/sync/tests/unit/test_extension_storage_tracker.js b/services/sync/tests/unit/test_extension_storage_tracker.js
deleted file mode 100644
index fac51a897..000000000
--- a/services/sync/tests/unit/test_extension_storage_tracker.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://services-sync/engines/extension-storage.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://gre/modules/ExtensionStorageSync.jsm");
-
-Service.engineManager.register(ExtensionStorageEngine);
-const engine = Service.engineManager.get("extension-storage");
-do_get_profile(); // so we can use FxAccounts
-loadWebExtensionTestFunctions();
-
-add_task(function* test_changing_extension_storage_changes_score() {
- const tracker = engine._tracker;
- const extension = {id: "my-extension-id"};
- Svc.Obs.notify("weave:engine:start-tracking");
- yield* withSyncContext(function*(context) {
- yield ExtensionStorageSync.set(extension, {"a": "b"}, context);
- });
- do_check_eq(tracker.score, SCORE_INCREMENT_MEDIUM);
-
- tracker.resetScore();
- yield* withSyncContext(function*(context) {
- yield ExtensionStorageSync.remove(extension, "a", context);
- });
- do_check_eq(tracker.score, SCORE_INCREMENT_MEDIUM);
-
- Svc.Obs.notify("weave:engine:stop-tracking");
-});
-
-function run_test() {
- run_next_test();
-}
diff --git a/services/sync/tests/unit/test_forms_tracker.js b/services/sync/tests/unit/test_forms_tracker.js
index f14e208b3..5f7aaa648 100644
--- a/services/sync/tests/unit/test_forms_tracker.js
+++ b/services/sync/tests/unit/test_forms_tracker.js
@@ -40,18 +40,6 @@ function run_test() {
addEntry("address", "Memory Lane");
do_check_attribute_count(tracker.changedIDs, 3);
-
- _("Check that ignoreAll is respected");
- tracker.clearChangedIDs();
- tracker.score = 0;
- tracker.ignoreAll = true;
- addEntry("username", "johndoe123");
- addEntry("favoritecolor", "green");
- removeEntry("name", "John Doe");
- tracker.ignoreAll = false;
- do_check_empty(tracker.changedIDs);
- equal(tracker.score, 0);
-
_("Let's stop tracking again.");
tracker.clearChangedIDs();
Svc.Obs.notify("weave:engine:stop-tracking");
@@ -63,8 +51,6 @@ function run_test() {
removeEntry("email", "john@doe.com");
do_check_empty(tracker.changedIDs);
-
-
} finally {
_("Clean up.");
engine._store.wipe();
diff --git a/services/sync/tests/unit/test_fxa_migration.js b/services/sync/tests/unit/test_fxa_migration.js
new file mode 100644
index 000000000..7c65d5996
--- /dev/null
+++ b/services/sync/tests/unit/test_fxa_migration.js
@@ -0,0 +1,279 @@
+// Test the FxAMigration module
+Cu.import("resource://services-sync/FxaMigrator.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+Cu.import("resource://gre/modules/FxAccounts.jsm");
+Cu.import("resource://gre/modules/FxAccountsCommon.js");
+Cu.import("resource://services-sync/browserid_identity.js");
+
+// Set our username pref early so sync initializes with the legacy provider.
+Services.prefs.setCharPref("services.sync.username", "foo");
+// And ensure all debug messages end up being printed.
+Services.prefs.setCharPref("services.sync.log.appender.dump", "Debug");
+
+// Now import sync
+Cu.import("resource://services-sync/service.js");
+Cu.import("resource://services-sync/record.js");
+Cu.import("resource://services-sync/util.js");
+
+// And reset the username.
+Services.prefs.clearUserPref("services.sync.username");
+
+Cu.import("resource://testing-common/services/sync/utils.js");
+Cu.import("resource://testing-common/services/common/logging.js");
+Cu.import("resource://testing-common/services/sync/rotaryengine.js");
+
+const FXA_USERNAME = "someone@somewhere";
+
+// Utilities
+function promiseOneObserver(topic) {
+ return new Promise((resolve, reject) => {
+ let observer = function(subject, topic, data) {
+ Services.obs.removeObserver(observer, topic);
+ resolve({ subject: subject, data: data });
+ }
+ Services.obs.addObserver(observer, topic, false);
+ });
+}
+
+function promiseStopServer(server) {
+ return new Promise((resolve, reject) => {
+ server.stop(resolve);
+ });
+}
+
+
+// Helpers
+function configureLegacySync() {
+ let engine = new RotaryEngine(Service);
+ engine.enabled = true;
+ Svc.Prefs.set("registerEngines", engine.name);
+ Svc.Prefs.set("log.logger.engine.rotary", "Trace");
+
+ let contents = {
+ meta: {global: {engines: {rotary: {version: engine.version,
+ syncID: engine.syncID}}}},
+ crypto: {},
+ rotary: {}
+ };
+
+ const USER = "foo";
+ const PASSPHRASE = "abcdeabcdeabcdeabcdeabcdea";
+
+ setBasicCredentials(USER, "password", PASSPHRASE);
+
+ let onRequest = function(request, response) {
+ // ideally we'd only do this while a legacy user is configured, but WTH.
+ response.setHeader("x-weave-alert", JSON.stringify({code: "soft-eol"}));
+ }
+ let server = new SyncServer({onRequest: onRequest});
+ server.registerUser(USER, "password");
+ server.createContents(USER, contents);
+ server.start();
+
+ Service.serverURL = server.baseURI;
+ Service.clusterURL = server.baseURI;
+ Service.identity.username = USER;
+ Service._updateCachedURLs();
+
+ Service.engineManager._engines[engine.name] = engine;
+
+ return [engine, server];
+}
+
+function configureFxa() {
+ Services.prefs.setCharPref("identity.fxaccounts.auth.uri", "http://localhost");
+}
+
+add_task(function *testMigration() {
+ configureFxa();
+
+ // when we do a .startOver we want the new provider.
+ let oldValue = Services.prefs.getBoolPref("services.sync-testing.startOverKeepIdentity");
+ Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", false);
+
+ // disable the addons engine - this engine choice is arbitrary, but we
+ // want to check it remains disabled after migration.
+ Services.prefs.setBoolPref("services.sync.engine.addons", false);
+
+ do_register_cleanup(() => {
+ Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", oldValue)
+ Services.prefs.setBoolPref("services.sync.engine.addons", true);
+ });
+
+ // No sync user - that should report no user-action necessary.
+ Assert.deepEqual((yield fxaMigrator._queueCurrentUserState()), null,
+ "no user state when complete");
+
+ // Arrange for a legacy sync user and manually bump the migrator
+ let [engine, server] = configureLegacySync();
+
+ // Check our disabling of the "addons" engine worked, and for good measure,
+ // that the "passwords" engine is enabled.
+ Assert.ok(!Service.engineManager.get("addons").enabled, "addons is disabled");
+ Assert.ok(Service.engineManager.get("passwords").enabled, "passwords is enabled");
+
+ // monkey-patch the migration sentinel code so we know it was called.
+ let haveStartedSentinel = false;
+ let origSetFxAMigrationSentinel = Service.setFxAMigrationSentinel;
+ let promiseSentinelWritten = new Promise((resolve, reject) => {
+ Service.setFxAMigrationSentinel = function(arg) {
+ haveStartedSentinel = true;
+ return origSetFxAMigrationSentinel.call(Service, arg).then(result => {
+ Service.setFxAMigrationSentinel = origSetFxAMigrationSentinel;
+ resolve(result);
+ return result;
+ });
+ }
+ });
+
+ // We are now configured for legacy sync, but we aren't in an EOL state yet,
+ // so should still be not waiting for a user.
+ Assert.deepEqual((yield fxaMigrator._queueCurrentUserState()), null,
+ "no user state before server EOL");
+
+ // Start a sync - this will cause an EOL notification which the migrator's
+ // observer will notice.
+ let promise = promiseOneObserver("fxa-migration:state-changed");
+ _("Starting sync");
+ Service.sync();
+ _("Finished sync");
+
+ // We should have seen the observer, so be waiting for an FxA user.
+ Assert.equal((yield promise).data, fxaMigrator.STATE_USER_FXA, "now waiting for FxA.")
+
+ // Re-calling our user-state promise should also reflect the same state.
+ Assert.equal((yield fxaMigrator._queueCurrentUserState()),
+ fxaMigrator.STATE_USER_FXA,
+ "still waiting for FxA.");
+
+ // arrange for an unverified FxA user.
+ let config = makeIdentityConfig({username: FXA_USERNAME});
+ let fxa = new FxAccounts({});
+ config.fxaccount.user.email = config.username;
+ delete config.fxaccount.user.verified;
+ // *sob* - shouldn't need this boilerplate
+ fxa.internal.currentAccountState.getCertificate = function(data, keyPair, mustBeValidUntil) {
+ this.cert = {
+ validUntil: fxa.internal.now() + CERT_LIFETIME,
+ cert: "certificate",
+ };
+ return Promise.resolve(this.cert.cert);
+ };
+
+ // As soon as we set the FxA user the observers should fire and magically
+ // transition.
+ promise = promiseOneObserver("fxa-migration:state-changed");
+ fxAccounts.setSignedInUser(config.fxaccount.user);
+
+ let observerInfo = yield promise;
+ Assert.equal(observerInfo.data,
+ fxaMigrator.STATE_USER_FXA_VERIFIED,
+ "now waiting for verification");
+ Assert.ok(observerInfo.subject instanceof Ci.nsISupportsString,
+ "email was passed to observer");
+ Assert.equal(observerInfo.subject.data,
+ FXA_USERNAME,
+ "email passed to observer is correct");
+
+ // should have seen the user set, so state should automatically update.
+ Assert.equal((yield fxaMigrator._queueCurrentUserState()),
+ fxaMigrator.STATE_USER_FXA_VERIFIED,
+ "now waiting for verification");
+
+ // Before we verify the user, fire off a sync that calls us back during
+ // the sync and before it completes - this way we can ensure we do the right
+ // thing in terms of blocking sync and waiting for it to complete.
+
+ let wasWaiting = false;
+ // This is a PITA as sync is pseudo-blocking.
+ engine._syncFinish = function () {
+ // We aren't in a generator here, so use a helper to block on promises.
+ function getState() {
+ let cb = Async.makeSpinningCallback();
+ fxaMigrator._queueCurrentUserState().then(state => cb(null, state));
+ return cb.wait();
+ }
+ // should still be waiting for verification.
+ Assert.equal(getState(), fxaMigrator.STATE_USER_FXA_VERIFIED,
+ "still waiting for verification");
+
+ // arrange for the user to be verified. The fxAccount's mock story is
+ // broken, so go behind its back.
+ config.fxaccount.user.verified = true;
+ fxAccounts.setSignedInUser(config.fxaccount.user);
+ Services.obs.notifyObservers(null, ONVERIFIED_NOTIFICATION, null);
+
+ // spinningly wait for the migrator to catch up - sync is running so
+ // we should be in a 'null' user-state as there is no user-action
+ // necessary.
+ let cb = Async.makeSpinningCallback();
+ promiseOneObserver("fxa-migration:state-changed").then(({ data: state }) => cb(null, state));
+ Assert.equal(cb.wait(), null, "no user action necessary while sync completes.");
+
+ // We must not have started writing the sentinel yet.
+ Assert.ok(!haveStartedSentinel, "haven't written a sentinel yet");
+
+ // sync should be blocked from continuing
+ Assert.ok(Service.scheduler.isBlocked, "sync is blocked.")
+
+ wasWaiting = true;
+ throw ex;
+ };
+
+ _("Starting sync");
+ Service.sync();
+ _("Finished sync");
+
+ // mock sync so we can ensure the final sync is scheduled with the FxA user.
+ // (letting a "normal" sync complete is a PITA without mocking huge amounts
+ // of FxA infra)
+ let promiseFinalSync = new Promise((resolve, reject) => {
+ let oldSync = Service.sync;
+ Service.sync = function() {
+ Service.sync = oldSync;
+ resolve();
+ }
+ });
+
+ Assert.ok(wasWaiting, "everything was good while sync was running.")
+
+ // The migration is now going to run to completion.
+ // sync should still be "blocked"
+ Assert.ok(Service.scheduler.isBlocked, "sync is blocked.");
+
+ // We should see the migration sentinel written and it should return true.
+ Assert.ok((yield promiseSentinelWritten), "wrote the sentinel");
+
+ // And we should see a new sync start
+ yield promiseFinalSync;
+
+ // and we should be configured for FxA
+ let WeaveService = Cc["@mozilla.org/weave/service;1"]
+ .getService(Components.interfaces.nsISupports)
+ .wrappedJSObject;
+ Assert.ok(WeaveService.fxAccountsEnabled, "FxA is enabled");
+ Assert.ok(Service.identity instanceof BrowserIDManager,
+ "sync is configured with the browserid_identity provider.");
+ Assert.equal(Service.identity.username, config.username, "correct user configured")
+ Assert.ok(!Service.scheduler.isBlocked, "sync is not blocked.")
+ // and the user state should remain null.
+ Assert.deepEqual((yield fxaMigrator._queueCurrentUserState()),
+ null,
+ "still no user action necessary");
+ // and our engines should be in the same enabled/disabled state as before.
+ Assert.ok(!Service.engineManager.get("addons").enabled, "addons is still disabled");
+ Assert.ok(Service.engineManager.get("passwords").enabled, "passwords is still enabled");
+
+ // aaaand, we are done - clean up.
+ yield promiseStopServer(server);
+});
+
+
+function run_test() {
+ initTestLogging();
+ do_register_cleanup(() => {
+ fxaMigrator.finalize();
+ Svc.Prefs.resetBranch("");
+ });
+ run_next_test();
+}
diff --git a/services/sync/tests/unit/test_fxa_migration_sentinel.js b/services/sync/tests/unit/test_fxa_migration_sentinel.js
new file mode 100644
index 000000000..bed2dd756
--- /dev/null
+++ b/services/sync/tests/unit/test_fxa_migration_sentinel.js
@@ -0,0 +1,150 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test the reading and writing of the sync migration sentinel.
+Cu.import("resource://gre/modules/Promise.jsm");
+Cu.import("resource://gre/modules/FxAccounts.jsm");
+Cu.import("resource://gre/modules/FxAccountsCommon.js");
+
+Cu.import("resource://testing-common/services/sync/utils.js");
+Cu.import("resource://testing-common/services/common/logging.js");
+
+Cu.import("resource://services-sync/record.js");
+
+// Set our username pref early so sync initializes with the legacy provider.
+Services.prefs.setCharPref("services.sync.username", "foo");
+
+// Now import sync
+Cu.import("resource://services-sync/service.js");
+
+const USER = "foo";
+const PASSPHRASE = "abcdeabcdeabcdeabcdeabcdea";
+
+function promiseStopServer(server) {
+ return new Promise((resolve, reject) => {
+ server.stop(resolve);
+ });
+}
+
+let numServerRequests = 0;
+
+// Helpers
+function configureLegacySync() {
+ let contents = {
+ meta: {global: {}},
+ crypto: {},
+ };
+
+ setBasicCredentials(USER, "password", PASSPHRASE);
+
+ numServerRequests = 0;
+ let server = new SyncServer({
+ onRequest: () => {
+ ++numServerRequests
+ }
+ });
+ server.registerUser(USER, "password");
+ server.createContents(USER, contents);
+ server.start();
+
+ Service.serverURL = server.baseURI;
+ Service.clusterURL = server.baseURI;
+ Service.identity.username = USER;
+ Service._updateCachedURLs();
+
+ return server;
+}
+
+// Test a simple round-trip of the get/set functions.
+add_task(function *() {
+ // Arrange for a legacy sync user.
+ let server = configureLegacySync();
+
+ Assert.equal((yield Service.getFxAMigrationSentinel()), null, "no sentinel to start");
+
+ let sentinel = {foo: "bar"};
+ yield Service.setFxAMigrationSentinel(sentinel);
+
+ Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got the sentinel back");
+
+ yield promiseStopServer(server);
+});
+
+// Test the records are cached by the record manager.
+add_task(function *() {
+ // Arrange for a legacy sync user.
+ let server = configureLegacySync();
+ Service.login();
+
+ // Reset the request count here as the login would have made some.
+ numServerRequests = 0;
+
+ Assert.equal((yield Service.getFxAMigrationSentinel()), null, "no sentinel to start");
+ Assert.equal(numServerRequests, 1, "first fetch should hit the server");
+
+ let sentinel = {foo: "bar"};
+ yield Service.setFxAMigrationSentinel(sentinel);
+ Assert.equal(numServerRequests, 2, "setting sentinel should hit the server");
+
+ Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got the sentinel back");
+ Assert.equal(numServerRequests, 2, "second fetch should not should hit the server");
+
+ // Clobber the caches and ensure we still get the correct value back when we
+ // do hit the server.
+ Service.recordManager.clearCache();
+ Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got the sentinel back");
+ Assert.equal(numServerRequests, 3, "should have re-hit the server with empty caches");
+
+ yield promiseStopServer(server);
+});
+
+// Test the records are cached by a sync.
+add_task(function* () {
+ let server = configureLegacySync();
+
+ // A first sync clobbers meta/global due to it being empty, so we first
+ // do a sync which forces a good set of data on the server.
+ Service.sync();
+
+ // Now create a sentinel exists on the server. It's encrypted, so we need to
+ // put an encrypted version.
+ let cryptoWrapper = new CryptoWrapper("meta", "fxa_credentials");
+ let sentinel = {foo: "bar"};
+ cryptoWrapper.cleartext = {
+ id: "fxa_credentials",
+ sentinel: sentinel,
+ deleted: false,
+ }
+ cryptoWrapper.encrypt(Service.identity.syncKeyBundle);
+ let payload = {
+ ciphertext: cryptoWrapper.ciphertext,
+ IV: cryptoWrapper.IV,
+ hmac: cryptoWrapper.hmac,
+ };
+
+ server.createContents(USER, {
+ meta: {fxa_credentials: payload},
+ crypto: {},
+ });
+
+ // Another sync - this will cause the encrypted record to be fetched.
+ Service.sync();
+ // Reset the request count here as the sync will have made many!
+ numServerRequests = 0;
+
+ // Asking for the sentinel should use the copy cached in the record manager.
+ Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got it");
+ Assert.equal(numServerRequests, 0, "should not have hit the server");
+
+ // And asking for it again should work (we have to work around the fact the
+ // ciphertext is clobbered on first decrypt...)
+ Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got it again");
+ Assert.equal(numServerRequests, 0, "should not have hit the server");
+
+ yield promiseStopServer(server);
+});
+
+function run_test() {
+ initTestLogging();
+ run_next_test();
+}
diff --git a/services/sync/tests/unit/test_fxa_node_reassignment.js b/services/sync/tests/unit/test_fxa_node_reassignment.js
index 3e4cefd53..2f61afd6f 100644
--- a/services/sync/tests/unit/test_fxa_node_reassignment.js
+++ b/services/sync/tests/unit/test_fxa_node_reassignment.js
@@ -1,368 +1,321 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-_("Test that node reassignment happens correctly using the FxA identity mgr.");
-// The node-reassignment logic is quite different for FxA than for the legacy
-// provider. In particular, there's no special request necessary for
-// reassignment - it comes from the token server - so we need to ensure the
-// Fxa cluster manager grabs a new token.
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-common/rest.js");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/status.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/rotaryengine.js");
-Cu.import("resource://services-sync/browserid_identity.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-Service.engineManager.clear();
-
-function run_test() {
- Log.repository.getLogger("Sync.AsyncResource").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.Resource").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.RESTRequest").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
- initTestLogging();
-
- Service.engineManager.register(RotaryEngine);
-
- // Setup the FxA identity manager and cluster manager.
- Status.__authManager = Service.identity = new BrowserIDManager();
- Service._clusterManager = Service.identity.createClusterManager(Service);
-
- // None of the failures in this file should result in a UI error.
- function onUIError() {
- do_throw("Errors should not be presented in the UI.");
- }
- Svc.Obs.add("weave:ui:login:error", onUIError);
- Svc.Obs.add("weave:ui:sync:error", onUIError);
-
- run_next_test();
-}
-
-
-// API-compatible with SyncServer handler. Bind `handler` to something to use
-// as a ServerCollection handler.
-function handleReassign(handler, req, resp) {
- resp.setStatusLine(req.httpVersion, 401, "Node reassignment");
- resp.setHeader("Content-Type", "application/json");
- let reassignBody = JSON.stringify({error: "401inator in place"});
- resp.bodyOutputStream.write(reassignBody, reassignBody.length);
-}
-
-var numTokenRequests = 0;
-
-function prepareServer(cbAfterTokenFetch) {
- let config = makeIdentityConfig({username: "johndoe"});
- // A server callback to ensure we don't accidentally hit the wrong endpoint
- // after a node reassignment.
- let callback = {
- __proto__: SyncServerCallback,
- onRequest(req, resp) {
- let full = `${req.scheme}://${req.host}:${req.port}${req.path}`;
- do_check_true(full.startsWith(config.fxaccount.token.endpoint),
- `request made to ${full}`);
- }
- }
- let server = new SyncServer(callback);
- server.registerUser("johndoe");
- server.start();
-
- // Set the token endpoint for the initial token request that's done implicitly
- // via configureIdentity.
- config.fxaccount.token.endpoint = server.baseURI + "1.1/johndoe/";
- // And future token fetches will do magic around numReassigns.
- let numReassigns = 0;
- return configureIdentity(config).then(() => {
- Service.identity._tokenServerClient = {
- getTokenFromBrowserIDAssertion: function(uri, assertion, cb) {
- // Build a new URL with trailing zeros for the SYNC_VERSION part - this
- // will still be seen as equivalent by the test server, but different
- // by sync itself.
- numReassigns += 1;
- let trailingZeros = new Array(numReassigns + 1).join('0');
- let token = config.fxaccount.token;
- token.endpoint = server.baseURI + "1.1" + trailingZeros + "/johndoe";
- token.uid = config.username;
- numTokenRequests += 1;
- cb(null, token);
- if (cbAfterTokenFetch) {
- cbAfterTokenFetch();
- }
- },
- };
- return server;
- });
-}
-
-function getReassigned() {
- try {
- return Services.prefs.getBoolPref("services.sync.lastSyncReassigned");
- } catch (ex) {
- if (ex.result == Cr.NS_ERROR_UNEXPECTED) {
- return false;
- }
- do_throw("Got exception retrieving lastSyncReassigned: " +
- Log.exceptionStr(ex));
- }
-}
-
-/**
- * Make a test request to `url`, then watch the result of two syncs
- * to ensure that a node request was made.
- * Runs `between` between the two. This can be used to undo deliberate failure
- * setup, detach observers, etc.
- */
-function* syncAndExpectNodeReassignment(server, firstNotification, between,
- secondNotification, url) {
- _("Starting syncAndExpectNodeReassignment\n");
- let deferred = Promise.defer();
- function onwards() {
- let numTokenRequestsBefore;
- function onFirstSync() {
- _("First sync completed.");
- Svc.Obs.remove(firstNotification, onFirstSync);
- Svc.Obs.add(secondNotification, onSecondSync);
-
- do_check_eq(Service.clusterURL, "");
-
- // Track whether we fetched a new token.
- numTokenRequestsBefore = numTokenRequests;
-
- // Allow for tests to clean up error conditions.
- between();
- }
- function onSecondSync() {
- _("Second sync completed.");
- Svc.Obs.remove(secondNotification, onSecondSync);
- Service.scheduler.clearSyncTriggers();
-
- // Make absolutely sure that any event listeners are done with their work
- // before we proceed.
- waitForZeroTimer(function () {
- _("Second sync nextTick.");
- do_check_eq(numTokenRequests, numTokenRequestsBefore + 1, "fetched a new token");
- Service.startOver();
- server.stop(deferred.resolve);
- });
- }
-
- Svc.Obs.add(firstNotification, onFirstSync);
- Service.sync();
- }
-
- // Make sure that we really do get a 401 (but we can only do that if we are
- // already logged in, as the login process is what sets up the URLs)
- if (Service.isLoggedIn) {
- _("Making request to " + url + " which should 401");
- let request = new RESTRequest(url);
- request.get(function () {
- do_check_eq(request.response.status, 401);
- Utils.nextTick(onwards);
- });
- } else {
- _("Skipping preliminary validation check for a 401 as we aren't logged in");
- Utils.nextTick(onwards);
- }
- yield deferred.promise;
-}
-
-// Check that when we sync we don't request a new token by default - our
-// test setup has configured the client with a valid token, and that token
-// should be used to form the cluster URL.
-add_task(function* test_single_token_fetch() {
- _("Test a normal sync only fetches 1 token");
-
- let numTokenFetches = 0;
-
- function afterTokenFetch() {
- numTokenFetches++;
- }
-
- // Set the cluster URL to an "old" version - this is to ensure we don't
- // use that old cached version for the first sync but prefer the value
- // we got from the token (and as above, we are also checking we don't grab
- // a new token). If the test actually attempts to connect to this URL
- // it will crash.
- Service.clusterURL = "http://example.com/";
-
- let server = yield prepareServer(afterTokenFetch);
-
- do_check_false(Service.isLoggedIn, "not already logged in");
- Service.sync();
- do_check_eq(Status.sync, SYNC_SUCCEEDED, "sync succeeded");
- do_check_eq(numTokenFetches, 0, "didn't fetch a new token");
- // A bit hacky, but given we know how prepareServer works we can deduce
- // that clusterURL we expect.
- let expectedClusterURL = server.baseURI + "1.1/johndoe/";
- do_check_eq(Service.clusterURL, expectedClusterURL);
- yield new Promise(resolve => server.stop(resolve));
-});
-
-add_task(function* test_momentary_401_engine() {
- _("Test a failure for engine URLs that's resolved by reassignment.");
- let server = yield prepareServer();
- let john = server.user("johndoe");
-
- _("Enabling the Rotary engine.");
- let engine = Service.engineManager.get("rotary");
- engine.enabled = true;
-
- // We need the server to be correctly set up prior to experimenting. Do this
- // through a sync.
- let global = {syncID: Service.syncID,
- storageVersion: STORAGE_VERSION,
- rotary: {version: engine.version,
- syncID: engine.syncID}}
- john.createCollection("meta").insert("global", global);
-
- _("First sync to prepare server contents.");
- Service.sync();
-
- _("Setting up Rotary collection to 401.");
- let rotary = john.createCollection("rotary");
- let oldHandler = rotary.collectionHandler;
- rotary.collectionHandler = handleReassign.bind(this, undefined);
-
- // We want to verify that the clusterURL pref has been cleared after a 401
- // inside a sync. Flag the Rotary engine to need syncing.
- john.collection("rotary").timestamp += 1000;
-
- function between() {
- _("Undoing test changes.");
- rotary.collectionHandler = oldHandler;
-
- function onLoginStart() {
- // lastSyncReassigned shouldn't be cleared until a sync has succeeded.
- _("Ensuring that lastSyncReassigned is still set at next sync start.");
- Svc.Obs.remove("weave:service:login:start", onLoginStart);
- do_check_true(getReassigned());
- }
-
- _("Adding observer that lastSyncReassigned is still set on login.");
- Svc.Obs.add("weave:service:login:start", onLoginStart);
- }
-
- yield syncAndExpectNodeReassignment(server,
- "weave:service:sync:finish",
- between,
- "weave:service:sync:finish",
- Service.storageURL + "rotary");
-});
-
-// This test ends up being a failing info fetch *after we're already logged in*.
-add_task(function* test_momentary_401_info_collections_loggedin() {
- _("Test a failure for info/collections after login that's resolved by reassignment.");
- let server = yield prepareServer();
-
- _("First sync to prepare server contents.");
- Service.sync();
-
- _("Arrange for info/collections to return a 401.");
- let oldHandler = server.toplevelHandlers.info;
- server.toplevelHandlers.info = handleReassign;
-
- function undo() {
- _("Undoing test changes.");
- server.toplevelHandlers.info = oldHandler;
- }
-
- do_check_true(Service.isLoggedIn, "already logged in");
-
- yield syncAndExpectNodeReassignment(server,
- "weave:service:sync:error",
- undo,
- "weave:service:sync:finish",
- Service.infoURL);
-});
-
-// This test ends up being a failing info fetch *before we're logged in*.
-// In this case we expect to recover during the login phase - so the first
-// sync succeeds.
-add_task(function* test_momentary_401_info_collections_loggedout() {
- _("Test a failure for info/collections before login that's resolved by reassignment.");
-
- let oldHandler;
- let sawTokenFetch = false;
-
- function afterTokenFetch() {
- // After a single token fetch, we undo our evil handleReassign hack, so
- // the next /info request returns the collection instead of a 401
- server.toplevelHandlers.info = oldHandler;
- sawTokenFetch = true;
- }
-
- let server = yield prepareServer(afterTokenFetch);
-
- // Return a 401 for the next /info request - it will be reset immediately
- // after a new token is fetched.
- oldHandler = server.toplevelHandlers.info
- server.toplevelHandlers.info = handleReassign;
-
- do_check_false(Service.isLoggedIn, "not already logged in");
-
- Service.sync();
- do_check_eq(Status.sync, SYNC_SUCCEEDED, "sync succeeded");
- // sync was successful - check we grabbed a new token.
- do_check_true(sawTokenFetch, "a new token was fetched by this test.")
- // and we are done.
- Service.startOver();
- let deferred = Promise.defer();
- server.stop(deferred.resolve);
- yield deferred.promise;
-});
-
-// This test ends up being a failing meta/global fetch *after we're already logged in*.
-add_task(function* test_momentary_401_storage_loggedin() {
- _("Test a failure for any storage URL after login that's resolved by" +
- "reassignment.");
- let server = yield prepareServer();
-
- _("First sync to prepare server contents.");
- Service.sync();
-
- _("Arrange for meta/global to return a 401.");
- let oldHandler = server.toplevelHandlers.storage;
- server.toplevelHandlers.storage = handleReassign;
-
- function undo() {
- _("Undoing test changes.");
- server.toplevelHandlers.storage = oldHandler;
- }
-
- do_check_true(Service.isLoggedIn, "already logged in");
-
- yield syncAndExpectNodeReassignment(server,
- "weave:service:sync:error",
- undo,
- "weave:service:sync:finish",
- Service.storageURL + "meta/global");
-});
-
-// This test ends up being a failing meta/global fetch *before we've logged in*.
-add_task(function* test_momentary_401_storage_loggedout() {
- _("Test a failure for any storage URL before login, not just engine parts. " +
- "Resolved by reassignment.");
- let server = yield prepareServer();
-
- // Return a 401 for all storage requests.
- let oldHandler = server.toplevelHandlers.storage;
- server.toplevelHandlers.storage = handleReassign;
-
- function undo() {
- _("Undoing test changes.");
- server.toplevelHandlers.storage = oldHandler;
- }
-
- do_check_false(Service.isLoggedIn, "already logged in");
-
- yield syncAndExpectNodeReassignment(server,
- "weave:service:login:error",
- undo,
- "weave:service:sync:finish",
- Service.storageURL + "meta/global");
-});
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+_("Test that node reassignment happens correctly using the FxA identity mgr.");
+// The node-reassignment logic is quite different for FxA than for the legacy
+// provider. In particular, there's no special request necessary for
+// reassignment - it comes from the token server - so we need to ensure the
+// Fxa cluster manager grabs a new token.
+
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-common/rest.js");
+Cu.import("resource://services-sync/constants.js");
+Cu.import("resource://services-sync/service.js");
+Cu.import("resource://services-sync/status.js");
+Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/rotaryengine.js");
+Cu.import("resource://services-sync/browserid_identity.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
+
+Service.engineManager.clear();
+
+function run_test() {
+ Log.repository.getLogger("Sync.AsyncResource").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.Resource").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.RESTRequest").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
+ Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
+ initTestLogging();
+
+ Service.engineManager.register(RotaryEngine);
+
+ // Setup the FxA identity manager and cluster manager.
+ Status.__authManager = Service.identity = new BrowserIDManager();
+ Service._clusterManager = Service.identity.createClusterManager(Service);
+
+ // None of the failures in this file should result in a UI error.
+ function onUIError() {
+ do_throw("Errors should not be presented in the UI.");
+ }
+ Svc.Obs.add("weave:ui:login:error", onUIError);
+ Svc.Obs.add("weave:ui:sync:error", onUIError);
+
+ run_next_test();
+}
+
+
+// API-compatible with SyncServer handler. Bind `handler` to something to use
+// as a ServerCollection handler.
+function handleReassign(handler, req, resp) {
+ resp.setStatusLine(req.httpVersion, 401, "Node reassignment");
+ resp.setHeader("Content-Type", "application/json");
+ let reassignBody = JSON.stringify({error: "401inator in place"});
+ resp.bodyOutputStream.write(reassignBody, reassignBody.length);
+}
+
+let numTokenRequests = 0;
+
+function prepareServer(cbAfterTokenFetch) {
+ let config = makeIdentityConfig({username: "johndoe"});
+ let server = new SyncServer();
+ server.registerUser("johndoe");
+ server.start();
+
+ // Set the token endpoint for the initial token request that's done implicitly
+ // via configureIdentity.
+ config.fxaccount.token.endpoint = server.baseURI + "1.1/johndoe";
+ // And future token fetches will do magic around numReassigns.
+ let numReassigns = 0;
+ return configureIdentity(config).then(() => {
+ Service.identity._tokenServerClient = {
+ getTokenFromBrowserIDAssertion: function(uri, assertion, cb) {
+ // Build a new URL with trailing zeros for the SYNC_VERSION part - this
+ // will still be seen as equivalent by the test server, but different
+ // by sync itself.
+ numReassigns += 1;
+ let trailingZeros = new Array(numReassigns + 1).join('0');
+ let token = config.fxaccount.token;
+ token.endpoint = server.baseURI + "1.1" + trailingZeros + "/johndoe";
+ token.uid = config.username;
+ numTokenRequests += 1;
+ cb(null, token);
+ if (cbAfterTokenFetch) {
+ cbAfterTokenFetch();
+ }
+ },
+ };
+ Service.clusterURL = config.fxaccount.token.endpoint;
+ return server;
+ });
+}
+
+function getReassigned() {
+ try {
+ return Services.prefs.getBoolPref("services.sync.lastSyncReassigned");
+ } catch (ex if (ex.result == Cr.NS_ERROR_UNEXPECTED)) {
+ return false;
+ } catch (ex) {
+ do_throw("Got exception retrieving lastSyncReassigned: " +
+ Utils.exceptionStr(ex));
+ }
+}
+
+/**
+ * Make a test request to `url`, then watch the result of two syncs
+ * to ensure that a node request was made.
+ * Runs `between` between the two. This can be used to undo deliberate failure
+ * setup, detach observers, etc.
+ */
+function syncAndExpectNodeReassignment(server, firstNotification, between,
+ secondNotification, url) {
+ _("Starting syncAndExpectNodeReassignment\n");
+ let deferred = Promise.defer();
+ function onwards() {
+ let numTokenRequestsBefore;
+ function onFirstSync() {
+ _("First sync completed.");
+ Svc.Obs.remove(firstNotification, onFirstSync);
+ Svc.Obs.add(secondNotification, onSecondSync);
+
+ do_check_eq(Service.clusterURL, "");
+
+ // Track whether we fetched a new token.
+ numTokenRequestsBefore = numTokenRequests;
+
+ // Allow for tests to clean up error conditions.
+ between();
+ }
+ function onSecondSync() {
+ _("Second sync completed.");
+ Svc.Obs.remove(secondNotification, onSecondSync);
+ Service.scheduler.clearSyncTriggers();
+
+ // Make absolutely sure that any event listeners are done with their work
+ // before we proceed.
+ waitForZeroTimer(function () {
+ _("Second sync nextTick.");
+ do_check_eq(numTokenRequests, numTokenRequestsBefore + 1, "fetched a new token");
+ Service.startOver();
+ server.stop(deferred.resolve);
+ });
+ }
+
+ Svc.Obs.add(firstNotification, onFirstSync);
+ Service.sync();
+ }
+
+ // Make sure that it works!
+ _("Making request to " + url + " which should 401");
+ let request = new RESTRequest(url);
+ request.get(function () {
+ do_check_eq(request.response.status, 401);
+ Utils.nextTick(onwards);
+ });
+ yield deferred.promise;
+}
+
+add_task(function test_momentary_401_engine() {
+ _("Test a failure for engine URLs that's resolved by reassignment.");
+ let server = yield prepareServer();
+ let john = server.user("johndoe");
+
+ _("Enabling the Rotary engine.");
+ let engine = Service.engineManager.get("rotary");
+ engine.enabled = true;
+
+ // We need the server to be correctly set up prior to experimenting. Do this
+ // through a sync.
+ let global = {syncID: Service.syncID,
+ storageVersion: STORAGE_VERSION,
+ rotary: {version: engine.version,
+ syncID: engine.syncID}}
+ john.createCollection("meta").insert("global", global);
+
+ _("First sync to prepare server contents.");
+ Service.sync();
+
+ _("Setting up Rotary collection to 401.");
+ let rotary = john.createCollection("rotary");
+ let oldHandler = rotary.collectionHandler;
+ rotary.collectionHandler = handleReassign.bind(this, undefined);
+
+ // We want to verify that the clusterURL pref has been cleared after a 401
+ // inside a sync. Flag the Rotary engine to need syncing.
+ john.collection("rotary").timestamp += 1000;
+
+ function between() {
+ _("Undoing test changes.");
+ rotary.collectionHandler = oldHandler;
+
+ function onLoginStart() {
+ // lastSyncReassigned shouldn't be cleared until a sync has succeeded.
+ _("Ensuring that lastSyncReassigned is still set at next sync start.");
+ Svc.Obs.remove("weave:service:login:start", onLoginStart);
+ do_check_true(getReassigned());
+ }
+
+ _("Adding observer that lastSyncReassigned is still set on login.");
+ Svc.Obs.add("weave:service:login:start", onLoginStart);
+ }
+
+ yield syncAndExpectNodeReassignment(server,
+ "weave:service:sync:finish",
+ between,
+ "weave:service:sync:finish",
+ Service.storageURL + "rotary");
+});
+
+// This test ends up being a failing info fetch *after we're already logged in*.
+add_task(function test_momentary_401_info_collections_loggedin() {
+ _("Test a failure for info/collections after login that's resolved by reassignment.");
+ let server = yield prepareServer();
+
+ _("First sync to prepare server contents.");
+ Service.sync();
+
+ _("Arrange for info/collections to return a 401.");
+ let oldHandler = server.toplevelHandlers.info;
+ server.toplevelHandlers.info = handleReassign;
+
+ function undo() {
+ _("Undoing test changes.");
+ server.toplevelHandlers.info = oldHandler;
+ }
+
+ do_check_true(Service.isLoggedIn, "already logged in");
+
+ yield syncAndExpectNodeReassignment(server,
+ "weave:service:sync:error",
+ undo,
+ "weave:service:sync:finish",
+ Service.infoURL);
+});
+
+// This test ends up being a failing info fetch *before we're logged in*.
+// In this case we expect to recover during the login phase - so the first
+// sync succeeds.
+add_task(function test_momentary_401_info_collections_loggedout() {
+ _("Test a failure for info/collections before login that's resolved by reassignment.");
+
+ let oldHandler;
+ let sawTokenFetch = false;
+
+ function afterTokenFetch() {
+ // After a single token fetch, we undo our evil handleReassign hack, so
+ // the next /info request returns the collection instead of a 401
+ server.toplevelHandlers.info = oldHandler;
+ sawTokenFetch = true;
+ }
+
+ let server = yield prepareServer(afterTokenFetch);
+
+ // Return a 401 for the next /info request - it will be reset immediately
+ // after a new token is fetched.
+ oldHandler = server.toplevelHandlers.info
+ server.toplevelHandlers.info = handleReassign;
+
+ do_check_false(Service.isLoggedIn, "not already logged in");
+
+ Service.sync();
+ do_check_eq(Status.sync, SYNC_SUCCEEDED, "sync succeeded");
+ // sync was successful - check we grabbed a new token.
+ do_check_true(sawTokenFetch, "a new token was fetched by this test.")
+ // and we are done.
+ Service.startOver();
+ let deferred = Promise.defer();
+ server.stop(deferred.resolve);
+ yield deferred.promise;
+});
+
+// This test ends up being a failing meta/global fetch *after we're already logged in*.
+add_task(function test_momentary_401_storage_loggedin() {
+ _("Test a failure for any storage URL after login that's resolved by" +
+ "reassignment.");
+ let server = yield prepareServer();
+
+ _("First sync to prepare server contents.");
+ Service.sync();
+
+ _("Arrange for meta/global to return a 401.");
+ let oldHandler = server.toplevelHandlers.storage;
+ server.toplevelHandlers.storage = handleReassign;
+
+ function undo() {
+ _("Undoing test changes.");
+ server.toplevelHandlers.storage = oldHandler;
+ }
+
+ do_check_true(Service.isLoggedIn, "already logged in");
+
+ yield syncAndExpectNodeReassignment(server,
+ "weave:service:sync:error",
+ undo,
+ "weave:service:sync:finish",
+ Service.storageURL + "meta/global");
+});
+
+// This test ends up being a failing meta/global fetch *before we've logged in*.
+add_task(function test_momentary_401_storage_loggedout() {
+ _("Test a failure for any storage URL before login, not just engine parts. " +
+ "Resolved by reassignment.");
+ let server = yield prepareServer();
+
+ // Return a 401 for all storage requests.
+ let oldHandler = server.toplevelHandlers.storage;
+ server.toplevelHandlers.storage = handleReassign;
+
+ function undo() {
+ _("Undoing test changes.");
+ server.toplevelHandlers.storage = oldHandler;
+ }
+
+ do_check_false(Service.isLoggedIn, "already logged in");
+
+ yield syncAndExpectNodeReassignment(server,
+ "weave:service:login:error",
+ undo,
+ "weave:service:sync:finish",
+ Service.storageURL + "meta/global");
+});
+
diff --git a/services/sync/tests/unit/test_fxa_service_cluster.js b/services/sync/tests/unit/test_fxa_service_cluster.js
index b4f83a7fe..f6f97184a 100644
--- a/services/sync/tests/unit/test_fxa_service_cluster.js
+++ b/services/sync/tests/unit/test_fxa_service_cluster.js
@@ -1,68 +1,68 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/fxa_utils.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-add_task(function* test_findCluster() {
- _("Test FxA _findCluster()");
-
- _("_findCluster() throws on 500 errors.");
- initializeIdentityWithTokenServerResponse({
- status: 500,
- headers: [],
- body: "",
- });
-
- yield Service.identity.initializeWithCurrentIdentity();
- yield Assert.rejects(Service.identity.whenReadyToAuthenticate.promise,
- "should reject due to 500");
-
- Assert.throws(function() {
- Service._clusterManager._findCluster();
- });
-
- _("_findCluster() returns null on authentication errors.");
- initializeIdentityWithTokenServerResponse({
- status: 401,
- headers: {"content-type": "application/json"},
- body: "{}",
- });
-
- yield Service.identity.initializeWithCurrentIdentity();
- yield Assert.rejects(Service.identity.whenReadyToAuthenticate.promise,
- "should reject due to 401");
-
- cluster = Service._clusterManager._findCluster();
- Assert.strictEqual(cluster, null);
-
- _("_findCluster() works with correct tokenserver response.");
- let endpoint = "http://example.com/something";
- initializeIdentityWithTokenServerResponse({
- status: 200,
- headers: {"content-type": "application/json"},
- body:
- JSON.stringify({
- api_endpoint: endpoint,
- duration: 300,
- id: "id",
- key: "key",
- uid: "uid",
- })
- });
-
- yield Service.identity.initializeWithCurrentIdentity();
- yield Service.identity.whenReadyToAuthenticate.promise;
- cluster = Service._clusterManager._findCluster();
- // The cluster manager ensures a trailing "/"
- Assert.strictEqual(cluster, endpoint + "/");
-
- Svc.Prefs.resetBranch("");
-});
-
-function run_test() {
- initTestLogging();
- run_next_test();
-}
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource://services-sync/service.js");
+Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/fxa_utils.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
+
+add_task(function test_findCluster() {
+ _("Test FxA _findCluster()");
+
+ _("_findCluster() throws on 500 errors.");
+ initializeIdentityWithTokenServerResponse({
+ status: 500,
+ headers: [],
+ body: "",
+ });
+
+ yield Service.identity.initializeWithCurrentIdentity();
+ yield Assert.rejects(Service.identity.whenReadyToAuthenticate.promise,
+ "should reject due to 500");
+
+ Assert.throws(function() {
+ Service._clusterManager._findCluster();
+ });
+
+ _("_findCluster() returns null on authentication errors.");
+ initializeIdentityWithTokenServerResponse({
+ status: 401,
+ headers: {"content-type": "application/json"},
+ body: "{}",
+ });
+
+ yield Service.identity.initializeWithCurrentIdentity();
+ yield Assert.rejects(Service.identity.whenReadyToAuthenticate.promise,
+ "should reject due to 401");
+
+ cluster = Service._clusterManager._findCluster();
+ Assert.strictEqual(cluster, null);
+
+ _("_findCluster() works with correct tokenserver response.");
+ let endpoint = "http://example.com/something";
+ initializeIdentityWithTokenServerResponse({
+ status: 200,
+ headers: {"content-type": "application/json"},
+ body:
+ JSON.stringify({
+ api_endpoint: endpoint,
+ duration: 300,
+ id: "id",
+ key: "key",
+ uid: "uid",
+ })
+ });
+
+ yield Service.identity.initializeWithCurrentIdentity();
+ yield Service.identity.whenReadyToAuthenticate.promise;
+ cluster = Service._clusterManager._findCluster();
+ // The cluster manager ensures a trailing "/"
+ Assert.strictEqual(cluster, endpoint + "/");
+
+ Svc.Prefs.resetBranch("");
+});
+
+function run_test() {
+ initTestLogging();
+ run_next_test();
+}
diff --git a/services/sync/tests/unit/test_fxa_startOver.js b/services/sync/tests/unit/test_fxa_startOver.js
index 629379648..e27d86ea0 100644
--- a/services/sync/tests/unit/test_fxa_startOver.js
+++ b/services/sync/tests/unit/test_fxa_startOver.js
@@ -1,63 +1,63 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://services-sync/identity.js");
-Cu.import("resource://services-sync/browserid_identity.js");
-Cu.import("resource://services-sync/service.js");
-
-function run_test() {
- initTestLogging("Trace");
- run_next_test();
-}
-
-add_task(function* test_startover() {
- let oldValue = Services.prefs.getBoolPref("services.sync-testing.startOverKeepIdentity", true);
- Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", false);
-
- ensureLegacyIdentityManager();
- yield configureIdentity({username: "johndoe"});
-
- // The boolean flag on the xpcom service should reflect a legacy provider.
- let xps = Cc["@mozilla.org/weave/service;1"]
- .getService(Components.interfaces.nsISupports)
- .wrappedJSObject;
- do_check_false(xps.fxAccountsEnabled);
-
- // we expect the "legacy" provider (but can't instanceof that, as BrowserIDManager
- // extends it)
- do_check_false(Service.identity instanceof BrowserIDManager);
-
- Service.serverURL = "https://localhost/";
- Service.clusterURL = Service.serverURL;
-
- Service.login();
- // We should have a cluster URL
- do_check_true(Service.clusterURL.length > 0);
-
- // remember some stuff so we can reset it after.
- let oldIdentity = Service.identity;
- let oldClusterManager = Service._clusterManager;
- let deferred = Promise.defer();
- Services.obs.addObserver(function observeStartOverFinished() {
- Services.obs.removeObserver(observeStartOverFinished, "weave:service:start-over:finish");
- deferred.resolve();
- }, "weave:service:start-over:finish", false);
-
- Service.startOver();
- yield deferred.promise; // wait for the observer to fire.
-
- // the xpcom service should indicate FxA is enabled.
- do_check_true(xps.fxAccountsEnabled);
- // should have swapped identities.
- do_check_true(Service.identity instanceof BrowserIDManager);
- // should have clobbered the cluster URL
- do_check_eq(Service.clusterURL, "");
-
- // we should have thrown away the old identity provider and cluster manager.
- do_check_neq(oldIdentity, Service.identity);
- do_check_neq(oldClusterManager, Service._clusterManager);
-
- // reset the world.
- Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", oldValue);
-});
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource://testing-common/services/sync/utils.js");
+Cu.import("resource://services-sync/identity.js");
+Cu.import("resource://services-sync/browserid_identity.js");
+Cu.import("resource://services-sync/service.js");
+
+function run_test() {
+ initTestLogging("Trace");
+ run_next_test();
+}
+
+add_task(function* test_startover() {
+ let oldValue = Services.prefs.getBoolPref("services.sync-testing.startOverKeepIdentity", true);
+ Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", false);
+
+ ensureLegacyIdentityManager();
+ yield configureIdentity({username: "johndoe"});
+
+ // The boolean flag on the xpcom service should reflect a legacy provider.
+ let xps = Cc["@mozilla.org/weave/service;1"]
+ .getService(Components.interfaces.nsISupports)
+ .wrappedJSObject;
+ do_check_false(xps.fxAccountsEnabled);
+
+ // we expect the "legacy" provider (but can't instanceof that, as BrowserIDManager
+ // extends it)
+ do_check_false(Service.identity instanceof BrowserIDManager);
+
+ Service.serverURL = "https://localhost/";
+ Service.clusterURL = Service.serverURL;
+
+ Service.login();
+ // We should have a cluster URL
+ do_check_true(Service.clusterURL.length > 0);
+
+ // remember some stuff so we can reset it after.
+ let oldIdentity = Service.identity;
+ let oldClusterManager = Service._clusterManager;
+ let deferred = Promise.defer();
+ Services.obs.addObserver(function observeStartOverFinished() {
+ Services.obs.removeObserver(observeStartOverFinished, "weave:service:start-over:finish");
+ deferred.resolve();
+ }, "weave:service:start-over:finish", false);
+
+ Service.startOver();
+ yield deferred.promise; // wait for the observer to fire.
+
+ // the xpcom service should indicate FxA is enabled.
+ do_check_true(xps.fxAccountsEnabled);
+ // should have swapped identities.
+ do_check_true(Service.identity instanceof BrowserIDManager);
+ // should have clobbered the cluster URL
+ do_check_eq(Service.clusterURL, "");
+
+ // we should have thrown away the old identity provider and cluster manager.
+ do_check_neq(oldIdentity, Service.identity);
+ do_check_neq(oldClusterManager, Service._clusterManager);
+
+ // reset the world.
+ Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", oldValue);
+});
diff --git a/services/sync/tests/unit/test_healthreport.js b/services/sync/tests/unit/test_healthreport.js
new file mode 100644
index 000000000..486320b6a
--- /dev/null
+++ b/services/sync/tests/unit/test_healthreport.js
@@ -0,0 +1,194 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Metrics.jsm", this);
+Cu.import("resource://gre/modules/Preferences.jsm", this);
+Cu.import("resource://gre/modules/Promise.jsm", this);
+Cu.import("resource://services-sync/main.js", this);
+Cu.import("resource://services-sync/healthreport.jsm", this);
+Cu.import("resource://testing-common/services/common/logging.js", this);
+Cu.import("resource://testing-common/services/healthreport/utils.jsm", this);
+
+function run_test() {
+ initTestLogging();
+
+ run_next_test();
+}
+
+add_task(function test_constructor() {
+ let provider = new SyncProvider();
+});
+
+// Provider can initialize and de-initialize properly.
+add_task(function* test_init() {
+ let storage = yield Metrics.Storage("init");
+ let provider = new SyncProvider();
+ yield provider.init(storage);
+ yield provider.shutdown();
+ yield storage.close();
+});
+
+add_task(function* test_collect() {
+ let storage = yield Metrics.Storage("collect");
+ let provider = new SyncProvider();
+ yield provider.init(storage);
+
+ // Initially nothing should be configured.
+ let now = new Date();
+ yield provider.collectDailyData();
+
+ let m = provider.getMeasurement("sync", 1);
+ let values = yield m.getValues();
+ Assert.equal(values.days.size, 1);
+ Assert.ok(values.days.hasDay(now));
+ let day = values.days.getDay(now);
+ Assert.ok(day.has("enabled"));
+ Assert.ok(day.has("activeProtocol"));
+ Assert.ok(day.has("preferredProtocol"));
+ Assert.equal(day.get("enabled"), 0);
+ Assert.equal(day.get("preferredProtocol"), "1.5");
+ Assert.equal(day.get("activeProtocol"), "1.5",
+ "Protocol without setup should be FX Accounts version.");
+
+ // Now check for old Sync setup.
+ let branch = new Preferences("services.sync.");
+ branch.set("username", "foo");
+ branch.reset("fxaccounts.enabled");
+ yield provider.collectDailyData();
+ values = yield m.getValues();
+ Assert.equal(values.days.getDay(now).get("activeProtocol"), "1.1",
+ "Protocol with old Sync setup is correct.");
+
+ Assert.equal(Weave.Status.__authManager, undefined, "Detect code changes");
+
+ // Let's enable Sync so we can get more useful data.
+ // We need to do this because the FHR probe only records more info if Sync
+ // is configured properly.
+ Weave.Service.identity.account = "johndoe";
+ Weave.Service.identity.basicPassword = "ilovejane";
+ Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase();
+ Weave.Service.clusterURL = "http://localhost/";
+ Assert.equal(Weave.Status.checkSetup(), Weave.STATUS_OK);
+
+ yield provider.collectDailyData();
+ values = yield m.getValues();
+ day = values.days.getDay(now);
+ Assert.equal(day.get("enabled"), 1);
+
+ // An empty account should have 1 device: us.
+ let dm = provider.getMeasurement("devices", 1);
+ values = yield dm.getValues();
+ Assert.ok(values.days.hasDay(now));
+ day = values.days.getDay(now);
+ Assert.equal(day.size, 1);
+ let engine = Weave.Service.clientsEngine;
+ Assert.ok(engine);
+ Assert.ok(day.has(engine.localType));
+ Assert.equal(day.get(engine.localType), 1);
+
+ // Add some devices and ensure they show up.
+ engine._store._remoteClients["id1"] = {type: "mobile"};
+ engine._store._remoteClients["id2"] = {type: "tablet"};
+ engine._store._remoteClients["id3"] = {type: "mobile"};
+
+ yield provider.collectDailyData();
+ values = yield dm.getValues();
+ day = values.days.getDay(now);
+
+ let expected = {
+ "foobar": 0,
+ "tablet": 1,
+ "mobile": 2,
+ "desktop": 0,
+ };
+
+ for (let type in expected) {
+ let count = expected[type];
+
+ if (engine.localType == type) {
+ count++;
+ }
+
+ if (!count) {
+ Assert.ok(!day.has(type));
+ } else {
+ Assert.ok(day.has(type));
+ Assert.equal(day.get(type), count);
+ }
+ }
+
+ engine._store._remoteClients = {};
+
+ yield provider.shutdown();
+ yield storage.close();
+});
+
+add_task(function* test_sync_events() {
+ let storage = yield Metrics.Storage("sync_events");
+ let provider = new SyncProvider();
+ yield provider.init(storage);
+
+ let m = provider.getMeasurement("sync", 1);
+
+ for (let i = 0; i < 5; i++) {
+ Services.obs.notifyObservers(null, "weave:service:sync:start", null);
+ }
+
+ for (let i = 0; i < 3; i++) {
+ Services.obs.notifyObservers(null, "weave:service:sync:finish", null);
+ }
+
+ for (let i = 0; i < 2; i++) {
+ Services.obs.notifyObservers(null, "weave:service:sync:error", null);
+ }
+
+ // Wait for storage to complete.
+ yield m.storage.enqueueOperation(() => {
+ return Promise.resolve();
+ });
+
+ let values = yield m.getValues();
+ let now = new Date();
+ Assert.ok(values.days.hasDay(now));
+ let day = values.days.getDay(now);
+
+ Assert.ok(day.has("syncStart"));
+ Assert.ok(day.has("syncSuccess"));
+ Assert.ok(day.has("syncError"));
+ Assert.equal(day.get("syncStart"), 5);
+ Assert.equal(day.get("syncSuccess"), 3);
+ Assert.equal(day.get("syncError"), 2);
+
+ yield provider.shutdown();
+ yield storage.close();
+});
+
+add_task(function* test_healthreporter_json() {
+ let reporter = yield getHealthReporter("healthreporter_json");
+ yield reporter.init();
+ try {
+ yield reporter._providerManager.registerProvider(new SyncProvider());
+ yield reporter.collectMeasurements();
+ let payload = yield reporter.getJSONPayload(true);
+ let now = new Date();
+ let today = reporter._formatDate(now);
+
+ Assert.ok(today in payload.data.days);
+ let day = payload.data.days[today];
+
+ Assert.ok("org.mozilla.sync.sync" in day);
+ Assert.ok("org.mozilla.sync.devices" in day);
+
+ let devices = day["org.mozilla.sync.devices"];
+ let engine = Weave.Service.clientsEngine;
+ Assert.ok(engine);
+ let type = engine.localType;
+ Assert.ok(type);
+ Assert.ok(type in devices);
+ Assert.equal(devices[type], 1);
+ } finally {
+ reporter._shutdown();
+ }
+});
diff --git a/services/sync/tests/unit/test_healthreport_migration.js b/services/sync/tests/unit/test_healthreport_migration.js
new file mode 100644
index 000000000..23f756748
--- /dev/null
+++ b/services/sync/tests/unit/test_healthreport_migration.js
@@ -0,0 +1,155 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Metrics.jsm", this);
+Cu.import("resource://gre/modules/Preferences.jsm", this);
+Cu.import("resource://gre/modules/Promise.jsm", this);
+Cu.import("resource://services-sync/healthreport.jsm", this);
+Cu.import("resource://services-sync/FxaMigrator.jsm", this);
+Cu.import("resource://testing-common/services/common/logging.js", this);
+Cu.import("resource://testing-common/services/healthreport/utils.jsm", this);
+
+
+function run_test() {
+ initTestLogging();
+
+ run_next_test();
+}
+
+add_task(function* test_no_data() {
+ let storage = yield Metrics.Storage("collect");
+ let provider = new SyncProvider();
+ yield provider.init(storage);
+
+ try {
+ // Initially nothing should be configured.
+ let now = new Date();
+ yield provider.collectDailyData();
+
+ let m = provider.getMeasurement("migration", 1);
+ let values = yield m.getValues();
+ Assert.equal(values.days.size, 0);
+ Assert.ok(!values.days.hasDay(now));
+ } finally {
+ yield provider.shutdown();
+ yield storage.close();
+ }
+});
+
+function checkCorrectStateRecorded(provider, state) {
+ // Wait for storage to complete.
+ yield m.storage.enqueueOperation(() => {
+ return Promise.resolve();
+ });
+
+ let m = provider.getMeasurement("migration", 1);
+ let values = yield m.getValues();
+ Assert.equal(values.days.size, 1);
+ Assert.ok(values.days.hasDay(now));
+ let day = values.days.getDay(now);
+
+ Assert.ok(day.has("state"));
+ Assert.equal(day.get("state"), state);
+}
+
+add_task(function* test_state() {
+ let storage = yield Metrics.Storage("collect");
+ let provider = new SyncProvider();
+ yield provider.init(storage);
+
+ try {
+ // Initially nothing should be configured.
+ let now = new Date();
+
+ // We record both a "user" and "internal" state in the same field.
+ // So simulate a "user" state first.
+ Services.obs.notifyObservers(null, "fxa-migration:state-changed",
+ fxaMigrator.STATE_USER_FXA_VERIFIED);
+ checkCorrectStateRecorded(provider, fxaMigrator.STATE_USER_FXA_VERIFIED);
+
+ // And an internal state.
+ Services.obs.notifyObservers(null, "fxa-migration:internal-state-changed",
+ fxaMigrator.STATE_INTERNAL_WAITING_SYNC_COMPLETE);
+ checkCorrectStateRecorded(provider, fxaMigrator.STATE_INTERNAL_WAITING_SYNC_COMPLETE);
+ } finally {
+ yield provider.shutdown();
+ yield storage.close();
+ }
+});
+
+add_task(function* test_flags() {
+ let storage = yield Metrics.Storage("collect");
+ let provider = new SyncProvider();
+ yield provider.init(storage);
+
+ try {
+ // Initially nothing should be configured.
+ let now = new Date();
+
+ let m = provider.getMeasurement("migration", 1);
+
+ let record = function*(what) {
+ Services.obs.notifyObservers(null, "fxa-migration:internal-telemetry", what);
+ // Wait for storage to complete.
+ yield m.storage.enqueueOperation(Promise.resolve);
+ let values = yield m.getValues();
+ Assert.equal(values.days.size, 1);
+ return values.days.getDay(now);
+ }
+
+ let values = yield m.getValues();
+ Assert.equal(values.days.size, 1);
+ let day = values.days.getDay(now);
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_ACCEPTED));
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_DECLINED));
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
+
+ // let's send an unknown value to ensure our error mitigation works.
+ day = yield record("unknown");
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_ACCEPTED));
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_DECLINED));
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
+
+ // record an fxaMigrator.TELEMETRY_ACCEPTED state.
+ day = yield record(fxaMigrator.TELEMETRY_ACCEPTED);
+ Assert.ok(day.has(fxaMigrator.TELEMETRY_ACCEPTED));
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_DECLINED));
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
+ Assert.equal(day.get(fxaMigrator.TELEMETRY_ACCEPTED), 1);
+
+ // and again - it should get 2.
+ day = yield record(fxaMigrator.TELEMETRY_ACCEPTED);
+ Assert.equal(day.get(fxaMigrator.TELEMETRY_ACCEPTED), 2);
+
+ // record fxaMigrator.TELEMETRY_DECLINED - also a counter.
+ day = yield record(fxaMigrator.TELEMETRY_DECLINED);
+ Assert.ok(day.has(fxaMigrator.TELEMETRY_ACCEPTED));
+ Assert.ok(day.has(fxaMigrator.TELEMETRY_DECLINED));
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
+ Assert.equal(day.get(fxaMigrator.TELEMETRY_ACCEPTED), 2);
+ Assert.equal(day.get(fxaMigrator.TELEMETRY_DECLINED), 1);
+
+ day = yield record(fxaMigrator.TELEMETRY_DECLINED);
+ Assert.ok(day.has(fxaMigrator.TELEMETRY_ACCEPTED));
+ Assert.ok(day.has(fxaMigrator.TELEMETRY_DECLINED));
+ Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
+ Assert.equal(day.get(fxaMigrator.TELEMETRY_ACCEPTED), 2);
+ Assert.equal(day.get(fxaMigrator.TELEMETRY_DECLINED), 2);
+
+ // and fxaMigrator.TELEMETRY_UNLINKED - this is conceptually a "daily bool".
+ // (ie, it's DAILY_LAST_NUMERIC_FIELD and only ever has |1| written to it)
+ day = yield record(fxaMigrator.TELEMETRY_UNLINKED);
+ Assert.ok(day.has(fxaMigrator.TELEMETRY_ACCEPTED));
+ Assert.ok(day.has(fxaMigrator.TELEMETRY_DECLINED));
+ Assert.ok(day.has(fxaMigrator.TELEMETRY_UNLINKED));
+ Assert.equal(day.get(fxaMigrator.TELEMETRY_UNLINKED), 1);
+ // and doing it again still leaves us with |1|
+ day = yield record(fxaMigrator.TELEMETRY_UNLINKED);
+ Assert.equal(day.get(fxaMigrator.TELEMETRY_UNLINKED), 1);
+ } finally {
+ yield provider.shutdown();
+ yield storage.close();
+ }
+});
diff --git a/services/sync/tests/unit/test_history_store.js b/services/sync/tests/unit/test_history_store.js
index 207b621e0..2381f103d 100644
--- a/services/sync/tests/unit/test_history_store.js
+++ b/services/sync/tests/unit/test_history_store.js
@@ -68,12 +68,12 @@ function ensureThrows(func) {
};
}
-var store = new HistoryEngine(Service)._store;
+let store = new HistoryEngine(Service)._store;
function applyEnsureNoFailures(records) {
do_check_eq(store.applyIncomingBatch(records).length, 0);
}
-var fxuri, fxguid, tburi, tbguid;
+let fxuri, fxguid, tburi, tbguid;
function run_test() {
initTestLogging("Trace");
@@ -189,8 +189,8 @@ add_test(function test_invalid_records() {
.DBConnection;
let stmt = connection.createAsyncStatement(
"INSERT INTO moz_places "
- + "(url, url_hash, title, rev_host, visit_count, last_visit_date) "
- + "VALUES ('invalid-uri', hash('invalid-uri'), 'Invalid URI', '.', 1, " + TIMESTAMP3 + ")"
+ + "(url, title, rev_host, visit_count, last_visit_date) "
+ + "VALUES ('invalid-uri', 'Invalid URI', '.', 1, " + TIMESTAMP3 + ")"
);
Async.querySpinningly(stmt);
stmt.finalize();
@@ -198,7 +198,7 @@ add_test(function test_invalid_records() {
stmt = connection.createAsyncStatement(
"INSERT INTO moz_historyvisits "
+ "(place_id, visit_date, visit_type, session) "
- + "VALUES ((SELECT id FROM moz_places WHERE url_hash = hash('invalid-uri') AND url = 'invalid-uri'), "
+ + "VALUES ((SELECT id FROM moz_places WHERE url = 'invalid-uri'), "
+ TIMESTAMP3 + ", " + Ci.nsINavHistoryService.TRANSITION_TYPED + ", 1)"
);
Async.querySpinningly(stmt);
@@ -226,7 +226,7 @@ add_test(function test_invalid_records() {
type: Ci.nsINavHistoryService.TRANSITION_EMBED}]}
]);
- _("Make sure we handle records with invalid visit codes or visit dates, gracefully ignoring those visits.");
+ _("Make sure we report records with invalid visits, gracefully handle non-integer dates.");
let no_date_visit_guid = Utils.makeGUID();
let no_type_visit_guid = Utils.makeGUID();
let invalid_type_visit_guid = Utils.makeGUID();
@@ -235,11 +235,11 @@ add_test(function test_invalid_records() {
{id: no_date_visit_guid,
histUri: "http://no.date.visit/",
title: "Visit has no date",
- visits: [{type: Ci.nsINavHistoryService.TRANSITION_EMBED}]},
+ visits: [{date: TIMESTAMP3}]},
{id: no_type_visit_guid,
histUri: "http://no.type.visit/",
title: "Visit has no type",
- visits: [{date: TIMESTAMP3}]},
+ visits: [{type: Ci.nsINavHistoryService.TRANSITION_EMBED}]},
{id: invalid_type_visit_guid,
histUri: "http://invalid.type.visit/",
title: "Visit has invalid type",
@@ -251,7 +251,14 @@ add_test(function test_invalid_records() {
visits: [{date: 1234.567,
type: Ci.nsINavHistoryService.TRANSITION_EMBED}]}
]);
- do_check_eq(failed.length, 0);
+ do_check_eq(failed.length, 3);
+ failed.sort();
+ let expected = [no_date_visit_guid,
+ no_type_visit_guid,
+ invalid_type_visit_guid].sort();
+ for (let i = 0; i < expected.length; i++) {
+ do_check_eq(failed[i], expected[i]);
+ }
_("Make sure we handle records with javascript: URLs gracefully.");
applyEnsureNoFailures([
diff --git a/services/sync/tests/unit/test_history_tracker.js b/services/sync/tests/unit/test_history_tracker.js
index 5ed022fb0..ca1090b79 100644
--- a/services/sync/tests/unit/test_history_tracker.js
+++ b/services/sync/tests/unit/test_history_tracker.js
@@ -22,13 +22,13 @@ function onScoreUpdated(callback) {
Service.engineManager.clear();
Service.engineManager.register(HistoryEngine);
-var engine = Service.engineManager.get("history");
-var tracker = engine._tracker;
+let engine = Service.engineManager.get("history");
+let tracker = engine._tracker;
// Don't write out by default.
tracker.persistChangedIDs = false;
-var _counter = 0;
+let _counter = 0;
function addVisit() {
let uriString = "http://getfirefox.com/" + _counter++;
let uri = Utils.makeURI(uriString);
diff --git a/services/sync/tests/unit/test_hmac_error.js b/services/sync/tests/unit/test_hmac_error.js
index 272c0de47..e41ff3797 100644
--- a/services/sync/tests/unit/test_hmac_error.js
+++ b/services/sync/tests/unit/test_hmac_error.js
@@ -8,7 +8,7 @@ Cu.import("resource://testing-common/services/sync/rotaryengine.js");
Cu.import("resource://testing-common/services/sync/utils.js");
// Track HMAC error counts.
-var hmacErrorCount = 0;
+let hmacErrorCount = 0;
(function () {
let hHE = Service.handleHMACEvent;
Service.handleHMACEvent = function () {
@@ -49,7 +49,7 @@ function shared_setup() {
return [engine, rotaryColl, clientsColl, keysWBO, global];
}
-add_task(function *hmac_error_during_404() {
+add_test(function hmac_error_during_404() {
_("Attempt to replicate the HMAC error setup.");
let [engine, rotaryColl, clientsColl, keysWBO, global] = shared_setup();
@@ -83,14 +83,13 @@ add_task(function *hmac_error_during_404() {
try {
_("Syncing.");
- yield sync_and_validate_telem();
-
+ Service.sync();
_("Partially resetting client, as if after a restart, and forcing redownload.");
Service.collectionKeys.clear();
engine.lastSync = 0; // So that we redownload records.
key404Counter = 1;
_("---------------------------");
- yield sync_and_validate_telem();
+ Service.sync();
_("---------------------------");
// Two rotary items, one client record... no errors.
@@ -98,7 +97,7 @@ add_task(function *hmac_error_during_404() {
} finally {
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
- yield new Promise(resolve => server.stop(resolve));
+ server.stop(run_next_test);
}
});
diff --git a/services/sync/tests/unit/test_identity_manager.js b/services/sync/tests/unit/test_identity_manager.js
index 1ac198ade..97dace95f 100644
--- a/services/sync/tests/unit/test_identity_manager.js
+++ b/services/sync/tests/unit/test_identity_manager.js
@@ -5,7 +5,7 @@ Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/identity.js");
Cu.import("resource://services-sync/util.js");
-var identity = new IdentityManager();
+let identity = new IdentityManager();
function run_test() {
initTestLogging("Trace");
diff --git a/services/sync/tests/unit/test_interval_triggers.js b/services/sync/tests/unit/test_interval_triggers.js
index eca5ec289..0f355e636 100644
--- a/services/sync/tests/unit/test_interval_triggers.js
+++ b/services/sync/tests/unit/test_interval_triggers.js
@@ -10,13 +10,8 @@ Cu.import("resource://testing-common/services/sync/utils.js");
Svc.DefaultPrefs.set("registerEngines", "");
Cu.import("resource://services-sync/service.js");
-var scheduler = Service.scheduler;
-var clientsEngine = Service.clientsEngine;
-
-// Don't remove stale clients when syncing. This is a test-only workaround
-// that lets us add clients directly to the store, without losing them on
-// the next sync.
-clientsEngine._removeRemoteClient = id => {};
+let scheduler = Service.scheduler;
+let clientsEngine = Service.clientsEngine;
function promiseStopServer(server) {
let deferred = Promise.defer();
@@ -46,7 +41,7 @@ function sync_httpd_setup() {
});
}
-function* setUp(server) {
+function setUp(server) {
yield configureIdentity({username: "johndoe"});
Service.serverURL = server.baseURI + "/";
Service.clusterURL = server.baseURI + "/";
@@ -65,7 +60,7 @@ function run_test() {
run_next_test();
}
-add_identity_test(this, function* test_successful_sync_adjustSyncInterval() {
+add_identity_test(this, function test_successful_sync_adjustSyncInterval() {
_("Test successful sync calling adjustSyncInterval");
let syncSuccesses = 0;
function onSyncFinish() {
@@ -164,7 +159,7 @@ add_identity_test(this, function* test_successful_sync_adjustSyncInterval() {
yield promiseStopServer(server);
});
-add_identity_test(this, function* test_unsuccessful_sync_adjustSyncInterval() {
+add_identity_test(this, function test_unsuccessful_sync_adjustSyncInterval() {
_("Test unsuccessful sync calling adjustSyncInterval");
let syncFailures = 0;
@@ -269,7 +264,7 @@ add_identity_test(this, function* test_unsuccessful_sync_adjustSyncInterval() {
yield promiseStopServer(server);
});
-add_identity_test(this, function* test_back_triggers_sync() {
+add_identity_test(this, function test_back_triggers_sync() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -301,7 +296,7 @@ add_identity_test(this, function* test_back_triggers_sync() {
yield deferred.promise;
});
-add_identity_test(this, function* test_adjust_interval_on_sync_error() {
+add_identity_test(this, function test_adjust_interval_on_sync_error() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -332,7 +327,7 @@ add_identity_test(this, function* test_adjust_interval_on_sync_error() {
yield promiseStopServer(server);
});
-add_identity_test(this, function* test_bug671378_scenario() {
+add_identity_test(this, function test_bug671378_scenario() {
// Test scenario similar to bug 671378. This bug appeared when a score
// update occurred that wasn't large enough to trigger a sync so
// scheduleNextSync() was called without a time interval parameter,
diff --git a/services/sync/tests/unit/test_jpakeclient.js b/services/sync/tests/unit/test_jpakeclient.js
index 783edb460..ff13c5716 100644
--- a/services/sync/tests/unit/test_jpakeclient.js
+++ b/services/sync/tests/unit/test_jpakeclient.js
@@ -38,8 +38,8 @@ function new_channel() {
return cid;
}
-var server;
-var channels = {}; // Map channel -> ServerChannel object
+let server;
+let channels = {}; // Map channel -> ServerChannel object
function server_new_channel(request, response) {
check_headers(request);
let cid = new_channel();
@@ -48,7 +48,7 @@ function server_new_channel(request, response) {
response.bodyOutputStream.write(body, body.length);
}
-var error_report;
+let error_report;
function server_report(request, response) {
check_headers(request);
@@ -68,7 +68,7 @@ function server_report(request, response) {
}
// Hook for test code.
-var hooks = {};
+let hooks = {};
function initHooks() {
hooks.onGET = function onGET(request) {};
}
@@ -146,7 +146,7 @@ ServerChannel.prototype = {
/**
* Controller that throws for everything.
*/
-var BaseController = {
+let BaseController = {
displayPIN: function displayPIN() {
do_throw("displayPIN() shouldn't have been called!");
},
@@ -369,7 +369,7 @@ add_test(function test_wrongPIN() {
displayPIN: function displayPIN(pin) {
this.cid = pin.slice(JPAKE_LENGTH_SECRET);
let secret = pin.slice(0, JPAKE_LENGTH_SECRET);
- secret = Array.prototype.slice.call(secret).reverse().join("");
+ secret = [char for each (char in secret)].reverse().join("");
let new_pin = secret + this.cid;
_("Received PIN " + pin + ", but I'm entering " + new_pin);
diff --git a/services/sync/tests/unit/test_keys.js b/services/sync/tests/unit/test_keys.js
index a828b619c..6a2fdd027 100644
--- a/services/sync/tests/unit/test_keys.js
+++ b/services/sync/tests/unit/test_keys.js
@@ -7,7 +7,7 @@ Cu.import("resource://services-sync/keys.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/util.js");
-var collectionKeys = new CollectionKeyManager();
+let collectionKeys = new CollectionKeyManager();
function sha256HMAC(message, key) {
let h = Utils.makeHMACHasher(Ci.nsICryptoHMAC.SHA256, key);
diff --git a/services/sync/tests/unit/test_load_modules.js b/services/sync/tests/unit/test_load_modules.js
index 0b222520c..4f561bae6 100644
--- a/services/sync/tests/unit/test_load_modules.js
+++ b/services/sync/tests/unit/test_load_modules.js
@@ -9,7 +9,6 @@ const modules = [
"engines/addons.js",
"engines/bookmarks.js",
"engines/clients.js",
- "engines/extension-storage.js",
"engines/forms.js",
"engines/history.js",
"engines/passwords.js",
@@ -20,6 +19,7 @@ const modules = [
"jpakeclient.js",
"keys.js",
"main.js",
+ "notifications.js",
"policies.js",
"record.js",
"resource.js",
diff --git a/services/sync/tests/unit/test_node_reassignment.js b/services/sync/tests/unit/test_node_reassignment.js
index 66d21b6f1..7fe5ed7ed 100644
--- a/services/sync/tests/unit/test_node_reassignment.js
+++ b/services/sync/tests/unit/test_node_reassignment.js
@@ -23,7 +23,7 @@ function run_test() {
Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
initTestLogging();
- validate_all_future_pings();
+
ensureLegacyIdentityManager();
Service.engineManager.register(RotaryEngine);
@@ -92,12 +92,11 @@ function prepareServer() {
function getReassigned() {
try {
return Services.prefs.getBoolPref("services.sync.lastSyncReassigned");
+ } catch (ex if (ex.result == Cr.NS_ERROR_UNEXPECTED)) {
+ return false;
} catch (ex) {
- if (ex.result == Cr.NS_ERROR_UNEXPECTED) {
- return false;
- }
do_throw("Got exception retrieving lastSyncReassigned: " +
- Log.exceptionStr(ex));
+ Utils.exceptionStr(ex));
}
}
@@ -107,7 +106,7 @@ function getReassigned() {
* Runs `between` between the two. This can be used to undo deliberate failure
* setup, detach observers, etc.
*/
-function* syncAndExpectNodeReassignment(server, firstNotification, between,
+function syncAndExpectNodeReassignment(server, firstNotification, between,
secondNotification, url) {
let deferred = Promise.defer();
function onwards() {
@@ -161,7 +160,7 @@ function* syncAndExpectNodeReassignment(server, firstNotification, between,
yield deferred.promise;
}
-add_task(function* test_momentary_401_engine() {
+add_task(function test_momentary_401_engine() {
_("Test a failure for engine URLs that's resolved by reassignment.");
let server = yield prepareServer();
let john = server.user("johndoe");
@@ -213,7 +212,7 @@ add_task(function* test_momentary_401_engine() {
});
// This test ends up being a failing fetch *after we're already logged in*.
-add_task(function* test_momentary_401_info_collections() {
+add_task(function test_momentary_401_info_collections() {
_("Test a failure for info/collections that's resolved by reassignment.");
let server = yield prepareServer();
@@ -236,7 +235,7 @@ add_task(function* test_momentary_401_info_collections() {
Service.infoURL);
});
-add_task(function* test_momentary_401_storage_loggedin() {
+add_task(function test_momentary_401_storage_loggedin() {
_("Test a failure for any storage URL, not just engine parts. " +
"Resolved by reassignment.");
let server = yield prepareServer();
@@ -261,7 +260,7 @@ add_task(function* test_momentary_401_storage_loggedin() {
Service.storageURL + "meta/global");
});
-add_task(function* test_momentary_401_storage_loggedout() {
+add_task(function test_momentary_401_storage_loggedout() {
_("Test a failure for any storage URL, not just engine parts. " +
"Resolved by reassignment.");
let server = yield prepareServer();
@@ -283,7 +282,7 @@ add_task(function* test_momentary_401_storage_loggedout() {
Service.storageURL + "meta/global");
});
-add_task(function* test_loop_avoidance_storage() {
+add_task(function test_loop_avoidance_storage() {
_("Test that a repeated failure doesn't result in a sync loop " +
"if node reassignment cannot resolve the failure.");
@@ -383,7 +382,7 @@ add_task(function* test_loop_avoidance_storage() {
yield deferred.promise;
});
-add_task(function* test_loop_avoidance_engine() {
+add_task(function test_loop_avoidance_engine() {
_("Test that a repeated 401 in an engine doesn't result in a sync loop " +
"if node reassignment cannot resolve the failure.");
let server = yield prepareServer();
diff --git a/services/sync/tests/unit/test_notifications.js b/services/sync/tests/unit/test_notifications.js
new file mode 100644
index 000000000..9d6da1d2d
--- /dev/null
+++ b/services/sync/tests/unit/test_notifications.js
@@ -0,0 +1,32 @@
+Cu.import("resource://services-sync/notifications.js");
+
+function run_test() {
+ var logStats = initTestLogging("Info");
+
+ var blah = 0;
+
+ function callback(i) {
+ blah = i;
+ }
+
+ let button = new NotificationButton("label", "accessKey", callback);
+
+ button.callback(5);
+
+ do_check_eq(blah, 5);
+ do_check_eq(logStats.errorsLogged, 0);
+
+ function badCallback() {
+ throw new Error("oops");
+ }
+
+ button = new NotificationButton("label", "accessKey", badCallback);
+
+ try {
+ button.callback();
+ } catch (e) {
+ do_check_eq(e.message, "oops");
+ }
+
+ do_check_eq(logStats.errorsLogged, 1);
+}
diff --git a/services/sync/tests/unit/test_password_store.js b/services/sync/tests/unit/test_password_store.js
index d232d5e63..c56901d79 100644
--- a/services/sync/tests/unit/test_password_store.js
+++ b/services/sync/tests/unit/test_password_store.js
@@ -5,137 +5,6 @@ Cu.import("resource://services-sync/engines/passwords.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
-
-function checkRecord(name, record, expectedCount, timeCreated,
- expectedTimeCreated, timePasswordChanged,
- expectedTimePasswordChanged, recordIsUpdated) {
- let engine = Service.engineManager.get("passwords");
- let store = engine._store;
-
- let count = {};
- let logins = Services.logins.findLogins(count, record.hostname,
- record.formSubmitURL, null);
-
- _("Record" + name + ":" + JSON.stringify(logins));
- _("Count" + name + ":" + count.value);
-
- do_check_eq(count.value, expectedCount);
-
- if (expectedCount > 0) {
- do_check_true(!!store.getAllIDs()[record.id]);
- let stored_record = logins[0].QueryInterface(Ci.nsILoginMetaInfo);
-
- if (timeCreated !== undefined) {
- do_check_eq(stored_record.timeCreated, expectedTimeCreated);
- }
-
- if (timePasswordChanged !== undefined) {
- if (recordIsUpdated) {
- do_check_true(stored_record.timePasswordChanged >= expectedTimePasswordChanged);
- } else {
- do_check_eq(stored_record.timePasswordChanged, expectedTimePasswordChanged);
- }
- return stored_record.timePasswordChanged;
- }
- } else {
- do_check_true(!store.getAllIDs()[record.id]);
- }
-}
-
-
-function changePassword(name, hostname, password, expectedCount, timeCreated,
- expectedTimeCreated, timePasswordChanged,
- expectedTimePasswordChanged, insert, recordIsUpdated) {
-
- const BOGUS_GUID = "zzzzzz" + hostname;
-
- let record = {id: BOGUS_GUID,
- hostname: hostname,
- formSubmitURL: hostname,
- username: "john",
- password: password,
- usernameField: "username",
- passwordField: "password"};
-
- if (timeCreated !== undefined) {
- record.timeCreated = timeCreated;
- }
-
- if (timePasswordChanged !== undefined) {
- record.timePasswordChanged = timePasswordChanged;
- }
-
-
- let engine = Service.engineManager.get("passwords");
- let store = engine._store;
-
- if (insert) {
- do_check_eq(store.applyIncomingBatch([record]).length, 0);
- }
-
- return checkRecord(name, record, expectedCount, timeCreated,
- expectedTimeCreated, timePasswordChanged,
- expectedTimePasswordChanged, recordIsUpdated);
-
-}
-
-
-function test_apply_records_with_times(hostname, timeCreated, timePasswordChanged) {
- // The following record is going to be inserted in the store and it needs
- // to be found there. Then its timestamps are going to be compared to
- // the expected values.
- changePassword(" ", hostname, "password", 1, timeCreated, timeCreated,
- timePasswordChanged, timePasswordChanged, true);
-}
-
-
-function test_apply_multiple_records_with_times() {
- // The following records are going to be inserted in the store and they need
- // to be found there. Then their timestamps are going to be compared to
- // the expected values.
- changePassword("A", "http://foo.a.com", "password", 1, undefined, undefined,
- undefined, undefined, true);
- changePassword("B", "http://foo.b.com", "password", 1, 1000, 1000, undefined,
- undefined, true);
- changePassword("C", "http://foo.c.com", "password", 1, undefined, undefined,
- 1000, 1000, true);
- changePassword("D", "http://foo.d.com", "password", 1, 1000, 1000, 1000,
- 1000, true);
-
- // The following records are not going to be inserted in the store and they
- // are not going to be found there.
- changePassword("NotInStoreA", "http://foo.aaaa.com", "password", 0,
- undefined, undefined, undefined, undefined, false);
- changePassword("NotInStoreB", "http://foo.bbbb.com", "password", 0, 1000,
- 1000, undefined, undefined, false);
- changePassword("NotInStoreC", "http://foo.cccc.com", "password", 0,
- undefined, undefined, 1000, 1000, false);
- changePassword("NotInStoreD", "http://foo.dddd.com", "password", 0, 1000,
- 1000, 1000, 1000, false);
-}
-
-
-function test_apply_same_record_with_different_times() {
- // The following record is going to be inserted multiple times in the store
- // and it needs to be found there. Then its timestamps are going to be
- // compared to the expected values.
- var timePasswordChanged = 100;
- timePasswordChanged = changePassword("A", "http://a.tn", "password", 1, 100,
- 100, 100, timePasswordChanged, true);
- timePasswordChanged = changePassword("A", "http://a.tn", "password", 1, 100,
- 100, 800, timePasswordChanged, true,
- true);
- timePasswordChanged = changePassword("A", "http://a.tn", "password", 1, 500,
- 100, 800, timePasswordChanged, true,
- true);
- timePasswordChanged = changePassword("A", "http://a.tn", "password2", 1, 500,
- 100, 1536213005222, timePasswordChanged,
- true, true);
- timePasswordChanged = changePassword("A", "http://a.tn", "password2", 1, 500,
- 100, 800, timePasswordChanged, true, true);
-}
-
-
function run_test() {
initTestLogging("Trace");
Log.repository.getLogger("Sync.Engine.Passwords").level = Log.Level.Trace;
@@ -161,9 +30,12 @@ function run_test() {
let engine = Service.engineManager.get("passwords");
let store = engine._store;
+ function applyEnsureNoFailures(records) {
+ do_check_eq(store.applyIncomingBatch(records).length, 0);
+ }
try {
- do_check_eq(store.applyIncomingBatch([recordA, recordB]).length, 0);
+ applyEnsureNoFailures([recordA, recordB]);
// Only the good record makes it to Services.logins.
let badCount = {};
@@ -183,17 +55,7 @@ function run_test() {
do_check_true(!!store.getAllIDs()[BOGUS_GUID_B]);
do_check_true(!store.getAllIDs()[BOGUS_GUID_A]);
-
- test_apply_records_with_times("http://afoo.baz.com", undefined, undefined);
- test_apply_records_with_times("http://bfoo.baz.com", 1000, undefined);
- test_apply_records_with_times("http://cfoo.baz.com", undefined, 2000);
- test_apply_records_with_times("http://dfoo.baz.com", 1000, 2000);
-
- test_apply_multiple_records_with_times();
-
- test_apply_same_record_with_different_times();
-
} finally {
store.wipe();
}
-} \ No newline at end of file
+}
diff --git a/services/sync/tests/unit/test_password_tracker.js b/services/sync/tests/unit/test_password_tracker.js
index 09ca141a6..ddfc524ab 100644
--- a/services/sync/tests/unit/test_password_tracker.js
+++ b/services/sync/tests/unit/test_password_tracker.js
@@ -8,9 +8,9 @@ Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Service.engineManager.register(PasswordEngine);
-var engine = Service.engineManager.get("passwords");
-var store = engine._store;
-var tracker = engine._tracker;
+let engine = Service.engineManager.get("passwords");
+let store = engine._store;
+let tracker = engine._tracker;
// Don't do asynchronous writes.
tracker.persistChangedIDs = false;
diff --git a/services/sync/tests/unit/test_password_validator.js b/services/sync/tests/unit/test_password_validator.js
deleted file mode 100644
index a4a148fbe..000000000
--- a/services/sync/tests/unit/test_password_validator.js
+++ /dev/null
@@ -1,158 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Components.utils.import("resource://services-sync/engines/passwords.js");
-
-function getDummyServerAndClient() {
- return {
- server: [
- {
- id: "11111",
- guid: "11111",
- hostname: "https://www.11111.com",
- formSubmitURL: "https://www.11111.com/login",
- password: "qwerty123",
- passwordField: "pass",
- username: "foobar",
- usernameField: "user",
- httpRealm: null,
- },
- {
- id: "22222",
- guid: "22222",
- hostname: "https://www.22222.org",
- formSubmitURL: "https://www.22222.org/login",
- password: "hunter2",
- passwordField: "passwd",
- username: "baz12345",
- usernameField: "user",
- httpRealm: null,
- },
- {
- id: "33333",
- guid: "33333",
- hostname: "https://www.33333.com",
- formSubmitURL: "https://www.33333.com/login",
- password: "p4ssw0rd",
- passwordField: "passwad",
- username: "quux",
- usernameField: "user",
- httpRealm: null,
- },
- ],
- client: [
- {
- id: "11111",
- guid: "11111",
- hostname: "https://www.11111.com",
- formSubmitURL: "https://www.11111.com/login",
- password: "qwerty123",
- passwordField: "pass",
- username: "foobar",
- usernameField: "user",
- httpRealm: null,
- },
- {
- id: "22222",
- guid: "22222",
- hostname: "https://www.22222.org",
- formSubmitURL: "https://www.22222.org/login",
- password: "hunter2",
- passwordField: "passwd",
- username: "baz12345",
- usernameField: "user",
- httpRealm: null,
-
- },
- {
- id: "33333",
- guid: "33333",
- hostname: "https://www.33333.com",
- formSubmitURL: "https://www.33333.com/login",
- password: "p4ssw0rd",
- passwordField: "passwad",
- username: "quux",
- usernameField: "user",
- httpRealm: null,
- }
- ]
- };
-}
-
-
-add_test(function test_valid() {
- let { server, client } = getDummyServerAndClient();
- let validator = new PasswordValidator();
- let { problemData, clientRecords, records, deletedRecords } =
- validator.compareClientWithServer(client, server);
- equal(clientRecords.length, 3);
- equal(records.length, 3)
- equal(deletedRecords.length, 0);
- deepEqual(problemData, validator.emptyProblemData());
-
- run_next_test();
-});
-
-add_test(function test_missing() {
- let validator = new PasswordValidator();
- {
- let { server, client } = getDummyServerAndClient();
-
- client.pop();
-
- let { problemData, clientRecords, records, deletedRecords } =
- validator.compareClientWithServer(client, server);
-
- equal(clientRecords.length, 2);
- equal(records.length, 3)
- equal(deletedRecords.length, 0);
-
- let expected = validator.emptyProblemData();
- expected.clientMissing.push("33333");
- deepEqual(problemData, expected);
- }
- {
- let { server, client } = getDummyServerAndClient();
-
- server.pop();
-
- let { problemData, clientRecords, records, deletedRecords } =
- validator.compareClientWithServer(client, server);
-
- equal(clientRecords.length, 3);
- equal(records.length, 2)
- equal(deletedRecords.length, 0);
-
- let expected = validator.emptyProblemData();
- expected.serverMissing.push("33333");
- deepEqual(problemData, expected);
- }
-
- run_next_test();
-});
-
-
-add_test(function test_deleted() {
- let { server, client } = getDummyServerAndClient();
- let deletionRecord = { id: "444444", guid: "444444", deleted: true };
-
- server.push(deletionRecord);
- let validator = new PasswordValidator();
-
- let { problemData, clientRecords, records, deletedRecords } =
- validator.compareClientWithServer(client, server);
-
- equal(clientRecords.length, 3);
- equal(records.length, 4);
- deepEqual(deletedRecords, [deletionRecord]);
-
- let expected = validator.emptyProblemData();
- deepEqual(problemData, expected);
-
- run_next_test();
-});
-
-
-function run_test() {
- run_next_test();
-}
diff --git a/services/sync/tests/unit/test_postqueue.js b/services/sync/tests/unit/test_postqueue.js
deleted file mode 100644
index e60008a96..000000000
--- a/services/sync/tests/unit/test_postqueue.js
+++ /dev/null
@@ -1,455 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-let { PostQueue } = Cu.import("resource://services-sync/record.js", {});
-
-initTestLogging("Trace");
-
-function makeRecord(nbytes) {
- // make a string 2-bytes less - the added quotes will make it correct.
- return {
- toJSON: () => "x".repeat(nbytes-2),
- }
-}
-
-function makePostQueue(config, lastModTime, responseGenerator) {
- let stats = {
- posts: [],
- }
- let poster = (data, headers, batch, commit) => {
- let thisPost = { nbytes: data.length, batch, commit };
- if (headers.length) {
- thisPost.headers = headers;
- }
- stats.posts.push(thisPost);
- return responseGenerator.next().value;
- }
-
- let done = () => {}
- let pq = new PostQueue(poster, lastModTime, config, getTestLogger(), done);
- return { pq, stats };
-}
-
-add_test(function test_simple() {
- let config = {
- max_post_bytes: 1000,
- max_post_records: 100,
- max_batch_bytes: Infinity,
- max_batch_records: Infinity,
- }
-
- const time = 11111111;
-
- function* responseGenerator() {
- yield { success: true, status: 200, headers: { 'x-weave-timestamp': time + 100, 'x-last-modified': time + 100 } };
- }
-
- let { pq, stats } = makePostQueue(config, time, responseGenerator());
- pq.enqueue(makeRecord(10));
- pq.flush(true);
-
- deepEqual(stats.posts, [{
- nbytes: 12, // expect our 10 byte record plus "[]" to wrap it.
- commit: true, // we don't know if we have batch semantics, so committed.
- headers: [["x-if-unmodified-since", time]],
- batch: "true"}]);
-
- run_next_test();
-});
-
-// Test we do the right thing when we need to make multiple posts when there
-// are no batch semantics
-add_test(function test_max_post_bytes_no_batch() {
- let config = {
- max_post_bytes: 50,
- max_post_records: 4,
- max_batch_bytes: Infinity,
- max_batch_records: Infinity,
- }
-
- const time = 11111111;
- function* responseGenerator() {
- yield { success: true, status: 200, headers: { 'x-weave-timestamp': time + 100, 'x-last-modified': time + 100 } };
- yield { success: true, status: 200, headers: { 'x-weave-timestamp': time + 200, 'x-last-modified': time + 200 } };
- }
-
- let { pq, stats } = makePostQueue(config, time, responseGenerator());
- pq.enqueue(makeRecord(20)); // total size now 22 bytes - "[" + record + "]"
- pq.enqueue(makeRecord(20)); // total size now 43 bytes - "[" + record + "," + record + "]"
- pq.enqueue(makeRecord(20)); // this will exceed our byte limit, so will be in the 2nd POST.
- pq.flush(true);
-
- deepEqual(stats.posts, [
- {
- nbytes: 43, // 43 for the first post
- commit: false,
- headers: [["x-if-unmodified-since", time]],
- batch: "true",
- },{
- nbytes: 22,
- commit: false, // we know we aren't in a batch, so never commit.
- headers: [["x-if-unmodified-since", time + 100]],
- batch: null,
- }
- ]);
- equal(pq.lastModified, time + 200);
-
- run_next_test();
-});
-
-// Similar to the above, but we've hit max_records instead of max_bytes.
-add_test(function test_max_post_records_no_batch() {
- let config = {
- max_post_bytes: 100,
- max_post_records: 2,
- max_batch_bytes: Infinity,
- max_batch_records: Infinity,
- }
-
- const time = 11111111;
-
- function* responseGenerator() {
- yield { success: true, status: 200, headers: { 'x-weave-timestamp': time + 100, 'x-last-modified': time + 100 } };
- yield { success: true, status: 200, headers: { 'x-weave-timestamp': time + 200, 'x-last-modified': time + 200 } };
- }
-
- let { pq, stats } = makePostQueue(config, time, responseGenerator());
- pq.enqueue(makeRecord(20)); // total size now 22 bytes - "[" + record + "]"
- pq.enqueue(makeRecord(20)); // total size now 43 bytes - "[" + record + "," + record + "]"
- pq.enqueue(makeRecord(20)); // this will exceed our records limit, so will be in the 2nd POST.
- pq.flush(true);
-
- deepEqual(stats.posts, [
- {
- nbytes: 43, // 43 for the first post
- commit: false,
- batch: "true",
- headers: [["x-if-unmodified-since", time]],
- },{
- nbytes: 22,
- commit: false, // we know we aren't in a batch, so never commit.
- batch: null,
- headers: [["x-if-unmodified-since", time + 100]],
- }
- ]);
- equal(pq.lastModified, time + 200);
-
- run_next_test();
-});
-
-// Batch tests.
-
-// Test making a single post when batch semantics are in place.
-add_test(function test_single_batch() {
- let config = {
- max_post_bytes: 1000,
- max_post_records: 100,
- max_batch_bytes: 2000,
- max_batch_records: 200,
- }
- const time = 11111111;
- function* responseGenerator() {
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time, 'x-weave-timestamp': time + 100 },
- };
- }
-
- let { pq, stats } = makePostQueue(config, time, responseGenerator());
- ok(pq.enqueue(makeRecord(10)).enqueued);
- pq.flush(true);
-
- deepEqual(stats.posts, [
- {
- nbytes: 12, // expect our 10 byte record plus "[]" to wrap it.
- commit: true, // we don't know if we have batch semantics, so committed.
- batch: "true",
- headers: [["x-if-unmodified-since", time]],
- }
- ]);
-
- run_next_test();
-});
-
-// Test we do the right thing when we need to make multiple posts when there
-// are batch semantics in place.
-add_test(function test_max_post_bytes_batch() {
- let config = {
- max_post_bytes: 50,
- max_post_records: 4,
- max_batch_bytes: 5000,
- max_batch_records: 100,
- }
-
- const time = 11111111;
- function* responseGenerator() {
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time, 'x-weave-timestamp': time + 100 },
- };
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time + 200, 'x-weave-timestamp': time + 200 },
- };
- }
-
- let { pq, stats } = makePostQueue(config, time, responseGenerator());
- ok(pq.enqueue(makeRecord(20)).enqueued); // total size now 22 bytes - "[" + record + "]"
- ok(pq.enqueue(makeRecord(20)).enqueued); // total size now 43 bytes - "[" + record + "," + record + "]"
- ok(pq.enqueue(makeRecord(20)).enqueued); // this will exceed our byte limit, so will be in the 2nd POST.
- pq.flush(true);
-
- deepEqual(stats.posts, [
- {
- nbytes: 43, // 43 for the first post
- commit: false,
- batch: "true",
- headers: [['x-if-unmodified-since', time]],
- },{
- nbytes: 22,
- commit: true,
- batch: 1234,
- headers: [['x-if-unmodified-since', time]],
- }
- ]);
-
- equal(pq.lastModified, time + 200);
-
- run_next_test();
-});
-
-// Test we do the right thing when the batch bytes limit is exceeded.
-add_test(function test_max_post_bytes_batch() {
- let config = {
- max_post_bytes: 50,
- max_post_records: 20,
- max_batch_bytes: 70,
- max_batch_records: 100,
- }
-
- const time0 = 11111111;
- const time1 = 22222222;
- function* responseGenerator() {
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time0, 'x-weave-timestamp': time0 + 100 },
- };
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time1, 'x-weave-timestamp': time1 },
- };
- yield { success: true, status: 202, obj: { batch: 5678 },
- headers: { 'x-last-modified': time1, 'x-weave-timestamp': time1 + 100 },
- };
- yield { success: true, status: 202, obj: { batch: 5678 },
- headers: { 'x-last-modified': time1 + 200, 'x-weave-timestamp': time1 + 200 },
- };
- }
-
- let { pq, stats } = makePostQueue(config, time0, responseGenerator());
- ok(pq.enqueue(makeRecord(20)).enqueued); // total size now 22 bytes - "[" + record + "]"
- ok(pq.enqueue(makeRecord(20)).enqueued); // total size now 43 bytes - "[" + record + "," + record + "]"
- // this will exceed our POST byte limit, so will be in the 2nd POST - but still in the first batch.
- ok(pq.enqueue(makeRecord(20)).enqueued); // 22 bytes for 2nd post, 55 bytes in the batch.
- // this will exceed our batch byte limit, so will be in a new batch.
- ok(pq.enqueue(makeRecord(20)).enqueued); // 22 bytes in 3rd post/2nd batch
- ok(pq.enqueue(makeRecord(20)).enqueued); // 43 bytes in 3rd post/2nd batch
- // This will exceed POST byte limit, so will be in the 4th post, part of the 2nd batch.
- ok(pq.enqueue(makeRecord(20)).enqueued); // 22 bytes for 4th post/2nd batch
- pq.flush(true);
-
- deepEqual(stats.posts, [
- {
- nbytes: 43, // 43 for the first post
- commit: false,
- batch: "true",
- headers: [['x-if-unmodified-since', time0]],
- },{
- // second post of 22 bytes in the first batch, committing it.
- nbytes: 22,
- commit: true,
- batch: 1234,
- headers: [['x-if-unmodified-since', time0]],
- }, {
- // 3rd post of 43 bytes in a new batch, not yet committing it.
- nbytes: 43,
- commit: false,
- batch: "true",
- headers: [['x-if-unmodified-since', time1]],
- },{
- // 4th post of 22 bytes in second batch, committing it.
- nbytes: 22,
- commit: true,
- batch: 5678,
- headers: [['x-if-unmodified-since', time1]],
- },
- ]);
-
- equal(pq.lastModified, time1 + 200);
-
- run_next_test();
-});
-
-// Test we split up the posts when we exceed the record limit when batch semantics
-// are in place.
-add_test(function test_max_post_bytes_batch() {
- let config = {
- max_post_bytes: 1000,
- max_post_records: 2,
- max_batch_bytes: 5000,
- max_batch_records: 100,
- }
-
- const time = 11111111;
- function* responseGenerator() {
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time, 'x-weave-timestamp': time + 100 },
- };
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time + 200, 'x-weave-timestamp': time + 200 },
- };
- }
-
- let { pq, stats } = makePostQueue(config, time, responseGenerator());
- ok(pq.enqueue(makeRecord(20)).enqueued); // total size now 22 bytes - "[" + record + "]"
- ok(pq.enqueue(makeRecord(20)).enqueued); // total size now 43 bytes - "[" + record + "," + record + "]"
- ok(pq.enqueue(makeRecord(20)).enqueued); // will exceed record limit, so will be in 2nd post.
- pq.flush(true);
-
- deepEqual(stats.posts, [
- {
- nbytes: 43, // 43 for the first post
- commit: false,
- batch: "true",
- headers: [['x-if-unmodified-since', time]],
- },{
- nbytes: 22,
- commit: true,
- batch: 1234,
- headers: [['x-if-unmodified-since', time]],
- }
- ]);
-
- equal(pq.lastModified, time + 200);
-
- run_next_test();
-});
-
-// Test that a single huge record fails to enqueue
-add_test(function test_huge_record() {
- let config = {
- max_post_bytes: 50,
- max_post_records: 100,
- max_batch_bytes: 5000,
- max_batch_records: 100,
- }
-
- const time = 11111111;
- function* responseGenerator() {
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time, 'x-weave-timestamp': time + 100 },
- };
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time + 200, 'x-weave-timestamp': time + 200 },
- };
- }
-
- let { pq, stats } = makePostQueue(config, time, responseGenerator());
- ok(pq.enqueue(makeRecord(20)).enqueued);
-
- let { enqueued, error } = pq.enqueue(makeRecord(1000));
- ok(!enqueued);
- notEqual(error, undefined);
-
- // make sure that we keep working, skipping the bad record entirely
- // (handling the error the queue reported is left up to caller)
- ok(pq.enqueue(makeRecord(20)).enqueued);
- ok(pq.enqueue(makeRecord(20)).enqueued);
-
- pq.flush(true);
-
- deepEqual(stats.posts, [
- {
- nbytes: 43, // 43 for the first post
- commit: false,
- batch: "true",
- headers: [['x-if-unmodified-since', time]],
- },{
- nbytes: 22,
- commit: true,
- batch: 1234,
- headers: [['x-if-unmodified-since', time]],
- }
- ]);
-
- equal(pq.lastModified, time + 200);
-
- run_next_test();
-});
-
-// Test we do the right thing when the batch record limit is exceeded.
-add_test(function test_max_records_batch() {
- let config = {
- max_post_bytes: 1000,
- max_post_records: 3,
- max_batch_bytes: 10000,
- max_batch_records: 5,
- }
-
- const time0 = 11111111;
- const time1 = 22222222;
- function* responseGenerator() {
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time0, 'x-weave-timestamp': time0 + 100 },
- };
- yield { success: true, status: 202, obj: { batch: 1234 },
- headers: { 'x-last-modified': time1, 'x-weave-timestamp': time1 },
- };
- yield { success: true, status: 202, obj: { batch: 5678 },
- headers: { 'x-last-modified': time1, 'x-weave-timestamp': time1 + 100 },
- };
- yield { success: true, status: 202, obj: { batch: 5678 },
- headers: { 'x-last-modified': time1 + 200, 'x-weave-timestamp': time1 + 200 },
- };
- }
-
- let { pq, stats } = makePostQueue(config, time0, responseGenerator());
-
- ok(pq.enqueue(makeRecord(20)).enqueued);
- ok(pq.enqueue(makeRecord(20)).enqueued);
- ok(pq.enqueue(makeRecord(20)).enqueued);
-
- ok(pq.enqueue(makeRecord(20)).enqueued);
- ok(pq.enqueue(makeRecord(20)).enqueued);
-
- ok(pq.enqueue(makeRecord(20)).enqueued);
- ok(pq.enqueue(makeRecord(20)).enqueued);
- ok(pq.enqueue(makeRecord(20)).enqueued);
-
- ok(pq.enqueue(makeRecord(20)).enqueued);
-
- pq.flush(true);
-
- deepEqual(stats.posts, [
- { // 3 records
- nbytes: 64,
- commit: false,
- batch: "true",
- headers: [['x-if-unmodified-since', time0]],
- },{ // 2 records -- end batch1
- nbytes: 43,
- commit: true,
- batch: 1234,
- headers: [['x-if-unmodified-since', time0]],
- }, { // 3 records
- nbytes: 64,
- commit: false,
- batch: "true",
- headers: [['x-if-unmodified-since', time1]],
- },{ // 1 record -- end batch2
- nbytes: 22,
- commit: true,
- batch: 5678,
- headers: [['x-if-unmodified-since', time1]],
- },
- ]);
-
- equal(pq.lastModified, time1 + 200);
-
- run_next_test();
-}); \ No newline at end of file
diff --git a/services/sync/tests/unit/test_prefs_store.js b/services/sync/tests/unit/test_prefs_store.js
index 9c321bceb..51b220d53 100644
--- a/services/sync/tests/unit/test_prefs_store.js
+++ b/services/sync/tests/unit/test_prefs_store.js
@@ -23,22 +23,25 @@ function makePersona(id) {
}
function run_test() {
- _("Test fixtures.");
- // read our custom prefs file before doing anything.
- Services.prefs.readUserPrefs(do_get_file("prefs_test_prefs_store.js"));
- // Now we've read from this file, any writes the pref service makes will be
- // back to this prefs_test_prefs_store.js directly in the obj dir. This
- // upsets things in confusing ways :) We avoid this by explicitly telling the
- // pref service to use a file in our profile dir.
- let prefFile = do_get_profile();
- prefFile.append("prefs.js");
- Services.prefs.savePrefFile(prefFile);
- Services.prefs.readUserPrefs(prefFile);
-
let store = Service.engineManager.get("prefs")._store;
let prefs = new Preferences();
try {
+ _("Test fixtures.");
+ Svc.Prefs.set("prefs.sync.testing.int", true);
+ Svc.Prefs.set("prefs.sync.testing.string", true);
+ Svc.Prefs.set("prefs.sync.testing.bool", true);
+ Svc.Prefs.set("prefs.sync.testing.dont.change", true);
+ Svc.Prefs.set("prefs.sync.testing.turned.off", false);
+ Svc.Prefs.set("prefs.sync.testing.nonexistent", true);
+
+ prefs.set("testing.int", 123);
+ prefs.set("testing.string", "ohai");
+ prefs.set("testing.bool", true);
+ prefs.set("testing.dont.change", "Please don't change me.");
+ prefs.set("testing.turned.off", "I won't get synced.");
+ prefs.set("testing.not.turned.on", "I won't get synced either!");
+
_("The GUID corresponds to XUL App ID.");
let allIDs = store.getAllIDs();
let ids = Object.keys(allIDs);
@@ -58,22 +61,17 @@ function run_test() {
do_check_eq(record.value["testing.int"], 123);
do_check_eq(record.value["testing.string"], "ohai");
do_check_eq(record.value["testing.bool"], true);
- // non-existing prefs get null as the value
do_check_eq(record.value["testing.nonexistent"], null);
- // as do prefs that have a default value.
- do_check_eq(record.value["testing.default"], null);
do_check_false("testing.turned.off" in record.value);
do_check_false("testing.not.turned.on" in record.value);
- _("Prefs record contains non-default pref sync prefs too.");
- do_check_eq(record.value["services.sync.prefs.sync.testing.int"], null);
- do_check_eq(record.value["services.sync.prefs.sync.testing.string"], null);
- do_check_eq(record.value["services.sync.prefs.sync.testing.bool"], null);
- do_check_eq(record.value["services.sync.prefs.sync.testing.dont.change"], null);
- // but this one is a user_pref so *will* be synced.
+ _("Prefs record contains pref sync prefs too.");
+ do_check_eq(record.value["services.sync.prefs.sync.testing.int"], true);
+ do_check_eq(record.value["services.sync.prefs.sync.testing.string"], true);
+ do_check_eq(record.value["services.sync.prefs.sync.testing.bool"], true);
+ do_check_eq(record.value["services.sync.prefs.sync.testing.dont.change"], true);
do_check_eq(record.value["services.sync.prefs.sync.testing.turned.off"], false);
- do_check_eq(record.value["services.sync.prefs.sync.testing.nonexistent"], null);
- do_check_eq(record.value["services.sync.prefs.sync.testing.default"], null);
+ do_check_eq(record.value["services.sync.prefs.sync.testing.nonexistent"], true);
_("Update some prefs, including one that's to be reset/deleted.");
Svc.Prefs.set("testing.deleteme", "I'm going to be deleted!");
@@ -99,28 +97,28 @@ function run_test() {
// Ensure we don't go to the network to fetch personas and end up leaking
// stuff.
Services.io.offline = true;
- do_check_false(!!prefs.get("lightweightThemes.selectedThemeID"));
+ do_check_false(!!prefs.get("lightweightThemes.isThemeSelected"));
do_check_eq(LightweightThemeManager.currentTheme, null);
let persona1 = makePersona();
let persona2 = makePersona();
let usedThemes = JSON.stringify([persona1, persona2]);
record.value = {
- "lightweightThemes.selectedThemeID": persona1.id,
+ "lightweightThemes.isThemeSelected": true,
"lightweightThemes.usedThemes": usedThemes
};
store.update(record);
- do_check_eq(prefs.get("lightweightThemes.selectedThemeID"), persona1.id);
+ do_check_true(prefs.get("lightweightThemes.isThemeSelected"));
do_check_true(Utils.deepEquals(LightweightThemeManager.currentTheme,
persona1));
_("Disable persona");
record.value = {
- "lightweightThemes.selectedThemeID": null,
+ "lightweightThemes.isThemeSelected": false,
"lightweightThemes.usedThemes": usedThemes
};
store.update(record);
- do_check_false(!!prefs.get("lightweightThemes.selectedThemeID"));
+ do_check_false(prefs.get("lightweightThemes.isThemeSelected"));
do_check_eq(LightweightThemeManager.currentTheme, null);
_("Only the current app's preferences are applied.");
@@ -131,37 +129,6 @@ function run_test() {
store.update(record);
do_check_eq(prefs.get("testing.int"), 42);
- _("The light-weight theme preference is handled correctly.");
- let lastThemeID = undefined;
- let orig_updateLightWeightTheme = store._updateLightWeightTheme;
- store._updateLightWeightTheme = function(themeID) {
- lastThemeID = themeID;
- }
- try {
- record = new PrefRec("prefs", PREFS_GUID);
- record.value = {
- "testing.int": 42,
- };
- store.update(record);
- do_check_true(lastThemeID === undefined,
- "should not have tried to change the theme with an unrelated pref.");
- Services.prefs.setCharPref("lightweightThemes.selectedThemeID", "foo");
- record.value = {
- "lightweightThemes.selectedThemeID": "foo",
- };
- store.update(record);
- do_check_true(lastThemeID === undefined,
- "should not have tried to change the theme when the incoming pref matches current value.");
-
- record.value = {
- "lightweightThemes.selectedThemeID": "bar",
- };
- store.update(record);
- do_check_eq(lastThemeID, "bar",
- "should have tried to change the theme when the incoming pref was different.");
- } finally {
- store._updateLightWeightTheme = orig_updateLightWeightTheme;
- }
} finally {
prefs.resetBranch("");
}
diff --git a/services/sync/tests/unit/test_records_crypto.js b/services/sync/tests/unit/test_records_crypto.js
index 392a746ef..4d623c917 100644
--- a/services/sync/tests/unit/test_records_crypto.js
+++ b/services/sync/tests/unit/test_records_crypto.js
@@ -10,7 +10,7 @@ Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
-var cryptoWrap;
+let cryptoWrap;
function crypted_resource_handler(metadata, response) {
let obj = {id: "resource",
@@ -148,32 +148,6 @@ function run_test() {
do_check_eq(bookmarkItem.decrypt(Service.collectionKeys.keyForCollection("bookmarks")).stuff,
"my payload here");
- do_check_true(Service.collectionKeys.hasKeysFor(["bookmarks"]));
-
- // Add a key for some new collection and verify that it isn't the
- // default key.
- do_check_false(Service.collectionKeys.hasKeysFor(["forms"]));
- do_check_false(Service.collectionKeys.hasKeysFor(["bookmarks", "forms"]));
- let oldFormsKey = Service.collectionKeys.keyForCollection("forms");
- do_check_eq(oldFormsKey, Service.collectionKeys._default);
- let newKeys = Service.collectionKeys.ensureKeysFor(["forms"]);
- do_check_true(newKeys.hasKeysFor(["forms"]));
- do_check_true(newKeys.hasKeysFor(["bookmarks", "forms"]));
- let newFormsKey = newKeys.keyForCollection("forms");
- do_check_neq(newFormsKey, oldFormsKey);
-
- // Verify that this doesn't overwrite keys
- let regetKeys = newKeys.ensureKeysFor(["forms"]);
- do_check_eq(regetKeys.keyForCollection("forms"), newFormsKey);
-
- const emptyKeys = new CollectionKeyManager();
- payload = {
- default: Service.collectionKeys._default.keyPairB64,
- collections: {}
- };
- // Verify that not passing `modified` doesn't throw
- emptyKeys.setContents(payload, null);
-
log.info("Done!");
}
finally {
diff --git a/services/sync/tests/unit/test_resource.js b/services/sync/tests/unit/test_resource.js
index 8f5534c92..027d662b4 100644
--- a/services/sync/tests/unit/test_resource.js
+++ b/services/sync/tests/unit/test_resource.js
@@ -7,9 +7,9 @@ Cu.import("resource://services-sync/identity.js");
Cu.import("resource://services-sync/resource.js");
Cu.import("resource://services-sync/util.js");
-var logger;
+let logger;
-var fetched = false;
+let fetched = false;
function server_open(metadata, response) {
let body;
if (metadata.method == "GET") {
@@ -45,7 +45,7 @@ function server_404(metadata, response) {
response.bodyOutputStream.write(body, body.length);
}
-var pacFetched = false;
+let pacFetched = false;
function server_pac(metadata, response) {
pacFetched = true;
let body = 'function FindProxyForURL(url, host) { return "DIRECT"; }';
@@ -55,7 +55,7 @@ function server_pac(metadata, response) {
}
-var sample_data = {
+let sample_data = {
some: "sample_data",
injson: "format",
number: 42
@@ -140,7 +140,7 @@ function server_headers(metadata, response) {
header_names = header_names.sort();
headers = {};
- for (let header of header_names) {
+ for each (let header in header_names) {
headers[header] = metadata.getHeader(header);
}
let body = JSON.stringify(headers);
@@ -442,8 +442,6 @@ function run_test() {
// It throws and logs.
do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI);
do_check_eq(error, "Error: NS_ERROR_MALFORMED_URI");
- // Note the strings haven't been formatted yet, but that's OK for this test.
- do_check_eq(warnings.pop(), "${action} request to ${url} failed: ${ex}");
do_check_eq(warnings.pop(),
"Got exception calling onProgress handler during fetch of " +
server.baseURI + "/json");
@@ -467,7 +465,6 @@ function run_test() {
// It throws and logs.
do_check_eq(error.result, Cr.NS_ERROR_XPC_JS_THREW_STRING);
do_check_eq(error, "Error: NS_ERROR_XPC_JS_THREW_STRING");
- do_check_eq(warnings.pop(), "${action} request to ${url} failed: ${ex}");
do_check_eq(warnings.pop(),
"Got exception calling onProgress handler during fetch of " +
server.baseURI + "/json");
diff --git a/services/sync/tests/unit/test_resource_async.js b/services/sync/tests/unit/test_resource_async.js
index 0db91a1b5..c4b9a3804 100644
--- a/services/sync/tests/unit/test_resource_async.js
+++ b/services/sync/tests/unit/test_resource_async.js
@@ -7,9 +7,9 @@ Cu.import("resource://services-sync/identity.js");
Cu.import("resource://services-sync/resource.js");
Cu.import("resource://services-sync/util.js");
-var logger;
+let logger;
-var fetched = false;
+let fetched = false;
function server_open(metadata, response) {
let body;
if (metadata.method == "GET") {
@@ -45,7 +45,7 @@ function server_404(metadata, response) {
response.bodyOutputStream.write(body, body.length);
}
-var pacFetched = false;
+let pacFetched = false;
function server_pac(metadata, response) {
_("Invoked PAC handler.");
pacFetched = true;
@@ -55,7 +55,7 @@ function server_pac(metadata, response) {
response.bodyOutputStream.write(body, body.length);
}
-var sample_data = {
+let sample_data = {
some: "sample_data",
injson: "format",
number: 42
@@ -140,7 +140,7 @@ function server_headers(metadata, response) {
header_names = header_names.sort();
headers = {};
- for (let header of header_names) {
+ for each (let header in header_names) {
headers[header] = metadata.getHeader(header);
}
let body = JSON.stringify(headers);
@@ -148,7 +148,7 @@ function server_headers(metadata, response) {
response.bodyOutputStream.write(body, body.length);
}
-var quotaValue;
+let quotaValue;
Observers.add("weave:service:quota:remaining",
function (subject) { quotaValue = subject; });
@@ -221,7 +221,7 @@ add_test(function test_new_channel() {
});
-var server;
+let server;
add_test(function setup() {
server = httpd_setup({
diff --git a/services/sync/tests/unit/test_resource_header.js b/services/sync/tests/unit/test_resource_header.js
index 4f28e01da..1835cc0e0 100644
--- a/services/sync/tests/unit/test_resource_header.js
+++ b/services/sync/tests/unit/test_resource_header.js
@@ -11,7 +11,7 @@ function run_test() {
run_next_test();
}
-var httpServer = new HttpServer();
+let httpServer = new HttpServer();
httpServer.registerPathHandler("/content", contentHandler);
httpServer.start(-1);
@@ -20,8 +20,8 @@ const TEST_URL = "http://localhost:" + HTTP_PORT + "/content";
const BODY = "response body";
// Keep headers for later inspection.
-var auth = null;
-var foo = null;
+let auth = null;
+let foo = null;
function contentHandler(metadata, response) {
_("Handling request.");
auth = metadata.getHeader("Authorization");
diff --git a/services/sync/tests/unit/test_resource_ua.js b/services/sync/tests/unit/test_resource_ua.js
index 31c2cd379..279a2b3e6 100644
--- a/services/sync/tests/unit/test_resource_ua.js
+++ b/services/sync/tests/unit/test_resource_ua.js
@@ -7,18 +7,15 @@ Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
-var httpProtocolHandler = Cc["@mozilla.org/network/protocol;1?name=http"]
- .getService(Ci.nsIHttpProtocolHandler);
-
// Tracking info/collections.
-var collectionsHelper = track_collections_helper();
-var collections = collectionsHelper.collections;
+let collectionsHelper = track_collections_helper();
+let collections = collectionsHelper.collections;
-var meta_global;
-var server;
+let meta_global;
+let server;
-var expectedUA;
-var ua;
+let expectedUA;
+let ua;
function uaHandler(f) {
return function(request, response) {
ua = request.getHeader("User-Agent");
@@ -40,10 +37,7 @@ function run_test() {
Service.clusterURL = server.baseURI + "/";
_("Server URL: " + server.baseURI);
- // Note this string is missing the trailing ".destkop" as the test
- // adjusts the "client.type" pref where that portion comes from.
expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
- " (" + httpProtocolHandler.oscpu + ")" +
" FxSync/" + WEAVE_VERSION + "." +
Services.appinfo.appBuildID;
diff --git a/services/sync/tests/unit/test_score_triggers.js b/services/sync/tests/unit/test_score_triggers.js
index 513be685a..98d3e094a 100644
--- a/services/sync/tests/unit/test_score_triggers.js
+++ b/services/sync/tests/unit/test_score_triggers.js
@@ -12,13 +12,13 @@ Cu.import("resource://testing-common/services/sync/utils.js");
Service.engineManager.clear();
Service.engineManager.register(RotaryEngine);
-var engine = Service.engineManager.get("rotary");
-var tracker = engine._tracker;
+let engine = Service.engineManager.get("rotary");
+let tracker = engine._tracker;
engine.enabled = true;
// Tracking info/collections.
-var collectionsHelper = track_collections_helper();
-var upd = collectionsHelper.with_updated_collection;
+let collectionsHelper = track_collections_helper();
+let upd = collectionsHelper.with_updated_collection;
function sync_httpd_setup() {
let handlers = {};
diff --git a/services/sync/tests/unit/test_service_attributes.js b/services/sync/tests/unit/test_service_attributes.js
index 931c7741a..dc82f5edb 100644
--- a/services/sync/tests/unit/test_service_attributes.js
+++ b/services/sync/tests/unit/test_service_attributes.js
@@ -29,6 +29,7 @@ function test_urls() {
Service.serverURL = "http://weave.server/";
Service.clusterURL = "http://weave.cluster/";
+ do_check_eq(Svc.Prefs.get("clusterURL"), "http://weave.cluster/");
do_check_eq(Service.userBaseURL, "http://weave.cluster/1.1/johndoe/");
do_check_eq(Service.infoURL,
@@ -62,11 +63,11 @@ function test_urls() {
_("The 'serverURL' attributes updates/resets preferences.");
// Identical value doesn't do anything
Service.serverURL = Service.serverURL;
- do_check_eq(Service.clusterURL, "http://weave.cluster/");
+ do_check_eq(Svc.Prefs.get("clusterURL"), "http://weave.cluster/");
Service.serverURL = "http://different.auth.node/";
do_check_eq(Svc.Prefs.get("serverURL"), "http://different.auth.node/");
- do_check_eq(Service.clusterURL, "");
+ do_check_eq(Svc.Prefs.get("clusterURL"), undefined);
} finally {
Svc.Prefs.resetBranch("");
@@ -83,12 +84,12 @@ function test_syncID() {
do_check_eq(Svc.Prefs.get("client.syncID"), undefined);
// Performing the first get on the attribute will generate a new GUID.
- do_check_eq(Service.syncID, "fake-guid-00");
- do_check_eq(Svc.Prefs.get("client.syncID"), "fake-guid-00");
+ do_check_eq(Service.syncID, "fake-guid-0");
+ do_check_eq(Svc.Prefs.get("client.syncID"), "fake-guid-0");
Svc.Prefs.set("client.syncID", Utils.makeGUID());
- do_check_eq(Svc.Prefs.get("client.syncID"), "fake-guid-01");
- do_check_eq(Service.syncID, "fake-guid-01");
+ do_check_eq(Svc.Prefs.get("client.syncID"), "fake-guid-1");
+ do_check_eq(Service.syncID, "fake-guid-1");
} finally {
Svc.Prefs.resetBranch("");
new FakeGUIDService();
diff --git a/services/sync/tests/unit/test_service_detect_upgrade.js b/services/sync/tests/unit/test_service_detect_upgrade.js
index 0f46832d9..528bd751b 100644
--- a/services/sync/tests/unit/test_service_detect_upgrade.js
+++ b/services/sync/tests/unit/test_service_detect_upgrade.js
@@ -60,7 +60,7 @@ add_test(function v4_upgrade() {
}]}]};
delete Svc.Session;
Svc.Session = {
- getBrowserState: () => JSON.stringify(myTabs)
+ getBrowserState: function () JSON.stringify(myTabs)
};
Service.status.resetSync();
@@ -229,7 +229,7 @@ add_test(function v5_upgrade() {
}]}]};
delete Svc.Session;
Svc.Session = {
- getBrowserState: () => JSON.stringify(myTabs)
+ getBrowserState: function () JSON.stringify(myTabs)
};
Service.status.resetSync();
diff --git a/services/sync/tests/unit/test_service_getStorageInfo.js b/services/sync/tests/unit/test_service_getStorageInfo.js
index 841dceb78..4d463044b 100644
--- a/services/sync/tests/unit/test_service_getStorageInfo.js
+++ b/services/sync/tests/unit/test_service_getStorageInfo.js
@@ -7,10 +7,7 @@ Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
-var httpProtocolHandler = Cc["@mozilla.org/network/protocol;1?name=http"]
- .getService(Ci.nsIHttpProtocolHandler);
-
-var collections = {steam: 65.11328,
+let collections = {steam: 65.11328,
petrol: 82.488281,
diesel: 2.25488281};
@@ -40,7 +37,6 @@ add_test(function test_success() {
Service.identity.username,
Service.identity.basicPassword));
let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
- " (" + httpProtocolHandler.oscpu + ")" +
" FxSync/" + WEAVE_VERSION + "." +
Services.appinfo.appBuildID + ".desktop";
do_check_eq(handler.request.getHeader("User-Agent"), expectedUA);
diff --git a/services/sync/tests/unit/test_service_login.js b/services/sync/tests/unit/test_service_login.js
index 2ecb0a377..52ee5e63a 100644
--- a/services/sync/tests/unit/test_service_login.js
+++ b/services/sync/tests/unit/test_service_login.js
@@ -183,7 +183,7 @@ add_test(function test_login_on_sync() {
// This test exercises these two branches.
_("We're ready to sync if locked.");
- Service.enabled = true;
+ Svc.Prefs.set("enabled", true);
Services.io.offline = false;
Service.scheduler.checkSyncStatus();
do_check_true(scheduleCalled);
diff --git a/services/sync/tests/unit/test_service_passwordUTF8.js b/services/sync/tests/unit/test_service_passwordUTF8.js
index e781050b3..733911291 100644
--- a/services/sync/tests/unit/test_service_passwordUTF8.js
+++ b/services/sync/tests/unit/test_service_passwordUTF8.js
@@ -11,13 +11,13 @@ const APPLES = "\uf8ff\uf8ff\uf8ff\uf8ff";
const LOWBYTES = "\xff\xff\xff\xff";
// Poor man's /etc/passwd. Static since there's no btoa()/atob() in xpcshell.
-var basicauth = {};
+let basicauth = {};
basicauth[LOWBYTES] = "Basic am9obmRvZTr/////";
basicauth[Utils.encodeUTF8(JAPANESE)] = "Basic am9obmRvZTrjk7/jl7/jm7/jn78=";
// Global var for the server password, read by info_collections(),
// modified by change_password().
-var server_password;
+let server_password;
function login_handling(handler) {
return function (request, response) {
diff --git a/services/sync/tests/unit/test_service_startOver.js b/services/sync/tests/unit/test_service_startOver.js
index 899420548..6fb0a66d7 100644
--- a/services/sync/tests/unit/test_service_startOver.js
+++ b/services/sync/tests/unit/test_service_startOver.js
@@ -28,7 +28,7 @@ function run_test() {
run_next_test();
}
-add_identity_test(this, function* test_resetLocalData() {
+add_identity_test(this, function test_resetLocalData() {
yield configureIdentity();
Service.status.enforceBackoff = true;
Service.status.backoffInterval = 42;
diff --git a/services/sync/tests/unit/test_service_startup.js b/services/sync/tests/unit/test_service_startup.js
index 5148f6d13..6ced39da9 100644
--- a/services/sync/tests/unit/test_service_startup.js
+++ b/services/sync/tests/unit/test_service_startup.js
@@ -10,7 +10,6 @@ Svc.Prefs.set("registerEngines", "Tab,Bookmarks,Form,History");
Cu.import("resource://services-sync/service.js");
function run_test() {
- validate_all_future_pings();
_("When imported, Service.onStartup is called");
initTestLogging("Trace");
@@ -21,7 +20,7 @@ function run_test() {
// Test fixtures
Service.identity.username = "johndoe";
- do_check_true(xps.enabled);
+ do_check_false(xps.enabled);
Cu.import("resource://services-sync/service.js");
@@ -30,7 +29,7 @@ function run_test() {
_("Engines are registered.");
let engines = Service.engineManager.getAll();
- do_check_true(Utils.deepEquals(engines.map(engine => engine.name),
+ do_check_true(Utils.deepEquals([engine.name for each (engine in engines)],
['tabs', 'bookmarks', 'forms', 'history']));
_("Observers are notified of startup");
@@ -46,4 +45,10 @@ function run_test() {
Svc.Prefs.resetBranch("");
do_test_finished();
});
+
+ do_check_false(xps.enabled);
+
+ Service.identity.account = "johndoe";
+ Service.clusterURL = "http://localhost/";
+ do_check_true(xps.enabled);
}
diff --git a/services/sync/tests/unit/test_service_sync_locked.js b/services/sync/tests/unit/test_service_sync_locked.js
index ee952c7ee..e2cbbfa92 100644
--- a/services/sync/tests/unit/test_service_sync_locked.js
+++ b/services/sync/tests/unit/test_service_sync_locked.js
@@ -5,17 +5,14 @@ Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
function run_test() {
- validate_all_future_pings();
let debug = [];
let info = [];
function augmentLogger(old) {
let d = old.debug;
let i = old.info;
- // For the purposes of this test we don't need to do full formatting
- // of the 2nd param, as the ones we care about are always strings.
- old.debug = function(m, p) { debug.push(p ? m + ": " + p : m); d.call(old, m, p); }
- old.info = function(m, p) { info.push(p ? m + ": " + p : m); i.call(old, m, p); }
+ old.debug = function(m) { debug.push(m); d.call(old, m); }
+ old.info = function(m) { info.push(m); i.call(old, m); }
return old;
}
@@ -31,7 +28,9 @@ function run_test() {
Service.sync();
Service._locked = false;
- do_check_true(debug[debug.length - 2].startsWith("Exception calling WrappedLock: Could not acquire lock. Label: \"service.js: login\"."));
- do_check_eq(info[info.length - 1], "Cannot start sync: already syncing?");
+ do_check_eq(debug[debug.length - 2],
+ "Exception: Could not acquire lock. Label: \"service.js: login\". No traceback available");
+ do_check_eq(info[info.length - 1],
+ "Cannot start sync: already syncing?");
}
diff --git a/services/sync/tests/unit/test_service_sync_remoteSetup.js b/services/sync/tests/unit/test_service_sync_remoteSetup.js
index 83dbf3cd7..852ba64d5 100644
--- a/services/sync/tests/unit/test_service_sync_remoteSetup.js
+++ b/services/sync/tests/unit/test_service_sync_remoteSetup.js
@@ -10,7 +10,6 @@ Cu.import("resource://testing-common/services/sync/fakeservices.js");
Cu.import("resource://testing-common/services/sync/utils.js");
function run_test() {
- validate_all_future_pings();
let logger = Log.repository.rootLogger;
Log.repository.rootLogger.addAppender(new Log.DumpAppender());
@@ -54,27 +53,15 @@ function run_test() {
return_timestamp(request, response, ts);
}
- const GLOBAL_PATH = "/1.1/johndoe/storage/meta/global";
- const INFO_PATH = "/1.1/johndoe/info/collections";
-
- let handlers = {
+ let server = httpd_setup({
"/1.1/johndoe/storage": storageHandler,
"/1.1/johndoe/storage/crypto/keys": upd("crypto", keysWBO.handler()),
"/1.1/johndoe/storage/crypto": upd("crypto", cryptoColl.handler()),
"/1.1/johndoe/storage/clients": upd("clients", clients.handler()),
- "/1.1/johndoe/storage/meta": upd("meta", wasCalledHandler(metaColl)),
"/1.1/johndoe/storage/meta/global": upd("meta", wasCalledHandler(meta_global)),
+ "/1.1/johndoe/storage/meta": upd("meta", wasCalledHandler(metaColl)),
"/1.1/johndoe/info/collections": collectionsHelper.handler
- };
-
- function mockHandler(path, mock) {
- server.registerPathHandler(path, mock(handlers[path]));
- return {
- restore() { server.registerPathHandler(path, handlers[path]); }
- }
- }
-
- let server = httpd_setup(handlers);
+ });
try {
_("Log in.");
@@ -102,63 +89,6 @@ function run_test() {
Service.recordManager.get(Service.metaURL).payload.syncID = "foobar";
do_check_true(Service._remoteSetup());
- let returnStatusCode = (method, code) => (oldMethod) => (req, res) => {
- if (req.method === method) {
- res.setStatusLine(req.httpVersion, code, "");
- } else {
- oldMethod(req, res);
- }
- };
-
- let mock = mockHandler(GLOBAL_PATH, returnStatusCode("GET", 401));
- Service.recordManager.del(Service.metaURL);
- _("Checking that remoteSetup returns false on 401 on first get /meta/global.");
- do_check_false(Service._remoteSetup());
- mock.restore();
-
- Service.login("johndoe", "ilovejane", syncKey);
- mock = mockHandler(GLOBAL_PATH, returnStatusCode("GET", 503));
- Service.recordManager.del(Service.metaURL);
- _("Checking that remoteSetup returns false on 503 on first get /meta/global.");
- do_check_false(Service._remoteSetup());
- do_check_eq(Service.status.sync, METARECORD_DOWNLOAD_FAIL);
- mock.restore();
-
- mock = mockHandler(GLOBAL_PATH, returnStatusCode("GET", 404));
- Service.recordManager.del(Service.metaURL);
- _("Checking that remoteSetup recovers on 404 on first get /meta/global.");
- do_check_true(Service._remoteSetup());
- mock.restore();
-
- let makeOutdatedMeta = () => {
- Service.metaModified = 0;
- let infoResponse = Service._fetchInfo();
- return {
- status: infoResponse.status,
- obj: {
- crypto: infoResponse.obj.crypto,
- clients: infoResponse.obj.clients,
- meta: 1
- }
- };
- }
-
- _("Checking that remoteSetup recovers on 404 on get /meta/global after clear cached one.");
- mock = mockHandler(GLOBAL_PATH, returnStatusCode("GET", 404));
- Service.recordManager.set(Service.metaURL, { isNew: false });
- do_check_true(Service._remoteSetup(makeOutdatedMeta()));
- mock.restore();
-
- _("Checking that remoteSetup returns false on 503 on get /meta/global after clear cached one.");
- mock = mockHandler(GLOBAL_PATH, returnStatusCode("GET", 503));
- Service.status.sync = "";
- Service.recordManager.set(Service.metaURL, { isNew: false });
- do_check_false(Service._remoteSetup(makeOutdatedMeta()));
- do_check_eq(Service.status.sync, "");
- mock.restore();
-
- metaColl.delete({});
-
_("Do an initial sync.");
let beforeSync = Date.now()/1000;
Service.sync();
@@ -230,6 +160,7 @@ function run_test() {
do_check_false(Service.verifyAndFetchSymmetricKeys());
do_check_eq(Service.status.login, LOGIN_FAILED_INVALID_PASSPHRASE);
+
} finally {
Svc.Prefs.resetBranch("");
server.stop(do_test_finished);
diff --git a/services/sync/tests/unit/test_service_sync_specified.js b/services/sync/tests/unit/test_service_sync_specified.js
deleted file mode 100644
index 7cb0f9d9c..000000000
--- a/services/sync/tests/unit/test_service_sync_specified.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://services-sync/engines/clients.js");
-Cu.import("resource://services-sync/record.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-initTestLogging();
-Service.engineManager.clear();
-
-let syncedEngines = []
-
-function SteamEngine() {
- SyncEngine.call(this, "Steam", Service);
-}
-SteamEngine.prototype = {
- __proto__: SyncEngine.prototype,
- _sync: function _sync() {
- syncedEngines.push(this.name);
- }
-};
-Service.engineManager.register(SteamEngine);
-
-function StirlingEngine() {
- SyncEngine.call(this, "Stirling", Service);
-}
-StirlingEngine.prototype = {
- __proto__: SteamEngine.prototype,
- _sync: function _sync() {
- syncedEngines.push(this.name);
- }
-};
-Service.engineManager.register(StirlingEngine);
-
-// Tracking info/collections.
-var collectionsHelper = track_collections_helper();
-var upd = collectionsHelper.with_updated_collection;
-
-function sync_httpd_setup(handlers) {
-
- handlers["/1.1/johndoe/info/collections"] = collectionsHelper.handler;
- delete collectionsHelper.collections.crypto;
- delete collectionsHelper.collections.meta;
-
- let cr = new ServerWBO("keys");
- handlers["/1.1/johndoe/storage/crypto/keys"] =
- upd("crypto", cr.handler());
-
- let cl = new ServerCollection();
- handlers["/1.1/johndoe/storage/clients"] =
- upd("clients", cl.handler());
-
- return httpd_setup(handlers);
-}
-
-function setUp() {
- syncedEngines = [];
- let engine = Service.engineManager.get("steam");
- engine.enabled = true;
- engine.syncPriority = 1;
-
- engine = Service.engineManager.get("stirling");
- engine.enabled = true;
- engine.syncPriority = 2;
-
- let server = sync_httpd_setup({
- "/1.1/johndoe/storage/meta/global": new ServerWBO("global", {}).handler(),
- });
- new SyncTestingInfrastructure(server, "johndoe", "ilovejane",
- "abcdeabcdeabcdeabcdeabcdea");
- return server;
-}
-
-function run_test() {
- initTestLogging("Trace");
- validate_all_future_pings();
- Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
-
- run_next_test();
-}
-
-add_test(function test_noEngines() {
- _("Test: An empty array of engines to sync does nothing.");
- let server = setUp();
-
- try {
- _("Sync with no engines specified.");
- Service.sync([]);
- deepEqual(syncedEngines, [], "no engines were synced");
-
- } finally {
- Service.startOver();
- server.stop(run_next_test);
- }
-});
-
-add_test(function test_oneEngine() {
- _("Test: Only one engine is synced.");
- let server = setUp();
-
- try {
-
- _("Sync with 1 engine specified.");
- Service.sync(["steam"]);
- deepEqual(syncedEngines, ["steam"])
-
- } finally {
- Service.startOver();
- server.stop(run_next_test);
- }
-});
-
-add_test(function test_bothEnginesSpecified() {
- _("Test: All engines are synced when specified in the correct order (1).");
- let server = setUp();
-
- try {
- _("Sync with both engines specified.");
- Service.sync(["steam", "stirling"]);
- deepEqual(syncedEngines, ["steam", "stirling"])
-
- } finally {
- Service.startOver();
- server.stop(run_next_test);
- }
-});
-
-add_test(function test_bothEnginesSpecified() {
- _("Test: All engines are synced when specified in the correct order (2).");
- let server = setUp();
-
- try {
- _("Sync with both engines specified.");
- Service.sync(["stirling", "steam"]);
- deepEqual(syncedEngines, ["stirling", "steam"])
-
- } finally {
- Service.startOver();
- server.stop(run_next_test);
- }
-});
-
-add_test(function test_bothEnginesDefault() {
- _("Test: All engines are synced when nothing is specified.");
- let server = setUp();
-
- try {
- Service.sync();
- deepEqual(syncedEngines, ["steam", "stirling"])
-
- } finally {
- Service.startOver();
- server.stop(run_next_test);
- }
-});
diff --git a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
index ee1800fd3..c945cb6c2 100644
--- a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
+++ b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
@@ -41,15 +41,13 @@ function StirlingEngine() {
StirlingEngine.prototype = {
__proto__: SteamEngine.prototype,
// This engine's enabled state is the same as the SteamEngine's.
- get prefName() {
- return "steam";
- }
+ get prefName() "steam"
};
Service.engineManager.register(StirlingEngine);
// Tracking info/collections.
-var collectionsHelper = track_collections_helper();
-var upd = collectionsHelper.with_updated_collection;
+let collectionsHelper = track_collections_helper();
+let upd = collectionsHelper.with_updated_collection;
function sync_httpd_setup(handlers) {
@@ -86,7 +84,6 @@ function run_test() {
initTestLogging("Trace");
Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
- validate_all_future_pings();
run_next_test();
}
diff --git a/services/sync/tests/unit/test_service_wipeServer.js b/services/sync/tests/unit/test_service_wipeServer.js
index 9320f4b88..3fc45cf86 100644
--- a/services/sync/tests/unit/test_service_wipeServer.js
+++ b/services/sync/tests/unit/test_service_wipeServer.js
@@ -31,7 +31,7 @@ FakeCollection.prototype = {
}
};
-function* setUpTestFixtures(server) {
+function setUpTestFixtures(server) {
let cryptoService = new FakeCryptoService();
Service.serverURL = server.baseURI + "/";
@@ -52,7 +52,7 @@ function promiseStopServer(server) {
return deferred.promise;
}
-add_identity_test(this, function* test_wipeServer_list_success() {
+add_identity_test(this, function test_wipeServer_list_success() {
_("Service.wipeServer() deletes collections given as argument.");
let steam_coll = new FakeCollection();
@@ -86,7 +86,7 @@ add_identity_test(this, function* test_wipeServer_list_success() {
}
});
-add_identity_test(this, function* test_wipeServer_list_503() {
+add_identity_test(this, function test_wipeServer_list_503() {
_("Service.wipeServer() deletes collections given as argument.");
let steam_coll = new FakeCollection();
@@ -127,7 +127,7 @@ add_identity_test(this, function* test_wipeServer_list_503() {
}
});
-add_identity_test(this, function* test_wipeServer_all_success() {
+add_identity_test(this, function test_wipeServer_all_success() {
_("Service.wipeServer() deletes all the things.");
/**
@@ -157,7 +157,7 @@ add_identity_test(this, function* test_wipeServer_all_success() {
Svc.Prefs.resetBranch("");
});
-add_identity_test(this, function* test_wipeServer_all_404() {
+add_identity_test(this, function test_wipeServer_all_404() {
_("Service.wipeServer() accepts a 404.");
/**
@@ -189,7 +189,7 @@ add_identity_test(this, function* test_wipeServer_all_404() {
Svc.Prefs.resetBranch("");
});
-add_identity_test(this, function* test_wipeServer_all_503() {
+add_identity_test(this, function test_wipeServer_all_503() {
_("Service.wipeServer() throws if it encounters a non-200/404 response.");
/**
@@ -221,7 +221,7 @@ add_identity_test(this, function* test_wipeServer_all_503() {
Svc.Prefs.resetBranch("");
});
-add_identity_test(this, function* test_wipeServer_all_connectionRefused() {
+add_identity_test(this, function test_wipeServer_all_connectionRefused() {
_("Service.wipeServer() throws if it encounters a network problem.");
let server = httpd_setup({});
yield setUpTestFixtures(server);
diff --git a/services/sync/tests/unit/test_status.js b/services/sync/tests/unit/test_status.js
index 378aafe90..bc2d67f42 100644
--- a/services/sync/tests/unit/test_status.js
+++ b/services/sync/tests/unit/test_status.js
@@ -18,9 +18,9 @@ function run_test() {
// Check login status
- for (let code of [LOGIN_FAILED_NO_USERNAME,
- LOGIN_FAILED_NO_PASSWORD,
- LOGIN_FAILED_NO_PASSPHRASE]) {
+ for each (let code in [LOGIN_FAILED_NO_USERNAME,
+ LOGIN_FAILED_NO_PASSWORD,
+ LOGIN_FAILED_NO_PASSPHRASE]) {
Status.login = code;
do_check_eq(Status.login, code);
do_check_eq(Status.service, CLIENT_NOT_CONFIGURED);
diff --git a/services/sync/tests/unit/test_syncedtabs.js b/services/sync/tests/unit/test_syncedtabs.js
deleted file mode 100644
index fe2cb6d1b..000000000
--- a/services/sync/tests/unit/test_syncedtabs.js
+++ /dev/null
@@ -1,221 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et:
-*/
-"use strict";
-
-Cu.import("resource://services-sync/main.js");
-Cu.import("resource://services-sync/SyncedTabs.jsm");
-Cu.import("resource://gre/modules/Log.jsm");
-
-const faviconService = Cc["@mozilla.org/browser/favicon-service;1"]
- .getService(Ci.nsIFaviconService);
-
-Log.repository.getLogger("Sync.RemoteTabs").addAppender(new Log.DumpAppender());
-
-// A mock "Tabs" engine which the SyncedTabs module will use instead of the real
-// engine. We pass a constructor that Sync creates.
-function MockTabsEngine() {
- this.clients = {}; // We'll set this dynamically
-}
-
-MockTabsEngine.prototype = {
- name: "tabs",
- enabled: true,
-
- getAllClients() {
- return this.clients;
- },
-
- getOpenURLs() {
- return new Set();
- },
-}
-
-// A clients engine that doesn't need to be a constructor.
-let MockClientsEngine = {
- clientSettings: null, // Set in `configureClients`.
-
- isMobile(guid) {
- if (!guid.endsWith("desktop") && !guid.endsWith("mobile")) {
- throw new Error("this module expected guids to end with 'desktop' or 'mobile'");
- }
- return guid.endsWith("mobile");
- },
- remoteClientExists(id) {
- return this.clientSettings[id] !== false;
- },
- getClientName(id) {
- if (this.clientSettings[id]) {
- return this.clientSettings[id];
- }
- let engine = Weave.Service.engineManager.get("tabs");
- return engine.clients[id].clientName;
- },
-}
-
-// Configure Sync with our mock tabs engine and force it to become initialized.
-Services.prefs.setCharPref("services.sync.username", "someone@somewhere.com");
-
-Weave.Service.engineManager.unregister("tabs");
-Weave.Service.engineManager.register(MockTabsEngine);
-Weave.Service.clientsEngine = MockClientsEngine;
-
-// Tell the Sync XPCOM service it is initialized.
-let weaveXPCService = Cc["@mozilla.org/weave/service;1"]
- .getService(Ci.nsISupports)
- .wrappedJSObject;
-weaveXPCService.ready = true;
-
-function configureClients(clients, clientSettings = {}) {
- // Configure the instance Sync created.
- let engine = Weave.Service.engineManager.get("tabs");
- // each client record is expected to have an id.
- for (let [guid, client] of Object.entries(clients)) {
- client.id = guid;
- }
- engine.clients = clients;
- // Apply clients collection overrides.
- MockClientsEngine.clientSettings = clientSettings;
- // Send an observer that pretends the engine just finished a sync.
- Services.obs.notifyObservers(null, "weave:engine:sync:finish", "tabs");
-}
-
-// The tests.
-add_task(function* test_noClients() {
- // no clients, can't be tabs.
- yield configureClients({});
-
- let tabs = yield SyncedTabs.getTabClients();
- equal(Object.keys(tabs).length, 0);
-});
-
-add_task(function* test_clientWithTabs() {
- yield configureClients({
- guid_desktop: {
- clientName: "My Desktop",
- tabs: [
- {
- urlHistory: ["http://foo.com/"],
- icon: "http://foo.com/favicon",
- }],
- },
- guid_mobile: {
- clientName: "My Phone",
- tabs: [],
- }
- });
-
- let clients = yield SyncedTabs.getTabClients();
- equal(clients.length, 2);
- clients.sort((a, b) => { return a.name.localeCompare(b.name);});
- equal(clients[0].tabs.length, 1);
- equal(clients[0].tabs[0].url, "http://foo.com/");
- equal(clients[0].tabs[0].icon, "http://foo.com/favicon");
- // second client has no tabs.
- equal(clients[1].tabs.length, 0);
-});
-
-add_task(function* test_staleClientWithTabs() {
- yield configureClients({
- guid_desktop: {
- clientName: "My Desktop",
- tabs: [
- {
- urlHistory: ["http://foo.com/"],
- icon: "http://foo.com/favicon",
- }],
- },
- guid_mobile: {
- clientName: "My Phone",
- tabs: [],
- },
- guid_stale_mobile: {
- clientName: "My Deleted Phone",
- tabs: [],
- },
- guid_stale_desktop: {
- clientName: "My Deleted Laptop",
- tabs: [
- {
- urlHistory: ["https://bar.com/"],
- icon: "https://bar.com/favicon",
- }],
- },
- guid_stale_name_desktop: {
- clientName: "My Generic Device",
- tabs: [
- {
- urlHistory: ["https://example.edu/"],
- icon: "https://example.edu/favicon",
- }],
- },
- }, {
- guid_stale_mobile: false,
- guid_stale_desktop: false,
- // We should always use the device name from the clients collection, instead
- // of the possibly stale tabs collection.
- guid_stale_name_desktop: "My Laptop",
- });
- let clients = yield SyncedTabs.getTabClients();
- clients.sort((a, b) => { return a.name.localeCompare(b.name);});
- equal(clients.length, 3);
- equal(clients[0].name, "My Desktop");
- equal(clients[0].tabs.length, 1);
- equal(clients[0].tabs[0].url, "http://foo.com/");
- equal(clients[1].name, "My Laptop");
- equal(clients[1].tabs.length, 1);
- equal(clients[1].tabs[0].url, "https://example.edu/");
- equal(clients[2].name, "My Phone");
- equal(clients[2].tabs.length, 0);
-});
-
-add_task(function* test_clientWithTabsIconsDisabled() {
- Services.prefs.setBoolPref("services.sync.syncedTabs.showRemoteIcons", false);
- yield configureClients({
- guid_desktop: {
- clientName: "My Desktop",
- tabs: [
- {
- urlHistory: ["http://foo.com/"],
- icon: "http://foo.com/favicon",
- }],
- },
- });
-
- let clients = yield SyncedTabs.getTabClients();
- equal(clients.length, 1);
- clients.sort((a, b) => { return a.name.localeCompare(b.name);});
- equal(clients[0].tabs.length, 1);
- equal(clients[0].tabs[0].url, "http://foo.com/");
- // expect the default favicon (empty string) due to the pref being false.
- equal(clients[0].tabs[0].icon, "");
- Services.prefs.clearUserPref("services.sync.syncedTabs.showRemoteIcons");
-});
-
-add_task(function* test_filter() {
- // Nothing matches.
- yield configureClients({
- guid_desktop: {
- clientName: "My Desktop",
- tabs: [
- {
- urlHistory: ["http://foo.com/"],
- title: "A test page.",
- },
- {
- urlHistory: ["http://bar.com/"],
- title: "Another page.",
- }],
- },
- });
-
- let clients = yield SyncedTabs.getTabClients("foo");
- equal(clients.length, 1);
- equal(clients[0].tabs.length, 1);
- equal(clients[0].tabs[0].url, "http://foo.com/");
- // check it matches the title.
- clients = yield SyncedTabs.getTabClients("test");
- equal(clients.length, 1);
- equal(clients[0].tabs.length, 1);
- equal(clients[0].tabs[0].url, "http://foo.com/");
-});
diff --git a/services/sync/tests/unit/test_syncengine.js b/services/sync/tests/unit/test_syncengine.js
index 8c01ca048..393e49607 100644
--- a/services/sync/tests/unit/test_syncengine.js
+++ b/services/sync/tests/unit/test_syncengine.js
@@ -10,7 +10,7 @@ function makeSteamEngine() {
return new SyncEngine('Steam', Service);
}
-var server;
+let server;
function test_url_attributes() {
_("SyncEngine url attributes");
@@ -35,12 +35,12 @@ function test_syncID() {
do_check_eq(Svc.Prefs.get("steam.syncID"), undefined);
// Performing the first get on the attribute will generate a new GUID.
- do_check_eq(engine.syncID, "fake-guid-00");
- do_check_eq(Svc.Prefs.get("steam.syncID"), "fake-guid-00");
+ do_check_eq(engine.syncID, "fake-guid-0");
+ do_check_eq(Svc.Prefs.get("steam.syncID"), "fake-guid-0");
Svc.Prefs.set("steam.syncID", Utils.makeGUID());
- do_check_eq(Svc.Prefs.get("steam.syncID"), "fake-guid-01");
- do_check_eq(engine.syncID, "fake-guid-01");
+ do_check_eq(Svc.Prefs.get("steam.syncID"), "fake-guid-1");
+ do_check_eq(engine.syncID, "fake-guid-1");
} finally {
Svc.Prefs.resetBranch("");
}
diff --git a/services/sync/tests/unit/test_syncengine_sync.js b/services/sync/tests/unit/test_syncengine_sync.js
index 97289962f..6a6d047bf 100644
--- a/services/sync/tests/unit/test_syncengine_sync.js
+++ b/services/sync/tests/unit/test_syncengine_sync.js
@@ -15,22 +15,13 @@ function makeRotaryEngine() {
return new RotaryEngine(Service);
}
-function clean() {
+function cleanAndGo(server) {
Svc.Prefs.resetBranch("");
Svc.Prefs.set("log.logger.engine.rotary", "Trace");
Service.recordManager.clearCache();
-}
-
-function cleanAndGo(server) {
- clean();
server.stop(run_next_test);
}
-function promiseClean(server) {
- clean();
- return new Promise(resolve => server.stop(resolve));
-}
-
function configureService(server, username, password) {
Service.clusterURL = server.baseURI;
@@ -181,7 +172,7 @@ add_test(function test_syncStartup_syncIDMismatchResetsClient() {
try {
// Confirm initial environment
- do_check_eq(engine.syncID, 'fake-guid-00');
+ do_check_eq(engine.syncID, 'fake-guid-0');
do_check_eq(engine._tracker.changedIDs["rekolok"], undefined);
engine.lastSync = Date.now() / 1000;
@@ -676,7 +667,7 @@ add_test(function test_processIncoming_mobile_batchSize() {
});
-add_task(function *test_processIncoming_store_toFetch() {
+add_test(function test_processIncoming_store_toFetch() {
_("If processIncoming fails in the middle of a batch on mobile, state is saved in toFetch and lastSync.");
Service.identity.username = "foo";
Svc.Prefs.set("client.type", "mobile");
@@ -723,10 +714,11 @@ add_task(function *test_processIncoming_store_toFetch() {
let error;
try {
- yield sync_engine_and_validate_telem(engine, true);
+ engine.sync();
} catch (ex) {
error = ex;
}
+ do_check_true(!!error);
// Only the first two batches have been applied.
do_check_eq(Object.keys(engine._store.items).length,
@@ -738,7 +730,7 @@ add_task(function *test_processIncoming_store_toFetch() {
do_check_eq(engine.lastSync, collection.wbo("record-no-99").modified);
} finally {
- yield promiseClean(server);
+ cleanAndGo(server);
}
});
@@ -1229,7 +1221,7 @@ add_test(function test_processIncoming_failed_records() {
});
-add_task(function *test_processIncoming_decrypt_failed() {
+add_test(function test_processIncoming_decrypt_failed() {
_("Ensure that records failing to decrypt are either replaced or refetched.");
Service.identity.username = "foo";
@@ -1288,10 +1280,7 @@ add_task(function *test_processIncoming_decrypt_failed() {
});
engine.lastSync = collection.wbo("nojson").modified - 1;
- let ping = yield sync_engine_and_validate_telem(engine, true);
- do_check_eq(ping.engines[0].incoming.applied, 2);
- do_check_eq(ping.engines[0].incoming.failed, 4);
- do_check_eq(ping.engines[0].incoming.newFailed, 4);
+ engine.sync();
do_check_eq(engine.previousFailed.length, 4);
do_check_eq(engine.previousFailed[0], "nojson");
@@ -1305,7 +1294,7 @@ add_task(function *test_processIncoming_decrypt_failed() {
do_check_eq(observerSubject.failed, 4);
} finally {
- yield promiseClean(server);
+ cleanAndGo(server);
}
});
@@ -1369,7 +1358,7 @@ add_test(function test_uploadOutgoing_toEmptyServer() {
});
-add_task(function *test_uploadOutgoing_failed() {
+add_test(function test_uploadOutgoing_failed() {
_("SyncEngine._uploadOutgoing doesn't clear the tracker of objects that failed to upload.");
Service.identity.username = "foo";
@@ -1412,7 +1401,7 @@ add_task(function *test_uploadOutgoing_failed() {
do_check_eq(engine._tracker.changedIDs['peppercorn'], PEPPERCORN_CHANGED);
engine.enabled = true;
- yield sync_engine_and_validate_telem(engine, true);
+ engine.sync();
// Local timestamp has been set.
do_check_true(engine.lastSyncLocal > 0);
@@ -1427,14 +1416,11 @@ add_task(function *test_uploadOutgoing_failed() {
do_check_eq(engine._tracker.changedIDs['peppercorn'], PEPPERCORN_CHANGED);
} finally {
- yield promiseClean(server);
+ cleanAndGo(server);
}
});
-/* A couple of "functional" tests to ensure we split records into appropriate
- POST requests. More comprehensive unit-tests for this "batching" are in
- test_postqueue.js.
-*/
+
add_test(function test_uploadOutgoing_MAX_UPLOAD_RECORDS() {
_("SyncEngine._uploadOutgoing uploads in batches of MAX_UPLOAD_RECORDS");
@@ -1444,18 +1430,9 @@ add_test(function test_uploadOutgoing_MAX_UPLOAD_RECORDS() {
// Let's count how many times the client posts to the server
var noOfUploads = 0;
collection.post = (function(orig) {
- return function(data, request) {
- // This test doesn't arrange for batch semantics - so we expect the
- // first request to come in with batch=true and the others to have no
- // batch related headers at all (as the first response did not provide
- // a batch ID)
- if (noOfUploads == 0) {
- do_check_eq(request.queryString, "batch=true");
- } else {
- do_check_eq(request.queryString, "");
- }
+ return function() {
noOfUploads++;
- return orig.call(this, data, request);
+ return orig.apply(this, arguments);
};
}(collection.post));
@@ -1500,44 +1477,6 @@ add_test(function test_uploadOutgoing_MAX_UPLOAD_RECORDS() {
}
});
-add_test(function test_uploadOutgoing_largeRecords() {
- _("SyncEngine._uploadOutgoing throws on records larger than MAX_UPLOAD_BYTES");
-
- Service.identity.username = "foo";
- let collection = new ServerCollection();
-
- let engine = makeRotaryEngine();
- engine.allowSkippedRecord = false;
- engine._store.items["large-item"] = "Y".repeat(MAX_UPLOAD_BYTES*2);
- engine._tracker.addChangedID("large-item", 0);
- collection.insert("large-item");
-
-
- let meta_global = Service.recordManager.set(engine.metaURL,
- new WBORecord(engine.metaURL));
- meta_global.payload.engines = {rotary: {version: engine.version,
- syncID: engine.syncID}};
-
- let server = sync_httpd_setup({
- "/1.1/foo/storage/rotary": collection.handler()
- });
-
- let syncTesting = new SyncTestingInfrastructure(server);
-
- try {
- engine._syncStartup();
- let error = null;
- try {
- engine._uploadOutgoing();
- } catch (e) {
- error = e;
- }
- ok(!!error);
- } finally {
- cleanAndGo(server);
- }
-});
-
add_test(function test_syncFinish_noDelete() {
_("SyncEngine._syncFinish resets tracker's score");
@@ -1667,7 +1606,7 @@ add_test(function test_syncFinish_deleteLotsInBatches() {
});
-add_task(function *test_sync_partialUpload() {
+add_test(function test_sync_partialUpload() {
_("SyncEngine.sync() keeps changedIDs that couldn't be uploaded.");
Service.identity.username = "foo";
@@ -1715,12 +1654,11 @@ add_task(function *test_sync_partialUpload() {
engine.enabled = true;
let error;
try {
- yield sync_engine_and_validate_telem(engine, true);
+ engine.sync();
} catch (ex) {
error = ex;
}
-
- ok(!!error);
+ do_check_true(!!error);
// The timestamp has been updated.
do_check_true(engine.lastSyncLocal > 456);
@@ -1738,7 +1676,7 @@ add_task(function *test_sync_partialUpload() {
}
} finally {
- yield promiseClean(server);
+ cleanAndGo(server);
}
});
diff --git a/services/sync/tests/unit/test_syncscheduler.js b/services/sync/tests/unit/test_syncscheduler.js
index 730a3f996..d496b8838 100644
--- a/services/sync/tests/unit/test_syncscheduler.js
+++ b/services/sync/tests/unit/test_syncscheduler.js
@@ -26,13 +26,8 @@ CatapultEngine.prototype = {
Service.engineManager.register(CatapultEngine);
-var scheduler = new SyncScheduler(Service);
-var clientsEngine = Service.clientsEngine;
-
-// Don't remove stale clients when syncing. This is a test-only workaround
-// that lets us add clients directly to the store, without losing them on
-// the next sync.
-clientsEngine._removeRemoteClient = id => {};
+let scheduler = new SyncScheduler(Service);
+let clientsEngine = Service.clientsEngine;
function sync_httpd_setup() {
let global = new ServerWBO("global", {
@@ -74,7 +69,6 @@ function setUp(server) {
function cleanUpAndGo(server) {
let deferred = Promise.defer();
Utils.nextTick(function () {
- clientsEngine._store.wipe();
Service.startOver();
if (server) {
server.stop(deferred.resolve);
@@ -90,7 +84,6 @@ function run_test() {
Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
Log.repository.getLogger("Sync.scheduler").level = Log.Level.Trace;
- validate_all_future_pings();
// The scheduler checks Weave.fxaEnabled to determine whether to use
// FxA defaults or legacy defaults. As .fxaEnabled checks the username, we
@@ -148,33 +141,22 @@ add_test(function test_prefAttributes() {
Svc.Prefs.get("scheduler.immediateInterval") * 1000);
_("Custom values for prefs will take effect after a restart.");
- Svc.Prefs.set("scheduler.sync11.singleDeviceInterval", 420);
- Svc.Prefs.set("scheduler.idleInterval", 230);
- Svc.Prefs.set("scheduler.activeInterval", 180);
+ Svc.Prefs.set("scheduler.sync11.singleDeviceInterval", 42);
+ Svc.Prefs.set("scheduler.idleInterval", 23);
+ Svc.Prefs.set("scheduler.activeInterval", 18);
Svc.Prefs.set("scheduler.immediateInterval", 31415);
scheduler.setDefaults();
- do_check_eq(scheduler.idleInterval, 230000);
- do_check_eq(scheduler.singleDeviceInterval, 420000);
- do_check_eq(scheduler.activeInterval, 180000);
+ do_check_eq(scheduler.idleInterval, 23000);
+ do_check_eq(scheduler.singleDeviceInterval, 42000);
+ do_check_eq(scheduler.activeInterval, 18000);
do_check_eq(scheduler.immediateInterval, 31415000);
- _("Custom values for interval prefs can't be less than 60 seconds.");
- Svc.Prefs.set("scheduler.sync11.singleDeviceInterval", 42);
- Svc.Prefs.set("scheduler.idleInterval", 50);
- Svc.Prefs.set("scheduler.activeInterval", 50);
- Svc.Prefs.set("scheduler.immediateInterval", 10);
- scheduler.setDefaults();
- do_check_eq(scheduler.idleInterval, 60000);
- do_check_eq(scheduler.singleDeviceInterval, 60000);
- do_check_eq(scheduler.activeInterval, 60000);
- do_check_eq(scheduler.immediateInterval, 60000);
-
Svc.Prefs.resetBranch("");
scheduler.setDefaults();
run_next_test();
});
-add_identity_test(this, function* test_updateClientMode() {
+add_identity_test(this, function test_updateClientMode() {
_("Test updateClientMode adjusts scheduling attributes based on # of clients appropriately");
do_check_eq(scheduler.syncThreshold, SINGLE_USER_THRESHOLD);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
@@ -204,7 +186,7 @@ add_identity_test(this, function* test_updateClientMode() {
yield cleanUpAndGo();
});
-add_identity_test(this, function* test_masterpassword_locked_retry_interval() {
+add_identity_test(this, function test_masterpassword_locked_retry_interval() {
_("Test Status.login = MASTER_PASSWORD_LOCKED results in reschedule at MASTER_PASSWORD interval");
let loginFailed = false;
Svc.Obs.add("weave:service:login:error", function onLoginError() {
@@ -241,7 +223,7 @@ add_identity_test(this, function* test_masterpassword_locked_retry_interval() {
yield cleanUpAndGo(server);
});
-add_identity_test(this, function* test_calculateBackoff() {
+add_identity_test(this, function test_calculateBackoff() {
do_check_eq(Status.backoffInterval, 0);
// Test no interval larger than the maximum backoff is used if
@@ -263,7 +245,7 @@ add_identity_test(this, function* test_calculateBackoff() {
yield cleanUpAndGo();
});
-add_identity_test(this, function* test_scheduleNextSync_nowOrPast() {
+add_identity_test(this, function test_scheduleNextSync_nowOrPast() {
let deferred = Promise.defer();
Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
@@ -278,7 +260,7 @@ add_identity_test(this, function* test_scheduleNextSync_nowOrPast() {
yield deferred.promise;
});
-add_identity_test(this, function* test_scheduleNextSync_future_noBackoff() {
+add_identity_test(this, function test_scheduleNextSync_future_noBackoff() {
_("scheduleNextSync() uses the current syncInterval if no interval is provided.");
// Test backoffInterval is 0 as expected.
do_check_eq(Status.backoffInterval, 0);
@@ -327,7 +309,7 @@ add_identity_test(this, function* test_scheduleNextSync_future_noBackoff() {
yield cleanUpAndGo();
});
-add_identity_test(this, function* test_scheduleNextSync_future_backoff() {
+add_identity_test(this, function test_scheduleNextSync_future_backoff() {
_("scheduleNextSync() will honour backoff in all scheduling requests.");
// Let's take a backoff interval that's bigger than the default sync interval.
const BACKOFF = 7337;
@@ -377,7 +359,7 @@ add_identity_test(this, function* test_scheduleNextSync_future_backoff() {
yield cleanUpAndGo();
});
-add_identity_test(this, function* test_handleSyncError() {
+add_identity_test(this, function test_handleSyncError() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -443,7 +425,7 @@ add_identity_test(this, function* test_handleSyncError() {
yield deferred.promise;
});
-add_identity_test(this, function* test_client_sync_finish_updateClientMode() {
+add_identity_test(this, function test_client_sync_finish_updateClientMode() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -477,7 +459,7 @@ add_identity_test(this, function* test_client_sync_finish_updateClientMode() {
yield cleanUpAndGo(server);
});
-add_identity_test(this, function* test_autoconnect_nextSync_past() {
+add_identity_test(this, function test_autoconnect_nextSync_past() {
let deferred = Promise.defer();
// nextSync will be 0 by default, so it's way in the past.
@@ -493,7 +475,7 @@ add_identity_test(this, function* test_autoconnect_nextSync_past() {
yield deferred.promise;
});
-add_identity_test(this, function* test_autoconnect_nextSync_future() {
+add_identity_test(this, function test_autoconnect_nextSync_future() {
let deferred = Promise.defer();
let previousSync = Date.now() + scheduler.syncInterval / 2;
scheduler.nextSync = previousSync;
@@ -522,7 +504,7 @@ add_identity_test(this, function* test_autoconnect_nextSync_future() {
// XXX - this test can't be run with the browserid identity as it relies
// on the syncKey getter behaving in a certain way...
-add_task(function* test_autoconnect_mp_locked() {
+add_task(function test_autoconnect_mp_locked() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -559,7 +541,7 @@ add_task(function* test_autoconnect_mp_locked() {
yield deferred.promise;
});
-add_identity_test(this, function* test_no_autoconnect_during_wizard() {
+add_identity_test(this, function test_no_autoconnect_during_wizard() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -582,7 +564,7 @@ add_identity_test(this, function* test_no_autoconnect_during_wizard() {
yield deferred.promise;
});
-add_identity_test(this, function* test_no_autoconnect_status_not_ok() {
+add_identity_test(this, function test_no_autoconnect_status_not_ok() {
let server = sync_httpd_setup();
// Ensure we don't actually try to sync (or log in for that matter).
@@ -605,7 +587,7 @@ add_identity_test(this, function* test_no_autoconnect_status_not_ok() {
yield deferred.promise;
});
-add_identity_test(this, function* test_autoconnectDelay_pref() {
+add_identity_test(this, function test_autoconnectDelay_pref() {
let deferred = Promise.defer();
Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
@@ -625,7 +607,7 @@ add_identity_test(this, function* test_autoconnectDelay_pref() {
yield deferred.promise;
});
-add_identity_test(this, function* test_idle_adjustSyncInterval() {
+add_identity_test(this, function test_idle_adjustSyncInterval() {
// Confirm defaults.
do_check_eq(scheduler.idle, false);
@@ -645,7 +627,7 @@ add_identity_test(this, function* test_idle_adjustSyncInterval() {
yield cleanUpAndGo();
});
-add_identity_test(this, function* test_back_triggersSync() {
+add_identity_test(this, function test_back_triggersSync() {
// Confirm defaults.
do_check_false(scheduler.idle);
do_check_eq(Status.backoffInterval, 0);
@@ -668,7 +650,7 @@ add_identity_test(this, function* test_back_triggersSync() {
yield deferred.promise;
});
-add_identity_test(this, function* test_active_triggersSync_observesBackoff() {
+add_identity_test(this, function test_active_triggersSync_observesBackoff() {
// Confirm defaults.
do_check_false(scheduler.idle);
@@ -699,7 +681,7 @@ add_identity_test(this, function* test_active_triggersSync_observesBackoff() {
yield deferred.promise;
});
-add_identity_test(this, function* test_back_debouncing() {
+add_identity_test(this, function test_back_debouncing() {
_("Ensure spurious back-then-idle events, as observed on OS X, don't trigger a sync.");
// Confirm defaults.
@@ -727,7 +709,7 @@ add_identity_test(this, function* test_back_debouncing() {
yield deferred.promise;
});
-add_identity_test(this, function* test_no_sync_node() {
+add_identity_test(this, function test_no_sync_node() {
// Test when Status.sync == NO_SYNC_NODE_FOUND
// it is not overwritten on sync:finish
let server = sync_httpd_setup();
@@ -742,7 +724,7 @@ add_identity_test(this, function* test_no_sync_node() {
yield cleanUpAndGo(server);
});
-add_identity_test(this, function* test_sync_failed_partial_500s() {
+add_identity_test(this, function test_sync_failed_partial_500s() {
_("Test a 5xx status calls handleSyncError.");
scheduler._syncErrors = MAX_ERROR_COUNT_BEFORE_BACKOFF;
let server = sync_httpd_setup();
@@ -769,7 +751,7 @@ add_identity_test(this, function* test_sync_failed_partial_500s() {
yield cleanUpAndGo(server);
});
-add_identity_test(this, function* test_sync_failed_partial_400s() {
+add_identity_test(this, function test_sync_failed_partial_400s() {
_("Test a non-5xx status doesn't call handleSyncError.");
scheduler._syncErrors = MAX_ERROR_COUNT_BEFORE_BACKOFF;
let server = sync_httpd_setup();
@@ -799,7 +781,7 @@ add_identity_test(this, function* test_sync_failed_partial_400s() {
yield cleanUpAndGo(server);
});
-add_identity_test(this, function* test_sync_X_Weave_Backoff() {
+add_identity_test(this, function test_sync_X_Weave_Backoff() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -842,9 +824,9 @@ add_identity_test(this, function* test_sync_X_Weave_Backoff() {
Service.sync();
do_check_true(Status.backoffInterval >= BACKOFF * 1000);
- // Allowing 3 seconds worth of of leeway between when Status.minimumNextSync
+ // Allowing 1 second worth of of leeway between when Status.minimumNextSync
// was set and when this line gets executed.
- let minimumExpectedDelay = (BACKOFF - 3) * 1000;
+ let minimumExpectedDelay = (BACKOFF - 1) * 1000;
do_check_true(Status.minimumNextSync >= Date.now() + minimumExpectedDelay);
// Verify that the next sync is actually going to wait that long.
@@ -854,7 +836,7 @@ add_identity_test(this, function* test_sync_X_Weave_Backoff() {
yield cleanUpAndGo(server);
});
-add_identity_test(this, function* test_sync_503_Retry_After() {
+add_identity_test(this, function test_sync_503_Retry_After() {
let server = sync_httpd_setup();
yield setUp(server);
@@ -901,9 +883,9 @@ add_identity_test(this, function* test_sync_503_Retry_After() {
do_check_true(Status.enforceBackoff);
do_check_true(Status.backoffInterval >= BACKOFF * 1000);
- // Allowing 3 seconds worth of of leeway between when Status.minimumNextSync
+ // Allowing 1 second worth of of leeway between when Status.minimumNextSync
// was set and when this line gets executed.
- let minimumExpectedDelay = (BACKOFF - 3) * 1000;
+ let minimumExpectedDelay = (BACKOFF - 1) * 1000;
do_check_true(Status.minimumNextSync >= Date.now() + minimumExpectedDelay);
// Verify that the next sync is actually going to wait that long.
@@ -913,7 +895,7 @@ add_identity_test(this, function* test_sync_503_Retry_After() {
yield cleanUpAndGo(server);
});
-add_identity_test(this, function* test_loginError_recoverable_reschedules() {
+add_identity_test(this, function test_loginError_recoverable_reschedules() {
_("Verify that a recoverable login error schedules a new sync.");
yield configureIdentity({username: "johndoe"});
Service.serverURL = "http://localhost:1234/";
@@ -957,7 +939,7 @@ add_identity_test(this, function* test_loginError_recoverable_reschedules() {
yield deferred.promise;
});
-add_identity_test(this, function* test_loginError_fatal_clearsTriggers() {
+add_identity_test(this, function test_loginError_fatal_clearsTriggers() {
_("Verify that a fatal login error clears sync triggers.");
yield configureIdentity({username: "johndoe"});
@@ -974,22 +956,11 @@ add_identity_test(this, function* test_loginError_fatal_clearsTriggers() {
Svc.Obs.add("weave:service:login:error", function onLoginError() {
Svc.Obs.remove("weave:service:login:error", onLoginError);
Utils.nextTick(function aLittleBitAfterLoginError() {
+ do_check_eq(Status.login, LOGIN_FAILED_LOGIN_REJECTED);
+
+ do_check_eq(scheduler.nextSync, 0);
+ do_check_eq(scheduler.syncTimer, null);
- if (isConfiguredWithLegacyIdentity()) {
- // for the "legacy" identity, a 401 on info/collections means the
- // password is wrong, so we enter a "login rejected" state.
- do_check_eq(Status.login, LOGIN_FAILED_LOGIN_REJECTED);
-
- do_check_eq(scheduler.nextSync, 0);
- do_check_eq(scheduler.syncTimer, null);
- } else {
- // For the FxA identity, a 401 on info/collections means a transient
- // error, probably due to an inability to fetch a token.
- do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
- // syncs should still be scheduled.
- do_check_true(scheduler.nextSync > Date.now());
- do_check_true(scheduler.syncTimer.delay > 0);
- }
cleanUpAndGo(server).then(deferred.resolve);
});
});
@@ -1004,7 +975,7 @@ add_identity_test(this, function* test_loginError_fatal_clearsTriggers() {
yield deferred.promise;
});
-add_identity_test(this, function* test_proper_interval_on_only_failing() {
+add_identity_test(this, function test_proper_interval_on_only_failing() {
_("Ensure proper behavior when only failed records are applied.");
// If an engine reports that no records succeeded, we shouldn't decrease the
diff --git a/services/sync/tests/unit/test_syncstoragerequest.js b/services/sync/tests/unit/test_syncstoragerequest.js
index 14e5daade..7c5246bab 100644
--- a/services/sync/tests/unit/test_syncstoragerequest.js
+++ b/services/sync/tests/unit/test_syncstoragerequest.js
@@ -8,9 +8,6 @@ Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
-var httpProtocolHandler = Cc["@mozilla.org/network/protocol;1?name=http"]
- .getService(Ci.nsIHttpProtocolHandler);
-
function run_test() {
Log.repository.getLogger("Sync.RESTRequest").level = Log.Level.Trace;
initTestLogging();
@@ -25,7 +22,6 @@ add_test(function test_user_agent_desktop() {
let server = httpd_setup({"/resource": handler});
let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
- " (" + httpProtocolHandler.oscpu + ")" +
" FxSync/" + WEAVE_VERSION + "." +
Services.appinfo.appBuildID + ".desktop";
@@ -45,7 +41,6 @@ add_test(function test_user_agent_mobile() {
Svc.Prefs.set("client.type", "mobile");
let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
- " (" + httpProtocolHandler.oscpu + ")" +
" FxSync/" + WEAVE_VERSION + "." +
Services.appinfo.appBuildID + ".mobile";
diff --git a/services/sync/tests/unit/test_tab_engine.js b/services/sync/tests/unit/test_tab_engine.js
index 049250230..db4b20a70 100644
--- a/services/sync/tests/unit/test_tab_engine.js
+++ b/services/sync/tests/unit/test_tab_engine.js
@@ -1,7 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
-Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/engines/tabs.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/service.js");
@@ -24,12 +23,11 @@ add_test(function test_getOpenURLs() {
_("Test getOpenURLs.");
let [engine, store] = getMocks();
- let superLongURL = "http://" + (new Array(MAX_UPLOAD_BYTES).join("w")) + ".com/";
- let urls = ["http://bar.com", "http://foo.com", "http://foobar.com", superLongURL];
- function fourURLs() {
+ let urls = ["http://bar.com", "http://foo.com", "http://foobar.com"];
+ function threeURLs() {
return urls.pop();
}
- store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, fourURLs, 1, 4);
+ store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, threeURLs, 1, 3);
let matches;
@@ -42,10 +40,6 @@ add_test(function test_getOpenURLs() {
matches = openurlsset.has("http://barfoo.com");
ok(!matches);
- _(" test matching works (too long)");
- matches = openurlsset.has(superLongURL);
- ok(!matches);
-
run_next_test();
});
diff --git a/services/sync/tests/unit/test_tab_store.js b/services/sync/tests/unit/test_tab_store.js
index 93b60f0c7..f8265492f 100644
--- a/services/sync/tests/unit/test_tab_store.js
+++ b/services/sync/tests/unit/test_tab_store.js
@@ -20,26 +20,32 @@ function test_create() {
_("Create a first record");
let rec = {id: "id1",
clientName: "clientName1",
- cleartext: { "foo": "bar" },
+ cleartext: "cleartext1",
modified: 1000};
store.applyIncoming(rec);
- deepEqual(store._remoteClients["id1"], { lastModified: 1000, foo: "bar" });
+ do_check_eq(store._remoteClients["id1"], "cleartext1");
+ do_check_eq(Svc.Prefs.get("notifyTabState"), 1);
_("Create a second record");
rec = {id: "id2",
clientName: "clientName2",
- cleartext: { "foo2": "bar2" },
+ cleartext: "cleartext2",
modified: 2000};
store.applyIncoming(rec);
- deepEqual(store._remoteClients["id2"], { lastModified: 2000, foo2: "bar2" });
+ do_check_eq(store._remoteClients["id2"], "cleartext2");
+ do_check_eq(Svc.Prefs.get("notifyTabState"), 0);
_("Create a third record");
rec = {id: "id3",
clientName: "clientName3",
- cleartext: { "foo3": "bar3" },
+ cleartext: "cleartext3",
modified: 3000};
store.applyIncoming(rec);
- deepEqual(store._remoteClients["id3"], { lastModified: 3000, foo3: "bar3" });
+ do_check_eq(store._remoteClients["id3"], "cleartext3");
+ do_check_eq(Svc.Prefs.get("notifyTabState"), 0);
+
+ // reset the notifyTabState
+ Svc.Prefs.reset("notifyTabState");
}
function test_getAllTabs() {
@@ -53,20 +59,20 @@ function test_getAllTabs() {
_("Get all tabs.");
tabs = store.getAllTabs();
_("Tabs: " + JSON.stringify(tabs));
- equal(tabs.length, 1);
- equal(tabs[0].title, "title");
- equal(tabs[0].urlHistory.length, 2);
- equal(tabs[0].urlHistory[0], "http://foo.com");
- equal(tabs[0].urlHistory[1], "http://bar.com");
- equal(tabs[0].icon, "image");
- equal(tabs[0].lastUsed, 1);
+ do_check_eq(tabs.length, 1);
+ do_check_eq(tabs[0].title, "title");
+ do_check_eq(tabs[0].urlHistory.length, 2);
+ do_check_eq(tabs[0].urlHistory[0], "http://foo.com");
+ do_check_eq(tabs[0].urlHistory[1], "http://bar.com");
+ do_check_eq(tabs[0].icon, "image");
+ do_check_eq(tabs[0].lastUsed, 1);
_("Get all tabs, and check that filtering works.");
let twoUrls = ["about:foo", "http://fuubar.com"];
store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, "http://foo.com", 1, 1, () => 2, () => twoUrls);
tabs = store.getAllTabs(true);
_("Filtered: " + JSON.stringify(tabs));
- equal(tabs.length, 0);
+ do_check_eq(tabs.length, 0);
_("Get all tabs, and check that the entries safety limit works.");
let allURLs = [];
@@ -79,10 +85,10 @@ function test_getAllTabs() {
tabs = store.getAllTabs((url) => url.startsWith("about"));
_("Sliced: " + JSON.stringify(tabs));
- equal(tabs.length, 1);
- equal(tabs[0].urlHistory.length, 25);
- equal(tabs[0].urlHistory[0], "http://foo40.bar");
- equal(tabs[0].urlHistory[24], "http://foo16.bar");
+ do_check_eq(tabs.length, 1);
+ do_check_eq(tabs[0].urlHistory.length, 25);
+ do_check_eq(tabs[0].urlHistory[0], "http://foo40.bar");
+ do_check_eq(tabs[0].urlHistory[24], "http://foo16.bar");
}
function test_createRecord() {
@@ -99,14 +105,14 @@ function test_createRecord() {
store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, "http://foo.com", 1, 1);
record = store.createRecord("fake-guid");
- ok(record instanceof TabSetRecord);
- equal(record.tabs.length, 1);
+ do_check_true(record instanceof TabSetRecord);
+ do_check_eq(record.tabs.length, 1);
_("create a big record");
store.getWindowEnumerator = mockGetWindowEnumerator.bind(this, "http://foo.com", 1, numtabs);
record = store.createRecord("fake-guid");
- ok(record instanceof TabSetRecord);
- equal(record.tabs.length, 256);
+ do_check_true(record instanceof TabSetRecord);
+ do_check_eq(record.tabs.length, 256);
}
function run_test() {
diff --git a/services/sync/tests/unit/test_tab_tracker.js b/services/sync/tests/unit/test_tab_tracker.js
index f98920a44..e7dd48829 100644
--- a/services/sync/tests/unit/test_tab_tracker.js
+++ b/services/sync/tests/unit/test_tab_tracker.js
@@ -5,7 +5,7 @@ Cu.import("resource://services-sync/engines/tabs.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
-var clientsEngine = Service.clientsEngine;
+let clientsEngine = Service.clientsEngine;
function fakeSvcWinMediator() {
// actions on windows are captured in logs
@@ -15,11 +15,9 @@ function fakeSvcWinMediator() {
getEnumerator: function() {
return {
cnt: 2,
- hasMoreElements: function() {
- return this.cnt-- > 0;
- },
+ hasMoreElements: function() this.cnt-- > 0,
getNext: function() {
- let elt = {addTopics: [], remTopics: [], numAPL: 0, numRPL: 0};
+ let elt = {addTopics: [], remTopics: []};
logs.push(elt);
return {
addEventListener: function(topic) {
@@ -27,15 +25,7 @@ function fakeSvcWinMediator() {
},
removeEventListener: function(topic) {
elt.remTopics.push(topic);
- },
- gBrowser: {
- addProgressListener() {
- elt.numAPL++;
- },
- removeProgressListener() {
- elt.numRPL++;
- },
- },
+ }
};
}
};
@@ -61,7 +51,7 @@ function run_test() {
logs = fakeSvcWinMediator();
Svc.Obs.notify("weave:engine:start-tracking");
do_check_eq(logs.length, 2);
- for (let log of logs) {
+ 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);
@@ -69,15 +59,13 @@ function run_test() {
do_check_true(log.addTopics.indexOf("TabSelect") >= 0);
do_check_true(log.addTopics.indexOf("unload") >= 0);
do_check_eq(log.remTopics.length, 0);
- do_check_eq(log.numAPL, 1, "Added 1 progress listener");
- do_check_eq(log.numRPL, 0, "Didn't remove a progress listener");
}
_("Test listeners are unregistered on windows");
logs = fakeSvcWinMediator();
Svc.Obs.notify("weave:engine:stop-tracking");
do_check_eq(logs.length, 2);
- for (let log of logs) {
+ 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);
@@ -85,12 +73,10 @@ function run_test() {
do_check_true(log.remTopics.indexOf("TabClose") >= 0);
do_check_true(log.remTopics.indexOf("TabSelect") >= 0);
do_check_true(log.remTopics.indexOf("unload") >= 0);
- do_check_eq(log.numAPL, 0, "Didn't add a progress listener");
- do_check_eq(log.numRPL, 1, "Removed 1 progress listener");
}
_("Test tab listener");
- for (let evttype of ["TabOpen", "TabClose", "TabSelect"]) {
+ for each (let evttype in ["TabOpen", "TabClose", "TabSelect"]) {
// Pretend we just synced.
tracker.clearChangedIDs();
do_check_false(tracker.modified);
@@ -109,19 +95,4 @@ function run_test() {
tracker.onTab({type: "pageshow", originalTarget: "pageshow"});
do_check_true(Utils.deepEquals(Object.keys(engine.getChangedIDs()),
[clientsEngine.localID]));
-
- // Pretend we just synced and saw some progress listeners.
- tracker.clearChangedIDs();
- do_check_false(tracker.modified);
- tracker.onLocationChange({ isTopLevel: false }, undefined, undefined, 0);
- do_check_false(tracker.modified, "non-toplevel request didn't flag as modified");
-
- tracker.onLocationChange({ isTopLevel: true }, undefined, undefined,
- Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
- do_check_false(tracker.modified, "location change within the same document request didn't flag as modified");
-
- tracker.onLocationChange({ isTopLevel: true }, undefined, undefined, 0);
- do_check_true(tracker.modified, "location change for a new top-level document flagged as modified");
- do_check_true(Utils.deepEquals(Object.keys(engine.getChangedIDs()),
- [clientsEngine.localID]));
}
diff --git a/services/sync/tests/unit/test_telemetry.js b/services/sync/tests/unit/test_telemetry.js
deleted file mode 100644
index 50a3d136b..000000000
--- a/services/sync/tests/unit/test_telemetry.js
+++ /dev/null
@@ -1,564 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-common/observers.js");
-Cu.import("resource://services-sync/telemetry.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/record.js");
-Cu.import("resource://services-sync/resource.js");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://services-sync/engines/bookmarks.js");
-Cu.import("resource://services-sync/engines/clients.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://testing-common/services/sync/fxa_utils.js");
-Cu.import("resource://testing-common/services/sync/rotaryengine.js");
-Cu.import("resource://gre/modules/osfile.jsm", this);
-
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
-Cu.import("resource://services-sync/util.js");
-
-initTestLogging("Trace");
-
-function SteamStore(engine) {
- Store.call(this, "Steam", engine);
-}
-
-SteamStore.prototype = {
- __proto__: Store.prototype,
-};
-
-function SteamTracker(name, engine) {
- Tracker.call(this, name || "Steam", engine);
-}
-
-SteamTracker.prototype = {
- __proto__: Tracker.prototype
-};
-
-function SteamEngine(service) {
- Engine.call(this, "steam", service);
-}
-
-SteamEngine.prototype = {
- __proto__: Engine.prototype,
- _storeObj: SteamStore,
- _trackerObj: SteamTracker,
- _errToThrow: null,
- _sync() {
- if (this._errToThrow) {
- throw this._errToThrow;
- }
- }
-};
-
-function BogusEngine(service) {
- Engine.call(this, "bogus", service);
-}
-
-BogusEngine.prototype = Object.create(SteamEngine.prototype);
-
-function cleanAndGo(server) {
- Svc.Prefs.resetBranch("");
- Svc.Prefs.set("log.logger.engine.rotary", "Trace");
- Service.recordManager.clearCache();
- return new Promise(resolve => server.stop(resolve));
-}
-
-// Avoid addon manager complaining about not being initialized
-Service.engineManager.unregister("addons");
-
-add_identity_test(this, function *test_basic() {
- let helper = track_collections_helper();
- let upd = helper.with_updated_collection;
-
- yield configureIdentity({ username: "johndoe" });
- let handlers = {
- "/1.1/johndoe/info/collections": helper.handler,
- "/1.1/johndoe/storage/crypto/keys": upd("crypto", new ServerWBO("keys").handler()),
- "/1.1/johndoe/storage/meta/global": upd("meta", new ServerWBO("global").handler())
- };
-
- let collections = ["clients", "bookmarks", "forms", "history", "passwords", "prefs", "tabs"];
-
- for (let coll of collections) {
- handlers["/1.1/johndoe/storage/" + coll] = upd(coll, new ServerCollection({}, true).handler());
- }
-
- let server = httpd_setup(handlers);
- Service.serverURL = server.baseURI;
-
- yield sync_and_validate_telem(true);
-
- yield new Promise(resolve => server.stop(resolve));
-});
-
-add_task(function* test_processIncoming_error() {
- let engine = new BookmarksEngine(Service);
- let store = engine._store;
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {bookmarks: {version: engine.version,
- syncID: engine.syncID}}}},
- bookmarks: {}
- });
- new SyncTestingInfrastructure(server.server);
- let collection = server.user("foo").collection("bookmarks");
- try {
- // Create a bogus record that when synced down will provoke a
- // network error which in turn provokes an exception in _processIncoming.
- const BOGUS_GUID = "zzzzzzzzzzzz";
- let bogus_record = collection.insert(BOGUS_GUID, "I'm a bogus record!");
- bogus_record.get = function get() {
- throw "Sync this!";
- };
- // Make the 10 minutes old so it will only be synced in the toFetch phase.
- bogus_record.modified = Date.now() / 1000 - 60 * 10;
- engine.lastSync = Date.now() / 1000 - 60;
- engine.toFetch = [BOGUS_GUID];
-
- let error, ping;
- try {
- yield sync_engine_and_validate_telem(engine, true, errPing => ping = errPing);
- } catch(ex) {
- error = ex;
- }
- ok(!!error);
- ok(!!ping);
- equal(ping.uid, "0".repeat(32));
- deepEqual(ping.failureReason, {
- name: "othererror",
- error: "error.engine.reason.record_download_fail"
- });
-
- equal(ping.engines.length, 1);
- equal(ping.engines[0].name, "bookmarks");
- deepEqual(ping.engines[0].failureReason, {
- name: "othererror",
- error: "error.engine.reason.record_download_fail"
- });
-
- } finally {
- store.wipe();
- yield cleanAndGo(server);
- }
-});
-
-add_task(function *test_uploading() {
- let engine = new BookmarksEngine(Service);
- let store = engine._store;
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {bookmarks: {version: engine.version,
- syncID: engine.syncID}}}},
- bookmarks: {}
- });
- new SyncTestingInfrastructure(server.server);
-
- let parent = PlacesUtils.toolbarFolderId;
- let uri = Utils.makeURI("http://getfirefox.com/");
- let title = "Get Firefox";
-
- let bmk_id = PlacesUtils.bookmarks.insertBookmark(parent, uri,
- PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
-
- let guid = store.GUIDForId(bmk_id);
- let record = store.createRecord(guid);
-
- let collection = server.user("foo").collection("bookmarks");
- try {
- let ping = yield sync_engine_and_validate_telem(engine, false);
- ok(!!ping);
- equal(ping.engines.length, 1);
- equal(ping.engines[0].name, "bookmarks");
- ok(!!ping.engines[0].outgoing);
- greater(ping.engines[0].outgoing[0].sent, 0)
- ok(!ping.engines[0].incoming);
-
- PlacesUtils.bookmarks.setItemTitle(bmk_id, "New Title");
-
- store.wipe();
- engine.resetClient();
-
- ping = yield sync_engine_and_validate_telem(engine, false);
- equal(ping.engines.length, 1);
- equal(ping.engines[0].name, "bookmarks");
- equal(ping.engines[0].outgoing.length, 1);
- ok(!!ping.engines[0].incoming);
-
- } finally {
- // Clean up.
- store.wipe();
- yield cleanAndGo(server);
- }
-});
-
-add_task(function *test_upload_failed() {
- Service.identity.username = "foo";
- let collection = new ServerCollection();
- collection._wbos.flying = new ServerWBO('flying');
-
- let server = sync_httpd_setup({
- "/1.1/foo/storage/rotary": collection.handler()
- });
-
- let syncTesting = new SyncTestingInfrastructure(server);
-
- let engine = new RotaryEngine(Service);
- engine.lastSync = 123; // needs to be non-zero so that tracker is queried
- engine.lastSyncLocal = 456;
- engine._store.items = {
- flying: "LNER Class A3 4472",
- scotsman: "Flying Scotsman",
- peppercorn: "Peppercorn Class"
- };
- const FLYING_CHANGED = 12345;
- const SCOTSMAN_CHANGED = 23456;
- const PEPPERCORN_CHANGED = 34567;
- engine._tracker.addChangedID("flying", FLYING_CHANGED);
- engine._tracker.addChangedID("scotsman", SCOTSMAN_CHANGED);
- engine._tracker.addChangedID("peppercorn", PEPPERCORN_CHANGED);
-
- let meta_global = Service.recordManager.set(engine.metaURL, new WBORecord(engine.metaURL));
- meta_global.payload.engines = { rotary: { version: engine.version, syncID: engine.syncID } };
-
- try {
- engine.enabled = true;
- let ping = yield sync_engine_and_validate_telem(engine, true);
- ok(!!ping);
- equal(ping.engines.length, 1);
- equal(ping.engines[0].incoming, null);
- deepEqual(ping.engines[0].outgoing, [{ sent: 3, failed: 2 }]);
- engine.lastSync = 123;
- engine.lastSyncLocal = 456;
-
- ping = yield sync_engine_and_validate_telem(engine, true);
- ok(!!ping);
- equal(ping.engines.length, 1);
- equal(ping.engines[0].incoming.reconciled, 1);
- deepEqual(ping.engines[0].outgoing, [{ sent: 2, failed: 2 }]);
-
- } finally {
- yield cleanAndGo(server);
- }
-});
-
-add_task(function *test_sync_partialUpload() {
- Service.identity.username = "foo";
-
- let collection = new ServerCollection();
- let server = sync_httpd_setup({
- "/1.1/foo/storage/rotary": collection.handler()
- });
- let syncTesting = new SyncTestingInfrastructure(server);
- generateNewKeys(Service.collectionKeys);
-
- let engine = new RotaryEngine(Service);
- engine.lastSync = 123;
- engine.lastSyncLocal = 456;
-
-
- // Create a bunch of records (and server side handlers)
- for (let i = 0; i < 234; i++) {
- let id = 'record-no-' + i;
- engine._store.items[id] = "Record No. " + i;
- engine._tracker.addChangedID(id, i);
- // Let two items in the first upload batch fail.
- if (i != 23 && i != 42) {
- collection.insert(id);
- }
- }
-
- let meta_global = Service.recordManager.set(engine.metaURL,
- new WBORecord(engine.metaURL));
- meta_global.payload.engines = {rotary: {version: engine.version,
- syncID: engine.syncID}};
-
- try {
- engine.enabled = true;
- let ping = yield sync_engine_and_validate_telem(engine, true);
-
- ok(!!ping);
- ok(!ping.failureReason);
- equal(ping.engines.length, 1);
- equal(ping.engines[0].name, "rotary");
- ok(!ping.engines[0].incoming);
- ok(!ping.engines[0].failureReason);
- deepEqual(ping.engines[0].outgoing, [{ sent: 234, failed: 2 }]);
-
- collection.post = function() { throw "Failure"; }
-
- engine._store.items["record-no-1000"] = "Record No. 1000";
- engine._tracker.addChangedID("record-no-1000", 1000);
- collection.insert("record-no-1000", 1000);
-
- engine.lastSync = 123;
- engine.lastSyncLocal = 456;
- ping = null;
-
- try {
- // should throw
- yield sync_engine_and_validate_telem(engine, true, errPing => ping = errPing);
- } catch (e) {}
- // It would be nice if we had a more descriptive error for this...
- let uploadFailureError = {
- name: "othererror",
- error: "error.engine.reason.record_upload_fail"
- };
-
- ok(!!ping);
- deepEqual(ping.failureReason, uploadFailureError);
- equal(ping.engines.length, 1);
- equal(ping.engines[0].name, "rotary");
- deepEqual(ping.engines[0].incoming, {
- failed: 1,
- newFailed: 1,
- reconciled: 232
- });
- ok(!ping.engines[0].outgoing);
- deepEqual(ping.engines[0].failureReason, uploadFailureError);
-
- } finally {
- yield cleanAndGo(server);
- }
-});
-
-add_task(function* test_generic_engine_fail() {
- Service.engineManager.register(SteamEngine);
- let engine = Service.engineManager.get("steam");
- engine.enabled = true;
- let store = engine._store;
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {steam: {version: engine.version,
- syncID: engine.syncID}}}},
- steam: {}
- });
- new SyncTestingInfrastructure(server.server);
- let e = new Error("generic failure message")
- engine._errToThrow = e;
-
- try {
- let ping = yield sync_and_validate_telem(true);
- equal(ping.status.service, SYNC_FAILED_PARTIAL);
- deepEqual(ping.engines.find(e => e.name === "steam").failureReason, {
- name: "unexpectederror",
- error: String(e)
- });
- } finally {
- Service.engineManager.unregister(engine);
- yield cleanAndGo(server);
- }
-});
-
-add_task(function* test_engine_fail_ioerror() {
- Service.engineManager.register(SteamEngine);
- let engine = Service.engineManager.get("steam");
- engine.enabled = true;
- let store = engine._store;
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {steam: {version: engine.version,
- syncID: engine.syncID}}}},
- steam: {}
- });
- new SyncTestingInfrastructure(server.server);
- // create an IOError to re-throw as part of Sync.
- try {
- // (Note that fakeservices.js has replaced Utils.jsonMove etc, but for
- // this test we need the real one so we get real exceptions from the
- // filesystem.)
- yield Utils._real_jsonMove("file-does-not-exist", "anything", {});
- } catch (ex) {
- engine._errToThrow = ex;
- }
- ok(engine._errToThrow, "expecting exception");
-
- try {
- let ping = yield sync_and_validate_telem(true);
- equal(ping.status.service, SYNC_FAILED_PARTIAL);
- let failureReason = ping.engines.find(e => e.name === "steam").failureReason;
- equal(failureReason.name, "unexpectederror");
- // ensure the profile dir in the exception message has been stripped.
- ok(!failureReason.error.includes(OS.Constants.Path.profileDir), failureReason.error);
- ok(failureReason.error.includes("[profileDir]"), failureReason.error);
- } finally {
- Service.engineManager.unregister(engine);
- yield cleanAndGo(server);
- }
-});
-
-add_task(function* test_initial_sync_engines() {
- Service.engineManager.register(SteamEngine);
- let engine = Service.engineManager.get("steam");
- engine.enabled = true;
- let store = engine._store;
- let engines = {};
- // These are the only ones who actually have things to sync at startup.
- let engineNames = ["clients", "bookmarks", "prefs", "tabs"];
- let conf = { meta: { global: { engines } } };
- for (let e of engineNames) {
- engines[e] = { version: engine.version, syncID: engine.syncID };
- conf[e] = {};
- }
- let server = serverForUsers({"foo": "password"}, conf);
- new SyncTestingInfrastructure(server.server);
- try {
- let ping = yield wait_for_ping(() => Service.sync(), true);
-
- equal(ping.engines.find(e => e.name === "clients").outgoing[0].sent, 1);
- equal(ping.engines.find(e => e.name === "tabs").outgoing[0].sent, 1);
-
- // for the rest we don't care about specifics
- for (let e of ping.engines) {
- if (!engineNames.includes(engine.name)) {
- continue;
- }
- greaterOrEqual(e.took, 1);
- ok(!!e.outgoing)
- equal(e.outgoing.length, 1);
- notEqual(e.outgoing[0].sent, undefined);
- equal(e.outgoing[0].failed, undefined);
- }
- } finally {
- yield cleanAndGo(server);
- }
-});
-
-add_task(function* test_nserror() {
- Service.engineManager.register(SteamEngine);
- let engine = Service.engineManager.get("steam");
- engine.enabled = true;
- let store = engine._store;
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {steam: {version: engine.version,
- syncID: engine.syncID}}}},
- steam: {}
- });
- new SyncTestingInfrastructure(server.server);
- engine._errToThrow = Components.Exception("NS_ERROR_UNKNOWN_HOST", Cr.NS_ERROR_UNKNOWN_HOST);
- try {
- let ping = yield sync_and_validate_telem(true);
- deepEqual(ping.status, {
- service: SYNC_FAILED_PARTIAL,
- sync: LOGIN_FAILED_NETWORK_ERROR
- });
- let enginePing = ping.engines.find(e => e.name === "steam");
- deepEqual(enginePing.failureReason, {
- name: "nserror",
- code: Cr.NS_ERROR_UNKNOWN_HOST
- });
- } finally {
- Service.engineManager.unregister(engine);
- yield cleanAndGo(server);
- }
-});
-
-add_identity_test(this, function *test_discarding() {
- let helper = track_collections_helper();
- let upd = helper.with_updated_collection;
- let telem = get_sync_test_telemetry();
- telem.maxPayloadCount = 2;
- telem.submissionInterval = Infinity;
- let oldSubmit = telem.submit;
-
- let server;
- try {
-
- yield configureIdentity({ username: "johndoe" });
- let handlers = {
- "/1.1/johndoe/info/collections": helper.handler,
- "/1.1/johndoe/storage/crypto/keys": upd("crypto", new ServerWBO("keys").handler()),
- "/1.1/johndoe/storage/meta/global": upd("meta", new ServerWBO("global").handler())
- };
-
- let collections = ["clients", "bookmarks", "forms", "history", "passwords", "prefs", "tabs"];
-
- for (let coll of collections) {
- handlers["/1.1/johndoe/storage/" + coll] = upd(coll, new ServerCollection({}, true).handler());
- }
-
- server = httpd_setup(handlers);
- Service.serverURL = server.baseURI;
- telem.submit = () => ok(false, "Submitted telemetry ping when we should not have");
-
- for (let i = 0; i < 5; ++i) {
- Service.sync();
- }
- telem.submit = oldSubmit;
- telem.submissionInterval = -1;
- let ping = yield sync_and_validate_telem(true, true); // with this we've synced 6 times
- equal(ping.syncs.length, 2);
- equal(ping.discarded, 4);
- } finally {
- telem.maxPayloadCount = 500;
- telem.submissionInterval = -1;
- telem.submit = oldSubmit;
- if (server) {
- yield new Promise(resolve => server.stop(resolve));
- }
- }
-})
-
-add_task(function* test_no_foreign_engines_in_error_ping() {
- Service.engineManager.register(BogusEngine);
- let engine = Service.engineManager.get("bogus");
- engine.enabled = true;
- let store = engine._store;
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {bogus: {version: engine.version, syncID: engine.syncID}}}},
- steam: {}
- });
- engine._errToThrow = new Error("Oh no!");
- new SyncTestingInfrastructure(server.server);
- try {
- let ping = yield sync_and_validate_telem(true);
- equal(ping.status.service, SYNC_FAILED_PARTIAL);
- ok(ping.engines.every(e => e.name !== "bogus"));
- } finally {
- Service.engineManager.unregister(engine);
- yield cleanAndGo(server);
- }
-});
-
-add_task(function* test_sql_error() {
- Service.engineManager.register(SteamEngine);
- let engine = Service.engineManager.get("steam");
- engine.enabled = true;
- let store = engine._store;
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {steam: {version: engine.version,
- syncID: engine.syncID}}}},
- steam: {}
- });
- new SyncTestingInfrastructure(server.server);
- engine._sync = function() {
- // Just grab a DB connection and issue a bogus SQL statement synchronously.
- let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
- Async.querySpinningly(db.createAsyncStatement("select bar from foo"));
- };
- try {
- let ping = yield sync_and_validate_telem(true);
- let enginePing = ping.engines.find(e => e.name === "steam");
- deepEqual(enginePing.failureReason, { name: "sqlerror", code: 1 });
- } finally {
- Service.engineManager.unregister(engine);
- yield cleanAndGo(server);
- }
-});
-
-add_task(function* test_no_foreign_engines_in_success_ping() {
- Service.engineManager.register(BogusEngine);
- let engine = Service.engineManager.get("bogus");
- engine.enabled = true;
- let store = engine._store;
- let server = serverForUsers({"foo": "password"}, {
- meta: {global: {engines: {bogus: {version: engine.version, syncID: engine.syncID}}}},
- steam: {}
- });
-
- new SyncTestingInfrastructure(server.server);
- try {
- let ping = yield sync_and_validate_telem();
- ok(ping.engines.every(e => e.name !== "bogus"));
- } finally {
- Service.engineManager.unregister(engine);
- yield cleanAndGo(server);
- }
-}); \ No newline at end of file
diff --git a/services/sync/tests/unit/test_utils_catch.js b/services/sync/tests/unit/test_utils_catch.js
index 5f50bf7e4..a10e5eb0d 100644
--- a/services/sync/tests/unit/test_utils_catch.js
+++ b/services/sync/tests/unit/test_utils_catch.js
@@ -8,46 +8,38 @@ function run_test() {
catch: Utils.catch,
_log: {
debug: function(str) {
- didThrow = str.search(/^Exception/) == 0;
+ didThrow = str.search(/^Exception: /) == 0;
},
info: function(str) {
wasLocked = str.indexOf("Cannot start sync: already syncing?") == 0;
}
},
- func: function() {
- return this.catch(function() {
- rightThis = this == obj;
- didCall = true;
- return 5;
- })();
- },
+ func: function() this.catch(function() {
+ rightThis = this == obj;
+ didCall = true;
+ return 5;
+ })(),
- throwy: function() {
- return this.catch(function() {
- rightThis = this == obj;
- didCall = true;
- throw 10;
- })();
- },
+ throwy: function() this.catch(function() {
+ rightThis = this == obj;
+ didCall = true;
+ throw 10;
+ })(),
- callbacky: function() {
- return this.catch(function() {
- rightThis = this == obj;
- didCall = true;
- throw 10;
- }, function(ex) {
- wasTen = (ex == 10)
- })();
- },
+ callbacky: function() this.catch(function() {
+ rightThis = this == obj;
+ didCall = true;
+ throw 10;
+ }, function(ex) {
+ wasTen = (ex == 10)
+ })(),
- lockedy: function() {
- return this.catch(function() {
- rightThis = this == obj;
- didCall = true;
- throw("Could not acquire lock.");
- })();
- }
+ lockedy: function() this.catch(function() {
+ rightThis = this == obj;
+ didCall = true;
+ throw("Could not acquire lock.");
+ })()
};
_("Make sure a normal call will call and return");
diff --git a/services/sync/tests/unit/test_utils_deferGetSet.js b/services/sync/tests/unit/test_utils_deferGetSet.js
index 9d58a9873..55c0fcb0e 100644
--- a/services/sync/tests/unit/test_utils_deferGetSet.js
+++ b/services/sync/tests/unit/test_utils_deferGetSet.js
@@ -6,12 +6,8 @@ function run_test() {
base.prototype = {
dst: {},
- get a() {
- return "a";
- },
- set b(val) {
- this.dst.b = val + "!!!";
- }
+ get a() "a",
+ set b(val) this.dst.b = val + "!!!"
};
let src = new base();
diff --git a/services/sync/tests/unit/test_utils_deriveKey.js b/services/sync/tests/unit/test_utils_deriveKey.js
index 17dd889c7..e205fa9f8 100644
--- a/services/sync/tests/unit/test_utils_deriveKey.js
+++ b/services/sync/tests/unit/test_utils_deriveKey.js
@@ -1,7 +1,7 @@
Cu.import("resource://services-crypto/WeaveCrypto.js");
Cu.import("resource://services-sync/util.js");
-var cryptoSvc = new WeaveCrypto();
+let cryptoSvc = new WeaveCrypto();
function run_test() {
if (this.gczeal) {
diff --git a/services/sync/tests/unit/test_utils_lock.js b/services/sync/tests/unit/test_utils_lock.js
index d1830787e..fd8a4b1f5 100644
--- a/services/sync/tests/unit/test_utils_lock.js
+++ b/services/sync/tests/unit/test_utils_lock.js
@@ -27,23 +27,19 @@ function run_test() {
this._locked = false;
},
- func: function() {
- return this._lock("Test utils lock",
- function() {
- rightThis = this == obj;
- didCall = true;
- return 5;
- })();
- },
+ func: function() this._lock("Test utils lock",
+ function() {
+ rightThis = this == obj;
+ didCall = true;
+ return 5;
+ })(),
- throwy: function() {
- return this._lock("Test utils lock throwy",
- function() {
- rightThis = this == obj;
- didCall = true;
- this.throwy();
- })();
- }
+ throwy: function() this._lock("Test utils lock throwy",
+ function() {
+ rightThis = this == obj;
+ didCall = true;
+ this.throwy();
+ })()
};
_("Make sure a normal call will call and return");
diff --git a/services/sync/tests/unit/test_utils_notify.js b/services/sync/tests/unit/test_utils_notify.js
index 5bd38da5f..c191bbfef 100644
--- a/services/sync/tests/unit/test_utils_notify.js
+++ b/services/sync/tests/unit/test_utils_notify.js
@@ -9,21 +9,17 @@ function run_test() {
trace: function() {}
},
- func: function() {
- return this.notify("bar", "baz", function() {
- rightThis = this == obj;
- didCall = true;
- return 5;
- })();
- },
+ func: function() this.notify("bar", "baz", function() {
+ rightThis = this == obj;
+ didCall = true;
+ return 5;
+ })(),
- throwy: function() {
- return this.notify("bad", "one", function() {
- rightThis = this == obj;
- didCall = true;
- throw 10;
- })();
- }
+ throwy: function() this.notify("bad", "one", function() {
+ rightThis = this == obj;
+ didCall = true;
+ throw 10;
+ })()
};
let state = 0;
diff --git a/services/sync/tests/unit/test_warn_on_truncated_response.js b/services/sync/tests/unit/test_warn_on_truncated_response.js
index 1f0d87ba9..a9f070ee4 100644
--- a/services/sync/tests/unit/test_warn_on_truncated_response.js
+++ b/services/sync/tests/unit/test_warn_on_truncated_response.js
@@ -12,11 +12,11 @@ function run_test() {
run_next_test();
}
-var BODY = "response body";
+let BODY = "response body";
// contentLength needs to be longer than the response body
// length in order to get a mismatch between what is sent in
// the response and the content-length header value.
-var contentLength = BODY.length + 1;
+let contentLength = BODY.length + 1;
function contentHandler(request, response) {
_("Handling request.");
diff --git a/services/sync/tests/unit/xpcshell.ini b/services/sync/tests/unit/xpcshell.ini
index 4c0f0e7b7..dc33c0eb2 100644
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
-head = head_appinfo.js ../../../common/tests/unit/head_helpers.js head_helpers.js head_http_server.js head_errorhandler_common.js
+head = head_appinfo.js ../../../common/tests/unit/head_helpers.js head_helpers.js head_http_server.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'gonk'
support-files =
addon1-search.xml
bootstrap1-search.xml
@@ -10,10 +11,6 @@ support-files =
missing-xpi-search.xml
places_v10_from_v11.sqlite
rewrite-search.xml
- sync_ping_schema.json
- systemaddon-search.xml
- !/services/common/tests/unit/head_helpers.js
- !/toolkit/components/webextensions/test/xpcshell/head_sync.js
# The manifest is roughly ordered from low-level to high-level. When making
# systemic sweeping changes, this makes it easier to identify errors closer to
@@ -39,7 +36,6 @@ support-files =
# We have a number of other libraries that are pretty much standalone.
[test_addon_utils.js]
run-sequentially = Restarts server, can't change pref.
-tags = addons
[test_httpd_sync_server.js]
[test_jpakeclient.js]
# Bug 618233: this test produces random failures on Windows 7.
@@ -56,7 +52,6 @@ skip-if = os == "win" || os == "android"
# Generic Sync types.
[test_browserid_identity.js]
[test_collection_inc_get.js]
-[test_collection_getBatched.js]
[test_collections_recovery.js]
[test_identity_manager.js]
[test_keys.js]
@@ -97,7 +92,6 @@ skip-if = os == "mac" || os == "linux"
[test_service_sync_remoteSetup.js]
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
skip-if = os == "android"
-[test_service_sync_specified.js]
[test_service_sync_updateEnabledEngines.js]
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
skip-if = os == "android"
@@ -109,8 +103,7 @@ skip-if = os == "mac" || os == "linux"
[test_corrupt_keys.js]
[test_declined.js]
-[test_errorhandler_1.js]
-[test_errorhandler_2.js]
+[test_errorhandler.js]
[test_errorhandler_filelog.js]
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
skip-if = os == "android"
@@ -121,6 +114,7 @@ skip-if = os == "android"
[test_hmac_error.js]
[test_interval_triggers.js]
[test_node_reassignment.js]
+[test_notifications.js]
[test_score_triggers.js]
[test_sendcredentials_controller.js]
[test_status.js]
@@ -136,18 +130,12 @@ skip-if = os == "android"
# Finally, we test each engine.
[test_addons_engine.js]
run-sequentially = Hardcoded port in static files.
-tags = addons
[test_addons_reconciler.js]
-tags = addons
[test_addons_store.js]
run-sequentially = Hardcoded port in static files.
-tags = addons
[test_addons_tracker.js]
-tags = addons
[test_bookmark_batch_fail.js]
-[test_bookmark_duping.js]
[test_bookmark_engine.js]
-[test_bookmark_invalid.js]
[test_bookmark_legacy_microsummaries_support.js]
[test_bookmark_livemarks.js]
[test_bookmark_order.js]
@@ -158,13 +146,8 @@ tags = addons
# Too many intermittent "ASSERTION: thread pool wasn't shutdown: '!mPool'" (bug 804479)
skip-if = debug
[test_bookmark_tracker.js]
-requesttimeoutfactor = 4
-[test_bookmark_validator.js]
[test_clients_engine.js]
[test_clients_escape.js]
-[test_extension_storage_crypto.js]
-[test_extension_storage_engine.js]
-[test_extension_storage_tracker.js]
[test_forms_store.js]
[test_forms_tracker.js]
# Too many intermittent "ASSERTION: thread pool wasn't shutdown: '!mPool'" (bug 804479)
@@ -176,21 +159,24 @@ skip-if = debug
skip-if = debug
[test_places_guid_downgrade.js]
[test_password_store.js]
-[test_password_validator.js]
[test_password_tracker.js]
# Too many intermittent "ASSERTION: thread pool wasn't shutdown: '!mPool'" (bug 804479)
skip-if = debug
[test_prefs_store.js]
-support-files = prefs_test_prefs_store.js
[test_prefs_tracker.js]
[test_tab_engine.js]
[test_tab_store.js]
[test_tab_tracker.js]
-[test_warn_on_truncated_response.js]
-[test_postqueue.js]
+[test_healthreport.js]
+skip-if = ! healthreport
+
+[test_healthreport_migration.js]
+skip-if = ! healthreport
-# Synced tabs.
-[test_syncedtabs.js]
+[test_warn_on_truncated_response.js]
-[test_telemetry.js]
+# FxA migration
+[test_block_sync.js]
+[test_fxa_migration.js]
+[test_fxa_migration_sentinel.js]