Bug 1052825 - Part 4: Add test in mobileconnection for unlocking puk via MMI. r=hsinyi
--- a/dom/mobileconnection/tests/marionette/head.js
+++ b/dom/mobileconnection/tests/marionette/head.js
@@ -4,16 +4,21 @@
const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
const SETTINGS_KEY_DATA_ENABLED = "ril.data.enabled";
const SETTINGS_KEY_DATA_ROAMING_ENABLED = "ril.data.roaming_enabled";
const SETTINGS_KEY_DATA_APN_SETTINGS = "ril.data.apnSettings";
const PREF_KEY_RIL_DEBUGGING_ENABLED = "ril.debugging.enabled";
+// The pin code hard coded in emulator is "0000".
+const DEFAULT_PIN = "0000";
+// The puk code hard coded in emulator is "12345678".
+const DEFAULT_PUK = "12345678";
+
// Emulate Promise.jsm semantics.
Promise.defer = function() { return new Deferred(); };
function Deferred() {
this.promise = new Promise(function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}.bind(this));
Object.freeze(this);
@@ -296,43 +301,94 @@ function getMozMobileConnectionByService
if (aServiceId !== undefined) {
mobileConn =
workingFrame.contentWindow.navigator.mozMobileConnections[aServiceId];
}
return mobileConn;
}
/**
+ * Get MozIccManager
+ *
+ * @return a MozIccManager
+ */
+function getMozIccManager() {
+ return workingFrame.contentWindow.navigator.mozIccManager;
+}
+
+/**
+ * Get MozIcc by IccId
+ *
+ * @param aIccId [optional]
+ * Default: The first item of |mozIccManager.iccIds|.
+ *
+ * @return A MozIcc.
+ */
+function getMozIccByIccId(aIccId) {
+ let iccManager = getMozIccManager();
+
+ aIccId = aIccId || iccManager.iccIds[0];
+ if (!aIccId) {
+ ok(true, "iccManager.iccIds[0] is " + aIccId);
+ return null;
+ }
+
+ return iccManager.getIccById(aIccId);
+}
+
+/**
+ * Wait for one named event.
+ *
+ * Resolve if that named event occurs. Never reject.
+ *
+ * Fulfill params: the DOMEvent passed.
+ *
+ * @param aEventTarget
+ * An EventTarget object.
+ * @param aEventName
+ * A string event name.
+ * @param aMatchFun [optional]
+ * A matching function returns true or false to filter the event.
+ *
+ * @return A deferred promise.
+ */
+function waitForTargetEvent(aEventTarget, aEventName, aMatchFun) {
+ let deferred = Promise.defer();
+
+ aEventTarget.addEventListener(aEventName, function onevent(aEvent) {
+ if (!aMatchFun || aMatchFun(aEvent)) {
+ aEventTarget.removeEventListener(aEventName, onevent);
+ ok(true, "Event '" + aEventName + "' got.");
+ deferred.resolve(aEvent);
+ }
+ });
+
+ return deferred.promise;
+}
+
+/**
* 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.
+ * @param aMatchFun [optional]
+ * A matching function returns true or false to filter the event.
*
* @return A deferred promise.
*/
-function waitForManagerEvent(aEventName, aServiceId) {
- let deferred = Promise.defer();
-
+function waitForManagerEvent(aEventName, aServiceId, aMatchFun) {
let mobileConn = getMozMobileConnectionByServiceId(aServiceId);
-
- mobileConn.addEventListener(aEventName, function onevent(aEvent) {
- mobileConn.removeEventListener(aEventName, onevent);
-
- ok(true, "MobileConnection event '" + aEventName + "' got.");
- deferred.resolve(aEvent);
- });
-
- return deferred.promise;
+ return waitForTargetEvent(mobileConn, aEventName, aMatchFun);
}
/**
* Get available networks.
*
* Fulfill params:
* An array of MozMobileNetworkInfo.
* Reject params:
@@ -673,36 +729,25 @@ function setRadioEnabled(aEnabled, aServ
* 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 setRadioEnabledAndWait(aEnabled, aServiceId) {
- let deferred = Promise.defer();
+ let promises = [];
- let promises = [];
- promises.push(waitForManagerEvent("radiostatechange", aServiceId));
- promises.push(setRadioEnabled(aEnabled, aServiceId));
- Promise.all(promises).then(function keepWaiting() {
+ promises.push(waitForManagerEvent("radiostatechange", aServiceId, function() {
let mobileConn = getMozMobileConnectionByServiceId(aServiceId);
- // To ignore some transient states, we only resolve that deferred promise
- // when |radioState| equals to the expected one and never rejects.
- let state = mobileConn.radioState;
- aEnabled = aEnabled ? "enabled" : "disabled";
- if (state == aEnabled) {
- deferred.resolve();
- return;
- }
+ return mobileConn.radioState === aEnabled ? "enabled" : "disabled";
+ }));
+ promises.push(setRadioEnabled(aEnabled, aServiceId));
- return waitForManagerEvent("radiostatechange", aServiceId).then(keepWaiting);
- });
-
- return deferred.promise;
+ return Promise.all(promises);
}
/**
* Set CLIR (calling line id restriction).
*
* Fulfill params: (none)
* Reject params:
* 'RadioNotAvailable', 'RequestNotSupported', or 'GenericFailure'
@@ -1118,26 +1163,26 @@ function cleanUp() {
* @param aTestCaseMain
* A function that takes no parameter.
*/
function startTestBase(aTestCaseMain) {
// Turn on debugging pref.
let debugPref = SpecialPowers.getBoolPref(PREF_KEY_RIL_DEBUGGING_ENABLED);
SpecialPowers.setBoolPref(PREF_KEY_RIL_DEBUGGING_ENABLED, true);
- Promise.resolve()
+ return Promise.resolve()
.then(aTestCaseMain)
+ .catch((aError) => {
+ ok(false, "promise rejects during test: " + aError);
+ })
.then(() => {
// Restore debugging pref.
SpecialPowers.setBoolPref(PREF_KEY_RIL_DEBUGGING_ENABLED, debugPref);
+ cleanUp();
})
- .then(cleanUp, function() {
- ok(false, 'promise rejects during test.');
- cleanUp();
- });
}
/**
* Common test routine helper for mobile connection tests.
*
* This function ensures global |mobileConnection| variable is available during
* the process and performs clean-ups as well.
*
--- a/dom/mobileconnection/tests/marionette/manifest.ini
+++ b/dom/mobileconnection/tests/marionette/manifest.ini
@@ -12,16 +12,17 @@ qemu = true
[test_mobile_preferred_network_type.js]
[test_mobile_preferred_network_type_radio_off.js]
[test_mobile_data_connection.js]
[test_mobile_data_location.js]
[test_mobile_data_state.js]
[test_mobile_mmi.js]
[test_mobile_mmi_change_pin.js]
[test_mobile_mmi_call_forwarding.js]
+[test_mobile_mmi_unlock_puk.js]
[test_mobile_roaming_preference.js]
[test_call_barring_get_option.js]
[test_call_barring_set_error.js]
[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]
new file mode 100644
--- /dev/null
+++ b/dom/mobileconnection/tests/marionette/test_mobile_mmi_unlock_puk.js
@@ -0,0 +1,122 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+function restartRadioAndWait(aCardState) {
+ let iccManager = getMozIccManager();
+ return setRadioEnabledAndWait(false).then(() => {
+ let promises = [];
+
+ promises.push(waitForTargetEvent(iccManager, "iccdetected")
+ .then((aEvent) => {
+ let icc = getMozIccByIccId(aEvent.iccId);
+ if (icc.cardState !== aCardState) {
+ return waitForTargetEvent(icc, "cardstatechange", function() {
+ return icc.cardState === aCardState;
+ });
+ }
+ }));
+ promises.push(setRadioEnabledAndWait(true));
+
+ return Promise.all(promises);
+ });
+}
+
+function passingWrongPinAndWait(aIcc) {
+ return aIcc.getCardLockRetryCount("pin").then((aResult) => {
+ let promises = [];
+ let retryCount = aResult.retryCount;
+
+ ok(true, "pin retryCount is " + retryCount);
+
+ promises.push(waitForTargetEvent(aIcc, "cardstatechange", function() {
+ return aIcc.cardState === "pukRequired";
+ }));
+
+ for (let i = 0; i < retryCount; i++) {
+ promises.push(aIcc.unlockCardLock({ lockType: "pin", pin: "1111" })
+ .then(() => {
+ ok(false, "unlocking pin should not success");
+ }, (aError) => {
+ ok(true, "pin retryCount = " + aError.retryCount);
+ }));
+ }
+
+ return Promise.all(promises);
+ });
+}
+
+function sendUnlockPukMmi(aPuk, aNewPin, aNewPinAgain) {
+ let MMI_CODE = "**05*" + aPuk + "*" + aNewPin + "*" + aNewPinAgain + "#";
+ log("Test " + MMI_CODE);
+
+ return sendMMI(MMI_CODE);
+}
+
+function testUnlockPukMmiError(aPuk, aNewPin, aNewPinAgain, aErrorName,
+ aRetryCount = null) {
+ return sendUnlockPukMmi(aPuk, aNewPin, aNewPinAgain)
+ .then(() => {
+ ok(false, "unlocking puk should not success");
+ }, (aError) => {
+ is(aError.name, aErrorName, "Check name");
+ is(aError.message, "", "Check message");
+ is(aError.serviceCode, "scPuk", "Check service code");
+ is(aError.additionalInformation, aRetryCount,
+ "Check additional information");
+ });
+}
+
+function testUnlockPukAndWait(aIcc, aCardState) {
+ let promises = [];
+
+ promises.push(waitForTargetEvent(aIcc, "cardstatechange", function() {
+ return aIcc.cardState === aCardState;
+ }));
+ promises.push(sendUnlockPukMmi(DEFAULT_PUK, DEFAULT_PIN, DEFAULT_PIN));
+
+ return Promise.all(promises);
+}
+
+// Start test
+startTestCommon(function() {
+ let icc = getMozIccByIccId();
+ let retryCount;
+
+ // Enable PIN-lock.
+ return icc.setCardLock({lockType: "pin", enabled: true, pin: DEFAULT_PIN})
+ // Reset card state to "pinRequired" by restarting radio.
+ .then(() => restartRadioAndWait("pinRequired"))
+ .then(() => { icc = getMozIccByIccId(); })
+ // Switch card state to "pukRequired" by entering wrong pin.
+ .then(() => passingWrongPinAndWait(icc))
+
+ // Get current PUK-lock retry count.
+ .then(() => icc.getCardLockRetryCount("puk"))
+ .then((aResult) => {
+ retryCount = aResult.retryCount;
+ ok(true, "puk retryCount is " + retryCount);
+ })
+
+ // Test passing no puk.
+ .then(() => testUnlockPukMmiError("", "1111", "2222", "emMmiError"))
+ // Test passing no newPin.
+ .then(() => testUnlockPukMmiError("11111111", "", "", "emMmiError"))
+ // Test passing mismatched newPin.
+ .then(() => testUnlockPukMmiError("11111111", "1111", "2222",
+ "emMmiErrorMismatchPin"))
+ // Test passing invalid puk (> 8 digit).
+ .then(() => testUnlockPukMmiError("123456789", DEFAULT_PIN, DEFAULT_PIN,
+ "emMmiErrorInvalidPin"))
+ // Test passing incorrect puk.
+ .then(() => testUnlockPukMmiError("11111111", DEFAULT_PIN, DEFAULT_PIN,
+ "emMmiErrorBadPuk", retryCount - 1))
+
+ // Test unlock PUK-lock success.
+ .then(() => testUnlockPukAndWait(icc, "ready"))
+
+ // Restore pin state.
+ .then(() => icc.setCardLock({lockType: "pin", enabled: false, pin: DEFAULT_PIN}));
+});