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