1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/test/unit/head_crashreporter.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,170 @@ 1.4 +Components.utils.import("resource://gre/modules/osfile.jsm"); 1.5 + 1.6 +function getEventDir() { 1.7 + return OS.Path.join(do_get_tempdir().path, "crash-events"); 1.8 +} 1.9 + 1.10 +/* 1.11 + * Run an xpcshell subprocess and crash it. 1.12 + * 1.13 + * @param setup 1.14 + * A string of JavaScript code to execute in the subprocess 1.15 + * before crashing. If this is a function and not a string, 1.16 + * it will have .toSource() called on it, and turned into 1.17 + * a call to itself. (for programmer convenience) 1.18 + * This code will be evaluted between crasher_subprocess_head.js 1.19 + * and crasher_subprocess_tail.js, so it will have access 1.20 + * to everything defined in crasher_subprocess_head.js, 1.21 + * which includes "crashReporter", a variable holding 1.22 + * the crash reporter service. 1.23 + * 1.24 + * @param callback 1.25 + * A JavaScript function to be called after the subprocess 1.26 + * crashes. It will be passed (minidump, extra), where 1.27 + * minidump is an nsILocalFile of the minidump file produced, 1.28 + * and extra is an object containing the key,value pairs from 1.29 + * the .extra file. 1.30 + * 1.31 + * @param canReturnZero 1.32 + * If true, the subprocess may return with a zero exit code. 1.33 + * Certain types of crashes may not cause the process to 1.34 + * exit with an error. 1.35 + */ 1.36 +function do_crash(setup, callback, canReturnZero) 1.37 +{ 1.38 + // get current process filename (xpcshell) 1.39 + let ds = Components.classes["@mozilla.org/file/directory_service;1"] 1.40 + .getService(Components.interfaces.nsIProperties); 1.41 + let bin = ds.get("CurProcD", Components.interfaces.nsILocalFile); 1.42 + bin.append("xpcshell"); 1.43 + if (!bin.exists()) { 1.44 + bin.leafName = "xpcshell.exe"; 1.45 + do_check_true(bin.exists()); 1.46 + if (!bin.exists()) 1.47 + // weird, can't find xpcshell binary? 1.48 + do_throw("Can't find xpcshell binary!"); 1.49 + } 1.50 + // get Gre dir (GreD) 1.51 + let greD = ds.get("GreD", Components.interfaces.nsILocalFile); 1.52 + let headfile = do_get_file("crasher_subprocess_head.js"); 1.53 + let tailfile = do_get_file("crasher_subprocess_tail.js"); 1.54 + // run xpcshell -g GreD -f head -e "some setup code" -f tail 1.55 + let process = Components.classes["@mozilla.org/process/util;1"] 1.56 + .createInstance(Components.interfaces.nsIProcess); 1.57 + process.init(bin); 1.58 + let args = ['-g', greD.path, 1.59 + '-f', headfile.path]; 1.60 + if (setup) { 1.61 + if (typeof(setup) == "function") 1.62 + // funky, but convenient 1.63 + setup = "("+setup.toSource()+")();"; 1.64 + args.push('-e', setup); 1.65 + } 1.66 + args.push('-f', tailfile.path); 1.67 + 1.68 + let env = Components.classes["@mozilla.org/process/environment;1"] 1.69 + .getService(Components.interfaces.nsIEnvironment); 1.70 + 1.71 + let crashD = do_get_tempdir(); 1.72 + crashD.append("crash-events"); 1.73 + if (!crashD.exists()) { 1.74 + crashD.create(crashD.DIRECTORY_TYPE, 0700); 1.75 + } 1.76 + 1.77 + env.set("CRASHES_EVENTS_DIR", crashD.path); 1.78 + 1.79 + try { 1.80 + process.run(true, args, args.length); 1.81 + } 1.82 + catch(ex) {} // on Windows we exit with a -1 status when crashing. 1.83 + finally { 1.84 + env.set("CRASHES_EVENTS_DIR", ""); 1.85 + } 1.86 + 1.87 + if (!canReturnZero) { 1.88 + // should exit with an error (should have crashed) 1.89 + do_check_neq(process.exitValue, 0); 1.90 + } 1.91 + 1.92 + handleMinidump(callback); 1.93 +} 1.94 + 1.95 +function handleMinidump(callback) 1.96 +{ 1.97 + // find minidump 1.98 + let minidump = null; 1.99 + let en = do_get_tempdir().directoryEntries; 1.100 + while (en.hasMoreElements()) { 1.101 + let f = en.getNext().QueryInterface(Components.interfaces.nsILocalFile); 1.102 + if (f.leafName.substr(-4) == ".dmp") { 1.103 + minidump = f; 1.104 + break; 1.105 + } 1.106 + } 1.107 + 1.108 + if (minidump == null) 1.109 + do_throw("No minidump found!"); 1.110 + 1.111 + let extrafile = minidump.clone(); 1.112 + extrafile.leafName = extrafile.leafName.slice(0, -4) + ".extra"; 1.113 + 1.114 + // Just in case, don't let these files linger. 1.115 + do_register_cleanup(function() { 1.116 + if (minidump.exists()) 1.117 + minidump.remove(false); 1.118 + if (extrafile.exists()) 1.119 + extrafile.remove(false); 1.120 + }); 1.121 + do_check_true(extrafile.exists()); 1.122 + let extra = parseKeyValuePairsFromFile(extrafile); 1.123 + 1.124 + if (callback) 1.125 + callback(minidump, extra); 1.126 + 1.127 + if (minidump.exists()) 1.128 + minidump.remove(false); 1.129 + if (extrafile.exists()) 1.130 + extrafile.remove(false); 1.131 +} 1.132 + 1.133 +function do_content_crash(setup, callback) 1.134 +{ 1.135 + do_load_child_test_harness(); 1.136 + do_test_pending(); 1.137 + 1.138 + // Setting the minidump path won't work in the child, so we need to do 1.139 + // that here. 1.140 + let crashReporter = 1.141 + Components.classes["@mozilla.org/toolkit/crash-reporter;1"] 1.142 + .getService(Components.interfaces.nsICrashReporter); 1.143 + crashReporter.minidumpPath = do_get_tempdir(); 1.144 + 1.145 + let headfile = do_get_file("../unit/crasher_subprocess_head.js"); 1.146 + let tailfile = do_get_file("../unit/crasher_subprocess_tail.js"); 1.147 + if (setup) { 1.148 + if (typeof(setup) == "function") 1.149 + // funky, but convenient 1.150 + setup = "("+setup.toSource()+")();"; 1.151 + } 1.152 + 1.153 + let handleCrash = function() { 1.154 + try { 1.155 + handleMinidump(callback); 1.156 + } catch (x) { 1.157 + do_report_unexpected_exception(x); 1.158 + } 1.159 + do_test_finished(); 1.160 + }; 1.161 + 1.162 + sendCommand("load(\"" + headfile.path.replace(/\\/g, "/") + "\");", function() 1.163 + sendCommand(setup, function() 1.164 + sendCommand("load(\"" + tailfile.path.replace(/\\/g, "/") + "\");", 1.165 + function() do_execute_soon(handleCrash) 1.166 + ) 1.167 + ) 1.168 + ); 1.169 +} 1.170 + 1.171 +// Import binary APIs via js-ctypes. 1.172 +Components.utils.import("resource://test/CrashTestUtils.jsm"); 1.173 +Components.utils.import("resource://gre/modules/KeyValueParser.jsm");