--- a/browser/extensions/formautofill/FormAutofillSync.jsm
+++ b/browser/extensions/formautofill/FormAutofillSync.jsm
@@ -179,18 +179,17 @@ FormAutofillStore.prototype = {
};
function FormAutofillTracker(name, engine) {
Tracker.call(this, name, engine);
}
FormAutofillTracker.prototype = {
__proto__: Tracker.prototype,
- observe: function observe(subject, topic, data) {
- Tracker.prototype.observe.call(this, subject, topic, data);
+ async observe(subject, topic, data) {
if (topic != "formautofill-storage-changed") {
return;
}
if (subject && subject.wrappedJSObject && subject.wrappedJSObject.sourceSync) {
return;
}
switch (data) {
case "add":
@@ -209,21 +208,21 @@ FormAutofillTracker.prototype = {
get ignoreAll() {
return false;
},
// Define an empty setter so that the engine doesn't throw a `TypeError`
// setting a read-only property.
set ignoreAll(value) {},
- startTracking() {
+ onStart() {
Services.obs.addObserver(this, "formautofill-storage-changed");
},
- stopTracking() {
+ onStop() {
Services.obs.removeObserver(this, "formautofill-storage-changed");
},
// We never want to persist changed IDs, as the changes are already stored
// in FormAutofillStorage
persistChangedIDs: false,
// Ensure we aren't accidentally using the base persistence.
--- a/browser/extensions/formautofill/test/unit/test_sync.js
+++ b/browser/extensions/formautofill/test/unit/test_sync.js
@@ -137,16 +137,17 @@ add_task(async function test_outgoing()
guid: existingGUID,
},
{
guid: deletedGUID,
deleted: true,
},
]);
+ await engine._tracker.asyncObserver.promiseObserversComplete();
// The tracker should have a score recorded for the 2 additions we had.
equal(engine._tracker.score, SCORE_INCREMENT_XLARGE * 2);
engine.lastSync = 0;
await engine.sync();
Assert.equal(collection.count(), 2);
Assert.ok(collection.wbo(existingGUID));
--- a/services/sync/modules/addonsreconciler.js
+++ b/services/sync/modules/addonsreconciler.js
@@ -52,17 +52,17 @@ this.EXPORTED_SYMBOLS = ["AddonsReconcil
* The internal state is persisted to a JSON file in the profile directory.
*
* An instance of this is bound to an AddonsEngine instance. In reality, it
* likely exists as a singleton. To AddonsEngine, it functions as a store and
* an entity which emits events for tracking.
*
* The usage pattern for instances of this class is:
*
- * let reconciler = new AddonsReconciler();
+ * let reconciler = new AddonsReconciler(...);
* await reconciler.ensureStateLoaded();
*
* // At this point, your instance should be ready to use.
*
* When you are finished with the instance, please call:
*
* reconciler.stopListening();
* await reconciler.saveState(...);
@@ -108,19 +108,20 @@ this.EXPORTED_SYMBOLS = ["AddonsReconcil
* Restartless add-ons have interesting behavior during uninstall. These
* add-ons are first disabled then they are actually uninstalled. So, we will
* see AL.onDisabling and AL.onDisabled. The onUninstalling and onUninstalled
* events only come after the Addon Manager is closed or another view is
* switched to. In the case of Sync performing the uninstall, the uninstall
* events will occur immediately. However, we still see disabling events and
* heed them like they were normal. In the end, the state is proper.
*/
-this.AddonsReconciler = function AddonsReconciler() {
+this.AddonsReconciler = function AddonsReconciler(queueCaller) {
this._log = Log.repository.getLogger("Sync.AddonsReconciler");
this._log.manageLevelFromPref("services.sync.log.logger.addonsreconciler");
+ this.queueCaller = queueCaller;
Svc.Obs.add("xpcom-shutdown", this.stopListening, this);
};
AddonsReconciler.prototype = {
/** Flag indicating whether we are listening to AddonManager events. */
_listening: false,
/**
@@ -580,40 +581,40 @@ AddonsReconciler.prototype = {
}
} catch (ex) {
this._log.warn("Exception", ex);
}
},
// AddonListeners
onEnabling: function onEnabling(addon, requiresRestart) {
- Async.promiseSpinningly(this._handleListener("onEnabling", addon, requiresRestart));
+ this.queueCaller.enqueueCall(() => this._handleListener("onEnabling", addon, requiresRestart));
},
onEnabled: function onEnabled(addon) {
- Async.promiseSpinningly(this._handleListener("onEnabled", addon));
+ this.queueCaller.enqueueCall(() => this._handleListener("onEnabled", addon));
},
onDisabling: function onDisabling(addon, requiresRestart) {
- Async.promiseSpinningly(this._handleListener("onDisabling", addon, requiresRestart));
+ this.queueCaller.enqueueCall(() => this._handleListener("onDisabling", addon, requiresRestart));
},
onDisabled: function onDisabled(addon) {
- Async.promiseSpinningly(this._handleListener("onDisabled", addon));
+ this.queueCaller.enqueueCall(() => this._handleListener("onDisabled", addon));
},
onInstalling: function onInstalling(addon, requiresRestart) {
- Async.promiseSpinningly(this._handleListener("onInstalling", addon, requiresRestart));
+ this.queueCaller.enqueueCall(() => this._handleListener("onInstalling", addon, requiresRestart));
},
onInstalled: function onInstalled(addon) {
- Async.promiseSpinningly(this._handleListener("onInstalled", addon));
+ this.queueCaller.enqueueCall(() => this._handleListener("onInstalled", addon));
},
onUninstalling: function onUninstalling(addon, requiresRestart) {
- Async.promiseSpinningly(this._handleListener("onUninstalling", addon, requiresRestart));
+ this.queueCaller.enqueueCall(() => this._handleListener("onUninstalling", addon, requiresRestart));
},
onUninstalled: function onUninstalled(addon) {
- Async.promiseSpinningly(this._handleListener("onUninstalled", addon));
+ this.queueCaller.enqueueCall(() => this._handleListener("onUninstalled", addon));
},
onOperationCancelled: function onOperationCancelled(addon) {
- Async.promiseSpinningly(this._handleListener("onOperationCancelled", addon));
+ this.queueCaller.enqueueCall(() => this._handleListener("onOperationCancelled", addon));
},
// InstallListeners
onInstallEnded: function onInstallEnded(install, addon) {
- Async.promiseSpinningly(this._handleListener("onInstallEnded", addon));
+ this.queueCaller.enqueueCall(() => this._handleListener("onInstallEnded", addon));
}
};
--- a/services/sync/modules/bookmark_repair.js
+++ b/services/sync/modules/bookmark_repair.js
@@ -698,17 +698,17 @@ class BookmarkRepairResponder extends Co
if (data != "bookmarks") {
return;
}
Svc.Obs.remove("weave:engine:sync:uploaded", this.onUploaded, this);
if (subject.failed) {
return;
}
log.debug(`bookmarks engine has uploaded stuff - creating a repair response`, subject);
- Async.promiseSpinningly(this._finishRepair());
+ this.service.clientsEngine._tracker.asyncObserver.enqueueCall(() => this._finishRepair());
}
async _finishRepair() {
let clientsEngine = this.service.clientsEngine;
let flowID = this._currentState.request.flowID;
let response = {
request: this._currentState.request.request,
collection: "bookmarks",
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -61,19 +61,17 @@ this.Tracker = function Tracker(name, en
this._ignored = [];
this._storage = new JSONFile({
path: Utils.jsonFilePath("changes/" + this.file),
dataPostProcessor: json => this._dataPostProcessor(json),
beforeSave: () => this._beforeSave(),
});
this.ignoreAll = false;
- Svc.Obs.add("weave:engine:start-tracking", this);
- Svc.Obs.add("weave:engine:stop-tracking", this);
-
+ this.asyncObserver = Async.asyncObserver(this, this._log);
};
Tracker.prototype = {
/*
* Score can be called as often as desired to decide which engines to sync
*
* Valid values for score:
* -1: Do not sync unless the user specifically requests it (almost disabled)
@@ -91,33 +89,33 @@ Tracker.prototype = {
return typeof json == "object" && json || {};
},
// Ensure the Weave storage directory exists before writing the file.
_beforeSave() {
return ensureDirectory(this._storage.path);
},
- get changedIDs() {
- Async.promiseSpinningly(this._storage.load());
- return this._storage.data;
- },
-
set score(value) {
this._score = value;
Observers.notify("weave:engine:score:updated", this.name);
},
// Should be called by service everytime a sync has been done for an engine
resetScore() {
this._score = 0;
},
persistChangedIDs: true,
+ async getChangedIDs() {
+ await this._storage.load();
+ return this._storage.data;
+ },
+
_saveChangedIDs() {
if (!this.persistChangedIDs) {
this._log.debug("Not saving changedIDs.");
return;
}
this._storage.saveSoon();
},
@@ -131,136 +129,129 @@ Tracker.prototype = {
},
unignoreID(id) {
let index = this._ignored.indexOf(id);
if (index != -1)
this._ignored.splice(index, 1);
},
- _saveChangedID(id, when) {
+ async _saveChangedID(id, when) {
this._log.trace(`Adding changed ID: ${id}, ${JSON.stringify(when)}`);
- this.changedIDs[id] = when;
+ const changedIDs = await this.getChangedIDs();
+ changedIDs[id] = when;
this._saveChangedIDs();
},
- addChangedID(id, when) {
+ async addChangedID(id, when) {
if (!id) {
this._log.warn("Attempted to add undefined ID to tracker");
return false;
}
if (this.ignoreAll || this._ignored.includes(id)) {
return false;
}
// Default to the current time in seconds if no time is provided.
if (when == null) {
when = this._now();
}
+ const changedIDs = await this.getChangedIDs();
// Add/update the entry if we have a newer time.
- if ((this.changedIDs[id] || -Infinity) < when) {
- this._saveChangedID(id, when);
+ if ((changedIDs[id] || -Infinity) < when) {
+ await this._saveChangedID(id, when);
}
return true;
},
- removeChangedID(...ids) {
+ async removeChangedID(...ids) {
if (!ids.length || this.ignoreAll) {
return false;
}
for (let id of ids) {
if (!id) {
this._log.warn("Attempted to remove undefined ID from tracker");
continue;
}
if (this._ignored.includes(id)) {
this._log.debug(`Not removing ignored ID ${id} from tracker`);
continue;
}
- if (this.changedIDs[id] != null) {
+ const changedIDs = await this.getChangedIDs();
+ if (changedIDs[id] != null) {
this._log.trace("Removing changed ID " + id);
- delete this.changedIDs[id];
+ delete changedIDs[id];
}
}
- this._saveChangedIDs();
+ await this._saveChangedIDs();
return true;
},
- clearChangedIDs() {
+ async clearChangedIDs() {
this._log.trace("Clearing changed ID list");
this._storage.data = {};
- this._saveChangedIDs();
+ await this._saveChangedIDs();
},
_now() {
return Date.now() / 1000;
},
_isTracking: false,
- // Override these in your subclasses.
- startTracking() {
+ start() {
+ if (!this.engineIsEnabled()) {
+ return;
+ }
+ this._log.trace("start().");
+ if (!this._isTracking) {
+ this.onStart();
+ this._isTracking = true;
+ }
},
- stopTracking() {
+ async stop() {
+ this._log.trace("stop().");
+ if (this._isTracking) {
+ await this.asyncObserver.promiseObserversComplete();
+ this.onStop();
+ this._isTracking = false;
+ }
},
+ // Override these in your subclasses.
+ onStart() {},
+ onStop() {},
+ async observe(subject, topic, data) {},
+
engineIsEnabled() {
if (!this.engine) {
// Can't tell -- we must be running in a test!
return true;
}
return this.engine.enabled;
},
- onEngineEnabledChanged(engineEnabled) {
+ async onEngineEnabledChanged(engineEnabled) {
if (engineEnabled == this._isTracking) {
return;
}
if (engineEnabled) {
- this.startTracking();
- this._isTracking = true;
+ this.start();
} else {
- this.stopTracking();
- this._isTracking = false;
- this.clearChangedIDs();
- }
- },
-
- observe(subject, topic, data) {
- switch (topic) {
- case "weave:engine:start-tracking":
- if (!this.engineIsEnabled()) {
- return;
- }
- this._log.trace("Got start-tracking.");
- if (!this._isTracking) {
- this.startTracking();
- this._isTracking = true;
- }
- return;
- case "weave:engine:stop-tracking":
- this._log.trace("Got stop-tracking.");
- if (this._isTracking) {
- this.stopTracking();
- this._isTracking = false;
- }
+ await this.stop();
+ await this.clearChangedIDs();
}
},
async finalize() {
- // Stop listening for tracking and engine enabled change notifications.
- // Important for tests where we unregister the engine during cleanup.
- Svc.Obs.remove("weave:engine:start-tracking", this);
- Svc.Obs.remove("weave:engine:stop-tracking", this);
-
// Persist all pending tracked changes to disk, and wait for the final write
// to finish.
this._saveChangedIDs();
await this._storage.finalize();
},
};
@@ -655,16 +646,17 @@ this.Engine = function Engine(name, serv
this._modified = this.emptyChangeset();
this._tracker; // initialize tracker to load previously changed IDs
this._log.debug("Engine constructed");
XPCOMUtils.defineLazyPreferenceGetter(this, "_enabled",
`services.sync.engine.${this.prefName}`, false,
(data, previous, latest) =>
+ // We do not await on the promise onEngineEnabledChanged returns.
this._tracker.onEngineEnabledChanged(latest));
};
Engine.prototype = {
// _storeObj, and _trackerObj should to be overridden in subclasses
_storeObj: Store,
_trackerObj: Tracker,
// Override this method to return a new changeset type.
@@ -707,16 +699,25 @@ Engine.prototype = {
},
get _tracker() {
let tracker = new this._trackerObj(this.Name, this);
this.__defineGetter__("_tracker", () => tracker);
return tracker;
},
+ startTracking() {
+ this._tracker.start();
+ },
+
+ // Returns a promise
+ stopTracking() {
+ return this._tracker.stop();
+ },
+
async sync() {
if (!this.enabled) {
return false;
}
if (!this._sync) {
throw new Error("engine does not implement _sync method");
}
@@ -736,17 +737,17 @@ Engine.prototype = {
},
async _wipeClient() {
await this.resetClient();
this._log.debug("Deleting all local data");
this._tracker.ignoreAll = true;
await this._store.wipe();
this._tracker.ignoreAll = false;
- this._tracker.clearChangedIDs();
+ await this._tracker.clearChangedIDs();
},
async wipeClient() {
return this._notify("wipe-client", this.name, this._wipeClient)();
},
/**
* If one exists, initialize and return a validator for this engine (which
@@ -952,17 +953,17 @@ SyncEngine.prototype = {
Svc.Prefs.set(this.name + ".lastSyncLocal", value.toString());
},
/*
* Returns a changeset for this sync. Engine implementations can override this
* method to bypass the tracker for certain or all changed items.
*/
async getChangedIDs() {
- return this._tracker.changedIDs;
+ return this._tracker.getChangedIDs();
},
// Create a new record using the store and add in metadata.
async _createRecord(id) {
let record = await this._store.createRecord(id, this.name);
record.id = id;
record.collection = this.name;
return record;
@@ -978,17 +979,16 @@ SyncEngine.prototype = {
},
addForWeakUpload(id, { forceTombstone = false } = {}) {
this._needWeakUpload.set(id, { forceTombstone });
},
// Any setup that needs to happen at the beginning of each sync.
async _syncStartup() {
-
// Determine if we need to wipe on outdated versions
let metaGlobal = await this.service.recordManager.get(this.metaURL);
let engines = metaGlobal.payload.engines || {};
let engineData = engines[this.name] || {};
let needsWipe = false;
// Assume missing versions are 0 and wipe the server
@@ -1034,17 +1034,17 @@ SyncEngine.prototype = {
// or any objects fail to upload, they will remain in this._modified. At
// the end of a sync, or after an error, we add all objects remaining in
// this._modified to the tracker.
this.lastSyncLocal = Date.now();
let initialChanges = await this.pullChanges();
this._modified.replace(initialChanges);
// Clear the tracker now. If the sync fails we'll add the ones we failed
// to upload back.
- this._tracker.clearChangedIDs();
+ await this._tracker.clearChangedIDs();
this._tracker.resetScore();
this._log.info(this._modified.count() +
" outgoing items pre-reconciliation");
// Keep track of what to delete at the end of sync
this._delete = {};
},
@@ -1332,17 +1332,17 @@ SyncEngine.prototype = {
throw ex;
}
this._log.warn("Error decrypting record", ex);
return { shouldApply: false, error: ex };
}
if (this._shouldDeleteRemotely(item)) {
this._log.trace("Deleting item from server without applying", item);
- this._deleteId(item.id);
+ await this._deleteId(item.id);
return { shouldApply: false, error: null };
}
let shouldApply;
try {
shouldApply = await this._reconcile(item);
} catch (ex) {
if (ex.code == Engine.prototype.eEngineAbortApplyIncoming) {
@@ -1407,32 +1407,32 @@ SyncEngine.prototype = {
// record will be deleted locally. If we return true, we'll reupload the
// record to the server -- any extra work that's needed as part of this
// process should be done at this point (such as mark the record's parent
// for reuploading in the case of bookmarks).
async _shouldReviveRemotelyDeletedRecord(remoteItem) {
return true;
},
- _deleteId(id) {
- this._tracker.removeChangedID(id);
+ async _deleteId(id) {
+ await this._tracker.removeChangedID(id);
this._noteDeletedId(id);
},
// Marks an ID for deletion at the end of the sync.
_noteDeletedId(id) {
if (this._delete.ids == null)
this._delete.ids = [id];
else
this._delete.ids.push(id);
},
async _switchItemToDupe(localDupeGUID, incomingItem) {
// The local, duplicate ID is always deleted on the server.
- this._deleteId(localDupeGUID);
+ await this._deleteId(localDupeGUID);
// We unconditionally change the item's ID in case the engine knows of
// an item but doesn't expose it through itemExists. If the API
// contract were stronger, this could be changed.
this._log.debug("Switching local ID to incoming: " + localDupeGUID + " -> " +
incomingItem.id);
return this._store.changeItemID(localDupeGUID, incomingItem.id);
},
@@ -1760,16 +1760,17 @@ SyncEngine.prototype = {
else {
// For many ids, split into chunks of at most 100
while (val.length > 0) {
await doDelete(key, val.slice(0, 100));
val = val.slice(100);
}
}
}
+ await this._tracker.asyncObserver.promiseObserversComplete();
},
async _syncCleanup() {
this._needWeakUpload.clear();
if (!this._modified) {
return;
}
@@ -1903,27 +1904,28 @@ SyncEngine.prototype = {
/*
* Returns a changeset containing entries for all currently tracked items.
* The default implementation returns a changeset with timestamps indicating
* when the item was added to the tracker.
*
* @return A `Changeset` object.
*/
async pullNewChanges() {
+ await this._tracker.asyncObserver.promiseObserversComplete();
return this.getChangedIDs();
},
/**
* Adds all remaining changeset entries back to the tracker, typically for
* items that failed to upload. This method is called at the end of each sync.
*
*/
async trackRemainingChanges() {
for (let [id, change] of this._modified.entries()) {
- this._tracker.addChangedID(id, change);
+ await this._tracker.addChangedID(id, change);
}
},
async finalize() {
await super.finalize();
await this._toFetchStorage.finalize();
await this._previousFailedStorage.finalize();
},
--- a/services/sync/modules/engines/addons.js
+++ b/services/sync/modules/engines/addons.js
@@ -109,17 +109,17 @@ Utils.deferGetSet(AddonRecord, "cleartex
* that AddonManager doesn't.
*
* The engine instance overrides a handful of functions on the base class. The
* rationale for each is documented by that function.
*/
this.AddonsEngine = function AddonsEngine(service) {
SyncEngine.call(this, "Addons", service);
- this._reconciler = new AddonsReconciler();
+ this._reconciler = new AddonsReconciler(this._tracker.asyncObserver);
};
AddonsEngine.prototype = {
__proto__: SyncEngine.prototype,
_storeObj: AddonsStore,
_trackerObj: AddonsTracker,
_recordObj: AddonRecord,
version: 1,
@@ -154,17 +154,18 @@ AddonsEngine.prototype = {
},
/**
* Override getChangedIDs to pull in tracker changes plus changes from the
* reconciler log.
*/
async getChangedIDs() {
let changes = {};
- for (let [id, modified] of Object.entries(this._tracker.changedIDs)) {
+ const changedIDs = await this._tracker.getChangedIDs();
+ for (let [id, modified] of Object.entries(changedIDs)) {
changes[id] = modified;
}
let lastSyncDate = new Date(this.lastSync * 1000);
// The reconciler should have been refreshed at the beginning of a sync and
// we assume this function is only called from within a sync.
let reconcilerChanges = this._reconciler.getChangesSinceDate(lastSyncDate);
@@ -703,30 +704,28 @@ AddonsTracker.prototype = {
}
if (!(await this.store.isAddonSyncable(addon))) {
this._log.debug("Ignoring change because add-on isn't syncable: " +
addon.id);
return;
}
- if (this.addChangedID(addon.guid, date.getTime() / 1000)) {
+ const added = await this.addChangedID(addon.guid, date.getTime() / 1000);
+ if (added) {
this.score += SCORE_INCREMENT_XLARGE;
}
},
- startTracking() {
- if (this.engine.enabled) {
- this.reconciler.startListening();
- }
-
+ onStart() {
+ this.reconciler.startListening();
this.reconciler.addChangeListener(this);
},
- stopTracking() {
+ onStop() {
this.reconciler.removeChangeListener(this);
this.reconciler.stopListening();
},
};
class AddonValidator extends CollectionValidator {
constructor(engine = null) {
super("addons", "id", [
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -655,20 +655,16 @@ BookmarksEngine.prototype = {
}
let mapped = await this._mapDupe(item);
this._log.debug(item.id + " mapped to " + mapped);
// We must return a string, not an object, and the entries in the GUIDMap
// are created via "new String()" making them an object.
return mapped ? mapped.toString() : mapped;
},
- async pullNewChanges() {
- return this._tracker.promiseChangedIDs();
- },
-
// Called when _findDupe returns a dupe item and the engine has decided to
// switch the existing item to the new incoming item.
async _switchItemToDupe(localDupeGUID, incomingItem) {
let newChanges = await PlacesSyncUtils.bookmarks.dedupe(localDupeGUID,
incomingItem.id,
incomingItem.parentid);
this._modified.insert(newChanges);
},
@@ -1138,19 +1134,19 @@ BufferedBookmarksStore.prototype = {
};
// The bookmarks tracker is a special flower. Instead of listening for changes
// via observer notifications, it queries Places for the set of items that have
// changed since the last sync. Because it's a "pull-based" tracker, it ignores
// all concepts of "add a changed ID." However, it still registers an observer
// to bump the score, so that changed bookmarks are synced immediately.
function BookmarksTracker(name, engine) {
+ Tracker.call(this, name, engine);
this._batchDepth = 0;
this._batchSawScoreIncrement = false;
- Tracker.call(this, name, engine);
}
BookmarksTracker.prototype = {
__proto__: Tracker.prototype,
// `_ignore` checks the change source for each observer notification, so we
// don't want to let the engine ignore all changes during a sync.
get ignoreAll() {
return false;
@@ -1159,75 +1155,65 @@ BookmarksTracker.prototype = {
// Define an empty setter so that the engine doesn't throw a `TypeError`
// setting a read-only property.
set ignoreAll(value) {},
// We never want to persist changed IDs, as the changes are already stored
// in Places.
persistChangedIDs: false,
- startTracking() {
+ onStart() {
PlacesUtils.bookmarks.addObserver(this, true);
- Svc.Obs.add("bookmarks-restore-begin", this);
- Svc.Obs.add("bookmarks-restore-success", this);
- Svc.Obs.add("bookmarks-restore-failed", this);
+ Svc.Obs.add("bookmarks-restore-begin", this.asyncObserver);
+ Svc.Obs.add("bookmarks-restore-success", this.asyncObserver);
+ Svc.Obs.add("bookmarks-restore-failed", this.asyncObserver);
},
- stopTracking() {
+ onStop() {
PlacesUtils.bookmarks.removeObserver(this);
- Svc.Obs.remove("bookmarks-restore-begin", this);
- Svc.Obs.remove("bookmarks-restore-success", this);
- Svc.Obs.remove("bookmarks-restore-failed", this);
+ Svc.Obs.remove("bookmarks-restore-begin", this.asyncObserver);
+ Svc.Obs.remove("bookmarks-restore-success", this.asyncObserver);
+ Svc.Obs.remove("bookmarks-restore-failed", this.asyncObserver);
},
// Ensure we aren't accidentally using the base persistence.
addChangedID(id, when) {
throw new Error("Don't add IDs to the bookmarks tracker");
},
removeChangedID(id) {
throw new Error("Don't remove IDs from the bookmarks tracker");
},
// This method is called at various times, so we override with a no-op
// instead of throwing.
clearChangedIDs() {},
- promiseChangedIDs() {
+ async getChangedIDs() {
return PlacesSyncUtils.bookmarks.pullChanges();
},
- get changedIDs() {
- throw new Error("Use promiseChangedIDs");
- },
-
set changedIDs(obj) {
throw new Error("Don't set initial changed bookmark IDs");
},
- observe: function observe(subject, topic, data) {
- Tracker.prototype.observe.call(this, subject, topic, data);
-
+ async observe(subject, topic, data) {
switch (topic) {
- case "weave:engine:start-tracking":
- break;
case "bookmarks-restore-begin":
this._log.debug("Ignoring changes from importing bookmarks.");
break;
case "bookmarks-restore-success":
this._log.debug("Tracking all items on successful import.");
if (data == "json") {
this._log.debug("Restore succeeded: wiping server and other clients.");
- Async.promiseSpinningly((async () => {
- await this.engine.service.resetClient([this.name]);
- await this.engine.service.wipeServer([this.name]);
- await this.engine.service.clientsEngine.sendCommand("wipeEngine", [this.name],
- null, { reason: "bookmark-restore" });
- })());
+ await this.engine.service.resetClient([this.name]);
+ await this.engine.service.wipeServer([this.name]);
+ await this.engine.service.clientsEngine.sendCommand("wipeEngine", [this.name],
+ null, { reason: "bookmark-restore" });
} else {
// "html", "html-initial", or "json-append"
this._log.debug("Import succeeded.");
}
break;
case "bookmarks-restore-failed":
this._log.debug("Tracking all items on failed import.");
break;
--- a/services/sync/modules/engines/clients.js
+++ b/services/sync/modules/engines/clients.js
@@ -360,17 +360,17 @@ ClientEngine.prototype = {
}
this._knownStaleFxADeviceIds = Utils.arraySub(localClients, fxaClients);
},
async _syncStartup() {
this.isFirstSync = !this.lastRecordUpload;
// Reupload new client record periodically.
if (Date.now() / 1000 - this.lastRecordUpload > CLIENTS_TTL_REFRESH) {
- this._tracker.addChangedID(this.localID);
+ await this._tracker.addChangedID(this.localID);
this.lastRecordUpload = Date.now() / 1000;
}
return SyncEngine.prototype._syncStartup.call(this);
},
async _processIncoming() {
// Fetch all records from the server.
this.lastSync = 0;
@@ -628,17 +628,17 @@ ClientEngine.prototype = {
this._log.debug("Handling HMAC mismatch for " + item.id);
let base = await SyncEngine.prototype.handleHMACMismatch.call(this, item, mayRetry);
if (base != SyncEngine.kRecoveryStrategy.error)
return base;
// It's a bad client record. Save it to be deleted at the end of the sync.
this._log.debug("Bad client record detected. Scheduling for deletion.");
- this._deleteId(item.id);
+ await this._deleteId(item.id);
// Neither try again nor error; we're going to delete it.
return SyncEngine.kRecoveryStrategy.ignore;
},
/**
* A hash of valid commands that the client knows about. The key is a command
* and the value is a hash containing information about the command such as
@@ -679,17 +679,17 @@ ClientEngine.prototype = {
args,
// We send the flowID to the other client so *it* can report it in its
// telemetry - we record it in ours below.
flowID: telemetryExtra.flowID,
};
if ((await this._addClientCommand(clientId, action))) {
this._log.trace(`Client ${clientId} got a new action`, [command, args]);
- this._tracker.addChangedID(clientId);
+ await this._tracker.addChangedID(clientId);
try {
telemetryExtra.deviceID = this.service.identity.hashedDeviceID(clientId);
} catch (_) {}
this.service.recordTelemetryEvent("sendcommand", command, undefined, telemetryExtra);
} else {
this._log.trace(`Client ${clientId} got a duplicate action`, [command, args]);
}
@@ -795,17 +795,17 @@ ClientEngine.prototype = {
}
// Add the command to the "cleared" commands list
if (shouldRemoveCommand) {
await this.removeLocalCommand(rawCommand);
didRemoveCommand = true;
}
}
if (didRemoveCommand) {
- this._tracker.addChangedID(this.localID);
+ await this._tracker.addChangedID(this.localID);
}
if (URIsToDisplay.length) {
this._handleDisplayURIs(URIsToDisplay);
}
return true;
})();
@@ -909,17 +909,17 @@ ClientEngine.prototype = {
* send this.
*/
_handleDisplayURIs: function _handleDisplayURIs(uris) {
Svc.Obs.notify("weave:engine:clients:display-uris", uris);
},
async _removeRemoteClient(id) {
delete this._store._remoteClients[id];
- this._tracker.removeChangedID(id);
+ await this._tracker.removeChangedID(id);
await this._removeClientCommands(id);
this._modified.delete(id);
},
};
function ClientStore(name, engine) {
Store.call(this, name, engine);
}
@@ -1042,38 +1042,31 @@ ClientStore.prototype = {
async wipe() {
this._remoteClients = {};
},
};
function ClientsTracker(name, engine) {
Tracker.call(this, name, engine);
- Svc.Obs.add("weave:engine:start-tracking", this);
- Svc.Obs.add("weave:engine:stop-tracking", this);
}
ClientsTracker.prototype = {
__proto__: Tracker.prototype,
_enabled: false,
- observe: function observe(subject, topic, data) {
+ onStart() {
+ Svc.Prefs.observe("client.name", this.asyncObserver);
+ },
+ onStop() {
+ Svc.Prefs.ignore("client.name", this.asyncObserver);
+ },
+
+ async observe(subject, topic, data) {
switch (topic) {
- case "weave:engine:start-tracking":
- if (!this._enabled) {
- Svc.Prefs.observe("client.name", this);
- this._enabled = true;
- }
- break;
- case "weave:engine:stop-tracking":
- if (this._enabled) {
- Svc.Prefs.ignore("client.name", this);
- this._enabled = false;
- }
- break;
case "nsPref:changed":
this._log.debug("client.name preference changed");
- this.addChangedID(this.engine.localID);
+ await this.addChangedID(this.engine.localID);
this.score += SCORE_INCREMENT_XLARGE;
break;
}
}
};
--- a/services/sync/modules/engines/extension-storage.js
+++ b/services/sync/modules/engines/extension-storage.js
@@ -56,27 +56,25 @@ ExtensionStorageEngine.prototype = {
};
function ExtensionStorageTracker(name, engine) {
Tracker.call(this, name, engine);
}
ExtensionStorageTracker.prototype = {
__proto__: Tracker.prototype,
- startTracking() {
- Svc.Obs.add("ext.storage.sync-changed", this);
+ onStart() {
+ Svc.Obs.add("ext.storage.sync-changed", this.asyncObserver);
},
- stopTracking() {
- Svc.Obs.remove("ext.storage.sync-changed", this);
+ onStop() {
+ Svc.Obs.remove("ext.storage.sync-changed", this.asyncObserver);
},
- observe(subject, topic, data) {
- Tracker.prototype.observe.call(this, subject, topic, data);
-
+ async observe(subject, topic, data) {
if (this.ignoreAll) {
return;
}
if (topic !== "ext.storage.sync-changed") {
return;
}
--- a/services/sync/modules/engines/forms.js
+++ b/services/sync/modules/engines/forms.js
@@ -216,41 +216,41 @@ function FormTracker(name, engine) {
}
FormTracker.prototype = {
__proto__: Tracker.prototype,
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
- startTracking() {
- Svc.Obs.add("satchel-storage-changed", this);
+ onStart() {
+ Svc.Obs.add("satchel-storage-changed", this.asyncObserver);
},
- stopTracking() {
- Svc.Obs.remove("satchel-storage-changed", this);
+ onStop() {
+ Svc.Obs.remove("satchel-storage-changed", this.asyncObserver);
},
- observe(subject, topic, data) {
- Tracker.prototype.observe.call(this, subject, topic, data);
+ async observe(subject, topic, data) {
if (this.ignoreAll) {
return;
}
switch (topic) {
case "satchel-storage-changed":
if (data == "formhistory-add" || data == "formhistory-remove") {
let guid = subject.QueryInterface(Ci.nsISupportsString).toString();
- this.trackEntry(guid);
+ await this.trackEntry(guid);
}
break;
}
},
- trackEntry(guid) {
- if (this.addChangedID(guid)) {
+ async trackEntry(guid) {
+ const added = await this.addChangedID(guid);
+ if (added) {
this.score += SCORE_INCREMENT_MEDIUM;
}
},
};
class FormsProblemData extends CollectionProblemData {
getSummary() {
--- a/services/sync/modules/engines/history.js
+++ b/services/sync/modules/engines/history.js
@@ -69,24 +69,25 @@ HistoryEngine.prototype = {
}
},
shouldSyncURL(url) {
return !url.startsWith("file:");
},
async pullNewChanges() {
- let modifiedGUIDs = Object.keys(this._tracker.changedIDs);
+ const changedIDs = await this._tracker.getChangedIDs();
+ let modifiedGUIDs = Object.keys(changedIDs);
if (!modifiedGUIDs.length) {
return {};
}
let guidsToRemove = await PlacesSyncUtils.history.determineNonSyncableGuids(modifiedGUIDs);
- this._tracker.removeChangedID(...guidsToRemove);
- return this._tracker.changedIDs;
+ await this._tracker.removeChangedID(...guidsToRemove);
+ return changedIDs;
},
};
function HistoryStore(name, engine) {
Store.call(this, name, engine);
// Explicitly nullify our references to our cached services so we don't leak
Svc.Obs.add("places-shutdown", function() {
@@ -432,58 +433,67 @@ HistoryStore.prototype = {
};
function HistoryTracker(name, engine) {
Tracker.call(this, name, engine);
}
HistoryTracker.prototype = {
__proto__: Tracker.prototype,
- startTracking() {
+ onStart() {
this._log.info("Adding Places observer.");
PlacesUtils.history.addObserver(this, true);
},
- stopTracking() {
+ onStop() {
this._log.info("Removing Places observer.");
PlacesUtils.history.removeObserver(this);
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsINavHistoryObserver,
Ci.nsISupportsWeakReference
]),
- onDeleteAffectsGUID(uri, guid, reason, source, increment) {
+ async onDeleteAffectsGUID(uri, guid, reason, source, increment) {
if (this.ignoreAll || reason == Ci.nsINavHistoryObserver.REASON_EXPIRED) {
return;
}
this._log.trace(source + ": " + uri.spec + ", reason " + reason);
- if (this.addChangedID(guid)) {
+ const added = await this.addChangedID(guid);
+ if (added) {
this.score += increment;
}
},
onDeleteVisits(uri, visitTime, guid, reason) {
- this.onDeleteAffectsGUID(uri, guid, reason, "onDeleteVisits", SCORE_INCREMENT_SMALL);
+ this.asyncObserver.enqueueCall(() =>
+ this.onDeleteAffectsGUID(uri, guid, reason, "onDeleteVisits", SCORE_INCREMENT_SMALL)
+ );
},
onDeleteURI(uri, guid, reason) {
- this.onDeleteAffectsGUID(uri, guid, reason, "onDeleteURI", SCORE_INCREMENT_XLARGE);
+ this.asyncObserver.enqueueCall(() =>
+ this.onDeleteAffectsGUID(uri, guid, reason, "onDeleteURI", SCORE_INCREMENT_XLARGE)
+ );
},
onVisits(aVisits) {
+ this.asyncObserver.enqueueCall(() => this._onVisits(aVisits));
+ },
+
+ async _onVisits(aVisits) {
if (this.ignoreAll) {
this._log.trace("ignoreAll: ignoring visits [" +
aVisits.map(v => v.guid).join(",") + "]");
return;
}
for (let {uri, guid} of aVisits) {
this._log.trace("onVisits: " + uri.spec);
- if (this.engine.shouldSyncURL(uri.spec) && this.addChangedID(guid)) {
+ if (this.engine.shouldSyncURL(uri.spec) && (await this.addChangedID(guid))) {
this.score += SCORE_INCREMENT_SMALL;
}
}
},
onClearHistory() {
this._log.trace("onClearHistory");
// Note that we're going to trigger a sync, but none of the cleared
--- a/services/sync/modules/engines/passwords.js
+++ b/services/sync/modules/engines/passwords.js
@@ -324,75 +324,74 @@ PasswordStore.prototype = {
async wipe() {
Services.logins.removeAllLogins();
},
};
function PasswordTracker(name, engine) {
Tracker.call(this, name, engine);
- Svc.Obs.add("weave:engine:start-tracking", this);
- Svc.Obs.add("weave:engine:stop-tracking", this);
}
PasswordTracker.prototype = {
__proto__: Tracker.prototype,
- startTracking() {
- Svc.Obs.add("passwordmgr-storage-changed", this);
+ onStart() {
+ Svc.Obs.add("passwordmgr-storage-changed", this.asyncObserver);
},
- stopTracking() {
- Svc.Obs.remove("passwordmgr-storage-changed", this);
+ onStop() {
+ Svc.Obs.remove("passwordmgr-storage-changed", this.asyncObserver);
},
- observe(subject, topic, data) {
- Tracker.prototype.observe.call(this, subject, topic, data);
-
+ async observe(subject, topic, data) {
if (this.ignoreAll) {
return;
}
// A single add, remove or change or removing all items
// will trigger a sync for MULTI_DEVICE.
switch (data) {
case "modifyLogin": {
subject.QueryInterface(Ci.nsIArrayExtensions);
let oldLogin = subject.GetElementAt(0);
let newLogin = subject.GetElementAt(1);
if (!isSyncableChange(oldLogin, newLogin)) {
this._log.trace(`${data}: Ignoring change for ${newLogin.guid}`);
break;
}
- if (this._trackLogin(newLogin)) {
+ const tracked = await this._trackLogin(newLogin);
+ if (tracked) {
this._log.trace(`${data}: Tracking change for ${newLogin.guid}`);
}
break;
}
case "addLogin":
case "removeLogin":
subject.QueryInterface(Ci.nsILoginMetaInfo).QueryInterface(Ci.nsILoginInfo);
- if (this._trackLogin(subject)) {
+ const tracked = await this._trackLogin(subject);
+ if (tracked) {
this._log.trace(data + ": " + subject.guid);
}
break;
case "removeAllLogins":
this._log.trace(data);
this.score += SCORE_INCREMENT_XLARGE;
break;
}
},
- _trackLogin(login) {
+ async _trackLogin(login) {
if (Utils.getSyncCredentialsHosts().has(login.hostname)) {
// Skip over Weave password/passphrase changes.
return false;
}
- if (!this.addChangedID(login.guid)) {
+ const added = await this.addChangedID(login.guid);
+ if (!added) {
return false;
}
this.score += SCORE_INCREMENT_XLARGE;
return true;
},
};
class PasswordValidator extends CollectionValidator {
--- a/services/sync/modules/engines/prefs.js
+++ b/services/sync/modules/engines/prefs.js
@@ -230,19 +230,17 @@ PrefStore.prototype = {
async wipe() {
this._log.trace("Ignoring wipe request");
}
};
function PrefTracker(name, engine) {
Tracker.call(this, name, engine);
- Svc.Obs.add("profile-before-change", this);
- Svc.Obs.add("weave:engine:start-tracking", this);
- Svc.Obs.add("weave:engine:stop-tracking", this);
+ Svc.Obs.add("profile-before-change", this.asyncObserver);
}
PrefTracker.prototype = {
__proto__: Tracker.prototype,
get modified() {
return Svc.Prefs.get("engine.prefs.modified", false);
},
set modified(value) {
@@ -256,31 +254,29 @@ PrefTracker.prototype = {
__prefs: null,
get _prefs() {
if (!this.__prefs) {
this.__prefs = new Preferences();
}
return this.__prefs;
},
- startTracking() {
- Services.prefs.addObserver("", this);
+ onStart() {
+ Services.prefs.addObserver("", this.asyncObserver);
},
- stopTracking() {
+ onStop() {
this.__prefs = null;
- Services.prefs.removeObserver("", this);
+ Services.prefs.removeObserver("", this.asyncObserver);
},
- observe(subject, topic, data) {
- Tracker.prototype.observe.call(this, subject, topic, data);
-
+ async observe(subject, topic, data) {
switch (topic) {
case "profile-before-change":
- this.stopTracking();
+ await this.stop();
break;
case "nsPref:changed":
if (this.ignoreAll) {
break;
}
// Trigger a sync for MULTI-DEVICE for a change that determines
// which prefs are synced or a regular pref change.
if (data.indexOf(PREF_SYNC_PREFS_PREFIX) == 0 ||
--- a/services/sync/modules/engines/tabs.js
+++ b/services/sync/modules/engines/tabs.js
@@ -272,18 +272,16 @@ TabStore.prototype = {
async update(record) {
this._log.trace("Ignoring tab updates as local ones win");
},
};
function TabTracker(name, engine) {
Tracker.call(this, name, engine);
- Svc.Obs.add("weave:engine:start-tracking", this);
- Svc.Obs.add("weave:engine:stop-tracking", this);
// Make sure "this" pointer is always set correctly for event listeners.
this.onTab = Utils.bind2(this, this.onTab);
this._unregisterListeners = Utils.bind2(this, this._unregisterListeners);
}
TabTracker.prototype = {
__proto__: Tracker.prototype,
@@ -317,35 +315,33 @@ TabTracker.prototype = {
for (let topic of this._topics) {
window.removeEventListener(topic, this.onTab);
}
if (window.gBrowser) {
window.gBrowser.removeProgressListener(this);
}
},
- startTracking() {
- Svc.Obs.add("domwindowopened", this);
+ onStart() {
+ Svc.Obs.add("domwindowopened", this.asyncObserver);
let wins = Services.wm.getEnumerator("navigator:browser");
while (wins.hasMoreElements()) {
this._registerListenersForWindow(wins.getNext());
}
},
- stopTracking() {
- Svc.Obs.remove("domwindowopened", this);
+ onStop() {
+ Svc.Obs.remove("domwindowopened", this.asyncObserver);
let wins = Services.wm.getEnumerator("navigator:browser");
while (wins.hasMoreElements()) {
this._unregisterListenersForWindow(wins.getNext());
}
},
- observe(subject, topic, data) {
- Tracker.prototype.observe.call(this, subject, topic, data);
-
+ async observe(subject, topic, data) {
switch (topic) {
case "domwindowopened":
let onLoad = () => {
subject.removeEventListener("load", onLoad);
// Only register after the window is done loading to avoid unloads.
this._registerListenersForWindow(subject);
};
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -297,16 +297,17 @@ Sync11Service.prototype = {
this.scheduler = new SyncScheduler(this);
this.errorHandler = new ErrorHandler(this);
this._log = Log.repository.getLogger("Sync.Service");
this._log.manageLevelFromPref("services.sync.log.logger.service.main");
this._log.info("Loading Weave " + WEAVE_VERSION);
+ this.asyncObserver = Async.asyncObserver(this, this._log);
this._clusterManager = this.identity.createClusterManager(this);
this.recordManager = new RecordManager(this);
this.enabled = true;
await this._registerEngines();
let ua = Cc["@mozilla.org/network/protocol;1?name=http"].
@@ -314,30 +315,31 @@ Sync11Service.prototype = {
this._log.info(ua);
if (!this._checkCrypto()) {
this.enabled = false;
this._log.info("Could not load the Weave crypto component. Disabling " +
"Weave, since it will not work correctly.");
}
- Svc.Obs.add("weave:service:setup-complete", this);
- Svc.Obs.add("sync:collection_changed", this); // Pulled from FxAccountsCommon
- Svc.Obs.add("fxaccounts:device_disconnected", this);
- Services.prefs.addObserver(PREFS_BRANCH + "engine.", this);
+ Svc.Obs.add("weave:service:setup-complete", this.asyncObserver);
+ Svc.Obs.add("sync:collection_changed", this.asyncObserver); // Pulled from FxAccountsCommon
+ Svc.Obs.add("fxaccounts:device_disconnected", this.asyncObserver);
+ // We use a different synchronous observer to make testing easier.
+ Services.prefs.addObserver(PREFS_BRANCH + "engine.", this.prefObserver.bind(this));
if (!this.enabled) {
this._log.info("Firefox Sync disabled.");
}
this._updateCachedURLs();
let status = this._checkSetup();
if (status != STATUS_DISABLED && status != CLIENT_NOT_CONFIGURED) {
- Svc.Obs.notify("weave:engine:start-tracking");
+ this._startTracking();
}
// Send an event now that Weave service is ready. We don't do this
// synchronously so that observers can import this module before
// registering an observer.
CommonUtils.nextTick(() => {
this.status.ready = true;
@@ -411,72 +413,80 @@ Sync11Service.prototype = {
} catch (ex) {
this._log.warn("Could not register engine " + name, ex);
}
}
this.engineManager.setDeclined(declined);
},
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
- Ci.nsISupportsWeakReference]),
-
- // nsIObserver
-
- observe: function observe(subject, topic, data) {
- switch (topic) {
- // Ideally this observer should be in the SyncScheduler, but it would require
- // some work to know about the sync specific engines. We should move this there once it does.
- case "sync:collection_changed":
- // We check if we're running TPS here to avoid TPS failing because it
- // couldn't get to get the sync lock, due to us currently syncing the
- // clients engine.
- if (data.includes("clients") && !Svc.Prefs.get("testing.tps", false)) {
- // Sync in the background (it's fine not to wait on the returned promise
- // because sync() has a lock).
- // [] = clients collection only
- this.sync({why: "collection_changed", engines: []}).catch(e => {
- this._log.error(e);
- });
- }
- break;
- case "fxaccounts:device_disconnected":
- data = JSON.parse(data);
- if (!data.isLocalDevice) {
- // Refresh the known stale clients list in the background.
- this.clientsEngine.updateKnownStaleClients().catch(e => {
- this._log.error(e);
- });
- }
- break;
- case "weave:service:setup-complete":
- let status = this._checkSetup();
- if (status != STATUS_DISABLED && status != CLIENT_NOT_CONFIGURED)
- Svc.Obs.notify("weave:engine:start-tracking");
- break;
- case "nsPref:changed":
- if (this._ignorePrefObserver)
- return;
- let engine = data.slice((PREFS_BRANCH + "engine.").length);
- this._handleEngineStatusChanged(engine);
- break;
+ async observe(subject, topic, data) {
+ try {
+ switch (topic) {
+ // Ideally this observer should be in the SyncScheduler, but it would require
+ // some work to know about the sync specific engines. We should move this there once it does.
+ case "sync:collection_changed":
+ // We check if we're running TPS here to avoid TPS failing because it
+ // couldn't get to get the sync lock, due to us currently syncing the
+ // clients engine.
+ if (data.includes("clients") && !Svc.Prefs.get("testing.tps", false)) {
+ // [] = clients collection only
+ await this.sync({why: "collection_changed", engines: []});
+ }
+ break;
+ case "fxaccounts:device_disconnected":
+ data = JSON.parse(data);
+ if (!data.isLocalDevice) {
+ await this.clientsEngine.updateKnownStaleClients();
+ }
+ break;
+ case "weave:service:setup-complete":
+ let status = this._checkSetup();
+ if (status != STATUS_DISABLED && status != CLIENT_NOT_CONFIGURED) {
+ this._startTracking();
+ }
+ break;
+ }
+ } catch (e) {
+ this._log.error(e);
}
},
- _handleEngineStatusChanged: function handleEngineDisabled(engine) {
+ prefObserver(subject, topic, data) {
+ if (this._ignorePrefObserver) {
+ return;
+ }
+ const engine = data.slice((PREFS_BRANCH + "engine.").length);
this._log.trace("Status for " + engine + " engine changed.");
if (Svc.Prefs.get("engineStatusChanged." + engine, false)) {
// The enabled status being changed back to what it was before.
Svc.Prefs.reset("engineStatusChanged." + engine);
} else {
// Remember that the engine status changed locally until the next sync.
Svc.Prefs.set("engineStatusChanged." + engine, true);
}
},
+ async _startTracking() {
+ const engines = this.engineManager.getAll();
+ for (let engine of engines) {
+ engine.startTracking();
+ }
+ // This is for TPS. We should try to do better.
+ Svc.Obs.notify("weave:service:tracking-started");
+ },
+
+ async _stopTracking() {
+ const engines = this.engineManager.getAll();
+ for (let engine of engines) {
+ await engine.stopTracking();
+ }
+ Svc.Obs.notify("weave:service:tracking-stopped");
+ },
+
/**
* Obtain a Resource instance with authentication credentials.
*/
resource: function resource(url) {
let res = new Resource(url);
res.authenticator = this.identity.getResourceAuthenticator();
return res;
@@ -773,17 +783,17 @@ Sync11Service.prototype = {
cryptoKeys, true);
if (keysChanged) {
this._log.info("Downloaded keys differed, as expected.");
}
},
async startOver() {
this._log.trace("Invoking Service.startOver.");
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await this._stopTracking();
this.status.resetSync();
// Deletion doesn't make sense if we aren't set up yet!
if (this.clusterURL != "") {
// Clear client-specific data from the server, including disabled engines.
for (let engine of [this.clientsEngine].concat(this.engineManager.getAll())) {
try {
await engine.removeClientData();
@@ -1084,16 +1094,17 @@ Sync11Service.prototype = {
return reason;
},
async sync({engines, why} = {}) {
let dateStr = Utils.formatTimestamp(new Date());
this._log.debug("User-Agent: " + Utils.userAgent);
await this.promiseInitialized;
+ await this.asyncObserver.promiseObserversComplete();
this._log.info(`Starting sync at ${dateStr} in browser session ${browserSessionID}`);
return this._catch(async function() {
// Make sure we're logged in.
if (this._shouldLogin()) {
this._log.debug("In sync: should login.");
if (!(await this.login())) {
this._log.debug("Not syncing: login returned false.");
return;
--- a/services/sync/tests/unit/head_helpers.js
+++ b/services/sync/tests/unit/head_helpers.js
@@ -143,42 +143,57 @@ async function installAddonFromInstall(i
return install.addon;
}
/**
* Convenience function to install an add-on from the extensions unit tests.
*
* @param name
* String name of add-on to install. e.g. test_install1
+ * @param reconciler
+ * addons reconciler, if passed we will wait on the events to be
+ * processed before resolving
* @return addon object that was installed
*/
-async function installAddon(name) {
+async function installAddon(name, reconciler = null) {
let install = await getAddonInstall(name);
Assert.notEqual(null, install);
- return installAddonFromInstall(install);
+ const addon = await installAddonFromInstall(install);
+ if (reconciler) {
+ await reconciler.queueCaller.promiseCallsComplete();
+ }
+ return addon;
}
/**
* Convenience function to uninstall an add-on.
*
* @param addon
* Addon instance to uninstall
+ * @param reconciler
+ * addons reconciler, if passed we will wait on the events to be
+ * processed before resolving
*/
-function uninstallAddon(addon) {
- return new Promise(res => {
- let listener = {onUninstalled(uninstalled) {
- if (uninstalled.id == addon.id) {
- AddonManager.removeAddonListener(listener);
- res(uninstalled);
+async function uninstallAddon(addon, reconciler = null) {
+ const uninstallPromise = new Promise(res => {
+ let listener = {
+ onUninstalled(uninstalled) {
+ if (uninstalled.id == addon.id) {
+ AddonManager.removeAddonListener(listener);
+ res(uninstalled);
+ }
}
- }};
-
+ };
AddonManager.addAddonListener(listener);
- addon.uninstall();
});
+ addon.uninstall();
+ await uninstallPromise;
+ if (reconciler) {
+ await reconciler.queueCaller.promiseCallsComplete();
+ }
}
async function generateNewKeys(collectionKeys, collections = null) {
let wbo = await collectionKeys.generateNewKeysWBO(collections);
let modified = new_timestamp();
collectionKeys.setContents(wbo.cleartext, modified);
}
--- a/services/sync/tests/unit/test_412.js
+++ b/services/sync/tests/unit/test_412.js
@@ -22,17 +22,17 @@ add_task(async function test_412_not_tre
try {
// Do sync.
_("initial sync to initialize the world");
await Service.sync();
// create a new record that should be uploaded and arrange for our lastSync
// timestamp to be wrong so we get a 412.
engine._store.items = {new: "new record"};
- engine._tracker.addChangedID("new", 0);
+ await engine._tracker.addChangedID("new", 0);
let saw412 = false;
let _uploadOutgoing = engine._uploadOutgoing;
engine._uploadOutgoing = async () => {
engine.lastSync -= 2;
try {
await _uploadOutgoing.call(engine);
} catch (ex) {
--- a/services/sync/tests/unit/test_addons_engine.js
+++ b/services/sync/tests/unit/test_addons_engine.js
@@ -22,17 +22,17 @@ let reconciler;
let tracker;
async function resetReconciler() {
reconciler._addons = {};
reconciler._changes = [];
await reconciler.saveState();
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
}
add_task(async function setup() {
loadAddonTestFunctions();
startupManager();
await Service.engineManager.register(AddonsEngine);
engine = Service.engineManager.get("addons");
@@ -63,72 +63,72 @@ add_task(async function test_addon_insta
add_task(async function test_find_dupe() {
_("Ensure the _findDupe() implementation is sane.");
// This gets invoked at the top of sync, which is bypassed by this
// test, so we do it manually.
await engine._refreshReconcilerState();
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
let record = {
id: Utils.makeGUID(),
addonID: addon.id,
enabled: true,
applicationID: Services.appinfo.ID,
source: "amo"
};
let dupe = await engine._findDupe(record);
Assert.equal(addon.syncGUID, dupe);
record.id = addon.syncGUID;
dupe = await engine._findDupe(record);
Assert.equal(null, dupe);
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
await resetReconciler();
});
add_task(async function test_get_changed_ids() {
_("Ensure getChangedIDs() has the appropriate behavior.");
_("Ensure getChangedIDs() returns an empty object by default.");
let changes = await engine.getChangedIDs();
Assert.equal("object", typeof(changes));
Assert.equal(0, Object.keys(changes).length);
_("Ensure tracker changes are populated.");
let now = new Date();
let changeTime = now.getTime() / 1000;
let guid1 = Utils.makeGUID();
- tracker.addChangedID(guid1, changeTime);
+ await tracker.addChangedID(guid1, changeTime);
changes = await engine.getChangedIDs();
Assert.equal("object", typeof(changes));
Assert.equal(1, Object.keys(changes).length);
Assert.ok(guid1 in changes);
Assert.equal(changeTime, changes[guid1]);
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
_("Ensure reconciler changes are populated.");
- let addon = await installAddon("test_bootstrap1_1");
- tracker.clearChangedIDs(); // Just in case.
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
+ await tracker.clearChangedIDs(); // Just in case.
changes = await engine.getChangedIDs();
Assert.equal("object", typeof(changes));
Assert.equal(1, Object.keys(changes).length);
Assert.ok(addon.syncGUID in changes);
_("Change time: " + changeTime + ", addon change: " + changes[addon.syncGUID]);
Assert.ok(changes[addon.syncGUID] >= changeTime);
let oldTime = changes[addon.syncGUID];
let guid2 = addon.syncGUID;
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
changes = await engine.getChangedIDs();
Assert.equal(1, Object.keys(changes).length);
Assert.ok(guid2 in changes);
Assert.ok(changes[guid2] > oldTime);
_("Ensure non-syncable add-ons aren't picked up by reconciler changes.");
reconciler._addons = {};
reconciler._changes = [];
--- a/services/sync/tests/unit/test_addons_reconciler.js
+++ b/services/sync/tests/unit/test_addons_reconciler.js
@@ -1,58 +1,65 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
+ChromeUtils.import("resource://services-common/async.js");
ChromeUtils.import("resource://services-sync/addonsreconciler.js");
ChromeUtils.import("resource://services-sync/engines/addons.js");
ChromeUtils.import("resource://services-sync/service.js");
ChromeUtils.import("resource://services-sync/util.js");
loadAddonTestFunctions();
startupManager();
-add_task(async function run_test() {
+function makeAddonsReconciler() {
+ const log = Service.engineManager.get("addons")._log;
+ const queueCaller = Async.asyncQueueCaller(log);
+ return new AddonsReconciler(queueCaller);
+}
+
+add_task(async function setup() {
Svc.Prefs.set("engine.addons", true);
await Service.engineManager.register(AddonsEngine);
});
add_task(async function test_defaults() {
_("Ensure new objects have reasonable defaults.");
- let reconciler = new AddonsReconciler();
+ let reconciler = makeAddonsReconciler();
await reconciler.ensureStateLoaded();
Assert.ok(!reconciler._listening);
Assert.equal("object", typeof(reconciler.addons));
Assert.equal(0, Object.keys(reconciler.addons).length);
Assert.equal(0, reconciler._changes.length);
Assert.equal(0, reconciler._listeners.length);
});
add_task(async function test_load_state_empty_file() {
_("Ensure loading from a missing file results in defaults being set.");
- let reconciler = new AddonsReconciler();
+ let reconciler = makeAddonsReconciler();
await reconciler.ensureStateLoaded();
let loaded = await reconciler.loadState();
Assert.ok(!loaded);
Assert.equal("object", typeof(reconciler.addons));
Assert.equal(0, Object.keys(reconciler.addons).length);
Assert.equal(0, reconciler._changes.length);
});
add_task(async function test_install_detection() {
_("Ensure that add-on installation results in appropriate side-effects.");
- let reconciler = new AddonsReconciler();
+ let reconciler = makeAddonsReconciler();
await reconciler.ensureStateLoaded();
reconciler.startListening();
let before = new Date();
let addon = await installAddon("test_bootstrap1_1");
let after = new Date();
Assert.equal(1, Object.keys(reconciler.addons).length);
@@ -81,28 +88,28 @@ add_task(async function test_install_det
Assert.equal(addon.id, change[2]);
await uninstallAddon(addon);
});
add_task(async function test_uninstall_detection() {
_("Ensure that add-on uninstallation results in appropriate side-effects.");
- let reconciler = new AddonsReconciler();
+ let reconciler = makeAddonsReconciler();
await reconciler.ensureStateLoaded();
reconciler.startListening();
reconciler._addons = {};
reconciler._changes = [];
let addon = await installAddon("test_bootstrap1_1");
let id = addon.id;
reconciler._changes = [];
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
Assert.equal(1, Object.keys(reconciler.addons).length);
Assert.ok(id in reconciler.addons);
let record = reconciler.addons[id];
Assert.ok(!record.installed);
Assert.equal(1, reconciler._changes.length);
@@ -111,17 +118,17 @@ add_task(async function test_uninstall_d
Assert.equal(id, change[2]);
});
add_task(async function test_load_state_future_version() {
_("Ensure loading a file from a future version results in no data loaded.");
const FILENAME = "TEST_LOAD_STATE_FUTURE_VERSION";
- let reconciler = new AddonsReconciler();
+ let reconciler = makeAddonsReconciler();
await reconciler.ensureStateLoaded();
// First we populate our new file.
let state = {version: 100, addons: {foo: {}}, changes: [[1, 1, "foo"]]};
// jsonSave() expects an object with ._log, so we give it a reconciler
// instance.
await Utils.jsonSave(FILENAME, reconciler, state);
@@ -132,17 +139,17 @@ add_task(async function test_load_state_
Assert.equal("object", typeof(reconciler.addons));
Assert.equal(0, Object.keys(reconciler.addons).length);
Assert.equal(0, reconciler._changes.length);
});
add_task(async function test_prune_changes_before_date() {
_("Ensure that old changes are pruned properly.");
- let reconciler = new AddonsReconciler();
+ let reconciler = makeAddonsReconciler();
await reconciler.ensureStateLoaded();
reconciler._changes = [];
let now = new Date();
const HOUR_MS = 1000 * 60 * 60;
_("Ensure pruning an empty changes array works.");
reconciler.pruneChangesBeforeDate(now);
--- a/services/sync/tests/unit/test_addons_store.js
+++ b/services/sync/tests/unit/test_addons_store.js
@@ -114,30 +114,30 @@ add_task(async function setup() {
// Don't flush to disk in the middle of an event listener!
// This causes test hangs on WinXP.
reconciler._shouldPersist = false;
});
add_task(async function test_remove() {
_("Ensure removing add-ons from deleted records works.");
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
let record = createRecordForThisApp(addon.syncGUID, addon.id, true, true);
let failed = await store.applyIncomingBatch([record]);
Assert.equal(0, failed.length);
let newAddon = await AddonManager.getAddonByID(addon.id);
Assert.equal(null, newAddon);
});
add_task(async function test_apply_enabled() {
_("Ensures that changes to the userEnabled flag apply.");
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
Assert.ok(addon.isActive);
Assert.ok(!addon.userDisabled);
_("Ensure application of a disable record works as expected.");
let records = [];
records.push(createRecordForThisApp(addon.syncGUID, addon.id, false, false));
let failed = await store.applyIncomingBatch(records);
Assert.equal(0, failed.length);
@@ -159,17 +159,17 @@ add_task(async function test_apply_enabl
records.push(createRecordForThisApp(addon.syncGUID, addon.id, false, false));
Svc.Prefs.set("addons.ignoreUserEnabledChanges", true);
failed = await store.applyIncomingBatch(records);
Assert.equal(0, failed.length);
addon = await AddonManager.getAddonByID(addon.id);
Assert.ok(!addon.userDisabled);
records = [];
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
Svc.Prefs.reset("addons.ignoreUserEnabledChanges");
});
add_task(async function test_apply_enabled_appDisabled() {
_("Ensures that changes to the userEnabled flag apply when the addon is appDisabled.");
let addon = await installAddon("test_install3"); // this addon is appDisabled by default.
Assert.ok(addon.appDisabled);
@@ -192,59 +192,59 @@ add_task(async function test_apply_enabl
records.push(createRecordForThisApp(addon.syncGUID, addon.id, true, false));
failed = await store.applyIncomingBatch(records);
Assert.equal(0, failed.length);
addon = await AddonManager.getAddonByID(addon.id);
Assert.ok(!addon.userDisabled);
await checkReconcilerUpToDate(addon);
records = [];
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
});
add_task(async function test_ignore_different_appid() {
_("Ensure that incoming records with a different application ID are ignored.");
// We test by creating a record that should result in an update.
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
Assert.ok(!addon.userDisabled);
let record = createRecordForThisApp(addon.syncGUID, addon.id, false, false);
record.applicationID = "FAKE_ID";
let failed = await store.applyIncomingBatch([record]);
Assert.equal(0, failed.length);
let newAddon = await AddonManager.getAddonByID(addon.id);
Assert.ok(!newAddon.userDisabled);
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
});
add_task(async function test_ignore_unknown_source() {
_("Ensure incoming records with unknown source are ignored.");
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
let record = createRecordForThisApp(addon.syncGUID, addon.id, false, false);
record.source = "DUMMY_SOURCE";
let failed = await store.applyIncomingBatch([record]);
Assert.equal(0, failed.length);
let newAddon = await AddonManager.getAddonByID(addon.id);
Assert.ok(!newAddon.userDisabled);
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
});
add_task(async function test_apply_uninstall() {
_("Ensures that uninstalling an add-on from a record works.");
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
let records = [];
records.push(createRecordForThisApp(addon.syncGUID, addon.id, true, true));
let failed = await store.applyIncomingBatch(records);
Assert.equal(0, failed.length);
addon = await AddonManager.getAddonByID(addon.id);
Assert.equal(null, addon);
@@ -253,17 +253,17 @@ add_task(async function test_apply_unins
add_task(async function test_addon_syncability() {
_("Ensure isAddonSyncable functions properly.");
Svc.Prefs.set("addons.trustedSourceHostnames",
"addons.mozilla.org,other.example.com");
Assert.ok(!(await store.isAddonSyncable(null)));
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
Assert.ok((await store.isAddonSyncable(addon)));
let dummy = {};
const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall", "isSyncable"];
for (let k of KEYS) {
dummy[k] = addon[k];
}
@@ -280,17 +280,17 @@ add_task(async function test_addon_synca
dummy.isSyncable = false;
Assert.ok(!(await store.isAddonSyncable(dummy)));
dummy.isSyncable = addon.isSyncable;
dummy.foreignInstall = true;
Assert.ok(!(await store.isAddonSyncable(dummy)));
dummy.foreignInstall = false;
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
Assert.ok(!store.isSourceURITrusted(null));
let trusted = [
"https://addons.mozilla.org/foo",
"https://other.example.com/foo"
];
@@ -324,76 +324,76 @@ add_task(async function test_get_all_ids
_("Installing two addons.");
// XXX - this test seems broken - at this point, before we've installed the
// addons below, store.getAllIDs() returns all addons installed by previous
// tests, even though those tests uninstalled the addon.
// So if any tests above ever add a new addon ID, they are going to need to
// be added here too.
// Assert.equal(0, Object.keys(store.getAllIDs()).length);
- let addon1 = await installAddon("test_install1");
- let addon2 = await installAddon("test_bootstrap1_1");
- let addon3 = await installAddon("test_install3");
+ let addon1 = await installAddon("test_install1", reconciler);
+ let addon2 = await installAddon("test_bootstrap1_1", reconciler);
+ let addon3 = await installAddon("test_install3", reconciler);
_("Ensure they're syncable.");
Assert.ok((await store.isAddonSyncable(addon1)));
Assert.ok((await store.isAddonSyncable(addon2)));
Assert.ok((await store.isAddonSyncable(addon3)));
let ids = await store.getAllIDs();
Assert.equal("object", typeof(ids));
Assert.equal(3, Object.keys(ids).length);
Assert.ok(addon1.syncGUID in ids);
Assert.ok(addon2.syncGUID in ids);
Assert.ok(addon3.syncGUID in ids);
addon1.install.cancel();
- await uninstallAddon(addon2);
- await uninstallAddon(addon3);
+ await uninstallAddon(addon2, reconciler);
+ await uninstallAddon(addon3, reconciler);
});
add_task(async function test_change_item_id() {
_("Ensures that changeItemID() works properly.");
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
let oldID = addon.syncGUID;
let newID = Utils.makeGUID();
await store.changeItemID(oldID, newID);
let newAddon = await AddonManager.getAddonByID(addon.id);
Assert.notEqual(null, newAddon);
Assert.equal(newID, newAddon.syncGUID);
- await uninstallAddon(newAddon);
+ await uninstallAddon(newAddon, reconciler);
});
add_task(async function test_create() {
_("Ensure creating/installing an add-on from a record works.");
let server = createAndStartHTTPServer(HTTP_PORT);
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
let id = addon.id;
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
let guid = Utils.makeGUID();
let record = createRecordForThisApp(guid, id, true, false);
let failed = await store.applyIncomingBatch([record]);
Assert.equal(0, failed.length);
let newAddon = await AddonManager.getAddonByID(id);
Assert.notEqual(null, newAddon);
Assert.equal(guid, newAddon.syncGUID);
Assert.ok(!newAddon.userDisabled);
- await uninstallAddon(newAddon);
+ await uninstallAddon(newAddon, reconciler);
await promiseStopServer(server);
});
add_task(async function test_create_missing_search() {
_("Ensures that failed add-on searches are handled gracefully.");
let server = createAndStartHTTPServer(HTTP_PORT);
@@ -481,31 +481,31 @@ add_task(async function test_incoming_sy
Assert.ok(!(await AddonManager.getAddonByID(SYSTEM_ADDON_ID).userDisabled));
await promiseStopServer(server);
});
add_task(async function test_wipe() {
_("Ensures that wiping causes add-ons to be uninstalled.");
- let addon1 = await installAddon("test_bootstrap1_1");
+ let addon1 = await installAddon("test_bootstrap1_1", reconciler);
await store.wipe();
let addon = await AddonManager.getAddonByID(addon1.id);
Assert.equal(null, addon);
});
add_task(async function test_wipe_and_install() {
_("Ensure wipe followed by install works.");
// This tests the reset sync flow where remote data is replaced by local. The
// receiving client will see a wipe followed by a record which should undo
// the wipe.
- let installed = await installAddon("test_bootstrap1_1");
+ let installed = await installAddon("test_bootstrap1_1", reconciler);
let record = createRecordForThisApp(installed.syncGUID, installed.id, true,
false);
await store.wipe();
let deleted = await AddonManager.getAddonByID(installed.id);
Assert.equal(null, deleted);
--- a/services/sync/tests/unit/test_addons_tracker.js
+++ b/services/sync/tests/unit/test_addons_tracker.js
@@ -16,21 +16,20 @@ Svc.Prefs.set("engine.addons", true);
let engine;
let reconciler;
let store;
let tracker;
const addon1ID = "addon1@tests.mozilla.org";
async function cleanup() {
- Svc.Obs.notify("weave:engine:stop-tracking");
- tracker.stopTracking();
+ tracker.stop();
tracker.resetScore();
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
reconciler._addons = {};
reconciler._changes = [];
await reconciler.saveState();
}
add_task(async function setup() {
await Service.engineManager.register(AddonsEngine);
@@ -43,84 +42,84 @@ add_task(async function setup() {
tracker.persistChangedIDs = false;
await cleanup();
});
add_task(async function test_empty() {
_("Verify the tracker is empty to start with.");
- Assert.equal(0, Object.keys(tracker.changedIDs).length);
+ Assert.equal(0, Object.keys((await tracker.getChangedIDs())).length);
Assert.equal(0, tracker.score);
await cleanup();
});
add_task(async function test_not_tracking() {
_("Ensures the tracker doesn't do anything when it isn't tracking.");
- let addon = await installAddon("test_bootstrap1_1");
- await uninstallAddon(addon);
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
+ await uninstallAddon(addon, reconciler);
- Assert.equal(0, Object.keys(tracker.changedIDs).length);
+ Assert.equal(0, Object.keys((await tracker.getChangedIDs())).length);
Assert.equal(0, tracker.score);
await cleanup();
});
add_task(async function test_track_install() {
_("Ensure that installing an add-on notifies tracker.");
reconciler.startListening();
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
Assert.equal(0, tracker.score);
- let addon = await installAddon("test_bootstrap1_1");
- let changed = tracker.changedIDs;
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
+ let changed = await tracker.getChangedIDs();
Assert.equal(1, Object.keys(changed).length);
Assert.ok(addon.syncGUID in changed);
Assert.equal(SCORE_INCREMENT_XLARGE, tracker.score);
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
await cleanup();
});
add_task(async function test_track_uninstall() {
_("Ensure that uninstalling an add-on notifies tracker.");
reconciler.startListening();
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
let guid = addon.syncGUID;
Assert.equal(0, tracker.score);
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
- await uninstallAddon(addon);
- let changed = tracker.changedIDs;
+ await uninstallAddon(addon, reconciler);
+ let changed = await tracker.getChangedIDs();
Assert.equal(1, Object.keys(changed).length);
Assert.ok(guid in changed);
Assert.equal(SCORE_INCREMENT_XLARGE, tracker.score);
await cleanup();
});
add_task(async function test_track_user_disable() {
_("Ensure that tracker sees disabling of add-on");
reconciler.startListening();
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
Assert.ok(!addon.userDisabled);
Assert.ok(!addon.appDisabled);
Assert.ok(addon.isActive);
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
Assert.equal(0, tracker.score);
let disabledPromise = new Promise(res => {
let listener = {
onDisabled(disabled) {
_("onDisabled");
if (disabled.id == addon.id) {
AddonManager.removeAddonListener(listener);
@@ -133,41 +132,43 @@ add_task(async function test_track_user_
};
AddonManager.addAddonListener(listener);
});
_("Disabling add-on");
addon.userDisabled = true;
_("Disabling started...");
await disabledPromise;
+ await reconciler.queueCaller.promiseCallsComplete();
- let changed = tracker.changedIDs;
+ let changed = await tracker.getChangedIDs();
Assert.equal(1, Object.keys(changed).length);
Assert.ok(addon.syncGUID in changed);
Assert.equal(SCORE_INCREMENT_XLARGE, tracker.score);
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
await cleanup();
});
add_task(async function test_track_enable() {
_("Ensure that enabling a disabled add-on notifies tracker.");
reconciler.startListening();
- let addon = await installAddon("test_bootstrap1_1");
+ let addon = await installAddon("test_bootstrap1_1", reconciler);
addon.userDisabled = true;
await Async.promiseYield();
Assert.equal(0, tracker.score);
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
addon.userDisabled = false;
await Async.promiseYield();
+ await reconciler.queueCaller.promiseCallsComplete();
- let changed = tracker.changedIDs;
+ let changed = await tracker.getChangedIDs();
Assert.equal(1, Object.keys(changed).length);
Assert.ok(addon.syncGUID in changed);
Assert.equal(SCORE_INCREMENT_XLARGE, tracker.score);
- await uninstallAddon(addon);
+ await uninstallAddon(addon, reconciler);
await cleanup();
});
--- a/services/sync/tests/unit/test_bookmark_duping.js
+++ b/services/sync/tests/unit/test_bookmark_duping.js
@@ -18,23 +18,23 @@ async function sharedSetup() {
let engine = new BookmarksEngine(Service);
await engine.initialize();
let store = engine._store;
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("bookmarks");
- Svc.Obs.notify("weave:engine:start-tracking"); // We skip usual startup...
+ engine._tracker.start(); // We skip usual startup...
return { engine, store, server, collection };
}
async function cleanup(engine, server) {
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await engine._tracker.stop();
let promiseStartOver = promiseOneObserver("weave:service:start-over:finish");
await Service.startOver();
await promiseStartOver;
await promiseStopServer(server);
await bms.eraseEverything();
await engine.resetClient();
await engine.finalize();
}
--- a/services/sync/tests/unit/test_bookmark_engine.js
+++ b/services/sync/tests/unit/test_bookmark_engine.js
@@ -64,17 +64,17 @@ add_bookmark_test(async function test_de
_("Ensure that we delete the Places and Reading List roots from the server.");
let store = engine._store;
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("bookmarks");
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
try {
let placesRecord = await store.createRecord("places");
collection.insert("places", encryptPayload(placesRecord.cleartext));
let listBmk = new Bookmark("bookmarks", Utils.makeGUID());
listBmk.bmkUri = "https://example.com";
listBmk.title = "Example reading list entry";
@@ -111,17 +111,17 @@ add_bookmark_test(async function test_de
deepEqual(collection.keys().sort(), ["menu", "mobile", "toolbar", "unfiled", newBmk.id].sort(),
"Should remove Places root and reading list items from server; upload local roots");
} finally {
await store.wipe();
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
await promiseStopServer(server);
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await engine._tracker.stop();
}
});
add_task(async function bad_record_allIDs() {
let server = new SyncServer();
server.start();
await SyncTestingInfrastructure(server);
@@ -249,17 +249,17 @@ async function test_restoreOrImport(engi
_(`Ensure that ${verbing} from a backup will reupload all records.`);
let store = engine._store;
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("bookmarks");
- Svc.Obs.notify("weave:engine:start-tracking"); // We skip usual startup...
+ engine._tracker.start(); // We skip usual startup...
try {
let folder1 = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title: "Folder 1",
});
@@ -303,16 +303,17 @@ async function test_restoreOrImport(engi
let wbos = collection.keys(function(id) {
return ["menu", "toolbar", "mobile", "unfiled", folder1.guid].indexOf(id) == -1;
});
Assert.equal(wbos.length, 1);
Assert.equal(wbos[0], bmk2.guid);
_(`Now ${verb} from a backup.`);
await bookmarkUtils.importFromFile(backupFilePath, replace);
+ await engine._tracker.asyncObserver.promiseObserversComplete();
let bookmarksCollection = server.user("foo").collection("bookmarks");
if (replace) {
_("Verify that we wiped the server.");
Assert.ok(!bookmarksCollection);
} else {
_("Verify that we didn't wipe the server.");
Assert.ok(!!bookmarksCollection);
@@ -695,17 +696,17 @@ add_bookmark_test(async function test_sy
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("bookmarks");
// TODO: Avoid random orange (bug 1374599), this is only necessary
// intermittently - reset the last sync date so that we'll get all bookmarks.
await engine.setLastSync(1);
- Svc.Obs.notify("weave:engine:start-tracking"); // We skip usual startup...
+ engine._tracker.start(); // We skip usual startup...
// Just matters that it's in the past, not how far.
let now = Date.now();
let oneYearMS = 365 * 24 * 60 * 60 * 1000;
try {
let item1GUID = "abcdefabcdef";
let item1 = new Bookmark("bookmarks", item1GUID);
@@ -844,17 +845,17 @@ add_task(async function test_sync_imap_U
let engine = new BookmarksEngine(Service);
await engine.initialize();
let store = engine._store;
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("bookmarks");
- Svc.Obs.notify("weave:engine:start-tracking"); // We skip usual startup...
+ engine._tracker.start(); // We skip usual startup...
try {
collection.insert("menu", encryptPayload({
id: "menu",
type: "folder",
parentid: "places",
title: "Bookmarks Menu",
children: ["bookmarkAAAA"],
--- a/services/sync/tests/unit/test_bookmark_store.js
+++ b/services/sync/tests/unit/test_bookmark_store.js
@@ -332,17 +332,17 @@ add_task(async function test_move_folder
});
add_task(async function test_move_order() {
let engine = new BookmarksEngine(Service);
let store = engine._store;
let tracker = engine._tracker;
// Make sure the tracker is turned on.
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
try {
_("Create two bookmarks");
let bmk1 = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
url: "http://getfirefox.com/",
title: "Get Firefox!",
});
let bmk2 = await PlacesUtils.bookmarks.insert({
@@ -369,17 +369,17 @@ add_task(async function test_move_order(
delete store._childrenToOrder;
_("Verify new order.");
let newChildIds = await PlacesSyncUtils.bookmarks.fetchChildRecordIds(
"toolbar");
Assert.deepEqual(newChildIds, [bmk2.guid, bmk1.guid]);
} finally {
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.stop();
_("Clean up.");
await store.wipe();
await engine.finalize();
}
});
add_task(async function test_orphan() {
let engine = new BookmarksEngine(Service);
--- a/services/sync/tests/unit/test_bookmark_tracker.js
+++ b/services/sync/tests/unit/test_bookmark_tracker.js
@@ -22,62 +22,58 @@ add_task(async function setup() {
store = engine._store;
tracker = engine._tracker;
tracker.persistChangedIDs = false;
});
// Test helpers.
async function verifyTrackerEmpty() {
await PlacesTestUtils.promiseAsyncUpdates();
- let changes = await tracker.promiseChangedIDs();
+ let changes = await tracker.getChangedIDs();
deepEqual(changes, {});
equal(tracker.score, 0);
}
async function resetTracker() {
await PlacesTestUtils.markBookmarksAsSynced();
tracker.resetScore();
}
async function cleanup() {
engine.lastSync = 0;
engine._needWeakUpload.clear();
await store.wipe();
await resetTracker();
- await stopTracking();
+ await tracker.stop();
}
// startTracking is a signal that the test wants to notice things that happen
// after this is called (ie, things already tracked should be discarded.)
async function startTracking() {
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
await PlacesTestUtils.markBookmarksAsSynced();
}
-async function stopTracking() {
- Svc.Obs.notify("weave:engine:stop-tracking");
-}
-
async function verifyTrackedItems(tracked) {
await PlacesTestUtils.promiseAsyncUpdates();
- let changedIDs = await tracker.promiseChangedIDs();
+ let changedIDs = await tracker.getChangedIDs();
let trackedIDs = new Set(Object.keys(changedIDs));
for (let guid of tracked) {
ok(guid in changedIDs, `${guid} should be tracked`);
ok(changedIDs[guid].modified > 0, `${guid} should have a modified time`);
ok(changedIDs[guid].counter >= -1, `${guid} should have a change counter`);
trackedIDs.delete(guid);
}
equal(trackedIDs.size, 0, `Unhandled tracked IDs: ${
JSON.stringify(Array.from(trackedIDs))}`);
}
async function verifyTrackedCount(expected) {
await PlacesTestUtils.promiseAsyncUpdates();
- let changedIDs = await tracker.promiseChangedIDs();
+ let changedIDs = await tracker.getChangedIDs();
do_check_attribute_count(changedIDs, expected);
}
// A debugging helper that dumps the full bookmarks tree.
async function dumpBookmarks() {
let columns = ["id", "title", "guid", "syncStatus", "syncChangeCounter", "position"];
return PlacesUtils.promiseDBConnection().then(connection => {
let all = [];
@@ -185,27 +181,27 @@ add_task(async function test_leftPaneFol
await startTracking();
// Creates the organizer queries as a side effect.
let leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID: ${leftPaneId}`);
{
await PlacesTestUtils.promiseAsyncUpdates();
- let changes = await tracker.promiseChangedIDs();
+ let changes = await tracker.getChangedIDs();
deepEqual(changes, {}, "New left pane queries should not be tracked");
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE);
}
_("Reset synced bookmarks to simulate a disconnect");
await PlacesSyncUtils.bookmarks.reset();
{
await PlacesTestUtils.promiseAsyncUpdates();
- let changes = await tracker.promiseChangedIDs();
+ let changes = await tracker.getChangedIDs();
deepEqual(Object.keys(changes).sort(), ["menu", "mobile", "toolbar", "unfiled"],
"Left pane queries should not be tracked after reset");
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE);
await PlacesTestUtils.markBookmarksAsSynced();
}
// The following tests corrupt the left pane queries in different ways.
// `PlacesUIUtils.maybeRebuildLeftPane` will rebuild the entire root, but
@@ -221,45 +217,45 @@ add_task(async function test_leftPaneFol
let folderId = await PlacesUtils.promiseItemId(folder.guid);
await setAnnoUnchecked(folderId, PlacesUIUtils.ORGANIZER_FOLDER_ANNO, 0,
PlacesUtils.annotations.TYPE_INT32);
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after deleting unrelated folder: ${leftPaneId}`);
await PlacesTestUtils.promiseAsyncUpdates();
- let changes = await tracker.promiseChangedIDs();
+ let changes = await tracker.getChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after deleting unrelated folder");
}
_("Corrupt organizer left pane version");
{
await setAnnoUnchecked(leftPaneId, PlacesUIUtils.ORGANIZER_FOLDER_ANNO,
-1, PlacesUtils.annotations.TYPE_INT32);
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after restoring version: ${leftPaneId}`);
await PlacesTestUtils.promiseAsyncUpdates();
- let changes = await tracker.promiseChangedIDs();
+ let changes = await tracker.getChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after restoring version");
}
_("Set left pane anno on nonexistent item");
{
await setAnnoUnchecked(999, PlacesUIUtils.ORGANIZER_QUERY_ANNO,
"Tags", PlacesUtils.annotations.TYPE_STRING);
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after detecting nonexistent item: ${leftPaneId}`);
await PlacesTestUtils.promiseAsyncUpdates();
- let changes = await tracker.promiseChangedIDs();
+ let changes = await tracker.getChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after detecting nonexistent item");
}
_("Move query out of left pane root");
{
let queryId = await PlacesUIUtils.leftPaneQueries.Downloads;
let queryGuid = await PlacesUtils.promiseItemGuid(queryId);
@@ -268,17 +264,17 @@ add_task(async function test_leftPaneFol
parentGuid: PlacesUtils.bookmarks.rootGuid,
index: PlacesUtils.bookmarks.DEFAULT_INDEX,
});
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after restoring moved query: ${leftPaneId}`);
await PlacesTestUtils.promiseAsyncUpdates();
- let changes = await tracker.promiseChangedIDs();
+ let changes = await tracker.getChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after restoring moved query");
}
_("Add duplicate query");
{
let leftPaneGuid = await PlacesUtils.promiseItemGuid(leftPaneId);
let query = await PlacesUtils.bookmarks.insert({
@@ -288,17 +284,17 @@ add_task(async function test_leftPaneFol
let queryId = await PlacesUtils.promiseItemId(query.guid);
await setAnnoUnchecked(queryId, PlacesUIUtils.ORGANIZER_QUERY_ANNO,
"Tags", PlacesUtils.annotations.TYPE_STRING);
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after removing dupe query: ${leftPaneId}`);
await PlacesTestUtils.promiseAsyncUpdates();
- let changes = await tracker.promiseChangedIDs();
+ let changes = await tracker.getChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after removing dupe query");
}
} finally {
_("Clean up.");
await cleanup();
}
});
@@ -520,17 +516,17 @@ add_task(async function test_async_onIte
await cleanup();
}
});
add_task(async function test_async_onItemChanged() {
_("Items updated using the asynchronous bookmarks API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert a bookmark");
let fxBmk = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.menuGuid,
url: "http://getfirefox.com",
title: "Get Firefox!",
});
@@ -555,17 +551,17 @@ add_task(async function test_async_onIte
await cleanup();
}
});
add_task(async function test_onItemChanged_itemDates() {
_("Changes to item dates should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert a bookmark");
let fx_id = PlacesUtils.bookmarks.insertBookmark(
PlacesUtils.bookmarks.bookmarksMenuFolder,
CommonUtils.makeURI("http://getfirefox.com"),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"Get Firefox!");
let fx_guid = await PlacesUtils.promiseItemGuid(fx_id);
@@ -591,17 +587,17 @@ add_task(async function test_onItemChang
await cleanup();
}
});
add_task(async function test_onItemTagged() {
_("Items tagged using the synchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Create a folder");
let folder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
PlacesUtils.bookmarks.DEFAULT_INDEX);
let folderGUID = await PlacesUtils.promiseItemGuid(folder);
_("Folder ID: " + folder);
_("Folder GUID: " + folderGUID);
@@ -628,17 +624,17 @@ add_task(async function test_onItemTagge
await cleanup();
}
});
add_task(async function test_onItemUntagged() {
_("Items untagged using the synchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert tagged bookmarks");
let uri = CommonUtils.makeURI("http://getfirefox.com");
let fx1ID = PlacesUtils.bookmarks.insertBookmark(
PlacesUtils.bookmarks.bookmarksMenuFolder, uri,
PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
let fx1GUID = await PlacesUtils.promiseItemGuid(fx1ID);
// Different parent and title; same URL.
@@ -660,17 +656,17 @@ add_task(async function test_onItemUntag
await cleanup();
}
});
add_task(async function test_async_onItemUntagged() {
_("Items untagged using the asynchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert tagged bookmarks");
let fxBmk1 = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.menuGuid,
url: "http://getfirefox.com",
title: "Get Firefox!",
});
@@ -703,17 +699,17 @@ add_task(async function test_async_onIte
await cleanup();
}
});
add_task(async function test_async_onItemTagged() {
_("Items tagged using the asynchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert untagged bookmarks");
let folder1 = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_FOLDER,
parentGuid: PlacesUtils.bookmarks.menuGuid,
title: "Folder 1",
});
let fxBmk1 = await PlacesUtils.bookmarks.insert({
@@ -761,17 +757,17 @@ add_task(async function test_async_onIte
await cleanup();
}
});
add_task(async function test_onItemKeywordChanged() {
_("Keyword changes via the synchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
let folder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
PlacesUtils.bookmarks.DEFAULT_INDEX);
_("Track changes to keywords");
let uri = CommonUtils.makeURI("http://getfirefox.com");
let b = PlacesUtils.bookmarks.insertBookmark(
folder, uri,
PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
@@ -793,17 +789,17 @@ add_task(async function test_onItemKeywo
await cleanup();
}
});
add_task(async function test_async_onItemKeywordChanged() {
_("Keyword changes via the asynchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert two bookmarks with the same URL");
let fxBmk1 = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.menuGuid,
url: "http://getfirefox.com",
title: "Get Firefox!",
});
@@ -830,17 +826,17 @@ add_task(async function test_async_onIte
await cleanup();
}
});
add_task(async function test_async_onItemKeywordDeleted() {
_("Keyword deletions via the asynchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert two bookmarks with the same URL and keywords");
let fxBmk1 = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.menuGuid,
url: "http://getfirefox.com",
title: "Get Firefox!",
});
@@ -863,50 +859,21 @@ add_task(async function test_async_onIte
await verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 2);
} finally {
_("Clean up.");
await cleanup();
}
});
-add_task(async function test_onItemPostDataChanged() {
- _("Post data changes should be tracked");
-
- try {
- await stopTracking();
-
- _("Insert a bookmark");
- let fx_id = PlacesUtils.bookmarks.insertBookmark(
- PlacesUtils.bookmarks.bookmarksMenuFolder,
- CommonUtils.makeURI("http://getfirefox.com"),
- PlacesUtils.bookmarks.DEFAULT_INDEX,
- "Get Firefox!");
- let fx_guid = await PlacesUtils.promiseItemGuid(fx_id);
- _(`Firefox GUID: ${fx_guid}`);
-
- await startTracking();
-
- // PlacesUtils.setPostDataForBookmark is deprecated, but still used by
- // PlacesTransactions.NewBookmark.
- _("Post data for the bookmark should be ignored");
- await PlacesUtils.setPostDataForBookmark(fx_id, "postData");
- await verifyTrackedItems([]);
- Assert.equal(tracker.score, 0);
- } finally {
- _("Clean up.");
- await cleanup();
- }
-});
-
add_task(async function test_onItemAnnoChanged() {
_("Item annotations should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
let folder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
PlacesUtils.bookmarks.DEFAULT_INDEX);
_("Track changes to annos.");
let b = PlacesUtils.bookmarks.insertBookmark(
folder, CommonUtils.makeURI("http://getfirefox.com"),
PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
let bGUID = await PlacesUtils.promiseItemGuid(b);
@@ -971,17 +938,17 @@ add_task(async function test_onItemAdded
await cleanup();
}
});
add_task(async function test_onItemDeleted_filtered_root() {
_("Deleted items outside the change roots should not be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert a bookmark underneath the Places root");
let rootBmkID = PlacesUtils.bookmarks.insertBookmark(
PlacesUtils.bookmarks.placesRoot,
CommonUtils.makeURI("http://getfirefox.com"),
PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
let rootBmkGUID = await PlacesUtils.promiseItemGuid(rootBmkID);
_(`New Places root bookmark GUID: ${rootBmkGUID}`);
@@ -998,17 +965,17 @@ add_task(async function test_onItemDelet
await cleanup();
}
});
add_task(async function test_onPageAnnoChanged() {
_("Page annotations should not be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert a bookmark without an annotation");
let pageURI = CommonUtils.makeURI("http://getfirefox.com");
PlacesUtils.bookmarks.insertBookmark(
PlacesUtils.bookmarks.bookmarksMenuFolder,
pageURI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"Get Firefox!");
@@ -1032,17 +999,17 @@ add_task(async function test_onPageAnnoC
await cleanup();
}
});
add_task(async function test_onFaviconChanged() {
_("Favicon changes should not be tracked");
try {
- await stopTracking();
+ await tracker.stop();
let pageURI = CommonUtils.makeURI("http://getfirefox.com");
let iconURI = CommonUtils.makeURI("http://getfirefox.com/icon");
PlacesUtils.bookmarks.insertBookmark(
PlacesUtils.bookmarks.bookmarksMenuFolder,
pageURI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"Get Firefox!");
@@ -1098,17 +1065,17 @@ add_task(async function test_onLivemarkA
await cleanup();
}
});
add_task(async function test_onLivemarkDeleted() {
_("Deleted livemarks should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert a livemark");
let livemark = await PlacesUtils.livemarks.addLivemark({
parentGuid: PlacesUtils.bookmarks.menuGuid,
feedURI: CommonUtils.makeURI("http://localhost:0"),
});
livemark.terminate();
@@ -1168,17 +1135,17 @@ add_task(async function test_onItemMoved
await cleanup();
}
});
add_task(async function test_async_onItemMoved_update() {
_("Items moved via the asynchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.menuGuid,
url: "http://getfirefox.com",
title: "Get Firefox!",
});
let tbBmk = await PlacesUtils.bookmarks.insert({
@@ -1213,17 +1180,17 @@ add_task(async function test_async_onIte
await cleanup();
}
});
add_task(async function test_async_onItemMoved_reorder() {
_("Items reordered via the asynchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Insert out-of-order bookmarks");
let fxBmk = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.menuGuid,
url: "http://getfirefox.com",
title: "Get Firefox!",
});
@@ -1260,17 +1227,17 @@ add_task(async function test_async_onIte
await cleanup();
}
});
add_task(async function test_onItemDeleted_removeFolderTransaction() {
_("Folders removed in a transaction should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
_("Create a folder with two children");
let folder_id = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarks.bookmarksMenuFolder,
"Test folder",
PlacesUtils.bookmarks.DEFAULT_INDEX);
let folder_guid = await PlacesUtils.promiseItemGuid(folder_id);
_(`Folder GUID: ${folder_guid}`);
@@ -1393,17 +1360,17 @@ add_task(async function test_onItemDelet
await cleanup();
}
});
add_task(async function test_async_onItemDeleted() {
_("Bookmarks deleted via the asynchronous API should be tracked");
try {
- await stopTracking();
+ await tracker.stop();
let fxBmk = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.menuGuid,
url: "http://getfirefox.com",
title: "Get Firefox!",
});
await PlacesUtils.bookmarks.insert({
@@ -1425,17 +1392,17 @@ add_task(async function test_async_onIte
await cleanup();
}
});
add_task(async function test_async_onItemDeleted_eraseEverything() {
_("Erasing everything should track all deleted items");
try {
- await stopTracking();
+ await tracker.stop();
let fxBmk = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.mobileGuid,
url: "http://getfirefox.com",
title: "Get Firefox!",
});
_(`Firefox GUID: ${fxBmk.guid}`);
--- a/services/sync/tests/unit/test_clients_engine.js
+++ b/services/sync/tests/unit/test_clients_engine.js
@@ -53,17 +53,17 @@ async function syncClientsEngine(server)
}
add_task(async function setup() {
engine = Service.clientsEngine;
});
async function cleanup() {
Svc.Prefs.resetBranch("");
- engine._tracker.clearChangedIDs();
+ await engine._tracker.clearChangedIDs();
await engine._resetClient();
// un-cleanup the logs (the resetBranch will have reset their levels), since
// not all the tests use SyncTestingInfrastructure, and it's cheap.
syncTestLogging();
// We don't finalize storage at cleanup, since we use the same clients engine
// instance across all tests.
}
@@ -330,36 +330,39 @@ add_task(async function test_sync() {
add_task(async function test_client_name_change() {
_("Ensure client name change incurs a client record update.");
let tracker = engine._tracker;
engine.localID; // Needed to increase the tracker changedIDs count.
let initialName = engine.localName;
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
_("initial name: " + initialName);
// Tracker already has data, so clear it.
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
let initialScore = tracker.score;
- equal(Object.keys(tracker.changedIDs).length, 0);
+ let changedIDs = await tracker.getChangedIDs();
+ equal(Object.keys(changedIDs).length, 0);
Svc.Prefs.set("client.name", "new name");
+ await tracker.asyncObserver.promiseObserversComplete();
_("new name: " + engine.localName);
notEqual(initialName, engine.localName);
- equal(Object.keys(tracker.changedIDs).length, 1);
- ok(engine.localID in tracker.changedIDs);
+ changedIDs = await tracker.getChangedIDs();
+ equal(Object.keys(changedIDs).length, 1);
+ ok(engine.localID in changedIDs);
ok(tracker.score > initialScore);
ok(tracker.score >= SCORE_INCREMENT_XLARGE);
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.stop();
await cleanup();
});
add_task(async function test_last_modified() {
_("Ensure that remote records have a sane serverLastModified attribute.");
let now = Date.now() / 1000;
@@ -434,17 +437,19 @@ add_task(async function test_send_comman
equal(clientCommands.length, 1);
let command = clientCommands[0];
equal(command.command, action);
equal(command.args.length, 2);
deepEqual(command.args, args);
ok(command.flowID);
- notEqual(tracker.changedIDs[remoteId], undefined);
+
+ const changes = await tracker.getChangedIDs();
+ notEqual(changes[remoteId], undefined);
await cleanup();
});
// The browser UI might call _addClientCommand indirectly without awaiting on the returned promise.
// We need to make sure this doesn't result on commands not being saved.
add_task(async function test_add_client_command_race() {
let promises = [];
@@ -496,17 +501,18 @@ add_task(async function test_command_val
_("Ensuring command is sent: " + action);
equal(clientCommands.length, 1);
let command = clientCommands[0];
equal(command.command, action);
deepEqual(command.args, args);
notEqual(engine._tracker, undefined);
- notEqual(engine._tracker.changedIDs[remoteId], undefined);
+ const changes = await engine._tracker.getChangedIDs();
+ notEqual(changes[remoteId], undefined);
} else {
_("Ensuring command is scrubbed: " + action);
equal(clientCommands, undefined);
if (store._tracker) {
equal(engine._tracker[remoteId], undefined);
}
}
@@ -941,17 +947,17 @@ add_task(async function test_send_uri_to
let store = engine._store;
let remoteId = Utils.makeGUID();
let rec = new ClientsRec("clients", remoteId);
rec.name = "remote";
await store.create(rec);
await store.createRecord(remoteId, "clients");
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
let initialScore = tracker.score;
let uri = "http://www.mozilla.org/";
let title = "Title of the Page";
await engine.sendURIToClientForDisplay(uri, remoteId, title);
let newRecord = store._remoteClients[remoteId];
@@ -1532,30 +1538,30 @@ add_task(async function test_command_syn
}), Date.now() / 1000));
try {
equal(collection.count(), 2, "2 remote records written");
await syncClientsEngine(server);
equal(collection.count(), 3, "3 remote records written (+1 for the synced local record)");
await engine.sendCommand("wipeAll", []);
- engine._tracker.addChangedID(engine.localID);
+ await engine._tracker.addChangedID(engine.localID);
const getClientFxaDeviceId = sinon.stub(engine, "getClientFxaDeviceId", (id) => "fxa-" + id);
const engineMock = sinon.mock(engine);
let _notifyCollectionChanged = engineMock.expects("_notifyCollectionChanged")
.withArgs(["fxa-" + remoteId, "fxa-" + remoteId2]);
_("Syncing.");
await syncClientsEngine(server);
_notifyCollectionChanged.verify();
engineMock.restore();
getClientFxaDeviceId.restore();
} finally {
await cleanup();
- engine._tracker.clearChangedIDs();
+ await engine._tracker.clearChangedIDs();
try {
server.deleteCollections("foo");
} finally {
await promiseStopServer(server);
}
}
});
@@ -1743,21 +1749,23 @@ add_task(async function test_other_clien
}
});
add_task(async function device_disconnected_notification_updates_known_stale_clients() {
const spyUpdate = sinon.spy(engine, "updateKnownStaleClients");
Services.obs.notifyObservers(null, "fxaccounts:device_disconnected",
JSON.stringify({ isLocalDevice: false }));
+ await Service.asyncObserver.promiseObserversComplete();
ok(spyUpdate.calledOnce, "updateKnownStaleClients should be called");
spyUpdate.reset();
Services.obs.notifyObservers(null, "fxaccounts:device_disconnected",
JSON.stringify({ isLocalDevice: true }));
+ await Service.asyncObserver.promiseObserversComplete();
ok(spyUpdate.notCalled, "updateKnownStaleClients should not be called");
spyUpdate.restore();
});
add_task(async function update_known_stale_clients() {
const makeFakeClient = (id) => ({ id, fxaDeviceId: `fxa-${id}` });
const clients = [makeFakeClient("one"), makeFakeClient("two"), makeFakeClient("three")];
--- a/services/sync/tests/unit/test_engine.js
+++ b/services/sync/tests/unit/test_engine.js
@@ -1,12 +1,13 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
ChromeUtils.import("resource://gre/modules/osfile.jsm");
+ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
ChromeUtils.import("resource://services-common/observers.js");
ChromeUtils.import("resource://services-sync/engines.js");
ChromeUtils.import("resource://services-sync/service.js");
ChromeUtils.import("resource://services-sync/util.js");
function SteamStore(engine) {
Store.call(this, "Steam", engine);
this.wasWiped = false;
@@ -65,17 +66,17 @@ Observers.add("weave:engine:wipe-client:
Observers.add("weave:engine:sync:start", engineObserver);
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.clearChangedIDs();
await engine.finalize();
}
add_task(async function test_members() {
_("Engine object members");
let engine = new SteamEngine("Steam", Service);
Assert.equal(engine.Name, "Steam");
Assert.equal(engine.prefName, "steam");
@@ -118,37 +119,40 @@ add_task(async function test_invalidChan
let engine = new SteamEngine("Steam", Service);
let tracker = engine._tracker;
await tracker._beforeSave();
await OS.File.writeAtomic(tracker._storage.path, new TextEncoder().encode("5"),
{ tmpPath: tracker._storage.path + ".tmp" });
ok(!tracker._storage.dataReady);
- tracker.changedIDs.placeholder = true;
- deepEqual(tracker.changedIDs, { placeholder: true },
+ const changes = await tracker.getChangedIDs();
+ changes.placeholder = true;
+ deepEqual(changes, { placeholder: true },
"Accessing changed IDs should load changes from disk as a side effect");
ok(tracker._storage.dataReady);
- Assert.ok(tracker.changedIDs.placeholder);
+ Assert.ok(changes.placeholder);
await cleanup(engine);
});
add_task(async function test_wipeClient() {
_("Engine.wipeClient calls resetClient, wipes store, clears changed IDs");
let engine = new SteamEngine("Steam", Service);
Assert.ok(!engine.wasReset);
Assert.ok(!engine._store.wasWiped);
- Assert.ok(engine._tracker.addChangedID("a-changed-id"));
- Assert.ok("a-changed-id" in engine._tracker.changedIDs);
+ Assert.ok((await engine._tracker.addChangedID("a-changed-id")));
+ let changes = await engine._tracker.getChangedIDs();
+ Assert.ok("a-changed-id" in changes);
await engine.wipeClient();
Assert.ok(engine.wasReset);
Assert.ok(engine._store.wasWiped);
- Assert.equal(JSON.stringify(engine._tracker.changedIDs), "{}");
+ changes = await engine._tracker.getChangedIDs();
+ Assert.equal(JSON.stringify(changes), "{}");
Assert.equal(engineObserver.topics[0], "weave:engine:wipe-client:start");
Assert.equal(engineObserver.topics[1], "weave:engine:reset-client:start");
Assert.equal(engineObserver.topics[2], "weave:engine:reset-client:finish");
Assert.equal(engineObserver.topics[3], "weave:engine:wipe-client:finish");
await cleanup(engine);
});
@@ -192,28 +196,41 @@ add_task(async function test_sync() {
add_task(async function test_disabled_no_track() {
_("When an engine is disabled, its tracker is not tracking.");
let engine = new SteamEngine("Steam", Service);
let tracker = engine._tracker;
Assert.equal(engine, tracker.engine);
Assert.ok(!engine.enabled);
Assert.ok(!tracker._isTracking);
- do_check_empty(tracker.changedIDs);
+ let changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
Assert.ok(!tracker.engineIsEnabled());
- tracker.observe(null, "weave:engine:start-tracking", null);
Assert.ok(!tracker._isTracking);
- do_check_empty(tracker.changedIDs);
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
- engine.enabled = true;
- tracker.observe(null, "weave:engine:start-tracking", null);
+ let promisePrefChangeHandled = PromiseUtils.defer();
+ const origMethod = tracker.onEngineEnabledChanged;
+ tracker.onEngineEnabledChanged = async (...args) => {
+ await origMethod.apply(tracker, args);
+ promisePrefChangeHandled.resolve();
+ };
+
+ engine.enabled = true; // Also enables the tracker automatically.
+ await promisePrefChangeHandled.promise;
Assert.ok(tracker._isTracking);
- do_check_empty(tracker.changedIDs);
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
- tracker.addChangedID("abcdefghijkl");
- Assert.ok(0 < tracker.changedIDs.abcdefghijkl);
+ await tracker.addChangedID("abcdefghijkl");
+ changes = await tracker.getChangedIDs();
+ Assert.ok(0 < changes.abcdefghijkl);
+ promisePrefChangeHandled = PromiseUtils.defer();
Svc.Prefs.set("engine." + engine.prefName, false);
+ await promisePrefChangeHandled.promise;
Assert.ok(!tracker._isTracking);
- do_check_empty(tracker.changedIDs);
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
await cleanup(engine);
});
--- a/services/sync/tests/unit/test_engine_abort.js
+++ b/services/sync/tests/unit/test_engine_abort.js
@@ -57,11 +57,11 @@ add_task(async function test_processInco
}
Assert.equal(err, undefined);
await promiseStopServer(server);
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
- engine._tracker.clearChangedIDs();
+ await engine._tracker.clearChangedIDs();
await engine.finalize();
});
--- a/services/sync/tests/unit/test_engine_changes_during_sync.js
+++ b/services/sync/tests/unit/test_engine_changes_during_sync.js
@@ -20,17 +20,17 @@ const LoginInfo = Components.Constructor
async function assertChildGuids(folderGuid, expectedChildGuids, message) {
let tree = await PlacesUtils.promiseBookmarksTree(folderGuid);
let childGuids = tree.children.map(child => child.guid);
deepEqual(childGuids, expectedChildGuids, message);
}
async function cleanup(engine, server) {
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await engine._tracker.stop();
await engine._store.wipe();
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
await promiseStopServer(server);
}
add_task(async function test_history_change_during_sync() {
_("Ensure that we don't bump the score when applying history records.");
@@ -47,20 +47,21 @@ add_task(async function test_history_cha
let uploadOutgoing = engine._uploadOutgoing;
engine._uploadOutgoing = async function() {
engine._uploadOutgoing = uploadOutgoing;
try {
await uploadOutgoing.call(this);
} finally {
_("Inserting local history visit");
await addVisit("during_sync");
+ await engine._tracker.asyncObserver.promiseObserversComplete();
}
};
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
try {
let remoteRec = new HistoryRec("history", "UrOOuzE5QM-e");
remoteRec.histUri = "http://getfirefox.com/";
remoteRec.title = "Get Firefox!";
remoteRec.visits = [{
date: PlacesUtils.toPRTime(Date.now()),
type: PlacesUtils.history.TRANSITION_TYPED,
@@ -101,20 +102,21 @@ add_task(async function test_passwords_c
engine._uploadOutgoing = uploadOutgoing;
try {
await uploadOutgoing.call(this);
} finally {
_("Inserting local password");
let login = new LoginInfo("https://example.com", "", null, "username",
"password", "", "");
Services.logins.addLogin(login);
+ await engine._tracker.asyncObserver.promiseObserversComplete();
}
};
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
try {
let remoteRec = new LoginRec("passwords", "{765e3d6e-071d-d640-a83d-81a7eb62d3ed}");
remoteRec.formSubmitURL = "";
remoteRec.httpRealm = "";
remoteRec.hostname = "https://mozilla.org";
remoteRec.username = "username";
remoteRec.password = "sekrit";
@@ -157,20 +159,21 @@ add_task(async function test_prefs_chang
engine._uploadOutgoing = async function() {
engine._uploadOutgoing = uploadOutgoing;
try {
await uploadOutgoing.call(this);
} finally {
_("Updating local pref value");
// Change the value of a synced pref.
Services.prefs.setCharPref(TEST_PREF, "hello");
+ await engine._tracker.asyncObserver.promiseObserversComplete();
}
};
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
try {
// All synced prefs are stored in a single record, so we'll only ever
// have one record on the server. This test just checks that we don't
// track or upload prefs changed during the sync.
let guid = CommonUtils.encodeBase64URL(Services.appinfo.ID);
let remoteRec = new PrefRec("prefs", guid);
remoteRec.value = {
@@ -223,20 +226,21 @@ add_task(async function test_forms_chang
FormHistory.update([{
op: "add",
fieldname: "favoriteDrink",
value: "cocoa",
}], {
handleCompletion: resolve,
});
});
+ await engine._tracker.asyncObserver.promiseObserversComplete();
}
};
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
try {
// Add an existing remote form history entry. We shouldn't bump the score when
// we apply this record.
let remoteRec = new FormRec("forms", "Tl9dHgmJSR6FkyxS");
remoteRec.name = "name";
remoteRec.value = "alice";
collection.insert(remoteRec.id, encryptPayload(remoteRec.cleartext));
@@ -293,16 +297,17 @@ add_task(async function test_bookmark_ch
await uploadOutgoing.call(this);
} finally {
_("Inserting bookmark into local store");
bmk3 = await PlacesUtils.bookmarks.insert({
parentGuid: folder1.guid,
url: "https://mozilla.org/",
title: "Mozilla",
});
+ await engine._tracker.asyncObserver.promiseObserversComplete();
}
};
// New bookmarks that should be uploaded during the first sync.
let folder1 = await PlacesUtils.bookmarks.insert({
type: PlacesUtils.bookmarks.TYPE_FOLDER,
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
title: "Folder 1",
@@ -311,17 +316,17 @@ add_task(async function test_bookmark_ch
let tbBmk = await PlacesUtils.bookmarks.insert({
parentGuid: folder1.guid,
url: "http://getthunderbird.com/",
title: "Get Thunderbird!",
});
_(`Thunderbird GUID: ${tbBmk.guid}`);
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
try {
let bmk2_guid = "get-firefox1"; // New child of Folder 1, created remotely.
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
--- a/services/sync/tests/unit/test_extension_storage_tracker.js
+++ b/services/sync/tests/unit/test_extension_storage_tracker.js
@@ -18,22 +18,22 @@ add_task(async function setup() {
engine = Service.engineManager.get("extension-storage");
do_get_profile(); // so we can use FxAccounts
loadWebExtensionTestFunctions();
});
add_task(async function test_changing_extension_storage_changes_score() {
const tracker = engine._tracker;
const extension = {id: "my-extension-id"};
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
await withSyncContext(async function(context) {
await extensionStorageSync.set(extension, {"a": "b"}, context);
});
Assert.equal(tracker.score, SCORE_INCREMENT_MEDIUM);
tracker.resetScore();
await withSyncContext(async function(context) {
await extensionStorageSync.remove(extension, "a", context);
});
Assert.equal(tracker.score, SCORE_INCREMENT_MEDIUM);
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.stop();
});
--- a/services/sync/tests/unit/test_forms_tracker.js
+++ b/services/sync/tests/unit/test_forms_tracker.js
@@ -9,65 +9,74 @@ ChromeUtils.import("resource://services-
add_task(async function run_test() {
_("Verify we've got an empty tracker to work with.");
let engine = new FormEngine(Service);
await engine.initialize();
let tracker = engine._tracker;
// Don't do asynchronous writes.
tracker.persistChangedIDs = false;
- do_check_empty(tracker.changedIDs);
+ let changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
Log.repository.rootLogger.addAppender(new Log.DumpAppender());
async function addEntry(name, value) {
await engine._store.create({name, value});
+ await engine._tracker.asyncObserver.promiseObserversComplete();
}
async function removeEntry(name, value) {
let guid = await engine._findDupe({name, value});
await engine._store.remove({id: guid});
+ await engine._tracker.asyncObserver.promiseObserversComplete();
}
try {
_("Create an entry. Won't show because we haven't started tracking yet");
await addEntry("name", "John Doe");
- do_check_empty(tracker.changedIDs);
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
_("Tell the tracker to start tracking changes.");
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
await removeEntry("name", "John Doe");
await addEntry("email", "john@doe.com");
- do_check_attribute_count(tracker.changedIDs, 2);
+ changes = await tracker.getChangedIDs();
+ do_check_attribute_count(changes, 2);
_("Notifying twice won't do any harm.");
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
await addEntry("address", "Memory Lane");
- do_check_attribute_count(tracker.changedIDs, 3);
+ changes = await tracker.getChangedIDs();
+ do_check_attribute_count(changes, 3);
_("Check that ignoreAll is respected");
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
tracker.score = 0;
tracker.ignoreAll = true;
await addEntry("username", "johndoe123");
await addEntry("favoritecolor", "green");
await removeEntry("name", "John Doe");
tracker.ignoreAll = false;
- do_check_empty(tracker.changedIDs);
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
equal(tracker.score, 0);
_("Let's stop tracking again.");
- tracker.clearChangedIDs();
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.clearChangedIDs();
+ await tracker.stop();
await removeEntry("address", "Memory Lane");
- do_check_empty(tracker.changedIDs);
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
_("Notifying twice won't do any harm.");
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.stop();
await removeEntry("email", "john@doe.com");
- do_check_empty(tracker.changedIDs);
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
} finally {
_("Clean up.");
await engine._store.wipe();
}
});
--- a/services/sync/tests/unit/test_fxa_node_reassignment.js
+++ b/services/sync/tests/unit/test_fxa_node_reassignment.js
@@ -247,17 +247,17 @@ add_task(async function test_momentary_4
}
await syncAndExpectNodeReassignment(server,
"weave:service:sync:finish",
between,
"weave:service:sync:finish",
Service.storageURL + "rotary");
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await 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() {
enableValidationPrefs();
_("Test a failure for info/collections after login that's resolved by reassignment.");
--- a/services/sync/tests/unit/test_history_engine.js
+++ b/services/sync/tests/unit/test_history_engine.js
@@ -132,17 +132,17 @@ add_task(async function test_history_dow
});
add_task(async function test_history_visit_roundtrip() {
let engine = new HistoryEngine(Service);
await engine.initialize();
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
let id = "aaaaaaaaaaaa";
let oneHourMS = 60 * 60 * 1000;
// Insert a visit with a non-round microsecond timestamp (e.g. it's not evenly
// divisible by 1000). This will typically be the case for visits that occur
// during normal navigation.
let time = (Date.now() - oneHourMS) * 1000 + 555;
// We use the low level updatePlaces api since it lets us provide microseconds
@@ -187,17 +187,17 @@ add_task(async function test_history_vis
});
add_task(async function test_history_visit_dedupe_old() {
let engine = new HistoryEngine(Service);
await engine.initialize();
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
await PlacesUtils.history.insert({
url: "https://www.example.com",
visits: Array.from({ length: 25 }, (_, index) => ({
transition: PlacesUtils.history.TRANSITION_LINK,
date: new Date(Date.UTC(2017, 10, 1 + index)),
}))
});
--- a/services/sync/tests/unit/test_history_tracker.js
+++ b/services/sync/tests/unit/test_history_tracker.js
@@ -42,33 +42,25 @@ async function verifyTrackedItems(tracke
ok(guid in changes, `${guid} should be tracked`);
ok(changes[guid] > 0, `${guid} should have a modified time`);
trackedIDs.delete(guid);
}
equal(trackedIDs.size, 0, `Unhandled tracked IDs: ${
JSON.stringify(Array.from(trackedIDs))}`);
}
-async function startTracking() {
- Svc.Obs.notify("weave:engine:start-tracking");
-}
-
-async function stopTracking() {
- Svc.Obs.notify("weave:engine:stop-tracking");
-}
-
async function resetTracker() {
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
tracker.resetScore();
}
async function cleanup() {
await PlacesTestUtils.clearHistory();
await resetTracker();
- await stopTracking();
+ await tracker.stop();
}
add_task(async function test_empty() {
_("Verify we've got an empty, disabled tracker to work with.");
await verifyTrackerEmpty();
Assert.ok(!tracker._isTracking);
await cleanup();
@@ -97,40 +89,40 @@ add_task(async function test_start_track
// Turn this back off.
tracker.persistChangedIDs = false;
tracker._storage._save = save;
}
};
});
_("Tell the tracker to start tracking changes.");
- await startTracking();
+ tracker.start();
let scorePromise = promiseOneObserver("weave:engine:score:updated");
await addVisit("start_tracking");
await scorePromise;
_("Score updated in test_start_tracking.");
await verifyTrackedCount(1);
Assert.equal(tracker.score, SCORE_INCREMENT_SMALL);
await savePromise;
_("changedIDs written to disk. Proceeding.");
await cleanup();
});
add_task(async function test_start_tracking_twice() {
_("Verifying preconditions.");
- await startTracking();
+ tracker.start();
await addVisit("start_tracking_twice1");
await verifyTrackedCount(1);
Assert.equal(tracker.score, SCORE_INCREMENT_SMALL);
_("Notifying twice won't do any harm.");
- await startTracking();
+ tracker.start();
let scorePromise = promiseOneObserver("weave:engine:score:updated");
await addVisit("start_tracking_twice2");
await scorePromise;
_("Score updated in test_start_tracking_twice.");
await verifyTrackedCount(2);
Assert.equal(tracker.score, 2 * SCORE_INCREMENT_SMALL);
@@ -141,17 +133,17 @@ add_task(async function test_track_delet
_("Deletions are tracked.");
// This isn't present because we weren't tracking when it was visited.
await addVisit("track_delete");
let uri = CommonUtils.makeURI("http://getfirefox.com/track_delete");
let guid = await engine._store.GUIDForUri(uri.spec);
await verifyTrackerEmpty();
- await startTracking();
+ tracker.start();
let visitRemovedPromise = promiseVisit("removed", uri);
let scorePromise = promiseOneObserver("weave:engine:score:updated");
await PlacesUtils.history.remove(uri);
await Promise.all([scorePromise, visitRemovedPromise]);
await verifyTrackedItems([guid]);
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE);
@@ -161,17 +153,17 @@ add_task(async function test_track_delet
add_task(async function test_dont_track_expiration() {
_("Expirations are not tracked.");
let uriToRemove = await addVisit("to_remove");
let guidToRemove = await engine._store.GUIDForUri(uriToRemove.spec);
await resetTracker();
await verifyTrackerEmpty();
- await startTracking();
+ tracker.start();
let visitRemovedPromise = promiseVisit("removed", uriToRemove);
let scorePromise = promiseOneObserver("weave:engine:score:updated");
// Observe expiration.
Services.obs.addObserver(function onExpiration(aSubject, aTopic, aData) {
Services.obs.removeObserver(onExpiration, aTopic);
// Remove the remaining page to update its score.
PlacesUtils.history.remove(uriToRemove);
@@ -186,54 +178,54 @@ add_task(async function test_dont_track_
await Promise.all([scorePromise, visitRemovedPromise]);
await verifyTrackedItems([guidToRemove]);
await cleanup();
});
add_task(async function test_stop_tracking() {
_("Let's stop tracking again.");
- await stopTracking();
+ await tracker.stop();
await addVisit("stop_tracking");
await verifyTrackerEmpty();
await cleanup();
});
add_task(async function test_stop_tracking_twice() {
- await stopTracking();
+ await tracker.stop();
await addVisit("stop_tracking_twice1");
_("Notifying twice won't do any harm.");
- await stopTracking();
+ await tracker.stop();
await addVisit("stop_tracking_twice2");
await verifyTrackerEmpty();
await cleanup();
});
add_task(async function test_filter_file_uris() {
- await startTracking();
+ tracker.start();
let uri = CommonUtils.makeURI("file:///Users/eoger/tps/config.json");
let visitAddedPromise = promiseVisit("added", uri);
await PlacesTestUtils.addVisits({
uri,
visitDate: Date.now() * 1000,
transition: PlacesUtils.history.TRANSITION_LINK
});
await visitAddedPromise;
await verifyTrackerEmpty();
- await stopTracking();
+ await tracker.stop();
await cleanup();
});
add_task(async function test_filter_hidden() {
- await startTracking();
+ tracker.start();
_("Add visit; should be hidden by the redirect");
let hiddenURI = await addVisit("hidden");
let hiddenGUID = await engine._store.GUIDForUri(hiddenURI.spec);
_(`Hidden visit GUID: ${hiddenGUID}`);
_("Add redirect visit; should be tracked");
let trackedURI = await addVisit("redirect", hiddenURI.spec,
--- a/services/sync/tests/unit/test_hmac_error.js
+++ b/services/sync/tests/unit/test_hmac_error.js
@@ -22,17 +22,17 @@ async function shared_setup() {
hmacErrorCount = 0;
// Make sure RotaryEngine is the only one we sync.
let { engine, tracker } = await 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"};
- tracker.addChangedID("scotsman", 0);
+ await tracker.addChangedID("scotsman", 0);
Assert.equal(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.
@@ -87,17 +87,17 @@ add_task(async function hmac_error_durin
key404Counter = 1;
_("---------------------------");
await sync_and_validate_telem();
_("---------------------------");
// Two rotary items, one client record... no errors.
Assert.equal(hmacErrorCount, 0);
} finally {
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await Service.engineManager.unregister(engine);
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
await promiseStopServer(server);
}
});
add_task(async function hmac_error_during_node_reassignment() {
@@ -216,17 +216,17 @@ add_task(async function hmac_error_durin
onSyncFinished = async function() {
// Two rotary items, one client record... no errors.
Assert.equal(hmacErrorCount, 0);
Svc.Obs.remove("weave:service:sync:finish", obs);
Svc.Obs.remove("weave:service:sync:error", obs);
(async () => {
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await Service.engineManager.unregister(engine);
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
server.stop(resolve);
})();
};
Service.sync();
--- a/services/sync/tests/unit/test_node_reassignment.js
+++ b/services/sync/tests/unit/test_node_reassignment.js
@@ -172,17 +172,17 @@ add_task(async function test_momentary_4
}
await syncAndExpectNodeReassignment(server,
"weave:service:sync:finish",
between,
"weave:service:sync:finish",
Service.storageURL + "rotary");
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await 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() {
enableValidationPrefs();
_("Test a failure for info/collections that's resolved by reassignment.");
@@ -485,11 +485,11 @@ add_task(async function test_loop_avoida
}
Svc.Obs.add(firstNotification, onFirstSync);
now = Date.now();
await Service.sync();
await deferred.promise;
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await Service.engineManager.unregister(engine);
});
--- a/services/sync/tests/unit/test_password_engine.js
+++ b/services/sync/tests/unit/test_password_engine.js
@@ -4,17 +4,17 @@ ChromeUtils.import("resource://services-
const LoginInfo = Components.Constructor(
"@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init");
const PropertyBag = Components.Constructor(
"@mozilla.org/hash-property-bag;1", Ci.nsIWritablePropertyBag);
async function cleanup(engine, server) {
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await engine._tracker.stop();
await engine.wipeClient();
Svc.Prefs.resetBranch("");
Service.recordManager.clearCache();
await promiseStopServer(server);
}
add_task(async function setup() {
await Service.engineManager.unregister("addons"); // To silence errors.
@@ -29,17 +29,17 @@ add_task(async function test_ignored_fie
await SyncTestingInfrastructure(server);
enableValidationPrefs();
let login = Services.logins.addLogin(new LoginInfo("https://example.com", "",
null, "username", "password", "", ""));
login.QueryInterface(Ci.nsILoginMetaInfo); // For `guid`.
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
try {
let nonSyncableProps = new PropertyBag();
nonSyncableProps.setProperty("timeLastUsed", Date.now());
nonSyncableProps.setProperty("timesUsed", 3);
Services.logins.modifyLogin(login, nonSyncableProps);
let noChanges = await engine.pullNewChanges();
@@ -62,17 +62,17 @@ add_task(async function test_ignored_syn
let engine = Service.engineManager.get("passwords");
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
enableValidationPrefs();
- Svc.Obs.notify("weave:engine:start-tracking");
+ engine._tracker.start();
try {
let login = Services.logins.addLogin(new LoginInfo(FXA_PWDMGR_HOST, null,
FXA_PWDMGR_REALM, "fxa-uid", "creds", "", ""));
let noChanges = await engine.pullNewChanges();
deepEqual(noChanges, {}, "Should not track new FxA credentials");
@@ -150,17 +150,17 @@ add_task(async function test_password_en
rec.password = "n3wpa55";
rec.usernameField = oldLogin.usernameField;
rec.passwordField = oldLogin.usernameField;
rec.timeCreated = oldLogin.timeCreated;
rec.timePasswordChanged = Date.now();
collection.insert(oldLogin.guid, encryptPayload(rec.cleartext));
}
- Svc.Obs.notify("weave:engine:start-tracking");
+ await engine._tracker.stop();
try {
await sync_engine_and_validate_telem(engine, false);
let newRec = JSON.parse(JSON.parse(
collection.payload(newLogin.guid)).ciphertext);
equal(newRec.password, "password",
"Should update remote password for newer login");
--- a/services/sync/tests/unit/test_password_tracker.js
+++ b/services/sync/tests/unit/test_password_tracker.js
@@ -20,81 +20,90 @@ add_task(async function setup() {
// Don't do asynchronous writes.
tracker.persistChangedIDs = false;
});
add_task(async function test_tracking() {
let recordNum = 0;
_("Verify we've got an empty tracker to work with.");
- do_check_empty(tracker.changedIDs);
+ let changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
- function createPassword() {
+ async function createPassword() {
_("RECORD NUM: " + recordNum);
let record = {id: "GUID" + recordNum,
hostname: "http://foo.bar.com",
formSubmitURL: "http://foo.bar.com/baz",
username: "john" + recordNum,
password: "smith",
usernameField: "username",
passwordField: "password"};
recordNum++;
let login = store._nsLoginInfoFromRecord(record);
Services.logins.addLogin(login);
+ await tracker.asyncObserver.promiseObserversComplete();
}
try {
_("Create a password record. Won't show because we haven't started tracking yet");
- createPassword();
- do_check_empty(tracker.changedIDs);
+ await createPassword();
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
Assert.equal(tracker.score, 0);
_("Tell the tracker to start tracking changes.");
- Svc.Obs.notify("weave:engine:start-tracking");
- createPassword();
- do_check_attribute_count(tracker.changedIDs, 1);
+ tracker.start();
+ await createPassword();
+ changes = await tracker.getChangedIDs();
+ do_check_attribute_count(changes, 1);
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE);
- _("Notifying twice won't do any harm.");
- Svc.Obs.notify("weave:engine:start-tracking");
- createPassword();
- do_check_attribute_count(tracker.changedIDs, 2);
+ _("Starting twice won't do any harm.");
+ tracker.start();
+ await createPassword();
+ changes = await tracker.getChangedIDs();
+ do_check_attribute_count(changes, 2);
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 2);
_("Let's stop tracking again.");
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
tracker.resetScore();
- Svc.Obs.notify("weave:engine:stop-tracking");
- createPassword();
- do_check_empty(tracker.changedIDs);
+ await tracker.stop();
+ await createPassword();
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
Assert.equal(tracker.score, 0);
- _("Notifying twice won't do any harm.");
- Svc.Obs.notify("weave:engine:stop-tracking");
- createPassword();
- do_check_empty(tracker.changedIDs);
+ _("Stopping twice won't do any harm.");
+ await tracker.stop();
+ await createPassword();
+ changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
Assert.equal(tracker.score, 0);
} finally {
_("Clean up.");
await store.wipe();
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
tracker.resetScore();
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.stop();
}
});
add_task(async function test_onWipe() {
_("Verify we've got an empty tracker to work with.");
- do_check_empty(tracker.changedIDs);
+ const changes = await tracker.getChangedIDs();
+ do_check_empty(changes);
Assert.equal(tracker.score, 0);
try {
_("A store wipe should increment the score");
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
await store.wipe();
+ await tracker.asyncObserver.promiseObserversComplete();
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE);
} finally {
tracker.resetScore();
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.stop();
}
});
--- a/services/sync/tests/unit/test_prefs_tracker.js
+++ b/services/sync/tests/unit/test_prefs_tracker.js
@@ -44,45 +44,50 @@ add_task(async function run_test() {
_("Test fixtures.");
Svc.Prefs.set("prefs.sync.testing.int", true);
_("Test fixtures haven't upped the tracker score yet because it hasn't started tracking yet.");
Assert.equal(tracker.score, 0);
_("Tell the tracker to start tracking changes.");
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
prefs.set("testing.int", 23);
+ await tracker.asyncObserver.promiseObserversComplete();
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE);
Assert.equal(tracker.modified, true);
_("Clearing changed IDs reset modified status.");
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
Assert.equal(tracker.modified, false);
_("Resetting a pref ups the score, too.");
prefs.reset("testing.int");
+ await tracker.asyncObserver.promiseObserversComplete();
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 2);
Assert.equal(tracker.modified, true);
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
_("So does changing a pref sync pref.");
Svc.Prefs.set("prefs.sync.testing.int", false);
+ await tracker.asyncObserver.promiseObserversComplete();
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 3);
Assert.equal(tracker.modified, true);
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
_("Now that the pref sync pref has been flipped, changes to it won't be picked up.");
prefs.set("testing.int", 42);
+ await tracker.asyncObserver.promiseObserversComplete();
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 3);
Assert.equal(tracker.modified, false);
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
_("Changing some other random pref won't do anything.");
prefs.set("testing.other", "blergh");
+ await tracker.asyncObserver.promiseObserversComplete();
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 3);
Assert.equal(tracker.modified, false);
} finally {
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.stop();
prefs.resetBranch("");
}
});
--- a/services/sync/tests/unit/test_score_triggers.js
+++ b/services/sync/tests/unit/test_score_triggers.js
@@ -59,17 +59,17 @@ add_task(async function test_tracker_sco
tracker.score += SCORE_INCREMENT_SMALL;
Assert.equal(engine.score, SCORE_INCREMENT_SMALL);
Assert.equal(scoreUpdated, 1);
} finally {
Svc.Obs.remove("weave:engine:score:updated", onScoreUpdated);
tracker.resetScore();
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await Service.engineManager.unregister(engine);
}
});
add_task(async function test_sync_triggered() {
let server = sync_httpd_setup();
let { engine, tracker } = await setUp(server);
@@ -81,17 +81,17 @@ add_task(async function test_sync_trigge
Assert.equal(Status.login, LOGIN_SUCCEEDED);
tracker.score += SCORE_INCREMENT_XLARGE;
await promiseOneObserver("weave:service:sync:finish");
await Service.startOver();
await promiseStopServer(server);
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await Service.engineManager.unregister(engine);
});
add_task(async function test_clients_engine_sync_triggered() {
enableValidationPrefs();
_("Ensure that client engine score changes trigger a sync.");
@@ -108,17 +108,17 @@ add_task(async function test_clients_eng
Service.clientsEngine._tracker.score += SCORE_INCREMENT_XLARGE;
await promiseOneObserver("weave:service:sync:finish");
_("Sync due to clients engine change completed.");
await Service.startOver();
await promiseStopServer(server);
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await Service.engineManager.unregister(engine);
});
add_task(async function test_incorrect_credentials_sync_not_triggered() {
enableValidationPrefs();
_("Ensure that score changes don't trigger a sync if Status.login != LOGIN_SUCCEEDED.");
let server = sync_httpd_setup();
@@ -142,11 +142,11 @@ add_task(async function test_incorrect_c
Svc.Obs.remove("weave:service:sync:start", onSyncStart);
Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED);
await Service.startOver();
await promiseStopServer(server);
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
await Service.engineManager.unregister(engine);
});
--- a/services/sync/tests/unit/test_syncengine_sync.js
+++ b/services/sync/tests/unit/test_syncengine_sync.js
@@ -14,17 +14,17 @@ ChromeUtils.import("resource://testing-c
function makeRotaryEngine() {
return new RotaryEngine(Service);
}
async function clean(engine) {
Svc.Prefs.resetBranch("");
Svc.Prefs.set("log.logger.engine.rotary", "Trace");
Service.recordManager.clearCache();
- engine._tracker.clearChangedIDs();
+ await engine._tracker.clearChangedIDs();
await engine.finalize();
}
async function cleanAndGo(engine, server) {
await clean(engine);
await promiseStopServer(server);
}
@@ -93,17 +93,18 @@ add_task(async function test_syncStartup
await SyncTestingInfrastructure(server);
let engine = makeRotaryEngine();
engine._store.items = {rekolok: "Rekonstruktionslokomotive"};
try {
// Confirm initial environment
- Assert.equal(engine._tracker.changedIDs.rekolok, undefined);
+ const changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.rekolok, undefined);
let metaGlobal = await Service.recordManager.get(engine.metaURL);
Assert.equal(metaGlobal.payload.engines, undefined);
Assert.ok(!!collection.payload("flying"));
Assert.ok(!!collection.payload("scotsman"));
engine.lastSync = Date.now() / 1000;
engine.lastSyncLocal = Date.now();
@@ -168,17 +169,18 @@ add_task(async function test_syncStartup
{engines: {rotary: {version: engine.version,
syncID: "foobar"}}});
server.registerPathHandler("/1.1/foo/storage/meta/global", global.handler());
try {
// Confirm initial environment
Assert.equal(engine.syncID, "fake-guid-00");
- Assert.equal(engine._tracker.changedIDs.rekolok, undefined);
+ const changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.rekolok, undefined);
engine.lastSync = Date.now() / 1000;
engine.lastSyncLocal = Date.now();
await engine._syncStartup();
// The engine has assumed the server's syncID
Assert.equal(engine.syncID, "foobar");
@@ -326,34 +328,35 @@ add_task(async function test_processInco
let engine = makeRotaryEngine();
engine._store.items = {newerserver: "New data, but not as new as server!",
olderidentical: "Older but identical",
updateclient: "Got data?",
original: "Original Entry",
long_original: "Long Original Entry",
nukeme: "Nuke me!"};
// Make this record 1 min old, thus older than the one on the server
- engine._tracker.addChangedID("newerserver", Date.now() / 1000 - 60);
+ await engine._tracker.addChangedID("newerserver", Date.now() / 1000 - 60);
// This record has been changed 2 mins later than the one on the server
- engine._tracker.addChangedID("olderidentical", Date.now() / 1000);
+ await engine._tracker.addChangedID("olderidentical", Date.now() / 1000);
let meta_global = Service.recordManager.set(engine.metaURL,
new WBORecord(engine.metaURL));
meta_global.payload.engines = {rotary: {version: engine.version,
syncID: engine.syncID}};
try {
// Confirm initial environment
Assert.equal(engine._store.items.newrecord, undefined);
Assert.equal(engine._store.items.newerserver, "New data, but not as new as server!");
Assert.equal(engine._store.items.olderidentical, "Older but identical");
Assert.equal(engine._store.items.updateclient, "Got data?");
Assert.equal(engine._store.items.nukeme, "Nuke me!");
- Assert.ok(engine._tracker.changedIDs.olderidentical > 0);
+ let changes = await engine._tracker.getChangedIDs();
+ Assert.ok(changes.olderidentical > 0);
await engine._syncStartup();
await engine._processIncoming();
// Timestamps of last sync and last server modification are set.
Assert.ok(engine.lastSync > 0);
Assert.ok(engine.lastModified > 0);
@@ -361,17 +364,18 @@ add_task(async function test_processInco
Assert.equal(engine._store.items.newrecord, "New stuff...");
// The 'newerserver' record is updated since the server data is newer.
Assert.equal(engine._store.items.newerserver, "New data!");
// The data for 'olderidentical' is identical on the server, so
// it's no longer marked as changed anymore.
Assert.equal(engine._store.items.olderidentical, "Older but identical");
- Assert.equal(engine._tracker.changedIDs.olderidentical, undefined);
+ changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.olderidentical, undefined);
// Updated with server data.
Assert.equal(engine._store.items.updateclient, "Get this!");
// The incoming ID is preferred.
Assert.equal(engine._store.items.original, undefined);
Assert.equal(engine._store.items.duplication, "Original Entry");
Assert.notEqual(engine._delete.ids.indexOf("original"), -1);
@@ -455,17 +459,17 @@ add_task(async function test_processInco
engine.lastModified = now + 1;
let record = encryptPayload({id: "DUPE_INCOMING", denomination: "incoming"});
let wbo = new ServerWBO("DUPE_INCOMING", record, now + 2);
server.insertWBO(user, "rotary", wbo);
// Simulate a locally-deleted item.
engine._store.items = {};
- engine._tracker.addChangedID("DUPE_LOCAL", now + 3);
+ await engine._tracker.addChangedID("DUPE_LOCAL", now + 3);
Assert.equal(false, (await engine._store.itemExists("DUPE_LOCAL")));
Assert.equal(false, (await engine._store.itemExists("DUPE_INCOMING")));
Assert.equal("DUPE_LOCAL", (await engine._findDupe({id: "DUPE_INCOMING"})));
engine.lastModified = server.getCollection(user, engine.name).timestamp;
await engine._sync();
// After the sync, the server's payload for the original ID should be marked
@@ -494,17 +498,17 @@ add_task(async function test_processInco
engine.lastModified = now + 1;
let record = encryptPayload({id: "DUPE_INCOMING", denomination: "incoming"});
let wbo = new ServerWBO("DUPE_INCOMING", record, now + 2);
server.insertWBO(user, "rotary", wbo);
// Simulate a locally-deleted item.
engine._store.items = {};
- engine._tracker.addChangedID("DUPE_LOCAL", now + 1);
+ await engine._tracker.addChangedID("DUPE_LOCAL", now + 1);
Assert.equal(false, (await engine._store.itemExists("DUPE_LOCAL")));
Assert.equal(false, (await engine._store.itemExists("DUPE_INCOMING")));
Assert.equal("DUPE_LOCAL", (await engine._findDupe({id: "DUPE_INCOMING"})));
await engine._sync();
// Since the remote change is newer, the incoming item should exist locally.
do_check_attribute_count(engine._store.items, 1);
@@ -530,17 +534,17 @@ add_task(async function test_processInco
engine.lastModified = now + 1;
// The local record is newer than the incoming one, so it should be retained.
let record = encryptPayload({id: "DUPE_INCOMING", denomination: "incoming"});
let wbo = new ServerWBO("DUPE_INCOMING", record, now + 2);
server.insertWBO(user, "rotary", wbo);
await engine._store.create({id: "DUPE_LOCAL", denomination: "local"});
- engine._tracker.addChangedID("DUPE_LOCAL", now + 3);
+ await engine._tracker.addChangedID("DUPE_LOCAL", now + 3);
Assert.ok((await engine._store.itemExists("DUPE_LOCAL")));
Assert.equal("DUPE_LOCAL", (await engine._findDupe({id: "DUPE_INCOMING"})));
engine.lastModified = server.getCollection(user, engine.name).timestamp;
await engine._sync();
// The ID should have been changed to incoming.
do_check_attribute_count(engine._store.items, 1);
@@ -569,17 +573,17 @@ add_task(async function test_processInco
engine.lastSync = now;
engine.lastModified = now + 1;
let record = encryptPayload({id: "DUPE_INCOMING", denomination: "incoming"});
let wbo = new ServerWBO("DUPE_INCOMING", record, now + 2);
server.insertWBO(user, "rotary", wbo);
await engine._store.create({id: "DUPE_LOCAL", denomination: "local"});
- engine._tracker.addChangedID("DUPE_LOCAL", now + 1);
+ await engine._tracker.addChangedID("DUPE_LOCAL", now + 1);
Assert.ok((await engine._store.itemExists("DUPE_LOCAL")));
Assert.equal("DUPE_LOCAL", (await engine._findDupe({id: "DUPE_INCOMING"})));
engine.lastModified = server.getCollection(user, engine.name).timestamp;
await engine._sync();
// The ID should have been changed to incoming.
do_check_attribute_count(engine._store.items, 1);
@@ -1051,17 +1055,17 @@ add_task(async function test_uploadOutgo
await SyncTestingInfrastructure(server);
await generateNewKeys(Service.collectionKeys);
let engine = makeRotaryEngine();
engine.lastSync = 123; // needs to be non-zero so that tracker is queried
engine._store.items = {flying: "LNER Class A3 4472",
scotsman: "Flying Scotsman"};
// Mark one of these records as changed
- engine._tracker.addChangedID("scotsman", 0);
+ await engine._tracker.addChangedID("scotsman", 0);
let meta_global = Service.recordManager.set(engine.metaURL,
new WBORecord(engine.metaURL));
meta_global.payload.engines = {rotary: {version: engine.version,
syncID: engine.syncID}};
try {
@@ -1077,17 +1081,18 @@ add_task(async function test_uploadOutgo
Assert.ok(engine.lastSyncLocal > 0);
// Ensure the marked record ('scotsman') has been uploaded and is
// no longer marked.
Assert.equal(collection.payload("flying"), undefined);
Assert.ok(!!collection.payload("scotsman"));
Assert.equal(JSON.parse(collection.wbo("scotsman").data.ciphertext).id,
"scotsman");
- Assert.equal(engine._tracker.changedIDs.scotsman, undefined);
+ const changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.scotsman, undefined);
// The 'flying' record wasn't marked so it wasn't uploaded
Assert.equal(collection.payload("flying"), undefined);
} finally {
await cleanAndGo(engine, server);
}
});
@@ -1107,18 +1112,18 @@ async function test_uploadOutgoing_max_r
await SyncTestingInfrastructure(server);
await generateNewKeys(Service.collectionKeys);
let engine = makeRotaryEngine();
engine.allowSkippedRecord = allowSkippedRecord;
engine.lastSync = 1;
engine._store.items = { flying: "a".repeat(1024 * 1024), scotsman: "abcd" };
- engine._tracker.addChangedID("flying", 1000);
- engine._tracker.addChangedID("scotsman", 1000);
+ await engine._tracker.addChangedID("flying", 1000);
+ await engine._tracker.addChangedID("scotsman", 1000);
let meta_global = Service.recordManager.set(engine.metaURL,
new WBORecord(engine.metaURL));
meta_global.payload.engines = {rotary: {version: engine.version,
syncID: engine.syncID}};
try {
// Confirm initial environment
@@ -1133,27 +1138,29 @@ async function test_uploadOutgoing_max_r
do_throw("should not get here");
}
await engine.trackRemainingChanges();
// Check we uploaded the other record to the server
Assert.ok(collection.payload("scotsman"));
// And that we won't try to upload the huge record next time.
- Assert.equal(engine._tracker.changedIDs.flying, undefined);
+ const changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.flying, undefined);
} catch (e) {
if (allowSkippedRecord) {
do_throw("should not get here");
}
await engine.trackRemainingChanges();
// Check that we will try to upload the huge record next time
- Assert.equal(engine._tracker.changedIDs.flying, 1000);
+ const changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.flying, 1000);
} finally {
// Check we didn't upload the oversized record to the server
Assert.equal(collection.payload("flying"), undefined);
await cleanAndGo(engine, server);
}
}
@@ -1185,48 +1192,50 @@ add_task(async function test_uploadOutgo
engine.lastSync = 123; // needs to be non-zero so that tracker is queried
engine._store.items = {flying: "LNER Class A3 4472",
scotsman: "Flying Scotsman",
peppercorn: "Peppercorn Class"};
// Mark these records as changed
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);
+ await engine._tracker.addChangedID("flying", FLYING_CHANGED);
+ await engine._tracker.addChangedID("scotsman", SCOTSMAN_CHANGED);
+ await 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 {
// Confirm initial environment
Assert.equal(engine.lastSyncLocal, 0);
Assert.equal(collection.payload("flying"), undefined);
- Assert.equal(engine._tracker.changedIDs.flying, FLYING_CHANGED);
- Assert.equal(engine._tracker.changedIDs.scotsman, SCOTSMAN_CHANGED);
- Assert.equal(engine._tracker.changedIDs.peppercorn, PEPPERCORN_CHANGED);
+ let changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.flying, FLYING_CHANGED);
+ Assert.equal(changes.scotsman, SCOTSMAN_CHANGED);
+ Assert.equal(changes.peppercorn, PEPPERCORN_CHANGED);
engine.enabled = true;
await sync_engine_and_validate_telem(engine, true);
// Local timestamp has been set.
Assert.ok(engine.lastSyncLocal > 0);
// Ensure the 'flying' record has been uploaded and is no longer marked.
Assert.ok(!!collection.payload("flying"));
- Assert.equal(engine._tracker.changedIDs.flying, undefined);
+ changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.flying, undefined);
// The 'scotsman' and 'peppercorn' records couldn't be uploaded so
// they weren't cleared from the tracker.
- Assert.equal(engine._tracker.changedIDs.scotsman, SCOTSMAN_CHANGED);
- Assert.equal(engine._tracker.changedIDs.peppercorn, PEPPERCORN_CHANGED);
+ Assert.equal(changes.scotsman, SCOTSMAN_CHANGED);
+ Assert.equal(changes.peppercorn, PEPPERCORN_CHANGED);
} finally {
await promiseClean(engine, server);
}
});
async function createRecordFailTelemetry(allowSkippedRecord) {
Service.identity.username = "foo";
@@ -1250,63 +1259,67 @@ async function createRecordFailTelemetry
return oldCreateRecord.call(engine._store, id, col);
};
engine.lastSync = 123; // needs to be non-zero so that tracker is queried
engine._store.items = {flying: "LNER Class A3 4472",
scotsman: "Flying Scotsman"};
// Mark these records as changed
const FLYING_CHANGED = 12345;
const SCOTSMAN_CHANGED = 23456;
- engine._tracker.addChangedID("flying", FLYING_CHANGED);
- engine._tracker.addChangedID("scotsman", SCOTSMAN_CHANGED);
+ await engine._tracker.addChangedID("flying", FLYING_CHANGED);
+ await engine._tracker.addChangedID("scotsman", SCOTSMAN_CHANGED);
let meta_global = Service.recordManager.set(engine.metaURL,
new WBORecord(engine.metaURL));
meta_global.payload.engines = {rotary: {version: engine.version,
syncID: engine.syncID}};
let ping;
try {
// Confirm initial environment
Assert.equal(engine.lastSyncLocal, 0);
Assert.equal(collection.payload("flying"), undefined);
- Assert.equal(engine._tracker.changedIDs.flying, FLYING_CHANGED);
- Assert.equal(engine._tracker.changedIDs.scotsman, SCOTSMAN_CHANGED);
+ let changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.flying, FLYING_CHANGED);
+ Assert.equal(changes.scotsman, SCOTSMAN_CHANGED);
engine.enabled = true;
ping = await sync_engine_and_validate_telem(engine, true, onErrorPing => {
ping = onErrorPing;
});
if (!allowSkippedRecord) {
do_throw("should not get here");
}
// Ensure the 'flying' record has been uploaded and is no longer marked.
Assert.ok(!!collection.payload("flying"));
- Assert.equal(engine._tracker.changedIDs.flying, undefined);
+ changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.flying, undefined);
} catch (err) {
if (allowSkippedRecord) {
do_throw("should not get here");
}
// Ensure the 'flying' record has not been uploaded and is still marked
Assert.ok(!collection.payload("flying"));
- Assert.ok(engine._tracker.changedIDs.flying);
+ const changes = await engine._tracker.getChangedIDs();
+ Assert.ok(changes.flying);
} finally {
// Local timestamp has been set.
Assert.ok(engine.lastSyncLocal > 0);
// We reported in telemetry that we failed a record
Assert.equal(ping.engines[0].outgoing[0].failed, 1);
// In any case, the 'scotsman' record couldn't be created so it wasn't
// uploaded nor it was not cleared from the tracker.
Assert.ok(!collection.payload("scotsman"));
- Assert.equal(engine._tracker.changedIDs.scotsman, SCOTSMAN_CHANGED);
+ const changes = await engine._tracker.getChangedIDs();
+ Assert.equal(changes.scotsman, SCOTSMAN_CHANGED);
engine._store.createRecord = oldCreateRecord;
await promiseClean(engine, server);
}
}
add_task(async function test_uploadOutgoing_createRecord_throws_reported_telemetry() {
_("SyncEngine._uploadOutgoing reports a failed record to telemetry if createRecord throws");
@@ -1321,17 +1334,17 @@ add_task(async function test_uploadOutgo
add_task(async function test_uploadOutgoing_largeRecords() {
_("SyncEngine._uploadOutgoing throws on records larger than the max record payload size");
let collection = new ServerCollection();
let engine = makeRotaryEngine();
engine.allowSkippedRecord = false;
engine._store.items["large-item"] = "Y".repeat(Service.getMaxRecordPayloadSize() * 2);
- engine._tracker.addChangedID("large-item", 0);
+ await 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}};
@@ -1493,17 +1506,17 @@ add_task(async function test_sync_partia
return orig.apply(this, arguments);
};
}(collection.post));
// 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);
+ await 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));
@@ -1520,26 +1533,27 @@ add_task(async function test_sync_partia
error = ex;
}
ok(!!error);
// The timestamp has been updated.
Assert.ok(engine.lastSyncLocal > 456);
+ const changes = await engine._tracker.getChangedIDs();
for (let i = 0; i < 234; i++) {
let id = "record-no-" + i;
// Ensure failed records are back in the tracker:
// * records no. 23 and 42 were rejected by the server,
// * records after the third batch and higher couldn't be uploaded because
// we failed hard on the 3rd upload.
if ((i == 23) || (i == 42) || (i >= 200))
- Assert.equal(engine._tracker.changedIDs[id], i);
+ Assert.equal(changes[id], i);
else
- Assert.equal(false, id in engine._tracker.changedIDs);
+ Assert.equal(false, id in changes);
}
} finally {
Service.serverConfiguration = oldServerConfiguration;
await promiseClean(engine, server);
}
});
--- a/services/sync/tests/unit/test_tab_tracker.js
+++ b/services/sync/tests/unit/test_tab_tracker.js
@@ -59,69 +59,69 @@ add_task(async function run_test() {
Assert.ok(tracker.modified);
Assert.ok(Utils.deepEquals(Object.keys((await engine.getChangedIDs())),
[clientsEngine.localID]));
let logs;
_("Test listeners are registered on windows");
logs = fakeSvcWinMediator();
- Svc.Obs.notify("weave:engine:start-tracking");
+ tracker.start();
Assert.equal(logs.length, 2);
for (let log of logs) {
Assert.equal(log.addTopics.length, 5);
Assert.ok(log.addTopics.indexOf("pageshow") >= 0);
Assert.ok(log.addTopics.indexOf("TabOpen") >= 0);
Assert.ok(log.addTopics.indexOf("TabClose") >= 0);
Assert.ok(log.addTopics.indexOf("TabSelect") >= 0);
Assert.ok(log.addTopics.indexOf("unload") >= 0);
Assert.equal(log.remTopics.length, 0);
Assert.equal(log.numAPL, 1, "Added 1 progress listener");
Assert.equal(log.numRPL, 0, "Didn't remove a progress listener");
}
_("Test listeners are unregistered on windows");
logs = fakeSvcWinMediator();
- Svc.Obs.notify("weave:engine:stop-tracking");
+ await tracker.stop();
Assert.equal(logs.length, 2);
for (let log of logs) {
Assert.equal(log.addTopics.length, 0);
Assert.equal(log.remTopics.length, 5);
Assert.ok(log.remTopics.indexOf("pageshow") >= 0);
Assert.ok(log.remTopics.indexOf("TabOpen") >= 0);
Assert.ok(log.remTopics.indexOf("TabClose") >= 0);
Assert.ok(log.remTopics.indexOf("TabSelect") >= 0);
Assert.ok(log.remTopics.indexOf("unload") >= 0);
Assert.equal(log.numAPL, 0, "Didn't add a progress listener");
Assert.equal(log.numRPL, 1, "Removed 1 progress listener");
}
_("Test tab listener");
for (let evttype of ["TabOpen", "TabClose", "TabSelect"]) {
// Pretend we just synced.
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
Assert.ok(!tracker.modified);
// Send a fake tab event
tracker.onTab({type: evttype, originalTarget: evttype});
Assert.ok(tracker.modified);
Assert.ok(Utils.deepEquals(Object.keys((await engine.getChangedIDs())),
[clientsEngine.localID]));
}
// Pretend we just synced.
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
Assert.ok(!tracker.modified);
tracker.onTab({type: "pageshow", originalTarget: "pageshow"});
Assert.ok(Utils.deepEquals(Object.keys((await engine.getChangedIDs())),
[clientsEngine.localID]));
// Pretend we just synced and saw some progress listeners.
- tracker.clearChangedIDs();
+ await tracker.clearChangedIDs();
Assert.ok(!tracker.modified);
tracker.onLocationChange({ isTopLevel: false }, undefined, undefined, 0);
Assert.ok(!tracker.modified, "non-toplevel request didn't flag as modified");
tracker.onLocationChange({ isTopLevel: true }, undefined, undefined,
Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
Assert.ok(!tracker.modified, "location change within the same document request didn't flag as modified");
--- a/services/sync/tests/unit/test_telemetry.js
+++ b/services/sync/tests/unit/test_telemetry.js
@@ -53,17 +53,17 @@ SteamEngine.prototype = {
function BogusEngine(service) {
Engine.call(this, "bogus", service);
}
BogusEngine.prototype = Object.create(SteamEngine.prototype);
async function cleanAndGo(engine, server) {
- engine._tracker.clearChangedIDs();
+ await engine._tracker.clearChangedIDs();
Svc.Prefs.resetBranch("");
syncTestLogging();
Service.recordManager.clearCache();
await promiseStopServer(server);
}
add_task(async function setup() {
// Avoid addon manager complaining about not being initialized
@@ -215,37 +215,39 @@ add_task(async function test_upload_fail
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);
+ await engine._tracker.addChangedID("flying", FLYING_CHANGED);
+ await engine._tracker.addChangedID("scotsman", SCOTSMAN_CHANGED);
+ await 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 {
+ let changes = await engine._tracker.getChangedIDs();
_(`test_upload_failed: Rotary tracker contents at first sync: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
engine.enabled = true;
let ping = await 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;
+ changes = await engine._tracker.getChangedIDs();
_(`test_upload_failed: Rotary tracker contents at second sync: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
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);
@@ -265,54 +267,56 @@ add_task(async function test_sync_partia
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);
+ await 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 {
+ let changes = await engine._tracker.getChangedIDs();
_(`test_sync_partialUpload: Rotary tracker contents at first sync: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
engine.enabled = true;
let ping = await 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 new Error("Failure"); };
engine._store.items["record-no-1000"] = "Record No. 1000";
- engine._tracker.addChangedID("record-no-1000", 1000);
+ await engine._tracker.addChangedID("record-no-1000", 1000);
collection.insert("record-no-1000", 1000);
engine.lastSync = 123;
engine.lastSyncLocal = 456;
ping = null;
+ changes = await engine._tracker.getChangedIDs();
_(`test_sync_partialUpload: Rotary tracker contents at second sync: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
try {
// should throw
await 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"
@@ -343,18 +347,19 @@ add_task(async function test_generic_eng
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
let e = new Error("generic failure message");
engine._errToThrow = e;
try {
+ const changes = await engine._tracker.getChangedIDs();
_(`test_generic_engine_fail: Steam tracker contents: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
let ping = await sync_and_validate_telem(true);
equal(ping.status.service, SYNC_FAILED_PARTIAL);
deepEqual(ping.engines.find(err => err.name === "steam").failureReason, {
name: "unexpectederror",
error: String(e)
});
} finally {
await cleanAndGo(engine, server);
@@ -407,18 +412,19 @@ add_task(async function test_engine_fail
// filesystem.)
await Utils._real_jsonMove("file-does-not-exist", "anything", {});
} catch (ex) {
engine._errToThrow = ex;
}
ok(engine._errToThrow, "expecting exception");
try {
+ const changes = await engine._tracker.getChangedIDs();
_(`test_engine_fail_ioerror: Steam tracker contents: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
let ping = await 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 {
@@ -433,18 +439,19 @@ add_task(async function test_clean_urls(
await Service.engineManager.register(SteamEngine);
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
engine._errToThrow = new TypeError("http://www.google .com is not a valid URL.");
try {
+ const changes = await engine._tracker.getChangedIDs();
_(`test_clean_urls: Steam tracker contents: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
let ping = await 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");
equal(failureReason.error, "<URL> is not a valid URL.");
// Handle other errors that include urls.
engine._errToThrow = "Other error message that includes some:url/foo/bar/ in it.";
ping = await sync_and_validate_telem(true);
@@ -467,18 +474,19 @@ add_task(async function test_initial_syn
engine.enabled = true;
// These are the only ones who actually have things to sync at startup.
let engineNames = ["clients", "bookmarks", "prefs", "tabs"];
let server = await serverForEnginesWithKeys({"foo": "password"}, ["bookmarks", "prefs", "tabs"].map(name =>
Service.engineManager.get(name)
));
await SyncTestingInfrastructure(server);
try {
+ const changes = await engine._tracker.getChangedIDs();
_(`test_initial_sync_engines: Steam tracker contents: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
let ping = await 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)) {
@@ -501,18 +509,19 @@ add_task(async function test_nserror() {
await Service.engineManager.register(SteamEngine);
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
engine._errToThrow = Components.Exception("NS_ERROR_UNKNOWN_HOST", Cr.NS_ERROR_UNKNOWN_HOST);
try {
+ const changes = await engine._tracker.getChangedIDs();
_(`test_nserror: Steam tracker contents: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
let ping = await 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",
@@ -531,18 +540,19 @@ add_task(async function test_sync_why()
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = await serverForFoo(engine);
await SyncTestingInfrastructure(server);
let e = new Error("generic failure message");
engine._errToThrow = e;
try {
+ const changes = await engine._tracker.getChangedIDs();
_(`test_generic_engine_fail: Steam tracker contents: ${
- JSON.stringify(engine._tracker.changedIDs)}`);
+ JSON.stringify(changes)}`);
let ping = await wait_for_ping(() => Service.sync({why: "user"}), true, false);
_(JSON.stringify(ping));
equal(ping.why, "user");
} finally {
await cleanAndGo(engine, server);
await Service.engineManager.unregister(engine);
}
});
--- a/services/sync/tests/unit/test_tracker_addChanged.js
+++ b/services/sync/tests/unit/test_tracker_addChanged.js
@@ -7,51 +7,57 @@ ChromeUtils.import("resource://services-
add_task(async function test_tracker_basics() {
let tracker = new Tracker("Tracker", Service);
tracker.persistChangedIDs = false;
let id = "the_id!";
_("Make sure nothing exists yet..");
- Assert.equal(tracker.changedIDs[id], null);
+ let changes = await tracker.getChangedIDs();
+ Assert.equal(changes[id], null);
_("Make sure adding of time 0 works");
- tracker.addChangedID(id, 0);
- Assert.equal(tracker.changedIDs[id], 0);
+ await tracker.addChangedID(id, 0);
+ changes = await tracker.getChangedIDs();
+ Assert.equal(changes[id], 0);
_("A newer time will replace the old 0");
- tracker.addChangedID(id, 10);
- Assert.equal(tracker.changedIDs[id], 10);
+ await tracker.addChangedID(id, 10);
+ changes = await tracker.getChangedIDs();
+ Assert.equal(changes[id], 10);
_("An older time will not replace the newer 10");
- tracker.addChangedID(id, 5);
- Assert.equal(tracker.changedIDs[id], 10);
+ await tracker.addChangedID(id, 5);
+ changes = await tracker.getChangedIDs();
+ Assert.equal(changes[id], 10);
_("Adding without time defaults to current time");
- tracker.addChangedID(id);
- Assert.ok(tracker.changedIDs[id] > 10);
+ await tracker.addChangedID(id);
+ changes = await tracker.getChangedIDs();
+ Assert.ok(changes[id] > 10);
});
add_task(async function test_tracker_persistence() {
let tracker = new Tracker("Tracker", Service);
let id = "abcdef";
tracker.persistChangedIDs = true;
let promiseSave = new Promise((resolve, reject) => {
let save = tracker._storage._save;
tracker._storage._save = function() {
save.call(tracker._storage).then(resolve, reject);
};
});
- tracker.addChangedID(id, 5);
+ await tracker.addChangedID(id, 5);
await promiseSave;
_("IDs saved.");
- Assert.equal(5, tracker.changedIDs[id]);
+ const changes = await tracker.getChangedIDs();
+ Assert.equal(5, changes[id]);
let json = await Utils.jsonLoad("changes/tracker", tracker);
Assert.equal(5, json[id]);
tracker.persistChangedIDs = false;
});
--- a/services/sync/tps/extensions/tps/resource/tps.jsm
+++ b/services/sync/tps/extensions/tps/resource/tps.jsm
@@ -93,18 +93,18 @@ const ACTIONS = [
ACTION_VERIFY_NOT,
];
const OBSERVER_TOPICS = ["fxaccounts:onlogin",
"fxaccounts:onlogout",
"private-browsing",
"profile-before-change",
"sessionstore-windows-restored",
- "weave:engine:start-tracking",
- "weave:engine:stop-tracking",
+ "weave:service:tracking-started",
+ "weave:service:tracking-stopped",
"weave:service:login:error",
"weave:service:setup-complete",
"weave:service:sync:finish",
"weave:service:sync:delayed",
"weave:service:sync:error",
"weave:service:sync:start",
"weave:service:resyncs-finished",
"places-browser-init-complete",
@@ -242,21 +242,21 @@ var TPS = {
// Ensure that the sync operation has been started by TPS
if (!this._triggeredSync) {
this.DumpError("Automatic sync got triggered, which is not allowed.");
}
this._syncActive = true;
break;
- case "weave:engine:start-tracking":
+ case "weave:service:tracking-started":
this._isTracking = true;
break;
- case "weave:engine:stop-tracking":
+ case "weave:service:tracking-stopped":
this._isTracking = false;
break;
}
} catch (e) {
this.DumpError("Observer failed", e);
}
},
@@ -1094,17 +1094,17 @@ var TPS = {
}
},
/**
* Waits for Sync to start tracking before returning.
*/
async waitForTracking() {
if (!this._isTracking) {
- await this.waitForEvent("weave:engine:start-tracking");
+ await this.waitForEvent("weave:service:tracking-started");
}
},
/**
* Login on the server
*/
async Login(force) {
if ((await Authentication.isLoggedIn()) && !force) {
--- a/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js
@@ -12,16 +12,17 @@ Services.prefs.setCharPref("services.syn
// engine. We pass a constructor that Sync creates.
function MockTabsEngine() {
this.clients = null; // We'll set this dynamically
}
MockTabsEngine.prototype = {
name: "tabs",
+ startTracking() {},
getAllClients() {
return this.clients;
},
};
// A clients engine that doesn't need to be a constructor.
let MockClientsEngine = {
isMobile(guid) {