--- a/services/sync/modules-testing/rotaryengine.js
+++ b/services/sync/modules-testing/rotaryengine.js
@@ -87,17 +87,18 @@ RotaryStore.prototype = {
this.items = {};
}
};
this.RotaryTracker = function RotaryTracker(name, engine) {
Tracker.call(this, name, engine);
}
RotaryTracker.prototype = {
- __proto__: Tracker.prototype
+ __proto__: Tracker.prototype,
+ persistChangedIDs: false,
};
this.RotaryEngine = function RotaryEngine(service) {
SyncEngine.call(this, "Rotary", service);
// Ensure that the engine starts with a clean slate.
this.toFetch = [];
this.previousFailed = [];
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -624,23 +624,25 @@ EngineManager.prototype = {
unregister(val) {
let name = val;
if (val instanceof Engine) {
name = val.name;
}
if (name in this._engines) {
let engine = this._engines[name];
delete this._engines[name];
- engine.finalize();
+ Async.promiseSpinningly(engine.finalize());
}
},
clear() {
for (let name in this._engines) {
+ let engine = this._engines[name];
delete this._engines[name];
+ Async.promiseSpinningly(engine.finalize());
}
},
};
this.Engine = function Engine(name, service) {
if (!service) {
throw new Error("Engine must be associated with a Service instance.");
}
@@ -740,18 +742,18 @@ Engine.prototype = {
* If one exists, initialize and return a validator for this engine (which
* must have a `validate(engine)` method that returns a promise to an object
* with a getSummary method). Otherwise return null.
*/
getValidator() {
return null;
},
- finalize() {
- Async.promiseSpinningly(this._tracker.finalize());
+ async finalize() {
+ await this._tracker.finalize();
},
};
this.SyncEngine = function SyncEngine(name, service) {
Engine.call(this, name || "SyncEngine", service);
this.loadToFetch();
this.loadPreviousFailed();
--- a/services/sync/tests/unit/head_helpers.js
+++ b/services/sync/tests/unit/head_helpers.js
@@ -478,8 +478,18 @@ function promiseNextTick() {
});
}
// 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";
};
+
+function registerRotaryEngine() {
+ Service.engineManager.clear();
+
+ Service.engineManager.register(RotaryEngine);
+ let engine = Service.engineManager.get("rotary");
+ engine.enabled = true;
+
+ return { engine, tracker: engine._tracker };
+}
--- a/services/sync/tests/unit/test_engine.js
+++ b/services/sync/tests/unit/test_engine.js
@@ -66,17 +66,17 @@ Observers.add("weave:engine:sync:start",
Observers.add("weave:engine:sync:finish", engineObserver);
async function cleanup(engine) {
Svc.Prefs.resetBranch("");
engine.wasReset = false;
engine.wasSynced = false;
engineObserver.reset();
engine._tracker.clearChangedIDs();
- await engine._tracker._storage.finalize();
+ await engine.finalize();
}
add_task(async function test_members() {
_("Engine object members");
let engine = new SteamEngine("Steam", Service);
do_check_eq(engine.Name, "Steam");
do_check_eq(engine.prefName, "steam");
do_check_true(engine._store instanceof SteamStore);
--- a/services/sync/tests/unit/test_engine_abort.js
+++ b/services/sync/tests/unit/test_engine_abort.js
@@ -57,13 +57,16 @@ add_task(async function test_processInco
err = ex;
}
do_check_eq(err, undefined);
await promiseStopServer(server);
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
+
+ engine._tracker.clearChangedIDs();
+ await engine.finalize();
});
function run_test() {
run_next_test();
}
--- a/services/sync/tests/unit/test_enginemanager.js
+++ b/services/sync/tests/unit/test_enginemanager.js
@@ -5,25 +5,25 @@ Cu.import("resource://services-sync/engi
Cu.import("resource://services-sync/service.js");
function run_test() {
run_next_test();
}
function PetrolEngine() {}
PetrolEngine.prototype.name = "petrol";
-PetrolEngine.prototype.finalize = function() {};
+PetrolEngine.prototype.finalize = async function() {};
function DieselEngine() {}
DieselEngine.prototype.name = "diesel";
-DieselEngine.prototype.finalize = function() {};
+DieselEngine.prototype.finalize = async function() {};
function DummyEngine() {}
DummyEngine.prototype.name = "dummy";
-DummyEngine.prototype.finalize = function() {};
+DummyEngine.prototype.finalize = async function() {};
function ActualEngine() {}
ActualEngine.prototype = {__proto__: Engine.prototype,
name: "actual"};
add_test(function test_basics() {
_("We start out with a clean slate");
--- a/services/sync/tests/unit/test_fxa_node_reassignment.js
+++ b/services/sync/tests/unit/test_fxa_node_reassignment.js
@@ -13,29 +13,29 @@ Cu.import("resource://services-sync/cons
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");
Cu.import("resource://gre/modules/PromiseUtils.jsm");
+// Disables all built-in engines. Important for avoiding errors thrown by the
+// add-ons engine.
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.");
}
@@ -205,18 +205,17 @@ add_task(async function test_single_toke
});
add_task(async function test_momentary_401_engine() {
_("Test a failure for engine URLs that's resolved by reassignment.");
let server = await prepareServer();
let john = server.user("johndoe");
_("Enabling the Rotary engine.");
- let engine = Service.engineManager.get("rotary");
- engine.enabled = true;
+ let { engine, tracker } = registerRotaryEngine();
// 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);
@@ -248,16 +247,19 @@ add_task(async function test_momentary_4
Svc.Obs.add("weave:service:login:start", onLoginStart);
}
await syncAndExpectNodeReassignment(server,
"weave:service:sync:finish",
between,
"weave:service:sync:finish",
Service.storageURL + "rotary");
+
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
});
// This test ends up being a failing info fetch *after we're already logged in*.
add_task(async function test_momentary_401_info_collections_loggedin() {
_("Test a failure for info/collections after login that's resolved by reassignment.");
let server = await prepareServer();
_("First sync to prepare server contents.");
--- a/services/sync/tests/unit/test_hmac_error.js
+++ b/services/sync/tests/unit/test_hmac_error.js
@@ -16,43 +16,40 @@ var hmacErrorCount = 0;
return hHE.call(Service);
};
})();
function shared_setup() {
hmacErrorCount = 0;
// Make sure RotaryEngine is the only one we sync.
- Service.engineManager._engines = {};
- Service.engineManager.register(RotaryEngine);
- let engine = Service.engineManager.get("rotary");
- engine.enabled = true;
+ let { engine, tracker } = registerRotaryEngine();
engine.lastSync = 123; // Needs to be non-zero so that tracker is queried.
engine._store.items = {flying: "LNER Class A3 4472",
scotsman: "Flying Scotsman"};
- engine._tracker.addChangedID("scotsman", 0);
+ tracker.addChangedID("scotsman", 0);
do_check_eq(1, Service.engineManager.getEnabled().length);
let engines = {rotary: {version: engine.version,
syncID: engine.syncID},
clients: {version: Service.clientsEngine.version,
syncID: Service.clientsEngine.syncID}};
// Common server objects.
let global = new ServerWBO("global", {engines});
let keysWBO = new ServerWBO("keys");
let rotaryColl = new ServerCollection({}, true);
let clientsColl = new ServerCollection({}, true);
- return [engine, rotaryColl, clientsColl, keysWBO, global];
+ return [engine, rotaryColl, clientsColl, keysWBO, global, tracker];
}
add_task(async function hmac_error_during_404() {
_("Attempt to replicate the HMAC error setup.");
- let [engine, rotaryColl, clientsColl, keysWBO, global] = shared_setup();
+ let [engine, rotaryColl, clientsColl, keysWBO, global, tracker] = shared_setup();
// Hand out 404s for crypto/keys.
let keysHandler = keysWBO.handler();
let key404Counter = 0;
let keys404Handler = function(request, response) {
if (key404Counter > 0) {
let body = "Not Found";
response.setStatusLine(request.httpVersion, 404, body);
@@ -88,25 +85,27 @@ add_task(async function hmac_error_durin
key404Counter = 1;
_("---------------------------");
await sync_and_validate_telem();
_("---------------------------");
// Two rotary items, one client record... no errors.
do_check_eq(hmacErrorCount, 0)
} finally {
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
await promiseStopServer(server);
}
});
add_task(async function hmac_error_during_node_reassignment() {
_("Attempt to replicate an HMAC error during node reassignment.");
- let [engine, rotaryColl, clientsColl, keysWBO, global] = shared_setup();
+ let [engine, rotaryColl, clientsColl, keysWBO, global, tracker] = shared_setup();
let collectionsHelper = track_collections_helper();
let upd = collectionsHelper.with_updated_collection;
// We'll provide a 401 mid-way through the sync. This function
// simulates shifting to a node which has no data.
function on401() {
_("Deleting server data...");
@@ -214,19 +213,20 @@ add_task(async function hmac_error_durin
onSyncFinished = function() {
// Two rotary items, one client record... no errors.
do_check_eq(hmacErrorCount, 0)
Svc.Obs.remove("weave:service:sync:finish", obs);
Svc.Obs.remove("weave:service:sync:error", obs);
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
- engine._tracker.clearChangedIDs();
server.stop(resolve);
};
Service.sync();
},
this);
};
};
--- a/services/sync/tests/unit/test_node_reassignment.js
+++ b/services/sync/tests/unit/test_node_reassignment.js
@@ -9,30 +9,26 @@ Cu.import("resource://services-common/re
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://testing-common/services/sync/utils.js");
Cu.import("resource://gre/modules/PromiseUtils.jsm");
-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();
validate_all_future_pings();
- Service.engineManager.register(RotaryEngine);
-
// 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();
@@ -139,18 +135,17 @@ async function syncAndExpectNodeReassign
}
add_task(async function test_momentary_401_engine() {
_("Test a failure for engine URLs that's resolved by reassignment.");
let server = await prepareServer();
let john = server.user("johndoe");
_("Enabling the Rotary engine.");
- let engine = Service.engineManager.get("rotary");
- engine.enabled = true;
+ let { engine, tracker } = registerRotaryEngine();
// 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);
@@ -182,16 +177,19 @@ add_task(async function test_momentary_4
Svc.Obs.add("weave:service:login:start", onLoginStart);
}
await syncAndExpectNodeReassignment(server,
"weave:service:sync:finish",
between,
"weave:service:sync:finish",
Service.storageURL + "rotary");
+
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
});
// This test ends up being a failing fetch *after we're already logged in*.
add_task(async function test_momentary_401_info_collections() {
_("Test a failure for info/collections that's resolved by reassignment.");
let server = await prepareServer();
_("First sync to prepare server contents.");
@@ -361,18 +359,17 @@ add_task(async function test_loop_avoida
add_task(async 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 = await prepareServer();
let john = server.user("johndoe");
_("Enabling the Rotary engine.");
- let engine = Service.engineManager.get("rotary");
- engine.enabled = true;
+ let { engine, tracker } = registerRotaryEngine();
let deferred = PromiseUtils.defer();
let getTokenCount = 0;
let mockTSC = { // TokenServerClient
getTokenFromBrowserIDAssertion(uri, assertion, cb) {
getTokenCount++;
cb(null, {
endpoint: server.baseURI + "1.1/johndoe/"
@@ -489,9 +486,12 @@ add_task(async function test_loop_avoida
});
}
Svc.Obs.add(firstNotification, onFirstSync);
now = Date.now();
Service.sync();
await deferred.promise;
+
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
});
--- a/services/sync/tests/unit/test_score_triggers.js
+++ b/services/sync/tests/unit/test_score_triggers.js
@@ -5,22 +5,16 @@ Cu.import("resource://services-sync/engi
Cu.import("resource://services-sync/engines/clients.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://testing-common/services/sync/utils.js");
-Service.engineManager.clear();
-Service.engineManager.register(RotaryEngine);
-var engine = Service.engineManager.get("rotary");
-var tracker = engine._tracker;
-engine.enabled = true;
-
// Tracking info/collections.
var collectionsHelper = track_collections_helper();
var upd = collectionsHelper.with_updated_collection;
function sync_httpd_setup() {
let handlers = {};
handlers["/1.1/johndoe/storage/meta/global"] =
@@ -39,28 +33,32 @@ function sync_httpd_setup() {
let cl = new ServerCollection();
handlers["/1.1/johndoe/storage/clients"] =
upd("clients", cl.handler());
return httpd_setup(handlers);
}
async function setUp(server) {
+ let engineInfo = registerRotaryEngine();
await SyncTestingInfrastructure(server, "johndoe", "ilovejane");
+ return engineInfo;
}
function run_test() {
initTestLogging("Trace");
Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
run_next_test();
}
add_test(function test_tracker_score_updated() {
+ let { engine, tracker } = registerRotaryEngine();
+
let scoreUpdated = 0;
function onScoreUpdated() {
scoreUpdated++;
}
Svc.Obs.add("weave:engine:score:updated", onScoreUpdated());
@@ -69,60 +67,68 @@ add_test(function test_tracker_score_upd
tracker.score += SCORE_INCREMENT_SMALL;
do_check_eq(engine.score, SCORE_INCREMENT_SMALL);
do_check_eq(scoreUpdated, 1);
} finally {
Svc.Obs.remove("weave:engine:score:updated", onScoreUpdated);
tracker.resetScore();
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
run_next_test();
}
});
add_task(async function test_sync_triggered() {
let server = sync_httpd_setup();
- await setUp(server);
+ let { engine, tracker } = await setUp(server);
Service.login();
Service.scheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
do_check_eq(Status.login, LOGIN_SUCCEEDED);
tracker.score += SCORE_INCREMENT_XLARGE;
- await promiseOneObserver("weave:service:sync:finish")
+ await promiseOneObserver("weave:service:sync:finish");
await promiseStopServer(server);
+
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
});
add_task(async function test_clients_engine_sync_triggered() {
_("Ensure that client engine score changes trigger a sync.");
// The clients engine is not registered like other engines. Therefore,
// it needs special treatment throughout the code. Here, we verify the
// global score tracker gives it that treatment. See bug 676042 for more.
let server = sync_httpd_setup();
- await setUp(server);
+ let { engine, tracker } = await setUp(server);
Service.login();
Service.scheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
do_check_eq(Status.login, LOGIN_SUCCEEDED);
Service.clientsEngine._tracker.score += SCORE_INCREMENT_XLARGE;
await promiseOneObserver("weave:service:sync:finish");
_("Sync due to clients engine change completed.");
await promiseStopServer(server);
+
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
});
add_task(async function test_incorrect_credentials_sync_not_triggered() {
_("Ensure that score changes don't trigger a sync if Status.login != LOGIN_SUCCEEDED.");
let server = sync_httpd_setup();
- await setUp(server);
+ let { engine, tracker } = await setUp(server);
// Ensure we don't actually try to sync.
function onSyncStart() {
do_throw("Should not get here!");
}
Svc.Obs.add("weave:service:sync:start", onSyncStart);
// Faking incorrect credentials to prevent score update.
@@ -136,9 +142,12 @@ add_task(async function test_incorrect_c
await promiseNextTick();
Svc.Obs.remove("weave:service:sync:start", onSyncStart);
do_check_eq(Status.login, LOGIN_FAILED_LOGIN_REJECTED);
Service.startOver();
await promiseStopServer(server);
+
+ tracker.clearChangedIDs();
+ Service.engineManager.unregister(engine);
});
--- a/services/sync/tests/unit/test_syncengine_sync.js
+++ b/services/sync/tests/unit/test_syncengine_sync.js
@@ -10,30 +10,31 @@ Cu.import("resource://services-sync/serv
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/rotaryengine.js");
Cu.import("resource://testing-common/services/sync/utils.js");
function makeRotaryEngine() {
return new RotaryEngine(Service);
}
-function clean(engine) {
+async function clean(engine) {
Svc.Prefs.resetBranch("");
Svc.Prefs.set("log.logger.engine.rotary", "Trace");
Service.recordManager.clearCache();
engine._tracker.clearChangedIDs();
+ await engine.finalize();
}
async function cleanAndGo(engine, server) {
- clean(engine);
+ await clean(engine);
await promiseStopServer(server);
}
async function promiseClean(engine, server) {
- clean(engine);
+ await clean(engine);
await promiseStopServer(server);
}
async function createServerAndConfigureClient() {
let engine = new RotaryEngine(Service);
let contents = {
meta: {global: {engines: {rotary: {version: engine.version,
--- a/services/sync/tests/unit/test_telemetry.js
+++ b/services/sync/tests/unit/test_telemetry.js
@@ -55,20 +55,20 @@ SteamEngine.prototype = {
function BogusEngine(service) {
Engine.call(this, "bogus", service);
}
BogusEngine.prototype = Object.create(SteamEngine.prototype);
async function cleanAndGo(engine, server) {
+ engine._tracker.clearChangedIDs();
Svc.Prefs.resetBranch("");
Svc.Prefs.set("log.logger.engine.rotary", "Trace");
Service.recordManager.clearCache();
- engine._tracker.clearChangedIDs();
await promiseStopServer(server);
}
// Avoid addon manager complaining about not being initialized
Service.engineManager.unregister("addons");
add_task(async function test_basic() {
let helper = track_collections_helper();
@@ -237,16 +237,17 @@ add_task(async function test_upload_fail
ping = await 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 {
await cleanAndGo(engine, server);
+ await engine.finalize();
}
});
add_task(async function test_sync_partialUpload() {
let collection = new ServerCollection();
let server = sync_httpd_setup({
"/1.1/foo/storage/rotary": collection.handler()
});
@@ -319,16 +320,17 @@ add_task(async function test_sync_partia
newFailed: 1,
reconciled: 232
});
ok(!ping.engines[0].outgoing);
deepEqual(ping.engines[0].failureReason, uploadFailureError);
} finally {
await cleanAndGo(engine, server);
+ await engine.finalize();
}
});
add_task(async function test_generic_engine_fail() {
Service.engineManager.register(SteamEngine);
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {