tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_remote_settings_recover_broken.js (3707B)


      1 const PREF_SETTINGS_SERVER = "services.settings.server";
      2 const CHANGES_PATH = "/v1" + Utils.CHANGES_PATH;
      3 const BROKEN_SYNC_THRESHOLD = 10; // See default pref value
      4 
      5 let server;
      6 let client;
      7 let maybeSyncBackup;
      8 
      9 async function clear_state() {
     10  // Disable logging output.
     11  Services.prefs.setStringPref("services.settings.loglevel", "critical");
     12  // Pull data from the test server.
     13  Services.prefs.setStringPref(
     14    PREF_SETTINGS_SERVER,
     15    `http://localhost:${server.identity.primaryPort}/v1`
     16  );
     17 
     18  // Clear sync history.
     19  await new SyncHistory("").clear();
     20 
     21  // Simulate a response whose ETag gets incremented on each call
     22  // (in order to generate several history entries, indexed by timestamp).
     23  let timestamp = 1337;
     24  server.registerPathHandler(CHANGES_PATH, (request, response) => {
     25    response.setStatusLine(null, 200, "OK");
     26    response.setHeader("Content-Type", "application/json; charset=UTF-8");
     27    response.setHeader("Date", new Date(1000000).toUTCString());
     28    response.setHeader("ETag", `"${timestamp}"`);
     29    response.write(
     30      JSON.stringify({
     31        timestamp,
     32        changes: [
     33          {
     34            last_modified: ++timestamp,
     35            bucket: "main",
     36            collection: "desktop-manager",
     37          },
     38        ],
     39      })
     40    );
     41  });
     42 
     43  // Restore original maybeSync() method between each test.
     44  client.maybeSync = maybeSyncBackup;
     45 }
     46 
     47 function run_test() {
     48  // Set up an HTTP Server
     49  server = new HttpServer();
     50  server.start(-1);
     51 
     52  client = RemoteSettings("desktop-manager");
     53  maybeSyncBackup = client.maybeSync;
     54 
     55  run_next_test();
     56 
     57  registerCleanupFunction(() => {
     58    server.stop(() => {});
     59    // Restore original maybeSync() method when test suite is done.
     60    client.maybeSync = maybeSyncBackup;
     61  });
     62 }
     63 
     64 add_task(clear_state);
     65 
     66 add_task(async function test_db_is_destroyed_when_sync_is_broken() {
     67  // Simulate a successful sync.
     68  client.maybeSync = async () => {
     69    // Store some data in local DB.
     70    await client.db.importChanges({}, 1515, []);
     71  };
     72  await RemoteSettings.pollChanges({ trigger: "timer" });
     73 
     74  // Register a client with a failing sync method.
     75  client.maybeSync = () => {
     76    throw new RemoteSettingsClient.InvalidSignatureError(
     77      "main/desktop-manager"
     78    );
     79  };
     80 
     81  // Now obtain several failures in a row.
     82  for (var i = 0; i < BROKEN_SYNC_THRESHOLD; i++) {
     83    try {
     84      await RemoteSettings.pollChanges({ trigger: "timer" });
     85    } catch (e) {}
     86  }
     87 
     88  // Synchronization is in broken state.
     89  Assert.equal(
     90    await client.db.getLastModified(),
     91    1515,
     92    "Local DB was not destroyed yet"
     93  );
     94 
     95  // Synchronize again. Broken state will be detected.
     96  try {
     97    await RemoteSettings.pollChanges({ trigger: "timer" });
     98  } catch (e) {}
     99 
    100  // DB was destroyed.
    101  Assert.equal(
    102    await client.db.getLastModified(),
    103    null,
    104    "Local DB was destroyed"
    105  );
    106 });
    107 
    108 add_task(clear_state);
    109 
    110 add_task(async function test_db_is_not_destroyed_when_state_is_server_error() {
    111  // Since we don't mock the server endpoints to obtain the changeset of this
    112  // collection, the call to `maybeSync()` will fail with network errors.
    113 
    114  // Store some data in local DB.
    115  await client.db.importChanges({}, 1515, []);
    116 
    117  // Now obtain several failures in a row.
    118  let lastError;
    119  for (var i = 0; i < BROKEN_SYNC_THRESHOLD + 1; i++) {
    120    try {
    121      await RemoteSettings.pollChanges({ trigger: "timer" });
    122    } catch (e) {
    123      lastError = e;
    124    }
    125  }
    126  Assert.ok(
    127    /Cannot parse server content/.test(lastError.message),
    128    "Error is about server"
    129  );
    130  // DB was not destroyed.
    131  Assert.equal(
    132    await client.db.getLastModified(),
    133    1515,
    134    "Local DB was not destroyed"
    135  );
    136 });
    137 
    138 add_task(clear_state);