diff options
Diffstat (limited to 'toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js')
-rw-r--r-- | toolkit/modules/tests/xpcshell/test_sqlite_shutdown.js | 122 |
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); +}); |