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=invalid-name 20 21import datetime 22from importlib import reload 23from io import StringIO 24import os 25import sys 26import tempfile 27import unittest 28from unittest import mock 29from atest import arg_parser 30from atest import atest_main 31from atest import atest_utils 32from atest import constants 33from atest import module_info 34from atest.atest_enum import DetectType 35from atest.metrics import metrics 36from atest.metrics import metrics_utils 37from atest.test_finders import test_info 38from pyfakefs import fake_filesystem_unittest 39 40GREEN = '\x1b[1;32m' 41CYAN = '\x1b[1;36m' 42MAGENTA = '\x1b[1;35m' 43END = '\x1b[0m' 44 45 46# pylint: disable=protected-access 47class AtestUnittests(unittest.TestCase): 48 """Unit tests for atest_main.py""" 49 50 @mock.patch('os.environ.get', return_value=None) 51 def test_missing_environment_variables_uninitialized(self, _): 52 """Test _has_environment_variables when no env vars.""" 53 self.assertTrue(atest_main._missing_environment_variables()) 54 55 @mock.patch('os.environ.get', return_value='out/testcases/') 56 def test_missing_environment_variables_initialized(self, _): 57 """Test _has_environment_variables when env vars.""" 58 self.assertFalse(atest_main._missing_environment_variables()) 59 60 def test_parse_args(self): 61 """Test _parse_args parses command line args.""" 62 test_one = 'test_name_one' 63 test_two = 'test_name_two' 64 custom_arg = '--custom_arg' 65 custom_arg_val = 'custom_arg_val' 66 pos_custom_arg = 'pos_custom_arg' 67 68 # Test out test and custom args are properly retrieved. 69 args = [test_one, test_two, '--', custom_arg, custom_arg_val] 70 parsed_args = atest_main._parse_args(args) 71 self.assertEqual(parsed_args.tests, [test_one, test_two]) 72 self.assertEqual(parsed_args.custom_args, [custom_arg, custom_arg_val]) 73 74 # Test out custom positional args with no test args. 75 args = ['--', pos_custom_arg, custom_arg_val] 76 parsed_args = atest_main._parse_args(args) 77 self.assertEqual(parsed_args.tests, []) 78 self.assertEqual(parsed_args.custom_args, [pos_custom_arg, custom_arg_val]) 79 80 def test_has_valid_test_mapping_args(self): 81 """Test _has_valid_test_mapping_args method.""" 82 # Test test mapping related args are not mixed with incompatible args. 83 options_no_tm_support = [ 84 ( 85 '--annotation-filter', 86 'androidx.test.filters.SmallTest', 87 ), 88 ] 89 tm_options = ['--test-mapping', '--include-subdirs'] 90 91 for tm_option in tm_options: 92 for no_tm_option, no_tm_option_value in options_no_tm_support: 93 args = [tm_option, no_tm_option] 94 if no_tm_option_value is not None: 95 args.append(no_tm_option_value) 96 parsed_args = atest_main._parse_args(args) 97 self.assertFalse( 98 atest_main._has_valid_test_mapping_args(parsed_args), 99 'Failed to validate: %s' % args, 100 ) 101 102 @mock.patch.object(atest_utils, 'get_adb_devices') 103 @mock.patch.object(metrics_utils, 'send_exit_event') 104 def test_validate_exec_mode(self, _send_exit, _devs): 105 """Test _validate_exec_mode.""" 106 _devs.return_value = ['127.0.0.1:34556'] 107 args = [] 108 no_install_test_info = test_info.TestInfo( 109 'mod', 110 '', 111 set(), 112 data={}, 113 module_class=['JAVA_LIBRARIES'], 114 install_locations=set(['device']), 115 ) 116 host_test_info = test_info.TestInfo( 117 'mod', 118 '', 119 set(), 120 data={}, 121 module_class=['NATIVE_TESTS'], 122 install_locations=set(['host']), 123 ) 124 device_test_info = test_info.TestInfo( 125 'mod', 126 '', 127 set(), 128 data={}, 129 module_class=['NATIVE_TESTS'], 130 install_locations=set(['device']), 131 ) 132 both_test_info = test_info.TestInfo( 133 'mod', 134 '', 135 set(), 136 data={}, 137 module_class=['NATIVE_TESTS'], 138 install_locations=set(['host', 'device']), 139 ) 140 141 # $atest <Both-support> 142 parsed_args = atest_main._parse_args(args) 143 test_infos = [host_test_info] 144 atest_main._validate_exec_mode(parsed_args, test_infos) 145 self.assertFalse(parsed_args.host) 146 147 # $atest <Both-support> with host_tests set to True 148 parsed_args = atest_main._parse_args([]) 149 test_infos = [host_test_info] 150 atest_main._validate_exec_mode(parsed_args, test_infos, host_tests=True) 151 # Make sure the host option is not set. 152 self.assertFalse(parsed_args.host) 153 154 # $atest <Both-support> with host_tests set to False 155 parsed_args = atest_main._parse_args([]) 156 test_infos = [host_test_info] 157 atest_main._validate_exec_mode(parsed_args, test_infos, host_tests=False) 158 self.assertFalse(parsed_args.host) 159 160 # $atest <device-only> with host_tests set to False 161 parsed_args = atest_main._parse_args([]) 162 test_infos = [device_test_info] 163 atest_main._validate_exec_mode(parsed_args, test_infos, host_tests=False) 164 # Make sure the host option is not set. 165 self.assertFalse(parsed_args.host) 166 167 # $atest <device-only> with host_tests set to True 168 parsed_args = atest_main._parse_args([]) 169 test_infos = [device_test_info] 170 self.assertRaises( 171 SystemExit, 172 atest_main._validate_exec_mode, 173 parsed_args, 174 test_infos, 175 host_tests=True, 176 ) 177 178 # $atest <Both-support> 179 parsed_args = atest_main._parse_args([]) 180 test_infos = [both_test_info] 181 atest_main._validate_exec_mode(parsed_args, test_infos) 182 self.assertFalse(parsed_args.host) 183 184 # $atest <no_install_test_info> 185 parsed_args = atest_main._parse_args([]) 186 test_infos = [no_install_test_info] 187 atest_main._validate_exec_mode(parsed_args, test_infos) 188 self.assertFalse(parsed_args.host) 189 190 def test_make_test_run_dir(self): 191 """Test make_test_run_dir.""" 192 tmp_dir = tempfile.mkdtemp() 193 constants.ATEST_RESULT_ROOT = tmp_dir 194 date_time = None 195 196 work_dir = atest_main.make_test_run_dir() 197 folder_name = os.path.basename(work_dir) 198 date_time = datetime.datetime.strptime( 199 '_'.join(folder_name.split('_')[0:2]), atest_main.TEST_RUN_DIR_PREFIX 200 ) 201 reload(constants) 202 self.assertTrue(date_time) 203 204 def test_has_set_sufficient_devices_no_device_no_require(self): 205 required_num = 0 206 self.assertTrue(atest_main.has_set_sufficient_devices(required_num)) 207 208 def test_has_set_sufficient_devices_equal_required_attached_devices(self): 209 required_num = 2 210 attached_devices = ['serial1', 'serial2'] 211 212 self.assertTrue( 213 atest_main.has_set_sufficient_devices(required_num, attached_devices) 214 ) 215 216 def test_has_set_sufficient_devices_attached_devices_more_than_required(self): 217 required_num = 2 218 attached_devices = ['serial1', 'serial2', 'serial3'] 219 220 self.assertTrue( 221 atest_main.has_set_sufficient_devices(required_num, attached_devices) 222 ) 223 224 def test_has_set_sufficient_devices_not_enough_devices(self): 225 required_num = 2 226 attached_devices = ['serial1'] 227 228 self.assertFalse( 229 atest_main.has_set_sufficient_devices(required_num, attached_devices) 230 ) 231 232 def test_ravenwood_tests_is_deviceless(self): 233 ravenwood_test_info = test_info.TestInfo( 234 'mod', 235 '', 236 set(), 237 compatibility_suites=[ 238 test_info.MODULE_COMPATIBILITY_SUITES_RAVENWOOD_TESTS 239 ], 240 ) 241 242 self.assertEqual( 243 constants.DEVICELESS_TEST, 244 ravenwood_test_info.get_supported_exec_mode(), 245 'If compatibility suites contains ravenwood-tests, ' 246 'the test should be recognized as deviceless.', 247 ) 248 249 250class AtestMainUnitTests(unittest.TestCase): 251 252 def test_performance_tests_inject_default_args(self): 253 non_perf_test_info = test_info.TestInfo( 254 'some_module', 255 'TestRunner', 256 set(), 257 compatibility_suites=['not-performance'], 258 ) 259 perf_test_info = test_info.TestInfo( 260 'some_module', 261 'TestRunner', 262 set(), 263 compatibility_suites=['performance-tests'], 264 ) 265 args_original = atest_main._parse_args([]) 266 args = atest_main._parse_args([]) 267 268 with self.subTest(name='does not inject default args for non-perf tests'): 269 atest_main._AtestMain._inject_default_arguments_based_on_test_infos( 270 [non_perf_test_info], args 271 ) 272 273 self.assertEqual(args_original, args) 274 275 with self.subTest(name='injects default args for perf tests'): 276 atest_main._AtestMain._inject_default_arguments_based_on_test_infos( 277 [perf_test_info], args 278 ) 279 280 self.assertNotEqual(args_original, args) 281 282 283# pylint: disable=missing-function-docstring 284class AtestUnittestFixture(fake_filesystem_unittest.TestCase): 285 """Fixture for ModuleInfo tests.""" 286 287 def setUp(self): 288 self.setUpPyfakefs() 289 290 # pylint: disable=protected-access 291 def create_empty_module_info(self): 292 fake_temp_file_name = next(tempfile._get_candidate_names()) 293 self.fs.create_file(fake_temp_file_name, contents='{}') 294 return module_info.load_from_file(module_file=fake_temp_file_name) 295 296 def create_module_info(self, modules=None): 297 mod_info = self.create_empty_module_info() 298 modules = modules or [] 299 300 for m in modules: 301 mod_info.name_to_module_info[m['module_name']] = m 302 303 return mod_info 304 305 def create_test_info( 306 self, 307 test_name='hello_world_test', 308 test_runner='AtestTradefedRunner', 309 build_targets=None, 310 ): 311 """Create a test_info.TestInfo object.""" 312 if not build_targets: 313 build_targets = set() 314 return test_info.TestInfo(test_name, test_runner, build_targets) 315 316 317class PrintModuleInfoTest(AtestUnittestFixture): 318 """Test conditions for _print_module_info.""" 319 320 def tearDown(self): 321 sys.stdout = sys.__stdout__ 322 323 def test_has_valid_test_mapping_args_is_test_mapping_detect_event_send_1( 324 self, 325 ): 326 # Arrange 327 expected_detect_type = DetectType.IS_TEST_MAPPING 328 expected_result = 1 329 metrics.LocalDetectEvent = mock.MagicMock() 330 args = arg_parser.create_atest_arg_parser().parse_args([]) 331 332 # Act 333 atest_main._has_valid_test_mapping_args(args) 334 335 # Assert 336 metrics.LocalDetectEvent.assert_called_once_with( 337 detect_type=expected_detect_type, result=expected_result 338 ) 339 340 def test_has_valid_test_mapping_args_mpt_test_mapping_detect_event_send_0( 341 self, 342 ): 343 # Arrange 344 expected_detect_type = DetectType.IS_TEST_MAPPING 345 expected_result = 0 346 metrics.LocalDetectEvent = mock.MagicMock() 347 args = arg_parser.create_atest_arg_parser().parse_args(['test1']) 348 349 # Act 350 atest_main._has_valid_test_mapping_args(args) 351 352 # Assert 353 metrics.LocalDetectEvent.assert_called_once_with( 354 detect_type=expected_detect_type, result=expected_result 355 ) 356 357 358# pylint: disable=too-many-arguments 359def module( 360 name=None, 361 path=None, 362 installed=None, 363 classes=None, 364 auto_test_config=None, 365 test_config=None, 366 shared_libs=None, 367 dependencies=None, 368 runtime_dependencies=None, 369 data=None, 370 data_dependencies=None, 371 compatibility_suites=None, 372 host_dependencies=None, 373 srcs=None, 374): 375 name = name or 'libhello' 376 377 m = {} 378 379 m['module_name'] = name 380 m['class'] = classes 381 m['path'] = [path or ''] 382 m['installed'] = installed or [] 383 m['is_unit_test'] = 'false' 384 m['auto_test_config'] = auto_test_config or [] 385 m['test_config'] = test_config or [] 386 m['shared_libs'] = shared_libs or [] 387 m['runtime_dependencies'] = runtime_dependencies or [] 388 m['dependencies'] = dependencies or [] 389 m['data'] = data or [] 390 m['data_dependencies'] = data_dependencies or [] 391 m['compatibility_suites'] = compatibility_suites or [] 392 m['host_dependencies'] = host_dependencies or [] 393 m['srcs'] = srcs or [] 394 return m 395 396 397if __name__ == '__main__': 398 unittest.main() 399