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 19# pylint: disable=line-too-long 20 21import unittest 22import json 23import os 24import re 25import sys 26 27from importlib import reload 28from io import StringIO 29from unittest import mock 30 31import cli_translator as cli_t 32import constants 33import test_finder_handler 34import test_mapping 35import unittest_constants as uc 36import unittest_utils 37 38from metrics import metrics 39from test_finders import module_finder 40from test_finders import test_finder_base 41 42 43# TEST_MAPPING related consts 44TEST_MAPPING_TOP_DIR = os.path.join(uc.TEST_DATA_DIR, 'test_mapping') 45TEST_MAPPING_DIR = os.path.join(TEST_MAPPING_TOP_DIR, 'folder1') 46TEST_1 = test_mapping.TestDetail({'name': 'test1', 'host': True}) 47TEST_2 = test_mapping.TestDetail({'name': 'test2'}) 48TEST_3 = test_mapping.TestDetail({'name': 'test3'}) 49TEST_4 = test_mapping.TestDetail({'name': 'test4'}) 50TEST_5 = test_mapping.TestDetail({'name': 'test5'}) 51TEST_6 = test_mapping.TestDetail({'name': 'test6'}) 52TEST_7 = test_mapping.TestDetail({'name': 'test7'}) 53TEST_8 = test_mapping.TestDetail({'name': 'test8'}) 54TEST_9 = test_mapping.TestDetail({'name': 'test9'}) 55TEST_10 = test_mapping.TestDetail({'name': 'test10'}) 56 57SEARCH_DIR_RE = re.compile(r'^find ([^ ]*).*$') 58 59 60#pylint: disable=unused-argument 61def gettestinfos_side_effect(test_names, test_mapping_test_details=None): 62 """Mock return values for _get_test_info.""" 63 test_infos = set() 64 for test_name in test_names: 65 if test_name == uc.MODULE_NAME: 66 test_infos.add(uc.MODULE_INFO) 67 if test_name == uc.CLASS_NAME: 68 test_infos.add(uc.CLASS_INFO) 69 return test_infos 70 71 72#pylint: disable=protected-access 73#pylint: disable=no-self-use 74class CLITranslatorUnittests(unittest.TestCase): 75 """Unit tests for cli_t.py""" 76 77 def setUp(self): 78 """Run before execution of every test""" 79 self.ctr = cli_t.CLITranslator() 80 81 # Create a mock of args. 82 self.args = mock.Mock 83 self.args.tests = [] 84 # Test mapping related args 85 self.args.test_mapping = False 86 self.args.include_subdirs = False 87 self.args.enable_file_patterns = False 88 # Cache finder related args 89 self.args.clear_cache = False 90 self.ctr.mod_info = mock.Mock 91 self.ctr.mod_info.name_to_module_info = {} 92 93 def tearDown(self): 94 """Run after execution of every test""" 95 reload(uc) 96 97 @mock.patch('builtins.input', return_value='n') 98 @mock.patch.object(module_finder.ModuleFinder, 'find_test_by_module_name') 99 @mock.patch.object(module_finder.ModuleFinder, 'get_fuzzy_searching_results') 100 @mock.patch.object(metrics, 'FindTestFinishEvent') 101 @mock.patch.object(test_finder_handler, 'get_find_methods_for_test') 102 # pylint: disable=too-many-locals 103 def test_get_test_infos(self, mock_getfindmethods, _metrics, mock_getfuzzyresults, 104 mock_findtestbymodule, mock_input): 105 """Test _get_test_infos method.""" 106 ctr = cli_t.CLITranslator() 107 find_method_return_module_info = lambda x, y: uc.MODULE_INFOS 108 # pylint: disable=invalid-name 109 find_method_return_module_class_info = (lambda x, test: uc.MODULE_INFOS 110 if test == uc.MODULE_NAME 111 else uc.CLASS_INFOS) 112 find_method_return_nothing = lambda x, y: None 113 one_test = [uc.MODULE_NAME] 114 mult_test = [uc.MODULE_NAME, uc.CLASS_NAME] 115 116 # Let's make sure we return what we expect. 117 expected_test_infos = {uc.MODULE_INFO} 118 mock_getfindmethods.return_value = [ 119 test_finder_base.Finder(None, find_method_return_module_info, None)] 120 unittest_utils.assert_strict_equal( 121 self, ctr._get_test_infos(one_test), expected_test_infos) 122 123 # Check we receive multiple test infos. 124 expected_test_infos = {uc.MODULE_INFO, uc.CLASS_INFO} 125 mock_getfindmethods.return_value = [ 126 test_finder_base.Finder(None, find_method_return_module_class_info, 127 None)] 128 unittest_utils.assert_strict_equal( 129 self, ctr._get_test_infos(mult_test), expected_test_infos) 130 131 # Check return null set when we have no tests found or multiple results. 132 mock_getfindmethods.return_value = [ 133 test_finder_base.Finder(None, find_method_return_nothing, None)] 134 null_test_info = set() 135 mock_getfuzzyresults.return_value = [] 136 self.assertEqual(null_test_info, ctr._get_test_infos(one_test)) 137 self.assertEqual(null_test_info, ctr._get_test_infos(mult_test)) 138 139 # Check returning test_info when the user says Yes. 140 mock_input.return_value = "Y" 141 mock_getfindmethods.return_value = [ 142 test_finder_base.Finder(None, find_method_return_module_info, None)] 143 mock_getfuzzyresults.return_value = one_test 144 mock_findtestbymodule.return_value = uc.MODULE_INFO 145 unittest_utils.assert_strict_equal( 146 self, ctr._get_test_infos([uc.TYPO_MODULE_NAME]), {uc.MODULE_INFO}) 147 148 # Check the method works for test mapping. 149 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 150 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 151 expected_test_infos = {uc.MODULE_INFO, uc.CLASS_INFO} 152 mock_getfindmethods.return_value = [ 153 test_finder_base.Finder(None, find_method_return_module_class_info, 154 None)] 155 test_infos = ctr._get_test_infos( 156 mult_test, [test_detail1, test_detail2]) 157 unittest_utils.assert_strict_equal( 158 self, test_infos, expected_test_infos) 159 for test_info in test_infos: 160 if test_info == uc.MODULE_INFO: 161 self.assertEqual( 162 test_detail1.options, 163 test_info.data[constants.TI_MODULE_ARG]) 164 else: 165 self.assertEqual( 166 test_detail2.options, 167 test_info.data[constants.TI_MODULE_ARG]) 168 169 @mock.patch.object(metrics, 'FindTestFinishEvent') 170 @mock.patch.object(test_finder_handler, 'get_find_methods_for_test') 171 def test_get_test_infos_2(self, mock_getfindmethods, _metrics): 172 """Test _get_test_infos method.""" 173 ctr = cli_t.CLITranslator() 174 find_method_return_module_info2 = lambda x, y: uc.MODULE_INFOS2 175 find_method_ret_mod_cls_info2 = ( 176 lambda x, test: uc.MODULE_INFOS2 177 if test == uc.MODULE_NAME else uc.CLASS_INFOS2) 178 one_test = [uc.MODULE_NAME] 179 mult_test = [uc.MODULE_NAME, uc.CLASS_NAME] 180 # Let's make sure we return what we expect. 181 expected_test_infos = {uc.MODULE_INFO, uc.MODULE_INFO2} 182 mock_getfindmethods.return_value = [ 183 test_finder_base.Finder(None, find_method_return_module_info2, 184 None)] 185 unittest_utils.assert_strict_equal( 186 self, ctr._get_test_infos(one_test), expected_test_infos) 187 # Check we receive multiple test infos. 188 expected_test_infos = {uc.MODULE_INFO, uc.CLASS_INFO, uc.MODULE_INFO2, 189 uc.CLASS_INFO2} 190 mock_getfindmethods.return_value = [ 191 test_finder_base.Finder(None, find_method_ret_mod_cls_info2, 192 None)] 193 unittest_utils.assert_strict_equal( 194 self, ctr._get_test_infos(mult_test), expected_test_infos) 195 # Check the method works for test mapping. 196 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 197 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 198 expected_test_infos = {uc.MODULE_INFO, uc.CLASS_INFO, uc.MODULE_INFO2, 199 uc.CLASS_INFO2} 200 mock_getfindmethods.return_value = [ 201 test_finder_base.Finder(None, find_method_ret_mod_cls_info2, 202 None)] 203 test_infos = ctr._get_test_infos( 204 mult_test, [test_detail1, test_detail2]) 205 unittest_utils.assert_strict_equal( 206 self, test_infos, expected_test_infos) 207 for test_info in test_infos: 208 if test_info in [uc.MODULE_INFO, uc.MODULE_INFO2]: 209 self.assertEqual( 210 test_detail1.options, 211 test_info.data[constants.TI_MODULE_ARG]) 212 elif test_info in [uc.CLASS_INFO, uc.CLASS_INFO2]: 213 self.assertEqual( 214 test_detail2.options, 215 test_info.data[constants.TI_MODULE_ARG]) 216 217 @mock.patch.object(cli_t.CLITranslator, '_get_test_infos', 218 side_effect=gettestinfos_side_effect) 219 def test_translate_class(self, _info): 220 """Test translate method for tests by class name.""" 221 # Check that we can find a class. 222 self.args.tests = [uc.CLASS_NAME] 223 targets, test_infos = self.ctr.translate(self.args) 224 unittest_utils.assert_strict_equal( 225 self, targets, uc.CLASS_BUILD_TARGETS) 226 unittest_utils.assert_strict_equal(self, test_infos, {uc.CLASS_INFO}) 227 228 @mock.patch.object(cli_t.CLITranslator, '_get_test_infos', 229 side_effect=gettestinfos_side_effect) 230 def test_translate_module(self, _info): 231 """Test translate method for tests by module or class name.""" 232 # Check that we get all the build targets we expect. 233 self.args.tests = [uc.MODULE_NAME, uc.CLASS_NAME] 234 targets, test_infos = self.ctr.translate(self.args) 235 unittest_utils.assert_strict_equal( 236 self, targets, uc.MODULE_CLASS_COMBINED_BUILD_TARGETS) 237 unittest_utils.assert_strict_equal(self, test_infos, {uc.MODULE_INFO, 238 uc.CLASS_INFO}) 239 240 @mock.patch.object(cli_t.CLITranslator, '_find_tests_by_test_mapping') 241 @mock.patch.object(cli_t.CLITranslator, '_get_test_infos', 242 side_effect=gettestinfos_side_effect) 243 def test_translate_test_mapping(self, _info, mock_testmapping): 244 """Test translate method for tests in test mapping.""" 245 # Check that test mappings feeds into get_test_info properly. 246 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 247 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 248 mock_testmapping.return_value = ([test_detail1, test_detail2], None) 249 self.args.tests = [] 250 targets, test_infos = self.ctr.translate(self.args) 251 unittest_utils.assert_strict_equal( 252 self, targets, uc.MODULE_CLASS_COMBINED_BUILD_TARGETS) 253 unittest_utils.assert_strict_equal(self, test_infos, {uc.MODULE_INFO, 254 uc.CLASS_INFO}) 255 256 @mock.patch.object(cli_t.CLITranslator, '_find_tests_by_test_mapping') 257 @mock.patch.object(cli_t.CLITranslator, '_get_test_infos', 258 side_effect=gettestinfos_side_effect) 259 def test_translate_test_mapping_all(self, _info, mock_testmapping): 260 """Test translate method for tests in test mapping.""" 261 # Check that test mappings feeds into get_test_info properly. 262 test_detail1 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST) 263 test_detail2 = test_mapping.TestDetail(uc.TEST_MAPPING_TEST_WITH_OPTION) 264 mock_testmapping.return_value = ([test_detail1, test_detail2], None) 265 self.args.tests = ['src_path:all'] 266 self.args.test_mapping = True 267 targets, test_infos = self.ctr.translate(self.args) 268 unittest_utils.assert_strict_equal( 269 self, targets, uc.MODULE_CLASS_COMBINED_BUILD_TARGETS) 270 unittest_utils.assert_strict_equal(self, test_infos, {uc.MODULE_INFO, 271 uc.CLASS_INFO}) 272 273 def test_find_tests_by_test_mapping_presubmit(self): 274 """Test _find_tests_by_test_mapping method to locate presubmit tests.""" 275 os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR} 276 with mock.patch.dict('os.environ', os_environ_mock, clear=True): 277 tests, all_tests = self.ctr._find_tests_by_test_mapping( 278 path=TEST_MAPPING_DIR, file_name='test_mapping_sample', 279 checked_files=set()) 280 expected = set([TEST_1, TEST_2, TEST_5, TEST_7, TEST_9]) 281 expected_all_tests = {'presubmit': expected, 282 'postsubmit': set( 283 [TEST_3, TEST_6, TEST_8, TEST_10]), 284 'other_group': set([TEST_4])} 285 self.assertEqual(expected, tests) 286 self.assertEqual(expected_all_tests, all_tests) 287 288 def test_find_tests_by_test_mapping_postsubmit(self): 289 """Test _find_tests_by_test_mapping method to locate postsubmit tests. 290 """ 291 os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR} 292 with mock.patch.dict('os.environ', os_environ_mock, clear=True): 293 tests, all_tests = self.ctr._find_tests_by_test_mapping( 294 path=TEST_MAPPING_DIR, 295 test_group=constants.TEST_GROUP_POSTSUBMIT, 296 file_name='test_mapping_sample', checked_files=set()) 297 expected_presubmit = set([TEST_1, TEST_2, TEST_5, TEST_7, TEST_9]) 298 expected = set([TEST_3, TEST_6, TEST_8, TEST_10]) 299 expected_all_tests = {'presubmit': expected_presubmit, 300 'postsubmit': set( 301 [TEST_3, TEST_6, TEST_8, TEST_10]), 302 'other_group': set([TEST_4])} 303 self.assertEqual(expected, tests) 304 self.assertEqual(expected_all_tests, all_tests) 305 306 def test_find_tests_by_test_mapping_all_group(self): 307 """Test _find_tests_by_test_mapping method to locate postsubmit tests. 308 """ 309 os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR} 310 with mock.patch.dict('os.environ', os_environ_mock, clear=True): 311 tests, all_tests = self.ctr._find_tests_by_test_mapping( 312 path=TEST_MAPPING_DIR, test_group=constants.TEST_GROUP_ALL, 313 file_name='test_mapping_sample', checked_files=set()) 314 expected_presubmit = set([TEST_1, TEST_2, TEST_5, TEST_7, TEST_9]) 315 expected = set([ 316 TEST_1, TEST_2, TEST_3, TEST_4, TEST_5, TEST_6, TEST_7, TEST_8, 317 TEST_9, TEST_10]) 318 expected_all_tests = {'presubmit': expected_presubmit, 319 'postsubmit': set( 320 [TEST_3, TEST_6, TEST_8, TEST_10]), 321 'other_group': set([TEST_4])} 322 self.assertEqual(expected, tests) 323 self.assertEqual(expected_all_tests, all_tests) 324 325 def test_find_tests_by_test_mapping_include_subdir(self): 326 """Test _find_tests_by_test_mapping method to include sub directory.""" 327 os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR} 328 with mock.patch.dict('os.environ', os_environ_mock, clear=True): 329 tests, all_tests = self.ctr._find_tests_by_test_mapping( 330 path=TEST_MAPPING_TOP_DIR, file_name='test_mapping_sample', 331 include_subdirs=True, checked_files=set()) 332 expected = set([TEST_1, TEST_2, TEST_5, TEST_7, TEST_9]) 333 expected_all_tests = {'presubmit': expected, 334 'postsubmit': set([ 335 TEST_3, TEST_6, TEST_8, TEST_10]), 336 'other_group': set([TEST_4])} 337 self.assertEqual(expected, tests) 338 self.assertEqual(expected_all_tests, all_tests) 339 340 @mock.patch('builtins.input', return_value='') 341 def test_confirm_running(self, mock_input): 342 """Test _confirm_running method.""" 343 self.assertTrue(self.ctr._confirm_running([TEST_1])) 344 mock_input.return_value = 'N' 345 self.assertFalse(self.ctr._confirm_running([TEST_2])) 346 347 def test_print_fuzzy_searching_results(self): 348 """Test _print_fuzzy_searching_results""" 349 modules = [uc.MODULE_NAME, uc.MODULE2_NAME] 350 capture_output = StringIO() 351 sys.stdout = capture_output 352 self.ctr._print_fuzzy_searching_results(modules) 353 sys.stdout = sys.__stdout__ 354 output = 'Did you mean the following modules?\n{0}\n{1}\n'.format( 355 uc.MODULE_NAME, uc.MODULE2_NAME) 356 self.assertEqual(capture_output.getvalue(), output) 357 358 def test_filter_comments(self): 359 """Test filter_comments method""" 360 file_with_comments = os.path.join(TEST_MAPPING_TOP_DIR, 361 'folder6', 362 'test_mapping_sample_with_comments') 363 file_with_comments_golden = os.path.join(TEST_MAPPING_TOP_DIR, 364 'folder6', 365 'test_mapping_sample_golden') 366 test_mapping_dict = json.loads( 367 self.ctr.filter_comments(file_with_comments)) 368 test_mapping_dict_gloden = None 369 with open(file_with_comments_golden) as json_file: 370 test_mapping_dict_gloden = json.load(json_file) 371 372 self.assertEqual(test_mapping_dict, test_mapping_dict_gloden) 373 374 375if __name__ == '__main__': 376 unittest.main() 377