<?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:html="http://www.w3.org/1999/xhtml"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <title>Plugin Hang UI Test</title>
  <script type="application/javascript"
          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
  <script type="application/javascript"
          src="plugin-utils.js" />
  <script type="application/javascript"
          src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hang_test.js" />
  <script type="application/javascript"
          src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hangui_common.js" />

<body xmlns="http://www.w3.org/1999/xhtml">
  <iframe id="iframe1" src="hangui_subpage.html" width="400" height="400"></iframe>
</body>
<script class="testbody" type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);

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

const hangUITimeoutPref = "dom.ipc.plugins.hangUITimeoutSecs";
const hangUIMinDisplayPref = "dom.ipc.plugins.hangUIMinDisplaySecs";
const timeoutPref = "dom.ipc.plugins.timeoutSecs";

var worker = new ChromeWorker("hangui_iface.js");
worker.onmessage = function(event) {
  var result = event.data;
  var params = result.params;
  var output = params.testName;
  if (result.msg) {
    output += ": " + result.msg;
  }
  ok(result.status, output);
  if (params.callback) {
    var cb = eval(params.callback);
    var timeout = setTimeout(function() { clearTimeout(timeout); cb(); }, 100);
  }
};
worker.onerror = function(event) {
  var output = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
  ok(false, output);
};

var iframe;
var p;
var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);

function hanguiOperation(testName, timeoutSec, expectFind, expectClose, opCode,
                         commandId, check, cb) {
  var timeoutMs = timeoutSec * 1000 + EPSILON_MS;
  worker.postMessage({ "timeoutMs": timeoutMs, "expectToFind": expectFind,
                       "expectToClose": expectClose, "opCode": opCode,
                       "commandId": commandId, "check": check,
                       "testName": testName, "callback": cb });
}

function hanguiExpect(testName, shouldBeShowing, shouldClose, cb) {
  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
  if (!shouldBeShowing && !timeoutSec) {
    timeoutSec = Services.prefs.getIntPref(timeoutPref);
  }
  hanguiOperation(testName, timeoutSec, shouldBeShowing, shouldClose, HANGUIOP_NOTHING, 0, false, cb);
}

function hanguiContinue(testName, check, cb) {
  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_CONTINUE, check, cb);
}

function hanguiStop(testName, check, cb) {
  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_STOP, check, cb);
}

function hanguiCancel(testName, cb) {
  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_CANCEL, 0, false, cb);
}

function finishTest() {
  if (obsCount > 0) {
    os.removeObserver(testObserver, "plugin-crashed");
    --obsCount;
  }
  SpecialPowers.clearUserPref(hangUITimeoutPref);
  SpecialPowers.clearUserPref(hangUIMinDisplayPref);
  SpecialPowers.clearUserPref(timeoutPref);
  SimpleTest.finish();
}

function runTests() {
  resetVars();

  hanguiOperation("Prime ChromeWorker", 0, false, false, HANGUIOP_NOTHING, 0,
                  false, "test1");
}

window.frameLoaded = runTests;

var obsCount = 0;

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

  is(p, aEvent.target, "Plugin crashed event target is plugin element");

  ok(aEvent instanceof PluginCrashedEvent,
     "plugin crashed event has the right interface");

  is(typeof aEvent.pluginDumpID, "string", "pluginDumpID is correct type");
  isnot(aEvent.pluginDumpID, "", "got a non-empty dump ID");
  is(typeof aEvent.pluginName, "string", "pluginName is correct type");
  is(aEvent.pluginName, "Test Plug-in", "got correct plugin name");
  is(typeof aEvent.pluginFilename, "string", "pluginFilename is correct type");
  isnot(aEvent.pluginFilename, "", "got a non-empty filename");
  // The app itself may or may not have decided to submit the report, so
  // allow either true or false here.
  ok("submittedCrashReport" in aEvent, "submittedCrashReport is a property of event");
  is(typeof aEvent.submittedCrashReport, "boolean", "submittedCrashReport is correct type");

  os.removeObserver(testObserver, "plugin-crashed");
  --obsCount;
}

function resetVars() {
  iframe = document.getElementById('iframe1');
  p = iframe.contentDocument.getElementById("plugin1");
  if (obsCount == 0) {
    os.addObserver(testObserver, "plugin-crashed", true);
    ++obsCount;
  }
  iframe.contentDocument.addEventListener("PluginCrashed",
                                          onPluginCrashedHangUI,
                                          false);
}

function test9b() {
  hanguiExpect("test9b: Plugin Hang UI is not showing (checkbox)", false);
  p.stall(STALL_DURATION);
  hanguiExpect("test9b: Plugin Hang UI is still not showing (checkbox)", false, false, "finishTest");
  p.stall(STALL_DURATION);
}

function test9a() {
  resetVars();
  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
  SpecialPowers.setIntPref(timeoutPref, 45);
  hanguiContinue("test9a: Continue button works with checkbox", true, "test9b");
  p.stall(STALL_DURATION);
}

function test9() {
  window.frameLoaded = test9a;
  iframe.contentWindow.location.reload();
}

function test8a() {
  resetVars();
  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
  SpecialPowers.setIntPref(hangUIMinDisplayPref, 4);
  hanguiExpect("test8a: Plugin Hang UI is not showing (disabled due to hangUIMinDisplaySecs)", false, false, "test9");
  var exceptionThrown = false;
  try {
    p.hang();
  } catch(e) {
    exceptionThrown = true;
  }
  ok(exceptionThrown, "test8a: Exception thrown from hang() when plugin was terminated");
}

function test8() {
  window.frameLoaded = test8a;
  iframe.contentWindow.location.reload();
}

function test7a() {
  resetVars();
  SpecialPowers.setIntPref(hangUITimeoutPref, 0);
  hanguiExpect("test7a: Plugin Hang UI is not showing (disabled)", false, false, "test8");
  var exceptionThrown = false;
  try {
    p.hang();
  } catch(e) {
    exceptionThrown = true;
  }
  ok(exceptionThrown, "test7a: Exception thrown from hang() when plugin was terminated");
}

function test7() {
  window.frameLoaded = test7a;
  iframe.contentWindow.location.reload();
}

function test6() {
  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
  SpecialPowers.setIntPref(timeoutPref, 3);
  hanguiExpect("test6: Plugin Hang UI is showing", true, true, "test7");
  var exceptionThrown = false;
  try {
    p.hang();
  } catch(e) {
    exceptionThrown = true;
  }
  ok(exceptionThrown, "test6: Exception thrown from hang() when plugin was terminated (child timeout)");
}

function test5a() {
  resetVars();
  hanguiCancel("test5a: Close button works", "test6");
  p.stall(STALL_DURATION);
}

function test5() {
  window.frameLoaded = test5a;
  iframe.contentWindow.location.reload();
}

function test4() {
  hanguiStop("test4: Stop button works", false, "test5");
  // We'll get an exception here because the plugin was terminated
  var exceptionThrown = false;
  try {
    p.hang();
  } catch(e) {
    exceptionThrown = true;
  }
  ok(exceptionThrown, "test4: Exception thrown from hang() when plugin was terminated");
}

function test3() {
  hanguiContinue("test3: Continue button works", false, "test4");
  p.stall(STALL_DURATION);
}

function test2() {
  // This test is identical to test1 because there were some bugs where the
  // Hang UI would show on the first hang but not on subsequent hangs
  hanguiExpect("test2: Plugin Hang UI is showing", true, true, "test3");
  p.stall(STALL_DURATION);
}

function test1() {
  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
  SpecialPowers.setIntPref(timeoutPref, 45);
  hanguiExpect("test1: Plugin Hang UI is showing", true, true, "test2");
  p.stall(STALL_DURATION);
}

]]>
</script>
</window>