/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ ChromeUtils.importESModule("resource://services-sync/engines/tabs.sys.mjs"); const { Service } = ChromeUtils.importESModule( "resource://services-sync/service.sys.mjs" ); const { TabProvider } = ChromeUtils.importESModule( "resource://services-sync/engines/tabs.sys.mjs" ); const FAR_FUTURE = 4102405200000; // 2100/01/01 add_task(async function setup() { // Since these are xpcshell tests, we'll need to mock ui features TabProvider.shouldSkipWindow = mockShouldSkipWindow; TabProvider.getWindowEnumerator = mockGetWindowEnumerator.bind(this, [ "http://foo.com", ]); }); async function prepareServer() { _("Setting up Sync server"); Service.serverConfiguration = { max_post_records: 100, }; let server = new SyncServer(); server.start(); await SyncTestingInfrastructure(server, "username"); server.registerUser("username"); let collection = server.createCollection("username", "tabs"); await generateNewKeys(Service.collectionKeys); let engine = Service.engineManager.get("tabs"); await engine.initialize(); return { server, collection, engine }; } async function withPatchedValue(object, name, patchedVal, fn) { _(`patching ${name}=${patchedVal}`); let old = object[name]; object[name] = patchedVal; try { await fn(); } finally { object[name] = old; } } add_task(async function test_tab_quickwrite_works() { _("Ensure a simple quickWrite works."); let { server, collection, engine } = await prepareServer(); Assert.equal(collection.count(), 0, "starting with 0 tab records"); Assert.ok(await engine.quickWrite()); // Validate we didn't bork lastSync let lastSync = await engine.getLastSync(); Assert.ok(lastSync < FAR_FUTURE); Assert.equal(collection.count(), 1, "tab record was written"); await promiseStopServer(server); }); add_task(async function test_tab_bad_status() { _("Ensure quickWrite silently aborts when we aren't setup correctly."); let { server, engine } = await prepareServer(); // Store the original lock to reset it back after this test let lock = engine.lock; // Arrange for this test to fail if it tries to take the lock. engine.lock = function () { throw new Error("this test should abort syncing before locking"); }; let quickWrite = engine.quickWrite.bind(engine); // lol javascript. await withPatchedValue(engine, "enabled", false, quickWrite); await withPatchedValue(Service, "serverConfiguration", null, quickWrite); Services.prefs.clearUserPref("services.sync.username"); await quickWrite(); // Validate we didn't bork lastSync let lastSync = await engine.getLastSync(); Assert.ok(lastSync < FAR_FUTURE); Service.status.resetSync(); engine.lock = lock; await promiseStopServer(server); }); add_task(async function test_tab_quickwrite_lock() { _("Ensure we fail to quickWrite if the engine is locked."); let { server, collection, engine } = await prepareServer(); Assert.equal(collection.count(), 0, "starting with 0 tab records"); engine.lock(); Assert.ok(!(await engine.quickWrite())); Assert.equal(collection.count(), 0, "didn't sync due to being locked"); engine.unlock(); await promiseStopServer(server); }); add_task(async function test_tab_quickwrite_keeps_old_tabs() { _("Ensure we don't delete other tabs on quickWrite (bug 1801295)."); let { server, engine } = await prepareServer(); // need a first sync to ensure everything is setup correctly. await Service.sync({ engines: ["tabs"] }); const id = "fake-guid-99"; let remoteRecord = encryptPayload({ id, clientName: "not local", tabs: [ { title: "title2", urlHistory: ["http://bar.com/"], icon: "", lastUsed: 3000, }, ], }); let collection = server.getCollection("username", "tabs"); collection.insert(id, remoteRecord); await Service.sync({ engines: ["tabs"] }); // collection should now have 2 records - ours and the pretend remote one we inserted. Assert.equal(collection.count(), 2, "starting with 2 tab records"); // So fxAccounts.device.recentDeviceList is not null. engine.service.clientsEngine.fxAccounts.device._deviceListCache = { devices: [], }; // trick the clients engine into thinking it has a remote client with the same guid. engine.service.clientsEngine._store._remoteClients = {}; engine.service.clientsEngine._store._remoteClients[id] = { id, fxaDeviceId: id, }; let clients = await engine.getAllClients(); Assert.equal(clients.length, 1); _("Doing a quick-write"); Assert.ok(await engine.quickWrite()); // Should still have our client after a quickWrite. _("Grabbing clients after the quick-write"); clients = await engine.getAllClients(); Assert.equal(clients.length, 1); engine.service.clientsEngine._store._remoteClients = {}; await promiseStopServer(server); }); add_task(async function test_tab_lastSync() { _("Ensure we restore the lastSync timestamp after a quick-write."); let { server, collection, engine } = await prepareServer(); await engine.initialize(); await engine.service.clientsEngine.initialize(); let origLastSync = engine.lastSync; Assert.ok(await engine.quickWrite()); Assert.equal(engine.lastSync, origLastSync); Assert.equal(collection.count(), 1, "successful sync"); engine.unlock(); await promiseStopServer(server); }); add_task(async function test_tab_quickWrite_telemetry() { _("Ensure we record the telemetry we expect."); // hook into telemetry let telem = get_sync_test_telemetry(); telem.payloads = []; let oldSubmit = telem.submit; let submitPromise = new Promise((resolve, reject) => { telem.submit = function (ping) { telem.submit = oldSubmit; resolve(ping); }; }); let { server, collection, engine } = await prepareServer(); Assert.equal(collection.count(), 0, "starting with 0 tab records"); Assert.ok(await engine.quickWrite()); Assert.equal(collection.count(), 1, "tab record was written"); let ping = await submitPromise; let syncs = ping.syncs; Assert.equal(syncs.length, 1); let sync = syncs[0]; Assert.equal(sync.why, "quick-write"); Assert.equal(sync.engines.length, 1); Assert.equal(sync.engines[0].name, "tabs"); await promiseStopServer(server); });