• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright 2017, 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
17"""Unittests for atest."""
18
19# pylint: disable=line-too-long
20
21import datetime
22import os
23import sys
24import tempfile
25import unittest
26
27from importlib import reload
28from io import StringIO
29from unittest import mock
30
31# pylint: disable=wrong-import-order
32import atest
33import constants
34import module_info
35
36from metrics import metrics_utils
37from test_finders import test_info
38
39#pylint: disable=protected-access
40class AtestUnittests(unittest.TestCase):
41    """Unit tests for atest.py"""
42
43    @mock.patch('os.environ.get', return_value=None)
44    def test_missing_environment_variables_uninitialized(self, _):
45        """Test _has_environment_variables when no env vars."""
46        self.assertTrue(atest._missing_environment_variables())
47
48    @mock.patch('os.environ.get', return_value='out/testcases/')
49    def test_missing_environment_variables_initialized(self, _):
50        """Test _has_environment_variables when env vars."""
51        self.assertFalse(atest._missing_environment_variables())
52
53    def test_parse_args(self):
54        """Test _parse_args parses command line args."""
55        test_one = 'test_name_one'
56        test_two = 'test_name_two'
57        custom_arg = '--custom_arg'
58        custom_arg_val = 'custom_arg_val'
59        pos_custom_arg = 'pos_custom_arg'
60
61        # Test out test and custom args are properly retrieved.
62        args = [test_one, test_two, '--', custom_arg, custom_arg_val]
63        parsed_args = atest._parse_args(args)
64        self.assertEqual(parsed_args.tests, [test_one, test_two])
65        self.assertEqual(parsed_args.custom_args, [custom_arg, custom_arg_val])
66
67        # Test out custom positional args with no test args.
68        args = ['--', pos_custom_arg, custom_arg_val]
69        parsed_args = atest._parse_args(args)
70        self.assertEqual(parsed_args.tests, [])
71        self.assertEqual(parsed_args.custom_args, [pos_custom_arg,
72                                                   custom_arg_val])
73
74    def test_has_valid_test_mapping_args(self):
75        """Test _has_valid_test_mapping_args method."""
76        # Test test mapping related args are not mixed with incompatible args.
77        options_no_tm_support = [
78            ('--generate-baseline', '5'),
79            ('--detect-regression', 'path'),
80            ('--generate-new-metrics', '5')
81        ]
82        tm_options = [
83            '--test-mapping',
84            '--include-subdirs'
85        ]
86
87        for tm_option in tm_options:
88            for no_tm_option, no_tm_option_value in options_no_tm_support:
89                args = [tm_option, no_tm_option]
90                if no_tm_option_value is not None:
91                    args.append(no_tm_option_value)
92                parsed_args = atest._parse_args(args)
93                self.assertFalse(
94                    atest._has_valid_test_mapping_args(parsed_args),
95                    'Failed to validate: %s' % args)
96
97    @mock.patch.object(module_info.ModuleInfo, '_merge_soong_info')
98    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:'/'})
99    @mock.patch('json.load', return_value={})
100    @mock.patch('builtins.open', new_callable=mock.mock_open)
101    @mock.patch('os.path.isfile', return_value=True)
102    @mock.patch('atest_utils._has_colors', return_value=True)
103    @mock.patch.object(module_info.ModuleInfo, 'get_module_info',)
104    def test_print_module_info_from_module_name(self, mock_get_module_info,
105                                                _mock_has_colors, _isfile,
106                                                _open, _json, _merge):
107        """Test _print_module_info_from_module_name method."""
108        mod_one_name = 'mod1'
109        mod_one_path = ['src/path/mod1']
110        mod_one_installed = ['installed/path/mod1']
111        mod_one_suites = ['device_test_mod1', 'native_test_mod1']
112        mod_one = {constants.MODULE_NAME: mod_one_name,
113                   constants.MODULE_PATH: mod_one_path,
114                   constants.MODULE_INSTALLED: mod_one_installed,
115                   constants.MODULE_COMPATIBILITY_SUITES: mod_one_suites}
116
117        # Case 1: The testing_module('mod_one') can be found in module_info.
118        mock_get_module_info.return_value = mod_one
119        capture_output = StringIO()
120        sys.stdout = capture_output
121        mod_info = module_info.ModuleInfo()
122        # Check return value = True, since 'mod_one' can be found.
123        self.assertTrue(
124            atest._print_module_info_from_module_name(mod_info, mod_one_name))
125        # Assign sys.stdout back to default.
126        sys.stdout = sys.__stdout__
127        correct_output = ('\x1b[1;32mmod1\x1b[0m\n'
128                          '\x1b[1;36m\tCompatibility suite\x1b[0m\n'
129                          '\t\tdevice_test_mod1\n'
130                          '\t\tnative_test_mod1\n'
131                          '\x1b[1;36m\tSource code path\x1b[0m\n'
132                          '\t\tsrc/path/mod1\n'
133                          '\x1b[1;36m\tInstalled path\x1b[0m\n'
134                          '\t\tinstalled/path/mod1\n')
135        # Check the function correctly printed module_info in color to stdout
136        self.assertEqual(capture_output.getvalue(), correct_output)
137
138        # Case 2: The testing_module('mod_one') can NOT be found in module_info.
139        mock_get_module_info.return_value = None
140        capture_output = StringIO()
141        sys.stdout = capture_output
142        # Check return value = False, since 'mod_one' can NOT be found.
143        self.assertFalse(
144            atest._print_module_info_from_module_name(mod_info, mod_one_name))
145        # Assign sys.stdout back to default.
146        sys.stdout = sys.__stdout__
147        null_output = ''
148        # Check if no module_info, then nothing printed to screen.
149        self.assertEqual(capture_output.getvalue(), null_output)
150
151    @mock.patch.object(module_info.ModuleInfo, '_merge_soong_info')
152    @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:'/'})
153    @mock.patch('json.load', return_value={})
154    @mock.patch('builtins.open', new_callable=mock.mock_open)
155    @mock.patch('os.path.isfile', return_value=True)
156    @mock.patch('atest_utils._has_colors', return_value=True)
157    @mock.patch.object(module_info.ModuleInfo, 'get_module_info',)
158    def test_print_test_info(self, mock_get_module_info, _mock_has_colors,
159                             _isfile, _open, _json, _merge):
160        """Test _print_test_info method."""
161        mod_one_name = 'mod1'
162        mod_one = {constants.MODULE_NAME: mod_one_name,
163                   constants.MODULE_PATH: ['path/mod1'],
164                   constants.MODULE_INSTALLED: ['installed/mod1'],
165                   constants.MODULE_COMPATIBILITY_SUITES: ['suite_mod1']}
166        mod_two_name = 'mod2'
167        mod_two = {constants.MODULE_NAME: mod_two_name,
168                   constants.MODULE_PATH: ['path/mod2'],
169                   constants.MODULE_INSTALLED: ['installed/mod2'],
170                   constants.MODULE_COMPATIBILITY_SUITES: ['suite_mod2']}
171        mod_three_name = 'mod3'
172        mod_three = {constants.MODULE_NAME: mod_two_name,
173                     constants.MODULE_PATH: ['path/mod3'],
174                     constants.MODULE_INSTALLED: ['installed/mod3'],
175                     constants.MODULE_COMPATIBILITY_SUITES: ['suite_mod3']}
176        test_name = mod_one_name
177        build_targets = set([mod_one_name, mod_two_name, mod_three_name])
178        t_info = test_info.TestInfo(test_name, 'mock_runner', build_targets)
179        test_infos = set([t_info])
180
181        # The _print_test_info() will print the module_info of the test_info's
182        # test_name first. Then, print its related build targets. If the build
183        # target be printed before(e.g. build_target == test_info's test_name),
184        # it will skip it and print the next build_target.
185        # Since the build_targets of test_info are mod_one, mod_two, and
186        # mod_three, it will print mod_one first, then mod_two, and mod_three.
187        #
188        # _print_test_info() calls _print_module_info_from_module_name() to
189        # print the module_info. And _print_module_info_from_module_name()
190        # calls get_module_info() to get the module_info. So we can mock
191        # get_module_info() to achieve that.
192        mock_get_module_info.side_effect = [mod_one, mod_two, mod_three]
193
194        capture_output = StringIO()
195        sys.stdout = capture_output
196        mod_info = module_info.ModuleInfo()
197        atest._print_test_info(mod_info, test_infos)
198        # Assign sys.stdout back to default.
199        sys.stdout = sys.__stdout__
200        correct_output = ('\x1b[1;32mmod1\x1b[0m\n'
201                          '\x1b[1;36m\tCompatibility suite\x1b[0m\n'
202                          '\t\tsuite_mod1\n'
203                          '\x1b[1;36m\tSource code path\x1b[0m\n'
204                          '\t\tpath/mod1\n'
205                          '\x1b[1;36m\tInstalled path\x1b[0m\n'
206                          '\t\tinstalled/mod1\n'
207                          '\x1b[1;35m\tRelated build targets\x1b[0m\n'
208                          '\t\tmod1, mod2, mod3\n'
209                          '\x1b[1;32mmod2\x1b[0m\n'
210                          '\x1b[1;36m\tCompatibility suite\x1b[0m\n'
211                          '\t\tsuite_mod2\n'
212                          '\x1b[1;36m\tSource code path\x1b[0m\n'
213                          '\t\tpath/mod2\n'
214                          '\x1b[1;36m\tInstalled path\x1b[0m\n'
215                          '\t\tinstalled/mod2\n'
216                          '\x1b[1;32mmod3\x1b[0m\n'
217                          '\x1b[1;36m\tCompatibility suite\x1b[0m\n'
218                          '\t\tsuite_mod3\n'
219                          '\x1b[1;36m\tSource code path\x1b[0m\n'
220                          '\t\tpath/mod3\n'
221                          '\x1b[1;36m\tInstalled path\x1b[0m\n'
222                          '\t\tinstalled/mod3\n'
223                          '\x1b[1;37m\x1b[0m\n')
224        self.assertEqual(capture_output.getvalue(), correct_output)
225
226    @mock.patch.object(metrics_utils, 'send_exit_event')
227    def test_validate_exec_mode(self, _send_exit):
228        """Test _validate_exec_mode."""
229        args = []
230        parsed_args = atest._parse_args(args)
231        no_install_test_info = test_info.TestInfo(
232            'mod', '', set(), data={}, module_class=["JAVA_LIBRARIES"],
233            install_locations=set(['device']))
234        host_test_info = test_info.TestInfo(
235            'mod', '', set(), data={}, module_class=["NATIVE_TESTS"],
236            install_locations=set(['host']))
237        device_test_info = test_info.TestInfo(
238            'mod', '', set(), data={}, module_class=["NATIVE_TESTS"],
239            install_locations=set(['device']))
240        both_test_info = test_info.TestInfo(
241            'mod', '', set(), data={}, module_class=["NATIVE_TESTS"],
242            install_locations=set(['host', 'device']))
243
244        # $atest <Both-support>
245        test_infos = [host_test_info]
246        atest._validate_exec_mode(parsed_args, test_infos)
247        self.assertFalse(parsed_args.host)
248
249        # $atest <Both-support> with host_tests set to True
250        parsed_args = atest._parse_args([])
251        test_infos = [host_test_info]
252        atest._validate_exec_mode(parsed_args, test_infos, host_tests=True)
253        # Make sure the host option is not set.
254        self.assertFalse(parsed_args.host)
255
256        # $atest <Both-support> with host_tests set to False
257        parsed_args = atest._parse_args([])
258        test_infos = [host_test_info]
259        atest._validate_exec_mode(parsed_args, test_infos, host_tests=False)
260        self.assertFalse(parsed_args.host)
261
262        # $atest <device-only> with host_tests set to False
263        parsed_args = atest._parse_args([])
264        test_infos = [device_test_info]
265        atest._validate_exec_mode(parsed_args, test_infos, host_tests=False)
266        # Make sure the host option is not set.
267        self.assertFalse(parsed_args.host)
268
269        # $atest <device-only> with host_tests set to True
270        parsed_args = atest._parse_args([])
271        test_infos = [device_test_info]
272        self.assertRaises(SystemExit, atest._validate_exec_mode,
273                          parsed_args, test_infos, host_tests=True)
274
275        # $atest <Both-support>
276        parsed_args = atest._parse_args([])
277        test_infos = [both_test_info]
278        atest._validate_exec_mode(parsed_args, test_infos)
279        self.assertFalse(parsed_args.host)
280
281        # $atest <no_install_test_info>
282        parsed_args = atest._parse_args([])
283        test_infos = [no_install_test_info]
284        atest._validate_exec_mode(parsed_args, test_infos)
285        self.assertFalse(parsed_args.host)
286
287    def test_make_test_run_dir(self):
288        """Test make_test_run_dir."""
289        tmp_dir = tempfile.mkdtemp()
290        constants.ATEST_RESULT_ROOT = tmp_dir
291        date_time = None
292
293        work_dir = atest.make_test_run_dir()
294        folder_name = os.path.basename(work_dir)
295        date_time = datetime.datetime.strptime('_'.join(folder_name.split('_')[0:2]),
296                                               atest.TEST_RUN_DIR_PREFIX)
297        reload(constants)
298        self.assertTrue(date_time)
299
300
301if __name__ == '__main__':
302    unittest.main()
303