• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5import array
6import logging
7import unittest
8
9import common
10from autotest_lib.client.cros.cellular.mbim_compliance import mbim_constants
11from autotest_lib.client.cros.cellular.mbim_compliance import \
12        mbim_command_message
13from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors
14from autotest_lib.client.cros.cellular.mbim_compliance import mbim_message
15from autotest_lib.client.cros.cellular.mbim_compliance import \
16        mbim_message_request
17from autotest_lib.client.cros.cellular.mbim_compliance import \
18        mbim_message_response
19
20
21class 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
29class 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
353if __name__ == '__main__':
354    logging.basicConfig(level=logging.DEBUG)
355    unittest.main()
356