• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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