1#!/usr/bin/env python3
2#
3#   Copyright 2016 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import mock
18import shutil
19import tempfile
20import unittest
21
22from acts import keys
23from acts import signals
24from acts import test_runner
25
26import acts_android_device_test
27import mock_controller
28
29
30class ActsTestRunnerTest(unittest.TestCase):
31    """This test class has unit tests for the implementation of everything
32    under acts.test_runner.
33    """
34
35    def setUp(self):
36        self.tmp_dir = tempfile.mkdtemp()
37        self.base_mock_test_config = {
38            "testbed": {
39                "name": "SampleTestBed",
40            },
41            "logpath": self.tmp_dir,
42            "cli_args": None,
43            "testpaths": ["./"],
44            "icecream": 42,
45            "extra_param": "haha"
46        }
47        self.mock_run_list = [('SampleTest', None)]
48
49    def tearDown(self):
50        shutil.rmtree(self.tmp_dir)
51
52    def test_register_controller_no_config(self):
53        tr = test_runner.TestRunner(self.base_mock_test_config,
54                                    self.mock_run_list)
55        with self.assertRaisesRegexp(signals.ControllerError,
56                                     "No corresponding config found for"):
57            tr.register_controller(mock_controller)
58
59    def test_register_optional_controller_no_config(self):
60        tr = test_runner.TestRunner(self.base_mock_test_config,
61                                    self.mock_run_list)
62        self.assertIsNone(
63            tr.register_controller(mock_controller, required=False))
64
65    def test_register_controller_third_party_dup_register(self):
66        """Verifies correctness of registration, internal tally of controllers
67        objects, and the right error happen when a controller module is
68        registered twice.
69        """
70        mock_test_config = dict(self.base_mock_test_config)
71        tb_key = keys.Config.key_testbed.value
72        mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
73        mock_test_config[tb_key][mock_ctrlr_config_name] = ["magic1", "magic2"]
74        tr = test_runner.TestRunner(mock_test_config, self.mock_run_list)
75        tr.register_controller(mock_controller)
76        registered_name = "mock_controller"
77        self.assertTrue(mock_controller in tr.controller_registry)
78        mock_ctrlrs = tr.controller_registry[mock_controller]
79        self.assertEqual(mock_ctrlrs[0].magic, "magic1")
80        self.assertEqual(mock_ctrlrs[1].magic, "magic2")
81        expected_msg = "Controller module .* has already been registered."
82        with self.assertRaisesRegexp(signals.ControllerError, expected_msg):
83            tr.register_controller(mock_controller)
84
85    def test_register_optional_controller_third_party_dup_register(self):
86        """Verifies correctness of registration, internal tally of controllers
87        objects, and the right error happen when an optional controller module
88        is registered twice.
89        """
90        mock_test_config = dict(self.base_mock_test_config)
91        tb_key = keys.Config.key_testbed.value
92        mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
93        mock_test_config[tb_key][mock_ctrlr_config_name] = ["magic1", "magic2"]
94        tr = test_runner.TestRunner(mock_test_config, self.mock_run_list)
95        tr.register_controller(mock_controller, required=False)
96        expected_msg = "Controller module .* has already been registered."
97        with self.assertRaisesRegexp(signals.ControllerError, expected_msg):
98            tr.register_controller(mock_controller, required=False)
99
100    def test_register_controller_builtin_dup_register(self):
101        """Same as test_register_controller_third_party_dup_register, except
102        this is for a builtin controller module.
103        """
104        mock_test_config = dict(self.base_mock_test_config)
105        tb_key = keys.Config.key_testbed.value
106        mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
107        mock_ref_name = "haha"
108        setattr(mock_controller, "ACTS_CONTROLLER_REFERENCE_NAME",
109                mock_ref_name)
110        try:
111            mock_ctrlr_ref_name = mock_controller.ACTS_CONTROLLER_REFERENCE_NAME
112            mock_test_config[tb_key][mock_ctrlr_config_name] = [
113                "magic1", "magic2"
114            ]
115            tr = test_runner.TestRunner(mock_test_config, self.mock_run_list)
116            tr.register_controller(mock_controller, builtin=True)
117            self.assertTrue(mock_ref_name in tr.test_run_info)
118            self.assertTrue(mock_controller in tr.controller_registry)
119            mock_ctrlrs = tr.test_run_info[mock_ctrlr_ref_name]
120            self.assertEqual(mock_ctrlrs[0].magic, "magic1")
121            self.assertEqual(mock_ctrlrs[1].magic, "magic2")
122            expected_msg = "Controller module .* has already been registered."
123            with self.assertRaisesRegexp(signals.ControllerError,
124                                         expected_msg):
125                tr.register_controller(mock_controller, builtin=True)
126        finally:
127            delattr(mock_controller, "ACTS_CONTROLLER_REFERENCE_NAME")
128
129    def test_register_controller_no_get_info(self):
130        mock_test_config = dict(self.base_mock_test_config)
131        tb_key = keys.Config.key_testbed.value
132        mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
133        mock_ref_name = "haha"
134        get_info = getattr(mock_controller, "get_info")
135        delattr(mock_controller, "get_info")
136        try:
137            mock_test_config[tb_key][mock_ctrlr_config_name] = [
138                "magic1", "magic2"
139            ]
140            tr = test_runner.TestRunner(mock_test_config, self.mock_run_list)
141            tr.register_controller(mock_controller)
142            self.assertEqual(tr.results.controller_info, {})
143        finally:
144            setattr(mock_controller, "get_info", get_info)
145
146    def test_register_controller_return_value(self):
147        mock_test_config = dict(self.base_mock_test_config)
148        tb_key = keys.Config.key_testbed.value
149        mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
150        mock_test_config[tb_key][mock_ctrlr_config_name] = ["magic1", "magic2"]
151        tr = test_runner.TestRunner(mock_test_config, self.mock_run_list)
152        magic_devices = tr.register_controller(mock_controller)
153        self.assertEqual(magic_devices[0].magic, "magic1")
154        self.assertEqual(magic_devices[1].magic, "magic2")
155
156    def test_run_twice(self):
157        """Verifies that:
158        1. Repeated run works properly.
159        2. The original configuration is not altered if a test controller
160           module modifies configuration.
161        """
162        mock_test_config = dict(self.base_mock_test_config)
163        tb_key = keys.Config.key_testbed.value
164        mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
165        my_config = [{
166            "serial": "xxxx",
167            "magic": "Magic1"
168        }, {
169            "serial": "xxxx",
170            "magic": "Magic2"
171        }]
172        mock_test_config[tb_key][mock_ctrlr_config_name] = my_config
173        tr = test_runner.TestRunner(mock_test_config,
174                                    [('IntegrationTest', None)])
175        tr.run()
176        self.assertFalse(tr.controller_registry)
177        self.assertTrue(mock_test_config[tb_key][mock_ctrlr_config_name][0])
178        tr.run()
179        tr.stop()
180        self.assertFalse(tr.controller_registry)
181        results = tr.results.summary_dict()
182        self.assertEqual(results["Requested"], 2)
183        self.assertEqual(results["Executed"], 2)
184        self.assertEqual(results["Passed"], 2)
185        expected_info = {
186            'MagicDevice': [{
187                'MyMagic': {
188                    'magic': 'Magic1'
189                }
190            }, {
191                'MyMagic': {
192                    'magic': 'Magic2'
193                }
194            }]
195        }
196        self.assertEqual(tr.results.controller_info, expected_info)
197
198    @mock.patch(
199        'acts.controllers.adb.AdbProxy',
200        return_value=acts_android_device_test.MockAdbProxy(1))
201    @mock.patch(
202        'acts.controllers.fastboot.FastbootProxy',
203        return_value=acts_android_device_test.MockFastbootProxy(1))
204    @mock.patch(
205        'acts.controllers.android_device.list_adb_devices', return_value=["1"])
206    @mock.patch(
207        'acts.controllers.android_device.get_all_instances',
208        return_value=acts_android_device_test.get_mock_ads(1))
209    @mock.patch(
210        'acts.controllers.android_device.AndroidDevice.ensure_screen_on',
211        return_value=True)
212    @mock.patch(
213        'acts.controllers.android_device.AndroidDevice.exit_setup_wizard',
214        return_value=True)
215    def test_run_two_test_classes(self, mock_exit_setup_wizard,
216                                  mock_ensure_screen_on, mock_get_all,
217                                  mock_list_adb, mock_fastboot, mock_adb):
218        """Verifies that runing more than one test class in one test run works
219        proerly.
220
221        This requires using a built-in controller module. Using AndroidDevice
222        module since it has all the mocks needed already.
223        """
224        mock_test_config = dict(self.base_mock_test_config)
225        tb_key = keys.Config.key_testbed.value
226        mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
227        my_config = [{
228            "serial": "xxxx",
229            "magic": "Magic1"
230        }, {
231            "serial": "xxxx",
232            "magic": "Magic2"
233        }]
234        mock_test_config[tb_key][mock_ctrlr_config_name] = my_config
235        mock_test_config[tb_key]["AndroidDevice"] = [{
236            "serial": "1",
237            "skip_sl4a": True
238        }]
239        tr = test_runner.TestRunner(mock_test_config,
240                                    [('IntegrationTest', None),
241                                     ('IntegrationTest', None)])
242        tr.run()
243        tr.stop()
244        self.assertFalse(tr.controller_registry)
245        results = tr.results.summary_dict()
246        self.assertEqual(results["Requested"], 2)
247        self.assertEqual(results["Executed"], 2)
248        self.assertEqual(results["Passed"], 2)
249
250    def test_verify_controller_module(self):
251        test_runner.TestRunner.verify_controller_module(mock_controller)
252
253    def test_verify_controller_module_null_attr(self):
254        try:
255            tmp = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
256            mock_controller.ACTS_CONTROLLER_CONFIG_NAME = None
257            msg = "Controller interface .* in .* cannot be null."
258            with self.assertRaisesRegexp(signals.ControllerError, msg):
259                test_runner.TestRunner.verify_controller_module(
260                    mock_controller)
261        finally:
262            mock_controller.ACTS_CONTROLLER_CONFIG_NAME = tmp
263
264    def test_verify_controller_module_missing_attr(self):
265        try:
266            tmp = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
267            delattr(mock_controller, "ACTS_CONTROLLER_CONFIG_NAME")
268            msg = "Module .* missing required controller module attribute"
269            with self.assertRaisesRegexp(signals.ControllerError, msg):
270                test_runner.TestRunner.verify_controller_module(
271                    mock_controller)
272        finally:
273            setattr(mock_controller, "ACTS_CONTROLLER_CONFIG_NAME", tmp)
274
275
276if __name__ == "__main__":
277    unittest.main()
278