Atest: new --list-module/-L argument for *ts.
This CL responds the users who'd like to list testable modules
by suite name on atest. Now atest provides a "--list-modules"
argument which behaves the same as running *ts-tradefed list modules.
Refactor below methods from module_finder to module_info.py.
* is_testable_module
* has_test_config
* get_robolectric_test_name
* is_robolectric_test
* is_auto_gen_test_config
Add new methods in module-info.py.
* get_testable_modules
This could also be benefit for tab_completion.
Bug: b/122353423
Test: atest --list-modules cts
atest --list-modules vts
Make sure the results be consistent with *ts-tradefed.
Change-Id: I76a60e1142cd5e3d6d38d37bebb8d57c45ffc5e2
diff --git a/atest/atest.py b/atest/atest.py
index 30adfa3..4a83201 100755
--- a/atest/atest.py
+++ b/atest/atest.py
@@ -485,7 +485,6 @@
results_dir: Path for saving atest logs.
extra_args: Dict of extra args for test runners to utilize.
test_infos: A list of TestInfos.
-
"""
for test_runner, tests in test_runner_handler.group_tests_by_test_runners(test_infos):
runner = test_runner(results_dir)
@@ -494,6 +493,19 @@
print('Would run test via command: %s'
% (atest_utils.colorize(run_cmd, constants.GREEN)))
+def _print_testable_modules(mod_info, suite):
+ """Print the testable modules for a given suite.
+
+ Args:
+ mod_info: ModuleInfo object.
+ suite: A string of suite name.
+ """
+ testable_modules = mod_info.get_testable_modules(suite)
+ print('\n%s' % atest_utils.colorize('%s Testable %s modules' % (
+ len(testable_modules), suite), constants.CYAN))
+ print('-------')
+ for module in sorted(testable_modules):
+ print('\t%s' % module)
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
@@ -520,29 +532,26 @@
results_dir = make_test_run_dir()
mod_info = module_info.ModuleInfo(force_build=args.rebuild_module_info)
translator = cli_translator.CLITranslator(module_info=mod_info)
+ if args.list_modules:
+ _print_testable_modules(mod_info, args.list_modules)
+ return constants.EXIT_CODE_SUCCESS
build_targets = set()
test_infos = set()
if _will_run_tests(args):
build_targets, test_infos = translator.translate(args)
if not test_infos:
- if SEND_CC_LOG:
- metrics_utils.send_exit_event(constants.EXIT_CODE_TEST_NOT_FOUND)
return constants.EXIT_CODE_TEST_NOT_FOUND
if not is_from_test_mapping(test_infos):
_validate_exec_mode(args, test_infos)
else:
_validate_tm_tests_exec_mode(args, test_infos)
if args.info:
- if SEND_CC_LOG:
- metrics_utils.send_exit_event(constants.EXIT_CODE_SUCCESS)
return _print_test_info(mod_info, test_infos)
build_targets |= test_runner_handler.get_test_runner_reqs(mod_info,
test_infos)
extra_args = get_extra_args(args)
if args.dry_run:
_dry_run(results_dir, extra_args, test_infos)
- if SEND_CC_LOG:
- metrics_utils.send_exit_event(constants.EXIT_CODE_SUCCESS)
return constants.EXIT_CODE_SUCCESS
if args.detect_regression:
@@ -556,8 +565,6 @@
build_targets.add(mod_info.module_info_target)
success = atest_utils.build(build_targets, args.verbose)
if not success:
- if SEND_CC_LOG:
- metrics_utils.send_exit_event(constants.EXIT_CODE_BUILD_FAILURE)
return constants.EXIT_CODE_BUILD_FAILURE
elif constants.TEST_STEP not in steps:
logging.warn('Install step without test step currently not '
@@ -580,9 +587,10 @@
None, regression_args, reporter)
if tests_exit_code != constants.EXIT_CODE_SUCCESS:
tests_exit_code = constants.EXIT_CODE_TEST_FAILURE
- if SEND_CC_LOG:
- metrics_utils.send_exit_event(tests_exit_code)
return tests_exit_code
if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
+ EXIT_CODE = main(sys.argv[1:])
+ if SEND_CC_LOG:
+ metrics_utils.send_exit_event(EXIT_CODE)
+ sys.exit(EXIT_CODE)
diff --git a/atest/atest_arg_parser.py b/atest/atest_arg_parser.py
index 793a422..23b2f8c 100644
--- a/atest/atest_arg_parser.py
+++ b/atest/atest_arg_parser.py
@@ -54,6 +54,7 @@
'previous test run to disable cleanup, for -t to work. '
'Otherwise, device will need to be setup again with -i.')
self.add_argument('-s', '--serial', help='The device to run the test on.')
+ self.add_argument('-L', '--list-modules', help='List testable modules for the given suite.')
self.add_argument('-d', '--disable-teardown', action='store_true',
help='Disables test teardown and cleanup.')
self.add_argument('-m', constants.REBUILD_MODULE_INFO_FLAG, action='store_true',
diff --git a/atest/module_info.py b/atest/module_info.py
index e239214..acf53dc 100644
--- a/atest/module_info.py
+++ b/atest/module_info.py
@@ -22,6 +22,7 @@
import atest_utils
import constants
+from test_finders import test_finder_utils
# JSON file generated by build system that lists all buildable targets.
_MODULE_INFO = 'module-info.json'
@@ -46,6 +47,7 @@
self.module_info_target = module_info_target
self.path_to_module_info = self._get_path_to_module_info(
self.name_to_module_info)
+ self.root_dir = os.environ.get(constants.ANDROID_BUILD_TOP)
@staticmethod
def _discover_mod_file_and_target(force_build):
@@ -155,3 +157,143 @@
def get_module_info(self, mod_name):
"""Return dict of info for given module name, None if non-existent."""
return self.name_to_module_info.get(mod_name)
+
+ def is_suite_in_compatibility_suites(self, suite, mod_info):
+ """Check if suite exists in the compatibility_suites of module-info.
+
+ Args:
+ suite: A string of suite name.
+ mod_info: Dict of module info to check.
+
+ Returns:
+ True if it exists in mod_info, False otherwise.
+ """
+ return suite in mod_info.get(constants.MODULE_COMPATIBILITY_SUITES, [])
+
+ def get_testable_modules(self, suite=None):
+ """Return the testable modules of the given suite name.
+
+ Args:
+ suite: A string of suite name. Set to None to return all testable
+ modules.
+
+ Returns:
+ List of testable modules. Empty list if non-existent.
+ If suite is None, return all the testable modules in module-info.
+ """
+ modules = set()
+ for _, info in self.name_to_module_info.items():
+ if self.is_testable_module(info):
+ if suite:
+ if self.is_suite_in_compatibility_suites(suite, info):
+ modules.add(info.get(constants.MODULE_NAME))
+ else:
+ modules.add(info.get(constants.MODULE_NAME))
+ return modules
+
+ def is_testable_module(self, mod_info):
+ """Check if module is something we can test.
+
+ A module is testable if:
+ - it's installed, or
+ - it's a robolectric module (or shares path with one).
+
+ Args:
+ mod_info: Dict of module info to check.
+
+ Returns:
+ True if we can test this module, False otherwise.
+ """
+ if not mod_info:
+ return False
+ if mod_info.get(constants.MODULE_INSTALLED) and self.has_test_config(mod_info):
+ return True
+ if self.is_robolectric_test(mod_info.get(constants.MODULE_NAME)):
+ return True
+ return False
+
+ def has_test_config(self, mod_info):
+ """Validate if this module has a test config.
+
+ A module can have a test config in the following manner:
+ - AndroidTest.xml at the module path.
+ - test_config be set in module-info.json.
+ - Auto-generated config via the auto_test_config key in module-info.json.
+
+ Args:
+ mod_info: Dict of module info to check.
+
+ Returns:
+ True if this module has a test config, False otherwise.
+ """
+ # Check if test_config in module-info is set.
+ for test_config in mod_info.get(constants.MODULE_TEST_CONFIG, []):
+ if os.path.isfile(os.path.join(self.root_dir, test_config)):
+ return True
+ # Check for AndroidTest.xml at the module path.
+ for path in mod_info.get(constants.MODULE_PATH, []):
+ if os.path.isfile(os.path.join(self.root_dir, path,
+ constants.MODULE_CONFIG)):
+ return True
+ # Check if the module has an auto-generated config.
+ return self.is_auto_gen_test_config(mod_info.get(constants.MODULE_NAME))
+
+ def get_robolectric_test_name(self, module_name):
+ """Returns runnable robolectric module name.
+
+ There are at least 2 modules in every robolectric module path, return
+ the module that we can run as a build target.
+
+ Arg:
+ module_name: String of module.
+
+ Returns:
+ String of module that is the runnable robolectric module, None if
+ none could be found.
+ """
+ module_name_info = self.name_to_module_info.get(module_name)
+ if not module_name_info:
+ return None
+ module_paths = module_name_info.get(constants.MODULE_PATH, [])
+ if module_paths:
+ for mod in self.get_module_names(module_paths[0]):
+ mod_info = self.get_module_info(mod)
+ if test_finder_utils.is_robolectric_module(mod_info):
+ return mod
+ return None
+
+ def is_robolectric_test(self, module_name):
+ """Check if module is a robolectric test.
+
+ A module can be a robolectric test if the specified module has their
+ class set as ROBOLECTRIC (or shares their path with a module that does).
+
+ Args:
+ module_name: String of module to check.
+
+ Returns:
+ True if the module is a robolectric module, else False.
+ """
+ # Check 1, module class is ROBOLECTRIC
+ mod_info = self.get_module_info(module_name)
+ if mod_info and test_finder_utils.is_robolectric_module(mod_info):
+ return True
+ # Check 2, shared modules in the path have class ROBOLECTRIC_CLASS.
+ if self.get_robolectric_test_name(module_name):
+ return True
+ return False
+
+ def is_auto_gen_test_config(self, module_name):
+ """Check if the test config file will be generated automatically.
+
+ Args:
+ module_name: A string of the module name.
+
+ Returns:
+ True if the test config file will be generated automatically.
+ """
+ if self.is_module(module_name):
+ mod_info = self.name_to_module_info.get(module_name)
+ auto_test_config = mod_info.get('auto_test_config', [])
+ return auto_test_config and auto_test_config[0]
+ return False
diff --git a/atest/module_info_unittest.py b/atest/module_info_unittest.py
index f247b4d..b6537c8 100755
--- a/atest/module_info_unittest.py
+++ b/atest/module_info_unittest.py
@@ -34,6 +34,29 @@
PATH_TO_MULT_MODULES_WITH_MULTI_ARCH = 'shared/path/to/be/used2'
TESTABLE_MODULES_WITH_SHARED_PATH = ['multiarch1', 'multiarch2', 'multiarch3', 'multiarch3_32']
+ROBO_MOD_PATH = ['/shared/robo/path']
+NON_RUN_ROBO_MOD_NAME = 'robo_mod'
+RUN_ROBO_MOD_NAME = 'run_robo_mod'
+NON_RUN_ROBO_MOD = {constants.MODULE_NAME: NON_RUN_ROBO_MOD_NAME,
+ constants.MODULE_PATH: ROBO_MOD_PATH,
+ constants.MODULE_CLASS: ['random_class']}
+RUN_ROBO_MOD = {constants.MODULE_NAME: RUN_ROBO_MOD_NAME,
+ constants.MODULE_PATH: ROBO_MOD_PATH,
+ constants.MODULE_CLASS: [constants.MODULE_CLASS_ROBOLECTRIC]}
+MOD_PATH_INFO_DICT = {ROBO_MOD_PATH[0]: [RUN_ROBO_MOD, NON_RUN_ROBO_MOD]}
+MOD_NAME_INFO_DICT = {
+ RUN_ROBO_MOD_NAME: RUN_ROBO_MOD,
+ NON_RUN_ROBO_MOD_NAME: NON_RUN_ROBO_MOD}
+MOD_NAME1 = 'mod1'
+MOD_NAME2 = 'mod2'
+MOD_NAME3 = 'mod3'
+MOD_NAME4 = 'mod4'
+MOD_INFO_DICT = {}
+MODULE_INFO = {constants.MODULE_NAME: 'random_name',
+ constants.MODULE_PATH: 'a/b/c/path',
+ constants.MODULE_CLASS: ['random_class']}
+NAME_TO_MODULE_INFO = {'random_name' : MODULE_INFO}
+
#pylint: disable=protected-access
class ModuleInfoUnittests(unittest.TestCase):
"""Unit tests for module_info.py"""
@@ -130,6 +153,123 @@
TESTABLE_MODULES_WITH_SHARED_PATH.sort()
self.assertEqual(module_list, TESTABLE_MODULES_WITH_SHARED_PATH)
+ def test_is_suite_in_compatibility_suites(self):
+ """Test is_suite_in_compatibility_suites."""
+ mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH)
+ info = {'compatibility_suites': []}
+ self.assertFalse(mod_info.is_suite_in_compatibility_suites("cts", info))
+ info2 = {'compatibility_suites': ["cts"]}
+ self.assertTrue(mod_info.is_suite_in_compatibility_suites("cts", info2))
+ self.assertFalse(mod_info.is_suite_in_compatibility_suites("vts", info2))
+ info3 = {'compatibility_suites': ["cts", "vts"]}
+ self.assertTrue(mod_info.is_suite_in_compatibility_suites("cts", info3))
+ self.assertTrue(mod_info.is_suite_in_compatibility_suites("vts", info3))
+ self.assertFalse(mod_info.is_suite_in_compatibility_suites("ats", info3))
+
+ @mock.patch.object(module_info.ModuleInfo, 'is_testable_module')
+ @mock.patch.object(module_info.ModuleInfo, 'is_suite_in_compatibility_suites')
+ def test_get_testable_modules(self, mock_is_suite_exist, mock_is_testable):
+ """Test get_testable_modules."""
+ mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH)
+ mock_is_testable.return_value = False
+ self.assertEqual(mod_info.get_testable_modules(), set())
+ mod_info.name_to_module_info = NAME_TO_MODULE_INFO
+ mock_is_testable.return_value = True
+ mock_is_suite_exist.return_value = True
+ self.assertEqual(1, len(mod_info.get_testable_modules('test_suite')))
+ mock_is_suite_exist.return_value = False
+ self.assertEqual(0, len(mod_info.get_testable_modules('test_suite')))
+ self.assertEqual(1, len(mod_info.get_testable_modules()))
+
+ @mock.patch.object(module_info.ModuleInfo, 'has_test_config')
+ @mock.patch.object(module_info.ModuleInfo, 'is_robolectric_test')
+ def test_is_testable_module(self, mock_is_robo_test, mock_has_test_config):
+ """Test is_testable_module."""
+ mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH)
+ mock_is_robo_test.return_value = False
+ mock_has_test_config.return_value = True
+ installed_module_info = {constants.MODULE_INSTALLED:
+ uc.DEFAULT_INSTALL_PATH}
+ non_installed_module_info = {constants.MODULE_NAME: 'rand_name'}
+ # Empty mod_info or a non-installed module.
+ self.assertFalse(mod_info.is_testable_module(non_installed_module_info))
+ self.assertFalse(mod_info.is_testable_module({}))
+ # Testable Module or is a robo module for non-installed module.
+ self.assertTrue(mod_info.is_testable_module(installed_module_info))
+ mock_has_test_config.return_value = False
+ self.assertFalse(mod_info.is_testable_module(installed_module_info))
+ mock_is_robo_test.return_value = True
+ self.assertTrue(mod_info.is_testable_module(non_installed_module_info))
+
+ @mock.patch.object(module_info.ModuleInfo, 'is_auto_gen_test_config')
+ def test_has_test_config(self, mock_is_auto_gen):
+ """Test has_test_config."""
+ mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH)
+ info = {constants.MODULE_PATH:[uc.TEST_DATA_DIR]}
+ mock_is_auto_gen.return_value = True
+ # Validate we see the config when it's auto-generated.
+ self.assertTrue(mod_info.has_test_config(info))
+ self.assertTrue(mod_info.has_test_config({}))
+ # Validate when actual config exists and there's no auto-generated config.
+ mock_is_auto_gen.return_value = False
+ self.assertTrue(mod_info.has_test_config(info))
+ self.assertFalse(mod_info.has_test_config({}))
+ # Validate the case mod_info MODULE_TEST_CONFIG be set
+ info2 = {constants.MODULE_PATH:[uc.TEST_CONFIG_DATA_DIR],
+ constants.MODULE_TEST_CONFIG:[os.path.join(uc.TEST_CONFIG_DATA_DIR, "a.xml")]}
+ self.assertTrue(mod_info.has_test_config(info2))
+
+ @mock.patch.object(module_info.ModuleInfo, 'get_module_names')
+ def test_get_robolectric_test_name(self, mock_get_module_names):
+ """Test get_robolectric_test_name."""
+ # Happy path testing, make sure we get the run robo target.
+ mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH)
+ mod_info.name_to_module_info = MOD_NAME_INFO_DICT
+ mod_info.path_to_module_info = MOD_PATH_INFO_DICT
+ mock_get_module_names.return_value = [RUN_ROBO_MOD_NAME, NON_RUN_ROBO_MOD_NAME]
+ self.assertEqual(mod_info.get_robolectric_test_name(
+ NON_RUN_ROBO_MOD_NAME), RUN_ROBO_MOD_NAME)
+ # Let's also make sure we don't return anything when we're not supposed
+ # to.
+ mock_get_module_names.return_value = [NON_RUN_ROBO_MOD_NAME]
+ self.assertEqual(mod_info.get_robolectric_test_name(
+ NON_RUN_ROBO_MOD_NAME), None)
+
+ @mock.patch.object(module_info.ModuleInfo, 'get_module_info')
+ @mock.patch.object(module_info.ModuleInfo, 'get_module_names')
+ def test_is_robolectric_test(self, mock_get_module_names, mock_get_module_info):
+ """Test is_robolectric_test."""
+ # Happy path testing, make sure we get the run robo target.
+ mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH)
+ mod_info.name_to_module_info = MOD_NAME_INFO_DICT
+ mod_info.path_to_module_info = MOD_PATH_INFO_DICT
+ mock_get_module_names.return_value = [RUN_ROBO_MOD_NAME, NON_RUN_ROBO_MOD_NAME]
+ mock_get_module_info.return_value = RUN_ROBO_MOD
+ # Test on a run robo module.
+ self.assertTrue(mod_info.is_robolectric_test(RUN_ROBO_MOD_NAME))
+ # Test on a non-run robo module but shares with a run robo module.
+ self.assertTrue(mod_info.is_robolectric_test(NON_RUN_ROBO_MOD_NAME))
+ # Make sure we don't find robo tests where they don't exist.
+ mock_get_module_info.return_value = None
+ self.assertFalse(mod_info.is_robolectric_test('rand_mod'))
+
+ @mock.patch.object(module_info.ModuleInfo, 'is_module')
+ def test_is_auto_gen_test_config(self, mock_is_module):
+ """Test is_auto_gen_test_config correctly detects the module."""
+ mod_info = module_info.ModuleInfo(module_file=JSON_FILE_PATH)
+ mock_is_module.return_value = True
+ is_auto_test_config = {'auto_test_config': [True]}
+ is_not_auto_test_config = {'auto_test_config': [False]}
+ is_not_auto_test_config_again = {'auto_test_config': []}
+ MOD_INFO_DICT[MOD_NAME1] = is_auto_test_config
+ MOD_INFO_DICT[MOD_NAME2] = is_not_auto_test_config
+ MOD_INFO_DICT[MOD_NAME3] = is_not_auto_test_config_again
+ MOD_INFO_DICT[MOD_NAME4] = {}
+ mod_info.name_to_module_info = MOD_INFO_DICT
+ self.assertTrue(mod_info.is_auto_gen_test_config(MOD_NAME1))
+ self.assertFalse(mod_info.is_auto_gen_test_config(MOD_NAME2))
+ self.assertFalse(mod_info.is_auto_gen_test_config(MOD_NAME3))
+ self.assertFalse(mod_info.is_auto_gen_test_config(MOD_NAME4))
if __name__ == '__main__':
unittest.main()
diff --git a/atest/test_finders/module_finder.py b/atest/test_finders/module_finder.py
index 2f620b2..2c41517 100644
--- a/atest/test_finders/module_finder.py
+++ b/atest/test_finders/module_finder.py
@@ -52,53 +52,6 @@
self.root_dir = os.environ.get(constants.ANDROID_BUILD_TOP)
self.module_info = module_info
- def _has_test_config(self, mod_info):
- """Validate if this module has a test config.
-
- A module can have a test config in the following manner:
- - AndroidTest.xml at the module path.
- - test_config be set in module-info.json.
- - Auto-generated config via the auto_test_config key in module-info.json.
-
- Args:
- mod_info: Dict of module info to check.
-
- Returns:
- True if this module has a test config, False otherwise.
- """
- # Check if test_config in module-info is set.
- for test_config in mod_info.get(constants.MODULE_TEST_CONFIG, []):
- if os.path.isfile(os.path.join(self.root_dir, test_config)):
- return True
- # Check for AndroidTest.xml at the module path.
- for path in mod_info.get(constants.MODULE_PATH, []):
- if os.path.isfile(os.path.join(self.root_dir, path,
- constants.MODULE_CONFIG)):
- return True
- # Check if the module has an auto-generated config.
- return self._is_auto_gen_test_config(mod_info.get(constants.MODULE_NAME))
-
- def _is_testable_module(self, mod_info):
- """Check if module is something we can test.
-
- A module is testable if:
- - it's installed.
- - it's a robolectric module (or shares path with one).
-
- Args:
- mod_info: Dict of module info to check.
-
- Returns:
- True if we can test this module, False otherwise.
- """
- if not mod_info:
- return False
- if mod_info.get(constants.MODULE_INSTALLED) and self._has_test_config(mod_info):
- return True
- if self._is_robolectric_test(mod_info.get(constants.MODULE_NAME)):
- return True
- return False
-
def _determine_testable_module(self, path):
"""Determine which module the user is trying to test.
@@ -117,9 +70,9 @@
# Robolectric tests always exist in pairs of 2, one module to build
# the test and another to run it. For now, we are assuming they are
# isolated in their own folders and will return if we find one.
- if self._is_robolectric_test(mod):
+ if self.module_info.is_robolectric_test(mod):
return mod
- if self._is_testable_module(mod_info):
+ if self.module_info.is_testable_module(mod_info):
testable_modules.append(mod_info.get(constants.MODULE_NAME))
return test_finder_utils.extract_test_from_tests(testable_modules)
@@ -171,50 +124,6 @@
test.build_targets.add(test.test_name)
return test
- def _get_robolectric_test_name(self, module_name):
- """Returns run robolectric module.
-
- There are at least 2 modules in every robolectric module path, return
- the module that we can run as a build target.
-
- Arg:
- module_name: String of module.
-
- Returns:
- String of module that is the run robolectric module, None if none
- could be found.
- """
- module_name_info = self.module_info.get_module_info(module_name)
- if not module_name_info:
- return None
- for mod in self.module_info.get_module_names(
- module_name_info.get(constants.MODULE_PATH, [])[0]):
- mod_info = self.module_info.get_module_info(mod)
- if test_finder_utils.is_robolectric_module(mod_info):
- return mod
- return None
-
- def _is_robolectric_test(self, module_name):
- """Check if module is a robolectric test.
-
- A module can be a robolectric test if the specified module has their
- class set as ROBOLECTRIC (or shares their path with a module that does).
-
- Args:
- module_name: String of module to check.
-
- Returns:
- True if the module is a robolectric module, else False.
- """
- # Check 1, module class is ROBOLECTRIC
- mod_info = self.module_info.get_module_info(module_name)
- if mod_info and test_finder_utils.is_robolectric_module(mod_info):
- return True
- # Check 2, shared modules in the path have class ROBOLECTRIC_CLASS.
- if self._get_robolectric_test_name(module_name):
- return True
- return False
-
def _update_to_robolectric_test_info(self, test):
"""Update the fields for a robolectric test.
@@ -225,7 +134,7 @@
TestInfo with robolectric fields.
"""
test.test_runner = self._ROBOLECTRIC_RUNNER
- test.test_name = self._get_robolectric_test_name(test.test_name)
+ test.test_name = self.module_info.get_robolectric_test_name(test.test_name)
return test
def _process_test_info(self, test):
@@ -251,27 +160,12 @@
# Check if this is only a vts module.
if self._is_vts_module(test.test_name):
return self._update_to_vts_test_info(test)
- elif self._is_robolectric_test(test.test_name):
+ elif self.module_info.is_robolectric_test(test.test_name):
return self._update_to_robolectric_test_info(test)
rel_config = test.data[constants.TI_REL_CONFIG]
test.build_targets = self._get_build_targets(module_name, rel_config)
return test
- def _is_auto_gen_test_config(self, module_name):
- """Check if the test config file will be generated automatically.
-
- Args:
- module_name: A string of the module name.
-
- Returns:
- True if the test config file will be generated automatically.
- """
- if self.module_info.is_module(module_name):
- mod_info = self.module_info.get_module_info(module_name)
- auto_test_config = mod_info.get('auto_test_config', [])
- return auto_test_config and auto_test_config[0]
- return False
-
def _get_build_targets(self, module_name, rel_config):
"""Get the test deps.
@@ -283,7 +177,7 @@
Set of build targets.
"""
targets = set()
- if not self._is_auto_gen_test_config(module_name):
+ if not self.module_info.is_auto_gen_test_config(module_name):
config_file = os.path.join(self.root_dir, rel_config)
targets = test_finder_utils.get_targets_from_xml(config_file,
self.module_info)
@@ -313,7 +207,7 @@
test_config_list = mod_info.get(constants.MODULE_TEST_CONFIG, [])
if test_config_list:
test_config = test_config_list[0]
- if not self._is_auto_gen_test_config(module_name) and test_config != '':
+ if not self.module_info.is_auto_gen_test_config(module_name) and test_config != '':
return test_config
return rel_config
@@ -327,7 +221,7 @@
A populated TestInfo namedtuple if found, else None.
"""
mod_info = self.module_info.get_module_info(module_name)
- if self._is_testable_module(mod_info):
+ if self.module_info.is_testable_module(mod_info):
# path is a list with only 1 element.
rel_config = os.path.join(mod_info['path'][0],
constants.MODULE_CONFIG)
@@ -543,7 +437,7 @@
[test_info.TestFilter(test_finder_utils.get_cc_filter(
'*', methods), frozenset())])
# Path to non-module dir, treat as package.
- elif (not file_name and not self._is_auto_gen_test_config(module_name)
+ elif (not file_name and not self.module_info.is_auto_gen_test_config(module_name)
and rel_module_dir != os.path.relpath(path, self.root_dir)):
dir_items = [os.path.join(path, f) for f in os.listdir(path)]
for dir_item in dir_items:
diff --git a/atest/test_finders/module_finder_unittest.py b/atest/test_finders/module_finder_unittest.py
index 47480c0..71b684c 100755
--- a/atest/test_finders/module_finder_unittest.py
+++ b/atest/test_finders/module_finder_unittest.py
@@ -66,16 +66,8 @@
constants.MODULE_PATH: ROBO_MOD_PATH,
constants.MODULE_CLASS: [constants.MODULE_CLASS_ROBOLECTRIC]}
-
SEARCH_DIR_RE = re.compile(r'^find ([^ ]*).*$')
-def get_mod_info_side_effect(mod):
- """Mock out get_module_info for ModuleInfo."""
- mod_info_dict = {
- RUN_ROBO_MOD_NAME: RUN_ROBO_MOD,
- NON_RUN_ROBO_MOD_NAME: NON_RUN_ROBO_MOD}
- return mod_info_dict.get(mod)
-
#pylint: disable=unused-argument
def classoutside_side_effect(find_cmd, shell=False):
@@ -108,32 +100,13 @@
self.mod_finder.module_info.get_module_info.return_value = is_not_vts_module
self.assertFalse(self.mod_finder._is_vts_module(mod_name))
- def test_is_auto_gen_test_config(self):
- """Test _is_auto_gen_test_config correctly detects the module."""
- mod_name = 'mod'
- self.mod_finder.module_info.is_module.return_value = True
- is_auto_test_config = {'auto_test_config': [True]}
- is_not_auto_test_config = {'auto_test_config': [False]}
- is_not_auto_test_config_again = {'auto_test_config': []}
-
- self.mod_finder.module_info.get_module_info.return_value = is_auto_test_config
- self.assertTrue(self.mod_finder._is_auto_gen_test_config(mod_name))
- self.mod_finder.module_info.get_module_info.return_value = is_not_auto_test_config
- self.assertFalse(self.mod_finder._is_auto_gen_test_config(mod_name))
- self.mod_finder.module_info.get_module_info.return_value = is_not_auto_test_config_again
- self.assertFalse(self.mod_finder._is_auto_gen_test_config(mod_name))
- self.mod_finder.module_info.get_module_info.return_value = {}
- self.assertFalse(self.mod_finder._is_auto_gen_test_config(mod_name))
-
# pylint: disable=unused-argument
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets',
return_value=uc.MODULE_BUILD_TARGETS)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
- def test_find_test_by_module_name(self, _robo, _get_targ, _has_test_config):
+ def test_find_test_by_module_name(self, _get_targ):
"""Test find_test_by_module_name."""
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
mod_info = {'installed': ['/path/to/install'],
'path': [uc.MODULE_DIR],
constants.MODULE_CLASS: []}
@@ -143,17 +116,12 @@
self.mod_finder.find_test_by_module_name(uc.MODULE_NAME),
uc.MODULE_INFO)
self.mod_finder.module_info.get_module_info.return_value = None
+ self.mod_finder.module_info.is_testable_module.return_value = False
self.assertIsNone(self.mod_finder.find_test_by_module_name('Not_Module'))
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_is_vts_module',
return_value=False)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
- @mock.patch.object(module_finder.ModuleFinder, '_is_auto_gen_test_config',
- return_value=False)
@mock.patch('subprocess.check_output', return_value=uc.FIND_ONE)
@mock.patch.object(test_finder_utils, 'get_fully_qualified_class_name',
return_value=uc.FULL_CLASS_NAME)
@@ -161,10 +129,13 @@
@mock.patch('os.path.isdir', return_value=True)
#pylint: disable=unused-argument
def test_find_test_by_class_name(self, _isdir, _isfile, _fqcn,
- mock_checkoutput, _auto, mock_build, _robo,
- _vts, _has_test_config):
+ mock_checkoutput, mock_build,
+ _vts):
"""Test find_test_by_class_name."""
mock_build.return_value = uc.CLASS_BUILD_TARGETS
+ self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
self.mod_finder.module_info.get_module_info.return_value = {
constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
@@ -201,24 +172,21 @@
uc.CONFIG2_FILE),
CLASS_INFO_MODULE_2)
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_is_vts_module',
return_value=False)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
- @mock.patch.object(module_finder.ModuleFinder, '_is_auto_gen_test_config',
- return_value=False)
@mock.patch('subprocess.check_output', return_value=uc.FIND_ONE)
@mock.patch.object(test_finder_utils, 'get_fully_qualified_class_name',
return_value=uc.FULL_CLASS_NAME)
@mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
#pylint: disable=unused-argument
def test_find_test_by_module_and_class(self, _isfile, _fqcn,
- mock_checkoutput, _auto, mock_build,
- _robo, _vts, _has_test_config):
+ mock_checkoutput, mock_build,
+ _vts):
"""Test find_test_by_module_and_class."""
+ self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
mock_build.return_value = uc.CLASS_BUILD_TARGETS
mod_info = {constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
constants.MODULE_PATH: [uc.MODULE_DIR],
@@ -230,6 +198,7 @@
mock_build.return_value = uc.MODULE_BUILD_TARGETS
t_info = self.mod_finder.find_test_by_module_and_class(MODULE_CLASS_METHOD)
unittest_utils.assert_equal_testinfos(self, t_info, uc.METHOD_INFO)
+ self.mod_finder.module_info.is_testable_module.return_value = False
# bad module, good class, returns None
bad_module = '%s:%s' % ('BadMod', uc.CLASS_NAME)
self.mod_finder.module_info.get_module_info.return_value = None
@@ -240,24 +209,21 @@
self.mod_finder.module_info.get_module_info.return_value = mod_info
self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_class))
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_is_vts_module',
return_value=False)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
- @mock.patch.object(module_finder.ModuleFinder, '_is_auto_gen_test_config',
- return_value=False)
@mock.patch('subprocess.check_output', return_value=uc.FIND_CC_ONE)
@mock.patch.object(test_finder_utils, 'find_class_file',
side_effect=[None, None, '/'])
@mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
#pylint: disable=unused-argument
def test_find_test_by_module_and_class_part_2(self, _isfile, mock_fcf,
- mock_checkoutput, _auto, mock_build,
- _robo, _vts, _has_test_config):
+ mock_checkoutput, mock_build,
+ _vts):
"""Test find_test_by_module_and_class for MODULE:CC_CLASS."""
+ self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
mock_build.return_value = uc.CLASS_BUILD_TARGETS
mod_info = {constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
constants.MODULE_PATH: [uc.CC_MODULE_DIR],
@@ -273,24 +239,22 @@
# bad module, good class, returns None
bad_module = '%s:%s' % ('BadMod', uc.CC_CLASS_NAME)
self.mod_finder.module_info.get_module_info.return_value = None
+ self.mod_finder.module_info.is_testable_module.return_value = False
self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_module))
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_is_vts_module',
return_value=False)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
- @mock.patch.object(module_finder.ModuleFinder, '_is_auto_gen_test_config',
- return_value=False)
@mock.patch('subprocess.check_output', return_value=uc.FIND_PKG)
@mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
@mock.patch('os.path.isdir', return_value=True)
#pylint: disable=unused-argument
def test_find_test_by_package_name(self, _isdir, _isfile, mock_checkoutput,
- _auto, mock_build, _robo, _vts, _has_test_config):
+ mock_build, _vts):
"""Test find_test_by_package_name."""
+ self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
mock_build.return_value = uc.CLASS_BUILD_TARGETS
self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
self.mod_finder.module_info.get_module_info.return_value = {
@@ -313,21 +277,18 @@
mock_checkoutput.return_value = ''
self.assertIsNone(self.mod_finder.find_test_by_package_name('Not pkg'))
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_is_vts_module',
return_value=False)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
- @mock.patch.object(module_finder.ModuleFinder, '_is_auto_gen_test_config',
- return_value=False)
@mock.patch('subprocess.check_output', return_value=uc.FIND_PKG)
@mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
#pylint: disable=unused-argument
def test_find_test_by_module_and_package(self, _isfile, mock_checkoutput,
- _auto, mock_build, _robo, _vts, _has_test_config):
+ mock_build, _vts):
"""Test find_test_by_module_and_package."""
+ self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
mock_build.return_value = uc.CLASS_BUILD_TARGETS
mod_info = {constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
constants.MODULE_PATH: [uc.MODULE_DIR],
@@ -342,6 +303,7 @@
self.mod_finder.find_test_by_module_and_package,
module_pkg_with_method)
# bad module, good pkg, returns None
+ self.mod_finder.module_info.is_testable_module.return_value = False
bad_module = '%s:%s' % ('BadMod', uc.PACKAGE)
self.mod_finder.module_info.get_module_info.return_value = None
self.assertIsNone(self.mod_finder.find_test_by_module_and_package(bad_module))
@@ -353,13 +315,9 @@
@mock.patch.object(test_finder_utils, 'has_cc_class',
return_value=True)
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
@mock.patch.object(module_finder.ModuleFinder, '_is_vts_module',
return_value=False)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
@mock.patch.object(test_finder_utils, 'get_fully_qualified_class_name',
return_value=uc.FULL_CLASS_NAME)
@mock.patch('os.path.realpath',
@@ -369,8 +327,10 @@
@mock.patch('os.path.exists')
#pylint: disable=unused-argument
def test_find_test_by_path(self, mock_pathexists, mock_dir, _isfile, _real,
- _fqcn, _robo, _vts, mock_build, _has_test_config, _has_cc_class):
+ _fqcn, _vts, mock_build, _has_cc_class):
"""Test find_test_by_path."""
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
mock_build.return_value = set()
# Check that we don't return anything with invalid test references.
mock_pathexists.return_value = False
@@ -422,22 +382,18 @@
unittest_utils.assert_equal_testinfos(
self, uc.CC_PATH_INFO2, self.mod_finder.find_test_by_path(class_path))
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets',
return_value=uc.MODULE_BUILD_TARGETS)
@mock.patch.object(module_finder.ModuleFinder, '_is_vts_module',
return_value=False)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
@mock.patch.object(test_finder_utils, 'find_parent_module_dir',
return_value=os.path.relpath(uc.TEST_DATA_DIR, uc.ROOT))
- @mock.patch.object(module_finder.ModuleFinder, '_is_auto_gen_test_config',
- return_value=False)
#pylint: disable=unused-argument
- def test_find_test_by_path_part_2(self, _is_auto_gen, _find_parent, _is_vts,
- _is_robo, _get_build, _has_test_config):
+ def test_find_test_by_path_part_2(self, _find_parent, _is_vts, _get_build):
"""Test find_test_by_path for directories."""
+ self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
# Dir with java files in it, should run as package
class_dir = os.path.join(uc.TEST_DATA_DIR, 'path_testing')
self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
@@ -462,99 +418,21 @@
unittest_utils.assert_equal_testinfos(
self, uc.CC_PATH_INFO, self.mod_finder.find_test_by_path(class_dir))
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config')
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test')
- def test_is_testable_module(self, mock_is_robo_test, mock_has_test_config):
- """Test _is_testable_module."""
- mock_is_robo_test.return_value = False
- mock_has_test_config.return_value = True
- installed_module_info = {constants.MODULE_INSTALLED:
- DEFAULT_INSTALL_PATH}
- non_installed_module_info = {constants.MODULE_NAME: 'rand_name'}
- # Empty mod_info or a non-installed module.
- self.assertFalse(self.mod_finder._is_testable_module(
- non_installed_module_info))
- self.assertFalse(self.mod_finder._is_testable_module({}))
-
- # Testable Module or is a robo module for non-installed module.
- self.assertTrue(self.mod_finder._is_testable_module(
- installed_module_info))
- mock_has_test_config.return_value = False
- self.assertFalse(self.mod_finder._is_testable_module(
- installed_module_info))
- mock_is_robo_test.return_value = True
- self.assertTrue(self.mod_finder._is_testable_module(
- non_installed_module_info))
-
- def test_get_robolectric_test_name(self):
- """Test get_robolectric_test_name."""
- # Happy path testing, make sure we get the run robo target.
- self.mod_finder.module_info.get_module_info.side_effect = get_mod_info_side_effect
- self.mod_finder.module_info.get_module_names.return_value = [
- RUN_ROBO_MOD_NAME, NON_RUN_ROBO_MOD_NAME]
- self.assertEqual(self.mod_finder._get_robolectric_test_name(
- NON_RUN_ROBO_MOD_NAME), RUN_ROBO_MOD_NAME)
- # Let's also make sure we don't return anything when we're not supposed
- # to.
- self.mod_finder.module_info.get_module_info.side_effect = get_mod_info_side_effect
- self.mod_finder.module_info.get_module_names.return_value = [
- NON_RUN_ROBO_MOD_NAME]
- self.assertEqual(self.mod_finder._get_robolectric_test_name(
- NON_RUN_ROBO_MOD_NAME), None)
-
- def test_is_robolectric_test(self):
- """Test _is_robolectric_test."""
- # Happy path testing, make sure we get the run robo target.
- self.mod_finder.module_info.get_module_info.side_effect = get_mod_info_side_effect
- self.mod_finder.module_info.get_module_names.return_value = [
- RUN_ROBO_MOD_NAME, NON_RUN_ROBO_MOD_NAME]
-
- self.mod_finder.module_info.get_module_info.return_value = RUN_ROBO_MOD
- # Test on a run robo module.
- self.assertTrue(self.mod_finder._is_robolectric_test(RUN_ROBO_MOD_NAME))
-
- # Test on a non-run robo module but shares with a run robo module.
- self.assertTrue(self.mod_finder._is_robolectric_test(NON_RUN_ROBO_MOD_NAME))
-
- # Make sure we don't find robo tests where they don't exist.
- self.mod_finder.module_info.get_module_info.return_value = None
- self.assertFalse(self.mod_finder._is_robolectric_test('rand_mod'))
-
- @mock.patch.object(module_finder.ModuleFinder, '_is_auto_gen_test_config')
- def test_has_test_config(self, mock_is_auto_gen):
- """Test _has_test_config."""
- mod_info = {constants.MODULE_PATH:[uc.TEST_DATA_DIR]}
- mock_is_auto_gen.return_value = True
- # Validate we see the config when it's auto-generated.
- self.assertTrue(self.mod_finder._has_test_config(mod_info))
- self.assertTrue(self.mod_finder._has_test_config({}))
- # Validate when actual config exists and there's no auto-generated config.
- mock_is_auto_gen.return_value = False
- self.assertTrue(self.mod_finder._has_test_config(mod_info))
- self.assertFalse(self.mod_finder._has_test_config({}))
- # Validate the case with MODULE_TEST_CONFIG be set
- mod_info2 = {constants.MODULE_PATH:[uc.TEST_CONFIG_DATA_DIR],
- constants.MODULE_TEST_CONFIG:[os.path.join(uc.TEST_CONFIG_DATA_DIR, "a.xml")]}
- self.assertTrue(self.mod_finder._has_test_config(mod_info2))
-
- @mock.patch.object(module_finder.ModuleFinder, '_has_test_config',
- return_value=True)
@mock.patch.object(module_finder.ModuleFinder, '_is_vts_module',
return_value=False)
- @mock.patch.object(module_finder.ModuleFinder, '_is_robolectric_test',
- return_value=False)
@mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
- @mock.patch.object(module_finder.ModuleFinder, '_is_auto_gen_test_config',
- return_value=False)
@mock.patch('subprocess.check_output', return_value=uc.CC_FIND_ONE)
@mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
@mock.patch('os.path.isdir', return_value=True)
#pylint: disable=unused-argument
def test_find_test_by_cc_class_name(self, _isdir, _isfile,
- mock_checkoutput, _auto, mock_build,
- _robo, _vts, _has_test_config):
+ mock_checkoutput, mock_build,
+ _vts):
"""Test find_test_by_cc_class_name."""
mock_build.return_value = uc.CLASS_BUILD_TARGETS
+ self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
+ self.mod_finder.module_info.is_robolectric_test.return_value = False
+ self.mod_finder.module_info.has_test_config.return_value = True
self.mod_finder.module_info.get_module_names.return_value = [uc.CC_MODULE_NAME]
self.mod_finder.module_info.get_module_info.return_value = {
constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
diff --git a/atest/unittest_constants.py b/atest/unittest_constants.py
index 1d33367..fd8ea4c 100644
--- a/atest/unittest_constants.py
+++ b/atest/unittest_constants.py
@@ -208,3 +208,5 @@
FIND_PATH_TESTCASE_CC = 'HelloWorldTest'
FIND_PATH_FOLDER = 'class_file_path_testing'
FIND_PATH = os.path.join(TEST_DATA_DIR, FIND_PATH_FOLDER)
+
+DEFAULT_INSTALL_PATH = ['/path/to/install']