test_remote_settings_older_than_local.js (4342B)
1 const PREF_SETTINGS_SERVER = "services.settings.server"; 2 3 let server; 4 let client; 5 6 async function clear_state() { 7 await client.db.clear(); 8 } 9 10 function setJSONResponse(response, changeset) { 11 response.setStatusLine(null, 200, "OK"); 12 response.setHeader("Content-Type", "application/json; charset=UTF-8"); 13 response.setHeader("Date", new Date().toUTCString()); 14 response.write(JSON.stringify(changeset)); 15 } 16 17 add_setup(() => { 18 Services.prefs.setStringPref("services.settings.loglevel", "debug"); 19 20 // Set up an HTTP Server 21 server = new HttpServer(); 22 server.start(-1); 23 24 Services.prefs.setStringPref( 25 PREF_SETTINGS_SERVER, 26 `http://localhost:${server.identity.primaryPort}/v1` 27 ); 28 29 client = RemoteSettings("some-cid"); 30 31 const bodies = { 32 // First successful sync at timestamp=333 33 "/v1/buckets/main/collections/some-cid/changeset?_expected=333": { 34 timestamp: 333, 35 metadata: { 36 signatures: [{ signature: "abc", x5u: "data:text/plain;base64,pem" }], 37 }, 38 changes: [ 39 { id: "rid2", last_modified: 22 }, 40 { id: "rid1", last_modified: 11 }, 41 ], 42 }, 43 // Client fetches with _expected=222&_since=333 44 "/v1/buckets/main/collections/some-cid/changeset?_expected=222&_since=%22333%22": 45 { 46 timestamp: 222, 47 metadata: { 48 signatures: [{ signature: "ghi", x5u: "data:text/plain;base64,pem" }], 49 }, 50 changes: [{ id: "rid1", last_modified: 11 }], 51 }, 52 // Client refetches full collection with _expected=222 after signature fails. 53 "/v1/buckets/main/collections/some-cid/changeset?_expected=222": { 54 timestamp: 222, 55 metadata: { 56 signatures: [{ signature: "ghi", x5u: "data:text/plain;base64,pem" }], 57 }, 58 changes: [{ id: "rid1", last_modified: 11 }], 59 }, 60 }; 61 const handler = (request, response) => { 62 const body = bodies[`${request.path}?${request.queryString}`]; 63 if (!body) { 64 const err = new Error( 65 `Unexpected request ${request.path}?${request.queryString}` 66 ); 67 console.error(err); 68 throw err; 69 } 70 setJSONResponse(response, body); 71 }; 72 Object.keys(bodies).map(path => 73 server.registerPathHandler(path.split("?")[0], handler) 74 ); 75 76 // In this test suite, the only valid data is the one at timestamp=222 or timestamp=333, but not a mix of the two. 77 let backup = client._verifier; 78 client._verifier = { 79 asyncVerifyContentSignature: serialized => { 80 return ( 81 serialized == 82 '{"data":[{"id":"rid2","last_modified":22}],"last_modified":"444"}' || 83 serialized == 84 '{"data":[{"id":"rid1","last_modified":11},{"id":"rid2","last_modified":22}],"last_modified":"333"}' || 85 serialized == 86 '{"data":[{"id":"rid1","last_modified":11}],"last_modified":"222"}' 87 ); 88 }, 89 }; 90 91 registerCleanupFunction(() => { 92 client._verifier = backup; 93 server.stop(() => {}); 94 Services.prefs.clearUserPref(PREF_SETTINGS_SERVER); 95 96 Services.prefs.clearUserPref("services.settings.loglevel"); 97 }); 98 }); 99 100 add_task(clear_state); 101 102 add_task(async function test_ignores_if_local_signature_is_valid() { 103 await client.maybeSync(333); 104 Assert.deepEqual( 105 [ 106 await client.db.getLastModified(), 107 (await client.get()).map(({ id }) => id), 108 ], 109 [333, ["rid1", "rid2"]] 110 ); 111 112 await client.maybeSync(222); 113 114 // The client should detect that timestamp is older, 115 // but it ignores it because local data is good. 116 Assert.deepEqual( 117 [ 118 await client.db.getLastModified(), 119 (await client.get()).map(({ id }) => id), 120 ], 121 [333, ["rid1", "rid2"]] 122 ); 123 }); 124 add_task(clear_state); 125 126 add_task(async function test_uses_old_data_if_local_signature_is_invalid() { 127 // Import some data in the local DB. Signature will be bad. 128 await client.db.importChanges({}, 333, [{ id: "myid", last_modified: 1234 }]); 129 Assert.deepEqual( 130 [ 131 await client.db.getLastModified(), 132 (await client.get()).map(({ id }) => id), 133 ], 134 [333, ["myid"]] 135 ); 136 137 await client.maybeSync(222); 138 139 // The client should detect that timestamp is older, 140 // but will replace local data with this old data. 141 Assert.deepEqual( 142 [ 143 await client.db.getLastModified(), 144 (await client.get()).map(({ id }) => id), 145 ], 146 [222, ["rid1"]] 147 ); 148 }); 149 add_task(clear_state);