• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Unit tests for controller manager."""
15
16import unittest
17from unittest import mock
18
19from mobly import controller_manager
20from mobly import signals
21from tests.lib import mock_controller
22
23
24class ControllerManagerTest(unittest.TestCase):
25  """Unit tests for Mobly's ControllerManager."""
26
27  def test_verify_controller_module(self):
28    controller_manager.verify_controller_module(mock_controller)
29
30  def test_verify_controller_module_null_attr(self):
31    try:
32      tmp = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
33      mock_controller.MOBLY_CONTROLLER_CONFIG_NAME = None
34      msg = 'Controller interface .* in .* cannot be null.'
35      with self.assertRaisesRegex(signals.ControllerError, msg):
36        controller_manager.verify_controller_module(mock_controller)
37    finally:
38      mock_controller.MOBLY_CONTROLLER_CONFIG_NAME = tmp
39
40  def test_verify_controller_module_missing_attr(self):
41    try:
42      tmp = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
43      delattr(mock_controller, 'MOBLY_CONTROLLER_CONFIG_NAME')
44      msg = 'Module .* missing required controller module attribute'
45      with self.assertRaisesRegex(signals.ControllerError, msg):
46        controller_manager.verify_controller_module(mock_controller)
47    finally:
48      setattr(mock_controller, 'MOBLY_CONTROLLER_CONFIG_NAME', tmp)
49
50  def test_register_controller_no_config(self):
51    c_manager = controller_manager.ControllerManager('SomeClass', {})
52    with self.assertRaisesRegex(
53        signals.ControllerError, 'No corresponding config found for'
54    ):
55      c_manager.register_controller(mock_controller)
56
57  def test_register_controller_no_config_for_not_required(self):
58    c_manager = controller_manager.ControllerManager('SomeClass', {})
59    self.assertIsNone(
60        c_manager.register_controller(mock_controller, required=False)
61    )
62
63  def test_register_controller_dup_register(self):
64    """Verifies correctness of registration, internal tally of controllers
65    objects, and the right error happen when a controller module is
66    registered twice.
67    """
68    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
69    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
70    c_manager = controller_manager.ControllerManager(
71        'SomeClass', controller_configs
72    )
73    c_manager.register_controller(mock_controller)
74    registered_name = 'mock_controller'
75    self.assertTrue(registered_name in c_manager._controller_objects)
76    mock_ctrlrs = c_manager._controller_objects[registered_name]
77    self.assertEqual(mock_ctrlrs[0].magic, 'magic1')
78    self.assertEqual(mock_ctrlrs[1].magic, 'magic2')
79    self.assertTrue(c_manager._controller_modules[registered_name])
80    expected_msg = 'Controller module .* has already been registered.'
81    with self.assertRaisesRegex(signals.ControllerError, expected_msg):
82      c_manager.register_controller(mock_controller)
83
84  def test_register_controller_return_value(self):
85    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
86    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
87    c_manager = controller_manager.ControllerManager(
88        'SomeClass', controller_configs
89    )
90    magic_devices = c_manager.register_controller(mock_controller)
91    self.assertEqual(magic_devices[0].magic, 'magic1')
92    self.assertEqual(magic_devices[1].magic, 'magic2')
93
94  def test_register_controller_change_return_value(self):
95    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
96    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
97    c_manager = controller_manager.ControllerManager(
98        'SomeClass', controller_configs
99    )
100    magic_devices = c_manager.register_controller(mock_controller)
101    magic1 = magic_devices.pop(0)
102    self.assertIs(magic1, c_manager._controller_objects['mock_controller'][0])
103    self.assertEqual(len(c_manager._controller_objects['mock_controller']), 2)
104
105  def test_register_controller_less_than_min_number(self):
106    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
107    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
108    c_manager = controller_manager.ControllerManager(
109        'SomeClass', controller_configs
110    )
111    expected_msg = 'Expected to get at least 3 controller objects, got 2.'
112    with self.assertRaisesRegex(signals.ControllerError, expected_msg):
113      c_manager.register_controller(mock_controller, min_number=3)
114
115  @mock.patch('yaml.dump', side_effect=TypeError('ha'))
116  def test_get_controller_info_record_not_serializable(self, _):
117    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
118    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
119    c_manager = controller_manager.ControllerManager(
120        'SomeClass', controller_configs
121    )
122    c_manager.register_controller(mock_controller)
123    record = c_manager.get_controller_info_records()[0]
124    actual_controller_info = record.controller_info
125    self.assertEqual(
126        actual_controller_info, "[{'MyMagic': 'magic1'}, {'MyMagic': 'magic2'}]"
127    )
128
129  def test_controller_record_exists_without_get_info(self):
130    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
131    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
132    c_manager = controller_manager.ControllerManager(
133        'SomeClass', controller_configs
134    )
135    get_info = getattr(mock_controller, 'get_info')
136    delattr(mock_controller, 'get_info')
137    try:
138      c_manager.register_controller(mock_controller)
139      record = c_manager.get_controller_info_records()[0]
140      self.assertIsNone(record.controller_info)
141      self.assertEqual(record.test_class, 'SomeClass')
142      self.assertEqual(record.controller_name, 'MagicDevice')
143    finally:
144      setattr(mock_controller, 'get_info', get_info)
145
146  @mock.patch('tests.lib.mock_controller.get_info')
147  def test_get_controller_info_records_empty(self, mock_get_info_func):
148    mock_get_info_func.return_value = None
149    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
150    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
151    c_manager = controller_manager.ControllerManager(
152        'SomeClass', controller_configs
153    )
154    c_manager.register_controller(mock_controller)
155    record = c_manager.get_controller_info_records()[0]
156    self.assertIsNone(record.controller_info)
157    self.assertEqual(record.test_class, 'SomeClass')
158    self.assertEqual(record.controller_name, 'MagicDevice')
159
160  @mock.patch('mobly.expects._ExpectErrorRecorder.add_error')
161  @mock.patch('tests.lib.mock_controller.get_info')
162  def test_get_controller_info_records_error(
163      self, mock_get_info_func, mock_add_error
164  ):
165    mock_get_info_func.side_effect = Exception('Record info failed.')
166    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
167    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
168    c_manager = controller_manager.ControllerManager(
169        'SomeClass', controller_configs
170    )
171    c_manager.register_controller(mock_controller)
172    self.assertFalse(c_manager.get_controller_info_records())
173    mock_add_error.assert_called_once()
174    error_record = mock_add_error.call_args[0][0]
175    self.assertIn('Record info failed.', error_record.stacktrace)
176
177  def test_get_controller_info_records(self):
178    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
179    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
180    c_manager = controller_manager.ControllerManager(
181        'SomeClass', controller_configs
182    )
183    c_manager.register_controller(mock_controller)
184    record = c_manager.get_controller_info_records()[0]
185    record_dict = record.to_dict()
186    record_dict.pop('Timestamp')
187    self.assertEqual(
188        record_dict,
189        {
190            'Controller Info': [{'MyMagic': 'magic1'}, {'MyMagic': 'magic2'}],
191            'Controller Name': 'MagicDevice',
192            'Test Class': 'SomeClass',
193        },
194    )
195
196  def test_get_controller_info_without_registration(self):
197    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
198    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
199    c_manager = controller_manager.ControllerManager(
200        'SomeClass', controller_configs
201    )
202    self.assertFalse(c_manager.get_controller_info_records())
203
204  @mock.patch('tests.lib.mock_controller.destroy')
205  def test_unregister_controller(self, mock_destroy_func):
206    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
207    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
208    c_manager = controller_manager.ControllerManager(
209        'SomeClass', controller_configs
210    )
211    objects = c_manager.register_controller(mock_controller)
212    c_manager.unregister_controllers()
213    mock_destroy_func.assert_called_once_with(objects)
214    self.assertFalse(c_manager._controller_objects)
215    self.assertFalse(c_manager._controller_modules)
216
217  @mock.patch('mobly.expects._ExpectErrorRecorder.add_error')
218  @mock.patch('tests.lib.mock_controller.destroy')
219  def test_unregister_controller_error(self, mock_destroy_func, mock_add_error):
220    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
221    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
222    c_manager = controller_manager.ControllerManager(
223        'SomeClass', controller_configs
224    )
225    c_manager.register_controller(mock_controller)
226    mock_destroy_func.side_effect = Exception('Failed in destroy.')
227    c_manager.unregister_controllers()
228    mock_add_error.assert_called_once()
229    error_record = mock_add_error.call_args[0][0]
230    self.assertIn('Failed in destroy.', error_record.stacktrace)
231    self.assertFalse(c_manager._controller_objects)
232    self.assertFalse(c_manager._controller_modules)
233
234  @mock.patch('tests.lib.mock_controller.destroy')
235  def test_unregister_controller_without_registration(self, mock_destroy_func):
236    mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME
237    controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']}
238    c_manager = controller_manager.ControllerManager(
239        'SomeClass', controller_configs
240    )
241    c_manager.unregister_controllers()
242    mock_destroy_func.assert_not_called()
243    self.assertFalse(c_manager._controller_objects)
244    self.assertFalse(c_manager._controller_modules)
245
246
247if __name__ == '__main__':
248  unittest.main()
249