diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /services/settings/test/unit/test_remote_settings_recover_broken.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'services/settings/test/unit/test_remote_settings_recover_broken.js')
-rw-r--r-- | services/settings/test/unit/test_remote_settings_recover_broken.js | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/services/settings/test/unit/test_remote_settings_recover_broken.js b/services/settings/test/unit/test_remote_settings_recover_broken.js new file mode 100644 index 0000000000..cedd5cbe30 --- /dev/null +++ b/services/settings/test/unit/test_remote_settings_recover_broken.js @@ -0,0 +1,153 @@ +/* import-globals-from ../../../common/tests/unit/head_helpers.js */ + +const { SyncHistory } = ChromeUtils.importESModule( + "resource://services-settings/SyncHistory.sys.mjs" +); +const { RemoteSettingsClient } = ChromeUtils.importESModule( + "resource://services-settings/RemoteSettingsClient.sys.mjs" +); +const { RemoteSettings } = ChromeUtils.importESModule( + "resource://services-settings/remote-settings.sys.mjs" +); +const { Utils } = ChromeUtils.importESModule( + "resource://services-settings/Utils.sys.mjs" +); + +const PREF_SETTINGS_SERVER = "services.settings.server"; +const CHANGES_PATH = "/v1" + Utils.CHANGES_PATH; +const BROKEN_SYNC_THRESHOLD = 10; // See default pref value + +let server; +let client; +let maybeSyncBackup; + +async function clear_state() { + // Disable logging output. + Services.prefs.setCharPref("services.settings.loglevel", "critical"); + // Pull data from the test server. + Services.prefs.setCharPref( + PREF_SETTINGS_SERVER, + `http://localhost:${server.identity.primaryPort}/v1` + ); + + // Clear sync history. + await new SyncHistory("").clear(); + + // Simulate a response whose ETag gets incremented on each call + // (in order to generate several history entries, indexed by timestamp). + let timestamp = 1337; + server.registerPathHandler(CHANGES_PATH, (request, response) => { + response.setStatusLine(null, 200, "OK"); + response.setHeader("Content-Type", "application/json; charset=UTF-8"); + response.setHeader("Date", new Date(1000000).toUTCString()); + response.setHeader("ETag", `"${timestamp}"`); + response.write( + JSON.stringify({ + timestamp, + changes: [ + { + last_modified: ++timestamp, + bucket: "main", + collection: "desktop-manager", + }, + ], + }) + ); + }); + + // Restore original maybeSync() method between each test. + client.maybeSync = maybeSyncBackup; +} + +function run_test() { + // Set up an HTTP Server + server = new HttpServer(); + server.start(-1); + + client = RemoteSettings("desktop-manager"); + maybeSyncBackup = client.maybeSync; + + run_next_test(); + + registerCleanupFunction(() => { + server.stop(() => {}); + // Restore original maybeSync() method when test suite is done. + client.maybeSync = maybeSyncBackup; + }); +} + +add_task(clear_state); + +add_task(async function test_db_is_destroyed_when_sync_is_broken() { + // Simulate a successful sync. + client.maybeSync = async () => { + // Store some data in local DB. + await client.db.importChanges({}, 1515, []); + }; + await RemoteSettings.pollChanges({ trigger: "timer" }); + + // Register a client with a failing sync method. + client.maybeSync = () => { + throw new RemoteSettingsClient.InvalidSignatureError( + "main/desktop-manager" + ); + }; + + // Now obtain several failures in a row. + for (var i = 0; i < BROKEN_SYNC_THRESHOLD; i++) { + try { + await RemoteSettings.pollChanges({ trigger: "timer" }); + } catch (e) {} + } + + // Synchronization is in broken state. + Assert.equal( + await client.db.getLastModified(), + 1515, + "Local DB was not destroyed yet" + ); + + // Synchronize again. Broken state will be detected. + try { + await RemoteSettings.pollChanges({ trigger: "timer" }); + } catch (e) {} + + // DB was destroyed. + Assert.equal( + await client.db.getLastModified(), + null, + "Local DB was destroyed" + ); +}); + +add_task(clear_state); + +add_task(async function test_db_is_not_destroyed_when_state_is_server_error() { + // Since we don't mock the server endpoints to obtain the changeset of this + // collection, the call to `maybeSync()` will fail with network errors. + + // Store some data in local DB. + await client.db.importChanges({}, 1515, []); + + // Now obtain several failures in a row. + let lastError; + for (var i = 0; i < BROKEN_SYNC_THRESHOLD + 1; i++) { + try { + await RemoteSettings.pollChanges({ trigger: "timer" }); + } catch (e) { + lastError = e; + } + } + Assert.ok( + /Cannot parse server content/.test(lastError.message), + "Error is about server" + ); + // DB was not destroyed. + Assert.equal( + await client.db.getLastModified(), + 1515, + "Local DB was not destroyed" + ); +}); + +add_task(clear_state); |