test_tab_engine.js (5498B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const { TabProvider } = ChromeUtils.importESModule( 5 "resource://services-sync/engines/tabs.sys.mjs" 6 ); 7 const { WBORecord } = ChromeUtils.importESModule( 8 "resource://services-sync/record.sys.mjs" 9 ); 10 const { Service } = ChromeUtils.importESModule( 11 "resource://services-sync/service.sys.mjs" 12 ); 13 14 let engine; 15 // We'll need the clients engine for testing as tabs is closely related 16 let clientsEngine; 17 18 async function syncClientsEngine(server) { 19 clientsEngine._lastFxADevicesFetch = 0; 20 clientsEngine.lastModified = server.getCollection("foo", "clients").timestamp; 21 await clientsEngine._sync(); 22 } 23 24 async function makeRemoteClients() { 25 let server = await serverForFoo(clientsEngine); 26 await configureIdentity({ username: "foo" }, server); 27 await Service.login(); 28 29 await SyncTestingInfrastructure(server); 30 await generateNewKeys(Service.collectionKeys); 31 32 let remoteId = Utils.makeGUID(); 33 let remoteId2 = Utils.makeGUID(); 34 let collection = server.getCollection("foo", "clients"); 35 36 _("Create remote client records"); 37 collection.insertRecord({ 38 id: remoteId, 39 name: "Remote client", 40 type: "desktop", 41 commands: [], 42 version: "48", 43 fxaDeviceId: remoteId, 44 fxaDeviceName: "Fxa - Remote client", 45 protocols: ["1.5"], 46 }); 47 48 collection.insertRecord({ 49 id: remoteId2, 50 name: "Remote client 2", 51 type: "desktop", 52 commands: [], 53 version: "48", 54 fxaDeviceId: remoteId2, 55 fxaDeviceName: "Fxa - Remote client 2", 56 protocols: ["1.5"], 57 }); 58 59 let fxAccounts = clientsEngine.fxAccounts; 60 clientsEngine.fxAccounts = { 61 notifyDevices() { 62 return Promise.resolve(true); 63 }, 64 device: { 65 getLocalId() { 66 return fxAccounts.device.getLocalId(); 67 }, 68 getLocalName() { 69 return fxAccounts.device.getLocalName(); 70 }, 71 getLocalType() { 72 return fxAccounts.device.getLocalType(); 73 }, 74 recentDeviceList: [{ id: remoteId, name: "remote device" }], 75 refreshDeviceList() { 76 return Promise.resolve(true); 77 }, 78 }, 79 _internal: { 80 now() { 81 return Date.now(); 82 }, 83 }, 84 }; 85 86 await syncClientsEngine(server); 87 } 88 89 add_task(async function setup() { 90 clientsEngine = Service.clientsEngine; 91 // Make some clients to test with 92 await makeRemoteClients(); 93 94 // Make the tabs engine for all the tests to use 95 engine = Service.engineManager.get("tabs"); 96 await engine.initialize(); 97 98 // Since these are xpcshell tests, we'll need to mock this 99 TabProvider.shouldSkipWindow = mockShouldSkipWindow; 100 }); 101 102 add_task(async function test_tab_engine_skips_incoming_local_record() { 103 _("Ensure incoming records that match local client ID are never applied."); 104 105 let localID = clientsEngine.localID; 106 let collection = new ServerCollection(); 107 108 _("Creating remote tab record with local client ID"); 109 let localRecord = encryptPayload({ 110 id: localID, 111 clientName: "local", 112 tabs: [ 113 { 114 title: "title", 115 urlHistory: ["http://foo.com/"], 116 icon: "", 117 lastUsed: 2000, 118 }, 119 ], 120 }); 121 collection.insert(localID, localRecord); 122 123 _("Creating remote tab record with a different client ID"); 124 let remoteID = "fake-guid-00"; // remote should match one of the test clients 125 let remoteRecord = encryptPayload({ 126 id: remoteID, 127 clientName: "not local", 128 tabs: [ 129 { 130 title: "title2", 131 urlHistory: ["http://bar.com/"], 132 icon: "", 133 lastUsed: 3000, 134 }, 135 ], 136 }); 137 collection.insert(remoteID, remoteRecord); 138 139 _("Setting up Sync server"); 140 let server = sync_httpd_setup({ 141 "/1.1/foo/storage/tabs": collection.handler(), 142 }); 143 144 await SyncTestingInfrastructure(server); 145 146 let syncID = await engine.resetLocalSyncID(); 147 let meta_global = Service.recordManager.set( 148 engine.metaURL, 149 new WBORecord(engine.metaURL) 150 ); 151 meta_global.payload.engines = { 152 tabs: { version: engine.version, syncID }, 153 }; 154 155 await generateNewKeys(Service.collectionKeys); 156 157 let promiseFinished = new Promise(resolve => { 158 let syncFinish = engine._syncFinish; 159 engine._syncFinish = async function () { 160 let remoteTabs = await engine._rustStore.getAll(); 161 equal( 162 remoteTabs.length, 163 1, 164 "Remote client record was applied and local wasn't" 165 ); 166 let record = remoteTabs[0]; 167 equal(record.clientId, remoteID, "Remote client ID matches"); 168 169 _("Ensure getAllClients returns the correct shape"); 170 let clients = await engine.getAllClients(); 171 equal(clients.length, 1); 172 let client = clients[0]; 173 equal(client.id, "fake-guid-00"); 174 equal(client.name, "Remote client"); 175 equal(client.type, "desktop"); 176 Assert.ok(client.lastModified); // lastModified should be filled in once serverModified is populated from the server 177 Assert.equal(client.tabs.length, 1); 178 let tab = client.tabs[0]; 179 Assert.equal(tab.title, "title2"); 180 Assert.deepEqual(tab.urlHistory, ["http://bar.com/"]); 181 Assert.equal(tab.icon, ""); 182 Assert.ok(!tab.inactive); 183 await syncFinish.call(engine); 184 resolve(); 185 }; 186 }); 187 188 _("Start sync"); 189 Service.scheduler.hasIncomingItems = false; 190 await engine._sync(); 191 await promiseFinished; 192 // Bug 1800185 - we don't want the sync scheduler to see these records as incoming. 193 Assert.ok(!Service.scheduler.hasIncomingItems); 194 });