Bug 961921 - Part 2: add data connection tests for DSDS. r=hsinyi
authorJessica Jong <jjong@mozilla.com>
Wed, 09 Apr 2014 18:54:00 +0200
changeset 177759 6892cdd30dd729f6bf8a0b28beb53af2cf428981
parent 177758 59f927e60a53699d16ca52cbdf15e58d6d875911
child 177760 c8388e3bac74adf61343c92794c51e885c6c3b67
push id6121
push usercbook@mozilla.com
push dateThu, 10 Apr 2014 09:51:13 +0000
treeherderb2g-inbound@6892cdd30dd7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsinyi
bugs961921
milestone31.0a1
Bug 961921 - Part 2: add data connection tests for DSDS. r=hsinyi
dom/mobileconnection/tests/marionette/head.js
dom/mobileconnection/tests/marionette/manifest.ini
dom/mobileconnection/tests/marionette/test_dsds_mobile_data_connection.js
--- a/dom/mobileconnection/tests/marionette/head.js
+++ b/dom/mobileconnection/tests/marionette/head.js
@@ -265,24 +265,32 @@ function ensureMobileConnection(aAdditio
  * Wait for one named MobileConnection event.
  *
  * Resolve if that named event occurs.  Never reject.
  *
  * Fulfill params: the DOMEvent passed.
  *
  * @param aEventName
  *        A string event name.
+ * @param aServiceId [optional]
+ *        A numeric DSDS service id. Default: the one indicated in
+ *        start*TestCommon() or 0 if not indicated.
  *
  * @return A deferred promise.
  */
-function waitForManagerEvent(aEventName) {
+function waitForManagerEvent(aEventName, aServiceId) {
   let deferred = Promise.defer();
 
-  mobileConnection.addEventListener(aEventName, function onevent(aEvent) {
-    mobileConnection.removeEventListener(aEventName, onevent);
+  let mobileConn = mobileConnection;
+  if (aServiceId !== undefined) {
+    mobileConn = navigator.mozMobileConnections[aServiceId];
+  }
+
+  mobileConn.addEventListener(aEventName, function onevent(aEvent) {
+    mobileConn.removeEventListener(aEventName, onevent);
 
     ok(true, "MobileConnection event '" + aEventName + "' got.");
     deferred.resolve(aEvent);
   });
 
   return deferred.promise;
 }
 
@@ -378,82 +386,101 @@ function selectNetworkAutomaticallyAndWa
  * Set data connection enabling state and wait for "datachange" event.
  *
  * Resolve if data connection state changed to the expected one.  Never reject.
  *
  * Fulfill params: (none)
  *
  * @param aEnabled
  *        A boolean state.
+ * @param aServiceId [optional]
+ *        A numeric DSDS service id. Default: the one indicated in
+ *        start*TestCommon() or 0 if not indicated.
  *
  * @return A deferred promise.
  */
-function setDataEnabledAndWait(aEnabled) {
+function setDataEnabledAndWait(aEnabled, aServiceId) {
   let deferred = Promise.defer();
 
   let promises = [];
-  promises.push(waitForManagerEvent("datachange"));
+  promises.push(waitForManagerEvent("datachange", aServiceId));
   promises.push(setDataEnabled(aEnabled));
   Promise.all(promises).then(function keepWaiting() {
+    let mobileConn = mobileConnection;
+    if (aServiceId !== undefined) {
+      mobileConn = navigator.mozMobileConnections[aServiceId];
+    }
     // To ignore some transient states, we only resolve that deferred promise
     // when the |connected| state equals to the expected one and never rejects.
-    let connected = mobileConnection.data.connected;
+    let connected = mobileConn.data.connected;
     if (connected == aEnabled) {
       deferred.resolve();
       return;
     }
 
-    return waitForManagerEvent("datachange").then(keepWaiting);
+    return waitForManagerEvent("datachange", aServiceId).then(keepWaiting);
   });
 
   return deferred.promise;
 }
 
 /**
  * Set voice/data state and wait for state change.
  *
  * Fulfill params: (none)
  *
  * @param aWhich
  *        "voice" or "data".
  * @param aState
  *        "unregistered", "searching", "denied", "roaming", or "home".
+ * @param aServiceId [optional]
+ *        A numeric DSDS service id. Default: the one indicated in
+ *        start*TestCommon() or 0 if not indicated.
  *
  * @return A deferred promise.
  */
-function setEmulatorVoiceDataStateAndWait(aWhich, aState) {
+function setEmulatorVoiceDataStateAndWait(aWhich, aState, aServiceId) {
   let promises = [];
-  promises.push(waitForManagerEvent(aWhich + "change"));
+  promises.push(waitForManagerEvent(aWhich + "change", aServiceId));
 
   let cmd = "gsm " + aWhich + " " + aState;
   promises.push(runEmulatorCmdSafe(cmd));
   return Promise.all(promises);
 }
 
 /**
  * Set voice and data roaming emulation and wait for state change.
  *
  * Fulfill params: (none)
  *
  * @param aRoaming
  *        A boolean state.
+ * @param aServiceId [optional]
+ *        A numeric DSDS service id. Default: the one indicated in
+ *        start*TestCommon() or 0 if not indicated.
  *
  * @return A deferred promise.
  */
-function setEmulatorRoamingAndWait(aRoaming) {
-  function doSetAndWait(aWhich, aRoaming) {
+function setEmulatorRoamingAndWait(aRoaming, aServiceId) {
+  function doSetAndWait(aWhich, aRoaming, aServiceId) {
     let state = (aRoaming ? "roaming" : "home");
-    return setEmulatorVoiceDataStateAndWait(aWhich, state)
-      .then(() => is(mobileConnection[aWhich].roaming, aRoaming,
-                     aWhich + ".roaming"));
+    return setEmulatorVoiceDataStateAndWait(aWhich, state, aServiceId)
+      .then(() => {
+        let mobileConn = mobileConnection;
+        if (aServiceId !== undefined) {
+          mobileConn = navigator.mozMobileConnections[aServiceId];
+        }
+        is(mobileConn[aWhich].roaming, aRoaming,
+                     aWhich + ".roaming")
+      });
   }
 
   // Set voice registration state first and then data registration state.
-  return doSetAndWait("voice", aRoaming)
-    .then(() => doSetAndWait("data", aRoaming));
+  return doSetAndWait("voice", aRoaming, aServiceId)
+    .then(() => doSetAndWait("data", aRoaming, aServiceId));
 }
 
 /**
  * Get GSM location emulation.
  *
  * Fulfill params:
  *   { lac: <lac>, cid: <cid> }
  * Reject params:
@@ -581,16 +608,33 @@ function getNetworkManager() {
     _networkManager = Cc["@mozilla.org/network/manager;1"]
                     .getService(Ci.nsINetworkManager);
     ok(_networkManager, "NetworkManager");
   }
 
   return _networkManager;
 }
 
+let _numOfRadioInterfaces;
+
+/*
+ * Get number of radio interfaces. Default is 1 if preference is not set.
+ */
+function getNumOfRadioInterfaces() {
+  if (!_numOfRadioInterfaces) {
+    try {
+      _numOfRadioInterfaces = SpecialPowers.getIntPref("ril.numRadioInterfaces");
+    } catch (ex) {
+      _numOfRadioInterfaces = 1;  // Pref not set.
+    }
+  }
+
+  return _numOfRadioInterfaces;
+}
+
 /**
  * Flush permission settings and call |finish()|.
  */
 function cleanUp() {
   waitFor(function() {
     SpecialPowers.flushPermissions(function() {
       // Use ok here so that we have at least one test run.
       ok(true, "permissions flushed");
@@ -634,8 +678,36 @@ function startTestBase(aTestCaseMain) {
  *        A numeric DSDS service id. Default: 0.
  */
 function startTestCommon(aTestCaseMain, aAdditionalPermissions, aServiceId) {
   startTestBase(function() {
     return ensureMobileConnection(aAdditionalPermissions, aServiceId)
       .then(aTestCaseMain);
   });
 }
+
+/**
+ * Common test routine helper for multi-sim mobile connection tests. The test
+ * ends immediately if the device tested is not multi-sim.
+ *
+ * This function ensures global |mobileConnection| variable is available during
+ * the process and performs clean-ups as well.
+ *
+ * @param aTestCaseMain
+ *        A function that takes one parameter -- mobileConnection.
+ * @param aAdditonalPermissions [optional]
+ *        An array of permission strings other than "mobileconnection" to be
+ *        pushed. Default: empty string.
+ * @param aServiceId [optional]
+ *        A numeric DSDS service id. Default: 0.
+ */
+function startDSDSTestCommon(aTestCaseMain, aAdditionalPermissions, aServiceId) {
+    if (getNumOfRadioInterfaces() > 1) {
+      startTestBase(function() {
+        return ensureMobileConnection(aAdditionalPermissions, aServiceId)
+          .then(aTestCaseMain);
+      });
+    } else {
+      log("Skipping DSDS tests on single SIM device.")
+      ok(true);  // We should run at least one test.
+      cleanUp();
+    }
+}
\ No newline at end of file
--- a/dom/mobileconnection/tests/marionette/manifest.ini
+++ b/dom/mobileconnection/tests/marionette/manifest.ini
@@ -20,8 +20,9 @@ qemu = true
 [test_call_barring_change_password.js]
 [test_mobile_set_radio.js]
 [test_mobile_last_known_network.js]
 [test_mobile_icc_change.js]
 [test_mobile_connections_array_uninitialized.js]
 [test_mobile_signal_strength.js]
 [test_mobile_data_ipv6.js]
 disabled = Bug 979137
+[test_dsds_mobile_data_connection.js]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/mobileconnection/tests/marionette/test_dsds_mobile_data_connection.js
@@ -0,0 +1,151 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+const SETTINGS_KEY_DATA_DEFAULT_ID = "ril.data.defaultServiceId";
+
+let connections = window.navigator.mozMobileConnections;
+let numOfRadioInterfaces = getNumOfRadioInterfaces();
+let currentDataDefaultId = 0;
+
+function muxModem(id) {
+  return runEmulatorCmdSafe("mux modem " + id);
+}
+
+function switchDataDefaultId(defaultId) {
+  return Promise.resolve()
+    .then(() => setSettings1(SETTINGS_KEY_DATA_DEFAULT_ID, defaultId))
+    .then(() => {
+      log("Data default id switched to: " + defaultId);
+      currentDataDefaultId = defaultId;
+    });
+}
+
+function setDataRoamingSettings(enableDataRoammingIds) {
+  let dataRoamingSettings = [];
+  for (let i = 0; i < numOfRadioInterfaces; i++) {
+    dataRoamingSettings.push(false);
+  }
+
+  for (let i = 0; i < enableDataRoammingIds.length; i++) {
+    log("Enable data roaming for id: " + enableDataRoammingIds[i]);
+    dataRoamingSettings[enableDataRoammingIds[i]] = true;
+  }
+
+  return setDataRoamingEnabled(dataRoamingSettings);
+}
+
+function setApnSettings() {
+  let apn = [{
+    "carrier":"T-Mobile US",
+    "apn":"epc.tmobile.com",
+    "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc",
+    "types":["default","supl","mms"]
+  }];
+
+  // Use the same APN for all sims for now.
+  let apns = [];
+  for (let i = 0; i < numOfRadioInterfaces; i++) {
+    apns.push(apn);
+  }
+
+  return setDataApnSettings(apns);
+
+}
+
+function waitForDataState(clientId, connected) {
+  let deferred = Promise.defer();
+
+  let connection = connections[clientId];
+  if (connection.data.connected === connected) {
+    log("data connection for client " + clientId + " is now " +
+      connection.data.connected);
+    deferred.resolve();
+    return;
+  }
+
+  return Promise.resolve()
+    .then(() => waitForManagerEvent("datachange", clientId))
+    .then(() => waitForDataState(clientId, connected));
+}
+
+function restoreTestEnvironment() {
+  return Promise.resolve()
+    .then(() => setEmulatorRoamingAndWait(false, currentDataDefaultId))
+    .then(() => setDataRoamingSettings([]))
+    .then(() => switchDataDefaultId(0))
+    .then(() => muxModem(0));
+}
+
+function testEnableData() {
+  log("Turn data on.");
+
+  let connection = connections[currentDataDefaultId];
+  is(connection.data.connected, false);
+
+  return Promise.resolve()
+    .then(() => setApnSettings())
+    .then(() => setDataEnabledAndWait(true, currentDataDefaultId));
+}
+
+function testSwitchDefaultDataToSimTwo() {
+  log("Switch data connection to sim 2.");
+
+  is(currentDataDefaultId, 0);
+  let connection = connections[currentDataDefaultId];
+  is(connection.data.connected, true);
+
+  return Promise.resolve()
+    .then(() => switchDataDefaultId(1))
+    .then(() => {
+      is(currentDataDefaultId, 1);
+    })
+    .then(() => waitForDataState(currentDataDefaultId, true));
+}
+
+function testDisableDataRoamingWhileRoaming() {
+  log("Disable data roaming setting while roaming.");
+
+  let connection = connections[currentDataDefaultId];
+  is(connection.data.connected, true);
+  is(connection.data.roaming, false);
+
+  return Promise.resolve()
+    .then(() => setDataRoamingSettings([]))
+    .then(() => muxModem(currentDataDefaultId))
+    .then(() => setEmulatorRoamingAndWait(true, currentDataDefaultId))
+    .then(() => waitForDataState(currentDataDefaultId, false));
+}
+
+function testEnableDataRoamingWhileRoaming() {
+  log("Enable data roaming setting while roaming.");
+
+  let connection = connections[currentDataDefaultId];
+  is(connection.data.connected, false);
+  is(connection.data.roaming, true);
+
+  return Promise.resolve()
+    .then(() => setDataRoamingSettings([currentDataDefaultId]))
+    .then(() => waitForDataState(currentDataDefaultId, true));
+}
+
+function testDisableData() {
+  log("Turn data off.");
+
+  let connection = connections[currentDataDefaultId];
+  is(connection.data.connected, true);
+
+  return Promise.resolve()
+    .then(() => setDataEnabledAndWait(false, currentDataDefaultId));
+}
+
+startDSDSTestCommon(function() {
+  return testEnableData()
+    .then(testSwitchDefaultDataToSimTwo)
+    .then(testDisableDataRoamingWhileRoaming)
+    .then(testEnableDataRoamingWhileRoaming)
+    .then(testDisableData)
+    .then(restoreTestEnvironment);
+}, ["settings-read", "settings-write"]);