1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/crashes/tests/xpcshell/test_crash_manager.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,281 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +"use strict"; 1.8 + 1.9 +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; 1.10 + 1.11 +let bsp = Cu.import("resource://gre/modules/CrashManager.jsm", this); 1.12 +Cu.import("resource://gre/modules/Promise.jsm", this); 1.13 +Cu.import("resource://gre/modules/Task.jsm", this); 1.14 +Cu.import("resource://gre/modules/osfile.jsm", this); 1.15 + 1.16 +Cu.import("resource://testing-common/CrashManagerTest.jsm", this); 1.17 + 1.18 +const DUMMY_DATE = new Date(Date.now() - 10 * 24 * 60 * 60 * 1000); 1.19 +DUMMY_DATE.setMilliseconds(0); 1.20 + 1.21 +function run_test() { 1.22 + do_get_profile(); 1.23 + configureLogging(); 1.24 + run_next_test(); 1.25 +} 1.26 + 1.27 +add_task(function* test_constructor_ok() { 1.28 + let m = new CrashManager({ 1.29 + pendingDumpsDir: "/foo", 1.30 + submittedDumpsDir: "/bar", 1.31 + eventsDirs: [], 1.32 + storeDir: "/baz", 1.33 + }); 1.34 + Assert.ok(m, "CrashManager can be created."); 1.35 +}); 1.36 + 1.37 +add_task(function* test_constructor_invalid() { 1.38 + Assert.throws(() => { 1.39 + new CrashManager({foo: true}); 1.40 + }); 1.41 +}); 1.42 + 1.43 +add_task(function* test_get_manager() { 1.44 + let m = yield getManager(); 1.45 + Assert.ok(m, "CrashManager obtained."); 1.46 + 1.47 + yield m.createDummyDump(true); 1.48 + yield m.createDummyDump(false); 1.49 +}); 1.50 + 1.51 +// Unsubmitted dump files on disk are detected properly. 1.52 +add_task(function* test_pending_dumps() { 1.53 + let m = yield getManager(); 1.54 + let now = Date.now(); 1.55 + let ids = []; 1.56 + const COUNT = 5; 1.57 + 1.58 + for (let i = 0; i < COUNT; i++) { 1.59 + ids.push(yield m.createDummyDump(false, new Date(now - i * 86400000))); 1.60 + } 1.61 + yield m.createIgnoredDumpFile("ignored", false); 1.62 + 1.63 + let entries = yield m.pendingDumps(); 1.64 + Assert.equal(entries.length, COUNT, "proper number detected."); 1.65 + 1.66 + for (let entry of entries) { 1.67 + Assert.equal(typeof(entry), "object", "entry is an object"); 1.68 + Assert.ok("id" in entry, "id in entry"); 1.69 + Assert.ok("path" in entry, "path in entry"); 1.70 + Assert.ok("date" in entry, "date in entry"); 1.71 + Assert.notEqual(ids.indexOf(entry.id), -1, "ID is known"); 1.72 + } 1.73 + 1.74 + for (let i = 0; i < COUNT; i++) { 1.75 + Assert.equal(entries[i].id, ids[COUNT-i-1], "Entries sorted by mtime"); 1.76 + } 1.77 +}); 1.78 + 1.79 +// Submitted dump files on disk are detected properly. 1.80 +add_task(function* test_submitted_dumps() { 1.81 + let m = yield getManager(); 1.82 + let COUNT = 5; 1.83 + 1.84 + for (let i = 0; i < COUNT; i++) { 1.85 + yield m.createDummyDump(true); 1.86 + } 1.87 + yield m.createIgnoredDumpFile("ignored", true); 1.88 + 1.89 + let entries = yield m.submittedDumps(); 1.90 + Assert.equal(entries.length, COUNT, "proper number detected."); 1.91 + 1.92 + let hrID = yield m.createDummyDump(true, new Date(), true); 1.93 + entries = yield m.submittedDumps(); 1.94 + Assert.equal(entries.length, COUNT + 1, "hr- in filename detected."); 1.95 + 1.96 + let gotIDs = new Set([e.id for (e of entries)]); 1.97 + Assert.ok(gotIDs.has(hrID)); 1.98 +}); 1.99 + 1.100 +// The store should expire after inactivity. 1.101 +add_task(function* test_store_expires() { 1.102 + let m = yield getManager(); 1.103 + 1.104 + Object.defineProperty(m, "STORE_EXPIRATION_MS", { 1.105 + value: 250, 1.106 + }); 1.107 + 1.108 + let store = yield m._getStore(); 1.109 + Assert.ok(store); 1.110 + Assert.equal(store, m._store); 1.111 + 1.112 + yield sleep(300); 1.113 + Assert.ok(!m._store, "Store has gone away."); 1.114 +}); 1.115 + 1.116 +// Ensure discovery of unprocessed events files works. 1.117 +add_task(function* test_unprocessed_events_files() { 1.118 + let m = yield getManager(); 1.119 + yield m.createEventsFile("1", "test.1", new Date(), "foo", 0); 1.120 + yield m.createEventsFile("2", "test.1", new Date(), "bar", 0); 1.121 + yield m.createEventsFile("1", "test.1", new Date(), "baz", 1); 1.122 + 1.123 + let paths = yield m._getUnprocessedEventsFiles(); 1.124 + Assert.equal(paths.length, 3); 1.125 +}); 1.126 + 1.127 +// Ensure only 1 aggregateEventsFiles() is allowed at a time. 1.128 +add_task(function* test_aggregate_events_locking() { 1.129 + let m = yield getManager(); 1.130 + 1.131 + let p1 = m.aggregateEventsFiles(); 1.132 + let p2 = m.aggregateEventsFiles(); 1.133 + 1.134 + Assert.strictEqual(p1, p2, "Same promise should be returned."); 1.135 +}); 1.136 + 1.137 +// Malformed events files should be deleted. 1.138 +add_task(function* test_malformed_files_deleted() { 1.139 + let m = yield getManager(); 1.140 + 1.141 + yield m.createEventsFile("1", "crash.main.1", new Date(), "foo\nbar"); 1.142 + 1.143 + let count = yield m.aggregateEventsFiles(); 1.144 + Assert.equal(count, 1); 1.145 + let crashes = yield m.getCrashes(); 1.146 + Assert.equal(crashes.length, 0); 1.147 + 1.148 + count = yield m.aggregateEventsFiles(); 1.149 + Assert.equal(count, 0); 1.150 +}); 1.151 + 1.152 +// Unknown event types should be ignored. 1.153 +add_task(function* test_aggregate_ignore_unknown_events() { 1.154 + let m = yield getManager(); 1.155 + 1.156 + yield m.createEventsFile("1", "crash.main.1", DUMMY_DATE, "id1"); 1.157 + yield m.createEventsFile("2", "foobar.1", new Date(), "dummy"); 1.158 + 1.159 + let count = yield m.aggregateEventsFiles(); 1.160 + Assert.equal(count, 2); 1.161 + 1.162 + count = yield m.aggregateEventsFiles(); 1.163 + Assert.equal(count, 1); 1.164 + 1.165 + count = yield m.aggregateEventsFiles(); 1.166 + Assert.equal(count, 1); 1.167 +}); 1.168 + 1.169 +add_task(function* test_prune_old() { 1.170 + let m = yield getManager(); 1.171 + let oldDate = new Date(Date.now() - 86400000); 1.172 + let newDate = new Date(Date.now() - 10000); 1.173 + yield m.createEventsFile("1", "crash.main.1", oldDate, "id1"); 1.174 + yield m.createEventsFile("2", "crash.plugin.1", newDate, "id2"); 1.175 + 1.176 + yield m.aggregateEventsFiles(); 1.177 + 1.178 + let crashes = yield m.getCrashes(); 1.179 + Assert.equal(crashes.length, 2); 1.180 + 1.181 + yield m.pruneOldCrashes(new Date(oldDate.getTime() + 10000)); 1.182 + 1.183 + crashes = yield m.getCrashes(); 1.184 + Assert.equal(crashes.length, 1, "Old crash has been pruned."); 1.185 + 1.186 + let c = crashes[0]; 1.187 + Assert.equal(c.id, "id2", "Proper crash was pruned."); 1.188 + 1.189 + // We can't test exact boundary conditions because dates from filesystem 1.190 + // don't have same guarantees as JS dates. 1.191 + yield m.pruneOldCrashes(new Date(newDate.getTime() + 5000)); 1.192 + crashes = yield m.getCrashes(); 1.193 + Assert.equal(crashes.length, 0); 1.194 +}); 1.195 + 1.196 +add_task(function* test_schedule_maintenance() { 1.197 + let m = yield getManager(); 1.198 + yield m.createEventsFile("1", "crash.main.1", DUMMY_DATE, "id1"); 1.199 + 1.200 + let oldDate = new Date(Date.now() - m.PURGE_OLDER_THAN_DAYS * 2 * 24 * 60 * 60 * 1000); 1.201 + yield m.createEventsFile("2", "crash.main.1", oldDate, "id2"); 1.202 + 1.203 + yield m.scheduleMaintenance(25); 1.204 + let crashes = yield m.getCrashes(); 1.205 + Assert.equal(crashes.length, 1); 1.206 + Assert.equal(crashes[0].id, "id1"); 1.207 +}); 1.208 + 1.209 +add_task(function* test_main_crash_event_file() { 1.210 + let m = yield getManager(); 1.211 + yield m.createEventsFile("1", "crash.main.1", DUMMY_DATE, "id1"); 1.212 + let count = yield m.aggregateEventsFiles(); 1.213 + Assert.equal(count, 1); 1.214 + 1.215 + let crashes = yield m.getCrashes(); 1.216 + Assert.equal(crashes.length, 1); 1.217 + Assert.equal(crashes[0].id, "id1"); 1.218 + Assert.equal(crashes[0].type, "main-crash"); 1.219 + Assert.deepEqual(crashes[0].crashDate, DUMMY_DATE); 1.220 + 1.221 + count = yield m.aggregateEventsFiles(); 1.222 + Assert.equal(count, 0); 1.223 +}); 1.224 + 1.225 +add_task(function* test_multiline_crash_id_rejected() { 1.226 + let m = yield getManager(); 1.227 + yield m.createEventsFile("1", "crash.main.1", DUMMY_DATE, "id1\nid2"); 1.228 + yield m.aggregateEventsFiles(); 1.229 + let crashes = yield m.getCrashes(); 1.230 + Assert.equal(crashes.length, 0); 1.231 +}); 1.232 + 1.233 +add_task(function* test_plugin_crash_event_file() { 1.234 + let m = yield getManager(); 1.235 + yield m.createEventsFile("1", "crash.plugin.1", DUMMY_DATE, "id1"); 1.236 + let count = yield m.aggregateEventsFiles(); 1.237 + Assert.equal(count, 1); 1.238 + 1.239 + let crashes = yield m.getCrashes(); 1.240 + Assert.equal(crashes.length, 1); 1.241 + Assert.equal(crashes[0].id, "id1"); 1.242 + Assert.equal(crashes[0].type, "plugin-crash"); 1.243 + Assert.deepEqual(crashes[0].crashDate, DUMMY_DATE); 1.244 + 1.245 + count = yield m.aggregateEventsFiles(); 1.246 + Assert.equal(count, 0); 1.247 +}); 1.248 + 1.249 +add_task(function* test_plugin_hang_event_file() { 1.250 + let m = yield getManager(); 1.251 + yield m.createEventsFile("1", "hang.plugin.1", DUMMY_DATE, "id1"); 1.252 + let count = yield m.aggregateEventsFiles(); 1.253 + Assert.equal(count, 1); 1.254 + 1.255 + let crashes = yield m.getCrashes(); 1.256 + Assert.equal(crashes.length, 1); 1.257 + Assert.equal(crashes[0].id, "id1"); 1.258 + Assert.equal(crashes[0].type, "plugin-hang"); 1.259 + Assert.deepEqual(crashes[0].crashDate, DUMMY_DATE); 1.260 + 1.261 + count = yield m.aggregateEventsFiles(); 1.262 + Assert.equal(count, 0); 1.263 +}); 1.264 + 1.265 +// Excessive amounts of files should be processed properly. 1.266 +add_task(function* test_high_water_mark() { 1.267 + let m = yield getManager(); 1.268 + 1.269 + let store = yield m._getStore(); 1.270 + 1.271 + for (let i = 0; i < store.HIGH_WATER_DAILY_THRESHOLD + 1; i++) { 1.272 + yield m.createEventsFile("m" + i, "crash.main.1", DUMMY_DATE, "m" + i); 1.273 + yield m.createEventsFile("pc" + i, "crash.plugin.1", DUMMY_DATE, "pc" + i); 1.274 + yield m.createEventsFile("ph" + i, "hang.plugin.1", DUMMY_DATE, "ph" + i); 1.275 + } 1.276 + 1.277 + let count = yield m.aggregateEventsFiles(); 1.278 + Assert.equal(count, 3 * bsp.CrashStore.prototype.HIGH_WATER_DAILY_THRESHOLD + 3); 1.279 + 1.280 + // Need to fetch again in case the first one was garbage collected. 1.281 + store = yield m._getStore(); 1.282 + // +1 is for preserved main process crash. 1.283 + Assert.equal(store.crashesCount, 3 * store.HIGH_WATER_DAILY_THRESHOLD + 1); 1.284 +});