Bug 784509 - New telephony tests for B2G, r=jgriffin, DONTBUILD because NPOTB
authorRob Wood <rwood@mozilla.com>
Fri, 24 Aug 2012 16:20:51 -0700
changeset 103584 72e95bee76fa7d6d8fba20342f97889c8ecbb320
parent 103583 6a8b865e6225f19de7258f1ee0a88e4837bcfdc7
child 103585 efc2630b978a8f758dcf9abe34b4bab25cd665de
push id23362
push userryanvm@gmail.com
push dateTue, 28 Aug 2012 02:11:38 +0000
treeherdermozilla-central@8af2ff9c6018 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgriffin, DONTBUILD
bugs784509
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 784509 - New telephony tests for B2G, r=jgriffin, DONTBUILD because NPOTB
dom/telephony/test/marionette/manifest.ini
dom/telephony/test/marionette/test_incoming_already_connected.js
dom/telephony/test/marionette/test_incoming_answer_remote_hangup.js
dom/telephony/test/marionette/test_incoming_connecting_hangup.js
dom/telephony/test/marionette/test_incoming_connecting_remote_hangup.js
dom/telephony/test/marionette/test_incoming_hangup_held.js
dom/telephony/test/marionette/test_incoming_remote_cancel.js
dom/telephony/test/marionette/test_incoming_remote_hangup_held.js
dom/telephony/test/marionette/test_outgoing_already_held.js
dom/telephony/test/marionette/test_outgoing_answer_local_hangup.js
dom/telephony/test/marionette/test_outgoing_remote_hangup_held.js
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -15,8 +15,19 @@ qemu = true
 #expectedfailure = true
 #[test_outgoing_busy.js]
 #expectedfailure = true
 [test_outgoing_reject.js]
 [test_voicemail_statuschanged.py]
 [test_voicemail_number.js]
 [test_incoming_hold_resume.js]
 [test_outgoing_hold_resume.js]
+[test_incoming_already_connected.js]
+[test_incoming_answer_remote_hangup.js]
+[test_incoming_connecting_hangup.js]
+[test_incoming_connecting_remote_hangup.js]
+[test_incoming_hangup_held.js]
+[test_incoming_remote_cancel.js]
+[test_incoming_remote_hangup_held.js]
+[test_outgoing_already_held.js]
+[test_outgoing_answer_local_hangup.js]
+[test_outgoing_remote_hangup_held.js]
+
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_incoming_already_connected.js
@@ -0,0 +1,206 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let outNumber = "5555551111";
+let inNumber = "5555552222";
+let outgoingCall;
+let incomingCall;
+let gotOriginalConnected = false;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    dial();
+  });
+}
+
+function dial() {
+  log("Make an outgoing call.");
+  outgoingCall = telephony.dial(outNumber);
+  ok(outgoingCall);
+  is(outgoingCall.number, outNumber);
+  is(outgoingCall.state, "dialing");
+
+  is(outgoingCall, telephony.active);
+  is(telephony.calls.length, 1);
+  is(telephony.calls[0], outgoingCall);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Call list is now: " + result);
+    is(result[0], "outbound to  " + outNumber + " : unknown");
+    is(result[1], "OK");
+    answer();
+  });
+}
+
+function answer() {
+  log("Answering the outgoing call.");
+
+  // We get no "connecting" event when the remote party answers the call.
+  outgoingCall.onconnected = function onconnectedOut(event) {
+    log("Received 'connected' call event for the original outgoing call.");
+
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "connected");
+    is(outgoingCall, telephony.active);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : active");
+      is(result[1], "OK");
+
+      if(!gotOriginalConnected){
+        gotOriginalConnected = true;
+        simulateIncoming();
+      } else {
+        // Received connected event for original call multiple times (fail)
+        ok(false,
+           "Received 'connected' event for original call multiple times");
+      }
+    });
+  };
+  runEmulatorCmd("gsm accept " + outNumber);
+}
+
+// With one connected call already, simulate an incoming call
+function simulateIncoming() {
+  log("Simulating an incoming call (with one call already connected).");
+
+  telephony.onincoming = function onincoming(event) {
+    log("Received 'incoming' call event.");
+    incomingCall = event.call;
+    ok(incomingCall);
+    is(incomingCall.number, inNumber);
+    is(incomingCall.state, "incoming");
+
+    // Should be two calls now
+    is(telephony.calls.length, 2);
+    is(telephony.calls[0], outgoingCall);
+    is(telephony.calls[1], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : active");
+      is(result[1], "inbound from " + inNumber + " : incoming");
+      is(result[2], "OK");
+      answerIncoming();
+    });
+  };
+  runEmulatorCmd("gsm call " + inNumber);
+}
+
+// Answer incoming call; original outgoing call should be held
+function answerIncoming() {
+  log("Answering the incoming call.");
+
+  let gotConnecting = false;
+  incomingCall.onconnecting = function onconnectingIn(event) { 
+    log("Received 'connecting' call event for incoming/2nd call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connecting");
+    gotConnecting = true;
+  };
+
+  incomingCall.onconnected = function onconnectedIn(event) {
+    log("Received 'connected' call event for incoming/2nd call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connected");
+    ok(gotConnecting);
+
+    is(incomingCall, telephony.active);
+    is(outgoingCall.state, "held");
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : held");
+      is(result[1], "inbound from " + inNumber + " : active");
+      is(result[2], "OK");
+      hangUpOutgoing();
+    });
+  };
+  incomingCall.answer();
+}
+
+// Hang-up original outgoing (now held) call
+function hangUpOutgoing() {
+  log("Hanging up the original outgoing (now held) call.");
+
+  let gotDisconnecting = false;
+  outgoingCall.ondisconnecting = function ondisconnectingOut(event) {
+    log("Received 'disconnecting' call event for original outgoing call.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "disconnecting");
+    gotDisconnecting = true;
+  };
+
+  outgoingCall.ondisconnected = function ondisconnectedOut(event) {
+    log("Received 'disconnected' call event for original outgoing call.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "disconnected");
+    ok(gotDisconnecting);
+
+    // Back to one call now
+    is(telephony.calls.length, 1);
+    is(incomingCall.state, "connected");
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : active");
+      is(result[1], "OK");
+      hangUpIncoming();
+    });
+  };
+  outgoingCall.hangUp();
+}
+
+// Hang-up remaining (incoming) call
+function hangUpIncoming() {
+  log("Hanging up the remaining (incoming) call.");
+
+  let gotDisconnecting = false;
+  incomingCall.ondisconnecting = function ondisconnectingIn(event) {
+    log("Received 'disconnecting' call event for remaining (incoming) call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnecting");
+    gotDisconnecting = true;
+  };
+
+  incomingCall.ondisconnected = function ondisconnectedIn(event) {
+    log("Received 'disconnected' call event for remaining (incoming) call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnected");
+    ok(gotDisconnecting);
+
+    // Zero calls left
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  incomingCall.hangUp();
+}
+
+function cleanUp() {
+  telephony.onincoming = null;
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_incoming_answer_remote_hangup.js
@@ -0,0 +1,107 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let inNumber = "5555551111";
+let incomingCall;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    simulateIncoming();
+  });
+}
+
+function simulateIncoming() {
+  log("Simulating an incoming call.");
+
+  telephony.onincoming = function onincoming(event) {
+    log("Received 'incoming' call event.");
+    incomingCall = event.call;
+    ok(incomingCall);
+    is(incomingCall.number, inNumber);
+    is(incomingCall.state, "incoming");
+
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : incoming");
+      is(result[1], "OK");
+      answerIncoming();
+    });
+  };
+  runEmulatorCmd("gsm call " + inNumber);
+}
+
+function answerIncoming() {
+  log("Answering the incoming call.");
+
+  let gotConnecting = false;
+  incomingCall.onconnecting = function onconnectingIn(event) { 
+    log("Received 'connecting' call event for incoming call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connecting");
+    gotConnecting = true;
+  };
+
+  incomingCall.onconnected = function onconnectedIn(event) {
+    log("Received 'connected' call event for incoming call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connected");
+    ok(gotConnecting);
+
+    is(incomingCall, telephony.active);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : active");
+      is(result[1], "OK");
+      remoteHangUp();
+    });
+  };
+  incomingCall.answer();
+}
+
+function remoteHangUp() {
+  log("Hanging up the call (remotely)");
+
+  // We get no 'disconnecting' event when remote party hangs-up the call
+
+  incomingCall.ondisconnected = function ondisconnected(event) {
+    log("Received 'disconnected' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnected");
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  runEmulatorCmd("gsm cancel " + inNumber);
+}
+
+function cleanUp() {
+  telephony.onincoming = null;
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_incoming_connecting_hangup.js
@@ -0,0 +1,113 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let inNumber = "5555551111";
+let incomingCall;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    simulateIncoming();
+  });
+}
+
+function simulateIncoming() {
+  log("Simulating an incoming call.");
+
+  telephony.onincoming = function onincoming(event) {
+    log("Received 'incoming' call event.");
+    incomingCall = event.call;
+    ok(incomingCall);
+    is(incomingCall.number, inNumber);
+    is(incomingCall.state, "incoming");
+
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : incoming");
+      is(result[1], "OK");
+      answerIncoming();
+    });
+  };
+  runEmulatorCmd("gsm call " + inNumber);
+}
+
+function answerIncoming() {
+  log("Answering the incoming call.");
+
+  incomingCall.onconnecting = function onconnecting(event) { 
+    log("Received 'connecting' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connecting");
+    // Now hang-up the call before it is fully connected
+
+    // Bug 784429: Hang-up while connecting, call is not terminated
+    // If hang-up between 'connecting' and 'connected' states, receive the
+    // 'disconnecting' event but then a 'connected' event, and the call is
+    // never terminated; this test times out waiting for 'disconnected', and
+    // will leave the emulator in a bad state (with an active incoming call).
+    // For now, hangUp after the 'connected' event so this test doesn't
+    // timeout; once the bug is fixed then update and remove the setTimeout
+
+    //hangUp();
+    log("==> Waiting one second, remove wait once bug 784429 is fixed <==");
+    setTimeout(hangUp, 1000);
+  };
+
+  incomingCall.onconnected = function onconnected(event) {
+    log("Received 'connected' call event.");
+  };
+  incomingCall.answer();
+};
+
+function hangUp() {
+  log("Hanging up the incoming call before fully connected.");
+
+  let gotDisconnecting = false;
+  incomingCall.ondisconnecting = function ondisconnecting(event) {
+    log("Received 'disconnecting' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnecting");
+    gotDisconnecting = true;
+  };
+
+  incomingCall.ondisconnected = function ondisconnected(event) {
+    log("Received 'disconnected' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnected");
+    ok(gotDisconnecting);
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  incomingCall.hangUp();
+}
+
+function cleanUp() {
+  telephony.onincoming = null;
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_incoming_connecting_remote_hangup.js
@@ -0,0 +1,95 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let inNumber = "5555551111";
+let incomingCall;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    simulateIncoming();
+  });
+}
+
+function simulateIncoming() {
+  log("Simulating an incoming call.");
+
+  telephony.onincoming = function onincoming(event) {
+    log("Received 'incoming' call event.");
+    incomingCall = event.call;
+    ok(incomingCall);
+    is(incomingCall.number, inNumber);
+    is(incomingCall.state, "incoming");
+
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : incoming");
+      is(result[1], "OK");
+      answerIncoming();
+    });
+  };
+  runEmulatorCmd("gsm call " + inNumber);
+}
+
+function answerIncoming() {
+  log("Answering the incoming call.");
+
+  incomingCall.onconnecting = function onconnecting(event) { 
+    log("Received 'connecting' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connecting");
+    // Now have the remote party hang-up the call before it is fully connected
+    remoteHangUp();
+  };
+
+  incomingCall.onconnected = function onconnected(event) {
+    log("Received 'connected' call event.");
+  };
+  incomingCall.answer();
+};
+
+function remoteHangUp() {
+  log("Hanging up the incoming call (remotely) before fully connected.");
+
+  // We get no 'disconnecting' event when remote party hangs-up the call
+
+  incomingCall.ondisconnected = function ondisconnected(event) {
+    log("Received 'disconnected' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnected");
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  runEmulatorCmd("gsm cancel " + inNumber);
+}
+
+function cleanUp() {
+  telephony.onincoming = null;
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_incoming_hangup_held.js
@@ -0,0 +1,145 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let inNumber = "5555551111";
+let incomingCall;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    simulateIncoming();
+  });
+}
+
+function simulateIncoming() {
+  log("Simulating an incoming call.");
+
+  telephony.onincoming = function onincoming(event) {
+    log("Received 'incoming' call event.");
+    incomingCall = event.call;
+    ok(incomingCall);
+    is(incomingCall.number, inNumber);
+    is(incomingCall.state, "incoming");
+
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : incoming");
+      is(result[1], "OK");
+      answerIncoming();
+    });
+  };
+  runEmulatorCmd("gsm call " + inNumber);
+}
+
+function answerIncoming() {
+  log("Answering the incoming call.");
+
+  let gotConnecting = false;
+  incomingCall.onconnecting = function onconnectingIn(event) { 
+    log("Received 'connecting' call event for incoming call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connecting");
+    gotConnecting = true;
+  };
+
+  incomingCall.onconnected = function onconnectedIn(event) {
+    log("Received 'connected' call event for incoming call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connected");
+    ok(gotConnecting);
+
+    is(incomingCall, telephony.active);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : active");
+      is(result[1], "OK");
+      hold();
+    });
+  };
+  incomingCall.answer();
+}
+
+function hold() {
+  log("Putting the call on hold.");
+
+  let gotHolding = false;
+  incomingCall.onholding = function onholding(event) {
+    log("Received 'holding' call event");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "holding");
+    gotHolding = true;
+  };
+
+  incomingCall.onheld = function onheld(event) {
+    log("Received 'held' call event");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "held");
+    ok(gotHolding);
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : held");
+      is(result[1], "OK");
+      hangUp();
+    });
+  };
+  incomingCall.hold();
+}
+
+function hangUp() {
+  log("Hanging up the held call (local hang-up).");
+
+  let gotDisconnecting = false;
+  incomingCall.ondisconnecting = function ondisconnecting(event) {
+    log("Received 'disconnecting' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnecting");
+    gotDisconnecting = true;
+  };
+
+  incomingCall.ondisconnected = function ondisconnectedOut(event) {
+    log("Received 'disconnected' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnected");
+    ok(gotDisconnecting);
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  incomingCall.hangUp();
+}
+
+function cleanUp() {
+  telephony.onincoming = null;
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_incoming_remote_cancel.js
@@ -0,0 +1,78 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let inNumber = "5555551111";
+let incomingCall;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    simulateIncoming();
+  });
+}
+
+function simulateIncoming() {
+  log("Simulating an incoming call.");
+
+  telephony.onincoming = function onincoming(event) {
+    log("Received 'incoming' call event.");
+    incomingCall = event.call;
+    ok(incomingCall);
+    is(incomingCall.number, inNumber);
+    is(incomingCall.state, "incoming");
+
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : incoming");
+      is(result[1], "OK");
+      cancelIncoming();
+    });
+  };
+  runEmulatorCmd("gsm call " + inNumber);
+}
+
+function cancelIncoming(){
+  log("Remote party cancelling call before it is answered.");
+
+  // We get no 'disconnecting' event when remote party cancels/hangs-up call
+
+  incomingCall.ondisconnected = function ondisconnected(event) {
+    log("Received 'disconnected' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnected");
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  runEmulatorCmd("gsm cancel " + inNumber);
+}
+
+function cleanUp() {
+  telephony.onincoming = null;
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_incoming_remote_hangup_held.js
@@ -0,0 +1,138 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let inNumber = "5555551111";
+let incomingCall;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    simulateIncoming();
+  });
+}
+
+function simulateIncoming() {
+  log("Simulating an incoming call.");
+
+  telephony.onincoming = function onincoming(event) {
+    log("Received 'incoming' call event.");
+    incomingCall = event.call;
+    ok(incomingCall);
+    is(incomingCall.number, inNumber);
+    is(incomingCall.state, "incoming");
+
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : incoming");
+      is(result[1], "OK");
+      answerIncoming();
+    });
+  };
+  runEmulatorCmd("gsm call " + inNumber);
+}
+
+function answerIncoming() {
+  log("Answering the incoming call.");
+
+  let gotConnecting = false;
+  incomingCall.onconnecting = function onconnectingIn(event) { 
+    log("Received 'connecting' call event for incoming call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connecting");
+    gotConnecting = true;
+  };
+
+  incomingCall.onconnected = function onconnectedIn(event) {
+    log("Received 'connected' call event for incoming call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connected");
+    ok(gotConnecting);
+
+    is(incomingCall, telephony.active);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : active");
+      is(result[1], "OK");
+      hold();
+    });
+  };
+  incomingCall.answer();
+}
+
+function hold() {
+  log("Putting the call on hold.");
+
+  let gotHolding = false;
+  incomingCall.onholding = function onholding(event) {
+    log("Received 'holding' call event");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "holding");
+    gotHolding = true;
+  };
+
+  incomingCall.onheld = function onheld(event) {
+    log("Received 'held' call event");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "held");
+    ok(gotHolding);
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : held");
+      is(result[1], "OK");
+      hangUp();
+    });
+  };
+  incomingCall.hold();
+}
+
+function hangUp() {
+  log("Hanging up the held call (remotely).");
+
+  // We get no 'disconnecting' event when remote party hangs-up the call
+
+  incomingCall.ondisconnected = function ondisconnected(event) {
+    log("Received 'disconnected' call event.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnected");
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  runEmulatorCmd("gsm cancel " + inNumber);
+}
+
+function cleanUp() {
+  telephony.onincoming = null;
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_outgoing_already_held.js
@@ -0,0 +1,229 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let inNumber = "5555551111";
+let outNumber = "5555552222";
+let incomingCall;
+let outgoingCall;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    simulateIncoming();
+  });
+}
+
+function simulateIncoming() {
+  log("Simulating an incoming call.");
+
+  telephony.onincoming = function onincoming(event) {
+    log("Received 'incoming' call event.");
+    incomingCall = event.call;
+    ok(incomingCall);
+    is(incomingCall.number, inNumber);
+    is(incomingCall.state, "incoming");
+
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : incoming");
+      is(result[1], "OK");
+      answerIncoming();
+    });
+  };
+  runEmulatorCmd("gsm call " + inNumber);
+}
+
+function answerIncoming() {
+  log("Answering the incoming call.");
+
+  let gotConnecting = false;
+  incomingCall.onconnecting = function onconnectingIn(event) { 
+    log("Received 'connecting' call event for original (incoming) call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connecting");
+    gotConnecting = true;
+  };
+
+  incomingCall.onconnected = function onconnectedIn(event) {
+    log("Received 'connected' call event for original (incoming) call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "connected");
+    ok(gotConnecting);
+
+    is(incomingCall, telephony.active);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : active");
+      is(result[1], "OK");
+      holdCall();
+    });
+  };
+  incomingCall.answer();
+}
+
+// Put the original (incoming) call on hold
+function holdCall(){
+  log("Putting the original (incoming) call on hold.");
+  
+  let gotHolding = false;
+  incomingCall.onholding = function onholding(event) {
+    log("Received 'holding' call event");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "holding");
+    gotHolding = true;
+  };
+
+  incomingCall.onheld = function onheld(event) {
+    log("Received 'held' call event");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "held");
+    ok(gotHolding);
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], incomingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : held");
+      is(result[1], "OK");   
+      dial();
+    });
+  };
+  incomingCall.hold();
+}
+
+// With one call on hold, make outgoing call
+function dial() {
+  log("Making an outgoing call (while have one call already held).");
+  
+  outgoingCall = telephony.dial(outNumber);
+  ok(outgoingCall);
+  is(outgoingCall.number, outNumber);
+  is(outgoingCall.state, "dialing");
+
+  is(outgoingCall, telephony.active);
+  is(telephony.calls.length, 2);
+  is(telephony.calls[0], incomingCall);
+  is(telephony.calls[1], outgoingCall);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Call list is now: " + result);
+    is(result[0], "inbound from " + inNumber + " : held");
+    is(result[1], "outbound to  " + outNumber + " : unknown");
+    is(result[2], "OK");
+    answerOutgoing();
+  });
+}
+
+// Have the outgoing call answered
+function answerOutgoing() {
+  log("Answering the outgoing/2nd call");
+
+  // We get no "connecting" event when the remote party answers the call.
+  outgoingCall.onconnected = function onconnectedOut(event) {
+    log("Received 'connected' call event for outgoing/2nd call.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "connected");
+
+    is(outgoingCall, telephony.active);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "inbound from " + inNumber + " : held");
+      is(result[1], "outbound to  " + outNumber + " : active");
+      is(result[2], "OK");
+      hangUpIncoming();
+    });
+  };
+  runEmulatorCmd("gsm accept " + outNumber);
+}
+
+// Hang-up the original incoming call, which is now held
+function hangUpIncoming() {
+  log("Hanging up the original incoming (now held) call.");
+
+  let gotDisconnecting = false;
+  incomingCall.ondisconnecting = function ondisconnectingIn(event) {
+    log("Received 'disconnecting' call event for original (incoming) call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnecting");
+    gotDisconnecting = true;
+  };
+
+  incomingCall.ondisconnected = function ondisconnectedIn(event) {
+    log("Received 'disconnected' call event for original (incoming) call.");
+    is(incomingCall, event.call);
+    is(incomingCall.state, "disconnected");
+    ok(gotDisconnecting);
+
+    // Now back to one call
+    is(telephony.active, outgoingCall);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : active");
+      is(result[1], "OK");
+      hangUpOutgoing();
+    });
+  };
+  incomingCall.hangUp();
+}
+
+// Hang-up the remaining (outgoing) call
+function hangUpOutgoing() {
+  log("Hanging up the remaining (outgoing) call.");
+ 
+  let gotDisconnecting = false;
+  outgoingCall.ondisconnecting = function ondisconnectingOut(event) {
+    log("Received 'disconnecting' call event for remaining (outgoing) call.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "disconnecting");
+    gotDisconnecting = true;
+  };
+
+  outgoingCall.ondisconnected = function ondisconnectedOut(event) {
+    log("Received 'disconnected' call event for remaining (outgoing) call.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "disconnected");
+    ok(gotDisconnecting);
+
+    // Now no calls
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  outgoingCall.hangUp();  
+}
+
+function cleanUp() {
+  telephony.onincoming = null;
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_outgoing_answer_local_hangup.js
@@ -0,0 +1,110 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let outgoingCall;
+let outNumber = "5555551111";
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    dial();
+  });
+}
+
+function dial() {
+  log("Make an outgoing call.");
+
+  outgoingCall = telephony.dial(outNumber);
+  ok(outgoingCall);
+  is(outgoingCall.number, outNumber);
+  is(outgoingCall.state, "dialing");
+
+  is(outgoingCall, telephony.active);
+  is(telephony.calls.length, 1);
+  is(telephony.calls[0], outgoingCall);
+
+  outgoingCall.onalerting = function onalerting(event) {
+    log("Received 'alerting' call event.");
+
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "alerting");
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : ringing");
+      is(result[1], "OK");
+      answer();
+    });
+  };
+}
+
+function answer() {
+  log("Answering the outgoing call.");
+
+  // We get no "connecting" event when the remote party answers the call.
+
+  outgoingCall.onconnected = function onconnected(event) {
+    log("Received 'connected' call event.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "connected");
+
+    is(outgoingCall, telephony.active);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : active");
+      is(result[1], "OK");
+      hangUp();
+    });
+  };
+  runEmulatorCmd("gsm accept " + outNumber);
+};
+
+function hangUp() {
+  log("Hanging up the outgoing call (local hang-up).");
+
+  let gotDisconnecting = false;
+  outgoingCall.ondisconnecting = function ondisconnectingOut(event) {
+    log("Received 'disconnecting' call event.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "disconnecting");
+    gotDisconnecting = true;
+  };
+
+  outgoingCall.ondisconnected = function ondisconnectedOut(event) {
+    log("Received 'disconnected' call event.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "disconnected");
+    ok(gotDisconnecting);
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  outgoingCall.hangUp();
+}
+
+function cleanUp() {
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_outgoing_remote_hangup_held.js
@@ -0,0 +1,133 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+SpecialPowers.addPermission("telephony", true, document);
+
+let telephony = window.navigator.mozTelephony;
+let outNumber = "5555551111";
+let outgoingCall;
+
+function verifyInitialState() {
+  log("Verifying initial state.");
+  ok(telephony);
+  is(telephony.active, null);
+  ok(telephony.calls);
+  is(telephony.calls.length, 0);
+
+  runEmulatorCmd("gsm list", function(result) {
+    log("Initial call list: " + result);
+    is(result[0], "OK");
+    dial();
+  });
+}
+
+function dial() {
+  log("Make an outgoing call.");
+
+  outgoingCall = telephony.dial(outNumber);
+  ok(outgoingCall);
+  is(outgoingCall.number, outNumber);
+  is(outgoingCall.state, "dialing");
+
+  is(outgoingCall, telephony.active);
+  is(telephony.calls.length, 1);
+  is(telephony.calls[0], outgoingCall);
+
+  outgoingCall.onalerting = function onalerting(event) {
+    log("Received 'alerting' call event.");
+
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "alerting");
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : ringing");
+      is(result[1], "OK");
+      answer();
+    });
+  };
+}
+
+function answer() {
+  log("Answering the outgoing call.");
+
+  // We get no "connecting" event when the remote party answers the call.
+
+  outgoingCall.onconnected = function onconnected(event) {
+    log("Received 'connected' call event.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "connected");
+
+    is(outgoingCall, telephony.active);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : active");
+      is(result[1], "OK");
+      hold();
+    });
+  };
+  runEmulatorCmd("gsm accept " + outNumber);
+};
+
+function hold() {
+  log("Holding the outgoing call.");
+
+  outgoingCall.onholding = function onholding(event) {
+    log("Received 'holding' call event.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "holding");
+
+    is(outgoingCall, telephony.active);
+  };
+
+  outgoingCall.onheld = function onheld(event) {
+    log("Received 'held' call event.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "held");
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 1);
+    is(telephony.calls[0], outgoingCall);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "outbound to  " + outNumber + " : held");
+      is(result[1], "OK");
+      hangUp();
+    });
+  };
+  outgoingCall.hold();
+}
+
+function hangUp() {
+  log("Hanging up the outgoing call (remotely).");
+
+  // We get no 'disconnecting' event when remote party hangs-up the call
+  
+  outgoingCall.ondisconnected = function ondisconnected(event) {
+    log("Received 'disconnected' call event.");
+    is(outgoingCall, event.call);
+    is(outgoingCall.state, "disconnected");
+
+    is(telephony.active, null);
+    is(telephony.calls.length, 0);
+
+    runEmulatorCmd("gsm list", function(result) {
+      log("Call list is now: " + result);
+      is(result[0], "OK");
+      cleanUp();
+    });
+  };
+  runEmulatorCmd("gsm cancel " + outNumber);
+}
+
+function cleanUp() {
+  SpecialPowers.removePermission("telephony", document);
+  finish();
+}
+
+// Start the test
+verifyInitialState();