Merge "Atest: stop running if there are mixed type filters" am: b08c7d0f09
Original change: https://android-review.googlesource.com/c/platform/tools/asuite/+/2031523
Change-Id: I5d756c8aa695cffe52e9fc693d9e6c19f6800df3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/atest/atest_enum.py b/atest/atest_enum.py
index 48a8fbf..f4405b3 100644
--- a/atest/atest_enum.py
+++ b/atest/atest_enum.py
@@ -16,7 +16,7 @@
Atest custom enum class.
"""
-from enum import IntEnum, unique
+from enum import IntEnum, unique, Enum
@unique
class DetectType(IntEnum):
@@ -63,6 +63,13 @@
AVD_INVALID_ARGS = 9
EXIT_BEFORE_MAIN = 10
DEVICE_NOT_FOUND = 11
+ MIXED_TYPE_FILTER = 12
+
+@unique
+class FilterType(Enum):
+ """An Enum class for filter types"""
+ WILDCARD_FILTER = 'wildcard class_method'
+ REGULAR_FILTER = 'regular class_method'
# TODO: (b/218441706) Convert AtestEnum to a real Enum class.
class AtestEnum(tuple):
diff --git a/atest/atest_utils.py b/atest/atest_utils.py
index a835add..0059ca0 100644
--- a/atest/atest_utils.py
+++ b/atest/atest_utils.py
@@ -44,7 +44,7 @@
import xml.etree.ElementTree as ET
-from atest_enum import DetectType
+from atest_enum import DetectType, FilterType
# This is a workaround of b/144743252, where the http.client failed to loaded
# because the googleapiclient was found before the built-in libs; enabling
@@ -143,6 +143,9 @@
_ROOT_PREPARER = "com.android.tradefed.targetprep.RootTargetPreparer"
+_WILDCARD_FILTER_RE = re.compile(r'.*[?|*]$')
+_REGULAR_FILTER_RE = re.compile(r'.*\w$')
+
def get_build_cmd(dump=False):
"""Compose build command with no-absolute path and flag "--make-mode".
@@ -1718,3 +1721,54 @@
if match:
return match.group('fqcn')
return ""
+
+def has_mixed_type_filters(test_infos):
+ """ There are different types in a test module.
+
+ Dict test_to_types is mapping module name and the set of types.
+ For example,
+ {
+ 'module_1': {'wildcard class_method'},
+ 'module_2': {'wildcard class_method', 'regular class_method'},
+ 'module_3': set()
+ }
+
+ Args:
+ test_infos: A set of TestInfos.
+
+ Returns:
+ True if more than one filter type in a test module, False otherwise.
+ """
+ test_to_types = dict()
+ for test_info in test_infos:
+ filters = test_info.data.get(constants.TI_FILTER, [])
+ filter_types = set()
+ for flt in filters:
+ filter_types |= get_filter_types(flt.to_set_of_tf_strings())
+ filter_types |= test_to_types.get(test_info.test_name, set())
+ test_to_types[test_info.test_name] = filter_types
+ for _, types in test_to_types.items():
+ if len(types) > 1:
+ return True
+ return False
+
+def get_filter_types(tf_filter_set):
+ """ Get filter types.
+
+ Args:
+ tf_filter_set: A set of tf filter strings.
+
+ Returns:
+ A set of FilterType.
+ """
+ type_set = set()
+ for tf_filter in tf_filter_set:
+ if _WILDCARD_FILTER_RE.match(tf_filter):
+ logging.debug('Filter and type: (%s, %s)',
+ tf_filter, FilterType.WILDCARD_FILTER.value)
+ type_set.add(FilterType.WILDCARD_FILTER.value)
+ if _REGULAR_FILTER_RE.match(tf_filter):
+ logging.debug('Filter and type: (%s, %s)',
+ tf_filter, FilterType.REGULAR_FILTER.value)
+ type_set.add(FilterType.REGULAR_FILTER.value)
+ return type_set
diff --git a/atest/atest_utils_unittest.py b/atest/atest_utils_unittest.py
index c63443c..c0a5de0 100755
--- a/atest/atest_utils_unittest.py
+++ b/atest/atest_utils_unittest.py
@@ -16,6 +16,7 @@
"""Unittests for atest_utils."""
+# pylint: disable=invalid-name
# pylint: disable=line-too-long
import hashlib
@@ -35,6 +36,7 @@
import unittest_constants
from test_finders import test_info
+from atest_enum import FilterType
TEST_MODULE_NAME_A = 'ModuleNameA'
@@ -690,5 +692,62 @@
self.assertNotEqual(
atest_utils.get_full_annotation_class_name(module_info, 'android.platform.test.annotations.pres'), presubmit)
+ def test_has_mixed_type_filters_one_module_with_one_type_return_false(self):
+ """Test method of has_mixed_type_filters"""
+ filter_1 = test_info.TestFilter('CLASS', frozenset(['METHOD']))
+ test_data_1 = {constants.TI_FILTER: [filter_1]}
+ test_info_1 = test_info.TestInfo('MODULE', 'RUNNER',
+ set(), test_data_1,
+ 'SUITE', '',
+ set())
+ self.assertFalse(atest_utils.has_mixed_type_filters([test_info_1]))
+
+ def test_has_mixed_type_filters_one_module_with_mixed_types_return_true(self):
+ """Test method of has_mixed_type_filters"""
+ filter_1 = test_info.TestFilter('CLASS', frozenset(['METHOD']))
+ filter_2 = test_info.TestFilter('CLASS', frozenset(['METHOD*']))
+ test_data_2 = {constants.TI_FILTER: [filter_1, filter_2]}
+ test_info_2 = test_info.TestInfo('MODULE', 'RUNNER',
+ set(), test_data_2,
+ 'SUITE', '',
+ set())
+ self.assertTrue(atest_utils.has_mixed_type_filters([test_info_2]))
+
+ def test_has_mixed_type_filters_two_module_with_mixed_types_return_false(self):
+ """Test method of has_mixed_type_filters"""
+ filter_1 = test_info.TestFilter('CLASS', frozenset(['METHOD']))
+ test_data_1 = {constants.TI_FILTER: [filter_1]}
+ test_info_1 = test_info.TestInfo('MODULE', 'RUNNER',
+ set(), test_data_1,
+ 'SUITE', '',
+ set())
+ filter_3 = test_info.TestFilter('CLASS', frozenset(['METHOD*']))
+ test_data_3 = {constants.TI_FILTER: [filter_3]}
+ test_info_3 = test_info.TestInfo('MODULE3', 'RUNNER',
+ set(), test_data_3,
+ 'SUITE', '',
+ set())
+ self.assertFalse(atest_utils.has_mixed_type_filters(
+ [test_info_1, test_info_3]))
+
+ def test_get_filter_types(self):
+ """Test method of get_filter_types."""
+ filters = set(['CLASS#METHOD'])
+ expect_types = set([FilterType.REGULAR_FILTER.value])
+ self.assertEqual(atest_utils.get_filter_types(filters), expect_types)
+
+ filters = set(['CLASS#METHOD*'])
+ expect_types = set([FilterType.WILDCARD_FILTER.value])
+ self.assertEqual(atest_utils.get_filter_types(filters), expect_types)
+
+ filters = set(['CLASS#METHOD', 'CLASS#METHOD*'])
+ expect_types = set([FilterType.WILDCARD_FILTER.value,
+ FilterType.REGULAR_FILTER.value])
+ self.assertEqual(atest_utils.get_filter_types(filters), expect_types)
+
+ filters = set(['CLASS#METHOD?', 'CLASS#METHOD*'])
+ expect_types = set([FilterType.WILDCARD_FILTER.value])
+ self.assertEqual(atest_utils.get_filter_types(filters), expect_types)
+
if __name__ == "__main__":
unittest.main()
diff --git a/atest/cli_translator.py b/atest/cli_translator.py
index 55cc410..a10f9b5 100644
--- a/atest/cli_translator.py
+++ b/atest/cli_translator.py
@@ -642,6 +642,12 @@
host_unit_test_infos = self._get_test_infos(host_unit_tests,
host_unit_test_details)
test_infos.update(host_unit_test_infos)
+ if atest_utils.has_mixed_type_filters(test_infos):
+ atest_utils.colorful_print(
+ 'Mixed type filters found. '
+ 'Please separate tests into different runs.',
+ constants.YELLOW)
+ sys.exit(ExitCode.MIXED_TYPE_FILTER)
finished_time = time.time() - start
logging.debug('Finding tests finished in %ss', finished_time)
metrics.LocalDetectEvent(