summaryrefslogtreecommitdiffstats
path: root/services/sync/tests/unit/test_extension_storage_engine.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/sync/tests/unit/test_extension_storage_engine.js')
-rw-r--r--services/sync/tests/unit/test_extension_storage_engine.js275
1 files changed, 275 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_extension_storage_engine.js b/services/sync/tests/unit/test_extension_storage_engine.js
new file mode 100644
index 0000000000..a061812aca
--- /dev/null
+++ b/services/sync/tests/unit/test_extension_storage_engine.js
@@ -0,0 +1,275 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ Service: "resource://services-sync/service.sys.mjs",
+ extensionStorageSync: "resource://gre/modules/ExtensionStorageSync.sys.mjs",
+});
+
+const { ExtensionStorageEngineBridge, ExtensionStorageEngineKinto } =
+ ChromeUtils.importESModule(
+ "resource://services-sync/engines/extension-storage.sys.mjs"
+ );
+
+const { BridgeWrapperXPCOM } = ChromeUtils.importESModule(
+ "resource://services-sync/bridged_engine.sys.mjs"
+);
+
+Services.prefs.setStringPref("webextensions.storage.sync.log.level", "debug");
+
+add_task(async function test_switching_between_kinto_and_bridged() {
+ function assertUsingKinto(message) {
+ let kintoEngine = Service.engineManager.get("extension-storage");
+ Assert.ok(kintoEngine instanceof ExtensionStorageEngineKinto, message);
+ }
+ function assertUsingBridged(message) {
+ let bridgedEngine = Service.engineManager.get("extension-storage");
+ Assert.ok(bridgedEngine instanceof ExtensionStorageEngineBridge, message);
+ }
+
+ let isUsingKinto = Services.prefs.getBoolPref(
+ "webextensions.storage.sync.kinto",
+ false
+ );
+ if (isUsingKinto) {
+ assertUsingKinto("Should use Kinto engine before flipping pref");
+ } else {
+ assertUsingBridged("Should use bridged engine before flipping pref");
+ }
+
+ _("Flip pref");
+ Services.prefs.setBoolPref("webextensions.storage.sync.kinto", !isUsingKinto);
+ await Service.engineManager.switchAlternatives();
+
+ if (isUsingKinto) {
+ assertUsingBridged("Should use bridged engine after flipping pref");
+ } else {
+ assertUsingKinto("Should use Kinto engine after flipping pref");
+ }
+
+ _("Clean up");
+ Services.prefs.clearUserPref("webextensions.storage.sync.kinto");
+ await Service.engineManager.switchAlternatives();
+});
+
+add_task(async function test_enable() {
+ const PREF = "services.sync.engine.extension-storage.force";
+
+ let addonsEngine = Service.engineManager.get("addons");
+ let extensionStorageEngine = Service.engineManager.get("extension-storage");
+
+ try {
+ Assert.ok(
+ addonsEngine.enabled,
+ "Add-ons engine should be enabled by default"
+ );
+ Assert.ok(
+ extensionStorageEngine.enabled,
+ "Extension storage engine should be enabled by default"
+ );
+
+ addonsEngine.enabled = false;
+ Assert.ok(
+ !extensionStorageEngine.enabled,
+ "Disabling add-ons should disable extension storage"
+ );
+
+ extensionStorageEngine.enabled = true;
+ Assert.ok(
+ !extensionStorageEngine.enabled,
+ "Enabling extension storage without override pref shouldn't work"
+ );
+
+ Services.prefs.setBoolPref(PREF, true);
+ Assert.ok(
+ extensionStorageEngine.enabled,
+ "Setting override pref should enable extension storage"
+ );
+
+ extensionStorageEngine.enabled = false;
+ Assert.ok(
+ !extensionStorageEngine.enabled,
+ "Disabling extension storage engine with override pref should work"
+ );
+
+ extensionStorageEngine.enabled = true;
+ Assert.ok(
+ extensionStorageEngine.enabled,
+ "Enabling extension storage with override pref should work"
+ );
+ } finally {
+ addonsEngine.enabled = true;
+ Services.prefs.clearUserPref(PREF);
+ }
+});
+
+add_task(async function test_notifyPendingChanges() {
+ let engine = new ExtensionStorageEngineBridge(Service);
+
+ let extension = { id: "ext-1" };
+ let expectedChange = {
+ a: "b",
+ c: "d",
+ };
+
+ let lastSync = 0;
+ let syncID = Utils.makeGUID();
+ let error = null;
+ engine.component = {
+ QueryInterface: ChromeUtils.generateQI([
+ "mozIBridgedSyncEngine",
+ "mozIExtensionStorageArea",
+ "mozISyncedExtensionStorageArea",
+ ]),
+ ensureCurrentSyncId(id, callback) {
+ if (syncID != id) {
+ syncID = id;
+ lastSync = 0;
+ }
+ callback.handleSuccess(id);
+ },
+ resetSyncId(callback) {
+ callback.handleSuccess(syncID);
+ },
+ syncStarted(callback) {
+ callback.handleSuccess();
+ },
+ getLastSync(callback) {
+ callback.handleSuccess(lastSync);
+ },
+ setLastSync(lastSyncMillis, callback) {
+ lastSync = lastSyncMillis;
+ callback.handleSuccess();
+ },
+ apply(callback) {
+ callback.handleSuccess([]);
+ },
+ fetchPendingSyncChanges(callback) {
+ if (error) {
+ callback.handleError(Cr.NS_ERROR_FAILURE, error.message);
+ } else {
+ callback.onChanged(extension.id, JSON.stringify(expectedChange));
+ callback.handleSuccess();
+ }
+ },
+ setUploaded(modified, ids, callback) {
+ callback.handleSuccess();
+ },
+ syncFinished(callback) {
+ callback.handleSuccess();
+ },
+ takeMigrationInfo(callback) {
+ callback.handleSuccess(null);
+ },
+ };
+
+ engine._bridge = new BridgeWrapperXPCOM(engine.component);
+
+ let server = await serverForFoo(engine);
+
+ let actualChanges = [];
+ let listener = changes => actualChanges.push(changes);
+ extensionStorageSync.addOnChangedListener(extension, listener);
+
+ try {
+ await SyncTestingInfrastructure(server);
+
+ info("Sync engine; notify about changes");
+ await sync_engine_and_validate_telem(engine, false);
+ deepEqual(
+ actualChanges,
+ [expectedChange],
+ "Should notify about changes during sync"
+ );
+
+ error = new Error("oops!");
+ actualChanges = [];
+ await sync_engine_and_validate_telem(engine, false);
+ deepEqual(
+ actualChanges,
+ [],
+ "Should finish syncing even if notifying about changes fails"
+ );
+ } finally {
+ extensionStorageSync.removeOnChangedListener(extension, listener);
+ await promiseStopServer(server);
+ await engine.finalize();
+ }
+});
+
+// It's difficult to know what to test - there's already tests for the bridged
+// engine etc - so we just try and check that this engine conforms to the
+// mozIBridgedSyncEngine interface guarantees.
+add_task(async function test_engine() {
+ // Forcibly set the bridged engine in the engine manager. the reason we do
+ // this, unlike the other tests where we just create the engine, is so that
+ // telemetry can get at the engine's `overrideTelemetryName`, which it gets
+ // through the engine manager.
+ await Service.engineManager.unregister("extension-storage");
+ await Service.engineManager.register(ExtensionStorageEngineBridge);
+ let engine = Service.engineManager.get("extension-storage");
+ Assert.equal(engine.version, 1);
+
+ Assert.deepEqual(await engine.getSyncID(), null);
+ await engine.resetLocalSyncID();
+ Assert.notEqual(await engine.getSyncID(), null);
+
+ Assert.equal(await engine.getLastSync(), 0);
+ // lastSync is seconds on this side of the world, but milli-seconds on the other.
+ await engine.setLastSync(1234.567);
+ // should have 2 digit precision.
+ Assert.equal(await engine.getLastSync(), 1234.57);
+ await engine.setLastSync(0);
+
+ // Set some data.
+ await extensionStorageSync.set({ id: "ext-2" }, { ext_2_key: "ext_2_value" });
+ // Now do a sync with out regular test server.
+ let server = await serverForFoo(engine);
+ try {
+ await SyncTestingInfrastructure(server);
+
+ info("Add server records");
+ let foo = server.user("foo");
+ let collection = foo.collection("extension-storage");
+ let now = new_timestamp();
+
+ collection.insert(
+ "fakeguid0000",
+ encryptPayload({
+ id: "fakeguid0000",
+ extId: "ext-1",
+ data: JSON.stringify({ foo: "bar" }),
+ }),
+ now
+ );
+
+ info("Sync the engine");
+
+ let ping = await sync_engine_and_validate_telem(engine, false);
+ Assert.ok(ping.engines.find(e => e.name == "rust-webext-storage"));
+ Assert.equal(
+ ping.engines.find(e => e.name == "extension-storage"),
+ null
+ );
+
+ // We should have applied the data from the existing collection record.
+ Assert.deepEqual(await extensionStorageSync.get({ id: "ext-1" }, null), {
+ foo: "bar",
+ });
+
+ // should now be 2 records on the server.
+ let payloads = collection.payloads();
+ Assert.equal(payloads.length, 2);
+ // find the new one we wrote.
+ let newPayload =
+ payloads[0].id == "fakeguid0000" ? payloads[1] : payloads[0];
+ Assert.equal(newPayload.data, `{"ext_2_key":"ext_2_value"}`);
+ // should have updated the timestamp.
+ greater(await engine.getLastSync(), 0, "Should update last sync time");
+ } finally {
+ await promiseStopServer(server);
+ await engine.finalize();
+ }
+});