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