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