Home | History | Annotate | Download | only in mbim_compliance
      1 # Copyright 2015 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import array
      6 import logging
      7 import unittest
      8 
      9 import common
     10 from autotest_lib.client.cros.cellular.mbim_compliance import mbim_constants
     11 from autotest_lib.client.cros.cellular.mbim_compliance import \
     12         mbim_command_message
     13 from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors
     14 from autotest_lib.client.cros.cellular.mbim_compliance import mbim_message
     15 from autotest_lib.client.cros.cellular.mbim_compliance import \
     16         mbim_message_request
     17 from autotest_lib.client.cros.cellular.mbim_compliance import \
     18         mbim_message_response
     19 
     20 
     21 class TestMessage(mbim_message.MBIMControlMessage):
     22     """ MBIMMessage for unit testing. """
     23     _FIELDS = (('I', 'message_type', mbim_message.FIELD_TYPE_PAYLOAD_ID),
     24                ('I', 'message_length', ''),
     25                ('I', 'transaction_id', ''))
     26     _DEFAULTS = {'message_length': 0, 'transaction_id': 0}
     27 
     28 
     29 class MBIMMessageTestCase(unittest.TestCase):
     30     """ Test cases for verifying MBIMMessage classes and MBIMMessageParser. """
     31 
     32 
     33     def test_fields_not_defined(self):
     34         """
     35         Verifies that an excepion is raised when constructing an MBIMMessage
     36         subclass that does not define a _FIELDS attribute.
     37         """
     38         with self.assertRaisesRegexp(
     39                 mbim_errors.MBIMComplianceControlMessageError,
     40                 'message must have some fields defined$'):
     41             class MBIMMessageFieldsNotDefined(mbim_message.MBIMControlMessage):
     42                 """ MBIMMessage without _FIELDS attribute. """
     43                 pass
     44 
     45 
     46     def test_message_missing_field_values(self):
     47         """
     48         Verifies that an exception is raised when constructing an MBIMMessage
     49         subclass object without providing values for all of the fields either
     50         in _DEFAULTS or in the constructor.
     51         """
     52         with self.assertRaisesRegexp(
     53                 mbim_errors.MBIMComplianceControlMessageError,
     54                 '^Missing field value'):
     55                 message = TestMessage()
     56 
     57 
     58     def test_argument_mismatch(self):
     59         """
     60         Verifies that an exception is raised when there is any argument which is
     61         not defined in the control message class.
     62         """
     63         with self.assertRaisesRegexp(
     64                 mbim_errors.MBIMComplianceControlMessageError,
     65                 '^Unexpected fields'):
     66                 message = TestMessage(message_type=4, fake=5)
     67 
     68 
     69     def test_message_default_value_set(self):
     70         """
     71         Verifies that the values for fields not provided in MBIMMessage
     72         constructor is taken from the _DEFAULTS attribute of the class.
     73         """
     74         message = TestMessage(message_type=3)
     75         self.assertEqual(message.message_length, 0)
     76         self.assertEqual(message.transaction_id, 0)
     77         self.assertEqual(message.message_type, 3)
     78 
     79 
     80     def test_message_default_value_override(self):
     81         """
     82         Verifies that the values for fields provided in MBIMMessage
     83         constructor overrides the values from the _DEFAULTS attribute of the
     84         class.
     85         """
     86         message = TestMessage(message_type=3, transaction_id=4)
     87         self.assertEqual(message.message_length, 0)
     88         self.assertEqual(message.transaction_id, 4)
     89         self.assertEqual(message.message_type, 3)
     90 
     91 
     92     def test_message_data_less_than_total_size_of_fields(self):
     93         """
     94         Verifies that an exception is raised when constructing a MBIMMessage
     95         subclass from raw message data of length less than the total size of
     96         fields specified by the _FIELDS attribute.
     97         """
     98         with self.assertRaisesRegexp(
     99                 mbim_errors.MBIMComplianceControlMessageError,
    100                 '^Length of Data'):
    101             message_data = array.array('B', [0x02, 0xAA])
    102             message = TestMessage(raw_data=message_data)
    103 
    104 
    105     def test_message_data_more_than_total_size_of_fields(self):
    106         """
    107         Verifies that it is OK to construct a MBIMMessage subclass from raw
    108         message data of length more than the total size of fields specified
    109         by the _FIELDS attribute. The additional data is put into
    110         |payload_buffer| field.
    111         """
    112         message_data = array.array('B', [0x02, 0xAA, 0xAA, 0XCC, 0xED, 0x98,
    113                                          0x80, 0x80, 0xAA, 0xED, 0x45, 0x45,
    114                                          0x50, 0x40])
    115         message = TestMessage(raw_data=message_data)
    116         self.assertEqual(message.payload_buffer, array.array('B', [0x50, 0x40]))
    117 
    118 
    119     def test_parse_mbim_open_done(self):
    120         """
    121         Verifies the packets of |MBIM_OPEN_DONE| type are parsed correctly.
    122         """
    123         packets = [array.array('B', [0x01, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00,
    124                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    125                                      0x00, 0x00])]
    126         message = mbim_message_response.parse_response_packets(packets)
    127         self.assertEqual(True, isinstance(message,
    128                 mbim_message_response.MBIMOpenDone))
    129         self.assertEqual(message.message_type, mbim_constants.MBIM_OPEN_DONE)
    130         self.assertEqual(message.message_length, 16)
    131         self.assertEqual(message.transaction_id, 1)
    132         self.assertEqual(message.status_codes,
    133                          mbim_constants.MBIM_STATUS_SUCCESS)
    134 
    135 
    136     def test_parse_mbim_close_done(self):
    137         """
    138         Verifies the packets of |MBIM_OPEN_DONE| type are parsed correctly.
    139         """
    140         packets = [array.array('B', [0x02, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00,
    141                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    142                                      0x00, 0x00])]
    143         message = mbim_message_response.parse_response_packets(packets)
    144         self.assertEqual(True, isinstance(message,
    145                 mbim_message_response.MBIMCloseDone))
    146         self.assertEqual(message.message_type, mbim_constants.MBIM_CLOSE_DONE)
    147         self.assertEqual(message.message_length, 16)
    148         self.assertEqual(message.transaction_id, 1)
    149         self.assertEqual(message.status_codes,
    150                          mbim_constants.MBIM_STATUS_SUCCESS)
    151 
    152 
    153     def test_parse_mbim_function_error_msg(self):
    154         """
    155         Verifies the |MBIM_FUNCTION_ERROR_MSG| packets are parsed correctly.
    156         """
    157         packets = [array.array('B', [0x04, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00,
    158                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00,
    159                                      0x00, 0x00])]
    160         message = mbim_message_response.parse_response_packets(packets)
    161         self.assertEqual(True, isinstance(message,
    162                 mbim_message_response.MBIMFunctionError))
    163         self.assertEqual(message.message_type,
    164                          mbim_constants.MBIM_FUNCTION_ERROR_MSG)
    165         self.assertEqual(message.message_length, 16)
    166         self.assertEqual(message.transaction_id, 1)
    167         self.assertEqual(message.error_status_code,
    168                          mbim_constants.MBIM_ERROR_UNKNOWN)
    169 
    170 
    171     def test_parse_mbim_command_done(self):
    172         """
    173         Verifies the packets of |MBIM_COMMAND_DONE| type are parsed correctly.
    174         This tests both the fragmentation reassembly and message parsing
    175         functionality.
    176         """
    177         packets = [array.array('B', [0x03, 0x00, 0x00, 0x80, 0x34, 0x00, 0x00,
    178                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
    179                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
    180                                      0x00, 0x06, 0xEE, 0x00, 0x00, 0x00, 0x00,
    181                                      0x80, 0x40, 0x20, 0x10, 0x00, 0xAA, 0xBB,
    182                                      0xCC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    183                                      0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01,
    184                                      0x01, 0x01, 0x01]),
    185                    array.array('B', [0x03, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00,
    186                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
    187                                      0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
    188                                      0x01, 0x01, 0x01])]
    189         message = mbim_message_response.parse_response_packets(packets)
    190         is_instance = isinstance(message,
    191                                  mbim_message_response.MBIMCommandDone)
    192         self.assertEqual(is_instance, True)
    193         self.assertEqual(message.message_type, mbim_constants.MBIM_COMMAND_DONE)
    194         self.assertEqual(message.message_length, 56)
    195         self.assertEqual(message.transaction_id, 1)
    196         self.assertEqual(message.total_fragments, 2)
    197         self.assertEqual(message.current_fragment, 0)
    198         self.assertEqual(message.device_service_id,
    199                          '\x02\x00\x06\xEE\x00\x00\x00\x00\x80\x40\x20\x10'
    200                          '\x00\xAA\xBB\xCC')
    201         self.assertEqual(message.cid, 1)
    202         self.assertEqual(message.status_codes,
    203                          mbim_constants.MBIM_STATUS_SUCCESS)
    204         self.assertEqual(message.information_buffer_length, 8)
    205         self.assertEqual(message.payload_buffer,
    206                          array.array('B', [0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    207                                            0x01, 0x01]))
    208 
    209 
    210     def test_parse_mbim_get_device_caps(self):
    211         """
    212         Verifies the packets of |MBIM_COMMAND_DONE| type for a GetDeviceCaps
    213         CID query are parsed correctly.
    214         This tests both the fragmentation reassembly and message parsing
    215         functionality.
    216         """
    217         packets = [array.array('B', [0x03, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00,
    218                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
    219                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2,
    220                                      0x89, 0xCC, 0x33, 0xBC, 0xBB, 0x8B, 0x4F,
    221                                      0xB6, 0xB0, 0x13, 0x3E, 0xC2, 0xAA, 0xE6,
    222                                      0xDF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    223                                      0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x01,
    224                                      0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    225                                      0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    226                                      0x0]),
    227                    array.array('B', [0x03, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00,
    228                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
    229                                      0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1F,
    230                                      0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
    231                                      0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
    232                                      0x00, 0x40, 0x00, 0x00, 0x00, 0x0A, 0x00,
    233                                      0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x1E,
    234                                      0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
    235                                      0x1E, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00,
    236                                      0x00]),
    237                    array.array('B', [0x03, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00,
    238                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
    239                                      0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12,
    240                                      0x00, 0x00, 0x00, 0x48, 0x00, 0x53, 0x00,
    241                                      0x50, 0x00, 0x41, 0x00, 0x2B, 0x00, 0x00,
    242                                      0x00, 0x33, 0x00, 0x35, 0x00, 0x31, 0x00,
    243                                      0x38, 0x00, 0x35, 0x00, 0x31, 0x00, 0x30,
    244                                      0x00, 0x36, 0x00, 0x30, 0x00, 0x30, 0x00,
    245                                      0x30, 0x00, 0x30, 0x00, 0x37, 0x00, 0x38,
    246                                      0x00]),
    247                    array.array('B', [0x03, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00,
    248                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
    249                                      0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34,
    250                                      0x00, 0x00, 0x00, 0x31, 0x00, 0x31, 0x00,
    251                                      0x2E, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30,
    252                                      0x00, 0x2E, 0x00, 0x31, 0x00, 0x36, 0x00,
    253                                      0x2E, 0x00, 0x30, 0x00, 0x34, 0x00, 0x2E,
    254                                      0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00,
    255                                      0x4D, 0x00, 0x4C, 0x00, 0x31, 0x00, 0x4D,
    256                                      0x0]),
    257                    array.array('B', [0x03, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
    258                                      0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
    259                                      0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x45,
    260                                      0x00, 0x39, 0x00, 0x33, 0x00, 0x36, 0x00,
    261                                      0x4D, 0x00, 0x00, 0x00])]
    262         message = mbim_message_response.parse_response_packets(packets)
    263         is_instance = isinstance(message,
    264                                  mbim_command_message.MBIMDeviceCapsInfo)
    265         self.assertEqual(is_instance, True)
    266         self.assertEqual(message.message_type, mbim_constants.MBIM_COMMAND_DONE)
    267         self.assertEqual(message.message_length, 208)
    268         self.assertEqual(message.transaction_id, 1)
    269         self.assertEqual(message.total_fragments, 5)
    270         self.assertEqual(message.current_fragment, 0)
    271         self.assertEqual(message.device_service_id,
    272                          '\xA2\x89\xCC3\xBC\xBB\x8BO\xB6\xB0\x13>\xC2\xAA\xE6'
    273                          '\xDF')
    274         self.assertEqual(message.cid, 1)
    275         self.assertEqual(message.status_codes,
    276                          mbim_constants.MBIM_STATUS_SUCCESS)
    277         self.assertEqual(message.information_buffer_length, 160)
    278         self.assertEqual(message.device_type, 1)
    279         self.assertEqual(message.cellular_class, 1)
    280         self.assertEqual(message.voice_class, 1)
    281         self.assertEqual(message.sim_class, 2)
    282         self.assertEqual(message.data_class, 2147483679)
    283         self.assertEqual(message.sms_caps, 3)
    284         self.assertEqual(message.control_caps, 3)
    285         self.assertEqual(message.max_sessions, 8)
    286         self.assertEqual(message.custom_data_class_offset, 64)
    287         self.assertEqual(message.custom_data_class_size, 10)
    288         self.assertEqual(message.device_id_offset, 76)
    289         self.assertEqual(message.device_id_size, 30)
    290         self.assertEqual(message.firmware_info_offset, 108)
    291         self.assertEqual(message.firmware_info_size, 30)
    292         self.assertEqual(message.hardware_info_offset, 140)
    293         self.assertEqual(message.hardware_info_size, 18)
    294 
    295 
    296     def test_generate_mbim_open(self):
    297         """
    298         Verifies the raw packet of |MBIM_OPEN| type is generated correctly.
    299         """
    300         message = mbim_message_request.MBIMOpen(max_control_transfer=40)
    301         packets = mbim_message_request.generate_request_packets(message, 64)
    302         self.assertEqual(packets, [array.array('B', [0x01, 0x00, 0x00, 0x00,
    303                                                      0x10, 0x00, 0x00, 0x00,
    304                                                      0x02, 0x00, 0x00, 0x00,
    305                                                      0x28, 0x00, 0x00, 0x00])])
    306 
    307 
    308     def test_generate_mbim_command_packets(self):
    309         """
    310         Verifies the raw packets of |MBIM_COMMAND| type are generated correctly.
    311         This verifies the fragmentation logic in the generate_request_packets.
    312         """
    313         payload_buffer=array.array('B', [0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
    314                                          0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    315                                          0x28, 0x00, 0x00, 0x00, 0x04, 0x05,
    316                                          0x06, 0x10, 0x87, 0xDE, 0xED, 0xAC,
    317                                          0x45, 0x35, 0x50, 0x60, 0x90, 0xED,
    318                                          0xAB])
    319         message = mbim_message_request.MBIMCommand(
    320                 device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes,
    321                 cid=mbim_constants.MBIM_CID_DEVICE_CAPS,
    322                 command_type=mbim_constants.COMMAND_TYPE_QUERY,
    323                 information_buffer_length=len(payload_buffer),
    324                 payload_buffer=payload_buffer)
    325         packets = mbim_message_request.generate_request_packets(message, 64)
    326         self.assertEqual(packets, [array.array('B', [0x03, 0x00, 0x00, 0x00,
    327                                                      0x40, 0x00, 0x00, 0x00,
    328                                                      0x01, 0x00, 0x00, 0x00,
    329                                                      0x02, 0x00, 0x00, 0x00,
    330                                                      0x00, 0x00, 0x00, 0x00,
    331                                                      0xA2, 0x89, 0xCC, 0x33,
    332                                                      0xBC, 0xBB, 0x8B, 0x4F,
    333                                                      0xB6, 0xB0, 0x13, 0x3E,
    334                                                      0xC2, 0xAA, 0xE6, 0xDF,
    335                                                      0x01, 0x00, 0x00, 0x00,
    336                                                      0x00, 0x00, 0x00, 0x00,
    337                                                      0x1F, 0x00, 0x00, 0x00,
    338                                                      0x01, 0x00, 0x00, 0x00,
    339                                                      0x10, 0x00, 0x00, 0x00,
    340                                                      0x01, 0x00, 0x00, 0x00,
    341                                                      0x28, 0x00, 0x00, 0x00]),
    342                                    array.array('B', [0x03, 0x00, 0x00, 0x00,
    343                                                      0x23, 0x00, 0x00, 0x00,
    344                                                      0x01, 0x00, 0x00, 0x00,
    345                                                      0x02, 0x00, 0x00, 0x00,
    346                                                      0x01, 0x00, 0x00, 0x00,
    347                                                      0x04, 0x05, 0x06, 0x10,
    348                                                      0x87, 0xDE, 0xED, 0xAC,
    349                                                      0x45, 0x35, 0x50, 0x60,
    350                                                      0x90, 0xED, 0xAB])])
    351 
    352 
    353 if __name__ == '__main__':
    354     logging.basicConfig(level=logging.DEBUG)
    355     unittest.main()
    356