summaryrefslogtreecommitdiffstats
path: root/services/settings/test/unit/test_shutdown_handling.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/settings/test/unit/test_shutdown_handling.js')
-rw-r--r--services/settings/test/unit/test_shutdown_handling.js139
1 files changed, 139 insertions, 0 deletions
diff --git a/services/settings/test/unit/test_shutdown_handling.js b/services/settings/test/unit/test_shutdown_handling.js
new file mode 100644
index 0000000000..a35ab6080a
--- /dev/null
+++ b/services/settings/test/unit/test_shutdown_handling.js
@@ -0,0 +1,139 @@
+/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+
+const { Database } = ChromeUtils.importESModule(
+ "resource://services-settings/Database.sys.mjs"
+);
+const { RemoteSettingsWorker } = ChromeUtils.importESModule(
+ "resource://services-settings/RemoteSettingsWorker.sys.mjs"
+);
+const { RemoteSettingsClient } = ChromeUtils.importESModule(
+ "resource://services-settings/RemoteSettingsClient.sys.mjs"
+);
+
+add_task(async function test_shutdown_abort_after_start() {
+ // Start a forever transaction:
+ let counter = 0;
+ let transactionStarted;
+ let startedPromise = new Promise(r => {
+ transactionStarted = r;
+ });
+ let promise = Database._executeIDB(
+ "records",
+ store => {
+ // Signal we've started.
+ transactionStarted();
+ function makeRequest() {
+ if (++counter > 1000) {
+ Assert.ok(
+ false,
+ "We ran 1000 requests and didn't get aborted, what?"
+ );
+ return;
+ }
+ dump("Making request " + counter + "\n");
+ const request = store
+ .index("cid")
+ .openCursor(IDBKeyRange.only("foopydoo/foo"));
+ request.onsuccess = event => {
+ makeRequest();
+ };
+ }
+ makeRequest();
+ },
+ { mode: "readonly" }
+ );
+
+ // Wait for the transaction to start.
+ await startedPromise;
+
+ Database._shutdownHandler(); // should abort the readonly transaction.
+
+ let rejection;
+ await promise.catch(e => {
+ rejection = e;
+ });
+ ok(rejection, "Promise should have rejected.");
+
+ // Now clear the shutdown flag and rejection error:
+ Database._cancelShutdown();
+ rejection = null;
+});
+
+add_task(async function test_shutdown_immediate_abort() {
+ // Now abort directly from the successful request.
+ let promise = Database._executeIDB(
+ "records",
+ store => {
+ let request = store
+ .index("cid")
+ .openCursor(IDBKeyRange.only("foopydoo/foo"));
+ request.onsuccess = event => {
+ // Abort immediately.
+ Database._shutdownHandler();
+ request = store
+ .index("cid")
+ .openCursor(IDBKeyRange.only("foopydoo/foo"));
+ Assert.ok(false, "IndexedDB allowed opening a cursor after aborting?!");
+ };
+ },
+ { mode: "readonly" }
+ );
+
+ let rejection;
+ // Wait for the abort
+ await promise.catch(e => {
+ rejection = e;
+ });
+ ok(rejection, "Directly aborted promise should also have rejected.");
+ // Now clear the shutdown flag and rejection error:
+ Database._cancelShutdown();
+});
+
+add_task(async function test_shutdown_worker() {
+ let client = new RemoteSettingsClient("language-dictionaries");
+ const before = await client.get({ syncIfEmpty: false });
+ Assert.equal(before.length, 0);
+
+ let records = [{}];
+ let importPromise = RemoteSettingsWorker._execute(
+ "_test_only_import",
+ ["main", "language-dictionaries", records, 0],
+ { mustComplete: true }
+ );
+ let stringifyPromise = RemoteSettingsWorker.canonicalStringify(
+ [],
+ [],
+ Date.now()
+ );
+ // Change the idle time so we shut the worker down even though we can't
+ // set gShutdown from outside of the worker management code.
+ Services.prefs.setIntPref(
+ "services.settings.worker_idle_max_milliseconds",
+ 1
+ );
+ RemoteSettingsWorker._abortCancelableRequests();
+ await Assert.rejects(
+ stringifyPromise,
+ /Shutdown/,
+ "Should have aborted the stringify request at shutdown."
+ );
+ await Assert.rejects(
+ importPromise,
+ /shutting down/,
+ "Ensure imports get aborted during shutdown"
+ );
+ const after = await client.get({ syncIfEmpty: false });
+ Assert.equal(after.length, 0);
+ await TestUtils.waitForCondition(() => !RemoteSettingsWorker.worker);
+ Assert.ok(
+ !RemoteSettingsWorker.worker,
+ "Worker should have been terminated."
+ );
+});