1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/mobilemessage/tests/marionette/head.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,505 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers; 1.8 + 1.9 +let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise; 1.10 + 1.11 +/** 1.12 + * Push required permissions and test if |navigator.mozMobileMessage| exists. 1.13 + * Resolve if it does, reject otherwise. 1.14 + * 1.15 + * Fulfill params: 1.16 + * manager -- an reference to navigator.mozMobileMessage. 1.17 + * 1.18 + * Reject params: (none) 1.19 + * 1.20 + * @return A deferred promise. 1.21 + */ 1.22 +let manager; 1.23 +function ensureMobileMessage() { 1.24 + let deferred = Promise.defer(); 1.25 + 1.26 + let permissions = [{ 1.27 + "type": "sms", 1.28 + "allow": 1, 1.29 + "context": document, 1.30 + }]; 1.31 + SpecialPowers.pushPermissions(permissions, function() { 1.32 + ok(true, "permissions pushed: " + JSON.stringify(permissions)); 1.33 + 1.34 + manager = window.navigator.mozMobileMessage; 1.35 + if (manager) { 1.36 + log("navigator.mozMobileMessage is instance of " + manager.constructor); 1.37 + } else { 1.38 + log("navigator.mozMobileMessage is undefined."); 1.39 + } 1.40 + 1.41 + if (manager instanceof MozMobileMessageManager) { 1.42 + deferred.resolve(manager); 1.43 + } else { 1.44 + deferred.reject(); 1.45 + } 1.46 + }); 1.47 + 1.48 + return deferred.promise; 1.49 +} 1.50 + 1.51 +/** 1.52 + * Wait for one named MobileMessageManager event. 1.53 + * 1.54 + * Resolve if that named event occurs. Never reject. 1.55 + * 1.56 + * Fulfill params: the DOMEvent passed. 1.57 + * 1.58 + * @param aEventName 1.59 + * A string event name. 1.60 + * 1.61 + * @return A deferred promise. 1.62 + */ 1.63 +function waitForManagerEvent(aEventName) { 1.64 + let deferred = Promise.defer(); 1.65 + 1.66 + manager.addEventListener(aEventName, function onevent(aEvent) { 1.67 + manager.removeEventListener(aEventName, onevent); 1.68 + 1.69 + ok(true, "MobileMessageManager event '" + aEventName + "' got."); 1.70 + deferred.resolve(aEvent); 1.71 + }); 1.72 + 1.73 + return deferred.promise; 1.74 +} 1.75 + 1.76 +/** 1.77 + * Send a SMS message to a single receiver. Resolve if it succeeds, reject 1.78 + * otherwise. 1.79 + * 1.80 + * Fulfill params: 1.81 + * message -- the sent SmsMessage. 1.82 + * 1.83 + * Reject params: 1.84 + * error -- a DOMError. 1.85 + * 1.86 + * @param aReceiver the address of the receiver. 1.87 + * @param aText the text body of the message. 1.88 + * 1.89 + * @return A deferred promise. 1.90 + */ 1.91 +function sendSmsWithSuccess(aReceiver, aText) { 1.92 + let deferred = Promise.defer(); 1.93 + 1.94 + let request = manager.send(aReceiver, aText); 1.95 + request.onsuccess = function(event) { 1.96 + deferred.resolve(event.target.result); 1.97 + }; 1.98 + request.onerror = function(event) { 1.99 + deferred.reject(event.target.error); 1.100 + }; 1.101 + 1.102 + return deferred.promise; 1.103 +} 1.104 + 1.105 +/** 1.106 + * Send a MMS message with specified parameters. Resolve if it fails, reject 1.107 + * otherwise. 1.108 + * 1.109 + * Fulfill params: 1.110 + * { 1.111 + * message, -- the failed MmsMessage 1.112 + * error, -- error of the send request 1.113 + * } 1.114 + * 1.115 + * Reject params: (none) 1.116 + * 1.117 + * @param aMmsParameters a MmsParameters instance. 1.118 + * 1.119 + * @param aSendParameters a MmsSendParameters instance. 1.120 + * 1.121 + * @return A deferred promise. 1.122 + */ 1.123 +function sendMmsWithFailure(aMmsParameters, aSendParameters) { 1.124 + let deferred = Promise.defer(); 1.125 + 1.126 + let result = { message: null, error: null }; 1.127 + function got(which, value) { 1.128 + result[which] = value; 1.129 + if (result.message != null && result.error != null) { 1.130 + deferred.resolve(result); 1.131 + } 1.132 + } 1.133 + 1.134 + manager.addEventListener("failed", function onfailed(event) { 1.135 + manager.removeEventListener("failed", onfailed); 1.136 + got("message", event.message); 1.137 + }); 1.138 + 1.139 + let request = manager.sendMMS(aMmsParameters, aSendParameters); 1.140 + request.onsuccess = function(event) { 1.141 + deferred.reject(); 1.142 + }; 1.143 + request.onerror = function(event) { 1.144 + got("error", event.target.error); 1.145 + } 1.146 + 1.147 + return deferred.promise; 1.148 +} 1.149 + 1.150 +/** 1.151 + * Retrieve messages from database. 1.152 + * 1.153 + * Fulfill params: 1.154 + * messages -- an array of {Sms,Mms}Message instances. 1.155 + * 1.156 + * Reject params: 1.157 + * event -- a DOMEvent 1.158 + * 1.159 + * @param aFilter an optional MozSmsFilter instance. 1.160 + * @param aReverse a boolean value indicating whether the order of the messages 1.161 + * should be reversed. 1.162 + * 1.163 + * @return A deferred promise. 1.164 + */ 1.165 +function getMessages(aFilter, aReverse) { 1.166 + let deferred = Promise.defer(); 1.167 + 1.168 + if (!aFilter) { 1.169 + aFilter = new MozSmsFilter; 1.170 + } 1.171 + let messages = []; 1.172 + let cursor = manager.getMessages(aFilter, aReverse || false); 1.173 + cursor.onsuccess = function(aEvent) { 1.174 + if (cursor.result) { 1.175 + messages.push(cursor.result); 1.176 + cursor.continue(); 1.177 + return; 1.178 + } 1.179 + 1.180 + deferred.resolve(messages); 1.181 + }; 1.182 + cursor.onerror = deferred.reject.bind(deferred); 1.183 + 1.184 + return deferred.promise; 1.185 +} 1.186 + 1.187 +/** 1.188 + * Retrieve all messages from database. 1.189 + * 1.190 + * Fulfill params: 1.191 + * messages -- an array of {Sms,Mms}Message instances. 1.192 + * 1.193 + * Reject params: 1.194 + * event -- a DOMEvent 1.195 + * 1.196 + * @return A deferred promise. 1.197 + */ 1.198 +function getAllMessages() { 1.199 + return getMessages(null, false); 1.200 +} 1.201 + 1.202 +/** 1.203 + * Retrieve all threads from database. 1.204 + * 1.205 + * Fulfill params: 1.206 + * threads -- an array of MozMobileMessageThread instances. 1.207 + * 1.208 + * Reject params: 1.209 + * event -- a DOMEvent 1.210 + * 1.211 + * @return A deferred promise. 1.212 + */ 1.213 +function getAllThreads() { 1.214 + let deferred = Promise.defer(); 1.215 + 1.216 + let threads = []; 1.217 + let cursor = manager.getThreads(); 1.218 + cursor.onsuccess = function(aEvent) { 1.219 + if (cursor.result) { 1.220 + threads.push(cursor.result); 1.221 + cursor.continue(); 1.222 + return; 1.223 + } 1.224 + 1.225 + deferred.resolve(threads); 1.226 + }; 1.227 + cursor.onerror = deferred.reject.bind(deferred); 1.228 + 1.229 + return deferred.promise; 1.230 +} 1.231 + 1.232 +/** 1.233 + * Retrieve a single specified thread from database. 1.234 + * 1.235 + * Fulfill params: 1.236 + * thread -- a MozMobileMessageThread instance. 1.237 + * 1.238 + * Reject params: 1.239 + * event -- a DOMEvent if an error occurs in the retrieving process, or 1.240 + * undefined if there's no such thread. 1.241 + * 1.242 + * @aThreadId a numeric value identifying the target thread. 1.243 + * 1.244 + * @return A deferred promise. 1.245 + */ 1.246 +function getThreadById(aThreadId) { 1.247 + return getAllThreads() 1.248 + .then(function(aThreads) { 1.249 + for (let thread of aThreads) { 1.250 + if (thread.id === aThreadId) { 1.251 + return thread; 1.252 + } 1.253 + } 1.254 + throw undefined; 1.255 + }); 1.256 +} 1.257 + 1.258 +/** 1.259 + * Delete messages specified from database. 1.260 + * 1.261 + * Fulfill params: 1.262 + * result -- an array of boolean values indicating whether delesion was 1.263 + * actually performed on the message record with corresponding id. 1.264 + * 1.265 + * Reject params: 1.266 + * event -- a DOMEvent. 1.267 + * 1.268 + * @aMessageId an array of numeric values identifying the target messages. 1.269 + * 1.270 + * @return An empty array if nothing to be deleted; otherwise, a deferred promise. 1.271 + */ 1.272 +function deleteMessagesById(aMessageIds) { 1.273 + if (!aMessageIds.length) { 1.274 + ok(true, "no message to be deleted"); 1.275 + return []; 1.276 + } 1.277 + 1.278 + let deferred = Promise.defer(); 1.279 + 1.280 + let request = manager.delete(aMessageIds); 1.281 + request.onsuccess = function(event) { 1.282 + deferred.resolve(event.target.result); 1.283 + }; 1.284 + request.onerror = deferred.reject.bind(deferred); 1.285 + 1.286 + return deferred.promise; 1.287 +} 1.288 + 1.289 +/** 1.290 + * Delete messages specified from database. 1.291 + * 1.292 + * Fulfill params: 1.293 + * result -- an array of boolean values indicating whether delesion was 1.294 + * actually performed on the message record with corresponding id. 1.295 + * 1.296 + * Reject params: 1.297 + * event -- a DOMEvent. 1.298 + * 1.299 + * @aMessages an array of {Sms,Mms}Message instances. 1.300 + * 1.301 + * @return A deferred promise. 1.302 + */ 1.303 +function deleteMessages(aMessages) { 1.304 + let ids = messagesToIds(aMessages); 1.305 + return deleteMessagesById(ids); 1.306 +} 1.307 + 1.308 +/** 1.309 + * Delete all messages from database. 1.310 + * 1.311 + * Fulfill params: 1.312 + * ids -- an array of numeric values identifying those deleted 1.313 + * {Sms,Mms}Messages. 1.314 + * 1.315 + * Reject params: 1.316 + * event -- a DOMEvent. 1.317 + * 1.318 + * @return A deferred promise. 1.319 + */ 1.320 +function deleteAllMessages() { 1.321 + return getAllMessages().then(deleteMessages); 1.322 +} 1.323 + 1.324 +let pendingEmulatorCmdCount = 0; 1.325 + 1.326 +/** 1.327 + * Send emulator command with safe guard. 1.328 + * 1.329 + * We should only call |finish()| after all emulator command transactions 1.330 + * end, so here comes with the pending counter. Resolve when the emulator 1.331 + * gives positive response, and reject otherwise. 1.332 + * 1.333 + * Fulfill params: 1.334 + * result -- an array of emulator response lines. 1.335 + * 1.336 + * Reject params: 1.337 + * result -- an array of emulator response lines. 1.338 + * 1.339 + * @return A deferred promise. 1.340 + */ 1.341 +function runEmulatorCmdSafe(aCommand) { 1.342 + let deferred = Promise.defer(); 1.343 + 1.344 + ++pendingEmulatorCmdCount; 1.345 + runEmulatorCmd(aCommand, function(aResult) { 1.346 + --pendingEmulatorCmdCount; 1.347 + 1.348 + ok(true, "Emulator response: " + JSON.stringify(aResult)); 1.349 + if (Array.isArray(aResult) && aResult[0] === "OK") { 1.350 + deferred.resolve(aResult); 1.351 + } else { 1.352 + deferred.reject(aResult); 1.353 + } 1.354 + }); 1.355 + 1.356 + return deferred.promise; 1.357 +} 1.358 + 1.359 +/** 1.360 + * Send simple text SMS to emulator. 1.361 + * 1.362 + * Fulfill params: 1.363 + * result -- an array of emulator response lines. 1.364 + * 1.365 + * Reject params: 1.366 + * result -- an array of emulator response lines. 1.367 + * 1.368 + * @return A deferred promise. 1.369 + */ 1.370 +function sendTextSmsToEmulator(aFrom, aText) { 1.371 + let command = "sms send " + aFrom + " " + aText; 1.372 + return runEmulatorCmdSafe(command); 1.373 +} 1.374 + 1.375 +/** 1.376 + * Send raw SMS TPDU to emulator. 1.377 + * 1.378 + * @param: aPdu 1.379 + * A hex string representing the whole SMS T-PDU. 1.380 + * 1.381 + * Fulfill params: 1.382 + * result -- an array of emulator response lines. 1.383 + * 1.384 + * Reject params: 1.385 + * result -- an array of emulator response lines. 1.386 + * 1.387 + * @return A deferred promise. 1.388 + */ 1.389 +function sendRawSmsToEmulator(aPdu) { 1.390 + let command = "sms pdu " + aPdu; 1.391 + return runEmulatorCmdSafe(command); 1.392 +} 1.393 + 1.394 +/** 1.395 + * Send multiple raw SMS TPDU to emulator and wait 1.396 + * 1.397 + * @param: aPdus 1.398 + * A array of hex strings. Each represents a SMS T-PDU. 1.399 + * 1.400 + * Fulfill params: 1.401 + * result -- array of resolved Promise, where 1.402 + * result[0].message representing the received message. 1.403 + * result[1-n] represents the response of sent emulator command. 1.404 + * 1.405 + * Reject params: 1.406 + * result -- an array of emulator response lines. 1.407 + * 1.408 + * @return A deferred promise. 1.409 + */ 1.410 +function sendMultipleRawSmsToEmulatorAndWait(aPdus) { 1.411 + let promises = []; 1.412 + 1.413 + promises.push(waitForManagerEvent("received")); 1.414 + for (let pdu of aPdus) { 1.415 + promises.push(sendRawSmsToEmulator(pdu)); 1.416 + } 1.417 + 1.418 + return Promise.all(promises); 1.419 +} 1.420 + 1.421 +/** 1.422 + * Create a new array of id attribute of input messages. 1.423 + * 1.424 + * @param aMessages an array of {Sms,Mms}Message instances. 1.425 + * 1.426 + * @return an array of numeric values. 1.427 + */ 1.428 +function messagesToIds(aMessages) { 1.429 + let ids = []; 1.430 + for (let message of aMessages) { 1.431 + ids.push(message.id); 1.432 + } 1.433 + return ids; 1.434 +} 1.435 + 1.436 +/** 1.437 + * Flush permission settings and call |finish()|. 1.438 + */ 1.439 +function cleanUp() { 1.440 + waitFor(function() { 1.441 + SpecialPowers.flushPermissions(function() { 1.442 + // Use ok here so that we have at least one test run. 1.443 + ok(true, "permissions flushed"); 1.444 + 1.445 + finish(); 1.446 + }); 1.447 + }, function() { 1.448 + return pendingEmulatorCmdCount === 0; 1.449 + }); 1.450 +} 1.451 + 1.452 +/** 1.453 + * Basic test routine helper for mobile message tests. 1.454 + * 1.455 + * This helper does nothing but clean-ups. 1.456 + * 1.457 + * @param aTestCaseMain 1.458 + * A function that takes no parameter. 1.459 + */ 1.460 +function startTestBase(aTestCaseMain) { 1.461 + Promise.resolve() 1.462 + .then(aTestCaseMain) 1.463 + .then(cleanUp, function() { 1.464 + ok(false, 'promise rejects during test.'); 1.465 + cleanUp(); 1.466 + }); 1.467 +} 1.468 + 1.469 +/** 1.470 + * Common test routine helper for mobile message tests. 1.471 + * 1.472 + * This function ensures global |manager| variable is available during the 1.473 + * process and performs clean-ups as well. 1.474 + * 1.475 + * @param aTestCaseMain 1.476 + * A function that takes no parameter. 1.477 + */ 1.478 +function startTestCommon(aTestCaseMain) { 1.479 + startTestBase(function() { 1.480 + return ensureMobileMessage() 1.481 + .then(deleteAllMessages) 1.482 + .then(aTestCaseMain) 1.483 + .then(deleteAllMessages); 1.484 + }); 1.485 +} 1.486 + 1.487 +/** 1.488 + * Helper to run the test case only needed in Multi-SIM environment. 1.489 + * 1.490 + * @param aTest 1.491 + * A function which will be invoked w/o parameter. 1.492 + * @return a Promise object. 1.493 + */ 1.494 +function runIfMultiSIM(aTest) { 1.495 + let numRIL; 1.496 + try { 1.497 + numRIL = SpecialPowers.getIntPref("ril.numRadioInterfaces"); 1.498 + } catch (ex) { 1.499 + numRIL = 1; // Pref not set. 1.500 + } 1.501 + 1.502 + if (numRIL > 1) { 1.503 + return aTest(); 1.504 + } else { 1.505 + log("Not a Multi-SIM environment. Test is skipped."); 1.506 + return Promise.resolve(); 1.507 + } 1.508 +}