<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
                 type="text/css"?>
<window title="Basic Plugin Tests"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script type="application/javascript"
          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
  <script type="application/javascript"
          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
  <script type="application/javascript" src="plugin-utils.js"></script>
  <script type="application/javascript">
    setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
  </script>
<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
</body>
<script class="testbody" type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
SimpleTest.ignoreAllUncaughtExceptions();

Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/Task.jsm");

var Cc = Components.classes;
var Ci = Components.interfaces;

const crashReporter = Cc["@mozilla.org/toolkit/crash-reporter;1"].getService(Ci.nsICrashReporter);
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";

var oldServerURL = crashReporter.serverURL;

const oldTimeoutPref = Services.prefs.getIntPref("dom.ipc.plugins.timeoutSecs");

var testObserver = {
  observe: function(subject, topic, data) {
    if (data == "submitting") // not done yet
      return;
    is(data, "success", "report should have been submitted successfully");
    is(topic, "crash-report-status", "Checking correct topic");
    ok(subject instanceof Ci.nsIPropertyBag2, "Subject should be a property bag");

    ok(subject.hasKey("minidumpID"), "Should have a local crash ID");
    let crashID = subject.getPropertyAsAString("minidumpID");
    isnot(crashID, "", "Local crash ID should not be an empty string");

    ok(subject.hasKey("serverCrashID"), "Should have a server crash ID");
    let remoteID = subject.getPropertyAsAString("serverCrashID");
    isnot(remoteID, "", "Server crash ID should not be an empty string");

    // Verify the data. The SJS script will return the data that was POSTed
    let req = new XMLHttpRequest();
    req.open("GET", SERVER_URL + "?id=" + remoteID, false);
    req.send(null);
    is(req.status, 200, "Server response should be 200 OK");
    let submitted = JSON.parse(req.responseText);

    ok(!("Throttleable" in submitted), "Submit request should not be Throttleable");
    is(submitted.ProcessType, "plugin", "Should specify ProcessType=plugin");
    ok("PluginHang" in submitted, "Request should contain PluginHang field");
    ok("additional_minidumps" in submitted, "Request should contain additional_minidumps field");
    let dumpNames = submitted.additional_minidumps.split(',');
    ok(dumpNames.indexOf("browser") != -1, "additional_minidumps should contain browser");
    info("additional_minidumps="+submitted.additional_minidumps);
    ok("upload_file_minidump" in submitted, "Request should contain upload_file_minidump field");
    ok("upload_file_minidump_browser" in submitted, "Request should contain upload_file_minidump_browser field");

    // Cleanup
    // First remove our fake submitted report
    let file = Services.dirsvc.get("UAppData", Ci.nsILocalFile);
    file.append("Crash Reports");
    file.append("submitted");
    file.append(remoteID + ".txt");
    file.remove(false);

    // Next unregister our observer
    Services.obs.removeObserver(testObserver, "crash-report-status");

    // Finally re-set prefs
    crashReporter.serverURL = oldServerURL;
    Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", oldTimeoutPref);

    // Check and cleanup CrashManager.
    Task.spawn(function* () {
      let cm = Services.crashmanager;
      let store = yield cm._getStore();
      is(store.crashesCount, 1, "Store should have only 1 item");

      let crash = store.getCrash(crashID);
      ok(!!crash, "Store should have the crash record");
      ok(crash.isOfType(cm.PROCESS_TYPE_PLUGIN, cm.CRASH_TYPE_HANG),
         "Crash type should be plugin-hang");
      is(crash.remoteID, remoteID, "Crash remoteID should match");

      is(crash.submissions.size, 1, "Crash should have a submission");
      let submission = crash.submissions.values().next().value;
      is(submission.result, cm.SUBMISSION_RESULT_OK,
         "Submission should be successful");

      store.reset();

      SimpleTest.finish();
    });
  },

  QueryInterface: function(iid) {
    if (iid.equals(Ci.nsIObserver) ||
        iid.equals(Ci.nsISupportsWeakReference) ||
        iid.equals(Ci.nsISupports))
      return this;
    throw Components.results.NS_NOINTERFACE;
  }
};

function onPluginCrashed(aEvent) {
  ok(true, "Plugin crashed notification received");
  is(aEvent.type, "PluginCrashed", "event is correct type");

  let submitButton = document.getAnonymousElementByAttribute(aEvent.target,
                                                             "class",
                                                             "submitButton");
  // try to submit this report
  sendMouseEvent({type:'click'}, submitButton, window);
}

function runTests() {
  // Default plugin hang timeout is too high for mochitests
  Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 1);

  // Override the crash reporter URL to send to our fake server
  crashReporter.serverURL = NetUtil.newURI(SERVER_URL);

  // Hook into plugin crash events
  Services.obs.addObserver(testObserver, "crash-report-status", true);
  document.addEventListener("PluginCrashed", onPluginCrashed, false);

  var pluginElement = document.getElementById("plugin1");
  try {
    Task.spawn(function* () {
      // Clear data in CrashManager in case previous tests caused something
      // to be added.
      let store = yield Services.crashmanager._getStore();
      store.reset();

      pluginElement.hang();
    });
  } catch (e) {
  }
}
]]>
</script>
</window>