| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import array |
| import logging |
| import unittest |
| |
| import common |
| from autotest_lib.client.cros.cellular.mbim_compliance import mbim_constants |
| from autotest_lib.client.cros.cellular.mbim_compliance import \ |
| mbim_command_message |
| from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors |
| from autotest_lib.client.cros.cellular.mbim_compliance import mbim_message |
| from autotest_lib.client.cros.cellular.mbim_compliance import \ |
| mbim_message_request |
| from autotest_lib.client.cros.cellular.mbim_compliance import \ |
| mbim_message_response |
| |
| |
| class TestMessage(mbim_message.MBIMControlMessage): |
| """ MBIMMessage for unit testing. """ |
| _FIELDS = (('I', 'message_type', mbim_message.FIELD_TYPE_PAYLOAD_ID), |
| ('I', 'message_length', ''), |
| ('I', 'transaction_id', '')) |
| _DEFAULTS = {'message_length': 0, 'transaction_id': 0} |
| |
| |
| class MBIMMessageTestCase(unittest.TestCase): |
| """ Test cases for verifying MBIMMessage classes and MBIMMessageParser. """ |
| |
| |
| def test_fields_not_defined(self): |
| """ |
| Verifies that an excepion is raised when constructing an MBIMMessage |
| subclass that does not define a _FIELDS attribute. |
| """ |
| with self.assertRaisesRegexp( |
| mbim_errors.MBIMComplianceControlMessageError, |
| 'message must have some fields defined$'): |
| class MBIMMessageFieldsNotDefined(mbim_message.MBIMControlMessage): |
| """ MBIMMessage without _FIELDS attribute. """ |
| pass |
| |
| |
| def test_message_missing_field_values(self): |
| """ |
| Verifies that an exception is raised when constructing an MBIMMessage |
| subclass object without providing values for all of the fields either |
| in _DEFAULTS or in the constructor. |
| """ |
| with self.assertRaisesRegexp( |
| mbim_errors.MBIMComplianceControlMessageError, |
| '^Missing field value'): |
| message = TestMessage() |
| |
| |
| def test_argument_mismatch(self): |
| """ |
| Verifies that an exception is raised when there is any argument which is |
| not defined in the control message class. |
| """ |
| with self.assertRaisesRegexp( |
| mbim_errors.MBIMComplianceControlMessageError, |
| '^Unexpected fields'): |
| message = TestMessage(message_type=4, fake=5) |
| |
| |
| def test_message_default_value_set(self): |
| """ |
| Verifies that the values for fields not provided in MBIMMessage |
| constructor is taken from the _DEFAULTS attribute of the class. |
| """ |
| message = TestMessage(message_type=3) |
| self.assertEqual(message.message_length, 0) |
| self.assertEqual(message.transaction_id, 0) |
| self.assertEqual(message.message_type, 3) |
| |
| |
| def test_message_default_value_override(self): |
| """ |
| Verifies that the values for fields provided in MBIMMessage |
| constructor overrides the values from the _DEFAULTS attribute of the |
| class. |
| """ |
| message = TestMessage(message_type=3, transaction_id=4) |
| self.assertEqual(message.message_length, 0) |
| self.assertEqual(message.transaction_id, 4) |
| self.assertEqual(message.message_type, 3) |
| |
| |
| def test_message_data_less_than_total_size_of_fields(self): |
| """ |
| Verifies that an exception is raised when constructing a MBIMMessage |
| subclass from raw message data of length less than the total size of |
| fields specified by the _FIELDS attribute. |
| """ |
| with self.assertRaisesRegexp( |
| mbim_errors.MBIMComplianceControlMessageError, |
| '^Length of Data'): |
| message_data = array.array('B', [0x02, 0xAA]) |
| message = TestMessage(raw_data=message_data) |
| |
| |
| def test_message_data_more_than_total_size_of_fields(self): |
| """ |
| Verifies that it is OK to construct a MBIMMessage subclass from raw |
| message data of length more than the total size of fields specified |
| by the _FIELDS attribute. The additional data is put into |
| |payload_buffer| field. |
| """ |
| message_data = array.array('B', [0x02, 0xAA, 0xAA, 0XCC, 0xED, 0x98, |
| 0x80, 0x80, 0xAA, 0xED, 0x45, 0x45, |
| 0x50, 0x40]) |
| message = TestMessage(raw_data=message_data) |
| self.assertEqual(message.payload_buffer, array.array('B', [0x50, 0x40])) |
| |
| |
| def test_parse_mbim_open_done(self): |
| """ |
| Verifies the packets of |MBIM_OPEN_DONE| type are parsed correctly. |
| """ |
| packets = [array.array('B', [0x01, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00])] |
| message = mbim_message_response.parse_response_packets(packets) |
| self.assertEqual(True, isinstance(message, |
| mbim_message_response.MBIMOpenDone)) |
| self.assertEqual(message.message_type, mbim_constants.MBIM_OPEN_DONE) |
| self.assertEqual(message.message_length, 16) |
| self.assertEqual(message.transaction_id, 1) |
| self.assertEqual(message.status_codes, |
| mbim_constants.MBIM_STATUS_SUCCESS) |
| |
| |
| def test_parse_mbim_close_done(self): |
| """ |
| Verifies the packets of |MBIM_OPEN_DONE| type are parsed correctly. |
| """ |
| packets = [array.array('B', [0x02, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00])] |
| message = mbim_message_response.parse_response_packets(packets) |
| self.assertEqual(True, isinstance(message, |
| mbim_message_response.MBIMCloseDone)) |
| self.assertEqual(message.message_type, mbim_constants.MBIM_CLOSE_DONE) |
| self.assertEqual(message.message_length, 16) |
| self.assertEqual(message.transaction_id, 1) |
| self.assertEqual(message.status_codes, |
| mbim_constants.MBIM_STATUS_SUCCESS) |
| |
| |
| def test_parse_mbim_function_error_msg(self): |
| """ |
| Verifies the |MBIM_FUNCTION_ERROR_MSG| packets are parsed correctly. |
| """ |
| packets = [array.array('B', [0x04, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, |
| 0x00, 0x00])] |
| message = mbim_message_response.parse_response_packets(packets) |
| self.assertEqual(True, isinstance(message, |
| mbim_message_response.MBIMFunctionError)) |
| self.assertEqual(message.message_type, |
| mbim_constants.MBIM_FUNCTION_ERROR_MSG) |
| self.assertEqual(message.message_length, 16) |
| self.assertEqual(message.transaction_id, 1) |
| self.assertEqual(message.error_status_code, |
| mbim_constants.MBIM_ERROR_UNKNOWN) |
| |
| |
| def test_parse_mbim_command_done(self): |
| """ |
| Verifies the packets of |MBIM_COMMAND_DONE| type are parsed correctly. |
| This tests both the fragmentation reassembly and message parsing |
| functionality. |
| """ |
| packets = [array.array('B', [0x03, 0x00, 0x00, 0x80, 0x34, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, |
| 0x00, 0x06, 0xEE, 0x00, 0x00, 0x00, 0x00, |
| 0x80, 0x40, 0x20, 0x10, 0x00, 0xAA, 0xBB, |
| 0xCC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, |
| 0x01, 0x01, 0x01]), |
| array.array('B', [0x03, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, |
| 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, |
| 0x01, 0x01, 0x01])] |
| message = mbim_message_response.parse_response_packets(packets) |
| is_instance = isinstance(message, |
| mbim_message_response.MBIMCommandDone) |
| self.assertEqual(is_instance, True) |
| self.assertEqual(message.message_type, mbim_constants.MBIM_COMMAND_DONE) |
| self.assertEqual(message.message_length, 56) |
| self.assertEqual(message.transaction_id, 1) |
| self.assertEqual(message.total_fragments, 2) |
| self.assertEqual(message.current_fragment, 0) |
| self.assertEqual(message.device_service_id, |
| '\x02\x00\x06\xEE\x00\x00\x00\x00\x80\x40\x20\x10' |
| '\x00\xAA\xBB\xCC') |
| self.assertEqual(message.cid, 1) |
| self.assertEqual(message.status_codes, |
| mbim_constants.MBIM_STATUS_SUCCESS) |
| self.assertEqual(message.information_buffer_length, 8) |
| self.assertEqual(message.payload_buffer, |
| array.array('B', [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
| 0x01, 0x01])) |
| |
| |
| def test_parse_mbim_get_device_caps(self): |
| """ |
| Verifies the packets of |MBIM_COMMAND_DONE| type for a GetDeviceCaps |
| CID query are parsed correctly. |
| This tests both the fragmentation reassembly and message parsing |
| functionality. |
| """ |
| packets = [array.array('B', [0x03, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, |
| 0x89, 0xCC, 0x33, 0xBC, 0xBB, 0x8B, 0x4F, |
| 0xB6, 0xB0, 0x13, 0x3E, 0xC2, 0xAA, 0xE6, |
| 0xDF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, |
| 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, |
| 0x0]), |
| array.array('B', [0x03, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, |
| 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1F, |
| 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, |
| 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, |
| 0x00, 0x40, 0x00, 0x00, 0x00, 0x0A, 0x00, |
| 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x1E, |
| 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, |
| 0x1E, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, |
| 0x00]), |
| array.array('B', [0x03, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, |
| 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, |
| 0x00, 0x00, 0x00, 0x48, 0x00, 0x53, 0x00, |
| 0x50, 0x00, 0x41, 0x00, 0x2B, 0x00, 0x00, |
| 0x00, 0x33, 0x00, 0x35, 0x00, 0x31, 0x00, |
| 0x38, 0x00, 0x35, 0x00, 0x31, 0x00, 0x30, |
| 0x00, 0x36, 0x00, 0x30, 0x00, 0x30, 0x00, |
| 0x30, 0x00, 0x30, 0x00, 0x37, 0x00, 0x38, |
| 0x00]), |
| array.array('B', [0x03, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, |
| 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, |
| 0x00, 0x00, 0x00, 0x31, 0x00, 0x31, 0x00, |
| 0x2E, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, |
| 0x00, 0x2E, 0x00, 0x31, 0x00, 0x36, 0x00, |
| 0x2E, 0x00, 0x30, 0x00, 0x34, 0x00, 0x2E, |
| 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, |
| 0x4D, 0x00, 0x4C, 0x00, 0x31, 0x00, 0x4D, |
| 0x0]), |
| array.array('B', [0x03, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, |
| 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x45, |
| 0x00, 0x39, 0x00, 0x33, 0x00, 0x36, 0x00, |
| 0x4D, 0x00, 0x00, 0x00])] |
| message = mbim_message_response.parse_response_packets(packets) |
| is_instance = isinstance(message, |
| mbim_command_message.MBIMDeviceCapsInfo) |
| self.assertEqual(is_instance, True) |
| self.assertEqual(message.message_type, mbim_constants.MBIM_COMMAND_DONE) |
| self.assertEqual(message.message_length, 208) |
| self.assertEqual(message.transaction_id, 1) |
| self.assertEqual(message.total_fragments, 5) |
| self.assertEqual(message.current_fragment, 0) |
| self.assertEqual(message.device_service_id, |
| '\xA2\x89\xCC3\xBC\xBB\x8BO\xB6\xB0\x13>\xC2\xAA\xE6' |
| '\xDF') |
| self.assertEqual(message.cid, 1) |
| self.assertEqual(message.status_codes, |
| mbim_constants.MBIM_STATUS_SUCCESS) |
| self.assertEqual(message.information_buffer_length, 160) |
| self.assertEqual(message.device_type, 1) |
| self.assertEqual(message.cellular_class, 1) |
| self.assertEqual(message.voice_class, 1) |
| self.assertEqual(message.sim_class, 2) |
| self.assertEqual(message.data_class, 2147483679) |
| self.assertEqual(message.sms_caps, 3) |
| self.assertEqual(message.control_caps, 3) |
| self.assertEqual(message.max_sessions, 8) |
| self.assertEqual(message.custom_data_class_offset, 64) |
| self.assertEqual(message.custom_data_class_size, 10) |
| self.assertEqual(message.device_id_offset, 76) |
| self.assertEqual(message.device_id_size, 30) |
| self.assertEqual(message.firmware_info_offset, 108) |
| self.assertEqual(message.firmware_info_size, 30) |
| self.assertEqual(message.hardware_info_offset, 140) |
| self.assertEqual(message.hardware_info_size, 18) |
| |
| |
| def test_generate_mbim_open(self): |
| """ |
| Verifies the raw packet of |MBIM_OPEN| type is generated correctly. |
| """ |
| message = mbim_message_request.MBIMOpen(max_control_transfer=40) |
| packets = mbim_message_request.generate_request_packets(message, 64) |
| self.assertEqual(packets, [array.array('B', [0x01, 0x00, 0x00, 0x00, |
| 0x10, 0x00, 0x00, 0x00, |
| 0x02, 0x00, 0x00, 0x00, |
| 0x28, 0x00, 0x00, 0x00])]) |
| |
| |
| def test_generate_mbim_command_packets(self): |
| """ |
| Verifies the raw packets of |MBIM_COMMAND| type are generated correctly. |
| This verifies the fragmentation logic in the generate_request_packets. |
| """ |
| payload_buffer=array.array('B', [0x01, 0x00, 0x00, 0x00, 0x10, 0x00, |
| 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, |
| 0x28, 0x00, 0x00, 0x00, 0x04, 0x05, |
| 0x06, 0x10, 0x87, 0xDE, 0xED, 0xAC, |
| 0x45, 0x35, 0x50, 0x60, 0x90, 0xED, |
| 0xAB]) |
| message = mbim_message_request.MBIMCommand( |
| device_service_id=mbim_constants.UUID_BASIC_CONNECT.bytes, |
| cid=mbim_constants.MBIM_CID_DEVICE_CAPS, |
| command_type=mbim_constants.COMMAND_TYPE_QUERY, |
| information_buffer_length=len(payload_buffer), |
| payload_buffer=payload_buffer) |
| packets = mbim_message_request.generate_request_packets(message, 64) |
| self.assertEqual(packets, [array.array('B', [0x03, 0x00, 0x00, 0x00, |
| 0x40, 0x00, 0x00, 0x00, |
| 0x01, 0x00, 0x00, 0x00, |
| 0x02, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, |
| 0xA2, 0x89, 0xCC, 0x33, |
| 0xBC, 0xBB, 0x8B, 0x4F, |
| 0xB6, 0xB0, 0x13, 0x3E, |
| 0xC2, 0xAA, 0xE6, 0xDF, |
| 0x01, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, |
| 0x1F, 0x00, 0x00, 0x00, |
| 0x01, 0x00, 0x00, 0x00, |
| 0x10, 0x00, 0x00, 0x00, |
| 0x01, 0x00, 0x00, 0x00, |
| 0x28, 0x00, 0x00, 0x00]), |
| array.array('B', [0x03, 0x00, 0x00, 0x00, |
| 0x23, 0x00, 0x00, 0x00, |
| 0x01, 0x00, 0x00, 0x00, |
| 0x02, 0x00, 0x00, 0x00, |
| 0x01, 0x00, 0x00, 0x00, |
| 0x04, 0x05, 0x06, 0x10, |
| 0x87, 0xDE, 0xED, 0xAC, |
| 0x45, 0x35, 0x50, 0x60, |
| 0x90, 0xED, 0xAB])]) |
| |
| |
| if __name__ == '__main__': |
| logging.basicConfig(level=logging.DEBUG) |
| unittest.main() |