test_tab_quickwrite.js (7171B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 ChromeUtils.importESModule("resource://services-sync/engines/tabs.sys.mjs"); 5 const { Service } = ChromeUtils.importESModule( 6 "resource://services-sync/service.sys.mjs" 7 ); 8 9 const { TabProvider } = ChromeUtils.importESModule( 10 "resource://services-sync/engines/tabs.sys.mjs" 11 ); 12 13 const FAR_FUTURE = 4102405200000; // 2100/01/01 14 15 add_task(async function setup() { 16 // Since these are xpcshell tests, we'll need to mock ui features 17 TabProvider.shouldSkipWindow = mockShouldSkipWindow; 18 TabProvider.getWindowEnumerator = mockGetWindowEnumerator.bind(this, [ 19 "http://foo.com", 20 ]); 21 }); 22 23 async function prepareServer() { 24 _("Setting up Sync server"); 25 Service.serverConfiguration = { 26 max_post_records: 100, 27 }; 28 29 let server = new SyncServer(); 30 server.start(); 31 await SyncTestingInfrastructure(server, "username"); 32 server.registerUser("username"); 33 34 let collection = server.createCollection("username", "tabs"); 35 await generateNewKeys(Service.collectionKeys); 36 37 let engine = Service.engineManager.get("tabs"); 38 await engine.initialize(); 39 40 return { server, collection, engine }; 41 } 42 43 async function withPatchedValue(object, name, patchedVal, fn) { 44 _(`patching ${name}=${patchedVal}`); 45 let old = object[name]; 46 object[name] = patchedVal; 47 try { 48 await fn(); 49 } finally { 50 object[name] = old; 51 } 52 } 53 54 add_task(async function test_tab_quickwrite_works() { 55 _("Ensure a simple quickWrite works."); 56 let { server, collection, engine } = await prepareServer(); 57 Assert.equal(collection.count(), 0, "starting with 0 tab records"); 58 Assert.ok(await engine.quickWrite()); 59 // Validate we didn't bork lastSync 60 let lastSync = await engine.getLastSync(); 61 Assert.less(lastSync, FAR_FUTURE); 62 Assert.equal(collection.count(), 1, "tab record was written"); 63 64 await promiseStopServer(server); 65 }); 66 67 add_task(async function test_tab_bad_status() { 68 _("Ensure quickWrite silently aborts when we aren't setup correctly."); 69 let { server, engine } = await prepareServer(); 70 // Store the original lock to reset it back after this test 71 let lock = engine.lock; 72 // Arrange for this test to fail if it tries to take the lock. 73 engine.lock = function () { 74 throw new Error("this test should abort syncing before locking"); 75 }; 76 let quickWrite = engine.quickWrite.bind(engine); // lol javascript. 77 78 await withPatchedValue(engine, "enabled", false, quickWrite); 79 await withPatchedValue(Service, "serverConfiguration", null, quickWrite); 80 81 Services.prefs.clearUserPref("services.sync.username"); 82 await quickWrite(); 83 // Validate we didn't bork lastSync 84 let lastSync = await engine.getLastSync(); 85 Assert.less(lastSync, FAR_FUTURE); 86 Service.status.resetSync(); 87 engine.lock = lock; 88 await promiseStopServer(server); 89 }); 90 91 add_task(async function test_tab_quickwrite_lock() { 92 _("Ensure we fail to quickWrite if the engine is locked."); 93 let { server, collection, engine } = await prepareServer(); 94 95 Assert.equal(collection.count(), 0, "starting with 0 tab records"); 96 engine.lock(); 97 Assert.ok(!(await engine.quickWrite())); 98 Assert.equal(collection.count(), 0, "didn't sync due to being locked"); 99 engine.unlock(); 100 101 await promiseStopServer(server); 102 }); 103 104 add_task(async function test_tab_quickwrite_keeps_old_tabs() { 105 _("Ensure we don't delete other tabs on quickWrite (bug 1801295)."); 106 let { server, engine } = await prepareServer(); 107 108 // The ID of another device. 109 const id = "fake-guid-99"; 110 111 // The clients engine is always going to tell us there are no other clients, 112 // but we need other clients, so we trick it. 113 // (We can't just stick this on the server, because we treat it as stale because it 114 // doesn't appear in the fxa list - but tricking it this way works) 115 let observeClientsFinished = (_subject, _topic, data) => { 116 if (data == "clients") { 117 engine.service.clientsEngine.fxAccounts.device._deviceListCache = { 118 devices: [], 119 }; 120 // trick the clients engine into thinking it has a remote client with the same guid. 121 engine.service.clientsEngine._store._remoteClients = {}; 122 engine.service.clientsEngine._store._remoteClients[id] = { 123 id, 124 fxaDeviceId: id, 125 }; 126 } 127 }; 128 Services.obs.addObserver(observeClientsFinished, "weave:engine:sync:finish"); 129 130 // need a first sync to ensure everything is setup correctly. 131 await Service.sync({ engines: ["tabs"] }); 132 133 let remoteRecord = encryptPayload({ 134 id, 135 clientName: "not local", 136 tabs: [ 137 { 138 title: "title2", 139 urlHistory: ["http://bar.com/"], 140 icon: "", 141 lastUsed: 3000, 142 }, 143 ], 144 }); 145 146 let collection = server.getCollection("username", "tabs"); 147 collection.insert(id, remoteRecord); 148 149 // This test can be flakey because sometimes we are so fast we think there is nothing to do. 150 // Resetting the last sync time here ensures we always fetch records from the server. 151 engine.setLastSync(0); 152 await Service.sync({ engines: ["tabs"] }); 153 154 // collection should now have 2 records - ours and the pretend remote one we inserted. 155 Assert.equal(collection.count(), 2, "starting with 2 tab records"); 156 157 let clients = await engine.getAllClients(); 158 Assert.equal(clients.length, 1); 159 160 _("Doing a quick-write"); 161 Assert.ok(await engine.quickWrite()); 162 163 // Should still have our client after a quickWrite. 164 _("Grabbing clients after the quick-write"); 165 clients = await engine.getAllClients(); 166 Assert.equal(clients.length, 1); 167 168 engine.service.clientsEngine._store._remoteClients = {}; 169 170 Services.obs.removeObserver( 171 observeClientsFinished, 172 "weave:engine:sync:finish" 173 ); 174 175 await promiseStopServer(server); 176 }); 177 178 add_task(async function test_tab_lastSync() { 179 _("Ensure we restore the lastSync timestamp after a quick-write."); 180 let { server, collection, engine } = await prepareServer(); 181 182 await engine.initialize(); 183 await engine.service.clientsEngine.initialize(); 184 185 let origLastSync = engine.lastSync; 186 Assert.ok(await engine.quickWrite()); 187 Assert.equal(engine.lastSync, origLastSync); 188 Assert.equal(collection.count(), 1, "successful sync"); 189 engine.unlock(); 190 191 await promiseStopServer(server); 192 }); 193 194 add_task(async function test_tab_quickWrite_telemetry() { 195 _("Ensure we record the telemetry we expect."); 196 // hook into telemetry 197 let telem = get_sync_test_telemetry(); 198 telem.payloads = []; 199 let oldSubmit = telem.submit; 200 let submitPromise = new Promise(resolve => { 201 telem.submit = function (ping) { 202 telem.submit = oldSubmit; 203 resolve(ping); 204 }; 205 }); 206 207 let { server, collection, engine } = await prepareServer(); 208 209 Assert.equal(collection.count(), 0, "starting with 0 tab records"); 210 Assert.ok(await engine.quickWrite()); 211 Assert.equal(collection.count(), 1, "tab record was written"); 212 213 let ping = await submitPromise; 214 let syncs = ping.syncs; 215 Assert.equal(syncs.length, 1); 216 let sync = syncs[0]; 217 Assert.equal(sync.why, "quick-write"); 218 Assert.equal(sync.engines.length, 1); 219 Assert.equal(sync.engines[0].name, "tabs"); 220 221 await promiseStopServer(server); 222 });