• 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 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