Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ |
michael@0 | 3 | |
michael@0 | 4 | MARIONETTE_TIMEOUT = 10000; |
michael@0 | 5 | |
michael@0 | 6 | const CB_MESSAGE_SIZE_ETWS = 56; |
michael@0 | 7 | |
michael@0 | 8 | const CB_GSM_GEOGRAPHICAL_SCOPE_NAMES = [ |
michael@0 | 9 | "cell-immediate", |
michael@0 | 10 | "plmn", |
michael@0 | 11 | "location-area", |
michael@0 | 12 | "cell" |
michael@0 | 13 | ]; |
michael@0 | 14 | |
michael@0 | 15 | const CB_ETWS_WARNING_TYPE_NAMES = [ |
michael@0 | 16 | "earthquake", |
michael@0 | 17 | "tsunami", |
michael@0 | 18 | "earthquake-tsunami", |
michael@0 | 19 | "test", |
michael@0 | 20 | "other" |
michael@0 | 21 | ]; |
michael@0 | 22 | |
michael@0 | 23 | SpecialPowers.addPermission("cellbroadcast", true, document); |
michael@0 | 24 | SpecialPowers.addPermission("mobileconnection", true, document); |
michael@0 | 25 | |
michael@0 | 26 | let cbs = window.navigator.mozCellBroadcast; |
michael@0 | 27 | ok(cbs instanceof window.MozCellBroadcast, |
michael@0 | 28 | "mozCellBroadcast is instanceof " + cbs.constructor); |
michael@0 | 29 | |
michael@0 | 30 | let pendingEmulatorCmdCount = 0; |
michael@0 | 31 | function sendCellBroadcastMessage(pdu, callback) { |
michael@0 | 32 | pendingEmulatorCmdCount++; |
michael@0 | 33 | |
michael@0 | 34 | let cmd = "cbs pdu " + pdu; |
michael@0 | 35 | runEmulatorCmd(cmd, function(result) { |
michael@0 | 36 | pendingEmulatorCmdCount--; |
michael@0 | 37 | |
michael@0 | 38 | is(result[0], "OK", "Emulator response"); |
michael@0 | 39 | |
michael@0 | 40 | if (callback) { |
michael@0 | 41 | window.setTimeout(callback, 0); |
michael@0 | 42 | } |
michael@0 | 43 | }); |
michael@0 | 44 | } |
michael@0 | 45 | |
michael@0 | 46 | function buildHexStr(n, numSemiOctets) { |
michael@0 | 47 | let str = n.toString(16); |
michael@0 | 48 | ok(str.length <= numSemiOctets); |
michael@0 | 49 | while (str.length < numSemiOctets) { |
michael@0 | 50 | str = "0" + str; |
michael@0 | 51 | } |
michael@0 | 52 | return str; |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | function seq(end, begin) { |
michael@0 | 56 | let result = []; |
michael@0 | 57 | for (let i = begin || 0; i < end; i++) { |
michael@0 | 58 | result.push(i); |
michael@0 | 59 | } |
michael@0 | 60 | return result; |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | function repeat(func, array, oncomplete) { |
michael@0 | 64 | (function do_call(index) { |
michael@0 | 65 | let next = index < (array.length - 1) ? do_call.bind(null, index + 1) : oncomplete; |
michael@0 | 66 | func.apply(null, [array[index], next]); |
michael@0 | 67 | })(0); |
michael@0 | 68 | } |
michael@0 | 69 | |
michael@0 | 70 | function doTestHelper(pdu, nextTest, checkFunc) { |
michael@0 | 71 | cbs.addEventListener("received", function onreceived(event) { |
michael@0 | 72 | cbs.removeEventListener("received", onreceived); |
michael@0 | 73 | |
michael@0 | 74 | checkFunc(event.message); |
michael@0 | 75 | |
michael@0 | 76 | window.setTimeout(nextTest, 0); |
michael@0 | 77 | }); |
michael@0 | 78 | |
michael@0 | 79 | if (Array.isArray(pdu)) { |
michael@0 | 80 | repeat(sendCellBroadcastMessage, pdu); |
michael@0 | 81 | } else { |
michael@0 | 82 | sendCellBroadcastMessage(pdu); |
michael@0 | 83 | } |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | /** |
michael@0 | 87 | * Tests receiving Cell Broadcast messages, event instance type, all attributes |
michael@0 | 88 | * of CellBroadcastMessage exist. |
michael@0 | 89 | */ |
michael@0 | 90 | function testEtwsMessageAttributes() { |
michael@0 | 91 | log("Test ETWS Primary Notification message attributes"); |
michael@0 | 92 | |
michael@0 | 93 | cbs.addEventListener("received", function onreceived(event) { |
michael@0 | 94 | cbs.removeEventListener("received", onreceived); |
michael@0 | 95 | |
michael@0 | 96 | // Bug 838542: following check throws an exception and fails this case. |
michael@0 | 97 | // ok(event instanceof MozCellBroadcastEvent, |
michael@0 | 98 | // "event is instanceof " + event.constructor) |
michael@0 | 99 | ok(event, "event is valid"); |
michael@0 | 100 | |
michael@0 | 101 | let message = event.message; |
michael@0 | 102 | ok(message, "event.message is valid"); |
michael@0 | 103 | |
michael@0 | 104 | // Attributes other than `language` and `body` should always be assigned. |
michael@0 | 105 | ok(message.gsmGeographicalScope != null, "message.gsmGeographicalScope"); |
michael@0 | 106 | ok(message.messageCode != null, "message.messageCode"); |
michael@0 | 107 | ok(message.messageId != null, "message.messageId"); |
michael@0 | 108 | ok('language' in message, "message.language"); |
michael@0 | 109 | ok(message.language == null, "message.language"); |
michael@0 | 110 | ok('body' in message, "message.body"); |
michael@0 | 111 | ok(message.body == null, "message.body"); |
michael@0 | 112 | is(message.messageClass, "normal", "message.messageClass"); |
michael@0 | 113 | ok(message.timestamp != null, "message.timestamp"); |
michael@0 | 114 | ok(message.etws != null, "message.etws"); |
michael@0 | 115 | ok(message.etws.warningType != null, "message.etws.warningType"); |
michael@0 | 116 | ok(message.etws.emergencyUserAlert != null, |
michael@0 | 117 | "message.etws.emergencyUserAlert"); |
michael@0 | 118 | ok(message.etws.popup != null, "message.etws.popup"); |
michael@0 | 119 | ok(message.cdmaServiceCategory != null, "message.cdmaServiceCategory"); |
michael@0 | 120 | |
michael@0 | 121 | window.setTimeout(testReceiving_ETWS_GeographicalScope, 0); |
michael@0 | 122 | }); |
michael@0 | 123 | |
michael@0 | 124 | // Here we use a simple ETWS message for test. |
michael@0 | 125 | let pdu = buildHexStr(0, CB_MESSAGE_SIZE_ETWS * 2); // 6 octets |
michael@0 | 126 | sendCellBroadcastMessage(pdu); |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | function testReceiving_ETWS_GeographicalScope() { |
michael@0 | 130 | log("Test receiving ETWS Primary Notification - Geographical Scope"); |
michael@0 | 131 | |
michael@0 | 132 | function do_test(gs, nextTest) { |
michael@0 | 133 | // Here we use a simple ETWS message for test. |
michael@0 | 134 | let pdu = buildHexStr(((gs & 0x03) << 14), 4) |
michael@0 | 135 | + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 2) * 2); |
michael@0 | 136 | |
michael@0 | 137 | doTestHelper(pdu, nextTest, function(message) { |
michael@0 | 138 | is(message.gsmGeographicalScope, CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[gs], |
michael@0 | 139 | "message.gsmGeographicalScope"); |
michael@0 | 140 | }); |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | repeat(do_test, seq(CB_GSM_GEOGRAPHICAL_SCOPE_NAMES.length), |
michael@0 | 144 | testReceiving_ETWS_MessageCode); |
michael@0 | 145 | } |
michael@0 | 146 | |
michael@0 | 147 | function testReceiving_ETWS_MessageCode() { |
michael@0 | 148 | log("Test receiving ETWS Primary Notification - Message Code"); |
michael@0 | 149 | |
michael@0 | 150 | // Message Code has 10 bits, and is ORed into a 16 bits 'serial' number. Here |
michael@0 | 151 | // we test every single bit to verify the operation doesn't go wrong. |
michael@0 | 152 | let messageCodesToTest = [ |
michael@0 | 153 | 0x000, 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x040, |
michael@0 | 154 | 0x080, 0x100, 0x200, 0x251 |
michael@0 | 155 | ]; |
michael@0 | 156 | |
michael@0 | 157 | function do_test(messageCode, nextTest) { |
michael@0 | 158 | let pdu = buildHexStr(((messageCode & 0x3FF) << 4), 4) |
michael@0 | 159 | + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 2) * 2); |
michael@0 | 160 | |
michael@0 | 161 | doTestHelper(pdu, nextTest, function(message) { |
michael@0 | 162 | is(message.messageCode, messageCode, "message.messageCode"); |
michael@0 | 163 | }); |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | repeat(do_test, messageCodesToTest, testReceiving_ETWS_MessageId); |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | function testReceiving_ETWS_MessageId() { |
michael@0 | 170 | log("Test receiving ETWS Primary Notification - Message Identifier"); |
michael@0 | 171 | |
michael@0 | 172 | // Message Identifier has 16 bits, but no bitwise operation is needed. |
michael@0 | 173 | // Test some selected values only. |
michael@0 | 174 | let messageIdsToTest = [ |
michael@0 | 175 | 0x0000, 0x0001, 0x0010, 0x0100, 0x1000, 0x1111, 0x8888, 0x8811 |
michael@0 | 176 | ]; |
michael@0 | 177 | |
michael@0 | 178 | function do_test(messageId, nextTest) { |
michael@0 | 179 | let pdu = buildHexStr(0, 4) |
michael@0 | 180 | + buildHexStr((messageId & 0xFFFF), 4) |
michael@0 | 181 | + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 4) * 2); |
michael@0 | 182 | |
michael@0 | 183 | doTestHelper(pdu, nextTest, function(message) { |
michael@0 | 184 | is(message.messageId, messageId, "message.messageId"); |
michael@0 | 185 | }); |
michael@0 | 186 | } |
michael@0 | 187 | |
michael@0 | 188 | repeat(do_test, messageIdsToTest, testReceiving_ETWS_Timestamp); |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | function testReceiving_ETWS_Timestamp() { |
michael@0 | 192 | log("Test receiving ETWS Primary Notification - Timestamp"); |
michael@0 | 193 | |
michael@0 | 194 | // Here we use a simple ETWS message for test. |
michael@0 | 195 | let pdu = buildHexStr(0, 12); // 6 octets |
michael@0 | 196 | doTestHelper(pdu, testReceiving_ETWS_WarningType, function(message) { |
michael@0 | 197 | // Cell Broadcast messages do not contain a timestamp field (however, ETWS |
michael@0 | 198 | // does). We only check the timestamp doesn't go too far (60 seconds) here. |
michael@0 | 199 | let msMessage = message.timestamp.getTime(); |
michael@0 | 200 | let msNow = Date.now(); |
michael@0 | 201 | ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp"); |
michael@0 | 202 | }); |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | function testReceiving_ETWS_WarningType() { |
michael@0 | 206 | log("Test receiving ETWS Primary Notification - Warning Type"); |
michael@0 | 207 | |
michael@0 | 208 | // Warning Type has 7 bits, and is ORed into a 16 bits 'WarningType' field. |
michael@0 | 209 | // Here we test every single bit to verify the operation doesn't go wrong. |
michael@0 | 210 | let warningTypesToTest = [ |
michael@0 | 211 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x41 |
michael@0 | 212 | ]; |
michael@0 | 213 | |
michael@0 | 214 | function do_test(warningType, nextTest) { |
michael@0 | 215 | let pdu = buildHexStr(0, 8) |
michael@0 | 216 | + buildHexStr(((warningType & 0x7F) << 9), 4) |
michael@0 | 217 | + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 6) * 2); |
michael@0 | 218 | |
michael@0 | 219 | doTestHelper(pdu, nextTest, function(message) { |
michael@0 | 220 | ok(message.etws, "message.etws"); |
michael@0 | 221 | is(message.etws.warningType, CB_ETWS_WARNING_TYPE_NAMES[warningType], |
michael@0 | 222 | "message.etws.warningType"); |
michael@0 | 223 | }); |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | repeat(do_test, warningTypesToTest, testReceiving_ETWS_EmergencyUserAlert); |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | function doTestEmergencyUserAlert_or_Popup(name, mask, nextTest) { |
michael@0 | 230 | let pdu = buildHexStr(0, 8) |
michael@0 | 231 | + buildHexStr(mask, 4) |
michael@0 | 232 | + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 6) * 2); |
michael@0 | 233 | doTestHelper(pdu, nextTest, function(message) { |
michael@0 | 234 | ok(message.etws != null, "message.etws"); |
michael@0 | 235 | is(message.etws[name], mask != 0, "message.etws." + name); |
michael@0 | 236 | }); |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | function testReceiving_ETWS_EmergencyUserAlert() { |
michael@0 | 240 | log("Test receiving ETWS Primary Notification - Emergency User Alert"); |
michael@0 | 241 | |
michael@0 | 242 | repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "emergencyUserAlert"), |
michael@0 | 243 | [0x100, 0x000], testReceiving_ETWS_Popup); |
michael@0 | 244 | } |
michael@0 | 245 | |
michael@0 | 246 | function testReceiving_ETWS_Popup() { |
michael@0 | 247 | log("Test receiving ETWS Primary Notification - Popup"); |
michael@0 | 248 | |
michael@0 | 249 | repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "popup"), |
michael@0 | 250 | [0x80, 0x000], cleanUp); |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | function cleanUp() { |
michael@0 | 254 | if (pendingEmulatorCmdCount > 0) { |
michael@0 | 255 | window.setTimeout(cleanUp, 100); |
michael@0 | 256 | return; |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | SpecialPowers.removePermission("mobileconnection", document); |
michael@0 | 260 | SpecialPowers.removePermission("cellbroadcast", true, document); |
michael@0 | 261 | |
michael@0 | 262 | finish(); |
michael@0 | 263 | } |
michael@0 | 264 | |
michael@0 | 265 | waitFor(testEtwsMessageAttributes, function() { |
michael@0 | 266 | return navigator.mozMobileConnections[0].voice.connected; |
michael@0 | 267 | }); |
michael@0 | 268 |