зеркало из https://github.com/mozilla/gecko-dev.git
Bug 978876 - Part 1: handle declined engines in desktop Sync meta/global. r=gps
* * * Bug 978876 - Part 2: refactor out meta/global upload.
This commit is contained in:
Родитель
e5a7647359
Коммит
9138511a11
|
@ -51,6 +51,7 @@ sync_engine_modules := \
|
|||
|
||||
sync_stage_modules := \
|
||||
cluster.js \
|
||||
declined.js \
|
||||
enginesync.js \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -445,9 +445,11 @@ this.EngineManager = function EngineManager(service) {
|
|||
this.service = service;
|
||||
|
||||
this._engines = {};
|
||||
|
||||
// This will be populated by Service on startup.
|
||||
this._declined = new Set();
|
||||
this._log = Log.repository.getLogger("Sync.EngineManager");
|
||||
this._log.level = Log.Level[Svc.Prefs.get(
|
||||
"log.logger.service.engines", "Debug")];
|
||||
this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.engines", "Debug")];
|
||||
}
|
||||
EngineManager.prototype = {
|
||||
get: function (name) {
|
||||
|
@ -477,10 +479,69 @@ EngineManager.prototype = {
|
|||
return [engine for ([name, engine] in Iterator(this._engines))];
|
||||
},
|
||||
|
||||
/**
|
||||
* N.B., does not pay attention to the declined list.
|
||||
*/
|
||||
getEnabled: function () {
|
||||
return this.getAll().filter(function(engine) engine.enabled);
|
||||
},
|
||||
|
||||
get enabledEngineNames() {
|
||||
return [e.name for each (e in this.getEnabled())];
|
||||
},
|
||||
|
||||
persistDeclined: function () {
|
||||
Svc.Prefs.set("declinedEngines", [...this._declined].join(","));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an array.
|
||||
*/
|
||||
getDeclined: function () {
|
||||
return [...this._declined];
|
||||
},
|
||||
|
||||
setDeclined: function (engines) {
|
||||
this._declined = new Set(engines);
|
||||
this.persistDeclined();
|
||||
},
|
||||
|
||||
isDeclined: function (engineName) {
|
||||
return this._declined.has(engineName);
|
||||
},
|
||||
|
||||
/**
|
||||
* Accepts a Set or an array.
|
||||
*/
|
||||
decline: function (engines) {
|
||||
for (let e of engines) {
|
||||
this._declined.add(e);
|
||||
}
|
||||
this.persistDeclined();
|
||||
},
|
||||
|
||||
undecline: function (engines) {
|
||||
for (let e of engines) {
|
||||
this._declined.delete(e);
|
||||
}
|
||||
this.persistDeclined();
|
||||
},
|
||||
|
||||
/**
|
||||
* Mark any non-enabled engines as declined.
|
||||
*
|
||||
* This is useful after initial customization during setup.
|
||||
*/
|
||||
declineDisabled: function () {
|
||||
for (let e of this.getAll()) {
|
||||
if (!e.enabled) {
|
||||
this._log.debug("Declining disabled engine " + e.name);
|
||||
this._declined.add(e.name);
|
||||
}
|
||||
}
|
||||
this.persistDeclined();
|
||||
},
|
||||
|
||||
/**
|
||||
* Register an Engine to the service. Alternatively, give an array of engine
|
||||
* objects to register.
|
||||
|
@ -638,16 +699,16 @@ SyncEngine.prototype = {
|
|||
__proto__: Engine.prototype,
|
||||
_recordObj: CryptoWrapper,
|
||||
version: 1,
|
||||
|
||||
|
||||
// How many records to pull in a single sync. This is primarily to avoid very
|
||||
// long first syncs against profiles with many history records.
|
||||
downloadLimit: null,
|
||||
|
||||
|
||||
// How many records to pull at one time when specifying IDs. This is to avoid
|
||||
// URI length limitations.
|
||||
guidFetchBatchSize: DEFAULT_GUID_FETCH_BATCH_SIZE,
|
||||
mobileGUIDFetchBatchSize: DEFAULT_MOBILE_GUID_FETCH_BATCH_SIZE,
|
||||
|
||||
|
||||
// How many records to process in a single batch.
|
||||
applyIncomingBatchSize: DEFAULT_STORE_BATCH_SIZE,
|
||||
|
||||
|
@ -863,7 +924,7 @@ SyncEngine.prototype = {
|
|||
newitems.newer = this.lastSync;
|
||||
newitems.full = true;
|
||||
newitems.limit = batchSize;
|
||||
|
||||
|
||||
// applied => number of items that should be applied.
|
||||
// failed => number of items that failed in this sync.
|
||||
// newFailed => number of items that failed for the first time in this sync.
|
||||
|
|
|
@ -553,5 +553,9 @@ IdentityManager.prototype = {
|
|||
createClusterManager: function(service) {
|
||||
Cu.import("resource://services-sync/stages/cluster.js");
|
||||
return new ClusterManager(service);
|
||||
}
|
||||
},
|
||||
|
||||
offerSyncOptions: function () {
|
||||
// TODO
|
||||
},
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@ Cu.import("resource://services-sync/record.js");
|
|||
Cu.import("resource://services-sync/resource.js");
|
||||
Cu.import("resource://services-sync/rest.js");
|
||||
Cu.import("resource://services-sync/stages/enginesync.js");
|
||||
Cu.import("resource://services-sync/stages/declined.js");
|
||||
Cu.import("resource://services-sync/status.js");
|
||||
Cu.import("resource://services-sync/userapi.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
|
@ -65,10 +66,6 @@ Sync11Service.prototype = {
|
|||
metaURL: null,
|
||||
cryptoKeyURL: null,
|
||||
|
||||
get enabledEngineNames() {
|
||||
return [e.name for each (e in this.engineManager.getEnabled())];
|
||||
},
|
||||
|
||||
get serverURL() Svc.Prefs.get("serverURL"),
|
||||
set serverURL(value) {
|
||||
if (!value.endsWith("/")) {
|
||||
|
@ -430,6 +427,12 @@ Sync11Service.prototype = {
|
|||
engines = pref.split(",");
|
||||
}
|
||||
|
||||
let declined = [];
|
||||
pref = Svc.Prefs.get("declinedEngines");
|
||||
if (pref) {
|
||||
declined = pref.split(",");
|
||||
}
|
||||
|
||||
this.clientsEngine = new ClientEngine(this);
|
||||
|
||||
for (let name of engines) {
|
||||
|
@ -448,12 +451,14 @@ Sync11Service.prototype = {
|
|||
continue;
|
||||
}
|
||||
|
||||
this.engineManager.register(ns[engineName], this);
|
||||
this.engineManager.register(ns[engineName]);
|
||||
} catch (ex) {
|
||||
this._log.warn("Could not register engine " + name + ": " +
|
||||
CommonUtils.exceptionStr(ex));
|
||||
}
|
||||
}
|
||||
|
||||
this.engineManager.setDeclined(declined);
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
|
@ -1062,6 +1067,7 @@ Sync11Service.prototype = {
|
|||
newMeta = new WBORecord("meta", "global");
|
||||
newMeta.payload.syncID = this.syncID;
|
||||
newMeta.payload.storageVersion = STORAGE_VERSION;
|
||||
newMeta.payload.declined = this.engineManager.getDeclined();
|
||||
|
||||
newMeta.isNew = true;
|
||||
|
||||
|
@ -1245,9 +1251,43 @@ Sync11Service.prototype = {
|
|||
// wait() throws if the first argument is truthy, which is exactly what
|
||||
// we want.
|
||||
let result = cb.wait();
|
||||
|
||||
// We successfully synchronized. Now let's update our declined engines.
|
||||
let meta = this.recordManager.get(this.metaURL);
|
||||
if (!meta) {
|
||||
this._log.warn("No meta/global; can't update declined state.");
|
||||
return;
|
||||
}
|
||||
|
||||
let declinedEngines = new DeclinedEngines(this);
|
||||
let didChange = declinedEngines.updateDeclined(meta, this.engineManager);
|
||||
if (!didChange) {
|
||||
this._log.info("No change to declined engines. Not reuploading meta/global.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.uploadMetaGlobal(meta);
|
||||
}))();
|
||||
},
|
||||
|
||||
/**
|
||||
* Upload meta/global, throwing the response on failure.
|
||||
*/
|
||||
uploadMetaGlobal: function (meta) {
|
||||
this._log.debug("Uploading meta/global: " + JSON.stringify(meta));
|
||||
|
||||
// It would be good to set the X-If-Unmodified-Since header to `timestamp`
|
||||
// for this PUT to ensure at least some level of transactionality.
|
||||
// Unfortunately, the servers don't support it after a wipe right now
|
||||
// (bug 693893), so we're going to defer this until bug 692700.
|
||||
let res = this.resource(this.metaURL);
|
||||
let response = res.put(meta);
|
||||
if (!response.success) {
|
||||
throw response;
|
||||
}
|
||||
this.recordManager.set(this.metaURL, meta);
|
||||
},
|
||||
|
||||
/**
|
||||
* If we have a passphrase, rather than a 25-alphadigit sync key,
|
||||
* use the provided sync ID to bootstrap it using PBKDF2.
|
||||
|
@ -1303,26 +1343,19 @@ Sync11Service.prototype = {
|
|||
let meta = new WBORecord("meta", "global");
|
||||
meta.payload.syncID = this.syncID;
|
||||
meta.payload.storageVersion = STORAGE_VERSION;
|
||||
meta.payload.declined = this.engineManager.getDeclined();
|
||||
meta.isNew = true;
|
||||
|
||||
this._log.debug("New metadata record: " + JSON.stringify(meta.payload));
|
||||
let res = this.resource(this.metaURL);
|
||||
// It would be good to set the X-If-Unmodified-Since header to `timestamp`
|
||||
// for this PUT to ensure at least some level of transactionality.
|
||||
// Unfortunately, the servers don't support it after a wipe right now
|
||||
// (bug 693893), so we're going to defer this until bug 692700.
|
||||
let resp = res.put(meta);
|
||||
if (!resp.success) {
|
||||
// If we got into a race condition, we'll abort the sync this way, too.
|
||||
// That's fine. We'll just wait till the next sync. The client that we're
|
||||
// racing is probably busy uploading stuff right now anyway.
|
||||
throw resp;
|
||||
}
|
||||
this.recordManager.set(this.metaURL, meta);
|
||||
// uploadMetaGlobal throws on failure -- including race conditions.
|
||||
// If we got into a race condition, we'll abort the sync this way, too.
|
||||
// That's fine. We'll just wait till the next sync. The client that we're
|
||||
// racing is probably busy uploading stuff right now anyway.
|
||||
this.uploadMetaGlobal(meta);
|
||||
|
||||
// Wipe everything we know about except meta because we just uploaded it
|
||||
let engines = [this.clientsEngine].concat(this.engineManager.getAll());
|
||||
let collections = [engine.name for each (engine in engines)];
|
||||
// TODO: there's a bug here. We should be calling resetClient, no?
|
||||
|
||||
// Generate, upload, and download new keys. Do this last so we don't wipe
|
||||
// them...
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ClusterManager"];
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This file contains code for maintaining the set of declined engines,
|
||||
* in conjunction with EngineManager.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DeclinedEngines"];
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://services-common/observers.js");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
|
||||
|
||||
this.DeclinedEngines = function (service) {
|
||||
this._log = Log.repository.getLogger("Sync.Declined");
|
||||
this._log.level = Log.Level[new Preferences(PREFS_BRANCH).get("log.logger.declined")];
|
||||
|
||||
this.service = service;
|
||||
}
|
||||
this.DeclinedEngines.prototype = {
|
||||
updateDeclined: function (meta, engineManager=this.service.engineManager) {
|
||||
let enabled = new Set([e.name for each (e in engineManager.getEnabled())]);
|
||||
let known = new Set([e.name for each (e in engineManager.getAll())]);
|
||||
let remoteDeclined = new Set(meta.payload.declined || []);
|
||||
let localDeclined = new Set(engineManager.getDeclined());
|
||||
|
||||
this._log.debug("Handling remote declined: " + JSON.stringify([...remoteDeclined]));
|
||||
this._log.debug("Handling local declined: " + JSON.stringify([...localDeclined]));
|
||||
|
||||
// Any engines that are locally enabled should be removed from the remote
|
||||
// declined list.
|
||||
//
|
||||
// Any engines that are locally declined should be added to the remote
|
||||
// declined list.
|
||||
let newDeclined = CommonUtils.union(localDeclined, CommonUtils.difference(remoteDeclined, enabled));
|
||||
|
||||
// If our declined set has changed, put it into the meta object and mark
|
||||
// it as changed.
|
||||
let declinedChanged = !CommonUtils.setEqual(newDeclined, remoteDeclined);
|
||||
this._log.debug("Declined changed? " + declinedChanged);
|
||||
if (declinedChanged) {
|
||||
meta.changed = true;
|
||||
meta.payload.declined = [...newDeclined];
|
||||
}
|
||||
|
||||
// Update the engine manager regardless.
|
||||
engineManager.setDeclined(newDeclined);
|
||||
|
||||
// Any engines that are locally known, locally disabled, and not remotely
|
||||
// or locally declined, are candidates for enablement.
|
||||
let undecided = CommonUtils.difference(CommonUtils.difference(known, enabled), newDeclined);
|
||||
if (undecided.size) {
|
||||
let subject = {
|
||||
declined: newDeclined,
|
||||
enabled: enabled,
|
||||
known: known,
|
||||
undecided: undecided,
|
||||
};
|
||||
CommonUtils.nextTick(() => {
|
||||
Observers.notify("weave:engines:notdeclined", subject);
|
||||
});
|
||||
}
|
||||
|
||||
return declinedChanged;
|
||||
},
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This file contains code for synchronizing engines.
|
||||
|
@ -71,11 +71,13 @@ EngineSynchronizer.prototype = {
|
|||
Svc.Prefs.set("lastPing", now);
|
||||
}
|
||||
|
||||
let engineManager = this.service.engineManager;
|
||||
|
||||
// Figure out what the last modified time is for each collection
|
||||
let info = this.service._fetchInfo(infoURL);
|
||||
|
||||
// Convert the response to an object and read out the modified times
|
||||
for (let engine of [this.service.clientsEngine].concat(this.service.engineManager.getAll())) {
|
||||
for (let engine of [this.service.clientsEngine].concat(engineManager.getAll())) {
|
||||
engine.lastModified = info.obj[engine.name] || 0;
|
||||
}
|
||||
|
||||
|
@ -97,13 +99,13 @@ EngineSynchronizer.prototype = {
|
|||
// Wipe data in the desired direction if necessary
|
||||
switch (Svc.Prefs.get("firstSync")) {
|
||||
case "resetClient":
|
||||
this.service.resetClient(this.service.enabledEngineNames);
|
||||
this.service.resetClient(engineManager.enabledEngineNames);
|
||||
break;
|
||||
case "wipeClient":
|
||||
this.service.wipeClient(this.service.enabledEngineNames);
|
||||
this.service.wipeClient(engineManager.enabledEngineNames);
|
||||
break;
|
||||
case "wipeRemote":
|
||||
this.service.wipeRemote(this.service.enabledEngineNames);
|
||||
this.service.wipeRemote(engineManager.enabledEngineNames);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -142,7 +144,7 @@ EngineSynchronizer.prototype = {
|
|||
}
|
||||
|
||||
try {
|
||||
for each (let engine in this.service.engineManager.getEnabled()) {
|
||||
for (let engine of engineManager.getEnabled()) {
|
||||
// If there's any problems with syncing the engine, report the failure
|
||||
if (!(this._syncEngine(engine)) || this.service.status.enforceBackoff) {
|
||||
this._log.info("Aborting sync for failure in " + engine.name);
|
||||
|
@ -160,12 +162,17 @@ EngineSynchronizer.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// Upload meta/global if any engines changed anything
|
||||
// Upload meta/global if any engines changed anything.
|
||||
let meta = this.service.recordManager.get(this.service.metaURL);
|
||||
if (meta.isNew || meta.changed) {
|
||||
this.service.resource(this.service.metaURL).put(meta);
|
||||
delete meta.isNew;
|
||||
delete meta.changed;
|
||||
this._log.info("meta/global changed locally: reuploading.");
|
||||
try {
|
||||
this.service.uploadMetaGlobal(meta);
|
||||
delete meta.isNew;
|
||||
delete meta.changed;
|
||||
} catch (error) {
|
||||
this._log.error("Unable to upload meta/global. Leaving marked as new.");
|
||||
}
|
||||
}
|
||||
|
||||
// If there were no sync engine failures
|
||||
|
@ -205,17 +212,19 @@ EngineSynchronizer.prototype = {
|
|||
return true;
|
||||
},
|
||||
|
||||
_updateEnabledEngines: function _updateEnabledEngines() {
|
||||
_updateEnabledFromMeta: function (meta, numClients, engineManager=this.service.engineManager) {
|
||||
this._log.info("Updating enabled engines: " +
|
||||
this.service.scheduler.numClients + " clients.");
|
||||
let meta = this.service.recordManager.get(this.service.metaURL);
|
||||
if (meta.isNew || !meta.payload.engines)
|
||||
numClients + " clients.");
|
||||
|
||||
if (meta.isNew || !meta.payload.engines) {
|
||||
this._log.debug("meta/global isn't new, or is missing engines. Not updating enabled state.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're the only client, and no engines are marked as enabled,
|
||||
// thumb our noses at the server data: it can't be right.
|
||||
// Belt-and-suspenders approach to Bug 615926.
|
||||
if ((this.service.scheduler.numClients <= 1) &&
|
||||
if ((numClients <= 1) &&
|
||||
([e for (e in meta.payload.engines) if (e != "clients")].length == 0)) {
|
||||
this._log.info("One client and no enabled engines: not touching local engine status.");
|
||||
return;
|
||||
|
@ -223,7 +232,11 @@ EngineSynchronizer.prototype = {
|
|||
|
||||
this.service._ignorePrefObserver = true;
|
||||
|
||||
let enabled = this.service.enabledEngineNames;
|
||||
let enabled = engineManager.enabledEngineNames;
|
||||
|
||||
let toDecline = new Set();
|
||||
let toUndecline = new Set();
|
||||
|
||||
for (let engineName in meta.payload.engines) {
|
||||
if (engineName == "clients") {
|
||||
// Clients is special.
|
||||
|
@ -235,7 +248,7 @@ EngineSynchronizer.prototype = {
|
|||
enabled.splice(index, 1);
|
||||
continue;
|
||||
}
|
||||
let engine = this.service.engineManager.get(engineName);
|
||||
let engine = engineManager.get(engineName);
|
||||
if (!engine) {
|
||||
// The engine doesn't exist locally. Nothing to do.
|
||||
continue;
|
||||
|
@ -247,9 +260,17 @@ EngineSynchronizer.prototype = {
|
|||
this._log.trace("Wiping data for " + engineName + " engine.");
|
||||
engine.wipeServer();
|
||||
delete meta.payload.engines[engineName];
|
||||
meta.changed = true;
|
||||
meta.changed = true; // TODO: Should we still do this?
|
||||
|
||||
// We also here mark the engine as declined, because the pref
|
||||
// was explicitly changed to false.
|
||||
// This will be reflected in meta/global in the next stage.
|
||||
this._log.trace("Engine " + engineName + " was disabled locally. Marking as declined.");
|
||||
toDecline.add(engineName);
|
||||
} else {
|
||||
// The engine was enabled remotely. Enable it locally.
|
||||
this._log.trace("Engine " + engineName + " was enabled. Marking as non-declined.");
|
||||
toUndecline.add(engineName);
|
||||
this._log.trace(engineName + " engine was enabled remotely.");
|
||||
engine.enabled = true;
|
||||
}
|
||||
|
@ -257,18 +278,31 @@ EngineSynchronizer.prototype = {
|
|||
|
||||
// Any remaining engines were either enabled locally or disabled remotely.
|
||||
for each (let engineName in enabled) {
|
||||
let engine = this.service.engineManager.get(engineName);
|
||||
let engine = engineManager.get(engineName);
|
||||
if (Svc.Prefs.get("engineStatusChanged." + engine.prefName, false)) {
|
||||
this._log.trace("The " + engineName + " engine was enabled locally.");
|
||||
toUndecline.add(engineName);
|
||||
} else {
|
||||
this._log.trace("The " + engineName + " engine was disabled remotely.");
|
||||
|
||||
// Don't automatically mark it as declined!
|
||||
engine.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.service.engineManager.decline(toDecline);
|
||||
this.service.engineManager.undecline(toUndecline);
|
||||
|
||||
Svc.Prefs.resetBranch("engineStatusChanged.");
|
||||
this.service._ignorePrefObserver = false;
|
||||
},
|
||||
|
||||
_updateEnabledEngines: function () {
|
||||
let meta = this.service.recordManager.get(this.service.metaURL);
|
||||
let numClients = this.service.scheduler.numClients;
|
||||
let engineManager = this.service.engineManager;
|
||||
|
||||
this._updateEnabledFromMeta(meta, numClients, engineManager);
|
||||
},
|
||||
};
|
||||
Object.freeze(EngineSynchronizer.prototype);
|
||||
|
|
|
@ -57,6 +57,7 @@ pref("services.sync.log.appender.file.logOnSuccess", false);
|
|||
pref("services.sync.log.appender.file.maxErrorAge", 864000); // 10 days
|
||||
pref("services.sync.log.rootLogger", "Debug");
|
||||
pref("services.sync.log.logger.addonutils", "Debug");
|
||||
pref("services.sync.log.logger.declined", "Debug");
|
||||
pref("services.sync.log.logger.service.main", "Debug");
|
||||
pref("services.sync.log.logger.status", "Debug");
|
||||
pref("services.sync.log.logger.authenticator", "Debug");
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://services-sync/stages/declined.js");
|
||||
Cu.import("resource://services-sync/stages/enginesync.js");
|
||||
Cu.import("resource://services-sync/engines.js");
|
||||
Cu.import("resource://services-sync/service.js");
|
||||
Cu.import("resource://services-common/observers.js");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function PetrolEngine() {}
|
||||
PetrolEngine.prototype.name = "petrol";
|
||||
|
||||
function DieselEngine() {}
|
||||
DieselEngine.prototype.name = "diesel";
|
||||
|
||||
function DummyEngine() {}
|
||||
DummyEngine.prototype.name = "dummy";
|
||||
|
||||
function ActualEngine() {}
|
||||
ActualEngine.prototype = {__proto__: Engine.prototype,
|
||||
name: 'actual'};
|
||||
|
||||
function getEngineManager() {
|
||||
let manager = new EngineManager(Service);
|
||||
Service.engineManager = manager;
|
||||
manager._engines = {
|
||||
"petrol": new PetrolEngine(),
|
||||
"diesel": new DieselEngine(),
|
||||
"dummy": new DummyEngine(),
|
||||
"actual": new ActualEngine(),
|
||||
};
|
||||
return manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'Fetch' a meta/global record that doesn't mention declined.
|
||||
*
|
||||
* Push it into the EngineSynchronizer to set enabled; verify that those are
|
||||
* correct.
|
||||
*
|
||||
* Then push it into DeclinedEngines to set declined; verify that none are
|
||||
* declined, and a notification is sent for our locally disabled-but-not-
|
||||
* declined engines.
|
||||
*/
|
||||
add_test(function testOldMeta() {
|
||||
let meta = {
|
||||
payload: {
|
||||
engines: {
|
||||
"petrol": 1,
|
||||
"diesel": 2,
|
||||
"nonlocal": 3, // Enabled but not supported.
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
_("Record: " + JSON.stringify(meta));
|
||||
|
||||
let manager = getEngineManager();
|
||||
|
||||
// Update enabled from meta/global.
|
||||
let engineSync = new EngineSynchronizer(Service);
|
||||
engineSync._updateEnabledFromMeta(meta, 3, manager);
|
||||
|
||||
Assert.ok(manager._engines["petrol"].enabled, "'petrol' locally enabled.");
|
||||
Assert.ok(manager._engines["diesel"].enabled, "'diesel' locally enabled.");
|
||||
Assert.ok(!("nonlocal" in manager._engines), "We don't know anything about the 'nonlocal' engine.");
|
||||
Assert.ok(!manager._engines["actual"].enabled, "'actual' not locally enabled.");
|
||||
Assert.ok(!manager.isDeclined("actual"), "'actual' not declined, though.");
|
||||
|
||||
let declinedEngines = new DeclinedEngines(Service);
|
||||
|
||||
function onNotDeclined(subject, topic, data) {
|
||||
Observers.remove("weave:engines:notdeclined", onNotDeclined);
|
||||
Assert.ok(subject.undecided.has("actual"), "EngineManager observed that 'actual' was undecided.");
|
||||
|
||||
let declined = manager.getDeclined();
|
||||
_("Declined: " + JSON.stringify(declined));
|
||||
|
||||
Assert.ok(!meta.changed, "No need to upload a new meta/global.");
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
Observers.add("weave:engines:notdeclined", onNotDeclined);
|
||||
|
||||
declinedEngines.updateDeclined(meta, manager);
|
||||
});
|
||||
|
||||
/**
|
||||
* 'Fetch' a meta/global that declines an engine we don't
|
||||
* recognize. Ensure that we track that declined engine along
|
||||
* with any we locally declined, and that the meta/global
|
||||
* record is marked as changed and includes all declined
|
||||
* engines.
|
||||
*/
|
||||
add_test(function testDeclinedMeta() {
|
||||
let meta = {
|
||||
payload: {
|
||||
engines: {
|
||||
"petrol": 1,
|
||||
"diesel": 2,
|
||||
"nonlocal": 3, // Enabled but not supported.
|
||||
},
|
||||
declined: ["nonexistent"], // Declined and not supported.
|
||||
},
|
||||
};
|
||||
|
||||
_("Record: " + JSON.stringify(meta));
|
||||
|
||||
let manager = getEngineManager();
|
||||
manager._engines["petrol"].enabled = true;
|
||||
manager._engines["diesel"].enabled = true;
|
||||
manager._engines["dummy"].enabled = true;
|
||||
manager._engines["actual"].enabled = false; // Disabled but not declined.
|
||||
|
||||
manager.decline(["localdecline"]); // Declined and not supported.
|
||||
|
||||
let declinedEngines = new DeclinedEngines(Service);
|
||||
|
||||
function onNotDeclined(subject, topic, data) {
|
||||
Observers.remove("weave:engines:notdeclined", onNotDeclined);
|
||||
Assert.ok(subject.undecided.has("actual"), "EngineManager observed that 'actual' was undecided.");
|
||||
|
||||
let declined = manager.getDeclined();
|
||||
_("Declined: " + JSON.stringify(declined));
|
||||
|
||||
Assert.equal(declined.indexOf("actual"), -1, "'actual' is locally disabled, but not marked as declined.");
|
||||
|
||||
Assert.equal(declined.indexOf("clients"), -1, "'clients' is enabled and not remotely declined.");
|
||||
Assert.equal(declined.indexOf("petrol"), -1, "'petrol' is enabled and not remotely declined.");
|
||||
Assert.equal(declined.indexOf("diesel"), -1, "'diesel' is enabled and not remotely declined.");
|
||||
Assert.equal(declined.indexOf("dummy"), -1, "'dummy' is enabled and not remotely declined.");
|
||||
|
||||
Assert.ok(0 <= declined.indexOf("nonexistent"), "'nonexistent' was declined on the server.");
|
||||
|
||||
Assert.ok(0 <= declined.indexOf("localdecline"), "'localdecline' was declined locally.");
|
||||
|
||||
// The meta/global is modified, too.
|
||||
Assert.ok(0 <= meta.payload.declined.indexOf("nonexistent"), "meta/global's declined contains 'nonexistent'.");
|
||||
Assert.ok(0 <= meta.payload.declined.indexOf("localdecline"), "meta/global's declined contains 'localdecline'.");
|
||||
Assert.strictEqual(true, meta.changed, "meta/global was changed.");
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
Observers.add("weave:engines:notdeclined", onNotDeclined);
|
||||
|
||||
declinedEngines.updateDeclined(meta, manager);
|
||||
});
|
||||
|
|
@ -5,6 +5,23 @@ Cu.import("resource://services-sync/engines.js");
|
|||
Cu.import("resource://services-sync/service.js");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function PetrolEngine() {}
|
||||
PetrolEngine.prototype.name = "petrol";
|
||||
|
||||
function DieselEngine() {}
|
||||
DieselEngine.prototype.name = "diesel";
|
||||
|
||||
function DummyEngine() {}
|
||||
DummyEngine.prototype.name = "dummy";
|
||||
|
||||
function ActualEngine() {}
|
||||
ActualEngine.prototype = {__proto__: Engine.prototype,
|
||||
name: 'actual'};
|
||||
|
||||
add_test(function test_basics() {
|
||||
_("We start out with a clean slate");
|
||||
|
||||
let manager = new EngineManager(Service);
|
||||
|
@ -14,8 +31,6 @@ function run_test() {
|
|||
do_check_eq(manager.get('dummy'), undefined);
|
||||
|
||||
_("Register an engine");
|
||||
function DummyEngine() {}
|
||||
DummyEngine.prototype.name = "dummy";
|
||||
manager.register(DummyEngine);
|
||||
let dummy = manager.get('dummy');
|
||||
do_check_true(dummy instanceof DummyEngine);
|
||||
|
@ -29,11 +44,6 @@ function run_test() {
|
|||
do_check_eq(manager.get('dummy'), dummy);
|
||||
|
||||
_("Register multiple engines in one go");
|
||||
function PetrolEngine() {}
|
||||
PetrolEngine.prototype.name = "petrol";
|
||||
function DieselEngine() {}
|
||||
DieselEngine.prototype.name = "diesel";
|
||||
|
||||
manager.register([PetrolEngine, DieselEngine]);
|
||||
let petrol = manager.get('petrol');
|
||||
let diesel = manager.get('diesel');
|
||||
|
@ -74,9 +84,6 @@ function run_test() {
|
|||
|
||||
_("Unregister an engine by value");
|
||||
// manager.unregister() checks for instanceof Engine, so let's make one:
|
||||
function ActualEngine() {}
|
||||
ActualEngine.prototype = {__proto__: Engine.prototype,
|
||||
name: 'actual'};
|
||||
manager.register(ActualEngine);
|
||||
let actual = manager.get('actual');
|
||||
do_check_true(actual instanceof ActualEngine);
|
||||
|
@ -84,4 +91,7 @@ function run_test() {
|
|||
|
||||
manager.unregister(actual);
|
||||
do_check_eq(manager.get('actual'), undefined);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ const modules = [
|
|||
"rest.js",
|
||||
"service.js",
|
||||
"stages/cluster.js",
|
||||
"stages/declined.js",
|
||||
"stages/enginesync.js",
|
||||
"status.js",
|
||||
"userapi.js",
|
||||
|
|
|
@ -102,6 +102,7 @@ skip-if = os == "android"
|
|||
skip-if = os == "mac" || os == "linux"
|
||||
|
||||
[test_corrupt_keys.js]
|
||||
[test_declined.js]
|
||||
[test_errorhandler.js]
|
||||
[test_errorhandler_filelog.js]
|
||||
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
|
||||
|
|
Загрузка…
Ссылка в новой задаче