summaryrefslogtreecommitdiffstats
path: root/toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js')
-rw-r--r--toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js124
1 files changed, 124 insertions, 0 deletions
diff --git a/toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js b/toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js
new file mode 100644
index 0000000000..c4fd217bd3
--- /dev/null
+++ b/toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js
@@ -0,0 +1,124 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { AsyncShutdown } = ChromeUtils.importESModule(
+ "resource://gre/modules/AsyncShutdown.sys.mjs"
+);
+
+function getConnection(dbName, extraOptions = {}) {
+ let path = dbName + ".sqlite";
+ let options = { path };
+ for (let [k, v] of Object.entries(extraOptions)) {
+ options[k] = v;
+ }
+
+ return Sqlite.openConnection(options);
+}
+
+async function getDummyDatabase(name, extraOptions = {}) {
+ const TABLES = {
+ dirs: "id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT",
+ files: "id INTEGER PRIMARY KEY AUTOINCREMENT, dir_id INTEGER, path TEXT",
+ };
+
+ let c = await getConnection(name, extraOptions);
+ c._initialStatementCount = 0;
+
+ for (let [k, v] of Object.entries(TABLES)) {
+ await c.execute("CREATE TABLE " + k + "(" + v + ")");
+ c._initialStatementCount++;
+ }
+
+ return c;
+}
+
+function sleep(ms) {
+ return new Promise(resolve => {
+ let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+
+ timer.initWithCallback(
+ {
+ notify() {
+ resolve();
+ },
+ },
+ ms,
+ timer.TYPE_ONE_SHOT
+ );
+ });
+}
+
+//
+// ----------- Don't add a test after this one, as it shuts down Sqlite.sys.mjs
+//
+add_task(async function test_shutdown_clients() {
+ info("Ensuring that Sqlite.sys.mjs doesn't shutdown before its clients");
+
+ let assertions = [];
+
+ let sleepStarted = false;
+ let sleepComplete = false;
+ Sqlite.shutdown.addBlocker(
+ "test_sqlite.js shutdown blocker (sleep)",
+ async function () {
+ sleepStarted = true;
+ await sleep(100);
+ sleepComplete = true;
+ }
+ );
+ assertions.push({ name: "sleepStarted", value: () => sleepStarted });
+ assertions.push({ name: "sleepComplete", value: () => sleepComplete });
+
+ Sqlite.shutdown.addBlocker(
+ "test_sqlite.js shutdown blocker (immediate)",
+ true
+ );
+
+ let dbOpened = false;
+ let dbClosed = false;
+
+ Sqlite.shutdown.addBlocker(
+ "test_sqlite.js shutdown blocker (open a connection during shutdown)",
+ async function () {
+ let db = await getDummyDatabase("opened during shutdown");
+ dbOpened = true;
+ db.close().then(() => (dbClosed = true)); // Don't wait for this task to complete, Sqlite.sys.mjs must wait automatically
+ }
+ );
+
+ assertions.push({ name: "dbOpened", value: () => dbOpened });
+ assertions.push({ name: "dbClosed", value: () => dbClosed });
+
+ info("Now shutdown Sqlite.sys.mjs synchronously");
+ Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
+ // Check opening a connection during shutdown fails.
+ let deferred = PromiseUtils.defer();
+ let conn = Sqlite.openConnection({
+ path: PathUtils.join(PathUtils.profileDir, "test_shutdown.sqlite"),
+ testDelayedOpenPromise: deferred.promise,
+ });
+ await AsyncShutdown.profileBeforeChange._trigger();
+ deferred.resolve();
+ await Assert.rejects(
+ conn,
+ /has been shutdown/,
+ "Should close the connection and not block"
+ );
+ Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
+
+ for (let { name, value } of assertions) {
+ Assert.ok(value(), "Checking: " + name);
+ }
+
+ info("Ensure that we cannot open databases anymore");
+ let exn;
+ try {
+ await getDummyDatabase("opened after shutdown");
+ } catch (ex) {
+ exn = ex;
+ }
+ Assert.ok(!!exn, `exception: ${exn.message}`);
+ Assert.ok(exn.message.includes("Sqlite.sys.mjs has been shutdown"));
+});