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