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 105617 72e95bee76fa7d6d8fba20342f97889c8ecbb320
parent 105616 6a8b865e6225f19de7258f1ee0a88e4837bcfdc7
child 105618 efc2630b978a8f758dcf9abe34b4bab25cd665de
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersjgriffin, DONTBUILD
bugs784509
milestone17.0a1
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();