1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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);
});
|