From 3bcc6b3e0efcf338ffffdc62d87c29700e173313 Mon Sep 17 00:00:00 2001 From: Michal Majewski Date: Mon, 15 Jan 2018 18:43:18 +0100 Subject: [PATCH] [test] Filter tests based on cmd line processor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: v8:6917 Change-Id: I7fa8f1857f338551dd7acd1b25eb7e9feb376576 Cq-Include-Trybots: luci.v8.try:v8_linux64_fyi_rel_ng Reviewed-on: https://chromium-review.googlesource.com/866720 Reviewed-by: Michael Achenbach Commit-Queue: MichaƂ Majewski Cr-Commit-Position: refs/heads/master@{#50602} --- tools/testrunner/standard_runner.py | 18 ++++++++------ tools/testrunner/testproc/filter.py | 38 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/tools/testrunner/standard_runner.py b/tools/testrunner/standard_runner.py index 8361a9ce3e..29f6666702 100755 --- a/tools/testrunner/standard_runner.py +++ b/tools/testrunner/standard_runner.py @@ -27,7 +27,7 @@ from testrunner.local.variants import ALL_VARIANTS from testrunner.objects import context from testrunner.objects import predictable from testrunner.testproc.execution import ExecutionProc -from testrunner.testproc.filter import StatusFileFilterProc +from testrunner.testproc.filter import StatusFileFilterProc, NameFilterProc from testrunner.testproc.loader import LoadProc from testrunner.testproc.progress import (VerboseProgressIndicator, ResultsTracker) @@ -400,8 +400,10 @@ class StandardTestRunner(base_runner.BaseTestRunner): for s in suites: s.ReadStatusFile(variables) s.ReadTestCases(ctx) - if len(args) > 0: - s.FilterTestCasesByArgs(args) + if not options.infra_staging: + # Tests will be filtered in the test processors pipeline + if len(args) > 0: + s.FilterTestCasesByArgs(args) all_tests += s.tests # First filtering by status applying the generic rules (tests without @@ -486,8 +488,9 @@ class StandardTestRunner(base_runner.BaseTestRunner): outproc_factory = None if options.infra_staging: - exit_code = self._run_test_procs(suites, options, progress_indicator, - ctx, outproc_factory) + exit_code = self._run_test_procs(suites, args, options, + progress_indicator, ctx, + outproc_factory) else: runner = execution.Runner(suites, progress_indicator, ctx, outproc_factory) @@ -559,8 +562,8 @@ class StandardTestRunner(base_runner.BaseTestRunner): count += 1 return shard - def _run_test_procs(self, suites, options, progress_indicator, context, - outproc_factory): + def _run_test_procs(self, suites, args, options, progress_indicator, + context, outproc_factory): jobs = options.j print '>>> Running with test processors' @@ -570,6 +573,7 @@ class StandardTestRunner(base_runner.BaseTestRunner): procs = [ loader, + NameFilterProc(args), VariantProc(VARIANTS), StatusFileFilterProc(options.slow_tests, options.pass_fail_tests), results, diff --git a/tools/testrunner/testproc/filter.py b/tools/testrunner/testproc/filter.py index 7dc00cfb2f..4264ff013b 100644 --- a/tools/testrunner/testproc/filter.py +++ b/tools/testrunner/testproc/filter.py @@ -2,6 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from collections import defaultdict +import fnmatch + from . import base @@ -43,3 +46,38 @@ class StatusFileFilterProc(base.TestProcFilter): (self._pass_fail_tests_mode == 'run' and not is_pass_fail) or (self._pass_fail_tests_mode == 'skip' and is_pass_fail) ) + + +class NameFilterProc(base.TestProcFilter): + """Filters tests based on command-line arguments. + + args can be a glob: asterisks in any position of the name + represent zero or more characters. Without asterisks, only exact matches + will be used with the exeption of the test-suite name as argument. + """ + def __init__(self, args): + super(NameFilterProc, self).__init__() + + self._globs = defaultdict(list) + for a in args: + argpath = a.split('/') + suitename = argpath[0] + path = '/'.join(argpath[1:]) + self._globs[suitename].append(path) + + for s, globs in self._globs.iteritems(): + if not globs or '*' in globs: + self._globs[s] = [] + + def _filter(self, test): + globs = self._globs.get(test.suite.name) + if globs is None: + return True + + if not globs: + return False + + for g in globs: + if fnmatch.fnmatch(test.path, g): + return False + return True