1#!/usr/bin/env python3
2#
3# Copyright 2018, 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 module_finder."""
18
19# pylint: disable=invalid-name
20# pylint: disable=missing-function-docstring
21# pylint: disable=too-many-lines
22# pylint: disable=unsubscriptable-object
23
24import copy
25import os
26import pathlib
27import re
28import tempfile
29import unittest
30from unittest import mock
31from atest import atest_error
32from atest import atest_utils
33from atest import constants
34from atest import module_info
35from atest import module_info_unittest_base
36from atest import unittest_constants as uc
37from atest import unittest_utils
38from atest.test_finders import module_finder
39from atest.test_finders import test_filter_utils
40from atest.test_finders import test_finder_utils
41from atest.test_finders import test_info
42from atest.test_runners import atest_tf_test_runner as atf_tr
43from pyfakefs import fake_filesystem_unittest
44
45MODULE_CLASS = '%s:%s' % (uc.MODULE_NAME, uc.CLASS_NAME)
46MODULE_PACKAGE = '%s:%s' % (uc.MODULE_NAME, uc.PACKAGE)
47CC_MODULE_CLASS = '%s:%s' % (uc.CC_MODULE_NAME, uc.CC_CLASS_NAME)
48KERNEL_TEST_CLASS = 'test_class_1'
49KERNEL_TEST_CONFIG = 'KernelTest.xml.data'
50KERNEL_MODULE_CLASS = '%s:%s' % (
51    constants.REQUIRED_LTP_TEST_MODULES[0],
52    KERNEL_TEST_CLASS,
53)
54KERNEL_CONFIG_FILE = os.path.join(uc.TEST_DATA_DIR, KERNEL_TEST_CONFIG)
55KERNEL_CLASS_FILTER = test_info.TestFilter(KERNEL_TEST_CLASS, frozenset())
56KERNEL_MODULE_CLASS_DATA = {
57    constants.TI_REL_CONFIG: KERNEL_CONFIG_FILE,
58    constants.TI_FILTER: frozenset([KERNEL_CLASS_FILTER]),
59}
60KERNEL_MODULE_CLASS_INFO = test_info.TestInfo(
61    constants.REQUIRED_LTP_TEST_MODULES[0],
62    atf_tr.AtestTradefedTestRunner.NAME,
63    uc.CLASS_BUILD_TARGETS,
64    KERNEL_MODULE_CLASS_DATA,
65)
66FLAT_METHOD_INFO = test_info.TestInfo(
67    uc.MODULE_NAME,
68    atf_tr.AtestTradefedTestRunner.NAME,
69    uc.MODULE_BUILD_TARGETS,
70    data={
71        constants.TI_FILTER: frozenset([uc.FLAT_METHOD_FILTER]),
72        constants.TI_REL_CONFIG: uc.CONFIG_FILE,
73    },
74)
75MODULE_CLASS_METHOD = '%s#%s' % (MODULE_CLASS, uc.METHOD_NAME)
76CC_MODULE_CLASS_METHOD = '%s#%s' % (CC_MODULE_CLASS, uc.CC_METHOD_NAME)
77CLASS_INFO_MODULE_2 = test_info.TestInfo(
78    uc.MODULE2_NAME,
79    atf_tr.AtestTradefedTestRunner.NAME,
80    uc.CLASS_BUILD_TARGETS,
81    data={
82        constants.TI_FILTER: frozenset([uc.CLASS_FILTER]),
83        constants.TI_REL_CONFIG: uc.CONFIG2_FILE,
84    },
85)
86CC_CLASS_INFO_MODULE_2 = test_info.TestInfo(
87    uc.CC_MODULE2_NAME,
88    atf_tr.AtestTradefedTestRunner.NAME,
89    uc.CLASS_BUILD_TARGETS,
90    data={
91        constants.TI_FILTER: frozenset([uc.CC_CLASS_FILTER]),
92        constants.TI_REL_CONFIG: uc.CC_CONFIG2_FILE,
93    },
94)
95DEFAULT_INSTALL_PATH = ['/path/to/install']
96ROBO_MOD_PATH = ['/shared/robo/path']
97NON_RUN_ROBO_MOD_NAME = 'robo_mod'
98RUN_ROBO_MOD_NAME = 'run_robo_mod'
99NON_RUN_ROBO_MOD = {
100    constants.MODULE_NAME: NON_RUN_ROBO_MOD_NAME,
101    constants.MODULE_PATH: ROBO_MOD_PATH,
102    constants.MODULE_CLASS: ['random_class'],
103}
104RUN_ROBO_MOD = {
105    constants.MODULE_NAME: RUN_ROBO_MOD_NAME,
106    constants.MODULE_PATH: ROBO_MOD_PATH,
107    constants.MODULE_CLASS: [constants.MODULE_CLASS_ROBOLECTRIC],
108}
109
110SEARCH_DIR_RE = re.compile(r'^find ([^ ]*).*$')
111
112
113# pylint: disable=unused-argument
114def classoutside_side_effect(find_cmd, shell=False):
115  """Mock the check output of a find cmd where class outside module path."""
116  search_dir = SEARCH_DIR_RE.match(find_cmd).group(1).strip()
117  if search_dir == uc.ROOT:
118    return uc.FIND_ONE
119  return None
120
121
122class ModuleFinderFindTestByModuleName(
123    module_info_unittest_base.ModuleInfoTest
124):
125
126  def setUp(self):
127    super().setUp()
128    self.build_top = pathlib.Path('/main')
129
130  def test_find_test_by_module_name_single_module_exists(self):
131    module_name = 'SingleModuleTestCases'
132    test_module = module_info_unittest_base.device_driven_test_module(
133        name=module_name,
134    )
135    finder = self.create_finder_with_module(test_module)
136
137    t_infos = finder.find_test_by_module_name(module_name=module_name)
138
139    with self.subTest(name='returns_one_test_info'):
140      self.assertEqual(len(t_infos), 1)
141    with self.subTest(name='test_name_is_module_name'):
142      self.assert_test_info_has_test_name(t_infos[0], module_name)
143      self.assert_test_info_has_raw_test_name(t_infos[0], module_name)
144    with self.subTest(name='contains_expected_build_targets'):
145      self.assert_test_info_contains_build_targets(t_infos[0], module_name)
146      self.assert_test_info_contains_build_targets(
147          t_infos[0],
148          'example_module-project',
149      )
150
151  @mock.patch.object(
152      test_finder_utils, 'find_parent_module_dir', return_value='/main'
153  )
154  @mock.patch(
155      'subprocess.check_output',
156      return_value=(
157          'path/to/testmodule/src/com/android/myjavatests/MyJavaTestClass.java'
158      ),
159  )
160  def test_find_test_by_module_class_name_native_found(
161      self, find_cmd, found_file_path
162  ):
163    module_name = 'MyModuleTestCases'
164    test_module = module_info_unittest_base.device_driven_test_module(
165        name=module_name, class_type=['NATIVE_TESTS']
166    )
167    finder = self.create_finder_with_module(test_module)
168
169    t_infos = finder.find_test_by_module_and_class(
170        'MyModuleTestCases:MyJavaTestClass'
171    )
172
173    with self.subTest(name='returns_one_test_info'):
174      self.assertEqual(len(t_infos), 1)
175    with self.subTest(name='test_name_is_module_name'):
176      self.assert_test_info_has_test_name(t_infos[0], module_name)
177      self.assert_test_info_has_raw_test_name(t_infos[0], module_name)
178    with self.subTest(name='contains_expected_filters'):
179      self.assert_test_info_has_class_filter(t_infos[0], 'MyJavaTestClass')
180    with self.subTest(name='contains_expected_build_targets'):
181      self.assert_test_info_contains_build_targets(t_infos[0], module_name)
182      self.assert_test_info_contains_build_targets(
183          t_infos[0],
184          'example_module-project',
185      )
186
187  @mock.patch.object(
188      test_finder_utils, 'find_parent_module_dir', return_value='/main'
189  )
190  @mock.patch(
191      'subprocess.check_output',
192      return_value=(
193          'path/to/testmodule/src/com/android/myjavatests/MyJavaTestClass.java'
194      ),
195  )
196  def test_find_test_by_module_class_name_unknown_test_info_is_none(
197      self, find_cmd, found_file_path
198  ):
199    test_class_name = 'MyJavaTestClass'
200    test_module = module_info_unittest_base.device_driven_test_module(
201        name='MyModuleTestCases', class_type=['NATIVE_TESTS']
202    )
203    finder = self.create_finder_with_module(test_module)
204
205    t_infos = finder.find_test_by_class_name(
206        class_name=test_class_name, module_name='Unknown'
207    )
208
209    self.assertIsNone(t_infos)
210
211  @mock.patch.object(
212      test_finder_utils, 'find_parent_module_dir', return_value='/main'
213  )
214  @mock.patch(
215      'subprocess.check_output',
216      return_value=[
217          'example_module/project/src/com/android/myjavatests/MyJavaTestClass.java'
218      ],
219  )
220  @mock.patch.object(
221      test_finder_utils,
222      'extract_selected_tests',
223      return_value=[
224          'example_module/project/configs/Config1.xml',
225          'example_module/project/configs/Config2.xml',
226      ],
227  )
228  def test_find_test_by_module_class_multiple_configs_tests_found(
229      self, mock_user_selection, mock_run_cmd, mock_parent_dir
230  ):
231    module_name = 'MyModuleTestCases'
232    test_module = (
233        module_info_unittest_base.device_driven_multi_config_test_module(
234            name=module_name,
235            class_type=['NATIVE_TESTS'],
236        )
237    )
238    finder = self.create_finder_with_module(test_module)
239
240    t_infos = finder.find_test_by_module_and_class(
241        'MyModuleTestCases:MyMultiConfigJavaTestClass'
242    )
243
244    with self.subTest(name='first_test_name_corresponds_to_module_name'):
245      self.assert_test_info_has_test_name(t_infos[0], module_name)
246    with self.subTest(name='second_test_name_corresponds_to_config_name'):
247      self.assert_test_info_has_test_name(t_infos[1], 'Config2')
248    with self.subTest(name='raw_test_name_corresponds_to_module_name'):
249      self.assert_test_info_has_raw_test_name(t_infos[0], module_name)
250      self.assert_test_info_has_raw_test_name(t_infos[1], module_name)
251    with self.subTest(name='contains_expected_filters'):
252      self.assert_test_info_has_class_filter(
253          t_infos[0], 'MyMultiConfigJavaTestClass'
254      )
255      self.assert_test_info_has_config(
256          t_infos[0], 'example_module/project/configs/Config1.xml'
257      )
258      self.assert_test_info_has_class_filter(
259          t_infos[1], 'MyMultiConfigJavaTestClass'
260      )
261      self.assert_test_info_has_config(
262          t_infos[1], 'example_module/project/configs/Config2.xml'
263      )
264    with self.subTest(name='contains_expected_build_targets'):
265      self.assert_test_info_contains_build_targets(t_infos[0], module_name)
266      self.assert_test_info_contains_build_targets(
267          t_infos[0],
268          'example_module-project',
269      )
270      self.assert_test_info_contains_build_targets(t_infos[1], module_name)
271      self.assert_test_info_contains_build_targets(
272          t_infos[1],
273          'example_module-project',
274      )
275
276  def create_finder_with_module(self, test_module):
277    return module_finder.ModuleFinder(self.create_module_info([test_module]))
278
279  def assert_test_info_has_test_name(
280      self, t_info: test_info.TestInfo, test_name: str
281  ):
282    self.assertEqual(t_info.test_name, test_name)
283
284  def assert_test_info_has_raw_test_name(
285      self, t_info: test_info.TestInfo, test_name: str
286  ):
287    self.assertEqual(t_info.raw_test_name, test_name)
288
289  def assert_test_info_has_class_filter(
290      self, t_info: test_info.TestInfo, class_name: str
291  ):
292    self.assertSetEqual(
293        frozenset([test_info.TestFilter(class_name, frozenset())]),
294        t_info.data[constants.TI_FILTER],
295    )
296
297  def assert_test_info_has_config(
298      self, t_info: test_info.TestInfo, config: str
299  ):
300    self.assertEqual(config, t_info.data[constants.TI_REL_CONFIG])
301
302  def assert_test_info_contains_build_targets(
303      self, t_info: test_info.TestInfo, expected_build_target: str
304  ):
305    self.assertTrue(
306        any(expected_build_target in target for target in t_info.build_targets)
307    )
308
309
310class ModuleFinderFindTestByPath(fake_filesystem_unittest.TestCase):
311  """Test cases that invoke find_test_by_path."""
312
313  def setUp(self):
314    super().setUp()
315    self.setUpPyfakefs()
316
317  # pylint: disable=protected-access
318  def create_empty_module_info(self):
319    fake_temp_file_name = next(tempfile._get_candidate_names())
320    self.fs.create_file(fake_temp_file_name, contents='{}')
321    return module_info.load_from_file(module_file=fake_temp_file_name)
322
323  def create_module_info(self, modules=None):
324    modules = modules or []
325    name_to_module_info = {}
326
327    for m in modules:
328      name_to_module_info[m['module_name']] = m
329
330    return module_info.load_from_dict(name_to_module_info=name_to_module_info)
331
332  # TODO: remove below mocks and hide unnecessary information.
333  @mock.patch.object(module_finder.ModuleFinder, '_get_test_info_filter')
334  @mock.patch.object(
335      test_finder_utils, 'find_parent_module_dir', return_value=None
336  )
337  # pylint: disable=unused-argument
338  def test_find_test_by_path_belong_to_dependencies(
339      self, _mock_find_parent, _mock_test_filter
340  ):
341    """Test find_test_by_path if belong to test dependencies."""
342    test1 = module(
343        name='test1',
344        classes=['class'],
345        dependencies=['lib1'],
346        installed=['install/test1'],
347        auto_test_config=[True],
348    )
349    test2 = module(
350        name='test2',
351        classes=['class'],
352        dependencies=['lib2'],
353        installed=['install/test2'],
354        auto_test_config=[True],
355    )
356    lib1 = module(name='lib1', srcs=['path/src1'])
357    lib2 = module(name='lib2', srcs=['path/src2'])
358    mod_info = self.create_module_info([test1, test2, lib1, lib2])
359    mod_finder = module_finder.ModuleFinder(module_info=mod_info)
360    self.fs.create_file('path/src1/main.cpp', contents='')
361    test1_filter = test_info.TestFilter('test1Filter', frozenset())
362    _mock_test_filter.return_value = test1_filter
363
364    t_infos = mod_finder.find_test_by_path('path/src1')
365
366    unittest_utils.assert_equal_testinfos(
367        self,
368        test_info.TestInfo(
369            'test1',
370            atf_tr.AtestTradefedTestRunner.NAME,
371            {'test1', 'MODULES-IN-'},
372            {
373                constants.TI_FILTER: test1_filter,
374                constants.TI_REL_CONFIG: 'AndroidTest.xml',
375            },
376            module_class=['class'],
377        ),
378        t_infos[0],
379    )
380
381
382# pylint: disable=protected-access
383class ModuleFinderUnittests(unittest.TestCase):
384  """Unit tests for module_finder.py"""
385
386  def setUp(self):
387    """Set up stuff for testing."""
388    super().setUp()
389    self.mod_finder = module_finder.ModuleFinder()
390    self.mod_finder.module_info = mock.Mock(spec=module_info.ModuleInfo)
391    self.mod_finder.module_info.path_to_module_info = {}
392    self.mod_finder.module_info.is_mobly_module.return_value = False
393    self.mod_finder.root_dir = uc.ROOT
394
395  def test_is_vts_module(self):
396    """Test _load_module_info_file regular operation."""
397    mod_name = 'mod'
398    is_vts_module_info = {'compatibility_suites': ['vts10', 'tests']}
399    self.mod_finder.module_info.get_module_info.return_value = (
400        is_vts_module_info
401    )
402    self.assertTrue(self.mod_finder._is_vts_module(mod_name))
403
404    is_not_vts_module = {'compatibility_suites': ['vts10', 'cts']}
405    self.mod_finder.module_info.get_module_info.return_value = is_not_vts_module
406    self.assertFalse(self.mod_finder._is_vts_module(mod_name))
407
408  # pylint: disable=unused-argument
409  @mock.patch.object(
410      module_finder.ModuleFinder,
411      '_get_build_targets',
412      return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS),
413  )
414  def test_find_test_by_module_name(self, _get_targ):
415    """Test find_test_by_module_name."""
416    self.mod_finder.module_info.is_robolectric_test.return_value = False
417    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
418        {}
419    )
420    self.mod_finder.module_info.has_test_config.return_value = True
421    mod_info = {
422        'installed': ['/path/to/install'],
423        'path': [uc.MODULE_DIR],
424        constants.MODULE_CLASS: [],
425        constants.MODULE_COMPATIBILITY_SUITES: [],
426    }
427    self.mod_finder.module_info.get_module_info.return_value = mod_info
428    self.mod_finder.module_info.get_robolectric_type.return_value = 0
429    t_infos = self.mod_finder.find_test_by_module_name(uc.MODULE_NAME)
430    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.MODULE_INFO)
431    self.mod_finder.module_info.get_module_info.return_value = None
432    self.mod_finder.module_info.is_testable_module.return_value = False
433    self.assertIsNone(self.mod_finder.find_test_by_module_name('Not_Module'))
434
435  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
436  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
437  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
438  @mock.patch.object(
439      test_filter_utils, 'is_parameterized_java_class', return_value=False
440  )
441  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
442  @mock.patch.object(
443      module_finder.ModuleFinder, '_is_vts_module', return_value=False
444  )
445  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
446  @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE)
447  @mock.patch.object(
448      test_filter_utils,
449      'get_fully_qualified_class_name',
450      return_value=uc.FULL_CLASS_NAME,
451  )
452  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
453  @mock.patch('os.path.isdir', return_value=True)
454  # pylint: disable=unused-argument
455  def test_find_test_by_class_name(
456      self,
457      _isdir,
458      _isfile,
459      _fqcn,
460      mock_checkoutput,
461      mock_build,
462      _vts,
463      _has_method_in_file,
464      _is_parameterized,
465      _is_build_file,
466      _mock_unit_tests,
467      mods_to_test,
468  ):
469    """Test find_test_by_class_name."""
470    mock_build.return_value = uc.CLASS_BUILD_TARGETS
471    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
472    self.mod_finder.module_info.is_robolectric_test.return_value = False
473    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
474        {}
475    )
476    self.mod_finder.module_info.has_test_config.return_value = True
477    self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
478    self.mod_finder.module_info.get_module_info.return_value = {
479        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
480        constants.MODULE_NAME: uc.MODULE_NAME,
481        constants.MODULE_CLASS: [],
482        constants.MODULE_COMPATIBILITY_SUITES: [],
483    }
484    self.mod_finder.module_info.get_robolectric_type.return_value = 0
485    mods_to_test.return_value = [uc.MODULE_NAME]
486    t_infos = self.mod_finder.find_test_by_class_name(uc.CLASS_NAME)
487    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO)
488
489    # with method
490    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
491    class_with_method = '%s#%s' % (uc.CLASS_NAME, uc.METHOD_NAME)
492    t_infos = self.mod_finder.find_test_by_class_name(class_with_method)
493    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO)
494    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
495    class_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME)
496    t_infos = self.mod_finder.find_test_by_class_name(class_methods)
497    unittest_utils.assert_equal_testinfos(self, t_infos[0], FLAT_METHOD_INFO)
498    # module and rel_config passed in
499    mock_build.return_value = uc.CLASS_BUILD_TARGETS
500    t_infos = self.mod_finder.find_test_by_class_name(
501        uc.CLASS_NAME, uc.MODULE_NAME, uc.CONFIG_FILE
502    )
503    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO)
504    # find output fails to find class file
505    mock_checkoutput.return_value = ''
506    self.assertIsNone(self.mod_finder.find_test_by_class_name('Not class'))
507    # class is outside given module path
508    mock_checkoutput.side_effect = classoutside_side_effect
509    t_infos = self.mod_finder.find_test_by_class_name(
510        uc.CLASS_NAME, uc.MODULE2_NAME, uc.CONFIG2_FILE
511    )
512    unittest_utils.assert_equal_testinfos(self, t_infos[0], CLASS_INFO_MODULE_2)
513
514  @mock.patch.object(
515      test_finder_utils, 'find_parent_module_dir', return_value='foo/bar/jank'
516  )
517  @mock.patch.object(
518      test_filter_utils, 'is_parameterized_java_class', return_value=False
519  )
520  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
521  @mock.patch.object(
522      module_finder.ModuleFinder, '_is_vts_module', return_value=False
523  )
524  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
525  @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE)
526  @mock.patch.object(
527      test_filter_utils,
528      'get_fully_qualified_class_name',
529      return_value=uc.FULL_CLASS_NAME,
530  )
531  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
532  # pylint: disable=unused-argument
533  def test_find_test_by_module_and_class(
534      self,
535      _isfile,
536      _fqcn,
537      mock_checkoutput,
538      mock_build,
539      _vts,
540      _has_method_in_file,
541      _is_parameterized,
542      mock_parent_dir,
543  ):
544    """Test find_test_by_module_and_class."""
545    # Native test was tested in test_find_test_by_cc_class_name().
546    self.mod_finder.module_info.is_native_test.return_value = False
547    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
548    self.mod_finder.module_info.is_robolectric_test.return_value = False
549    self.mod_finder.module_info.has_test_config.return_value = True
550    mock_build.return_value = uc.CLASS_BUILD_TARGETS
551    mod_info = {
552        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
553        constants.MODULE_PATH: [uc.MODULE_DIR],
554        constants.MODULE_CLASS: [],
555        constants.MODULE_COMPATIBILITY_SUITES: [],
556    }
557    self.mod_finder.module_info.get_module_info.return_value = mod_info
558    self.mod_finder.module_info.get_robolectric_type.return_value = 0
559    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
560        {}
561    )
562    t_infos = self.mod_finder.find_test_by_module_and_class(MODULE_CLASS)
563    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO)
564    # with method
565    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
566    t_infos = self.mod_finder.find_test_by_module_and_class(MODULE_CLASS_METHOD)
567    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO)
568    self.mod_finder.module_info.is_testable_module.return_value = False
569    # bad module, good class, returns None
570    bad_module = '%s:%s' % ('BadMod', uc.CLASS_NAME)
571    self.mod_finder.module_info.get_module_info.return_value = None
572    self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_module))
573    # find output fails to find class file
574    mock_checkoutput.return_value = ''
575    bad_class = '%s:%s' % (uc.MODULE_NAME, 'Anything')
576    self.mod_finder.module_info.get_module_info.return_value = mod_info
577    self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_class))
578
579  @mock.patch.object(module_finder.test_finder_utils, 'get_cc_class_info')
580  @mock.patch.object(
581      module_finder.ModuleFinder,
582      'find_test_by_kernel_class_name',
583      return_value=None,
584  )
585  @mock.patch.object(
586      module_finder.ModuleFinder, '_is_vts_module', return_value=False
587  )
588  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
589  @mock.patch('subprocess.check_output', return_value=uc.FIND_CC_ONE)
590  @mock.patch.object(
591      test_finder_utils, 'find_class_file', side_effect=[None, None, '/']
592  )
593  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
594  # pylint: disable=unused-argument
595  def test_find_test_by_module_and_class_part_2(
596      self,
597      _isfile,
598      mock_fcf,
599      mock_checkoutput,
600      mock_build,
601      _vts,
602      _find_kernel,
603      _class_info,
604  ):
605    """Test find_test_by_module_and_class for MODULE:CC_CLASS."""
606    # Native test was tested in test_find_test_by_cc_class_name()
607    self.mod_finder.module_info.is_native_test.return_value = False
608    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
609    self.mod_finder.module_info.is_robolectric_test.return_value = False
610    self.mod_finder.module_info.has_test_config.return_value = True
611    self.mod_finder.module_info.get_paths.return_value = []
612    mock_build.return_value = uc.CLASS_BUILD_TARGETS
613    mod_info = {
614        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
615        constants.MODULE_PATH: [uc.CC_MODULE_DIR],
616        constants.MODULE_CLASS: [],
617        constants.MODULE_COMPATIBILITY_SUITES: [],
618    }
619    self.mod_finder.module_info.get_module_info.return_value = mod_info
620    _class_info.return_value = {
621        'PFTest': {
622            'methods': {'test1', 'test2'},
623            'prefixes': set(),
624            'typed': False,
625        }
626    }
627    self.mod_finder.module_info.get_robolectric_type.return_value = 0
628    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
629        {}
630    )
631    t_infos = self.mod_finder.find_test_by_module_and_class(CC_MODULE_CLASS)
632    unittest_utils.assert_equal_testinfos(
633        self, t_infos[0], uc.CC_MODULE_CLASS_INFO
634    )
635    # with method
636    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
637    mock_fcf.side_effect = [None, None, '/']
638    t_infos = self.mod_finder.find_test_by_module_and_class(
639        CC_MODULE_CLASS_METHOD
640    )
641    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD3_INFO)
642    # bad module, good class, returns None
643    bad_module = '%s:%s' % ('BadMod', uc.CC_CLASS_NAME)
644    self.mod_finder.module_info.get_module_info.return_value = None
645    self.mod_finder.module_info.is_testable_module.return_value = False
646    self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_module))
647
648  @mock.patch.object(
649      module_finder.ModuleFinder,
650      '_get_module_test_config',
651      return_value=[KERNEL_CONFIG_FILE],
652  )
653  @mock.patch.object(
654      module_finder.ModuleFinder, '_is_vts_module', return_value=False
655  )
656  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
657  @mock.patch('subprocess.check_output', return_value=uc.FIND_CC_ONE)
658  @mock.patch.object(
659      test_finder_utils, 'find_class_file', side_effect=[None, None, '/']
660  )
661  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
662  # pylint: disable=unused-argument
663  def test_find_test_by_module_and_class_for_kernel_test(
664      self, _isfile, mock_fcf, mock_checkoutput, mock_build, _vts, _test_config
665  ):
666    """Test find_test_by_module_and_class for MODULE:CC_CLASS."""
667    # Kernel test was tested in find_test_by_kernel_class_name()
668    self.mod_finder.module_info.is_native_test.return_value = False
669    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
670    self.mod_finder.module_info.is_robolectric_test.return_value = False
671    self.mod_finder.module_info.has_test_config.return_value = True
672    self.mod_finder.module_info.get_paths.return_value = []
673    mock_build.return_value = uc.CLASS_BUILD_TARGETS
674    mod_info = {
675        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
676        constants.MODULE_PATH: [uc.CC_MODULE_DIR],
677        constants.MODULE_CLASS: [],
678        constants.MODULE_COMPATIBILITY_SUITES: [],
679    }
680    self.mod_finder.module_info.get_module_info.return_value = mod_info
681    self.mod_finder.module_info.get_robolectric_type.return_value = 0
682    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
683        {}
684    )
685    t_infos = self.mod_finder.find_test_by_module_and_class(KERNEL_MODULE_CLASS)
686    unittest_utils.assert_equal_testinfos(
687        self, t_infos[0], KERNEL_MODULE_CLASS_INFO
688    )
689
690  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
691  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
692  @mock.patch.object(
693      module_finder.ModuleFinder, '_is_vts_module', return_value=False
694  )
695  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
696  @mock.patch('subprocess.check_output', return_value=uc.FIND_PKG)
697  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
698  @mock.patch('os.path.isdir', return_value=True)
699  # pylint: disable=unused-argument
700  def test_find_test_by_package_name(
701      self,
702      _isdir,
703      _isfile,
704      mock_checkoutput,
705      mock_build,
706      _vts,
707      _mock_unit_tests,
708      mods_to_test,
709  ):
710    """Test find_test_by_package_name."""
711    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
712    self.mod_finder.module_info.is_robolectric_test.return_value = False
713    self.mod_finder.module_info.has_test_config.return_value = True
714    mock_build.return_value = uc.CLASS_BUILD_TARGETS
715    self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
716    self.mod_finder.module_info.get_module_info.return_value = {
717        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
718        constants.MODULE_NAME: uc.MODULE_NAME,
719        constants.MODULE_CLASS: [],
720        constants.MODULE_COMPATIBILITY_SUITES: [],
721    }
722    self.mod_finder.module_info.get_robolectric_type.return_value = 0
723    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
724        {}
725    )
726    mods_to_test.return_value = [uc.MODULE_NAME]
727    t_infos = self.mod_finder.find_test_by_package_name(uc.PACKAGE)
728    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO)
729    # with method, should raise
730    pkg_with_method = '%s#%s' % (uc.PACKAGE, uc.METHOD_NAME)
731    self.assertRaises(
732        atest_error.MethodWithoutClassError,
733        self.mod_finder.find_test_by_package_name,
734        pkg_with_method,
735    )
736    # module and rel_config passed in
737    t_infos = self.mod_finder.find_test_by_package_name(
738        uc.PACKAGE, uc.MODULE_NAME, uc.CONFIG_FILE
739    )
740    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO)
741    # find output fails to find class file
742    mock_checkoutput.return_value = ''
743    self.assertIsNone(self.mod_finder.find_test_by_package_name('Not pkg'))
744
745  @mock.patch('os.path.isdir', return_value=False)
746  @mock.patch.object(
747      module_finder.ModuleFinder, '_is_vts_module', return_value=False
748  )
749  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
750  @mock.patch('subprocess.check_output', return_value=uc.FIND_PKG)
751  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
752  # pylint: disable=unused-argument
753  def test_find_test_by_module_and_package(
754      self, _isfile, mock_checkoutput, mock_build, _vts, _isdir
755  ):
756    """Test find_test_by_module_and_package."""
757    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
758    self.mod_finder.module_info.is_robolectric_test.return_value = False
759    self.mod_finder.module_info.has_test_config.return_value = True
760    self.mod_finder.module_info.get_paths.return_value = []
761    mock_build.return_value = uc.CLASS_BUILD_TARGETS
762    mod_info = {
763        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
764        constants.MODULE_PATH: [uc.MODULE_DIR],
765        constants.MODULE_CLASS: [],
766        constants.MODULE_COMPATIBILITY_SUITES: [],
767    }
768    self.mod_finder.module_info.get_module_info.return_value = mod_info
769    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
770        {}
771    )
772    t_infos = self.mod_finder.find_test_by_module_and_package(MODULE_PACKAGE)
773    self.assertEqual(t_infos, None)
774    _isdir.return_value = True
775    self.mod_finder.module_info.get_robolectric_type.return_value = 0
776    t_infos = self.mod_finder.find_test_by_module_and_package(MODULE_PACKAGE)
777    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO)
778
779    # with method, raises
780    module_pkg_with_method = '%s:%s#%s' % (
781        uc.MODULE2_NAME,
782        uc.PACKAGE,
783        uc.METHOD_NAME,
784    )
785    self.assertRaises(
786        atest_error.MethodWithoutClassError,
787        self.mod_finder.find_test_by_module_and_package,
788        module_pkg_with_method,
789    )
790    # bad module, good pkg, returns None
791    self.mod_finder.module_info.is_testable_module.return_value = False
792    bad_module = '%s:%s' % ('BadMod', uc.PACKAGE)
793    self.mod_finder.module_info.get_module_info.return_value = None
794    self.assertIsNone(
795        self.mod_finder.find_test_by_module_and_package(bad_module)
796    )
797    # find output fails to find package path
798    mock_checkoutput.return_value = ''
799    bad_pkg = '%s:%s' % (uc.MODULE_NAME, 'Anything')
800    self.mod_finder.module_info.get_module_info.return_value = mod_info
801    self.assertIsNone(self.mod_finder.find_test_by_module_and_package(bad_pkg))
802
803  # TODO: Move and rewite it to ModuleFinderFindTestByPath.
804  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
805  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
806  @mock.patch.object(test_finder_utils, 'get_cc_class_info', return_value={})
807  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
808  @mock.patch.object(
809      test_filter_utils, 'is_parameterized_java_class', return_value=False
810  )
811  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
812  @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True)
813  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
814  @mock.patch.object(
815      module_finder.ModuleFinder, '_is_vts_module', return_value=False
816  )
817  @mock.patch.object(
818      test_filter_utils,
819      'get_fully_qualified_class_name',
820      return_value=uc.FULL_CLASS_NAME,
821  )
822  @mock.patch(
823      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
824  )
825  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
826  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
827  @mock.patch('os.path.exists')
828  # pylint: disable=unused-argument
829  def test_find_test_by_path(
830      self,
831      mock_pathexists,
832      mock_dir,
833      _isfile,
834      _real,
835      _fqcn,
836      _vts,
837      mock_build,
838      _has_cc_class,
839      _has_method_in_file,
840      _is_parameterized,
841      _is_build_file,
842      _get_cc_class_info,
843      _mock_unit_tests,
844      mods_to_test,
845  ):
846    """Test find_test_by_path."""
847    self.mod_finder.module_info.is_robolectric_test.return_value = False
848    self.mod_finder.module_info.has_test_config.return_value = True
849    self.mod_finder.module_info.get_modules_by_include_deps.return_value = set()
850    mock_build.return_value = set()
851    mods_to_test.return_value = [uc.MODULE_NAME]
852    # Check that we don't return anything with invalid test references.
853    mock_pathexists.return_value = False
854    unittest_utils.assert_equal_testinfos(
855        self, None, self.mod_finder.find_test_by_path('bad/path')
856    )
857    mock_pathexists.return_value = True
858    mock_dir.return_value = None
859    unittest_utils.assert_equal_testinfos(
860        self, None, self.mod_finder.find_test_by_path('no/module')
861    )
862    self.mod_finder.module_info.get_module_info.return_value = {
863        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
864        constants.MODULE_NAME: uc.MODULE_NAME,
865        constants.MODULE_CLASS: [],
866        constants.MODULE_COMPATIBILITY_SUITES: [],
867    }
868
869    # Happy path testing.
870    mock_dir.return_value = uc.MODULE_DIR
871
872    class_path = '%s.kt' % uc.CLASS_NAME
873    mock_build.return_value = uc.CLASS_BUILD_TARGETS
874    self.mod_finder.module_info.get_robolectric_type.return_value = 0
875    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
876        {}
877    )
878    t_infos = self.mod_finder.find_test_by_path(class_path)
879    unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0])
880
881    class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME)
882    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
883    t_infos = self.mod_finder.find_test_by_path(class_with_method)
884    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO)
885
886    class_path = '%s.java' % uc.CLASS_NAME
887    mock_build.return_value = uc.CLASS_BUILD_TARGETS
888    t_infos = self.mod_finder.find_test_by_path(class_path)
889    unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0])
890
891    class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME)
892    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
893    t_infos = self.mod_finder.find_test_by_path(class_with_method)
894    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO)
895
896    class_with_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME)
897    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
898    t_infos = self.mod_finder.find_test_by_path(class_with_methods)
899    unittest_utils.assert_equal_testinfos(self, t_infos[0], FLAT_METHOD_INFO)
900
901    # Cc path testing.
902    mods_to_test.return_value = [uc.CC_MODULE_NAME]
903    self.mod_finder.module_info.get_module_info.return_value = {
904        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
905        constants.MODULE_NAME: uc.CC_MODULE_NAME,
906        constants.MODULE_CLASS: [],
907        constants.MODULE_COMPATIBILITY_SUITES: [],
908    }
909    mock_dir.return_value = uc.CC_MODULE_DIR
910    class_path = '%s' % uc.CC_PATH
911    mock_build.return_value = uc.CLASS_BUILD_TARGETS
912    t_infos = self.mod_finder.find_test_by_path(class_path)
913    unittest_utils.assert_equal_testinfos(self, uc.CC_PATH_INFO2, t_infos[0])
914
915  # TODO: Move and rewite it to ModuleFinderFindTestByPath.
916  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
917  @mock.patch.object(
918      module_finder.ModuleFinder,
919      '_get_build_targets',
920      return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS),
921  )
922  @mock.patch.object(
923      module_finder.ModuleFinder, '_is_vts_module', return_value=False
924  )
925  @mock.patch.object(
926      test_finder_utils,
927      'find_parent_module_dir',
928      return_value=os.path.relpath(uc.TEST_DATA_DIR, uc.ROOT),
929  )
930  # pylint: disable=unused-argument
931  def test_find_test_by_path_part_2(
932      self, _find_parent, _is_vts, _get_build, mods_to_test
933  ):
934    """Test find_test_by_path for directories."""
935    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
936    self.mod_finder.module_info.is_robolectric_test.return_value = False
937    self.mod_finder.module_info.has_test_config.return_value = True
938    # Dir with java files in it, should run as package
939    class_dir = os.path.join(uc.TEST_DATA_DIR, 'path_testing')
940    mods_to_test.return_value = [uc.MODULE_NAME]
941    self.mod_finder.module_info.get_module_info.return_value = {
942        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
943        constants.MODULE_NAME: uc.MODULE_NAME,
944        constants.MODULE_CLASS: [],
945        constants.MODULE_COMPATIBILITY_SUITES: [],
946    }
947    self.mod_finder.module_info.get_robolectric_type.return_value = 0
948    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
949        {}
950    )
951    t_infos = self.mod_finder.find_test_by_path(class_dir)
952    unittest_utils.assert_equal_testinfos(self, uc.PATH_INFO, t_infos[0])
953    # Dir with no java files in it, should run whole module
954    empty_dir = os.path.join(uc.TEST_DATA_DIR, 'path_testing_empty')
955    t_infos = self.mod_finder.find_test_by_path(empty_dir)
956    unittest_utils.assert_equal_testinfos(self, uc.EMPTY_PATH_INFO, t_infos[0])
957    # Dir with cc files in it, should run as cc class
958    class_dir = os.path.join(uc.TEST_DATA_DIR, 'cc_path_testing')
959    mods_to_test.return_value = [uc.CC_MODULE_NAME]
960    self.mod_finder.module_info.get_module_info.return_value = {
961        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
962        constants.MODULE_NAME: uc.CC_MODULE_NAME,
963        constants.MODULE_CLASS: [],
964        constants.MODULE_COMPATIBILITY_SUITES: [],
965    }
966    t_infos = self.mod_finder.find_test_by_path(class_dir)
967    unittest_utils.assert_equal_testinfos(self, uc.CC_PATH_INFO, t_infos[0])
968
969  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
970  @mock.patch.object(module_finder.test_finder_utils, 'get_cc_class_info')
971  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
972  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
973  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
974  @mock.patch.object(
975      module_finder.ModuleFinder, '_is_vts_module', return_value=False
976  )
977  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
978  @mock.patch('subprocess.check_output', return_value=uc.CC_FIND_ONE)
979  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
980  @mock.patch('os.path.isdir', return_value=True)
981  # pylint: disable=unused-argument
982  def test_find_test_by_cc_class_name(
983      self,
984      _isdir,
985      _isfile,
986      mock_checkoutput,
987      mock_build,
988      _vts,
989      _has_method,
990      _is_build_file,
991      _mock_unit_tests,
992      _class_info,
993      candicate_mods,
994  ):
995    """Test find_test_by_cc_class_name."""
996    mock_build.return_value = uc.CLASS_BUILD_TARGETS
997    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
998    self.mod_finder.module_info.is_robolectric_test.return_value = False
999    self.mod_finder.module_info.has_test_config.return_value = True
1000    candicate_mods.return_value = [uc.CC_MODULE_NAME]
1001    self.mod_finder.module_info.get_module_info.return_value = {
1002        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1003        constants.MODULE_NAME: uc.CC_MODULE_NAME,
1004        constants.MODULE_CLASS: [],
1005        constants.MODULE_COMPATIBILITY_SUITES: [],
1006    }
1007    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1008    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
1009        {}
1010    )
1011    _class_info.return_value = {
1012        'PFTest': {
1013            'methods': {'test1', 'test2'},
1014            'prefixes': set(),
1015            'typed': False,
1016        }
1017    }
1018    t_infos = self.mod_finder.find_test_by_cc_class_name(uc.CC_CLASS_NAME)
1019    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_CLASS_INFO)
1020
1021    # with method
1022    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
1023    class_with_method = '%s#%s' % (uc.CC_CLASS_NAME, uc.CC_METHOD_NAME)
1024    t_infos = self.mod_finder.find_test_by_cc_class_name(class_with_method)
1025    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD_INFO)
1026    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
1027    class_methods = '%s,%s' % (class_with_method, uc.CC_METHOD2_NAME)
1028    t_infos = self.mod_finder.find_test_by_cc_class_name(class_methods)
1029    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD2_INFO)
1030    # module and rel_config passed in
1031    mock_build.return_value = uc.CLASS_BUILD_TARGETS
1032    t_infos = self.mod_finder.find_test_by_cc_class_name(
1033        uc.CC_CLASS_NAME, uc.CC_MODULE_NAME, uc.CC_CONFIG_FILE
1034    )
1035    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_CLASS_INFO)
1036    # find output fails to find class file
1037    mock_checkoutput.return_value = ''
1038    self.assertIsNone(self.mod_finder.find_test_by_cc_class_name('Not class'))
1039    # class is outside given module path
1040    mock_checkoutput.return_value = uc.CC_FIND_ONE
1041    t_infos = self.mod_finder.find_test_by_cc_class_name(
1042        uc.CC_CLASS_NAME, uc.CC_MODULE2_NAME, uc.CC_CONFIG2_FILE
1043    )
1044    unittest_utils.assert_equal_testinfos(
1045        self, t_infos[0], CC_CLASS_INFO_MODULE_2
1046    )
1047
1048  def test_get_testable_modules_with_ld(self):
1049    """Test get_testable_modules_with_ld"""
1050    self.mod_finder.module_info.get_testable_modules.return_value = [
1051        uc.MODULE_NAME,
1052        uc.MODULE2_NAME,
1053    ]
1054    # Without a misfit constraint
1055    ld1 = self.mod_finder.get_testable_modules_with_ld(uc.TYPO_MODULE_NAME)
1056    self.assertEqual([[16, uc.MODULE2_NAME], [1, uc.MODULE_NAME]], ld1)
1057    # With a misfit constraint
1058    ld2 = self.mod_finder.get_testable_modules_with_ld(uc.TYPO_MODULE_NAME, 2)
1059    self.assertEqual([[1, uc.MODULE_NAME]], ld2)
1060
1061  def test_get_fuzzy_searching_modules(self):
1062    """Test get_fuzzy_searching_modules"""
1063    self.mod_finder.module_info.get_testable_modules.return_value = [
1064        uc.MODULE_NAME,
1065        uc.MODULE2_NAME,
1066    ]
1067    result = self.mod_finder.get_fuzzy_searching_results(uc.TYPO_MODULE_NAME)
1068    self.assertEqual(uc.MODULE_NAME, result[0])
1069
1070  def test_get_build_targets_w_vts_core(self):
1071    """Test _get_build_targets."""
1072    self.mod_finder.module_info.is_auto_gen_test_config.return_value = True
1073    self.mod_finder.module_info.get_paths.return_value = []
1074    mod_info = {
1075        constants.MODULE_COMPATIBILITY_SUITES: [constants.VTS_CORE_SUITE]
1076    }
1077    self.mod_finder.module_info.get_module_info.return_value = mod_info
1078    self.assertEqual(
1079        self.mod_finder._get_build_targets('', ''),
1080        {constants.VTS_CORE_TF_MODULE},
1081    )
1082
1083  def test_get_build_targets_w_mts(self):
1084    """Test _get_build_targets if module belong to mts."""
1085    self.mod_finder.module_info.is_auto_gen_test_config.return_value = True
1086    self.mod_finder.module_info.get_paths.return_value = []
1087    mod_info = {constants.MODULE_COMPATIBILITY_SUITES: [constants.MTS_SUITE]}
1088    self.mod_finder.module_info.get_module_info.return_value = mod_info
1089    self.assertEqual(
1090        self.mod_finder._get_build_targets('', ''), {constants.CTS_JAR}
1091    )
1092
1093  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
1094  @mock.patch.object(
1095      test_filter_utils, 'is_parameterized_java_class', return_value=False
1096  )
1097  @mock.patch.object(
1098      module_finder.ModuleFinder, '_is_vts_module', return_value=False
1099  )
1100  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
1101  @mock.patch('subprocess.check_output', return_value='')
1102  @mock.patch.object(
1103      test_filter_utils,
1104      'get_fully_qualified_class_name',
1105      return_value=uc.FULL_CLASS_NAME,
1106  )
1107  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
1108  @mock.patch('os.path.isdir', return_value=True)
1109  # pylint: disable=unused-argument
1110  def test_find_test_by_class_name_w_module(
1111      self,
1112      _isdir,
1113      _isfile,
1114      _fqcn,
1115      mock_checkoutput,
1116      mock_build,
1117      _vts,
1118      _is_parameterized,
1119      mods_to_test,
1120  ):
1121    """Test test_find_test_by_class_name with module but without class found."""
1122    mock_build.return_value = uc.CLASS_BUILD_TARGETS
1123    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
1124    self.mod_finder.module_info.is_robolectric_test.return_value = False
1125    self.mod_finder.module_info.has_test_config.return_value = True
1126    mods_to_test.return_value = [uc.MODULE_NAME]
1127    self.mod_finder.module_info.get_module_info.return_value = {
1128        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1129        constants.MODULE_NAME: uc.MODULE_NAME,
1130        constants.MODULE_CLASS: [],
1131        constants.MODULE_COMPATIBILITY_SUITES: [],
1132    }
1133    self.mod_finder.module_info.get_paths.return_value = [uc.TEST_DATA_CONFIG]
1134    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1135    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
1136        {}
1137    )
1138    t_infos = self.mod_finder.find_test_by_class_name(
1139        uc.FULL_CLASS_NAME,
1140        module_name=uc.MODULE_NAME,
1141        rel_config=uc.CONFIG_FILE,
1142    )
1143    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO)
1144
1145  @mock.patch.object(
1146      module_finder.ModuleFinder, '_is_vts_module', return_value=False
1147  )
1148  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
1149  @mock.patch('subprocess.check_output', return_value='')
1150  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
1151  @mock.patch('os.path.isdir', return_value=True)
1152  # pylint: disable=unused-argument
1153  def test_find_test_by_package_name_w_module(
1154      self, _isdir, _isfile, mock_checkoutput, mock_build, _vts
1155  ):
1156    """Test find_test_by_package_name with module but without package found."""
1157    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
1158    self.mod_finder.module_info.is_robolectric_test.return_value = False
1159    self.mod_finder.module_info.has_test_config.return_value = True
1160    mock_build.return_value = uc.CLASS_BUILD_TARGETS
1161    self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
1162    self.mod_finder.module_info.get_module_info.return_value = {
1163        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1164        constants.MODULE_NAME: uc.MODULE_NAME,
1165        constants.MODULE_CLASS: [],
1166        constants.MODULE_COMPATIBILITY_SUITES: [],
1167    }
1168    self.mod_finder.module_info.get_paths.return_value = [uc.TEST_DATA_CONFIG]
1169    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1170    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
1171        {}
1172    )
1173    t_infos = self.mod_finder.find_test_by_package_name(
1174        uc.PACKAGE, module_name=uc.MODULE_NAME, rel_config=uc.CONFIG_FILE
1175    )
1176    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO)
1177
1178  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
1179  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
1180  @mock.patch.object(
1181      test_filter_utils, 'is_parameterized_java_class', return_value=True
1182  )
1183  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
1184  @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True)
1185  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
1186  @mock.patch.object(
1187      module_finder.ModuleFinder, '_is_vts_module', return_value=False
1188  )
1189  @mock.patch.object(
1190      test_filter_utils,
1191      'get_fully_qualified_class_name',
1192      return_value=uc.FULL_CLASS_NAME,
1193  )
1194  @mock.patch(
1195      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
1196  )
1197  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
1198  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
1199  @mock.patch('os.path.exists')
1200  # pylint: disable=unused-argument
1201  def test_find_test_by_path_is_parameterized_java(
1202      self,
1203      mock_pathexists,
1204      mock_dir,
1205      _isfile,
1206      _real,
1207      _fqcn,
1208      _vts,
1209      mock_build,
1210      _has_cc_class,
1211      _has_method_in_file,
1212      _is_parameterized,
1213      _is_build_file,
1214      mods_to_test,
1215  ):
1216    """Test find_test_by_path and input path is parameterized class."""
1217    self.mod_finder.module_info.is_robolectric_test.return_value = False
1218    self.mod_finder.module_info.has_test_config.return_value = True
1219    mock_build.return_value = set()
1220    mock_pathexists.return_value = True
1221    mods_to_test.return_value = [uc.MODULE_NAME]
1222    self.mod_finder.module_info.get_module_info.return_value = {
1223        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1224        constants.MODULE_NAME: uc.MODULE_NAME,
1225        constants.MODULE_CLASS: [],
1226        constants.MODULE_COMPATIBILITY_SUITES: [],
1227    }
1228    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1229    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
1230        {}
1231    )
1232    # Happy path testing.
1233    mock_dir.return_value = uc.MODULE_DIR
1234    class_path = '%s.java' % uc.CLASS_NAME
1235    # Input include only one method
1236    class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME)
1237    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
1238    t_infos = self.mod_finder.find_test_by_path(class_with_method)
1239    unittest_utils.assert_equal_testinfos(
1240        self, t_infos[0], uc.PARAMETERIZED_METHOD_INFO
1241    )
1242    # Input include multiple methods
1243    class_with_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME)
1244    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
1245    t_infos = self.mod_finder.find_test_by_path(class_with_methods)
1246    unittest_utils.assert_equal_testinfos(
1247        self, t_infos[0], uc.PARAMETERIZED_FLAT_METHOD_INFO
1248    )
1249
1250  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
1251  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
1252  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
1253  @mock.patch.object(
1254      test_filter_utils, 'is_parameterized_java_class', return_value=True
1255  )
1256  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
1257  @mock.patch.object(
1258      module_finder.ModuleFinder, '_is_vts_module', return_value=False
1259  )
1260  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
1261  @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE)
1262  @mock.patch.object(
1263      test_filter_utils,
1264      'get_fully_qualified_class_name',
1265      return_value=uc.FULL_CLASS_NAME,
1266  )
1267  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
1268  @mock.patch('os.path.isdir', return_value=True)
1269  # pylint: disable=unused-argument
1270  def test_find_test_by_class_name_is_parameterized(
1271      self,
1272      _isdir,
1273      _isfile,
1274      _fqcn,
1275      mock_checkoutput,
1276      mock_build,
1277      _vts,
1278      _has_method_in_file,
1279      _is_parameterized,
1280      _is_build_file,
1281      _mock_unit_tests,
1282      mods_to_test,
1283  ):
1284    """Test find_test_by_class_name and the class is parameterized java."""
1285    mock_build.return_value = uc.CLASS_BUILD_TARGETS
1286    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
1287    self.mod_finder.module_info.is_robolectric_test.return_value = False
1288    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
1289        {}
1290    )
1291    self.mod_finder.module_info.has_test_config.return_value = True
1292    mods_to_test.return_value = [uc.MODULE_NAME]
1293    self.mod_finder.module_info.get_module_info.return_value = {
1294        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1295        constants.MODULE_NAME: uc.MODULE_NAME,
1296        constants.MODULE_CLASS: [],
1297        constants.MODULE_COMPATIBILITY_SUITES: [],
1298    }
1299    # With method
1300    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
1301    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1302    class_with_method = '%s#%s' % (uc.CLASS_NAME, uc.METHOD_NAME)
1303    t_infos = self.mod_finder.find_test_by_class_name(class_with_method)
1304    unittest_utils.assert_equal_testinfos(
1305        self, t_infos[0], uc.PARAMETERIZED_METHOD_INFO
1306    )
1307    # With multiple method
1308    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
1309    class_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME)
1310    t_infos = self.mod_finder.find_test_by_class_name(class_methods)
1311    unittest_utils.assert_equal_testinfos(
1312        self, t_infos[0], uc.PARAMETERIZED_FLAT_METHOD_INFO
1313    )
1314
1315  # pylint: disable=unused-argument
1316  @mock.patch.object(
1317      module_finder.ModuleFinder,
1318      '_get_build_targets',
1319      return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS),
1320  )
1321  def test_find_test_by_config_name(self, _get_targ):
1322    """Test find_test_by_config_name."""
1323    self.mod_finder.module_info.is_robolectric_test.return_value = False
1324    self.mod_finder.module_info.has_test_config.return_value = True
1325
1326    mod_info = {
1327        'installed': ['/path/to/install'],
1328        'path': [uc.MODULE_DIR],
1329        constants.MODULE_TEST_CONFIG: [uc.CONFIG_FILE, uc.EXTRA_CONFIG_FILE],
1330        constants.MODULE_CLASS: [],
1331        constants.MODULE_COMPATIBILITY_SUITES: [],
1332    }
1333    name_to_module_info = {uc.MODULE_NAME: mod_info}
1334    self.mod_finder.module_info.name_to_module_info = name_to_module_info
1335    t_infos = self.mod_finder.find_test_by_config_name(uc.MODULE_CONFIG_NAME)
1336    unittest_utils.assert_equal_testinfos(
1337        self, t_infos[0], uc.TEST_CONFIG_MODULE_INFO
1338    )
1339
1340  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
1341  @mock.patch.object(
1342      test_filter_utils, 'is_parameterized_java_class', return_value=False
1343  )
1344  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
1345  @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True)
1346  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
1347  @mock.patch.object(
1348      module_finder.ModuleFinder, '_is_vts_module', return_value=False
1349  )
1350  @mock.patch.object(
1351      test_filter_utils,
1352      'get_fully_qualified_class_name',
1353      return_value=uc.FULL_CLASS_NAME,
1354  )
1355  @mock.patch(
1356      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
1357  )
1358  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
1359  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
1360  @mock.patch('os.path.exists')
1361  # pylint: disable=unused-argument
1362  def test_find_test_by_path_w_src_verify(
1363      self,
1364      mock_pathexists,
1365      mock_dir,
1366      _isfile,
1367      _real,
1368      _fqcn,
1369      _vts,
1370      mock_build,
1371      _has_cc_class,
1372      _has_method_in_file,
1373      _is_parameterized,
1374      mods_to_test,
1375  ):
1376    """Test find_test_by_path with src information."""
1377    self.mod_finder.module_info.is_robolectric_test.return_value = False
1378    self.mod_finder.module_info.has_test_config.return_value = True
1379    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1380    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
1381        {}
1382    )
1383    mods_to_test.return_value = [uc.MODULE_NAME]
1384    mock_build.return_value = uc.CLASS_BUILD_TARGETS
1385
1386    # Happy path testing.
1387    mock_dir.return_value = uc.MODULE_DIR
1388    # Test path not in module's `srcs` but `path`.
1389    class_path = f'somewhere/to/module/{uc.CLASS_NAME}.java'
1390    self.mod_finder.module_info.get_module_info.return_value = {
1391        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1392        constants.MODULE_NAME: uc.MODULE_NAME,
1393        constants.MODULE_CLASS: [],
1394        constants.MODULE_PATH: ['somewhere/to/module'],
1395        constants.MODULE_TEST_CONFIG: [uc.CONFIG_FILE],
1396        constants.MODULE_COMPATIBILITY_SUITES: [],
1397        constants.MODULE_SRCS: [],
1398    }
1399    t_infos = self.mod_finder.find_test_by_path(class_path)
1400    unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0])
1401
1402    # Test input file is in module's `srcs`.
1403    class_path = '%s.java' % uc.CLASS_NAME
1404    self.mod_finder.module_info.get_module_info.return_value = {
1405        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1406        constants.MODULE_NAME: uc.MODULE_NAME,
1407        constants.MODULE_CLASS: [],
1408        constants.MODULE_COMPATIBILITY_SUITES: [],
1409        constants.MODULE_SRCS: [class_path],
1410    }
1411
1412    t_infos = self.mod_finder.find_test_by_path(class_path)
1413    unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0])
1414
1415  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
1416  @mock.patch.object(test_finder_utils, 'get_cc_class_info')
1417  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
1418  @mock.patch.object(
1419      test_filter_utils, 'is_parameterized_java_class', return_value=False
1420  )
1421  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
1422  @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True)
1423  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
1424  @mock.patch.object(
1425      module_finder.ModuleFinder, '_is_vts_module', return_value=False
1426  )
1427  @mock.patch.object(
1428      test_filter_utils,
1429      'get_fully_qualified_class_name',
1430      return_value=uc.FULL_CLASS_NAME,
1431  )
1432  @mock.patch(
1433      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
1434  )
1435  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
1436  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
1437  @mock.patch('os.path.exists')
1438  # pylint: disable=unused-argument
1439  def test_find_test_by_path_for_cc_file(
1440      self,
1441      mock_pathexists,
1442      mock_dir,
1443      _isfile,
1444      _real,
1445      _fqcn,
1446      _vts,
1447      mock_build,
1448      _has_cc_class,
1449      _has_method_in_file,
1450      _is_parameterized,
1451      _is_build_file,
1452      _mock_cc_class_info,
1453      mods_to_test,
1454  ):
1455    """Test find_test_by_path for handling correct CC filter."""
1456    self.mod_finder.module_info.is_robolectric_test.return_value = False
1457    self.mod_finder.module_info.has_test_config.return_value = True
1458    mock_build.return_value = set()
1459    # Check that we don't return anything with invalid test references.
1460    mock_pathexists.return_value = False
1461    mock_pathexists.return_value = True
1462    mock_dir.return_value = None
1463    mods_to_test.return_value = [uc.MODULE_NAME]
1464    self.mod_finder.module_info.get_module_info.return_value = {
1465        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1466        constants.MODULE_NAME: uc.MODULE_NAME,
1467        constants.MODULE_CLASS: [],
1468        constants.MODULE_COMPATIBILITY_SUITES: [],
1469    }
1470    # Happy path testing.
1471    mock_dir.return_value = uc.MODULE_DIR
1472    # Cc path testing if get_cc_class_info found those information.
1473    mods_to_test.return_value = [uc.CC_MODULE_NAME]
1474    self.mod_finder.module_info.get_module_info.return_value = {
1475        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
1476        constants.MODULE_NAME: uc.CC_MODULE_NAME,
1477        constants.MODULE_CLASS: [],
1478        constants.MODULE_COMPATIBILITY_SUITES: [],
1479    }
1480    mock_dir.return_value = uc.CC_MODULE_DIR
1481    class_path = '%s' % uc.CC_PATH
1482    mock_build.return_value = uc.CLASS_BUILD_TARGETS
1483    # Test without parameterized test
1484    founded_classed = 'class1'
1485    founded_methods = {'method1'}
1486    founded_prefixes = set()
1487    _mock_cc_class_info.return_value = {
1488        founded_classed: {
1489            'methods': founded_methods,
1490            'prefixes': founded_prefixes,
1491            'typed': False,
1492        }
1493    }
1494    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1495    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
1496        {}
1497    )
1498    cc_path_data = {
1499        constants.TI_REL_CONFIG: uc.CC_CONFIG_FILE,
1500        constants.TI_FILTER: frozenset(
1501            {test_info.TestFilter(class_name='class1.*', methods=frozenset())}
1502        ),
1503    }
1504    cc_path_info = test_info.TestInfo(
1505        uc.CC_MODULE_NAME,
1506        atf_tr.AtestTradefedTestRunner.NAME,
1507        uc.CLASS_BUILD_TARGETS,
1508        cc_path_data,
1509    )
1510    t_infos = self.mod_finder.find_test_by_path(class_path)
1511    unittest_utils.assert_equal_testinfos(self, cc_path_info, t_infos[0])
1512    # Test with parameterize test defined in input path
1513    founded_prefixes = {'class1'}
1514    _mock_cc_class_info.return_value = {
1515        founded_classed: {
1516            'methods': founded_methods,
1517            'prefixes': founded_prefixes,
1518            'typed': False,
1519        }
1520    }
1521    cc_path_data = {
1522        constants.TI_REL_CONFIG: uc.CC_CONFIG_FILE,
1523        constants.TI_FILTER: frozenset(
1524            {test_info.TestFilter(class_name='*/class1.*', methods=frozenset())}
1525        ),
1526    }
1527    cc_path_info = test_info.TestInfo(
1528        uc.CC_MODULE_NAME,
1529        atf_tr.AtestTradefedTestRunner.NAME,
1530        uc.CLASS_BUILD_TARGETS,
1531        cc_path_data,
1532    )
1533    t_infos = self.mod_finder.find_test_by_path(class_path)
1534    unittest_utils.assert_equal_testinfos(self, cc_path_info, t_infos[0])
1535
1536  # pylint: disable=unused-argument
1537  @mock.patch.object(
1538      module_finder.ModuleFinder, '_is_vts_module', return_value=False
1539  )
1540  @mock.patch.object(
1541      module_finder.ModuleFinder,
1542      '_get_build_targets',
1543      return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS),
1544  )
1545  def test_process_test_info(self, _get_targ, _is_vts):
1546    """Test _process_test_info."""
1547    mod_info = {
1548        'installed': ['/path/to/install'],
1549        'path': [uc.MODULE_DIR],
1550        constants.MODULE_CLASS: [constants.MODULE_CLASS_JAVA_LIBRARIES],
1551        constants.MODULE_COMPATIBILITY_SUITES: [],
1552    }
1553    self.mod_finder.module_info.is_robolectric_test.return_value = False
1554    self.mod_finder.module_info.is_auto_gen_test_config.return_value = True
1555    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1556    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
1557        {}
1558    )
1559    self.mod_finder.module_info.get_module_info.return_value = mod_info
1560    processed_info = self.mod_finder._process_test_info(
1561        copy.deepcopy(uc.MODULE_INFO)
1562    )
1563    unittest_utils.assert_equal_testinfos(
1564        self, processed_info, uc.MODULE_INFO_W_DALVIK
1565    )
1566
1567  # pylint: disable=unused-argument
1568  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
1569  @mock.patch.object(module_info.ModuleInfo, 'get_instrumentation_target_apps')
1570  @mock.patch.object(module_info.ModuleInfo, 'get_robolectric_type')
1571  @mock.patch.object(module_info.ModuleInfo, 'is_testable_module')
1572  def test_process_test_info_with_instrumentation_target_apps(
1573      self, testable, robotype, tapps, btargets
1574  ):
1575    """Test _process_test_info."""
1576    testable.return_value = True
1577    robotype.return_value = 0
1578    target_module = 'AmSlam'
1579    test_module = 'AmSlamTests'
1580    artifact_path = '/out/somewhere/app/AmSlam.apk'
1581    tapps.return_value = {target_module: {artifact_path}}
1582    btargets.return_value = {target_module}
1583    self.mod_finder.module_info.is_auto_gen_test_config.return_value = True
1584    self.mod_finder.module_info.get_robolectric_type.return_value = 0
1585    test1 = module(
1586        name=target_module,
1587        classes=['APPS'],
1588        path=['foo/bar/AmSlam'],
1589        installed=[artifact_path],
1590    )
1591    test2 = module(
1592        name=test_module,
1593        classes=['APPS'],
1594        path=['foo/bar/AmSlam/test'],
1595        installed=['/out/somewhere/app/AmSlamTests.apk'],
1596    )
1597    info = test_info.TestInfo(
1598        test_module,
1599        atf_tr.AtestTradefedTestRunner.NAME,
1600        set(),
1601        {
1602            constants.TI_REL_CONFIG: uc.CONFIG_FILE,
1603            constants.TI_FILTER: frozenset(),
1604        },
1605    )
1606
1607    self.mod_finder.module_info = create_module_info([test1, test2])
1608    t_infos = self.mod_finder._process_test_info(info)
1609
1610    self.assertTrue(target_module in t_infos.build_targets)
1611    self.assertEqual([artifact_path], t_infos.artifacts)
1612
1613  @mock.patch.object(test_finder_utils, 'get_annotated_methods')
1614  def test_is_srcs_match_method_annotation_include_anno(
1615      self, _mock_get_anno_methods
1616  ):
1617    """Test _is_srcs_match_method_annotation with include annotation."""
1618    annotation_dict = {constants.INCLUDE_ANNOTATION: 'includeAnnotation1'}
1619    input_method = 'my_input_method'
1620    input_srcs = ['src1']
1621    # Test if input method matched include annotation.
1622    _mock_get_anno_methods.return_value = {input_method, 'not_my_input_method'}
1623
1624    is_matched = self.mod_finder._is_srcs_match_method_annotation(
1625        input_method, input_srcs, annotation_dict
1626    )
1627
1628    self.assertTrue(is_matched)
1629    # Test if input method not matched include annotation.
1630    _mock_get_anno_methods.return_value = {'not_my_input_method'}
1631
1632    is_matched = self.mod_finder._is_srcs_match_method_annotation(
1633        input_method, input_srcs, annotation_dict
1634    )
1635
1636    self.assertFalse(is_matched)
1637
1638  @mock.patch.object(test_finder_utils, 'get_annotated_methods')
1639  @mock.patch.object(test_finder_utils, 'get_java_methods')
1640  def test_is_srcs_match_method_exclude_anno(
1641      self, _mock_get_java_methods, _mock_get_exclude_anno_methods
1642  ):
1643    """Test _is_srcs_match_method_annotation with exclude annotation."""
1644    annotation_dict = {constants.EXCLUDE_ANNOTATION: 'excludeAnnotation1'}
1645    input_method = 'my_input_method'
1646    input_srcs = ['src1']
1647    _mock_get_java_methods.return_value = {input_method, 'method1', 'method2'}
1648    # Test if input method matched exclude annotation.
1649    _mock_get_exclude_anno_methods.return_value = {input_method, 'method1'}
1650
1651    is_matched = self.mod_finder._is_srcs_match_method_annotation(
1652        input_method, input_srcs, annotation_dict
1653    )
1654
1655    self.assertFalse(is_matched)
1656
1657    # Test if input method not matched exclude annotation.
1658    _mock_get_exclude_anno_methods.return_value = {'method2'}
1659
1660    is_matched = self.mod_finder._is_srcs_match_method_annotation(
1661        input_method, input_srcs, annotation_dict
1662    )
1663
1664    self.assertTrue(is_matched)
1665
1666  @mock.patch.object(atest_utils, 'get_android_junit_config_filters')
1667  @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs')
1668  def test_get_matched_test_infos_no_filter(
1669      self, _mock_get_conf_srcs, _mock_get_filters
1670  ):
1671    """Test _get_matched_test_infos without test filters."""
1672    test_info1 = 'test_info1'
1673    test_infos = [test_info1]
1674    test_config = 'test_config'
1675    test_srcs = ['src1', 'src2']
1676    _mock_get_conf_srcs.return_value = test_config, test_srcs
1677    filter_dict = {}
1678    _mock_get_filters.return_value = filter_dict
1679
1680    self.assertEqual(
1681        self.mod_finder._get_matched_test_infos(test_infos, {'method'}),
1682        test_infos,
1683    )
1684
1685  @mock.patch.object(
1686      module_finder.ModuleFinder, '_is_srcs_match_method_annotation'
1687  )
1688  @mock.patch.object(atest_utils, 'get_android_junit_config_filters')
1689  @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs')
1690  def test_get_matched_test_infos_get_filter_method_match(
1691      self, _mock_get_conf_srcs, _mock_get_filters, _mock_method_match
1692  ):
1693    """Test _get_matched_test_infos with test filters and method match."""
1694    test_infos = [KERNEL_MODULE_CLASS_INFO]
1695    test_config = 'test_config'
1696    test_srcs = ['src1', 'src2']
1697    _mock_get_conf_srcs.return_value = test_config, test_srcs
1698    filter_dict = {'include-annotation': 'annotate1'}
1699    _mock_get_filters.return_value = filter_dict
1700    _mock_method_match.return_value = True
1701
1702    unittest_utils.assert_strict_equal(
1703        self,
1704        self.mod_finder._get_matched_test_infos(test_infos, {'method'}),
1705        test_infos,
1706    )
1707
1708  @mock.patch.object(
1709      module_finder.ModuleFinder, '_is_srcs_match_method_annotation'
1710  )
1711  @mock.patch.object(atest_utils, 'get_android_junit_config_filters')
1712  @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs')
1713  def test_get_matched_test_infos_filter_method_not_match(
1714      self, _mock_get_conf_srcs, _mock_get_filters, _mock_method_match
1715  ):
1716    """Test _get_matched_test_infos but method not match."""
1717    test_infos = [KERNEL_MODULE_CLASS_INFO]
1718    test_config = 'test_config'
1719    test_srcs = ['src1', 'src2']
1720    _mock_get_conf_srcs.return_value = test_config, test_srcs
1721    filter_dict = {'include-annotation': 'annotate1'}
1722    _mock_get_filters.return_value = filter_dict
1723    _mock_method_match.return_value = False
1724
1725    self.assertEqual(
1726        self.mod_finder._get_matched_test_infos(test_infos, {'method'}), []
1727    )
1728
1729  @mock.patch.object(module_finder.ModuleFinder, '_get_matched_test_infos')
1730  @mock.patch.object(
1731      module_finder.ModuleFinder, '_get_test_infos', return_value=uc.MODULE_INFO
1732  )
1733  @mock.patch.object(
1734      module_finder.ModuleFinder,
1735      '_get_test_info_filter',
1736      return_value=uc.CLASS_FILTER,
1737  )
1738  @mock.patch.object(
1739      test_finder_utils, 'find_class_file', return_value=['path1']
1740  )
1741  def test_find_test_by_class_name_not_matched_filters(
1742      self,
1743      _mock_class_path,
1744      _mock_test_filters,
1745      _mock_test_infos,
1746      _mock_matched_test_infos,
1747  ):
1748    """Test find_test_by_class_name which has not matched filters."""
1749    found_test_infos = [uc.MODULE_INFO, uc.MODULE_INFO2]
1750    _mock_test_infos.return_value = found_test_infos
1751    matched_test_infos = [uc.MODULE_INFO2]
1752    _mock_matched_test_infos.return_value = matched_test_infos
1753
1754    # Test if class without method
1755    test_infos = self.mod_finder.find_test_by_class_name('my.test.class')
1756    self.assertEqual(len(test_infos), 2)
1757    unittest_utils.assert_equal_testinfos(self, test_infos[0], uc.MODULE_INFO)
1758    unittest_utils.assert_equal_testinfos(self, test_infos[1], uc.MODULE_INFO2)
1759
1760    # Test if class with method
1761    test_infos = self.mod_finder.find_test_by_class_name(
1762        'my.test.class#myMethod'
1763    )
1764    self.assertEqual(len(test_infos), 1)
1765    unittest_utils.assert_equal_testinfos(self, test_infos[0], uc.MODULE_INFO2)
1766
1767  @mock.patch.object(
1768      module_finder.ModuleFinder, '_get_test_infos', return_value=None
1769  )
1770  @mock.patch.object(
1771      module_finder.ModuleFinder,
1772      '_get_test_info_filter',
1773      return_value=uc.CLASS_FILTER,
1774  )
1775  @mock.patch.object(
1776      test_finder_utils, 'find_class_file', return_value=['path1']
1777  )
1778  def test_find_test_by_class_name_get_test_infos_none(
1779      self, _mock_class_path, _mock_test_filters, _mock_test_infos
1780  ):
1781    """Test find_test_by_class_name which has not matched test infos."""
1782    self.assertEqual(
1783        self.mod_finder.find_test_by_class_name('my.test.class'), None
1784    )
1785
1786
1787def create_empty_module_info():
1788  with fake_filesystem_unittest.Patcher() as patcher:
1789    # pylint: disable=protected-access
1790    fake_temp_file_name = next(tempfile._get_candidate_names())
1791    patcher.fs.create_file(fake_temp_file_name, contents='{}')
1792    return module_info.load_from_file(module_file=fake_temp_file_name)
1793
1794
1795def create_module_info(modules=None):
1796  name_to_module_info = {}
1797  modules = modules or []
1798
1799  for m in modules:
1800    name_to_module_info[m['module_name']] = m
1801
1802  return module_info.load_from_dict(name_to_module_info)
1803
1804
1805# pylint: disable=too-many-arguments
1806def module(
1807    name=None,
1808    path=None,
1809    installed=None,
1810    classes=None,
1811    auto_test_config=None,
1812    shared_libs=None,
1813    dependencies=None,
1814    runtime_dependencies=None,
1815    data=None,
1816    data_dependencies=None,
1817    compatibility_suites=None,
1818    host_dependencies=None,
1819    srcs=None,
1820):
1821  name = name or 'libhello'
1822
1823  m = {}
1824
1825  m['module_name'] = name
1826  m['class'] = classes
1827  m['path'] = path or ['']
1828  m['installed'] = installed or []
1829  m['is_unit_test'] = 'false'
1830  m['auto_test_config'] = auto_test_config or []
1831  m['shared_libs'] = shared_libs or []
1832  m['runtime_dependencies'] = runtime_dependencies or []
1833  m['dependencies'] = dependencies or []
1834  m['data'] = data or []
1835  m['data_dependencies'] = data_dependencies or []
1836  m['compatibility_suites'] = compatibility_suites or []
1837  m['host_dependencies'] = host_dependencies or []
1838  m['srcs'] = srcs or []
1839  return m
1840
1841
1842# pylint: disable=too-many-locals
1843def create_test_info(**kwargs):
1844  test_name = kwargs.pop('test_name')
1845  test_runner = kwargs.pop('test_runner')
1846  build_targets = kwargs.pop('build_targets')
1847  data = kwargs.pop('data', None)
1848  suite = kwargs.pop('suite', None)
1849  module_class = kwargs.pop('module_class', None)
1850  install_locations = kwargs.pop('install_locations', None)
1851  test_finder = kwargs.pop('test_finder', '')
1852  compatibility_suites = kwargs.pop('compatibility_suites', None)
1853
1854  t_info = test_info.TestInfo(
1855      test_name=test_name,
1856      test_runner=test_runner,
1857      build_targets=build_targets,
1858      data=data,
1859      suite=suite,
1860      module_class=module_class,
1861      install_locations=install_locations,
1862      test_finder=test_finder,
1863      compatibility_suites=compatibility_suites,
1864  )
1865  raw_test_name = kwargs.pop('raw_test_name', None)
1866  if raw_test_name:
1867    t_info.raw_test_name = raw_test_name
1868  artifacts = kwargs.pop('artifacts', set())
1869  if artifacts:
1870    t_info.artifacts = artifacts
1871  robo_type = kwargs.pop('robo_type', None)
1872  if robo_type:
1873    t_info.robo_type = robo_type
1874  mainline_modules = kwargs.pop('mainline_modules', set())
1875  if mainline_modules:
1876    t_info._mainline_modules = mainline_modules
1877  for keyword in ['from_test_mapping', 'host', 'aggregate_metrics_result']:
1878    value = kwargs.pop(keyword, 'None')
1879    if isinstance(value, bool):
1880      setattr(t_info, keyword, value)
1881  if kwargs:
1882    assert f'Unknown keyword(s) for test_info: {kwargs.keys()}'
1883  return t_info
1884
1885
1886if __name__ == '__main__':
1887  unittest.main()
1888