dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* Any copyright is dedicated to the Public Domain.
     2  * http://creativecommons.org/publicdomain/zero/1.0/ */
     4 MARIONETTE_TIMEOUT = 30000;
     6 const PDU_DCS_CODING_GROUP_BITS          = 0xF0;
     7 const PDU_DCS_MSG_CODING_7BITS_ALPHABET  = 0x00;
     8 const PDU_DCS_MSG_CODING_8BITS_ALPHABET  = 0x04;
     9 const PDU_DCS_MSG_CODING_16BITS_ALPHABET = 0x08;
    11 const PDU_DCS_MSG_CLASS_BITS             = 0x03;
    12 const PDU_DCS_MSG_CLASS_NORMAL           = 0xFF;
    13 const PDU_DCS_MSG_CLASS_0                = 0x00;
    14 const PDU_DCS_MSG_CLASS_ME_SPECIFIC      = 0x01;
    15 const PDU_DCS_MSG_CLASS_SIM_SPECIFIC     = 0x02;
    16 const PDU_DCS_MSG_CLASS_TE_SPECIFIC      = 0x03;
    17 const PDU_DCS_MSG_CLASS_USER_1           = 0x04;
    18 const PDU_DCS_MSG_CLASS_USER_2           = 0x05;
    20 const GECKO_SMS_MESSAGE_CLASSES = {};
    21 GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]       = "normal";
    22 GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]            = "class-0";
    23 GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_ME_SPECIFIC]  = "class-1";
    24 GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_SIM_SPECIFIC] = "class-2";
    25 GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_TE_SPECIFIC]  = "class-3";
    26 GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_1]       = "user-1";
    27 GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_2]       = "user-2";
    29 const CB_MESSAGE_SIZE_GSM  = 88;
    31 const CB_GSM_MESSAGEID_ETWS_BEGIN = 0x1100;
    32 const CB_GSM_MESSAGEID_ETWS_END   = 0x1107;
    34 const CB_GSM_GEOGRAPHICAL_SCOPE_NAMES = [
    35   "cell-immediate",
    36   "plmn",
    37   "location-area",
    38   "cell"
    39 ];
    41 const CB_ETWS_WARNING_TYPE_NAMES = [
    42   "earthquake",
    43   "tsunami",
    44   "earthquake-tsunami",
    45   "test",
    46   "other"
    47 ];
    49 const CB_DCS_LANG_GROUP_1 = [
    50   "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi",
    51   "no", "el", "tr", "hu", "pl", null
    52 ];
    53 const CB_DCS_LANG_GROUP_2 = [
    54   "cs", "he", "ar", "ru", "is", null, null, null, null, null,
    55   null, null, null, null, null, null
    56 ];
    58 const CB_MAX_CONTENT_7BIT = Math.floor((CB_MESSAGE_SIZE_GSM - 6) * 8 / 7);
    59 const CB_MAX_CONTENT_UCS2 = Math.floor((CB_MESSAGE_SIZE_GSM - 6) / 2);
    61 const BODY_7BITS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
    62                  + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
    63                  + "@@@@@@@@@@@@@"; // 93 ascii chars.
    64 const BODY_7BITS_IND = BODY_7BITS.substr(3);
    65 const BODY_UCS2 = "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
    66                 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
    67                 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
    68                 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
    69                 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
    70                 + "\u0000"; // 41 unicode chars.
    71 const BODY_UCS2_IND = BODY_UCS2.substr(1);
    73 SpecialPowers.addPermission("cellbroadcast", true, document);
    74 SpecialPowers.addPermission("mobileconnection", true, document);
    76 is(BODY_7BITS.length,     CB_MAX_CONTENT_7BIT,     "BODY_7BITS.length");
    77 is(BODY_7BITS_IND.length, CB_MAX_CONTENT_7BIT - 3, "BODY_7BITS_IND.length");
    78 is(BODY_UCS2.length,      CB_MAX_CONTENT_UCS2,     "BODY_UCS2.length");
    79 is(BODY_UCS2_IND.length,  CB_MAX_CONTENT_UCS2 - 1, "BODY_UCS2_IND.length")
    81 let cbs = window.navigator.mozCellBroadcast;
    82 ok(cbs instanceof window.MozCellBroadcast,
    83    "mozCellBroadcast is instanceof " + cbs.constructor);
    85 let pendingEmulatorCmdCount = 0;
    86 function sendCellBroadcastMessage(pdu, callback) {
    87   pendingEmulatorCmdCount++;
    89   let cmd = "cbs pdu " + pdu;
    90   runEmulatorCmd(cmd, function(result) {
    91     pendingEmulatorCmdCount--;
    93     is(result[0], "OK", "Emulator response");
    95     if (callback) {
    96       window.setTimeout(callback, 0);
    97     }
    98   });
    99 }
   101 function buildHexStr(n, numSemiOctets) {
   102   let str = n.toString(16);
   103   ok(str.length <= numSemiOctets);
   104   while (str.length < numSemiOctets) {
   105     str = "0" + str;
   106   }
   107   return str;
   108 }
   110 function seq(end, begin) {
   111   let result = [];
   112   for (let i = begin || 0; i < end; i++) {
   113     result.push(i);
   114   }
   115   return result;
   116 }
   118 function repeat(func, array, oncomplete) {
   119   (function do_call(index) {
   120     let next = index < (array.length - 1) ? do_call.bind(null, index + 1) : oncomplete;
   121     func.apply(null, [array[index], next]);
   122   })(0);
   123 }
   125 function doTestHelper(pdu, nextTest, checkFunc) {
   126   cbs.addEventListener("received", function onreceived(event) {
   127     cbs.removeEventListener("received", onreceived);
   129     checkFunc(event.message);
   131     window.setTimeout(nextTest, 0);
   132   });
   134   if (Array.isArray(pdu)) {
   135     repeat(sendCellBroadcastMessage, pdu);
   136   } else {
   137     sendCellBroadcastMessage(pdu);
   138   }
   139 }
   141 /**
   142  * Tests receiving Cell Broadcast messages, event instance type, all attributes
   143  * of CellBroadcastMessage exist.
   144  */
   145 function testGsmMessageAttributes() {
   146   log("Test GSM Cell Broadcast message attributes");
   148   cbs.addEventListener("received", function onreceived(event) {
   149     cbs.removeEventListener("received", onreceived);
   151     // Bug 838542: following check throws an exception and fails this case.
   152     // ok(event instanceof MozCellBroadcastEvent,
   153     //    "event is instanceof " + event.constructor)
   154     ok(event, "event is valid");
   156     let message = event.message;
   157     ok(message, "event.message is valid");
   159     // Attributes other than `language` and `body` should always be assigned.
   160     ok(message.gsmGeographicalScope != null, "message.gsmGeographicalScope");
   161     ok(message.messageCode != null, "message.messageCode");
   162     ok(message.messageId != null, "message.messageId");
   163     ok(message.language != null, "message.language");
   164     ok(message.body != null, "message.body");
   165     ok(message.messageClass != null, "message.messageClass");
   166     ok(message.timestamp != null, "message.timestamp");
   167     ok('etws' in message, "message.etws");
   168     if (message.etws) {
   169       ok('warningType' in message.etws, "message.etws.warningType");
   170       ok(message.etws.emergencyUserAlert != null, "message.etws.emergencyUserAlert");
   171       ok(message.etws.popup != null, "message.etws.popup");
   172     }
   173     ok(message.cdmaServiceCategory != null, "message.cdmaServiceCategory");
   175     window.setTimeout(testReceiving_GSM_GeographicalScope, 0);
   176   });
   178   // Here we use a simple GSM message for test.
   179   let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
   180   sendCellBroadcastMessage(pdu);
   181 }
   183 function testReceiving_GSM_GeographicalScope() {
   184   log("Test receiving GSM Cell Broadcast - Geographical Scope");
   186   function do_test(gs, nextTest) {
   187     let pdu = buildHexStr(((gs & 0x03) << 14), 4)
   188             + buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 2) * 2);
   190     doTestHelper(pdu, nextTest, function(message) {
   191       is(message.gsmGeographicalScope, CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[gs],
   192          "message.gsmGeographicalScope");
   193     });
   194   }
   196   repeat(do_test, seq(CB_GSM_GEOGRAPHICAL_SCOPE_NAMES.length),
   197          testReceiving_GSM_MessageCode);
   198 }
   200 function testReceiving_GSM_MessageCode() {
   201   log("Test receiving GSM Cell Broadcast - Message Code");
   203   // Message Code has 10 bits, and is ORed into a 16 bits 'serial' number. Here
   204   // we test every single bit to verify the operation doesn't go wrong.
   205   let messageCodesToTest = [
   206     0x000, 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x040,
   207     0x080, 0x100, 0x200, 0x251
   208   ];
   210   function do_test(messageCode, nextTest) {
   211     let pdu = buildHexStr(((messageCode & 0x3FF) << 4), 4)
   212             + buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 2) * 2);
   214     doTestHelper(pdu, nextTest, function(message) {
   215       is(message.messageCode, messageCode, "message.messageCode");
   216     });
   217   }
   219   repeat(do_test, messageCodesToTest, testReceiving_GSM_MessageId);
   220 }
   222 function testReceiving_GSM_MessageId() {
   223   log("Test receiving GSM Cell Broadcast - Message Identifier");
   225   // Message Identifier has 16 bits, but no bitwise operation is needed.
   226   // Test some selected values only.
   227   let messageIdsToTest = [
   228     0x0000, 0x0001, 0x0010, 0x0100, 0x1000, 0x1111, 0x8888, 0x8811,
   229   ];
   231   function do_test(messageId, nextTest) {
   232     let pdu = buildHexStr(0, 4)
   233             + buildHexStr((messageId & 0xFFFF), 4)
   234             + buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 4) * 2);
   236     doTestHelper(pdu, nextTest, function(message) {
   237       is(message.messageId, messageId, "message.messageId");
   238       ok(message.etws == null, "message.etws");
   239     });
   240   }
   242   repeat(do_test, messageIdsToTest, testReceiving_GSM_Language_and_Body);
   243 }
   245 // Copied from GsmPDUHelper.readCbDataCodingScheme
   246 function decodeDataCodingScheme(dcs) {
   247   let language = null;
   248   let hasLanguageIndicator = false;
   249   let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
   250   let messageClass = PDU_DCS_MSG_CLASS_NORMAL;
   252   switch (dcs & PDU_DCS_CODING_GROUP_BITS) {
   253     case 0x00: // 0000
   254       language = CB_DCS_LANG_GROUP_1[dcs & 0x0F];
   255       break;
   257     case 0x10: // 0001
   258       switch (dcs & 0x0F) {
   259         case 0x00:
   260           hasLanguageIndicator = true;
   261           break;
   262         case 0x01:
   263           encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
   264           hasLanguageIndicator = true;
   265           break;
   266       }
   267       break;
   269     case 0x20: // 0010
   270       language = CB_DCS_LANG_GROUP_2[dcs & 0x0F];
   271       break;
   273     case 0x40: // 01xx
   274     case 0x50:
   275     //case 0x60:
   276     //case 0x70:
   277     case 0x90: // 1001
   278       encoding = (dcs & 0x0C);
   279       if (encoding == 0x0C) {
   280         encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
   281       }
   282       messageClass = (dcs & PDU_DCS_MSG_CLASS_BITS);
   283       break;
   285     case 0xF0:
   286       encoding = (dcs & 0x04) ? PDU_DCS_MSG_CODING_8BITS_ALPHABET
   287                               : PDU_DCS_MSG_CODING_7BITS_ALPHABET;
   288       switch(dcs & PDU_DCS_MSG_CLASS_BITS) {
   289         case 0x01: messageClass = PDU_DCS_MSG_CLASS_USER_1; break;
   290         case 0x02: messageClass = PDU_DCS_MSG_CLASS_USER_2; break;
   291         case 0x03: messageClass = PDU_DCS_MSG_CLASS_TE_SPECIFIC; break;
   292       }
   293       break;
   295     case 0x30: // 0011 (Reserved)
   296     case 0x80: // 1000 (Reserved)
   297     case 0xA0: // 1010..1100 (Reserved)
   298     case 0xB0:
   299     case 0xC0:
   300       break;
   301     default:
   302       throw new Error("Unsupported CBS data coding scheme: " + dcs);
   303   }
   305   return [encoding, language, hasLanguageIndicator,
   306           GECKO_SMS_MESSAGE_CLASSES[messageClass]];
   307 }
   309 function testReceiving_GSM_Language_and_Body() {
   310   log("Test receiving GSM Cell Broadcast - Language & Body");
   312   function do_test(dcs) {
   313     let encoding, language, indicator, messageClass;
   314     try {
   315       [encoding, language, indicator, messageClass] = decodeDataCodingScheme(dcs);
   316     } catch (e) {
   317       // Unsupported coding group, skip.
   318       let nextGroup = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10;
   319       window.setTimeout(do_test.bind(null, nextGroup), 0);
   320       return;
   321     }
   323     let pdu = buildHexStr(0, 8)
   324             + buildHexStr(dcs, 2)
   325             + buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 5) * 2);
   327     let nextTest = (dcs < 0xFF) ? do_test.bind(null, dcs + 1)
   328                                  : testReceiving_GSM_Timestamp;
   329     doTestHelper(pdu, nextTest, function(message) {
   330       if (language) {
   331         is(message.language, language, "message.language");
   332       } else if (indicator) {
   333         is(message.language, "@@", "message.language");
   334       } else {
   335         ok(message.language == null, "message.language");
   336       }
   338       switch (encoding) {
   339         case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
   340           is(message.body, indicator ? BODY_7BITS_IND : BODY_7BITS, "message.body");
   341           break;
   342         case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
   343           ok(message.body == null, "message.body");
   344           break;
   345         case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
   346           is(message.body, indicator ? BODY_UCS2_IND : BODY_UCS2, "message.body");
   347           break;
   348       }
   350       is(message.messageClass, messageClass, "message.messageClass");
   351     });
   352   }
   354   do_test(0);
   355 }
   357 function testReceiving_GSM_Timestamp() {
   358   log("Test receiving GSM Cell Broadcast - Timestamp");
   360   let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
   361   doTestHelper(pdu, testReceiving_GSM_WarningType, function(message) {
   362     // Cell Broadcast messages do not contain a timestamp field (however, ETWS
   363     // does). We only check the timestamp doesn't go too far (60 seconds) here.
   364     let msMessage = message.timestamp.getTime();
   365     let msNow = Date.now();
   366     ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp");
   367   });
   368 }
   370 function testReceiving_GSM_WarningType() {
   371   log("Test receiving GSM Cell Broadcast - Warning Type");
   373   let messageIdsToTest = [];
   374   for (let i = CB_GSM_MESSAGEID_ETWS_BEGIN; i <= CB_GSM_MESSAGEID_ETWS_END; i++) {
   375     messageIdsToTest.push(i);
   376   }
   378   function do_test(messageId, nextTest) {
   379     let pdu = buildHexStr(0, 4)
   380             + buildHexStr((messageId & 0xFFFF), 4)
   381             + buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 4) * 2);
   383     doTestHelper(pdu, nextTest, function(message) {
   384       is(message.messageId, messageId, "message.messageId");
   385       ok(message.etws != null, "message.etws");
   387       let offset = messageId - CB_GSM_MESSAGEID_ETWS_BEGIN;
   388       if (offset < CB_ETWS_WARNING_TYPE_NAMES.length) {
   389         is(message.etws.warningType, CB_ETWS_WARNING_TYPE_NAMES[offset],
   390            "message.etws.warningType");
   391       } else {
   392         ok(message.etws.warningType == null, "message.etws.warningType");
   393       }
   394     });
   395   }
   397   repeat(do_test, messageIdsToTest, testReceiving_GSM_EmergencyUserAlert);
   398 }
   400 function doTestEmergencyUserAlert_or_Popup(name, mask, nextTest) {
   401   let pdu = buildHexStr(mask, 4)
   402           + buildHexStr(CB_GSM_MESSAGEID_ETWS_BEGIN, 4)
   403           + buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 4) * 2);
   405   doTestHelper(pdu, nextTest, function(message) {
   406     is(message.messageId, CB_GSM_MESSAGEID_ETWS_BEGIN, "message.messageId");
   407     ok(message.etws != null, "message.etws");
   408     is(message.etws[name], mask != 0, "message.etws." + name);
   409   });
   410 }
   412 function testReceiving_GSM_EmergencyUserAlert() {
   413   log("Test receiving GSM Cell Broadcast - Emergency User Alert");
   415   repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "emergencyUserAlert"),
   416          [0x2000, 0x0000], testReceiving_GSM_Popup);
   417 }
   419 function testReceiving_GSM_Popup() {
   420   log("Test receiving GSM Cell Broadcast - Popup");
   422   repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "popup"),
   423          [0x1000, 0x0000], testReceiving_GSM_Multipart);
   424 }
   426 function testReceiving_GSM_Multipart() {
   427   log("Test receiving GSM Cell Broadcast - Multipart Messages");
   429   function do_test(numParts, nextTest) {
   430     let pdus = [];
   431     for (let i = 1; i <= numParts; i++) {
   432       let pdu = buildHexStr(0, 10)
   433               + buildHexStr((i << 4) + numParts, 2)
   434               + buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 6) * 2);
   435       pdus.push(pdu);
   436     }
   438     doTestHelper(pdus, nextTest, function(message) {
   439       is(message.body.length, (numParts * CB_MAX_CONTENT_7BIT),
   440          "message.body");
   441     });
   442   }
   444   repeat(do_test, seq(16, 1), testReceiving_GSM_ServiceCategory);
   445 }
   447 function testReceiving_GSM_ServiceCategory() {
   448   log("Test receiving GSM Cell Broadcast - Service Category");
   450   cbs.addEventListener("received", function onreceived(event) {
   451     cbs.removeEventListener("received", onreceived);
   453     let message = event.message;
   455     // Bug 910091
   456     // "Service Category" is not defined in GSM.  We should always get '0' here.
   457     is(message.cdmaServiceCategory, 0, "message.cdmaServiceCategory");
   459     window.setTimeout(cleanUp, 0);
   460   });
   462   let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
   463   sendCellBroadcastMessage(pdu);
   464 }
   466 function cleanUp() {
   467   if (pendingEmulatorCmdCount > 0) {
   468     window.setTimeout(cleanUp, 100);
   469     return;
   470   }
   472   SpecialPowers.removePermission("mobileconnection", document);
   473   SpecialPowers.removePermission("cellbroadcast", true, document);
   475   finish();
   476 }
   478 waitFor(testGsmMessageAttributes, function() {
   479   return navigator.mozMobileConnections[0].voice.connected;
   480 });

mercurial