Atest: enable excluding MODULES-IN-* targets.

New --no-modules-in arguments is introduced to speed up the build time
by ignoring MODULES-IN-* targets.

BUG: 184567849

Test: m atest
atest-dev hello_world_test --no-modules -v # no MODULES-IN- targets.
 will see:
DEBUG: Will exclude all "MODULES-IN-*" from the build targets.
DEBUG: Ignore MODULES-IN-platform_testing-tests-example-native.

Change-Id: I78e57a2498febb6a35173c1c5986fd49ca1657a0
diff --git a/atest/atest.py b/atest/atest.py
index c7ed23f..3eee97b 100755
--- a/atest/atest.py
+++ b/atest/atest.py
@@ -648,6 +648,24 @@
                                            dry_run_cmds)
     return constants.EXIT_CODE_SUCCESS
 
+def _exclude_modules_in_targets(build_targets):
+    """Method that excludes MODULES-IN-* targets.
+
+    Args:
+        build_targets: A set of build targets.
+
+    Returns:
+        A set of build targets that excludes MODULES-IN-*.
+    """
+    shrank_build_targets = build_targets.copy()
+    logging.debug('Will exclude all "%s*" from the build targets.',
+                  constants.MODULES_IN)
+    for target in build_targets:
+        if target.startswith(constants.MODULES_IN):
+            logging.debug('Ignore %s.', target)
+            shrank_build_targets.remove(target)
+    return shrank_build_targets
+
 def acloud_create_validator(results_dir, args):
     """Check lunch'd target before running 'acloud create'.
 
@@ -721,6 +739,8 @@
     if _will_run_tests(args):
         find_start = time.time()
         build_targets, test_infos = translator.translate(args)
+        if args.no_modules_in:
+            build_targets = _exclude_modules_in_targets(build_targets)
         find_duration = time.time() - find_start
         if not test_infos:
             return constants.EXIT_CODE_TEST_NOT_FOUND
diff --git a/atest/atest_arg_parser.py b/atest/atest_arg_parser.py
index 55bab01..3b31d81 100644
--- a/atest/atest_arg_parser.py
+++ b/atest/atest_arg_parser.py
@@ -41,6 +41,7 @@
 DISABLE_TEARDOWN = 'Disable test teardown and cleanup.'
 DRY_RUN = 'Dry run atest without building, installing and running tests in real.'
 ENABLE_FILE_PATTERNS = 'Enable FILE_PATTERNS in TEST_MAPPING.'
+FLAKES_INFO = 'Test result with flakes info.'
 HISTORY = ('Show test results in chronological order(with specified number or '
            'all by default).')
 HOST = ('Run the test completely on the host without a device. '
@@ -57,25 +58,32 @@
 LATEST_RESULT = 'Print latest test result.'
 LIST_MODULES = 'List testable modules for the given suite.'
 NO_METRICS = 'Do not send metrics.'
+NO_MODULES_IN = ('Do not include MODULES-IN-* as build targets. Warning: This '
+                 'may result in missing dependencies issue.')
 REBUILD_MODULE_INFO = ('Forces a rebuild of the module-info.json file. '
                        'This may be necessary following a repo sync or '
                        'when writing a new test.')
+REQUEST_UPLOAD_RESULT = 'Request permission to upload test result or not.'
 RERUN_UNTIL_FAILURE = ('Rerun all tests until a failure occurs or the max '
                        'iteration is reached. (10 by default)')
 RETRY_ANY_FAILURE = ('Rerun failed tests until passed or the max iteration '
                      'is reached. (10 by default)')
 SERIAL = 'The device to run the test on.'
+SHARDING = 'Option to specify sharding count. The default value is 2'
 START_AVD = 'Automatically create an AVD and run tests on the virtual device.'
 TEST = ('Run the tests. WARNING: Many test configs force cleanup of device '
         'after test run. In this case, "-d" must be used in previous test run '
         'to disable cleanup for "-t" to work. Otherwise, device will need to '
         'be setup again with "-i".')
 TEST_MAPPING = 'Run tests defined in TEST_MAPPING files.'
-TF_TEMPLATE = ('Add extra tradefed template for ATest suite, '
-               'e.g. atest <test> --tf-template <template_key>=<template_path>')
+TEST_CONFIG_SELECTION = ('If multiple test config belong to same test module '
+                         'pop out a selection menu on console.')
 TF_DEBUG = ('Enable tradefed debug mode with a specify port. Default value is '
             '10888.')
-SHARDING = 'Option to specify sharding count. The default value is 2'
+TF_EARLY_DEVICE_RELEASE = ('Tradefed flag to release the device as soon as '
+                           'done with it.')
+TF_TEMPLATE = ('Add extra tradefed template for ATest suite, '
+               'e.g. atest <test> --tf-template <template_key>=<template_path>')
 UPDATE_CMD_MAPPING = ('Update the test command of input tests. Warning: result '
                       'will be saved under '
                       'tools/asuite/atest/test_data.')
@@ -86,12 +94,6 @@
 VERSION = 'Display version string.'
 WAIT_FOR_DEBUGGER = ('Wait for debugger prior to execution (Instrumentation '
                      'tests only).')
-FLAKES_INFO = 'Test result with flakes info.'
-TF_EARLY_DEVICE_RELEASE = ('Tradefed flag to release the device as soon as '
-                           'done with it.')
-TEST_CONFIG_SELECTION = ('If multiple test config belong to same test module '
-                         'pop out a selection menu on console.')
-REQUEST_UPLOAD_RESULT = 'Show the prompt to decide upload test result or not.'
 
 def _positive_int(value):
     """Verify value by whether or not a positive integer.
@@ -120,6 +122,7 @@
         """Initialise an ArgumentParser instance."""
         super().__init__(description=HELP_DESC, add_help=False)
 
+    # pylint: disable=too-many-statements
     def add_atest_args(self):
         """A function that does ArgumentParser.add_argument()"""
         self.add_argument('tests', nargs='*', help='Tests to build and/or run.')
@@ -135,6 +138,8 @@
                           help=INSTALL)
         self.add_argument('-m', constants.REBUILD_MODULE_INFO_FLAG,
                           action='store_true', help=REBUILD_MODULE_INFO)
+        self.add_argument('--no-modules-in', help=NO_MODULES_IN,
+                          action='store_true')
         self.add_argument('--sharding', nargs='?', const=2,
                           type=_positive_int, default=0,
                           help=SHARDING)
@@ -304,6 +309,7 @@
         LATEST_RESULT=LATEST_RESULT,
         LIST_MODULES=LIST_MODULES,
         NO_METRICS=NO_METRICS,
+        NO_MODULES_IN=NO_MODULES_IN,
         REBUILD_MODULE_INFO=REBUILD_MODULE_INFO,
         REQUEST_UPLOAD_RESULT=REQUEST_UPLOAD_RESULT,
         RERUN_UNTIL_FAILURE=RERUN_UNTIL_FAILURE,
@@ -353,7 +359,7 @@
         -d, --disable-teardown
             {DISABLE_TEARDOWN}
 
-        -D --tf-debug
+        -D, --tf-debug
             {TF_DEBUG}
 
         --host
@@ -368,6 +374,9 @@
         -m, --rebuild-module-info
             {REBUILD_MODULE_INFO} (default)
 
+        --no-modules-in
+            {NO_MODULES_IN}
+
         -s, --serial
             {SERIAL}
 
diff --git a/atest/constants_default.py b/atest/constants_default.py
index 8d0ee53..076426d 100644
--- a/atest/constants_default.py
+++ b/atest/constants_default.py
@@ -59,6 +59,7 @@
 FLAKES_INFO = 'FLAKES_INFO'
 TF_EARLY_DEVICE_RELEASE = 'TF_EARLY_DEVICE_RELEASE'
 REQUEST_UPLOAD_RESULT = 'REQUEST_UPLOAD_RESULT'
+MODULES_IN = 'MODULES-IN-'
 
 # Application exit codes.
 EXIT_CODE_SUCCESS = 0
diff --git a/atest/test_finders/cache_finder.py b/atest/test_finders/cache_finder.py
index 75c4c4d..951d925 100644
--- a/atest/test_finders/cache_finder.py
+++ b/atest/test_finders/cache_finder.py
@@ -120,7 +120,7 @@
         # If the cached build target can be found in current module-info, then
         # it is a valid build targets of the test.
         for build_target in t_info.build_targets:
-            if str(build_target).startswith('MODULES-IN-'):
+            if str(build_target).startswith(constants.MODULES_IN):
                 continue
             if not self.module_info.is_module(build_target):
                 logging.debug('%s is not a valid build target.', build_target)
diff --git a/atest/test_finders/module_finder.py b/atest/test_finders/module_finder.py
index e203732..f1dbfb4 100644
--- a/atest/test_finders/module_finder.py
+++ b/atest/test_finders/module_finder.py
@@ -33,7 +33,6 @@
 from test_runners import robolectric_test_runner
 from test_runners import vts_tf_test_runner
 
-_MODULES_IN = 'MODULES-IN-%s'
 _ANDROID_MK = 'Android.mk'
 
 # These are suites in LOCAL_COMPATIBILITY_SUITE that aren't really suites so
@@ -228,12 +227,16 @@
             targets.update(constants.SUITE_DEPS.get(suite, []))
         for module_path in self.module_info.get_paths(module_name):
             mod_dir = module_path.replace('/', '-')
-            targets.add(_MODULES_IN % mod_dir)
+            targets.add(constants.MODULES_IN + mod_dir)
         # (b/156457698) Force add vts_kernel_tests as build target if our test
         # belong to REQUIRED_KERNEL_TEST_MODULES due to required_module option
         # not working for sh_test in soong.
         if module_name in constants.REQUIRED_KERNEL_TEST_MODULES:
             targets.add('vts_kernel_tests')
+        # (b/184567849) Force adding module_name as a build_target. This will
+        # allow excluding MODULES-IN-* and prevent from missing build targets.
+        if module_name and self.module_info.is_module(module_name):
+            targets.add(module_name)
         return targets
 
     def _get_module_test_config(self, module_name, rel_config=None):
diff --git a/atest/test_finders/test_info.py b/atest/test_finders/test_info.py
index 61c3f72..fe3b550 100644
--- a/atest/test_finders/test_info.py
+++ b/atest/test_finders/test_info.py
@@ -125,10 +125,10 @@
         """
         test_paths = []
         for build_target in self.build_targets:
-            if str(build_target).startswith('MODULES-IN-'):
+            if str(build_target).startswith(constants.MODULES_IN):
                 test_paths.append(
                     str(build_target).replace(
-                        'MODULES-IN-', '').replace('-', '/'))
+                        constants.MODULES_IN, '').replace('-', '/'))
         return test_paths if test_paths else None
 
 class TestFilter(TestFilterBase):