1#!/usr/bin/env python3 2# 3# Copyright 2018, 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 module_finder.""" 18 19# pylint: disable=invalid-name 20# pylint: disable=missing-function-docstring 21# pylint: disable=too-many-lines 22# pylint: disable=unsubscriptable-object 23 24import copy 25import os 26import pathlib 27import re 28import tempfile 29import unittest 30from unittest import mock 31from atest import atest_error 32from atest import atest_utils 33from atest import constants 34from atest import module_info 35from atest import module_info_unittest_base 36from atest import unittest_constants as uc 37from atest import unittest_utils 38from atest.test_finders import module_finder 39from atest.test_finders import test_filter_utils 40from atest.test_finders import test_finder_utils 41from atest.test_finders import test_info 42from atest.test_runners import atest_tf_test_runner as atf_tr 43from pyfakefs import fake_filesystem_unittest 44 45MODULE_CLASS = '%s:%s' % (uc.MODULE_NAME, uc.CLASS_NAME) 46MODULE_PACKAGE = '%s:%s' % (uc.MODULE_NAME, uc.PACKAGE) 47CC_MODULE_CLASS = '%s:%s' % (uc.CC_MODULE_NAME, uc.CC_CLASS_NAME) 48KERNEL_TEST_CLASS = 'test_class_1' 49KERNEL_TEST_CONFIG = 'KernelTest.xml.data' 50KERNEL_MODULE_CLASS = '%s:%s' % ( 51 constants.REQUIRED_LTP_TEST_MODULES[0], 52 KERNEL_TEST_CLASS, 53) 54KERNEL_CONFIG_FILE = os.path.join(uc.TEST_DATA_DIR, KERNEL_TEST_CONFIG) 55KERNEL_CLASS_FILTER = test_info.TestFilter(KERNEL_TEST_CLASS, frozenset()) 56KERNEL_MODULE_CLASS_DATA = { 57 constants.TI_REL_CONFIG: KERNEL_CONFIG_FILE, 58 constants.TI_FILTER: frozenset([KERNEL_CLASS_FILTER]), 59} 60KERNEL_MODULE_CLASS_INFO = test_info.TestInfo( 61 constants.REQUIRED_LTP_TEST_MODULES[0], 62 atf_tr.AtestTradefedTestRunner.NAME, 63 uc.CLASS_BUILD_TARGETS, 64 KERNEL_MODULE_CLASS_DATA, 65) 66FLAT_METHOD_INFO = test_info.TestInfo( 67 uc.MODULE_NAME, 68 atf_tr.AtestTradefedTestRunner.NAME, 69 uc.MODULE_BUILD_TARGETS, 70 data={ 71 constants.TI_FILTER: frozenset([uc.FLAT_METHOD_FILTER]), 72 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 73 }, 74) 75MODULE_CLASS_METHOD = '%s#%s' % (MODULE_CLASS, uc.METHOD_NAME) 76CC_MODULE_CLASS_METHOD = '%s#%s' % (CC_MODULE_CLASS, uc.CC_METHOD_NAME) 77CLASS_INFO_MODULE_2 = test_info.TestInfo( 78 uc.MODULE2_NAME, 79 atf_tr.AtestTradefedTestRunner.NAME, 80 uc.CLASS_BUILD_TARGETS, 81 data={ 82 constants.TI_FILTER: frozenset([uc.CLASS_FILTER]), 83 constants.TI_REL_CONFIG: uc.CONFIG2_FILE, 84 }, 85) 86CC_CLASS_INFO_MODULE_2 = test_info.TestInfo( 87 uc.CC_MODULE2_NAME, 88 atf_tr.AtestTradefedTestRunner.NAME, 89 uc.CLASS_BUILD_TARGETS, 90 data={ 91 constants.TI_FILTER: frozenset([uc.CC_CLASS_FILTER]), 92 constants.TI_REL_CONFIG: uc.CC_CONFIG2_FILE, 93 }, 94) 95DEFAULT_INSTALL_PATH = ['/path/to/install'] 96ROBO_MOD_PATH = ['/shared/robo/path'] 97NON_RUN_ROBO_MOD_NAME = 'robo_mod' 98RUN_ROBO_MOD_NAME = 'run_robo_mod' 99NON_RUN_ROBO_MOD = { 100 constants.MODULE_NAME: NON_RUN_ROBO_MOD_NAME, 101 constants.MODULE_PATH: ROBO_MOD_PATH, 102 constants.MODULE_CLASS: ['random_class'], 103} 104RUN_ROBO_MOD = { 105 constants.MODULE_NAME: RUN_ROBO_MOD_NAME, 106 constants.MODULE_PATH: ROBO_MOD_PATH, 107 constants.MODULE_CLASS: [constants.MODULE_CLASS_ROBOLECTRIC], 108} 109 110SEARCH_DIR_RE = re.compile(r'^find ([^ ]*).*$') 111 112 113# pylint: disable=unused-argument 114def classoutside_side_effect(find_cmd, shell=False): 115 """Mock the check output of a find cmd where class outside module path.""" 116 search_dir = SEARCH_DIR_RE.match(find_cmd).group(1).strip() 117 if search_dir == uc.ROOT: 118 return uc.FIND_ONE 119 return None 120 121 122class ModuleFinderFindTestByModuleClassName( 123 module_info_unittest_base.ModuleInfoTest 124): 125 126 def setUp(self): 127 super().setUp() 128 self.build_top = pathlib.Path('/main') 129 130 def test_find_test_by_module_name_single_module_exists(self): 131 module_name = 'SingleModuleTestCases' 132 test_module = module_info_unittest_base.device_driven_test_module( 133 name=module_name, 134 ) 135 finder = self.create_finder_with_module(test_module) 136 137 t_infos = finder.find_test_by_module_name(module_name=module_name) 138 139 with self.subTest(name='returns_one_test_info'): 140 self.assertEqual(len(t_infos), 1) 141 with self.subTest(name='test_name_is_module_name'): 142 self.assert_test_info_has_test_name(t_infos[0], module_name) 143 self.assert_test_info_has_raw_test_name(t_infos[0], module_name) 144 with self.subTest(name='contains_expected_build_targets'): 145 self.assert_test_info_contains_build_targets(t_infos[0], module_name) 146 self.assert_test_info_contains_build_targets( 147 t_infos[0], 148 'example_module-project', 149 ) 150 151 @mock.patch( 152 'subprocess.check_output', 153 return_value=( 154 'path/to/testmodule/src/com/android/myjavatests/MyJavaTestClass.java' 155 ), 156 ) 157 def test_find_test_by_module_class_name_native_found(self, find_cmd): 158 module_name = 'MyModuleTestCases' 159 test_module = module_info_unittest_base.device_driven_test_module( 160 name=module_name, class_type=['NATIVE_TESTS'] 161 ) 162 finder = self.create_finder_with_module(test_module) 163 164 t_infos = finder.find_test_by_module_and_class( 165 'MyModuleTestCases:MyJavaTestClass' 166 ) 167 168 with self.subTest(name='returns_one_test_info'): 169 self.assertEqual(len(t_infos), 1) 170 with self.subTest(name='test_name_is_module_name'): 171 self.assert_test_info_has_test_name(t_infos[0], module_name) 172 self.assert_test_info_has_raw_test_name(t_infos[0], module_name) 173 with self.subTest(name='contains_expected_filters'): 174 self.assert_test_info_has_class_filter(t_infos[0], 'MyJavaTestClass') 175 with self.subTest(name='contains_expected_build_targets'): 176 self.assert_test_info_contains_build_targets(t_infos[0], module_name) 177 self.assert_test_info_contains_build_targets( 178 t_infos[0], 179 'example_module-project', 180 ) 181 182 @mock.patch( 183 'subprocess.check_output', 184 ) 185 def test_find_test_by_module_class_module_name_unknown_test_info_is_none( 186 self, find_cmd 187 ): 188 self.create_module_paths(['/project/module']) 189 test_file_src = self.create_class_in_module( 190 module_path='/project/module', class_name='MyJavaTestClass.java' 191 ) 192 test_module = module_info_unittest_base.device_driven_test_module( 193 name='MyModuleTestCases', 194 class_type=['NATIVE_TESTS'], 195 module_path='project/module', 196 srcs=[test_file_src], 197 ) 198 find_cmd.return_value = test_file_src 199 finder = self.create_finder_with_module(test_module) 200 201 t_infos = finder.find_test_by_class_name( 202 class_name='MyJavaTestClass', module_name='Unknown' 203 ) 204 205 self.assertIsNone(t_infos) 206 207 @mock.patch( 208 'subprocess.check_output', 209 return_value=[ 210 'example_module/project/src/com/android/myjavatests/MyJavaTestClass.java' 211 ], 212 ) 213 @mock.patch.object( 214 test_finder_utils, 'get_multiple_selection_answer', return_value='A' 215 ) 216 def test_find_test_by_module_class_multiple_configs_tests_found( 217 self, mock_test_selection, mock_run_cmd 218 ): 219 module_name = 'MyModuleTestCases' 220 test_module = ( 221 module_info_unittest_base.device_driven_multi_config_test_module( 222 name=module_name, 223 class_type=['NATIVE_TESTS'], 224 ) 225 ) 226 finder = self.create_finder_with_module(test_module) 227 228 t_infos = finder.find_test_by_module_and_class( 229 'MyModuleTestCases:MyMultiConfigJavaTestClass' 230 ) 231 232 with self.subTest(name='first_test_name_corresponds_to_module_name'): 233 self.assert_test_info_has_test_name(t_infos[0], module_name) 234 with self.subTest(name='second_test_name_corresponds_to_config_name'): 235 self.assert_test_info_has_test_name(t_infos[1], 'Config2') 236 with self.subTest(name='raw_test_name_corresponds_to_module_name'): 237 self.assert_test_info_has_raw_test_name(t_infos[0], module_name) 238 self.assert_test_info_has_raw_test_name(t_infos[1], module_name) 239 with self.subTest(name='contains_expected_filters'): 240 self.assert_test_info_has_class_filter( 241 t_infos[0], 'MyMultiConfigJavaTestClass' 242 ) 243 self.assert_test_info_has_config( 244 t_infos[0], 'example_module/project/configs/Config1.xml' 245 ) 246 self.assert_test_info_has_class_filter( 247 t_infos[1], 'MyMultiConfigJavaTestClass' 248 ) 249 self.assert_test_info_has_config( 250 t_infos[1], 'example_module/project/configs/Config2.xml' 251 ) 252 with self.subTest(name='contains_expected_build_targets'): 253 self.assert_test_info_contains_build_targets(t_infos[0], module_name) 254 self.assert_test_info_contains_build_targets( 255 t_infos[0], 256 'example_module-project', 257 ) 258 self.assert_test_info_contains_build_targets(t_infos[1], module_name) 259 self.assert_test_info_contains_build_targets( 260 t_infos[1], 261 'example_module-project', 262 ) 263 264 @mock.patch('subprocess.check_output') 265 def test_find_test_by_class_unique_class_name_finds_class(self, mock_run_cmd): 266 self.create_module_paths(['/project/tests/module1']) 267 test_file_src = self.create_class_in_module( 268 '/project/tests/module1', 'ClassOneTest.java' 269 ) 270 mock_run_cmd.return_value = test_file_src 271 test_module = module_info_unittest_base.device_driven_test_module( 272 name='module_name', 273 module_path='project/tests/module1', 274 srcs=[ 275 test_file_src, 276 '/project/tests/module1/src/tests/test2/ClassTwoTest.java', 277 ], 278 ) 279 finder = self.create_finder_with_module(test_module) 280 281 t_infos = finder.find_test_by_class_name(class_name='ClassOneTest') 282 283 with self.subTest(name='returns_one_test_info'): 284 self.assertEqual(len(t_infos), 1) 285 with self.subTest(name='test_info_has_expected_module_name'): 286 self.assert_test_info_has_test_name( 287 t_infos[0], test_module.get(constants.MODULE_NAME, []) 288 ) 289 with self.subTest(name='contains_expected_class_filter'): 290 self.assert_test_info_has_class_filter( 291 t_infos[0], 'project.tests.module1.ClassOneTest' 292 ) 293 294 @mock.patch.object(test_finder_utils, 'get_multiple_selection_answer') 295 @mock.patch('subprocess.check_output') 296 def test_find_test_by_class_multiple_class_names_returns_selection_menu( 297 self, mock_run_cmd, mock_test_selection 298 ): 299 self.create_module_paths( 300 ['/tests/android/module1', '/tests/android/module2'] 301 ) 302 test1_file_src = self.create_class_in_module( 303 '/tests/android/module1', 'ClassOneTest.java' 304 ) 305 test2_file_src = self.create_class_in_module( 306 '/tests/android/module2', 'ClassOneTest.java' 307 ) 308 mock_run_cmd.return_value = test1_file_src + '\n' + test2_file_src 309 mock_test_selection.return_value = '0' 310 test1_module = module_info_unittest_base.device_driven_test_module( 311 name='module1', 312 module_path='tests/android/module1', 313 srcs=[test1_file_src], 314 ) 315 test2_module = module_info_unittest_base.device_driven_test_module( 316 name='module2', 317 module_path='tests/android/module2', 318 srcs=[test2_file_src], 319 ) 320 finder = self.create_finder_with_multiple_modules( 321 [test1_module, test2_module] 322 ) 323 324 t_infos = finder.find_test_by_class_name(class_name='ClassOneTest') 325 326 with self.subTest(name='returns_one_test_info'): 327 self.assertEqual(len(t_infos), 1) 328 with self.subTest(name='test_info_has_expected_module_name'): 329 self.assert_test_info_has_test_name( 330 t_infos[0], test1_module.get(constants.MODULE_NAME, []) 331 ) 332 with self.subTest(name='contains_expected_class_filter'): 333 self.assert_test_info_has_class_filter( 334 t_infos[0], 'tests.android.module1.ClassOneTest' 335 ) 336 337 @mock.patch('subprocess.check_output') 338 def test_find_test_by_class_multiple_classes_in_module_finds_class( 339 self, mock_run_cmd 340 ): 341 self.create_module_paths(['/tests/android/module']) 342 test1_file_src = self.create_class_in_module( 343 '/tests/android/module', 'ClassOneTest.java' 344 ) 345 test2_file_src = self.create_class_in_module( 346 '/tests/android/module', 'ClassTwoTest.java' 347 ) 348 mock_run_cmd.return_value = test1_file_src 349 test_module = module_info_unittest_base.device_driven_test_module( 350 name='module1', 351 module_path='tests/android/module', 352 srcs=[test1_file_src, test2_file_src], 353 ) 354 finder = self.create_finder_with_module(test_module) 355 356 t_infos = finder.find_test_by_class_name(class_name='ClassOneTest') 357 358 with self.subTest(name='returns_one_test_info'): 359 self.assertEqual(len(t_infos), 1) 360 with self.subTest(name='test_info_has_expected_module_name'): 361 self.assert_test_info_has_test_name( 362 t_infos[0], test_module.get(constants.MODULE_NAME, []) 363 ) 364 with self.subTest(name='contains_expected_class_filter'): 365 self.assert_test_info_has_class_filter( 366 t_infos[0], 'tests.android.module.ClassOneTest' 367 ) 368 369 @mock.patch('atest.module_info.Loader.get_testable_module_from_memory') 370 @mock.patch('subprocess.check_output') 371 def test_find_test_by_class_multiple_modules_with_same_path_finds_class( 372 self, mock_run_cmd, mock_loader 373 ): 374 self.create_module_paths(['/tests/android/multi_module']) 375 test1_file_src = self.create_class_in_module( 376 '/tests/android/multi_module', 'ClassOneTest.java' 377 ) 378 test2_file_src = self.create_class_in_module( 379 '/tests/android/multi_module', 'ClassTwoTest.java' 380 ) 381 mock_run_cmd.return_value = test1_file_src 382 test1_module = module_info_unittest_base.device_driven_test_module( 383 name='multi_module1', 384 module_path='tests/android/multi_module', 385 srcs=[test1_file_src], 386 ) 387 test2_module = module_info_unittest_base.device_driven_test_module( 388 name='multi_module2', 389 module_path='tests/android/multi_module', 390 srcs=[test2_file_src], 391 ) 392 finder = self.create_finder_with_multiple_modules( 393 [test1_module, test2_module] 394 ) 395 mock_loader.return_value = set( 396 finder.module_info.name_to_module_info.keys() 397 ) 398 399 t_infos = finder.find_test_by_class_name(class_name='ClassOneTest') 400 401 with self.subTest(name='returns_one_test_info'): 402 self.assertEqual(len(t_infos), 1) 403 with self.subTest(name='test_info_has_expected_module_name'): 404 self.assert_test_info_has_test_name( 405 t_infos[0], test1_module.get(constants.MODULE_NAME, []) 406 ) 407 with self.subTest(name='contains_expected_class_filter'): 408 self.assert_test_info_has_class_filter( 409 t_infos[0], 'tests.android.multi_module.ClassOneTest' 410 ) 411 412 @mock.patch.object(test_finder_utils, 'get_multiple_selection_answer') 413 @mock.patch('subprocess.check_output') 414 def test_find_test_by_class_multiple_configs_one_test_per_config_found( 415 self, mock_run_cmd, mock_test_selection 416 ): 417 module_name = 'multi_config_module' 418 module_path = 'tests/android/multi_config_module' 419 mock_test_selection.return_value = 'A' 420 test1_file_src = self.create_class_in_module( 421 '/tests/android/multi_config_module', 'ClassOneTest.java' 422 ) 423 test_module = ( 424 module_info_unittest_base.device_driven_multi_config_test_module( 425 name=module_name, 426 module_path=module_path, 427 srcs=[test1_file_src], 428 ) 429 ) 430 mock_run_cmd.return_value = test1_file_src 431 finder = self.create_finder_with_module(test_module) 432 433 t_infos = finder.find_test_by_class_name(class_name='ClassOneTest') 434 435 with self.subTest(name='returns_two_test_info'): 436 self.assertEqual(len(t_infos), 2) 437 with self.subTest(name='first_test_name_corresponds_to_module_name'): 438 self.assert_test_info_has_test_name(t_infos[0], module_name) 439 with self.subTest(name='second_test_name_corresponds_to_config_name'): 440 self.assert_test_info_has_test_name(t_infos[1], 'Config2') 441 with self.subTest(name='contains_expected_class_filter'): 442 self.assert_test_info_has_class_filter( 443 t_infos[0], 'tests.android.multi_config_module.ClassOneTest' 444 ) 445 self.assert_test_info_has_config( 446 t_infos[0], f'{module_path}/configs/Config1.xml' 447 ) 448 self.assert_test_info_has_class_filter( 449 t_infos[1], 'tests.android.multi_config_module.ClassOneTest' 450 ) 451 self.assert_test_info_has_config( 452 t_infos[1], f'{module_path}/configs/Config2.xml' 453 ) 454 with self.subTest(name='raw_test_name_corresponds_to_module_name'): 455 self.assert_test_info_has_raw_test_name(t_infos[0], module_name) 456 self.assert_test_info_has_raw_test_name(t_infos[1], module_name) 457 with self.subTest(name='contains_expected_build_targets'): 458 self.assert_test_info_contains_build_targets(t_infos[0], module_name) 459 self.assert_test_info_contains_build_targets( 460 t_infos[0], 461 module_name, 462 ) 463 self.assert_test_info_contains_build_targets(t_infos[1], module_name) 464 self.assert_test_info_contains_build_targets( 465 t_infos[1], 466 module_name, 467 ) 468 469 def create_class_in_module(self, module_path: str, class_name: str) -> str: 470 file_path = module_path + '/src/' + class_name 471 self.fs.create_file( 472 file_path, contents='package ' + module_path[1:].replace('/', '.') 473 ) 474 return file_path 475 476 def create_module_paths(self, modules: list[str]): 477 for m in modules: 478 module_path = pathlib.Path(m) 479 module_path.mkdir(parents=True, exist_ok=True) 480 481 def create_finder_with_module( 482 self, test_module: dict 483 ) -> module_finder.ModuleFinder: 484 return module_finder.ModuleFinder(self.create_module_info([test_module])) 485 486 def create_finder_with_multiple_modules( 487 self, test_modules: list[dict] 488 ) -> module_finder.ModuleFinder: 489 return module_finder.ModuleFinder(self.create_module_info(test_modules)) 490 491 def assert_test_info_has_test_name( 492 self, t_info: test_info.TestInfo, test_name: str 493 ): 494 self.assertEqual(t_info.test_name, test_name) 495 496 def assert_test_info_has_raw_test_name( 497 self, t_info: test_info.TestInfo, test_name: str 498 ): 499 self.assertEqual(t_info.raw_test_name, test_name) 500 501 def assert_test_info_has_class_filter( 502 self, t_info: test_info.TestInfo, class_name: str 503 ): 504 self.assertSetEqual( 505 frozenset([test_info.TestFilter(class_name, frozenset())]), 506 t_info.data[constants.TI_FILTER], 507 ) 508 509 def assert_test_info_has_config( 510 self, t_info: test_info.TestInfo, config: str 511 ): 512 self.assertEqual(config, t_info.data[constants.TI_REL_CONFIG]) 513 514 def assert_test_info_contains_build_targets( 515 self, t_info: test_info.TestInfo, expected_build_target: str 516 ): 517 self.assertTrue( 518 any(expected_build_target in target for target in t_info.build_targets) 519 ) 520 521 522class ModuleFinderFindTestByPath(fake_filesystem_unittest.TestCase): 523 """Test cases that invoke find_test_by_path.""" 524 525 def setUp(self): 526 super().setUp() 527 self.setUpPyfakefs() 528 529 # pylint: disable=protected-access 530 def create_empty_module_info(self): 531 fake_temp_file_name = next(tempfile._get_candidate_names()) 532 self.fs.create_file(fake_temp_file_name, contents='{}') 533 return module_info.load_from_file(module_file=fake_temp_file_name) 534 535 def create_module_info(self, modules=None): 536 modules = modules or [] 537 name_to_module_info = {} 538 539 for m in modules: 540 name_to_module_info[m['module_name']] = m 541 542 return module_info.load_from_dict(name_to_module_info=name_to_module_info) 543 544 # TODO: remove below mocks and hide unnecessary information. 545 @mock.patch.object(module_finder.ModuleFinder, '_get_test_info_filter') 546 @mock.patch.object( 547 test_finder_utils, 'find_parent_module_dir', return_value=None 548 ) 549 # pylint: disable=unused-argument 550 def test_find_test_by_path_belong_to_dependencies( 551 self, _mock_find_parent, _mock_test_filter 552 ): 553 """Test find_test_by_path if belong to test dependencies.""" 554 test1 = module( 555 name='test1', 556 classes=['class'], 557 dependencies=['lib1'], 558 installed=['install/test1'], 559 auto_test_config=[True], 560 ) 561 test2 = module( 562 name='test2', 563 classes=['class'], 564 dependencies=['lib2'], 565 installed=['install/test2'], 566 auto_test_config=[True], 567 ) 568 lib1 = module(name='lib1', srcs=['path/src1']) 569 lib2 = module(name='lib2', srcs=['path/src2']) 570 mod_info = self.create_module_info([test1, test2, lib1, lib2]) 571 mod_finder = module_finder.ModuleFinder(module_info=mod_info) 572 self.fs.create_file('path/src1/main.cpp', contents='') 573 test1_filter = test_info.TestFilter('test1Filter', frozenset()) 574 _mock_test_filter.return_value = test1_filter 575 576 t_infos = mod_finder.find_test_by_path('path/src1') 577 578 unittest_utils.assert_equal_testinfos( 579 self, 580 test_info.TestInfo( 581 'test1', 582 atf_tr.AtestTradefedTestRunner.NAME, 583 {'test1', 'MODULES-IN-'}, 584 { 585 constants.TI_FILTER: test1_filter, 586 constants.TI_REL_CONFIG: 'AndroidTest.xml', 587 }, 588 module_class=['class'], 589 ), 590 t_infos[0], 591 ) 592 593 594# pylint: disable=protected-access 595class ModuleFinderUnittests(unittest.TestCase): 596 """Unit tests for module_finder.py""" 597 598 def setUp(self): 599 """Set up stuff for testing.""" 600 super().setUp() 601 self.mod_finder = module_finder.ModuleFinder() 602 self.mod_finder.module_info = mock.Mock(spec=module_info.ModuleInfo) 603 self.mod_finder.module_info.path_to_module_info = {} 604 self.mod_finder.module_info.is_mobly_module.return_value = False 605 self.mod_finder.root_dir = uc.ROOT 606 607 def test_is_vts_module(self): 608 """Test _load_module_info_file regular operation.""" 609 mod_name = 'mod' 610 is_vts_module_info = {'compatibility_suites': ['vts10', 'tests']} 611 self.mod_finder.module_info.get_module_info.return_value = ( 612 is_vts_module_info 613 ) 614 self.assertTrue(self.mod_finder._is_vts_module(mod_name)) 615 616 is_not_vts_module = {'compatibility_suites': ['vts10', 'cts']} 617 self.mod_finder.module_info.get_module_info.return_value = is_not_vts_module 618 self.assertFalse(self.mod_finder._is_vts_module(mod_name)) 619 620 # pylint: disable=unused-argument 621 @mock.patch.object( 622 module_finder.ModuleFinder, 623 '_get_build_targets', 624 return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS), 625 ) 626 def test_find_test_by_module_name(self, _get_targ): 627 """Test find_test_by_module_name.""" 628 self.mod_finder.module_info.is_robolectric_test.return_value = False 629 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 630 {} 631 ) 632 self.mod_finder.module_info.has_test_config.return_value = True 633 mod_info = { 634 'installed': ['/path/to/install'], 635 'path': [uc.MODULE_DIR], 636 constants.MODULE_CLASS: [], 637 constants.MODULE_COMPATIBILITY_SUITES: [], 638 } 639 self.mod_finder.module_info.get_module_info.return_value = mod_info 640 self.mod_finder.module_info.get_robolectric_type.return_value = 0 641 t_infos = self.mod_finder.find_test_by_module_name(uc.MODULE_NAME) 642 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.MODULE_INFO) 643 self.mod_finder.module_info.get_module_info.return_value = None 644 self.mod_finder.module_info.is_testable_module.return_value = False 645 self.assertIsNone(self.mod_finder.find_test_by_module_name('Not_Module')) 646 647 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 648 @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[]) 649 @mock.patch.object(atest_utils, 'is_build_file', return_value=True) 650 @mock.patch.object( 651 test_filter_utils, 'is_parameterized_java_class', return_value=False 652 ) 653 @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True) 654 @mock.patch.object( 655 module_finder.ModuleFinder, '_is_vts_module', return_value=False 656 ) 657 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 658 @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE) 659 @mock.patch.object( 660 test_filter_utils, 661 'get_fully_qualified_class_name', 662 return_value=uc.FULL_CLASS_NAME, 663 ) 664 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 665 @mock.patch('os.path.isdir', return_value=True) 666 # pylint: disable=unused-argument 667 def test_find_test_by_class_name( 668 self, 669 _isdir, 670 _isfile, 671 _fqcn, 672 mock_checkoutput, 673 mock_build, 674 _vts, 675 _has_method_in_file, 676 _is_parameterized, 677 _is_build_file, 678 _mock_unit_tests, 679 mods_to_test, 680 ): 681 """Test find_test_by_class_name.""" 682 mock_build.return_value = uc.CLASS_BUILD_TARGETS 683 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 684 self.mod_finder.module_info.is_robolectric_test.return_value = False 685 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 686 {} 687 ) 688 self.mod_finder.module_info.has_test_config.return_value = True 689 self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME] 690 self.mod_finder.module_info.get_module_info.return_value = { 691 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 692 constants.MODULE_NAME: uc.MODULE_NAME, 693 constants.MODULE_CLASS: [], 694 constants.MODULE_COMPATIBILITY_SUITES: [], 695 } 696 self.mod_finder.module_info.get_robolectric_type.return_value = 0 697 mods_to_test.return_value = [uc.MODULE_NAME] 698 t_infos = self.mod_finder.find_test_by_class_name(uc.CLASS_NAME) 699 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO) 700 701 # with method 702 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 703 class_with_method = '%s#%s' % (uc.CLASS_NAME, uc.METHOD_NAME) 704 t_infos = self.mod_finder.find_test_by_class_name(class_with_method) 705 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO) 706 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 707 class_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME) 708 t_infos = self.mod_finder.find_test_by_class_name(class_methods) 709 unittest_utils.assert_equal_testinfos(self, t_infos[0], FLAT_METHOD_INFO) 710 # module and rel_config passed in 711 mock_build.return_value = uc.CLASS_BUILD_TARGETS 712 t_infos = self.mod_finder.find_test_by_class_name( 713 uc.CLASS_NAME, uc.MODULE_NAME, uc.CONFIG_FILE 714 ) 715 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO) 716 # find output fails to find class file 717 mock_checkoutput.return_value = '' 718 self.assertIsNone(self.mod_finder.find_test_by_class_name('Not class')) 719 # class is outside given module path 720 mock_checkoutput.side_effect = classoutside_side_effect 721 t_infos = self.mod_finder.find_test_by_class_name( 722 uc.CLASS_NAME, uc.MODULE2_NAME, uc.CONFIG2_FILE 723 ) 724 unittest_utils.assert_equal_testinfos(self, t_infos[0], CLASS_INFO_MODULE_2) 725 726 @mock.patch.object( 727 test_finder_utils, 'find_parent_module_dir', return_value='foo/bar/jank' 728 ) 729 @mock.patch.object( 730 test_filter_utils, 'is_parameterized_java_class', return_value=False 731 ) 732 @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True) 733 @mock.patch.object( 734 module_finder.ModuleFinder, '_is_vts_module', return_value=False 735 ) 736 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 737 @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE) 738 @mock.patch.object( 739 test_filter_utils, 740 'get_fully_qualified_class_name', 741 return_value=uc.FULL_CLASS_NAME, 742 ) 743 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 744 # pylint: disable=unused-argument 745 def test_find_test_by_module_and_class( 746 self, 747 _isfile, 748 _fqcn, 749 mock_checkoutput, 750 mock_build, 751 _vts, 752 _has_method_in_file, 753 _is_parameterized, 754 mock_parent_dir, 755 ): 756 """Test find_test_by_module_and_class.""" 757 # Native test was tested in test_find_test_by_cc_class_name(). 758 self.mod_finder.module_info.is_native_test.return_value = False 759 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 760 self.mod_finder.module_info.is_robolectric_test.return_value = False 761 self.mod_finder.module_info.has_test_config.return_value = True 762 mock_build.return_value = uc.CLASS_BUILD_TARGETS 763 mod_info = { 764 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 765 constants.MODULE_PATH: [uc.MODULE_DIR], 766 constants.MODULE_CLASS: [], 767 constants.MODULE_COMPATIBILITY_SUITES: [], 768 } 769 self.mod_finder.module_info.get_module_info.return_value = mod_info 770 self.mod_finder.module_info.get_robolectric_type.return_value = 0 771 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 772 {} 773 ) 774 t_infos = self.mod_finder.find_test_by_module_and_class(MODULE_CLASS) 775 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO) 776 # with method 777 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 778 t_infos = self.mod_finder.find_test_by_module_and_class(MODULE_CLASS_METHOD) 779 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO) 780 self.mod_finder.module_info.is_testable_module.return_value = False 781 # bad module, good class, returns None 782 bad_module = '%s:%s' % ('BadMod', uc.CLASS_NAME) 783 self.mod_finder.module_info.get_module_info.return_value = None 784 self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_module)) 785 # find output fails to find class file 786 mock_checkoutput.return_value = '' 787 bad_class = '%s:%s' % (uc.MODULE_NAME, 'Anything') 788 self.mod_finder.module_info.get_module_info.return_value = mod_info 789 self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_class)) 790 791 @mock.patch.object(module_finder.test_finder_utils, 'get_cc_class_info') 792 @mock.patch.object( 793 module_finder.ModuleFinder, 794 'find_test_by_kernel_class_name', 795 return_value=None, 796 ) 797 @mock.patch.object( 798 module_finder.ModuleFinder, '_is_vts_module', return_value=False 799 ) 800 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 801 @mock.patch('subprocess.check_output', return_value=uc.FIND_CC_ONE) 802 @mock.patch.object( 803 test_finder_utils, 'find_class_file', side_effect=[None, None, '/'] 804 ) 805 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 806 # pylint: disable=unused-argument 807 def test_find_test_by_module_and_class_part_2( 808 self, 809 _isfile, 810 mock_fcf, 811 mock_checkoutput, 812 mock_build, 813 _vts, 814 _find_kernel, 815 _class_info, 816 ): 817 """Test find_test_by_module_and_class for MODULE:CC_CLASS.""" 818 # Native test was tested in test_find_test_by_cc_class_name() 819 self.mod_finder.module_info.is_native_test.return_value = False 820 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 821 self.mod_finder.module_info.is_robolectric_test.return_value = False 822 self.mod_finder.module_info.has_test_config.return_value = True 823 self.mod_finder.module_info.get_paths.return_value = [] 824 mock_build.return_value = uc.CLASS_BUILD_TARGETS 825 mod_info = { 826 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 827 constants.MODULE_PATH: [uc.CC_MODULE_DIR], 828 constants.MODULE_CLASS: [], 829 constants.MODULE_COMPATIBILITY_SUITES: [], 830 } 831 self.mod_finder.module_info.get_module_info.return_value = mod_info 832 _class_info.return_value = { 833 'PFTest': { 834 'methods': {'test1', 'test2'}, 835 'prefixes': set(), 836 'typed': False, 837 } 838 } 839 self.mod_finder.module_info.get_robolectric_type.return_value = 0 840 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 841 {} 842 ) 843 t_infos = self.mod_finder.find_test_by_module_and_class(CC_MODULE_CLASS) 844 unittest_utils.assert_equal_testinfos( 845 self, t_infos[0], uc.CC_MODULE_CLASS_INFO 846 ) 847 # with method 848 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 849 mock_fcf.side_effect = [None, None, '/'] 850 t_infos = self.mod_finder.find_test_by_module_and_class( 851 CC_MODULE_CLASS_METHOD 852 ) 853 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD3_INFO) 854 # bad module, good class, returns None 855 bad_module = '%s:%s' % ('BadMod', uc.CC_CLASS_NAME) 856 self.mod_finder.module_info.get_module_info.return_value = None 857 self.mod_finder.module_info.is_testable_module.return_value = False 858 self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_module)) 859 860 @mock.patch.object( 861 module_finder.ModuleFinder, 862 '_get_module_test_config', 863 return_value=[KERNEL_CONFIG_FILE], 864 ) 865 @mock.patch.object( 866 module_finder.ModuleFinder, '_is_vts_module', return_value=False 867 ) 868 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 869 @mock.patch('subprocess.check_output', return_value=uc.FIND_CC_ONE) 870 @mock.patch.object( 871 test_finder_utils, 'find_class_file', side_effect=[None, None, '/'] 872 ) 873 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 874 # pylint: disable=unused-argument 875 def test_find_test_by_module_and_class_for_kernel_test( 876 self, _isfile, mock_fcf, mock_checkoutput, mock_build, _vts, _test_config 877 ): 878 """Test find_test_by_module_and_class for MODULE:CC_CLASS.""" 879 # Kernel test was tested in find_test_by_kernel_class_name() 880 self.mod_finder.module_info.is_native_test.return_value = False 881 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 882 self.mod_finder.module_info.is_robolectric_test.return_value = False 883 self.mod_finder.module_info.has_test_config.return_value = True 884 self.mod_finder.module_info.get_paths.return_value = [] 885 mock_build.return_value = uc.CLASS_BUILD_TARGETS 886 mod_info = { 887 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 888 constants.MODULE_PATH: [uc.CC_MODULE_DIR], 889 constants.MODULE_CLASS: [], 890 constants.MODULE_COMPATIBILITY_SUITES: [], 891 } 892 self.mod_finder.module_info.get_module_info.return_value = mod_info 893 self.mod_finder.module_info.get_robolectric_type.return_value = 0 894 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 895 {} 896 ) 897 t_infos = self.mod_finder.find_test_by_module_and_class(KERNEL_MODULE_CLASS) 898 unittest_utils.assert_equal_testinfos( 899 self, t_infos[0], KERNEL_MODULE_CLASS_INFO 900 ) 901 902 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 903 @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[]) 904 @mock.patch.object( 905 module_finder.ModuleFinder, '_is_vts_module', return_value=False 906 ) 907 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 908 @mock.patch('subprocess.check_output', return_value=uc.FIND_PKG) 909 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 910 @mock.patch('os.path.isdir', return_value=True) 911 # pylint: disable=unused-argument 912 def test_find_test_by_package_name( 913 self, 914 _isdir, 915 _isfile, 916 mock_checkoutput, 917 mock_build, 918 _vts, 919 _mock_unit_tests, 920 mods_to_test, 921 ): 922 """Test find_test_by_package_name.""" 923 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 924 self.mod_finder.module_info.is_robolectric_test.return_value = False 925 self.mod_finder.module_info.has_test_config.return_value = True 926 mock_build.return_value = uc.CLASS_BUILD_TARGETS 927 self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME] 928 self.mod_finder.module_info.get_module_info.return_value = { 929 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 930 constants.MODULE_NAME: uc.MODULE_NAME, 931 constants.MODULE_CLASS: [], 932 constants.MODULE_COMPATIBILITY_SUITES: [], 933 } 934 self.mod_finder.module_info.get_robolectric_type.return_value = 0 935 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 936 {} 937 ) 938 mods_to_test.return_value = [uc.MODULE_NAME] 939 t_infos = self.mod_finder.find_test_by_package_name(uc.PACKAGE) 940 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO) 941 # with method, should raise 942 pkg_with_method = '%s#%s' % (uc.PACKAGE, uc.METHOD_NAME) 943 self.assertRaises( 944 atest_error.MethodWithoutClassError, 945 self.mod_finder.find_test_by_package_name, 946 pkg_with_method, 947 ) 948 # module and rel_config passed in 949 t_infos = self.mod_finder.find_test_by_package_name( 950 uc.PACKAGE, uc.MODULE_NAME, uc.CONFIG_FILE 951 ) 952 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO) 953 # find output fails to find class file 954 mock_checkoutput.return_value = '' 955 self.assertIsNone(self.mod_finder.find_test_by_package_name('Not pkg')) 956 957 @mock.patch('os.path.isdir', return_value=False) 958 @mock.patch.object( 959 module_finder.ModuleFinder, '_is_vts_module', return_value=False 960 ) 961 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 962 @mock.patch('subprocess.check_output', return_value=uc.FIND_PKG) 963 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 964 # pylint: disable=unused-argument 965 def test_find_test_by_module_and_package( 966 self, _isfile, mock_checkoutput, mock_build, _vts, _isdir 967 ): 968 """Test find_test_by_module_and_package.""" 969 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 970 self.mod_finder.module_info.is_robolectric_test.return_value = False 971 self.mod_finder.module_info.has_test_config.return_value = True 972 self.mod_finder.module_info.get_paths.return_value = [] 973 mock_build.return_value = uc.CLASS_BUILD_TARGETS 974 mod_info = { 975 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 976 constants.MODULE_PATH: [uc.MODULE_DIR], 977 constants.MODULE_CLASS: [], 978 constants.MODULE_COMPATIBILITY_SUITES: [], 979 } 980 self.mod_finder.module_info.get_module_info.return_value = mod_info 981 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 982 {} 983 ) 984 t_infos = self.mod_finder.find_test_by_module_and_package(MODULE_PACKAGE) 985 self.assertEqual(t_infos, None) 986 _isdir.return_value = True 987 self.mod_finder.module_info.get_robolectric_type.return_value = 0 988 t_infos = self.mod_finder.find_test_by_module_and_package(MODULE_PACKAGE) 989 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO) 990 991 # with method, raises 992 module_pkg_with_method = '%s:%s#%s' % ( 993 uc.MODULE2_NAME, 994 uc.PACKAGE, 995 uc.METHOD_NAME, 996 ) 997 self.assertRaises( 998 atest_error.MethodWithoutClassError, 999 self.mod_finder.find_test_by_module_and_package, 1000 module_pkg_with_method, 1001 ) 1002 # bad module, good pkg, returns None 1003 self.mod_finder.module_info.is_testable_module.return_value = False 1004 bad_module = '%s:%s' % ('BadMod', uc.PACKAGE) 1005 self.mod_finder.module_info.get_module_info.return_value = None 1006 self.assertIsNone( 1007 self.mod_finder.find_test_by_module_and_package(bad_module) 1008 ) 1009 # find output fails to find package path 1010 mock_checkoutput.return_value = '' 1011 bad_pkg = '%s:%s' % (uc.MODULE_NAME, 'Anything') 1012 self.mod_finder.module_info.get_module_info.return_value = mod_info 1013 self.assertIsNone(self.mod_finder.find_test_by_module_and_package(bad_pkg)) 1014 1015 # TODO: Move and rewite it to ModuleFinderFindTestByPath. 1016 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 1017 @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[]) 1018 @mock.patch.object(test_finder_utils, 'get_cc_class_info', return_value={}) 1019 @mock.patch.object(atest_utils, 'is_build_file', return_value=True) 1020 @mock.patch.object( 1021 test_filter_utils, 'is_parameterized_java_class', return_value=False 1022 ) 1023 @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True) 1024 @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True) 1025 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1026 @mock.patch.object( 1027 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1028 ) 1029 @mock.patch.object( 1030 test_filter_utils, 1031 'get_fully_qualified_class_name', 1032 return_value=uc.FULL_CLASS_NAME, 1033 ) 1034 @mock.patch( 1035 'os.path.realpath', side_effect=unittest_utils.realpath_side_effect 1036 ) 1037 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 1038 @mock.patch.object(test_finder_utils, 'find_parent_module_dir') 1039 @mock.patch('os.path.exists') 1040 # pylint: disable=unused-argument 1041 def test_find_test_by_path( 1042 self, 1043 mock_pathexists, 1044 mock_dir, 1045 _isfile, 1046 _real, 1047 _fqcn, 1048 _vts, 1049 mock_build, 1050 _has_cc_class, 1051 _has_method_in_file, 1052 _is_parameterized, 1053 _is_build_file, 1054 _get_cc_class_info, 1055 _mock_unit_tests, 1056 mods_to_test, 1057 ): 1058 """Test find_test_by_path.""" 1059 self.mod_finder.module_info.is_robolectric_test.return_value = False 1060 self.mod_finder.module_info.has_test_config.return_value = True 1061 self.mod_finder.module_info.get_modules_by_include_deps.return_value = set() 1062 mock_build.return_value = set() 1063 mods_to_test.return_value = [uc.MODULE_NAME] 1064 # Check that we don't return anything with invalid test references. 1065 mock_pathexists.return_value = False 1066 unittest_utils.assert_equal_testinfos( 1067 self, None, self.mod_finder.find_test_by_path('bad/path') 1068 ) 1069 mock_pathexists.return_value = True 1070 mock_dir.return_value = None 1071 unittest_utils.assert_equal_testinfos( 1072 self, None, self.mod_finder.find_test_by_path('no/module') 1073 ) 1074 self.mod_finder.module_info.get_module_info.return_value = { 1075 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1076 constants.MODULE_NAME: uc.MODULE_NAME, 1077 constants.MODULE_CLASS: [], 1078 constants.MODULE_COMPATIBILITY_SUITES: [], 1079 } 1080 1081 # Happy path testing. 1082 mock_dir.return_value = uc.MODULE_DIR 1083 1084 class_path = '%s.kt' % uc.CLASS_NAME 1085 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1086 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1087 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1088 {} 1089 ) 1090 t_infos = self.mod_finder.find_test_by_path(class_path) 1091 unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0]) 1092 1093 class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME) 1094 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1095 t_infos = self.mod_finder.find_test_by_path(class_with_method) 1096 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO) 1097 1098 class_path = '%s.java' % uc.CLASS_NAME 1099 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1100 t_infos = self.mod_finder.find_test_by_path(class_path) 1101 unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0]) 1102 1103 class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME) 1104 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1105 t_infos = self.mod_finder.find_test_by_path(class_with_method) 1106 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO) 1107 1108 class_with_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME) 1109 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1110 t_infos = self.mod_finder.find_test_by_path(class_with_methods) 1111 unittest_utils.assert_equal_testinfos(self, t_infos[0], FLAT_METHOD_INFO) 1112 1113 # Cc path testing. 1114 mods_to_test.return_value = [uc.CC_MODULE_NAME] 1115 self.mod_finder.module_info.get_module_info.return_value = { 1116 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1117 constants.MODULE_NAME: uc.CC_MODULE_NAME, 1118 constants.MODULE_CLASS: [], 1119 constants.MODULE_COMPATIBILITY_SUITES: [], 1120 } 1121 mock_dir.return_value = uc.CC_MODULE_DIR 1122 class_path = '%s' % uc.CC_PATH 1123 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1124 t_infos = self.mod_finder.find_test_by_path(class_path) 1125 unittest_utils.assert_equal_testinfos(self, uc.CC_PATH_INFO2, t_infos[0]) 1126 1127 # TODO: Move and rewite it to ModuleFinderFindTestByPath. 1128 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 1129 @mock.patch.object( 1130 module_finder.ModuleFinder, 1131 '_get_build_targets', 1132 return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS), 1133 ) 1134 @mock.patch.object( 1135 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1136 ) 1137 @mock.patch.object( 1138 test_finder_utils, 1139 'find_parent_module_dir', 1140 return_value=os.path.relpath(uc.TEST_DATA_DIR, uc.ROOT), 1141 ) 1142 # pylint: disable=unused-argument 1143 def test_find_test_by_path_part_2( 1144 self, _find_parent, _is_vts, _get_build, mods_to_test 1145 ): 1146 """Test find_test_by_path for directories.""" 1147 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 1148 self.mod_finder.module_info.is_robolectric_test.return_value = False 1149 self.mod_finder.module_info.has_test_config.return_value = True 1150 # Dir with java files in it, should run as package 1151 class_dir = os.path.join(uc.TEST_DATA_DIR, 'path_testing') 1152 mods_to_test.return_value = [uc.MODULE_NAME] 1153 self.mod_finder.module_info.get_module_info.return_value = { 1154 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1155 constants.MODULE_NAME: uc.MODULE_NAME, 1156 constants.MODULE_CLASS: [], 1157 constants.MODULE_COMPATIBILITY_SUITES: [], 1158 } 1159 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1160 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1161 {} 1162 ) 1163 t_infos = self.mod_finder.find_test_by_path(class_dir) 1164 unittest_utils.assert_equal_testinfos(self, uc.PATH_INFO, t_infos[0]) 1165 # Dir with no java files in it, should run whole module 1166 empty_dir = os.path.join(uc.TEST_DATA_DIR, 'path_testing_empty') 1167 t_infos = self.mod_finder.find_test_by_path(empty_dir) 1168 unittest_utils.assert_equal_testinfos(self, uc.EMPTY_PATH_INFO, t_infos[0]) 1169 # Dir with cc files in it, should run as cc class 1170 class_dir = os.path.join(uc.TEST_DATA_DIR, 'cc_path_testing') 1171 mods_to_test.return_value = [uc.CC_MODULE_NAME] 1172 self.mod_finder.module_info.get_module_info.return_value = { 1173 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1174 constants.MODULE_NAME: uc.CC_MODULE_NAME, 1175 constants.MODULE_CLASS: [], 1176 constants.MODULE_COMPATIBILITY_SUITES: [], 1177 } 1178 t_infos = self.mod_finder.find_test_by_path(class_dir) 1179 unittest_utils.assert_equal_testinfos(self, uc.CC_PATH_INFO, t_infos[0]) 1180 1181 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 1182 @mock.patch.object(module_finder.test_finder_utils, 'get_cc_class_info') 1183 @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[]) 1184 @mock.patch.object(atest_utils, 'is_build_file', return_value=True) 1185 @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True) 1186 @mock.patch.object( 1187 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1188 ) 1189 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1190 @mock.patch('subprocess.check_output', return_value=uc.CC_FIND_ONE) 1191 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 1192 @mock.patch('os.path.isdir', return_value=True) 1193 # pylint: disable=unused-argument 1194 def test_find_test_by_cc_class_name( 1195 self, 1196 _isdir, 1197 _isfile, 1198 mock_checkoutput, 1199 mock_build, 1200 _vts, 1201 _has_method, 1202 _is_build_file, 1203 _mock_unit_tests, 1204 _class_info, 1205 candicate_mods, 1206 ): 1207 """Test find_test_by_cc_class_name.""" 1208 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1209 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 1210 self.mod_finder.module_info.is_robolectric_test.return_value = False 1211 self.mod_finder.module_info.has_test_config.return_value = True 1212 candicate_mods.return_value = [uc.CC_MODULE_NAME] 1213 self.mod_finder.module_info.get_module_info.return_value = { 1214 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1215 constants.MODULE_NAME: uc.CC_MODULE_NAME, 1216 constants.MODULE_CLASS: [], 1217 constants.MODULE_COMPATIBILITY_SUITES: [], 1218 } 1219 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1220 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1221 {} 1222 ) 1223 _class_info.return_value = { 1224 'PFTest': { 1225 'methods': {'test1', 'test2'}, 1226 'prefixes': set(), 1227 'typed': False, 1228 } 1229 } 1230 t_infos = self.mod_finder.find_test_by_cc_class_name(uc.CC_CLASS_NAME) 1231 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_CLASS_INFO) 1232 1233 # with method 1234 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1235 class_with_method = '%s#%s' % (uc.CC_CLASS_NAME, uc.CC_METHOD_NAME) 1236 t_infos = self.mod_finder.find_test_by_cc_class_name(class_with_method) 1237 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD_INFO) 1238 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1239 class_methods = '%s,%s' % (class_with_method, uc.CC_METHOD2_NAME) 1240 t_infos = self.mod_finder.find_test_by_cc_class_name(class_methods) 1241 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD2_INFO) 1242 # module and rel_config passed in 1243 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1244 t_infos = self.mod_finder.find_test_by_cc_class_name( 1245 uc.CC_CLASS_NAME, uc.CC_MODULE_NAME, uc.CC_CONFIG_FILE 1246 ) 1247 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_CLASS_INFO) 1248 # find output fails to find class file 1249 mock_checkoutput.return_value = '' 1250 self.assertIsNone(self.mod_finder.find_test_by_cc_class_name('Not class')) 1251 # class is outside given module path 1252 mock_checkoutput.return_value = uc.CC_FIND_ONE 1253 t_infos = self.mod_finder.find_test_by_cc_class_name( 1254 uc.CC_CLASS_NAME, uc.CC_MODULE2_NAME, uc.CC_CONFIG2_FILE 1255 ) 1256 unittest_utils.assert_equal_testinfos( 1257 self, t_infos[0], CC_CLASS_INFO_MODULE_2 1258 ) 1259 1260 def test_get_testable_modules_with_ld(self): 1261 """Test get_testable_modules_with_ld""" 1262 self.mod_finder.module_info.get_testable_modules.return_value = [ 1263 uc.MODULE_NAME, 1264 uc.MODULE2_NAME, 1265 ] 1266 # Without a misfit constraint 1267 ld1 = self.mod_finder.get_testable_modules_with_ld(uc.TYPO_MODULE_NAME) 1268 self.assertEqual([[16, uc.MODULE2_NAME], [1, uc.MODULE_NAME]], ld1) 1269 # With a misfit constraint 1270 ld2 = self.mod_finder.get_testable_modules_with_ld(uc.TYPO_MODULE_NAME, 2) 1271 self.assertEqual([[1, uc.MODULE_NAME]], ld2) 1272 1273 def test_get_fuzzy_searching_modules(self): 1274 """Test get_fuzzy_searching_modules""" 1275 self.mod_finder.module_info.get_testable_modules.return_value = [ 1276 uc.MODULE_NAME, 1277 uc.MODULE2_NAME, 1278 ] 1279 result = self.mod_finder.get_fuzzy_searching_results(uc.TYPO_MODULE_NAME) 1280 self.assertEqual(uc.MODULE_NAME, result[0]) 1281 1282 def test_get_build_targets_w_vts_core(self): 1283 """Test _get_build_targets.""" 1284 self.mod_finder.module_info.is_auto_gen_test_config.return_value = True 1285 self.mod_finder.module_info.get_paths.return_value = [] 1286 mod_info = { 1287 constants.MODULE_COMPATIBILITY_SUITES: [constants.VTS_CORE_SUITE] 1288 } 1289 self.mod_finder.module_info.get_module_info.return_value = mod_info 1290 self.assertEqual( 1291 self.mod_finder._get_build_targets('', ''), 1292 {constants.VTS_CORE_TF_MODULE}, 1293 ) 1294 1295 def test_get_build_targets_w_mts(self): 1296 """Test _get_build_targets if module belong to mts.""" 1297 self.mod_finder.module_info.is_auto_gen_test_config.return_value = True 1298 self.mod_finder.module_info.get_paths.return_value = [] 1299 mod_info = {constants.MODULE_COMPATIBILITY_SUITES: [constants.MTS_SUITE]} 1300 self.mod_finder.module_info.get_module_info.return_value = mod_info 1301 self.assertEqual( 1302 self.mod_finder._get_build_targets('', ''), {constants.CTS_JAR} 1303 ) 1304 1305 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 1306 @mock.patch.object( 1307 test_filter_utils, 'is_parameterized_java_class', return_value=False 1308 ) 1309 @mock.patch.object( 1310 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1311 ) 1312 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1313 @mock.patch('subprocess.check_output', return_value='') 1314 @mock.patch.object( 1315 test_filter_utils, 1316 'get_fully_qualified_class_name', 1317 return_value=uc.FULL_CLASS_NAME, 1318 ) 1319 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 1320 @mock.patch('os.path.isdir', return_value=True) 1321 # pylint: disable=unused-argument 1322 def test_find_test_by_class_name_w_module( 1323 self, 1324 _isdir, 1325 _isfile, 1326 _fqcn, 1327 mock_checkoutput, 1328 mock_build, 1329 _vts, 1330 _is_parameterized, 1331 mods_to_test, 1332 ): 1333 """Test test_find_test_by_class_name with module but without class found.""" 1334 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1335 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 1336 self.mod_finder.module_info.is_robolectric_test.return_value = False 1337 self.mod_finder.module_info.has_test_config.return_value = True 1338 mods_to_test.return_value = [uc.MODULE_NAME] 1339 self.mod_finder.module_info.get_module_info.return_value = { 1340 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1341 constants.MODULE_NAME: uc.MODULE_NAME, 1342 constants.MODULE_CLASS: [], 1343 constants.MODULE_COMPATIBILITY_SUITES: [], 1344 } 1345 self.mod_finder.module_info.get_paths.return_value = [uc.TEST_DATA_CONFIG] 1346 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1347 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1348 {} 1349 ) 1350 t_infos = self.mod_finder.find_test_by_class_name( 1351 uc.FULL_CLASS_NAME, 1352 module_name=uc.MODULE_NAME, 1353 rel_config_path=uc.CONFIG_FILE, 1354 ) 1355 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO) 1356 1357 @mock.patch.object( 1358 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1359 ) 1360 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1361 @mock.patch('subprocess.check_output', return_value='') 1362 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 1363 @mock.patch('os.path.isdir', return_value=True) 1364 # pylint: disable=unused-argument 1365 def test_find_test_by_package_name_w_module( 1366 self, _isdir, _isfile, mock_checkoutput, mock_build, _vts 1367 ): 1368 """Test find_test_by_package_name with module but without package found.""" 1369 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 1370 self.mod_finder.module_info.is_robolectric_test.return_value = False 1371 self.mod_finder.module_info.has_test_config.return_value = True 1372 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1373 self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME] 1374 self.mod_finder.module_info.get_module_info.return_value = { 1375 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1376 constants.MODULE_NAME: uc.MODULE_NAME, 1377 constants.MODULE_CLASS: [], 1378 constants.MODULE_COMPATIBILITY_SUITES: [], 1379 } 1380 self.mod_finder.module_info.get_paths.return_value = [uc.TEST_DATA_CONFIG] 1381 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1382 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1383 {} 1384 ) 1385 t_infos = self.mod_finder.find_test_by_package_name( 1386 uc.PACKAGE, module_name=uc.MODULE_NAME, rel_config=uc.CONFIG_FILE 1387 ) 1388 unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO) 1389 1390 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 1391 @mock.patch.object(atest_utils, 'is_build_file', return_value=True) 1392 @mock.patch.object( 1393 test_filter_utils, 'is_parameterized_java_class', return_value=True 1394 ) 1395 @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True) 1396 @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True) 1397 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1398 @mock.patch.object( 1399 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1400 ) 1401 @mock.patch.object( 1402 test_filter_utils, 1403 'get_fully_qualified_class_name', 1404 return_value=uc.FULL_CLASS_NAME, 1405 ) 1406 @mock.patch( 1407 'os.path.realpath', side_effect=unittest_utils.realpath_side_effect 1408 ) 1409 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 1410 @mock.patch.object(test_finder_utils, 'find_parent_module_dir') 1411 @mock.patch('os.path.exists') 1412 # pylint: disable=unused-argument 1413 def test_find_test_by_path_is_parameterized_java( 1414 self, 1415 mock_pathexists, 1416 mock_dir, 1417 _isfile, 1418 _real, 1419 _fqcn, 1420 _vts, 1421 mock_build, 1422 _has_cc_class, 1423 _has_method_in_file, 1424 _is_parameterized, 1425 _is_build_file, 1426 mods_to_test, 1427 ): 1428 """Test find_test_by_path and input path is parameterized class.""" 1429 self.mod_finder.module_info.is_robolectric_test.return_value = False 1430 self.mod_finder.module_info.has_test_config.return_value = True 1431 mock_build.return_value = set() 1432 mock_pathexists.return_value = True 1433 mods_to_test.return_value = [uc.MODULE_NAME] 1434 self.mod_finder.module_info.get_module_info.return_value = { 1435 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1436 constants.MODULE_NAME: uc.MODULE_NAME, 1437 constants.MODULE_CLASS: [], 1438 constants.MODULE_COMPATIBILITY_SUITES: [], 1439 } 1440 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1441 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1442 {} 1443 ) 1444 # Happy path testing. 1445 mock_dir.return_value = uc.MODULE_DIR 1446 class_path = '%s.java' % uc.CLASS_NAME 1447 # Input include only one method 1448 class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME) 1449 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1450 t_infos = self.mod_finder.find_test_by_path(class_with_method) 1451 unittest_utils.assert_equal_testinfos( 1452 self, t_infos[0], uc.PARAMETERIZED_METHOD_INFO 1453 ) 1454 # Input include multiple methods 1455 class_with_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME) 1456 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1457 t_infos = self.mod_finder.find_test_by_path(class_with_methods) 1458 unittest_utils.assert_equal_testinfos( 1459 self, t_infos[0], uc.PARAMETERIZED_FLAT_METHOD_INFO 1460 ) 1461 1462 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 1463 @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[]) 1464 @mock.patch.object(atest_utils, 'is_build_file', return_value=True) 1465 @mock.patch.object( 1466 test_filter_utils, 'is_parameterized_java_class', return_value=True 1467 ) 1468 @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True) 1469 @mock.patch.object( 1470 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1471 ) 1472 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1473 @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE) 1474 @mock.patch.object( 1475 test_filter_utils, 1476 'get_fully_qualified_class_name', 1477 return_value=uc.FULL_CLASS_NAME, 1478 ) 1479 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 1480 @mock.patch('os.path.isdir', return_value=True) 1481 # pylint: disable=unused-argument 1482 def test_find_test_by_class_name_is_parameterized( 1483 self, 1484 _isdir, 1485 _isfile, 1486 _fqcn, 1487 mock_checkoutput, 1488 mock_build, 1489 _vts, 1490 _has_method_in_file, 1491 _is_parameterized, 1492 _is_build_file, 1493 _mock_unit_tests, 1494 mods_to_test, 1495 ): 1496 """Test find_test_by_class_name and the class is parameterized java.""" 1497 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1498 self.mod_finder.module_info.is_auto_gen_test_config.return_value = False 1499 self.mod_finder.module_info.is_robolectric_test.return_value = False 1500 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1501 {} 1502 ) 1503 self.mod_finder.module_info.has_test_config.return_value = True 1504 mods_to_test.return_value = [uc.MODULE_NAME] 1505 self.mod_finder.module_info.get_module_info.return_value = { 1506 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1507 constants.MODULE_NAME: uc.MODULE_NAME, 1508 constants.MODULE_CLASS: [], 1509 constants.MODULE_COMPATIBILITY_SUITES: [], 1510 } 1511 # With method 1512 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1513 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1514 class_with_method = '%s#%s' % (uc.CLASS_NAME, uc.METHOD_NAME) 1515 t_infos = self.mod_finder.find_test_by_class_name(class_with_method) 1516 unittest_utils.assert_equal_testinfos( 1517 self, t_infos[0], uc.PARAMETERIZED_METHOD_INFO 1518 ) 1519 # With multiple method 1520 mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS) 1521 class_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME) 1522 t_infos = self.mod_finder.find_test_by_class_name(class_methods) 1523 unittest_utils.assert_equal_testinfos( 1524 self, t_infos[0], uc.PARAMETERIZED_FLAT_METHOD_INFO 1525 ) 1526 1527 # pylint: disable=unused-argument 1528 @mock.patch.object( 1529 module_finder.ModuleFinder, 1530 '_get_build_targets', 1531 return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS), 1532 ) 1533 def test_find_test_by_config_name(self, _get_targ): 1534 """Test find_test_by_config_name.""" 1535 self.mod_finder.module_info.is_robolectric_test.return_value = False 1536 self.mod_finder.module_info.has_test_config.return_value = True 1537 1538 mod_info = { 1539 'installed': ['/path/to/install'], 1540 'path': [uc.MODULE_DIR], 1541 constants.MODULE_TEST_CONFIG: [uc.CONFIG_FILE, uc.EXTRA_CONFIG_FILE], 1542 constants.MODULE_CLASS: [], 1543 constants.MODULE_COMPATIBILITY_SUITES: [], 1544 } 1545 name_to_module_info = {uc.MODULE_NAME: mod_info} 1546 self.mod_finder.module_info.name_to_module_info = name_to_module_info 1547 t_infos = self.mod_finder.find_test_by_config_name(uc.MODULE_CONFIG_NAME) 1548 unittest_utils.assert_equal_testinfos( 1549 self, t_infos[0], uc.TEST_CONFIG_MODULE_INFO 1550 ) 1551 1552 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 1553 @mock.patch.object( 1554 test_filter_utils, 'is_parameterized_java_class', return_value=False 1555 ) 1556 @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True) 1557 @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True) 1558 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1559 @mock.patch.object( 1560 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1561 ) 1562 @mock.patch.object( 1563 test_filter_utils, 1564 'get_fully_qualified_class_name', 1565 return_value=uc.FULL_CLASS_NAME, 1566 ) 1567 @mock.patch( 1568 'os.path.realpath', side_effect=unittest_utils.realpath_side_effect 1569 ) 1570 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 1571 @mock.patch.object(test_finder_utils, 'find_parent_module_dir') 1572 @mock.patch('os.path.exists') 1573 # pylint: disable=unused-argument 1574 def test_find_test_by_path_w_src_verify( 1575 self, 1576 mock_pathexists, 1577 mock_dir, 1578 _isfile, 1579 _real, 1580 _fqcn, 1581 _vts, 1582 mock_build, 1583 _has_cc_class, 1584 _has_method_in_file, 1585 _is_parameterized, 1586 mods_to_test, 1587 ): 1588 """Test find_test_by_path with src information.""" 1589 self.mod_finder.module_info.is_robolectric_test.return_value = False 1590 self.mod_finder.module_info.has_test_config.return_value = True 1591 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1592 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1593 {} 1594 ) 1595 mods_to_test.return_value = [uc.MODULE_NAME] 1596 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1597 1598 # Happy path testing. 1599 mock_dir.return_value = uc.MODULE_DIR 1600 # Test path not in module's `srcs` but `path`. 1601 class_path = f'somewhere/to/module/{uc.CLASS_NAME}.java' 1602 self.mod_finder.module_info.get_module_info.return_value = { 1603 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1604 constants.MODULE_NAME: uc.MODULE_NAME, 1605 constants.MODULE_CLASS: [], 1606 constants.MODULE_PATH: ['somewhere/to/module'], 1607 constants.MODULE_TEST_CONFIG: [uc.CONFIG_FILE], 1608 constants.MODULE_COMPATIBILITY_SUITES: [], 1609 constants.MODULE_SRCS: [], 1610 } 1611 t_infos = self.mod_finder.find_test_by_path(class_path) 1612 unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0]) 1613 1614 # Test input file is in module's `srcs`. 1615 class_path = '%s.java' % uc.CLASS_NAME 1616 self.mod_finder.module_info.get_module_info.return_value = { 1617 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1618 constants.MODULE_NAME: uc.MODULE_NAME, 1619 constants.MODULE_CLASS: [], 1620 constants.MODULE_COMPATIBILITY_SUITES: [], 1621 constants.MODULE_SRCS: [class_path], 1622 } 1623 1624 t_infos = self.mod_finder.find_test_by_path(class_path) 1625 unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0]) 1626 1627 @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test') 1628 @mock.patch.object(test_finder_utils, 'get_cc_class_info') 1629 @mock.patch.object(atest_utils, 'is_build_file', return_value=True) 1630 @mock.patch.object( 1631 test_filter_utils, 'is_parameterized_java_class', return_value=False 1632 ) 1633 @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True) 1634 @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True) 1635 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1636 @mock.patch.object( 1637 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1638 ) 1639 @mock.patch.object( 1640 test_filter_utils, 1641 'get_fully_qualified_class_name', 1642 return_value=uc.FULL_CLASS_NAME, 1643 ) 1644 @mock.patch( 1645 'os.path.realpath', side_effect=unittest_utils.realpath_side_effect 1646 ) 1647 @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect) 1648 @mock.patch.object(test_finder_utils, 'find_parent_module_dir') 1649 @mock.patch('os.path.exists') 1650 # pylint: disable=unused-argument 1651 def test_find_test_by_path_for_cc_file( 1652 self, 1653 mock_pathexists, 1654 mock_dir, 1655 _isfile, 1656 _real, 1657 _fqcn, 1658 _vts, 1659 mock_build, 1660 _has_cc_class, 1661 _has_method_in_file, 1662 _is_parameterized, 1663 _is_build_file, 1664 _mock_cc_class_info, 1665 mods_to_test, 1666 ): 1667 """Test find_test_by_path for handling correct CC filter.""" 1668 self.mod_finder.module_info.is_robolectric_test.return_value = False 1669 self.mod_finder.module_info.has_test_config.return_value = True 1670 mock_build.return_value = set() 1671 # Check that we don't return anything with invalid test references. 1672 mock_pathexists.return_value = False 1673 mock_pathexists.return_value = True 1674 mock_dir.return_value = None 1675 mods_to_test.return_value = [uc.MODULE_NAME] 1676 self.mod_finder.module_info.get_module_info.return_value = { 1677 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1678 constants.MODULE_NAME: uc.MODULE_NAME, 1679 constants.MODULE_CLASS: [], 1680 constants.MODULE_COMPATIBILITY_SUITES: [], 1681 } 1682 # Happy path testing. 1683 mock_dir.return_value = uc.MODULE_DIR 1684 # Cc path testing if get_cc_class_info found those information. 1685 mods_to_test.return_value = [uc.CC_MODULE_NAME] 1686 self.mod_finder.module_info.get_module_info.return_value = { 1687 constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH, 1688 constants.MODULE_NAME: uc.CC_MODULE_NAME, 1689 constants.MODULE_CLASS: [], 1690 constants.MODULE_COMPATIBILITY_SUITES: [], 1691 } 1692 mock_dir.return_value = uc.CC_MODULE_DIR 1693 class_path = '%s' % uc.CC_PATH 1694 mock_build.return_value = uc.CLASS_BUILD_TARGETS 1695 # Test without parameterized test 1696 founded_classed = 'class1' 1697 founded_methods = {'method1'} 1698 founded_prefixes = set() 1699 _mock_cc_class_info.return_value = { 1700 founded_classed: { 1701 'methods': founded_methods, 1702 'prefixes': founded_prefixes, 1703 'typed': False, 1704 } 1705 } 1706 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1707 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1708 {} 1709 ) 1710 cc_path_data = { 1711 constants.TI_REL_CONFIG: uc.CC_CONFIG_FILE, 1712 constants.TI_FILTER: frozenset( 1713 {test_info.TestFilter(class_name='class1.*', methods=frozenset())} 1714 ), 1715 } 1716 cc_path_info = test_info.TestInfo( 1717 uc.CC_MODULE_NAME, 1718 atf_tr.AtestTradefedTestRunner.NAME, 1719 uc.CLASS_BUILD_TARGETS, 1720 cc_path_data, 1721 ) 1722 t_infos = self.mod_finder.find_test_by_path(class_path) 1723 unittest_utils.assert_equal_testinfos(self, cc_path_info, t_infos[0]) 1724 # Test with parameterize test defined in input path 1725 founded_prefixes = {'class1'} 1726 _mock_cc_class_info.return_value = { 1727 founded_classed: { 1728 'methods': founded_methods, 1729 'prefixes': founded_prefixes, 1730 'typed': False, 1731 } 1732 } 1733 cc_path_data = { 1734 constants.TI_REL_CONFIG: uc.CC_CONFIG_FILE, 1735 constants.TI_FILTER: frozenset( 1736 {test_info.TestFilter(class_name='*/class1.*', methods=frozenset())} 1737 ), 1738 } 1739 cc_path_info = test_info.TestInfo( 1740 uc.CC_MODULE_NAME, 1741 atf_tr.AtestTradefedTestRunner.NAME, 1742 uc.CLASS_BUILD_TARGETS, 1743 cc_path_data, 1744 ) 1745 t_infos = self.mod_finder.find_test_by_path(class_path) 1746 unittest_utils.assert_equal_testinfos(self, cc_path_info, t_infos[0]) 1747 1748 # pylint: disable=unused-argument 1749 @mock.patch.object( 1750 module_finder.ModuleFinder, '_is_vts_module', return_value=False 1751 ) 1752 @mock.patch.object( 1753 module_finder.ModuleFinder, 1754 '_get_build_targets', 1755 return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS), 1756 ) 1757 def test_process_test_info(self, _get_targ, _is_vts): 1758 """Test _process_test_info.""" 1759 mod_info = { 1760 'installed': ['/path/to/install'], 1761 'path': [uc.MODULE_DIR], 1762 constants.MODULE_CLASS: [constants.MODULE_CLASS_JAVA_LIBRARIES], 1763 constants.MODULE_COMPATIBILITY_SUITES: [], 1764 } 1765 self.mod_finder.module_info.is_robolectric_test.return_value = False 1766 self.mod_finder.module_info.is_auto_gen_test_config.return_value = True 1767 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1768 self.mod_finder.module_info.get_instrumentation_target_apps.return_value = ( 1769 {} 1770 ) 1771 self.mod_finder.module_info.get_module_info.return_value = mod_info 1772 processed_info = self.mod_finder._process_test_info( 1773 copy.deepcopy(uc.MODULE_INFO) 1774 ) 1775 unittest_utils.assert_equal_testinfos( 1776 self, processed_info, uc.MODULE_INFO_W_DALVIK 1777 ) 1778 1779 # pylint: disable=unused-argument 1780 @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets') 1781 @mock.patch.object(module_info.ModuleInfo, 'get_instrumentation_target_apps') 1782 @mock.patch.object(module_info.ModuleInfo, 'get_robolectric_type') 1783 @mock.patch.object(module_info.ModuleInfo, 'is_testable_module') 1784 def test_process_test_info_with_instrumentation_target_apps( 1785 self, testable, robotype, tapps, btargets 1786 ): 1787 """Test _process_test_info.""" 1788 testable.return_value = True 1789 robotype.return_value = 0 1790 target_module = 'AmSlam' 1791 test_module = 'AmSlamTests' 1792 artifact_path = '/out/somewhere/app/AmSlam.apk' 1793 tapps.return_value = {target_module: {artifact_path}} 1794 btargets.return_value = {target_module} 1795 self.mod_finder.module_info.is_auto_gen_test_config.return_value = True 1796 self.mod_finder.module_info.get_robolectric_type.return_value = 0 1797 test1 = module( 1798 name=target_module, 1799 classes=['APPS'], 1800 path=['foo/bar/AmSlam'], 1801 installed=[artifact_path], 1802 ) 1803 test2 = module( 1804 name=test_module, 1805 classes=['APPS'], 1806 path=['foo/bar/AmSlam/test'], 1807 installed=['/out/somewhere/app/AmSlamTests.apk'], 1808 ) 1809 info = test_info.TestInfo( 1810 test_module, 1811 atf_tr.AtestTradefedTestRunner.NAME, 1812 set(), 1813 { 1814 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 1815 constants.TI_FILTER: frozenset(), 1816 }, 1817 ) 1818 1819 self.mod_finder.module_info = create_module_info([test1, test2]) 1820 t_infos = self.mod_finder._process_test_info(info) 1821 1822 self.assertTrue(target_module in t_infos.build_targets) 1823 self.assertEqual([artifact_path], t_infos.artifacts) 1824 1825 @mock.patch.object(test_finder_utils, 'get_annotated_methods') 1826 def test_is_srcs_match_method_annotation_include_anno( 1827 self, _mock_get_anno_methods 1828 ): 1829 """Test _is_srcs_match_method_annotation with include annotation.""" 1830 annotation_dict = {constants.INCLUDE_ANNOTATION: 'includeAnnotation1'} 1831 input_method = 'my_input_method' 1832 input_srcs = ['src1'] 1833 # Test if input method matched include annotation. 1834 _mock_get_anno_methods.return_value = {input_method, 'not_my_input_method'} 1835 1836 is_matched = self.mod_finder._is_srcs_match_method_annotation( 1837 input_method, input_srcs, annotation_dict 1838 ) 1839 1840 self.assertTrue(is_matched) 1841 # Test if input method not matched include annotation. 1842 _mock_get_anno_methods.return_value = {'not_my_input_method'} 1843 1844 is_matched = self.mod_finder._is_srcs_match_method_annotation( 1845 input_method, input_srcs, annotation_dict 1846 ) 1847 1848 self.assertFalse(is_matched) 1849 1850 @mock.patch.object(test_finder_utils, 'get_annotated_methods') 1851 @mock.patch.object(test_finder_utils, 'get_java_methods') 1852 def test_is_srcs_match_method_exclude_anno( 1853 self, _mock_get_java_methods, _mock_get_exclude_anno_methods 1854 ): 1855 """Test _is_srcs_match_method_annotation with exclude annotation.""" 1856 annotation_dict = {constants.EXCLUDE_ANNOTATION: 'excludeAnnotation1'} 1857 input_method = 'my_input_method' 1858 input_srcs = ['src1'] 1859 _mock_get_java_methods.return_value = {input_method, 'method1', 'method2'} 1860 # Test if input method matched exclude annotation. 1861 _mock_get_exclude_anno_methods.return_value = {input_method, 'method1'} 1862 1863 is_matched = self.mod_finder._is_srcs_match_method_annotation( 1864 input_method, input_srcs, annotation_dict 1865 ) 1866 1867 self.assertFalse(is_matched) 1868 1869 # Test if input method not matched exclude annotation. 1870 _mock_get_exclude_anno_methods.return_value = {'method2'} 1871 1872 is_matched = self.mod_finder._is_srcs_match_method_annotation( 1873 input_method, input_srcs, annotation_dict 1874 ) 1875 1876 self.assertTrue(is_matched) 1877 1878 @mock.patch.object(atest_utils, 'get_android_junit_config_filters') 1879 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 1880 def test_get_matched_test_infos_no_filter( 1881 self, _mock_get_conf_srcs, _mock_get_filters 1882 ): 1883 """Test _get_matched_test_infos without test filters.""" 1884 test_info1 = 'test_info1' 1885 test_infos = [test_info1] 1886 test_config = 'test_config' 1887 test_srcs = ['src1', 'src2'] 1888 _mock_get_conf_srcs.return_value = test_config, test_srcs 1889 filter_dict = {} 1890 _mock_get_filters.return_value = filter_dict 1891 1892 self.assertEqual( 1893 self.mod_finder._get_matched_test_infos(test_infos, {'method'}), 1894 test_infos, 1895 ) 1896 1897 @mock.patch.object( 1898 module_finder.ModuleFinder, '_is_srcs_match_method_annotation' 1899 ) 1900 @mock.patch.object(atest_utils, 'get_android_junit_config_filters') 1901 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 1902 def test_get_matched_test_infos_get_filter_method_match( 1903 self, _mock_get_conf_srcs, _mock_get_filters, _mock_method_match 1904 ): 1905 """Test _get_matched_test_infos with test filters and method match.""" 1906 test_infos = [KERNEL_MODULE_CLASS_INFO] 1907 test_config = 'test_config' 1908 test_srcs = ['src1', 'src2'] 1909 _mock_get_conf_srcs.return_value = test_config, test_srcs 1910 filter_dict = {'include-annotation': 'annotate1'} 1911 _mock_get_filters.return_value = filter_dict 1912 _mock_method_match.return_value = True 1913 1914 unittest_utils.assert_strict_equal( 1915 self, 1916 self.mod_finder._get_matched_test_infos(test_infos, {'method'}), 1917 test_infos, 1918 ) 1919 1920 @mock.patch.object( 1921 module_finder.ModuleFinder, '_is_srcs_match_method_annotation' 1922 ) 1923 @mock.patch.object(atest_utils, 'get_android_junit_config_filters') 1924 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 1925 def test_get_matched_test_infos_filter_method_not_match( 1926 self, _mock_get_conf_srcs, _mock_get_filters, _mock_method_match 1927 ): 1928 """Test _get_matched_test_infos but method not match.""" 1929 test_infos = [KERNEL_MODULE_CLASS_INFO] 1930 test_config = 'test_config' 1931 test_srcs = ['src1', 'src2'] 1932 _mock_get_conf_srcs.return_value = test_config, test_srcs 1933 filter_dict = {'include-annotation': 'annotate1'} 1934 _mock_get_filters.return_value = filter_dict 1935 _mock_method_match.return_value = False 1936 1937 self.assertEqual( 1938 self.mod_finder._get_matched_test_infos(test_infos, {'method'}), [] 1939 ) 1940 1941 @mock.patch.object(module_finder.ModuleFinder, '_get_matched_test_infos') 1942 @mock.patch.object( 1943 module_finder.ModuleFinder, '_get_test_infos', return_value=uc.MODULE_INFO 1944 ) 1945 @mock.patch.object( 1946 module_finder.ModuleFinder, 1947 '_get_test_info_filter', 1948 return_value=uc.CLASS_FILTER, 1949 ) 1950 @mock.patch.object( 1951 test_finder_utils, 'find_class_file', return_value=['path1'] 1952 ) 1953 def test_find_test_by_class_name_not_matched_filters( 1954 self, 1955 _mock_class_path, 1956 _mock_test_filters, 1957 _mock_test_infos, 1958 _mock_matched_test_infos, 1959 ): 1960 """Test find_test_by_class_name which has not matched filters.""" 1961 found_test_infos = [uc.MODULE_INFO, uc.MODULE_INFO2] 1962 _mock_test_infos.return_value = found_test_infos 1963 matched_test_infos = [uc.MODULE_INFO2] 1964 _mock_matched_test_infos.return_value = matched_test_infos 1965 1966 # Test if class without method 1967 test_infos = self.mod_finder.find_test_by_class_name('my.test.class') 1968 self.assertEqual(len(test_infos), 2) 1969 unittest_utils.assert_equal_testinfos(self, test_infos[0], uc.MODULE_INFO) 1970 unittest_utils.assert_equal_testinfos(self, test_infos[1], uc.MODULE_INFO2) 1971 1972 # Test if class with method 1973 test_infos = self.mod_finder.find_test_by_class_name( 1974 'my.test.class#myMethod' 1975 ) 1976 self.assertEqual(len(test_infos), 1) 1977 unittest_utils.assert_equal_testinfos(self, test_infos[0], uc.MODULE_INFO2) 1978 1979 @mock.patch.object( 1980 module_finder.ModuleFinder, '_get_test_infos', return_value=None 1981 ) 1982 @mock.patch.object( 1983 module_finder.ModuleFinder, 1984 '_get_test_info_filter', 1985 return_value=uc.CLASS_FILTER, 1986 ) 1987 @mock.patch.object( 1988 test_finder_utils, 'find_class_file', return_value=['path1'] 1989 ) 1990 def test_find_test_by_class_name_get_test_infos_none( 1991 self, _mock_class_path, _mock_test_filters, _mock_test_infos 1992 ): 1993 """Test find_test_by_class_name which has not matched test infos.""" 1994 self.assertEqual( 1995 self.mod_finder.find_test_by_class_name('my.test.class'), None 1996 ) 1997 1998 1999def create_empty_module_info(): 2000 with fake_filesystem_unittest.Patcher() as patcher: 2001 # pylint: disable=protected-access 2002 fake_temp_file_name = next(tempfile._get_candidate_names()) 2003 patcher.fs.create_file(fake_temp_file_name, contents='{}') 2004 return module_info.load_from_file(module_file=fake_temp_file_name) 2005 2006 2007def create_module_info(modules=None): 2008 name_to_module_info = {} 2009 modules = modules or [] 2010 2011 for m in modules: 2012 name_to_module_info[m['module_name']] = m 2013 2014 return module_info.load_from_dict(name_to_module_info) 2015 2016 2017# pylint: disable=too-many-arguments 2018def module( 2019 name=None, 2020 path=None, 2021 installed=None, 2022 classes=None, 2023 auto_test_config=None, 2024 shared_libs=None, 2025 dependencies=None, 2026 runtime_dependencies=None, 2027 data=None, 2028 data_dependencies=None, 2029 compatibility_suites=None, 2030 host_dependencies=None, 2031 srcs=None, 2032): 2033 name = name or 'libhello' 2034 2035 m = {} 2036 2037 m['module_name'] = name 2038 m['class'] = classes 2039 m['path'] = path or [''] 2040 m['installed'] = installed or [] 2041 m['is_unit_test'] = 'false' 2042 m['auto_test_config'] = auto_test_config or [] 2043 m['shared_libs'] = shared_libs or [] 2044 m['runtime_dependencies'] = runtime_dependencies or [] 2045 m['dependencies'] = dependencies or [] 2046 m['data'] = data or [] 2047 m['data_dependencies'] = data_dependencies or [] 2048 m['compatibility_suites'] = compatibility_suites or [] 2049 m['host_dependencies'] = host_dependencies or [] 2050 m['srcs'] = srcs or [] 2051 return m 2052 2053 2054# pylint: disable=too-many-locals 2055def create_test_info(**kwargs): 2056 test_name = kwargs.pop('test_name') 2057 test_runner = kwargs.pop('test_runner') 2058 build_targets = kwargs.pop('build_targets') 2059 data = kwargs.pop('data', None) 2060 suite = kwargs.pop('suite', None) 2061 module_class = kwargs.pop('module_class', None) 2062 install_locations = kwargs.pop('install_locations', None) 2063 test_finder = kwargs.pop('test_finder', '') 2064 compatibility_suites = kwargs.pop('compatibility_suites', None) 2065 2066 t_info = test_info.TestInfo( 2067 test_name=test_name, 2068 test_runner=test_runner, 2069 build_targets=build_targets, 2070 data=data, 2071 suite=suite, 2072 module_class=module_class, 2073 install_locations=install_locations, 2074 test_finder=test_finder, 2075 compatibility_suites=compatibility_suites, 2076 ) 2077 raw_test_name = kwargs.pop('raw_test_name', None) 2078 if raw_test_name: 2079 t_info.raw_test_name = raw_test_name 2080 artifacts = kwargs.pop('artifacts', set()) 2081 if artifacts: 2082 t_info.artifacts = artifacts 2083 robo_type = kwargs.pop('robo_type', None) 2084 if robo_type: 2085 t_info.robo_type = robo_type 2086 mainline_modules = kwargs.pop('mainline_modules', set()) 2087 if mainline_modules: 2088 t_info._mainline_modules = mainline_modules 2089 for keyword in ['from_test_mapping', 'host', 'aggregate_metrics_result']: 2090 value = kwargs.pop(keyword, 'None') 2091 if isinstance(value, bool): 2092 setattr(t_info, keyword, value) 2093 if kwargs: 2094 assert f'Unknown keyword(s) for test_info: {kwargs.keys()}' 2095 return t_info 2096 2097 2098if __name__ == '__main__': 2099 unittest.main() 2100