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 cli_translator.""" 18 19from importlib import reload 20from io import StringIO 21import json 22import os 23import re 24import sys 25import tempfile 26import unittest 27from unittest import mock 28from atest import arg_parser 29from atest import atest_utils 30from atest import cli_translator as cli_t 31from atest import constants 32from atest import module_info 33from atest import test_finder_handler 34from atest import test_mapping 35from atest import unittest_constants as uc 36from atest import unittest_utils 37from atest.metrics import metrics 38from atest.test_finders import module_finder 39from atest.test_finders import test_finder_base 40from atest.test_finders import test_finder_utils 41from pyfakefs import fake_filesystem_unittest 42 43 44# TEST_MAPPING related consts 45TEST_MAPPING_TOP_DIR = os.path.join(uc.TEST_DATA_DIR, 'test_mapping') 46TEST_MAPPING_DIR = os.path.join(TEST_MAPPING_TOP_DIR, 'folder1') 47TEST_1 = test_mapping.TestDetail({'name': 'test1', 'host': True}) 48TEST_2 = test_mapping.TestDetail({'name': 'test2'}) 49TEST_3 = test_mapping.TestDetail({'name': 'test3'}) 50TEST_4 = test_mapping.TestDetail({'name': 'test4'}) 51TEST_5 = test_mapping.TestDetail({'name': 'test5'}) 52TEST_6 = test_mapping.TestDetail({'name': 'test6'}) 53TEST_7 = test_mapping.TestDetail({'name': 'test7'}) 54TEST_8 = test_mapping.TestDetail({'name': 'test8'}) 55TEST_9 = test_mapping.TestDetail({'name': 'test9'}) 56TEST_10 = test_mapping.TestDetail({'name': 'test10'}) 57 58SEARCH_DIR_RE = re.compile(r'^find ([^ ]*).*$') 59BUILD_TOP_DIR = tempfile.TemporaryDirectory().name 60PRODUCT_OUT_DIR = os.path.join(BUILD_TOP_DIR, 'out/target/product/vsoc_x86_64') 61HOST_OUT_DIR = os.path.join(BUILD_TOP_DIR, 'out/host/linux-x86') 62 63 64# pylint: disable=unused-argument 65def gettestinfos_side_effect( 66 test_names, test_mapping_test_details=None, is_rebuild_module_info=False 67): 68 """Mock return values for _get_test_info.""" 69 test_infos = [] 70 for test_name in test_names: 71 if test_name == uc.MODULE_NAME: 72 test_infos.append(uc.MODULE_INFO) 73 if test_name == uc.CLASS_NAME: 74 test_infos.append(uc.CLASS_INFO) 75 if test_name == uc.HOST_UNIT_TEST_NAME_1: 76 test_infos.append(uc.MODULE_INFO_HOST_1) 77 if test_name == uc.HOST_UNIT_TEST_NAME_2: 78 test_infos.append(uc.MODULE_INFO_HOST_2) 79 return test_infos 80 81 82# pylint: disable=protected-access 83class CLITranslatorUnittests(unittest.TestCase): 84 """Unit tests for cli_t.py""" 85 86 def setUp(self): 87 """Run before execution of every test""" 88 self.ctr = cli_t.CLITranslator() 89 90 # Create a mock of args. 91 self.args = arg_parser.create_atest_arg_parser().parse_args() 92 self.args.tests = [] 93 # Test mapping related args 94 self.args.test_mapping = False 95 self.args.include_subdirs = False 96 self.args.enable_file_patterns = False 97 self.args.rebuild_module_info = False 98 # Cache finder related args 99 self.args.clear_cache = False 100 self.ctr.mod_info = mock.Mock 101 self.ctr.mod_info.name_to_module_info = {} 102 103 def tearDown(self): 104 """Run after execution of every test""" 105 reload(uc) 106 107 @mock.patch.object(atest_utils, 'update_test_info_cache') 108 @mock.patch('builtins.input', return_value='n') 109 @mock.patch.object(module_finder.ModuleFinder, 'find_test_by_module_name') 110 @mock.patch.object(module_finder.ModuleFinder, 'get_fuzzy_searching_results') 111 @mock.patch.object(metrics, 'FindTestFinishEvent') 112 @mock.patch.object(test_finder_handler, 'get_find_methods_for_test') 113 # pylint: disable=too-many-locals 114 def test_get_test_infos( 115 self, 116 mock_getfindmethods, 117 _metrics, 118 mock_getfuzzyresults, 119 mock_findtestbymodule, 120 mock_input, 121 _mock_update_test_info, 122 ): 123 """Test _get_test_infos method.""" 124 ctr = cli_t.CLITranslator() 125 find_method_return_module_info = lambda x, y: uc.MODULE_INFOS 126 # pylint: disable=invalid-name 127 find_method_return_module_class_info = ( 128 lambda x, test: uc.MODULE_INFOS 129 if test == uc.MODULE_NAME 130 else uc.CLASS_INFOS 131 ) 132 find_method_return_nothing = lambda x, y: None 133 one_test = [uc.MODULE_NAME] 134 mult_test = [uc.MODULE_NAME, uc.CLASS_NAME] 135 136 # Let's make sure we return what we expect. 137 expected_test_infos = [uc.MODULE_INFO] 138 mock_getfindmethods.return_value = [ 139 test_finder_base.Finder(None, find_method_return_module_info, None) 140 ] 141 unittest_utils.assert_equal_testinfo_lists( 142 self, ctr._get_test_infos(one_test), expected_test_infos 143 ) 144 145 # Check we receive multiple test infos. 146 expected_test_infos = [uc.MODULE_INFO, uc.CLASS_INFO] 147 mock_getfindmethods.return_value = [ 148 test_finder_base.Finder( 149 None, find_method_return_module_class_info, None 150 ) 151 ] 152 unittest_utils.assert_equal_testinfo_lists( 153 self, ctr._get_test_infos(mult_test), expected_test_infos 154 ) 155 156 # Check return null set when we have no tests found or multiple results. 157 mock_getfindmethods.return_value = [ 158 test_finder_base.Finder(None, find_method_return_nothing, None) 159 ] 160 null_test_info = [] 161 mock_getfuzzyresults.return_value = [] 162 self.assertEqual(null_test_info, ctr._get_test_infos(one_test)) 163 self.assertEqual(null_test_info, ctr._get_test_infos(mult_test)) 164 165 # Check returning test_info when the user says Yes. 166 mock_input.return_value = 'Y' 167 mock_getfindmethods.return_value = [ 168 test_finder_base.Finder(None, find_method_return_module_info, None) 169 ] 170 mock_getfuzzyresults.return_value = one_test 171 mock_findtestbymodule.return_value = uc.MODULE_INFO 172 unittest_utils.assert_equal_testinfo_lists( 173 self, ctr._get_test_infos([uc.TYPO_MODULE_NAME]), [uc.MODULE_INFO] 174 ) 175 176 # Check the method works for test mapping. 177 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 178 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 179 expected_test_infos = [uc.MODULE_INFO, uc.CLASS_INFO] 180 mock_getfindmethods.return_value = [ 181 test_finder_base.Finder( 182 None, find_method_return_module_class_info, None 183 ) 184 ] 185 test_infos = ctr._get_test_infos(mult_test, [test_detail1, test_detail2]) 186 unittest_utils.assert_equal_testinfo_lists( 187 self, test_infos, expected_test_infos 188 ) 189 for test_info in test_infos: 190 if test_info == uc.MODULE_INFO: 191 self.assertEqual( 192 test_detail1.options, test_info.data[constants.TI_MODULE_ARG] 193 ) 194 else: 195 self.assertEqual( 196 test_detail2.options, test_info.data[constants.TI_MODULE_ARG] 197 ) 198 199 @mock.patch.object(atest_utils, 'update_test_info_cache') 200 @mock.patch.object(metrics, 'FindTestFinishEvent') 201 @mock.patch.object(test_finder_handler, 'get_find_methods_for_test') 202 def test_get_test_infos_2( 203 self, mock_getfindmethods, _metrics, _mock_update_test_info 204 ): 205 """Test _get_test_infos method.""" 206 ctr = cli_t.CLITranslator() 207 find_method_return_module_info2 = lambda x, y: uc.MODULE_INFOS2 208 find_method_ret_mod_cls_info2 = ( 209 lambda x, test: uc.MODULE_INFOS2 210 if test == uc.MODULE_NAME 211 else uc.CLASS_INFOS2 212 ) 213 one_test = [uc.MODULE_NAME] 214 mult_test = [uc.MODULE_NAME, uc.CLASS_NAME] 215 # Let's make sure we return what we expect. 216 expected_test_infos = [uc.MODULE_INFO, uc.MODULE_INFO2] 217 mock_getfindmethods.return_value = [ 218 test_finder_base.Finder(None, find_method_return_module_info2, None) 219 ] 220 unittest_utils.assert_equal_testinfo_lists( 221 self, ctr._get_test_infos(one_test), expected_test_infos 222 ) 223 # Check we receive multiple test infos. 224 expected_test_infos = [ 225 uc.MODULE_INFO, 226 uc.MODULE_INFO2, 227 uc.CLASS_INFO, 228 uc.CLASS_INFO2, 229 ] 230 mock_getfindmethods.return_value = [ 231 test_finder_base.Finder(None, find_method_ret_mod_cls_info2, None) 232 ] 233 unittest_utils.assert_equal_testinfo_lists( 234 self, ctr._get_test_infos(mult_test), expected_test_infos 235 ) 236 # Check the method works for test mapping. 237 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 238 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 239 expected_test_infos = [ 240 uc.MODULE_INFO, 241 uc.MODULE_INFO2, 242 uc.CLASS_INFO, 243 uc.CLASS_INFO2, 244 ] 245 mock_getfindmethods.return_value = [ 246 test_finder_base.Finder(None, find_method_ret_mod_cls_info2, None) 247 ] 248 test_infos = ctr._get_test_infos(mult_test, [test_detail1, test_detail2]) 249 unittest_utils.assert_equal_testinfo_lists( 250 self, test_infos, expected_test_infos 251 ) 252 for test_info in test_infos: 253 if test_info in [uc.MODULE_INFO, uc.MODULE_INFO2]: 254 self.assertEqual( 255 test_detail1.options, test_info.data[constants.TI_MODULE_ARG] 256 ) 257 elif test_info in [uc.CLASS_INFO, uc.CLASS_INFO2]: 258 self.assertEqual( 259 test_detail2.options, test_info.data[constants.TI_MODULE_ARG] 260 ) 261 262 @mock.patch.object(module_finder.ModuleFinder, 'get_fuzzy_searching_results') 263 @mock.patch.object(metrics, 'FindTestFinishEvent') 264 @mock.patch.object(test_finder_handler, 'get_find_methods_for_test') 265 def test_get_test_infos_with_mod_info( 266 self, 267 mock_getfindmethods, 268 _metrics, 269 mock_getfuzzyresults, 270 ): 271 """Test _get_test_infos method.""" 272 mod_info = module_info.load_from_file( 273 module_file=os.path.join(uc.TEST_DATA_DIR, uc.JSON_FILE) 274 ) 275 ctr = cli_t.CLITranslator(mod_info=mod_info) 276 null_test_info = [] 277 mock_getfindmethods.return_value = [] 278 mock_getfuzzyresults.return_value = [] 279 unittest_utils.assert_equal_testinfo_lists( 280 self, ctr._get_test_infos('not_exist_module'), null_test_info 281 ) 282 283 @mock.patch.object( 284 test_finder_utils, 'find_host_unit_tests', return_value=set() 285 ) 286 @mock.patch.object( 287 cli_t.CLITranslator, 288 '_get_test_infos', 289 side_effect=gettestinfos_side_effect, 290 ) 291 def test_translate_class(self, _info, _find): 292 """Test translate method for tests by class name.""" 293 # Check that we can find a class. 294 self.args.tests = [uc.CLASS_NAME] 295 self.args.host_unit_test_only = False 296 test_infos = self.ctr.translate(self.args) 297 unittest_utils.assert_strict_equal( 298 self, _gather_build_targets(test_infos), uc.CLASS_BUILD_TARGETS 299 ) 300 unittest_utils.assert_equal_testinfo_lists( 301 self, test_infos, [uc.CLASS_INFO] 302 ) 303 304 @mock.patch.object( 305 test_finder_utils, 'find_host_unit_tests', return_value=set() 306 ) 307 @mock.patch.object( 308 cli_t.CLITranslator, 309 '_get_test_infos', 310 side_effect=gettestinfos_side_effect, 311 ) 312 def test_translate_module(self, _info, _find): 313 """Test translate method for tests by module or class name.""" 314 # Check that we get all the build targets we expect. 315 self.args.tests = [uc.MODULE_NAME, uc.CLASS_NAME] 316 self.args.host_unit_test_only = False 317 test_infos = self.ctr.translate(self.args) 318 unittest_utils.assert_strict_equal( 319 self, 320 _gather_build_targets(test_infos), 321 uc.MODULE_CLASS_COMBINED_BUILD_TARGETS, 322 ) 323 unittest_utils.assert_equal_testinfo_lists( 324 self, test_infos, [uc.MODULE_INFO, uc.CLASS_INFO] 325 ) 326 327 @mock.patch.object(os, 'getcwd', return_value='/src/build_top/somewhere') 328 @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[]) 329 @mock.patch.object(cli_t.CLITranslator, '_find_tests_by_test_mapping') 330 @mock.patch.object( 331 cli_t.CLITranslator, 332 '_get_test_infos', 333 side_effect=gettestinfos_side_effect, 334 ) 335 def test_translate_test_mapping( 336 self, _info, mock_testmapping, _find_unit_tests, _getcwd 337 ): 338 """Test translate method for tests in test mapping.""" 339 # Check that test mappings feeds into get_test_info properly. 340 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 341 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 342 mock_testmapping.return_value = ([test_detail1, test_detail2], None) 343 self.args.tests = [] 344 self.args.host = False 345 self.args.host_unit_test_only = False 346 test_infos = self.ctr.translate(self.args) 347 unittest_utils.assert_strict_equal( 348 self, 349 _gather_build_targets(test_infos), 350 uc.MODULE_CLASS_COMBINED_BUILD_TARGETS, 351 ) 352 unittest_utils.assert_equal_testinfo_lists( 353 self, test_infos, [uc.MODULE_INFO, uc.CLASS_INFO] 354 ) 355 356 @mock.patch.object(cli_t.CLITranslator, '_find_tests_by_test_mapping') 357 @mock.patch.object( 358 cli_t.CLITranslator, 359 '_get_test_infos', 360 side_effect=gettestinfos_side_effect, 361 ) 362 def test_translate_test_mapping_all(self, _info, mock_testmapping): 363 """Test translate method for tests in test mapping.""" 364 # Check that test mappings feeds into get_test_info properly. 365 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 366 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 367 mock_testmapping.return_value = ([test_detail1, test_detail2], None) 368 self.args.tests = ['src_path:all'] 369 self.args.test_mapping = True 370 self.args.host = False 371 test_infos = self.ctr.translate(self.args) 372 unittest_utils.assert_strict_equal( 373 self, 374 _gather_build_targets(test_infos), 375 uc.MODULE_CLASS_COMBINED_BUILD_TARGETS, 376 ) 377 unittest_utils.assert_equal_testinfo_lists( 378 self, test_infos, [uc.MODULE_INFO, uc.CLASS_INFO] 379 ) 380 381 def test_find_tests_by_test_mapping_presubmit(self): 382 """Test _find_tests_by_test_mapping method to locate presubmit tests.""" 383 # TODO: (b/264015241) Stop mocking build variables. 384 os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR} 385 with mock.patch.dict('os.environ', os_environ_mock, clear=True): 386 tests, all_tests = self.ctr._find_tests_by_test_mapping( 387 path=TEST_MAPPING_DIR, 388 file_name='test_mapping_sample', 389 checked_files=set(), 390 ) 391 expected = set([TEST_1, TEST_2, TEST_5, TEST_7, TEST_9]) 392 expected_all_tests = { 393 'presubmit': expected, 394 'postsubmit': set([TEST_3, TEST_6, TEST_8, TEST_10]), 395 'other_group': set([TEST_4]), 396 } 397 self.assertEqual(expected, tests) 398 self.assertEqual(expected_all_tests, all_tests) 399 400 def test_find_tests_by_test_mapping_postsubmit(self): 401 """Test _find_tests_by_test_mapping method to locate postsubmit tests.""" 402 # TODO: (b/264015241) Stop mocking build variables. 403 os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR} 404 with mock.patch.dict('os.environ', os_environ_mock, clear=True): 405 tests, all_tests = self.ctr._find_tests_by_test_mapping( 406 path=TEST_MAPPING_DIR, 407 test_groups=[constants.TEST_GROUP_POSTSUBMIT], 408 file_name='test_mapping_sample', 409 checked_files=set(), 410 ) 411 expected_presubmit = set([TEST_1, TEST_2, TEST_5, TEST_7, TEST_9]) 412 expected = set([TEST_3, TEST_6, TEST_8, TEST_10]) 413 expected_all_tests = { 414 'presubmit': expected_presubmit, 415 'postsubmit': set([TEST_3, TEST_6, TEST_8, TEST_10]), 416 'other_group': set([TEST_4]), 417 } 418 self.assertEqual(expected, tests) 419 self.assertEqual(expected_all_tests, all_tests) 420 421 def test_find_tests_by_test_mapping_all_group(self): 422 """Test _find_tests_by_test_mapping method to locate postsubmit tests.""" 423 # TODO: (b/264015241) Stop mocking build variables. 424 os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR} 425 with mock.patch.dict('os.environ', os_environ_mock, clear=True): 426 tests, all_tests = self.ctr._find_tests_by_test_mapping( 427 path=TEST_MAPPING_DIR, 428 test_groups=[constants.TEST_GROUP_ALL], 429 file_name='test_mapping_sample', 430 checked_files=set(), 431 ) 432 expected_presubmit = set([TEST_1, TEST_2, TEST_5, TEST_7, TEST_9]) 433 expected = set([ 434 TEST_1, 435 TEST_2, 436 TEST_3, 437 TEST_4, 438 TEST_5, 439 TEST_6, 440 TEST_7, 441 TEST_8, 442 TEST_9, 443 TEST_10, 444 ]) 445 expected_all_tests = { 446 'presubmit': expected_presubmit, 447 'postsubmit': set([TEST_3, TEST_6, TEST_8, TEST_10]), 448 'other_group': set([TEST_4]), 449 } 450 self.assertEqual(expected, tests) 451 self.assertEqual(expected_all_tests, all_tests) 452 453 def test_find_tests_by_test_mapping_include_subdir(self): 454 """Test _find_tests_by_test_mapping method to include sub directory.""" 455 # TODO: (b/264015241) Stop mocking build variables. 456 os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR} 457 with mock.patch.dict('os.environ', os_environ_mock, clear=True): 458 tests, all_tests = self.ctr._find_tests_by_test_mapping( 459 path=TEST_MAPPING_TOP_DIR, 460 file_name='test_mapping_sample', 461 include_subdirs=True, 462 checked_files=set(), 463 ) 464 expected = set([TEST_1, TEST_2, TEST_5, TEST_7, TEST_9]) 465 expected_all_tests = { 466 'presubmit': expected, 467 'postsubmit': set([TEST_3, TEST_6, TEST_8, TEST_10]), 468 'other_group': set([TEST_4]), 469 } 470 self.assertEqual(expected, tests) 471 self.assertEqual(expected_all_tests, all_tests) 472 473 @mock.patch('builtins.input', return_value='') 474 def test_confirm_running(self, mock_input): 475 """Test _confirm_running method.""" 476 self.assertTrue(self.ctr._confirm_running([TEST_1])) 477 mock_input.return_value = 'N' 478 self.assertFalse(self.ctr._confirm_running([TEST_2])) 479 480 def test_print_fuzzy_searching_results(self): 481 """Test _print_fuzzy_searching_results""" 482 modules = [uc.MODULE_NAME, uc.MODULE2_NAME] 483 capture_output = StringIO() 484 sys.stdout = capture_output 485 self.ctr._print_fuzzy_searching_results(modules) 486 sys.stdout = sys.__stdout__ 487 output = 'Did you mean the following modules?\n{0}\n{1}\n'.format( 488 uc.MODULE_NAME, uc.MODULE2_NAME 489 ) 490 self.assertEqual(capture_output.getvalue(), output) 491 492 def test_filter_comments(self): 493 """Test filter_comments method""" 494 file_with_comments = os.path.join( 495 TEST_MAPPING_TOP_DIR, 'folder6', 'test_mapping_sample_with_comments' 496 ) 497 file_with_comments_golden = os.path.join( 498 TEST_MAPPING_TOP_DIR, 'folder6', 'test_mapping_sample_golden' 499 ) 500 test_mapping_dict = json.loads(self.ctr.filter_comments(file_with_comments)) 501 test_mapping_dict_gloden = None 502 with open(file_with_comments_golden) as json_file: 503 test_mapping_dict_gloden = json.load(json_file) 504 505 self.assertEqual(test_mapping_dict, test_mapping_dict_gloden) 506 507 @mock.patch.object(module_info.ModuleInfo, 'get_testable_modules') 508 def test_extract_testable_modules_by_wildcard(self, mock_mods): 509 """Test _extract_testable_modules_by_wildcard method.""" 510 mod_info = module_info.load_from_file( 511 module_file=os.path.join(uc.TEST_DATA_DIR, uc.JSON_FILE) 512 ) 513 ctr = cli_t.CLITranslator(mod_info=mod_info) 514 mock_mods.return_value = [ 515 'test1', 516 'test2', 517 'test3', 518 'test11', 519 'Test22', 520 'Test100', 521 'aTest101', 522 ] 523 # test '*' 524 expr1 = ['test*'] 525 result1 = ['test1', 'test2', 'test3', 'test11'] 526 self.assertEqual(ctr._extract_testable_modules_by_wildcard(expr1), result1) 527 # test '?' 528 expr2 = ['test?'] 529 result2 = ['test1', 'test2', 'test3'] 530 self.assertEqual(ctr._extract_testable_modules_by_wildcard(expr2), result2) 531 # test '*' and '?' 532 expr3 = ['*Test???'] 533 result3 = ['Test100', 'aTest101'] 534 self.assertEqual(ctr._extract_testable_modules_by_wildcard(expr3), result3) 535 536 @mock.patch.object(os, 'getcwd', return_value='/src/build_top/somewhere') 537 @mock.patch.object( 538 test_finder_utils, 539 'find_host_unit_tests', 540 return_value=[uc.HOST_UNIT_TEST_NAME_1, uc.HOST_UNIT_TEST_NAME_2], 541 ) 542 @mock.patch.object(cli_t.CLITranslator, '_find_tests_by_test_mapping') 543 @mock.patch.object( 544 cli_t.CLITranslator, 545 '_get_test_infos', 546 side_effect=gettestinfos_side_effect, 547 ) 548 def test_translate_test_mapping_host_unit_test( 549 self, _info, mock_testmapping, _find_unit_tests, _getcwd 550 ): 551 """Test translate method for tests belong to host unit tests.""" 552 # Check that test mappings feeds into get_test_info properly. 553 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 554 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 555 mock_testmapping.return_value = ([test_detail1, test_detail2], None) 556 self.args.tests = [] 557 self.args.host = False 558 self.args.host_unit_test_only = False 559 test_infos = self.ctr.translate(self.args) 560 unittest_utils.assert_equal_testinfo_lists( 561 self, 562 test_infos, 563 [ 564 uc.MODULE_INFO, 565 uc.CLASS_INFO, 566 uc.MODULE_INFO_HOST_1, 567 uc.MODULE_INFO_HOST_2, 568 ], 569 ) 570 571 @mock.patch.object( 572 test_finder_utils, 573 'find_host_unit_tests', 574 return_value=[uc.HOST_UNIT_TEST_NAME_1, uc.HOST_UNIT_TEST_NAME_2], 575 ) 576 @mock.patch.object(cli_t.CLITranslator, '_find_tests_by_test_mapping') 577 @mock.patch.object( 578 cli_t.CLITranslator, 579 '_get_test_infos', 580 side_effect=gettestinfos_side_effect, 581 ) 582 def test_translate_test_mapping_without_host_unit_test( 583 self, _info, mock_testmapping, _find_unit_tests 584 ): 585 """Test translate method not using host unit tests if test_mapping arg .""" 586 # Check that test mappings feeds into get_test_info properly. 587 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 588 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 589 mock_testmapping.return_value = ([test_detail1, test_detail2], None) 590 self.args.tests = [] 591 self.args.host = False 592 self.args.test_mapping = True 593 self.args.host_unit_test_only = False 594 test_infos = self.ctr.translate(self.args) 595 unittest_utils.assert_equal_testinfo_lists( 596 self, test_infos, [uc.MODULE_INFO, uc.CLASS_INFO] 597 ) 598 599 600class ParseTestIdentifierTest(unittest.TestCase): 601 """Test parse_test_identifier with different test names.""" 602 603 def test_no_mainline_modules(self): 604 """non-mainline module testing.""" 605 given = 'testName' 606 607 identifier = cli_t.parse_test_identifier(given) 608 609 self.assertEqual('testName', identifier.test_name) 610 self.assertEqual([], identifier.module_names) 611 self.assertEqual([], identifier.binary_names) 612 613 def test_single_mainline_module(self): 614 """only one mainline module.""" 615 given = 'testName[Module1.apk]' 616 617 identifier = cli_t.parse_test_identifier(given) 618 619 self.assertEqual('testName', identifier.test_name) 620 self.assertEqual(['Module1'], identifier.module_names) 621 self.assertEqual(['Module1.apk'], identifier.binary_names) 622 623 def test_multiple_mainline_modules(self): 624 """multiple mainline modules.""" 625 given = 'testName[Module1.apk+Module2.apex]' 626 627 identifier = cli_t.parse_test_identifier(given) 628 629 self.assertEqual('testName', identifier.test_name) 630 self.assertEqual(['Module1', 'Module2'], identifier.module_names) 631 self.assertEqual(['Module1.apk', 'Module2.apex'], identifier.binary_names) 632 633 def test_missing_closing_bracket(self): 634 """test the brackets are not in pair""" 635 given = 'testName[Module1.apk+Module2.apex' 636 637 identifier = cli_t.parse_test_identifier(given) 638 639 self.assertEqual(given, identifier.test_name) 640 self.assertEqual([], identifier.module_names) 641 self.assertEqual([], identifier.binary_names) 642 643 644class VerifyMainlineModuleTest(fake_filesystem_unittest.TestCase): 645 """test verify_mainline_modules sub-methods.""" 646 647 def setUp(self): 648 """Setup func.""" 649 self.setUpPyfakefs() 650 651 def test_verified_mainline_modules_no_brackets(self): 652 """True for it's not in mainline module pattern. (no brackets)""" 653 test_name = 'module0' 654 mod_info = create_module_info([ 655 module(name=test_name), 656 ]) 657 658 test_identifier = cli_t.parse_test_identifier(test_name) 659 translator = cli_t.CLITranslator(mod_info) 660 661 self.assertTrue(translator._verified_mainline_modules(test_identifier)) 662 663 def test_verified_mainline_modules_not_valid_test_module(self): 664 """False for test_name is not a module.""" 665 test_name = 'module1[foo.apk+goo.apk]' 666 mod_info = create_module_info([ 667 module(name='module_1'), 668 module(name='foo'), 669 module(name='goo'), 670 ]) 671 672 test_identifier = cli_t.parse_test_identifier(test_name) 673 translator = cli_t.CLITranslator(mod_info) 674 675 self.assertFalse(translator._verified_mainline_modules(test_identifier)) 676 677 def test_verified_mainline_modules_not_valid_mainline_module(self): 678 """False for mainline_modules are not modules.""" 679 test_name = 'module2[foo.apk+goo.apk]' 680 mod_info = create_module_info([module(name='module2')]) 681 682 test_identifier = cli_t.parse_test_identifier(test_name) 683 translator = cli_t.CLITranslator(mod_info) 684 685 self.assertFalse(translator._verified_mainline_modules(test_identifier)) 686 687 def test_verified_mainline_modules_no_test_mainline_modules(self): 688 """False for no definition in `test_mainline_modules` attribute.""" 689 test_name = 'module3[foo.apk+goo.apex]' 690 mod_info = create_module_info([ 691 module(name='module3', test_mainline_modules=[]), 692 module(name='foo', installed=['out/path/foo.apk']), 693 module(name='goo', installed=['out/path/goo.apex']), 694 ]) 695 696 test_identifier = cli_t.parse_test_identifier(test_name) 697 translator = cli_t.CLITranslator(mod_info) 698 699 self.assertFalse(translator._verified_mainline_modules(test_identifier)) 700 701 def test_verified_mainline_modules_test_mainline_modules(self): 702 """True for definition in `test_mainline_modules` attribute.""" 703 test_name = 'module4[foo.apk+goo.apex]' 704 mod_info = create_module_info([ 705 module(name='module4', test_mainline_modules=['foo.apk+goo.apex']), 706 module(name='foo', installed=['out/path/foo.apk']), 707 module(name='goo', installed=['out/path/goo.apex']), 708 ]) 709 710 test_identifier = cli_t.parse_test_identifier(test_name) 711 translator = cli_t.CLITranslator(mod_info) 712 713 self.assertTrue(translator._verified_mainline_modules(test_identifier)) 714 715 def test_verified_mainline_modules_were_in_test_config(self): 716 """True for mainline modules were defined in the test_config.""" 717 test_name = 'module5[foo.apk+goo.apex]' 718 mainline_config = 'out/module3/AndroidTest.xml' 719 self.fs.create_file( 720 mainline_config, 721 contents=""" 722 <configuration description="Mainline Module tests"> 723 <option name="config" 724 key="parameter" value="value_1" /> 725 <option name="config-descriptor:metadata" 726 key="mainline-param" value="foo.apk+goo.apex" /> 727 </configuration> 728 """, 729 ) 730 mod_info = create_module_info([ 731 module( 732 name='module5', 733 test_config=[mainline_config], 734 test_mainline_modules=[], 735 auto_test_config=[], 736 ), 737 module(name='foo', installed=['out/path/foo.apk']), 738 module(name='goo', installed=['out/path/goo.apex']), 739 ]) 740 741 test_identifier = cli_t.parse_test_identifier(test_name) 742 translator = cli_t.CLITranslator(mod_info) 743 744 self.assertTrue(translator._verified_mainline_modules(test_identifier)) 745 746 def test_verified_mainline_modules_were_in_auto_config(self): 747 """True for 'auto_test_config'=[True]""" 748 test_name = 'module6[foo.apk+goo.apex]' 749 mod_info = create_module_info([ 750 module( 751 name='module6', 752 test_config=['somewhere/AndroidTest.xml'], 753 auto_test_config=[True], 754 ), 755 module(name='foo', installed=['out/path/foo.apk']), 756 module(name='goo', installed=['out/path/goo.apex']), 757 ]) 758 759 test_identifier = cli_t.parse_test_identifier(test_name) 760 translator = cli_t.CLITranslator(mod_info) 761 762 self.assertTrue(translator._verified_mainline_modules(test_identifier)) 763 764 def test_verified_mainline_modules_have_no_association(self): 765 """False for null auto_test_config and null `mainline-param` in the test_config.""" 766 test_name = 'module7[foo.apk+goo.apex]' 767 config = 'out/module7/AndroidTest.xml' 768 self.fs.create_file( 769 config, 770 contents=""" 771 <configuration description="Mainline Module tests"> 772 <option name="config" 773 key="parameter" value="value_1" /> 774 </configuration> 775 """, 776 ) 777 mod_info = create_module_info([ 778 module(name='module7', test_config=[config], auto_test_config=[]), 779 module(name='foo', installed=['out/path/foo.apk']), 780 module(name='goo', installed=['out/path/goo.apex']), 781 ]) 782 783 test_identifier = cli_t.parse_test_identifier(test_name) 784 translator = cli_t.CLITranslator(mod_info) 785 786 self.assertFalse(translator._verified_mainline_modules(test_identifier)) 787 788 def test_verified_mainline_modules_were_in_auto_config(self): 789 """False for the given mainline is a capex file.""" 790 test_name = 'module8[foo.apk+goo.apex]' 791 mod_info = create_module_info([ 792 module(name='module8', test_mainline_modules=['foo.apk+goo.apex']), 793 module(name='foo', installed=['out/path/foo.apk']), 794 module(name='goo', installed=['out/path/goo.capex']), 795 ]) 796 797 test_identifier = cli_t.parse_test_identifier(test_name) 798 translator = cli_t.CLITranslator(mod_info) 799 800 self.assertFalse(translator._verified_mainline_modules(test_identifier)) 801 802 803def create_module_info(modules=None): 804 """wrapper func for creating module_info.ModuleInfo""" 805 name_to_module_info = {} 806 modules = modules or [] 807 808 for m in modules: 809 name_to_module_info[m['module_name']] = m 810 811 return module_info.load_from_dict(name_to_module_info) 812 813 814def module( 815 name=None, 816 path=None, 817 installed=None, 818 classes=None, 819 auto_test_config=None, 820 test_config=None, 821 shared_libs=None, 822 dependencies=None, 823 runtime_dependencies=None, 824 data=None, 825 data_dependencies=None, 826 compatibility_suites=None, 827 host_dependencies=None, 828 srcs=None, 829 supported_variants=None, 830 test_mainline_modules=None, 831): 832 """return a module info dict.""" 833 name = name or 'libhello' 834 835 m = {} 836 837 m['module_name'] = name 838 m['class'] = classes or ['ETC'] 839 m['path'] = [path or ''] 840 m['installed'] = installed or [] 841 m['is_unit_test'] = 'false' 842 m['auto_test_config'] = auto_test_config or [] 843 m['test_config'] = test_config or [] 844 m['shared_libs'] = shared_libs or [] 845 m['runtime_dependencies'] = runtime_dependencies or [] 846 m['dependencies'] = dependencies or [] 847 m['data'] = data or [] 848 m['data_dependencies'] = data_dependencies or [] 849 m['compatibility_suites'] = compatibility_suites or [] 850 m['host_dependencies'] = host_dependencies or [] 851 m['srcs'] = srcs or [] 852 m['supported_variants'] = supported_variants or [] 853 m['test_mainline_modules'] = test_mainline_modules or [] 854 return m 855 856 857def _gather_build_targets(test_infos): 858 targets = set() 859 for t_info in test_infos: 860 targets |= t_info.build_targets 861 return targets 862 863 864if __name__ == '__main__': 865 unittest.main() 866