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.js122
1 files changed, 122 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 000000000..b97fd8558
--- /dev/null
+++ b/toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js
@@ -0,0 +1,122 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+do_get_profile();
+
+Cu.import("resource://gre/modules/osfile.jsm");
+ // OS.File doesn't like to be first imported during shutdown
+Cu.import("resource://gre/modules/Sqlite.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/AsyncShutdown.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+
+function getConnection(dbName, extraOptions={}) {
+ let path = dbName + ".sqlite";
+ let options = {path: path};
+ for (let [k, v] of Object.entries(extraOptions)) {
+ options[k] = v;
+ }
+
+ return Sqlite.openConnection(options);
+}
+
+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 = yield getConnection(name, extraOptions);
+ c._initialStatementCount = 0;
+
+ for (let [k, v] of Object.entries(TABLES)) {
+ yield c.execute("CREATE TABLE " + k + "(" + v + ")");
+ c._initialStatementCount++;
+ }
+
+ return c;
+}
+
+function sleep(ms) {
+ let deferred = Promise.defer();
+
+ let timer = Cc["@mozilla.org/timer;1"]
+ .createInstance(Ci.nsITimer);
+
+ timer.initWithCallback({
+ notify: function () {
+ deferred.resolve();
+ },
+ }, ms, timer.TYPE_ONE_SHOT);
+
+ return deferred.promise;
+}
+
+function run_test() {
+ run_next_test();
+}
+
+
+//
+// ----------- Don't add a test after this one, as it shuts down Sqlite.jsm
+//
+add_task(function* test_shutdown_clients() {
+ do_print("Ensuring that Sqlite.jsm doesn't shutdown before its clients");
+
+ let assertions = [];
+
+ let sleepStarted = false;
+ let sleepComplete = false;
+ Sqlite.shutdown.addBlocker("test_sqlite.js shutdown blocker (sleep)",
+ Task.async(function*() {
+ sleepStarted = true;
+ yield 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)",
+ Task.async(function*() {
+ let db = yield getDummyDatabase("opened during shutdown");
+ dbOpened = true;
+ db.close().then(
+ () => dbClosed = true
+ ); // Don't wait for this task to complete, Sqlite.jsm must wait automatically
+ }));
+
+ assertions.push({name: "dbOpened", value: () => dbOpened});
+ assertions.push({name: "dbClosed", value: () => dbClosed});
+
+ do_print("Now shutdown Sqlite.jsm synchronously");
+ Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
+ AsyncShutdown.profileBeforeChange._trigger();
+ Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
+
+
+ for (let {name, value} of assertions) {
+ do_print("Checking: " + name);
+ do_check_true(value());
+ }
+
+ do_print("Ensure that we cannot open databases anymore");
+ let exn;
+ try {
+ yield getDummyDatabase("opened after shutdown");
+ } catch (ex) {
+ exn = ex;
+ }
+ do_check_true(!!exn);
+ do_check_true(exn.message.indexOf("Sqlite.jsm has been shutdown") != -1);
+});