toolkit/crashreporter/test/unit/head_crashreporter.js

changeset 0
6474c204b198
     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");

mercurial