author | Mark Hammond <mhammond@skippinet.com.au> |
Thu, 26 Apr 2018 17:53:56 +1000 | |
changeset 415931 | bea414aba9b9e74cd5e1feecf63b1cf0bc240279 |
parent 415930 | 8141b60030b908c1f291979d72e0f21db8206c5c |
child 415932 | 3f80d2aaef435081f05551eae1a5c9b42302d56b |
push id | 33911 |
push user | csabou@mozilla.com |
push date | Fri, 27 Apr 2018 10:01:39 +0000 |
treeherder | mozilla-central@822936017145 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | glasserc |
bugs | 1457071 |
milestone | 61.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/services/sync/modules/engines/extension-storage.js +++ b/services/sync/modules/engines/extension-storage.js @@ -46,16 +46,21 @@ ExtensionStorageEngine.prototype = { // can be set to true or false, if a power user wants to customize // the behavior despite the lack of UI. const forced = Svc.Prefs.get("engine." + this.prefName + ".force", undefined); if (forced !== undefined) { return forced; } return Svc.Prefs.get("engine.addons", false); }, + + _wipeClient() { + return extensionStorageSync.clearAll(); + }, + }; function ExtensionStorageTracker(name, engine) { Tracker.call(this, name, engine); } ExtensionStorageTracker.prototype = { __proto__: Tracker.prototype,
--- a/services/sync/tests/unit/test_extension_storage_engine.js +++ b/services/sync/tests/unit/test_extension_storage_engine.js @@ -43,16 +43,27 @@ add_task(async function test_calling_syn // first, which fails. await engine.sync(); } finally { ExtensionStorageEngine.prototype._sync = oldSync; } equal(syncMock.calls.length, 1); }); +add_task(async function test_calling_wipeClient_calls_clearAll() { + let oldClearAll = extensionStorageSync.clearAll; + let clearMock = extensionStorageSync.clearAll = mock({returns: Promise.resolve()}); + try { + await engine.wipeClient(); + } finally { + extensionStorageSync.clearAll = oldClearAll; + } + equal(clearMock.calls.length, 1); +}); + add_task(async function test_calling_sync_calls_ext_storage_sync() { const extension = {id: "my-extension"}; let oldSync = extensionStorageSync.syncAll; let syncMock = extensionStorageSync.syncAll = mock({returns: Promise.resolve()}); try { await withSyncContext(async function(context) { // Set something so that everyone knows that we're using storage.sync await extensionStorageSync.set(extension, {"a": "b"}, context);
--- a/toolkit/components/extensions/ExtensionStorageSync.jsm +++ b/toolkit/components/extensions/ExtensionStorageSync.jsm @@ -1158,16 +1158,35 @@ class ExtensionStorageSync { }, {preloadIds: ids}); if (Object.keys(changes).length > 0) { this.notifyListeners(extension, changes); } const histogram = this._telemetry.getKeyedHistogramById(HISTOGRAM_REMOVE_OPS); histogram.add(extension.id, keys.length); } + /* Wipe local data for all collections without causing the changes to be synced */ + async clearAll() { + const extensions = extensionContexts.keys(); + const extIds = Array.from(extensions, extension => extension.id); + log.debug(`Clearing extension data for ${JSON.stringify(extIds)}`); + if (extIds.length) { + const promises = Array.from(extensionContexts.keys(), extension => { + return openCollection(this.cryptoCollection, extension).then(coll => { + return coll.clear(); + }); + }); + await Promise.all(promises); + } + + // and clear the crypto collection. + const cc = await this.cryptoCollection.getCollection(); + await cc.clear(); + } + async clear(extension, context) { // We can't call Collection#clear here, because that just clears // the local database. We have to explicitly delete everything so // that the deletions can be synced as well. const coll = await this.getCollection(extension, context); const res = await coll.list(); const records = res.data; const keys = records.map(record => record.key);
--- a/toolkit/components/extensions/test/xpcshell/test_ext_storage_sync.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_storage_sync.js @@ -571,16 +571,49 @@ add_task(async function test_extension_i const cryptoCollection = new CryptoCollection(fxaService); await cryptoCollection._setSalt(extensionId, salt); equal(await cryptoCollection.extensionIdToCollectionId(extensionId), "ext-0_QHA1P93_yJoj7ONisrR0lW6uN4PZ3Ii-rT-QOjtvo"); }); }); +add_task(async function ensureCanSync_clearAll() { + const extensionId = uuid(); + const extension = {id: extensionId}; + + await withContextAndServer(async function(context, server) { + await withSignedInUser(loggedInUser, async function(extensionStorageSync, fxaService) { + server.installCollection("storage-sync-crypto"); + server.etag = 1000; + + let newKeys = await extensionStorageSync.ensureCanSync([extensionId]); + ok(newKeys.hasKeysFor([extensionId]), `key isn't present for ${extensionId}`); + + let posts = server.getPosts(); + equal(posts.length, 1); + const post = posts[0]; + assertPostedNewRecord(post); + + // Set data for an extension and sync. + await extensionStorageSync.set(extension, {"my-key": 5}, context); + let keyValue = await extensionStorageSync.get(extension, ["my-key"], context); + equal(keyValue["my-key"], 5, "should get back the data we set"); + + // clear everything. + await extensionStorageSync.clearAll(); + + keyValue = await extensionStorageSync.get(extension, ["my-key"], context); + deepEqual(keyValue, {}, "should have lost the data"); + // should have been no posts caused by the clear. + equal(posts.length, 1); + }); + }); +}); + add_task(async function ensureCanSync_posts_new_keys() { const extensionId = uuid(); await withContextAndServer(async function(context, server) { await withSignedInUser(loggedInUser, async function(extensionStorageSync, fxaService) { server.installCollection("storage-sync-crypto"); server.etag = 1000; let newKeys = await extensionStorageSync.ensureCanSync([extensionId]);