summaryrefslogtreecommitdiffstats
path: root/services/sync/tests/unit/test_tab_engine.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/sync/tests/unit/test_tab_engine.js')
-rw-r--r--services/sync/tests/unit/test_tab_engine.js225
1 files changed, 225 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_tab_engine.js b/services/sync/tests/unit/test_tab_engine.js
new file mode 100644
index 0000000000..298f8f799d
--- /dev/null
+++ b/services/sync/tests/unit/test_tab_engine.js
@@ -0,0 +1,225 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { TabProvider } = ChromeUtils.importESModule(
+ "resource://services-sync/engines/tabs.sys.mjs"
+);
+const { WBORecord } = ChromeUtils.importESModule(
+ "resource://services-sync/record.sys.mjs"
+);
+const { Service } = ChromeUtils.importESModule(
+ "resource://services-sync/service.sys.mjs"
+);
+
+let engine;
+// We'll need the clients engine for testing as tabs is closely related
+let clientsEngine;
+
+async function syncClientsEngine(server) {
+ clientsEngine._lastFxADevicesFetch = 0;
+ clientsEngine.lastModified = server.getCollection("foo", "clients").timestamp;
+ await clientsEngine._sync();
+}
+
+async function makeRemoteClients() {
+ let server = await serverForFoo(clientsEngine);
+ await configureIdentity({ username: "foo" }, server);
+ await Service.login();
+
+ await SyncTestingInfrastructure(server);
+ await generateNewKeys(Service.collectionKeys);
+
+ let remoteId = Utils.makeGUID();
+ let remoteId2 = Utils.makeGUID();
+ let collection = server.getCollection("foo", "clients");
+
+ _("Create remote client records");
+ collection.insertRecord({
+ id: remoteId,
+ name: "Remote client",
+ type: "desktop",
+ commands: [],
+ version: "48",
+ fxaDeviceId: remoteId,
+ fxaDeviceName: "Fxa - Remote client",
+ protocols: ["1.5"],
+ });
+
+ collection.insertRecord({
+ id: remoteId2,
+ name: "Remote client 2",
+ type: "desktop",
+ commands: [],
+ version: "48",
+ fxaDeviceId: remoteId2,
+ fxaDeviceName: "Fxa - Remote client 2",
+ protocols: ["1.5"],
+ });
+
+ let fxAccounts = clientsEngine.fxAccounts;
+ clientsEngine.fxAccounts = {
+ notifyDevices() {
+ return Promise.resolve(true);
+ },
+ device: {
+ getLocalId() {
+ return fxAccounts.device.getLocalId();
+ },
+ getLocalName() {
+ return fxAccounts.device.getLocalName();
+ },
+ getLocalType() {
+ return fxAccounts.device.getLocalType();
+ },
+ recentDeviceList: [{ id: remoteId, name: "remote device" }],
+ refreshDeviceList() {
+ return Promise.resolve(true);
+ },
+ },
+ _internal: {
+ now() {
+ return Date.now();
+ },
+ },
+ };
+
+ await syncClientsEngine(server);
+}
+
+add_task(async function setup() {
+ clientsEngine = Service.clientsEngine;
+ // Make some clients to test with
+ await makeRemoteClients();
+
+ // Make the tabs engine for all the tests to use
+ engine = Service.engineManager.get("tabs");
+ await engine.initialize();
+
+ // Since these are xpcshell tests, we'll need to mock this
+ TabProvider.shouldSkipWindow = mockShouldSkipWindow;
+});
+
+add_task(async function test_tab_engine_skips_incoming_local_record() {
+ _("Ensure incoming records that match local client ID are never applied.");
+
+ let localID = clientsEngine.localID;
+ let collection = new ServerCollection();
+
+ _("Creating remote tab record with local client ID");
+ let localRecord = encryptPayload({
+ id: localID,
+ clientName: "local",
+ tabs: [
+ {
+ title: "title",
+ urlHistory: ["http://foo.com/"],
+ icon: "",
+ lastUsed: 2000,
+ },
+ ],
+ });
+ collection.insert(localID, localRecord);
+
+ _("Creating remote tab record with a different client ID");
+ let remoteID = "fake-guid-00"; // remote should match one of the test clients
+ let remoteRecord = encryptPayload({
+ id: remoteID,
+ clientName: "not local",
+ tabs: [
+ {
+ title: "title2",
+ urlHistory: ["http://bar.com/"],
+ icon: "",
+ lastUsed: 3000,
+ },
+ ],
+ });
+ collection.insert(remoteID, remoteRecord);
+
+ _("Setting up Sync server");
+ let server = sync_httpd_setup({
+ "/1.1/foo/storage/tabs": collection.handler(),
+ });
+
+ await SyncTestingInfrastructure(server);
+
+ let syncID = await engine.resetLocalSyncID();
+ let meta_global = Service.recordManager.set(
+ engine.metaURL,
+ new WBORecord(engine.metaURL)
+ );
+ meta_global.payload.engines = {
+ tabs: { version: engine.version, syncID },
+ };
+
+ await generateNewKeys(Service.collectionKeys);
+
+ let promiseFinished = new Promise(resolve => {
+ let syncFinish = engine._syncFinish;
+ engine._syncFinish = async function () {
+ let remoteTabs = await engine._rustStore.getAll();
+ equal(
+ remoteTabs.length,
+ 1,
+ "Remote client record was applied and local wasn't"
+ );
+ let record = remoteTabs[0];
+ equal(record.clientId, remoteID, "Remote client ID matches");
+
+ _("Ensure getAllClients returns the correct shape");
+ let clients = await engine.getAllClients();
+ equal(clients.length, 1);
+ let client = clients[0];
+ equal(client.id, "fake-guid-00");
+ equal(client.name, "Remote client");
+ equal(client.type, "desktop");
+ Assert.ok(client.lastModified); // lastModified should be filled in once serverModified is populated from the server
+ deepEqual(client.tabs, [
+ {
+ title: "title2",
+ urlHistory: ["http://bar.com/"],
+ icon: "",
+ lastUsed: 3000,
+ },
+ ]);
+ await syncFinish.call(engine);
+ resolve();
+ };
+ });
+
+ _("Start sync");
+ Service.scheduler.hasIncomingItems = false;
+ await engine._sync();
+ await promiseFinished;
+ // Bug 1800185 - we don't want the sync scheduler to see these records as incoming.
+ Assert.ok(!Service.scheduler.hasIncomingItems);
+});
+
+// Ensure we trim tabs in the case of going past the max payload size allowed
+add_task(async function test_too_many_tabs() {
+ let a_lot_of_tabs = [];
+
+ for (let i = 0; i < 4000; ++i) {
+ a_lot_of_tabs.push(
+ `http://example${i}.com/some-super-long-url-chain-to-help-with-bytes`
+ );
+ }
+
+ TabProvider.getWindowEnumerator = mockGetWindowEnumerator.bind(
+ this,
+ a_lot_of_tabs
+ );
+
+ let encoder = Utils.utf8Encoder;
+ // see tryfitItems(..) in util.js
+ const computeSerializedSize = records =>
+ encoder.encode(JSON.stringify(records)).byteLength;
+
+ const maxPayloadSize = Service.getMaxRecordPayloadSize();
+ const maxSerializedSize = (maxPayloadSize / 4) * 3 - 1500;
+ // We are over max payload size
+ Assert.ok(computeSerializedSize(a_lot_of_tabs) > maxSerializedSize);
+ let tabs = await engine.getTabsWithinPayloadSize();
+ // We are now under max payload size
+ Assert.ok(computeSerializedSize(tabs) < maxSerializedSize);
+});