From 18d5fa5ebd46da901b0d6c65a52753bc720d8102 Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Wed, 5 Oct 2016 11:42:55 -0700 Subject: [PATCH 1/7] Create filter for pull request tests --- tools/run_tests/filter_pull_request_tests.py | 95 ++++++++++++++++++++ tools/run_tests/run_tests_matrix.py | 18 ++++ 2 files changed, 113 insertions(+) create mode 100644 tools/run_tests/filter_pull_request_tests.py diff --git a/tools/run_tests/filter_pull_request_tests.py b/tools/run_tests/filter_pull_request_tests.py new file mode 100644 index 00000000000..6cc06d9c409 --- /dev/null +++ b/tools/run_tests/filter_pull_request_tests.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python2.7 +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Filter out tests based on file differences compared to grpc:master""" + +from subprocess import call, check_output + +# triggers to skip c++ tests +run_cpp_starts_with_triggers = ('src/core', + 'src/cpp', + 'test/core', + 'test/cpp') + + +def _get_changed_files(): + """ + Get list of changed files between current branch and gRPC master branch + """ + # git fetch might need to be called on Jenkins slave + # todo(mattkwong): remove or uncomment below after seeing if Jenkins needs this + # call(['git', 'fetch']) + # this also collects files that are changed in the repo but not updated in the branch + return check_output(["git", "diff", "--name-only", "..origin/master"]).split() + + +def _can_skip_tests(file_names, starts_with_triggers=(), ends_with_triggers=()): + """ + Determines if tests are skippable based on if all file names do not match + any begin or end triggers + :param file_names: list of changed files generated by _get_changed_files() + :param starts_with_triggers: tuple of strings to match with beginning of file names + :param ends_with_triggers: tuple of strings to match with end of file names + :return: safe to skip tests + """ + for file_name in file_names: + if starts_with_triggers and file_name.startswith(starts_with_triggers) or \ + ends_with_triggers and file_name.endswith(ends_with_triggers): + return False + return True + + +def _remove_irrelevant_tests(tests, tag): + """ + Filters out tests by config or language + :param tests: list of all tests generated by run_tests_matrix.py + :param tag: string representing language or config to filter - "_(language)_" or "_(config)" + :return: list of relevant tests + """ + return [test for test in tests if not tag in test.shortname] + + +def filter_tests(tests): + """ + Filters out tests that are safe to ignore + :param tests: list of all tests generated by run_tests_matrix.py + :return: list of relevant tests + """ + print("Finding file differences between grpc:master repo and pull request...") + changed_files = _get_changed_files() + for changed_file in changed_files: + print(changed_file) + # C++, tsan, msan, and asan have the same filter + if _can_skip_tests(changed_files, starts_with_triggers=run_cpp_starts_with_triggers): + tests = _remove_irrelevant_tests(tests, '_c++_') # filter out c++ tests + tests = _remove_irrelevant_tests(tests, '_tsan') # filter out tsan tests + tests = _remove_irrelevant_tests(tests, '_msan') # filter out msan tests + tests = _remove_irrelevant_tests(tests, '_asan') # filter out asan tests + return tests diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py index 60c21a1e218..235bd162be0 100755 --- a/tools/run_tests/run_tests_matrix.py +++ b/tools/run_tests/run_tests_matrix.py @@ -36,6 +36,7 @@ import multiprocessing import os import report_utils import sys +from filter_pull_request_tests import filter_tests _ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..')) os.chdir(_ROOT) @@ -231,6 +232,11 @@ argp.add_argument('--dry_run', action='store_const', const=True, help='Only print what would be run.') +argp.add_argument('--filter_pr_tests', + default=False, + action='store_const', + const=True, + help='Filters out tests irrelavant to pull request changes.') args = argp.parse_args() extra_args = [] @@ -264,6 +270,18 @@ for job in jobs: print ' %s' % job.shortname print +if args.filter_pr_tests: + print 'IMPORTANT: Test filtering is not active; this is only for testing.' + relevant_jobs = filter_tests(jobs) + print + if len(relevant_jobs) == len(jobs): + print 'No tests were filtered.' + else: + print 'These tests were filtered:' + for job in list(set(jobs) - set(relevant_jobs)): + print ' %s' % job.shortname + print + if args.dry_run: print '--dry_run was used, exiting' sys.exit(1) From 44920d2cc601ccbc7f515fbbce13dd27565c8b77 Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Thu, 6 Oct 2016 18:18:11 -0700 Subject: [PATCH 2/7] Fixed some changes --- tools/run_tests/filter_pull_request_tests.py | 170 +++++++++++++++++-- 1 file changed, 153 insertions(+), 17 deletions(-) diff --git a/tools/run_tests/filter_pull_request_tests.py b/tools/run_tests/filter_pull_request_tests.py index 6cc06d9c409..fe8b8ed0f35 100644 --- a/tools/run_tests/filter_pull_request_tests.py +++ b/tools/run_tests/filter_pull_request_tests.py @@ -28,29 +28,101 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Filter out tests based on file differences compared to grpc:master""" +"""Filter out tests based on file differences compared to merge target branch""" from subprocess import call, check_output -# triggers to skip c++ tests -run_cpp_starts_with_triggers = ('src/core', - 'src/cpp', - 'test/core', - 'test/cpp') +# Whitelist for all tests +# Update all instances in corresponding trigger lists when modifying this +starts_with_whitelist = ['templates/', + 'doc/', + 'examples/', + 'summerofcode/', + 'src/cpp', + 'src/csharp', + 'src/node', + 'src/objective-c', + 'src/php', + 'src/python', + 'src/ruby', + 'test/core', + 'test/cpp', + 'test/distrib/cpp', + 'test/distrib/csharp', + 'test/distrib/node', + 'test/distrib/php', + 'test/distrib/python', + 'test/distrib/ruby'] + +ends_with_whitelist = ['README.md', + 'LICENSE'] + +# Triggers for core tests +core_starts_with_triggers = ['test/core'] + +# Triggers for c++ tests +cpp_starts_with_triggers = ['src/cpp', + 'test/cpp', + 'test/distrib/cpp'] + +# Triggers for c# tests +csharp_starts_with_triggers = ['src/csharp', + 'test/distrib/csharp'] + +# Triggers for node tests +node_starts_with_triggers = ['src/node', + 'test/distrib/node'] + +# Triggers for objective-c tests +objc_starts_with_triggers = ['src/objective-c'] + +# Triggers for php tests +php_starts_with_triggers = ['src/php', + 'test/distrib/php'] + +# Triggers for python tests +python_starts_with_triggers = ['src/python', + 'test/distrib/python'] + +# Triggers for ruby tests +ruby_starts_with_triggers = ['src/ruby', + 'test/distrib/ruby'] + + +def _filter_whitelist(whitelist, triggers): + """ + Removes triggers from whitelist + :param whitelist: list to remove values from + :param triggers: list of values to remove from whitelist + :return: filtered whitelist + """ + filtered_whitelist = list(whitelist) + for trigger in triggers: + if trigger in filtered_whitelist: + filtered_whitelist.remove(trigger) + else: + """ + If the trigger is not found in the whitelist, then there is likely + a mistake in the whitelist or trigger list, which needs to be addressed + to not wrongly skip tests + """ + print("ERROR: '%s' trigger not in whitelist. Please fix this!" % trigger) + return filtered_whitelist def _get_changed_files(): """ - Get list of changed files between current branch and gRPC master branch + Get list of changed files between current branch and base of target merge branch """ # git fetch might need to be called on Jenkins slave # todo(mattkwong): remove or uncomment below after seeing if Jenkins needs this # call(['git', 'fetch']) # this also collects files that are changed in the repo but not updated in the branch - return check_output(["git", "diff", "--name-only", "..origin/master"]).split() + # todo(mattkwong): change this to only collect changes files compared to base and not hardcode branch + return check_output(["git", "diff", "--name-only", "..origin/master"]).splitlines() -def _can_skip_tests(file_names, starts_with_triggers=(), ends_with_triggers=()): +def _can_skip_tests(file_names, starts_with_whitelist=[], ends_with_whitelist=[]): """ Determines if tests are skippable based on if all file names do not match any begin or end triggers @@ -59,9 +131,13 @@ def _can_skip_tests(file_names, starts_with_triggers=(), ends_with_triggers=()): :param ends_with_triggers: tuple of strings to match with end of file names :return: safe to skip tests """ + # convert lists to tuple to pass into str.startswith() and str.endswith() + starts_with_whitelist = tuple(starts_with_whitelist) + ends_with_whitelist = tuple(ends_with_whitelist) + print (starts_with_whitelist) for file_name in file_names: - if starts_with_triggers and file_name.startswith(starts_with_triggers) or \ - ends_with_triggers and file_name.endswith(ends_with_triggers): + if starts_with_whitelist and not file_name.startswith(starts_with_whitelist) and \ + ends_with_whitelist and not file_name.endswith(ends_with_whitelist): return False return True @@ -73,6 +149,7 @@ def _remove_irrelevant_tests(tests, tag): :param tag: string representing language or config to filter - "_(language)_" or "_(config)" :return: list of relevant tests """ + # todo(mattkwong): find a more reliable way to filter tests - don't use shortname return [test for test in tests if not tag in test.shortname] @@ -86,10 +163,69 @@ def filter_tests(tests): changed_files = _get_changed_files() for changed_file in changed_files: print(changed_file) - # C++, tsan, msan, and asan have the same filter - if _can_skip_tests(changed_files, starts_with_triggers=run_cpp_starts_with_triggers): - tests = _remove_irrelevant_tests(tests, '_c++_') # filter out c++ tests - tests = _remove_irrelevant_tests(tests, '_tsan') # filter out tsan tests - tests = _remove_irrelevant_tests(tests, '_msan') # filter out msan tests - tests = _remove_irrelevant_tests(tests, '_asan') # filter out asan tests + + changed_files = ['src/ruby/dgf'] + + # Filter core tests + skip_core = _can_skip_tests(changed_files, + starts_with_whitelist=_filter_whitelist(starts_with_whitelist, core_starts_with_triggers), + ends_with_whitelist=ends_with_whitelist) + if skip_core: + tests = _remove_irrelevant_tests(tests, '_c_') + + # Filter c++ tests + skip_cpp = _can_skip_tests(changed_files, + starts_with_whitelist=_filter_whitelist(starts_with_whitelist, cpp_starts_with_triggers), + ends_with_whitelist=ends_with_whitelist) + if skip_cpp: + tests = _remove_irrelevant_tests(tests, '_cpp_') + + # Tsan, msan, and asan tests skipped if core and c++ are skipped + if skip_core and skip_cpp: + tests = _remove_irrelevant_tests(tests, '_tsan') + tests = _remove_irrelevant_tests(tests, '_msan') + tests = _remove_irrelevant_tests(tests, '_asan') + + # Filter c# tests + skip_csharp = _can_skip_tests(changed_files, + starts_with_whitelist=_filter_whitelist(starts_with_whitelist, csharp_starts_with_triggers), + ends_with_whitelist=ends_with_whitelist) + if skip_csharp: + tests = _remove_irrelevant_tests(tests, '_csharp_') + + # Filter node tests + skip_node = _can_skip_tests(changed_files, + starts_with_whitelist=_filter_whitelist(starts_with_whitelist, node_starts_with_triggers), + ends_with_whitelist=ends_with_whitelist) + if skip_node: + tests = _remove_irrelevant_tests(tests, '_node_') + + # Filter objc tests + skip_objc = _can_skip_tests(changed_files, + starts_with_whitelist=_filter_whitelist(starts_with_whitelist, objc_starts_with_triggers), + ends_with_whitelist=ends_with_whitelist) + if skip_objc: + tests = _remove_irrelevant_tests(tests, '_objc_') + + # Filter php tests + skip_php = _can_skip_tests(changed_files, + starts_with_whitelist=_filter_whitelist(starts_with_whitelist, php_starts_with_triggers), + ends_with_whitelist=ends_with_whitelist) + if skip_php: + tests = _remove_irrelevant_tests(tests, '_php_') + + # Filter python tests + skip_python = _can_skip_tests(changed_files, + starts_with_whitelist=_filter_whitelist(starts_with_whitelist, python_starts_with_triggers), + ends_with_whitelist=ends_with_whitelist) + if skip_python: + tests = _remove_irrelevant_tests(tests, '_python_') + + # Filter ruby tests + skip_ruby = _can_skip_tests(changed_files, + starts_with_whitelist=_filter_whitelist(starts_with_whitelist, ruby_starts_with_triggers), + ends_with_whitelist=ends_with_whitelist) + if skip_ruby: + tests = _remove_irrelevant_tests(tests, '_ruby_') + return tests From 0f546b6f32f4751b7231ee455e92a423005a6bc2 Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Fri, 7 Oct 2016 15:25:56 -0700 Subject: [PATCH 3/7] changed filter to be more conservative - any no-whitelisted file runs all tests --- tools/run_tests/filter_pull_request_tests.py | 58 ++++++++++++++------ tools/run_tests/run_tests_matrix.py | 10 +++- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/tools/run_tests/filter_pull_request_tests.py b/tools/run_tests/filter_pull_request_tests.py index fe8b8ed0f35..29dbd978251 100644 --- a/tools/run_tests/filter_pull_request_tests.py +++ b/tools/run_tests/filter_pull_request_tests.py @@ -33,7 +33,8 @@ from subprocess import call, check_output # Whitelist for all tests -# Update all instances in corresponding trigger lists when modifying this +# If whitelist item should only trigger some tests, the item should be +# added to this list and the trigger list of tests that should be run starts_with_whitelist = ['templates/', 'doc/', 'examples/', @@ -110,16 +111,18 @@ def _filter_whitelist(whitelist, triggers): return filtered_whitelist -def _get_changed_files(): +def _get_changed_files(base_branch): """ Get list of changed files between current branch and base of target merge branch """ # git fetch might need to be called on Jenkins slave # todo(mattkwong): remove or uncomment below after seeing if Jenkins needs this # call(['git', 'fetch']) - # this also collects files that are changed in the repo but not updated in the branch - # todo(mattkwong): change this to only collect changes files compared to base and not hardcode branch - return check_output(["git", "diff", "--name-only", "..origin/master"]).splitlines() + + # get file changes between branch and merge-base of specified branch + # not combined to be Windows friendly + base_commit = check_output(["git", "merge-base", base_branch, "HEAD"]).rstrip() + return check_output(["git", "diff", base_commit, "--name-only"]).splitlines() def _can_skip_tests(file_names, starts_with_whitelist=[], ends_with_whitelist=[]): @@ -134,7 +137,6 @@ def _can_skip_tests(file_names, starts_with_whitelist=[], ends_with_whitelist=[] # convert lists to tuple to pass into str.startswith() and str.endswith() starts_with_whitelist = tuple(starts_with_whitelist) ends_with_whitelist = tuple(ends_with_whitelist) - print (starts_with_whitelist) for file_name in file_names: if starts_with_whitelist and not file_name.startswith(starts_with_whitelist) and \ ends_with_whitelist and not file_name.endswith(ends_with_whitelist): @@ -144,28 +146,48 @@ def _can_skip_tests(file_names, starts_with_whitelist=[], ends_with_whitelist=[] def _remove_irrelevant_tests(tests, tag): """ - Filters out tests by config or language + Filters out tests by config or language - will not remove sanitizer tests :param tests: list of all tests generated by run_tests_matrix.py :param tag: string representing language or config to filter - "_(language)_" or "_(config)" :return: list of relevant tests """ # todo(mattkwong): find a more reliable way to filter tests - don't use shortname - return [test for test in tests if not tag in test.shortname] + return [test for test in tests if + tag not in test.shortname or + '_msan' in test.shortname or + '_asan' in test.shortname or + '_tsan' in test.shortname] -def filter_tests(tests): +def _remove_irrelevant_sanitizer_tests(tests, language_tag=""): + """ + Filters out sanitizer tests - can specify a language to filter - this should be c++ only + :param tests: list of all tests generated by run_tests_matrix.py + :param language_tag: string specifying a language from which to filter sanitizer tests - "_(language)_" + :return: list of relevant tests + """ + if language_tag: + return [test for test in tests if not language_tag in test.shortname and + not '_asan' in test.shortname and + not '_msan' in test.shortname and + not '_tsan' in test.shortname] + else: + return [test for test in tests if + '_asan' not in test.shortname and + '_msan' not in test.shortname and + '_tsan' not in test.shortname] + +def filter_tests(tests, base_branch): """ Filters out tests that are safe to ignore :param tests: list of all tests generated by run_tests_matrix.py :return: list of relevant tests """ - print("Finding file differences between grpc:master repo and pull request...") - changed_files = _get_changed_files() + print("Finding file differences between %s repo and current branch..." % base_branch) + changed_files = _get_changed_files(base_branch) for changed_file in changed_files: print(changed_file) - changed_files = ['src/ruby/dgf'] - # Filter core tests skip_core = _can_skip_tests(changed_files, starts_with_whitelist=_filter_whitelist(starts_with_whitelist, core_starts_with_triggers), @@ -178,13 +200,12 @@ def filter_tests(tests): starts_with_whitelist=_filter_whitelist(starts_with_whitelist, cpp_starts_with_triggers), ends_with_whitelist=ends_with_whitelist) if skip_cpp: - tests = _remove_irrelevant_tests(tests, '_cpp_') + tests = _remove_irrelevant_tests(tests, '_c++_') + tests = _remove_irrelevant_sanitizer_tests(tests, language_tag='_c++_') - # Tsan, msan, and asan tests skipped if core and c++ are skipped + # Sanitizer tests skipped if core and c++ are skipped if skip_core and skip_cpp: - tests = _remove_irrelevant_tests(tests, '_tsan') - tests = _remove_irrelevant_tests(tests, '_msan') - tests = _remove_irrelevant_tests(tests, '_asan') + tests = _remove_irrelevant_sanitizer_tests(tests) # Filter c# tests skip_csharp = _can_skip_tests(changed_files, @@ -213,6 +234,7 @@ def filter_tests(tests): ends_with_whitelist=ends_with_whitelist) if skip_php: tests = _remove_irrelevant_tests(tests, '_php_') + tests = _remove_irrelevant_tests(tests, '_php7_') # Filter python tests skip_python = _can_skip_tests(changed_files, diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py index 235bd162be0..7548f6d90d9 100755 --- a/tools/run_tests/run_tests_matrix.py +++ b/tools/run_tests/run_tests_matrix.py @@ -237,6 +237,10 @@ argp.add_argument('--filter_pr_tests', action='store_const', const=True, help='Filters out tests irrelavant to pull request changes.') +argp.add_argument('--base_branch', + default='origin/master', + type=str, + help='Branch that pull request is requesting to merge into') args = argp.parse_args() extra_args = [] @@ -272,12 +276,12 @@ print if args.filter_pr_tests: print 'IMPORTANT: Test filtering is not active; this is only for testing.' - relevant_jobs = filter_tests(jobs) + relevant_jobs = filter_tests(jobs, args.base_branch) print if len(relevant_jobs) == len(jobs): - print 'No tests were filtered.' + print '(TESTING) No tests will be skipped.' else: - print 'These tests were filtered:' + print '(TESTING) These tests will be skipped:' for job in list(set(jobs) - set(relevant_jobs)): print ' %s' % job.shortname print From 3020bb792cf84122ddfbbdaf9ab5f222ad7d0dad Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Wed, 12 Oct 2016 18:24:53 -0700 Subject: [PATCH 4/7] Made whitelisting files easier and more intuitive --- tools/run_tests/filter_pull_request_tests.py | 265 +++++++------------ tools/run_tests/run_tests_matrix.py | 1 + 2 files changed, 99 insertions(+), 167 deletions(-) diff --git a/tools/run_tests/filter_pull_request_tests.py b/tools/run_tests/filter_pull_request_tests.py index 29dbd978251..55dab42f8a7 100644 --- a/tools/run_tests/filter_pull_request_tests.py +++ b/tools/run_tests/filter_pull_request_tests.py @@ -30,85 +30,76 @@ """Filter out tests based on file differences compared to merge target branch""" +import re from subprocess import call, check_output -# Whitelist for all tests -# If whitelist item should only trigger some tests, the item should be -# added to this list and the trigger list of tests that should be run -starts_with_whitelist = ['templates/', - 'doc/', - 'examples/', - 'summerofcode/', - 'src/cpp', - 'src/csharp', - 'src/node', - 'src/objective-c', - 'src/php', - 'src/python', - 'src/ruby', - 'test/core', - 'test/cpp', - 'test/distrib/cpp', - 'test/distrib/csharp', - 'test/distrib/node', - 'test/distrib/php', - 'test/distrib/python', - 'test/distrib/ruby'] - -ends_with_whitelist = ['README.md', - 'LICENSE'] - -# Triggers for core tests -core_starts_with_triggers = ['test/core'] - -# Triggers for c++ tests -cpp_starts_with_triggers = ['src/cpp', - 'test/cpp', - 'test/distrib/cpp'] - -# Triggers for c# tests -csharp_starts_with_triggers = ['src/csharp', - 'test/distrib/csharp'] - -# Triggers for node tests -node_starts_with_triggers = ['src/node', - 'test/distrib/node'] - -# Triggers for objective-c tests -objc_starts_with_triggers = ['src/objective-c'] - -# Triggers for php tests -php_starts_with_triggers = ['src/php', - 'test/distrib/php'] - -# Triggers for python tests -python_starts_with_triggers = ['src/python', - 'test/distrib/python'] - -# Triggers for ruby tests -ruby_starts_with_triggers = ['src/ruby', - 'test/distrib/ruby'] - - -def _filter_whitelist(whitelist, triggers): + +class TestSuite: """ - Removes triggers from whitelist - :param whitelist: list to remove values from - :param triggers: list of values to remove from whitelist - :return: filtered whitelist + Contains tag to identify job as belonging to this test suite and + triggers to identify if changed files are relevant """ - filtered_whitelist = list(whitelist) - for trigger in triggers: - if trigger in filtered_whitelist: - filtered_whitelist.remove(trigger) - else: - """ - If the trigger is not found in the whitelist, then there is likely - a mistake in the whitelist or trigger list, which needs to be addressed - to not wrongly skip tests - """ - print("ERROR: '%s' trigger not in whitelist. Please fix this!" % trigger) - return filtered_whitelist + def __init__(self, tags): + """ + Build TestSuite to group tests by their tags + :param tag: string used to identify if a job belongs to this TestSuite + todo(mattkwong): Change the use of tag because do not want to depend on + job.shortname to identify what suite a test belongs to + """ + self.triggers = [] + self.tags = tags + + def add_trigger(self, trigger): + """ + Add a regex to list of triggers that determine if a changed file should run tests + :param trigger: regex matching file relevant to tests + """ + self.triggers.append(trigger) + +# Create test suites +_core_test_suite = TestSuite(['_c_']) +_cpp_test_suite = TestSuite(['_c++_']) +_csharp_test_suite = TestSuite(['_csharp_']) +_node_test_suite = TestSuite(['_node_']) +_objc_test_suite = TestSuite(['_objc_']) +_php_test_suite = TestSuite(['_php_', '_php7_']) +_python_test_suite = TestSuite(['_python_']) +_ruby_test_suite = TestSuite(['_ruby']) +_all_test_suites = [_core_test_suite, _cpp_test_suite, _csharp_test_suite, + _node_test_suite, _objc_test_suite, _php_test_suite, + _python_test_suite, _ruby_test_suite] + +# Dictionary of whitelistable files where the key is a regex matching changed files +# and the value is a list of tests that should be run. An empty list means that +# the changed files should not trigger any tests. Any changed file that does not +# match any of these regexes will trigger all tests +_WHITELIST_DICT = { + '^templates/.*': [], + '^doc/.*': [], + '^examples/.*': [], + '^summerofcode/.*': [], + '.*README.md$': [], + '.*LICENSE$': [], + '^src/cpp.*': [_cpp_test_suite], + '^src/csharp.*': [_csharp_test_suite], + '^src/node.*': [_node_test_suite], + '^src/objective-c.*': [_objc_test_suite], + '^src/php.*': [_php_test_suite], + '^src/python.*': [_python_test_suite], + '^src/ruby.*': [_ruby_test_suite], + '^test/core.*': [_core_test_suite], + '^test/cpp.*': [_cpp_test_suite], + '^test/distrib/cpp.*': [_cpp_test_suite], + '^test/distrib/csharp.*': [_csharp_test_suite], + '^test/distrib/node.*': [_node_test_suite], + '^test/distrib/php.*': [_php_test_suite], + '^test/distrib/python.*': [_python_test_suite], + '^test/distrib/ruby.*': [_ruby_test_suite] +} +# Add all triggers to their respective test suites +for trigger, test_suites in _WHITELIST_DICT.iteritems(): + for test_suite in test_suites: + test_suite.add_trigger(trigger) def _get_changed_files(base_branch): @@ -119,28 +110,22 @@ def _get_changed_files(base_branch): # todo(mattkwong): remove or uncomment below after seeing if Jenkins needs this # call(['git', 'fetch']) - # get file changes between branch and merge-base of specified branch - # not combined to be Windows friendly + # Get file changes between branch and merge-base of specified branch + # Not combined to be Windows friendly base_commit = check_output(["git", "merge-base", base_branch, "HEAD"]).rstrip() return check_output(["git", "diff", base_commit, "--name-only"]).splitlines() -def _can_skip_tests(file_names, starts_with_whitelist=[], ends_with_whitelist=[]): +def _can_skip_tests(file_names, triggers): """ - Determines if tests are skippable based on if all file names do not match - any begin or end triggers + Determines if tests are skippable based on if all files do not match list of regexes :param file_names: list of changed files generated by _get_changed_files() - :param starts_with_triggers: tuple of strings to match with beginning of file names - :param ends_with_triggers: tuple of strings to match with end of file names + :param triggers: list of regexes matching file name that indicates tests should be run :return: safe to skip tests """ - # convert lists to tuple to pass into str.startswith() and str.endswith() - starts_with_whitelist = tuple(starts_with_whitelist) - ends_with_whitelist = tuple(ends_with_whitelist) for file_name in file_names: - if starts_with_whitelist and not file_name.startswith(starts_with_whitelist) and \ - ends_with_whitelist and not file_name.endswith(ends_with_whitelist): - return False + if any(re.match(trigger, file_name) for trigger in triggers): + return False return True @@ -152,30 +137,20 @@ def _remove_irrelevant_tests(tests, tag): :return: list of relevant tests """ # todo(mattkwong): find a more reliable way to filter tests - don't use shortname - return [test for test in tests if - tag not in test.shortname or - '_msan' in test.shortname or - '_asan' in test.shortname or - '_tsan' in test.shortname] + return [test for test in tests if tag not in test.shortname or + any(san_tag in test.shortname for san_tag in ['_asan', '_tsan', '_msan'])] -def _remove_irrelevant_sanitizer_tests(tests, language_tag=""): +def _remove_sanitizer_tests(tests): """ - Filters out sanitizer tests - can specify a language to filter - this should be c++ only + Filters out sanitizer tests :param tests: list of all tests generated by run_tests_matrix.py - :param language_tag: string specifying a language from which to filter sanitizer tests - "_(language)_" :return: list of relevant tests """ - if language_tag: - return [test for test in tests if not language_tag in test.shortname and - not '_asan' in test.shortname and - not '_msan' in test.shortname and - not '_tsan' in test.shortname] - else: - return [test for test in tests if - '_asan' not in test.shortname and - '_msan' not in test.shortname and - '_tsan' not in test.shortname] + # todo(mattkwong): find a more reliable way to filter tests - don't use shortname + return [test for test in tests if + all(san_tag not in test.shortname for san_tag in ['_asan', '_tsan', '_msan'])] + def filter_tests(tests, base_branch): """ @@ -183,71 +158,27 @@ def filter_tests(tests, base_branch): :param tests: list of all tests generated by run_tests_matrix.py :return: list of relevant tests """ - print("Finding file differences between %s repo and current branch..." % base_branch) + print("Finding file differences between %s repo and current branch...\n" % base_branch) changed_files = _get_changed_files(base_branch) for changed_file in changed_files: print(changed_file) + print - # Filter core tests - skip_core = _can_skip_tests(changed_files, - starts_with_whitelist=_filter_whitelist(starts_with_whitelist, core_starts_with_triggers), - ends_with_whitelist=ends_with_whitelist) - if skip_core: - tests = _remove_irrelevant_tests(tests, '_c_') - - # Filter c++ tests - skip_cpp = _can_skip_tests(changed_files, - starts_with_whitelist=_filter_whitelist(starts_with_whitelist, cpp_starts_with_triggers), - ends_with_whitelist=ends_with_whitelist) - if skip_cpp: - tests = _remove_irrelevant_tests(tests, '_c++_') - tests = _remove_irrelevant_sanitizer_tests(tests, language_tag='_c++_') - + # Regex that combines all keys in _WHITELIST_DICT + all_triggers = "(" + ")|(".join(_WHITELIST_DICT.keys()) + ")" + # Check if all tests have to be run + for changed_file in changed_files: + if not re.match(all_triggers, changed_file): + return(tests) + # Filter out tests by language + for test_suite in _all_test_suites: + if _can_skip_tests(changed_files, test_suite.triggers): + for tag in test_suite.tags: + print(" Filtering %s tests" % tag) + tests = _remove_irrelevant_tests(tests, tag) # Sanitizer tests skipped if core and c++ are skipped - if skip_core and skip_cpp: - tests = _remove_irrelevant_sanitizer_tests(tests) - - # Filter c# tests - skip_csharp = _can_skip_tests(changed_files, - starts_with_whitelist=_filter_whitelist(starts_with_whitelist, csharp_starts_with_triggers), - ends_with_whitelist=ends_with_whitelist) - if skip_csharp: - tests = _remove_irrelevant_tests(tests, '_csharp_') - - # Filter node tests - skip_node = _can_skip_tests(changed_files, - starts_with_whitelist=_filter_whitelist(starts_with_whitelist, node_starts_with_triggers), - ends_with_whitelist=ends_with_whitelist) - if skip_node: - tests = _remove_irrelevant_tests(tests, '_node_') - - # Filter objc tests - skip_objc = _can_skip_tests(changed_files, - starts_with_whitelist=_filter_whitelist(starts_with_whitelist, objc_starts_with_triggers), - ends_with_whitelist=ends_with_whitelist) - if skip_objc: - tests = _remove_irrelevant_tests(tests, '_objc_') - - # Filter php tests - skip_php = _can_skip_tests(changed_files, - starts_with_whitelist=_filter_whitelist(starts_with_whitelist, php_starts_with_triggers), - ends_with_whitelist=ends_with_whitelist) - if skip_php: - tests = _remove_irrelevant_tests(tests, '_php_') - tests = _remove_irrelevant_tests(tests, '_php7_') - - # Filter python tests - skip_python = _can_skip_tests(changed_files, - starts_with_whitelist=_filter_whitelist(starts_with_whitelist, python_starts_with_triggers), - ends_with_whitelist=ends_with_whitelist) - if skip_python: - tests = _remove_irrelevant_tests(tests, '_python_') - - # Filter ruby tests - skip_ruby = _can_skip_tests(changed_files, - starts_with_whitelist=_filter_whitelist(starts_with_whitelist, ruby_starts_with_triggers), - ends_with_whitelist=ends_with_whitelist) - if skip_ruby: - tests = _remove_irrelevant_tests(tests, '_ruby_') + if _can_skip_tests(changed_files, _cpp_test_suite.triggers + _core_test_suite.triggers): + print(" Filtering Sanitizer tests") + tests = _remove_sanitizer_tests(tests) return tests diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py index 7548f6d90d9..21d3dd4a0bc 100755 --- a/tools/run_tests/run_tests_matrix.py +++ b/tools/run_tests/run_tests_matrix.py @@ -277,6 +277,7 @@ print if args.filter_pr_tests: print 'IMPORTANT: Test filtering is not active; this is only for testing.' relevant_jobs = filter_tests(jobs, args.base_branch) + # todo(mattkwong): add skipped tests to report.xml print if len(relevant_jobs) == len(jobs): print '(TESTING) No tests will be skipped.' From f62140d56a980fde27ceab5ee059cf2450fa5c88 Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Mon, 17 Oct 2016 12:16:14 -0700 Subject: [PATCH 5/7] improve pull request test filtering --- tools/run_tests/filter_pull_request_tests.py | 110 ++++++++++--------- 1 file changed, 59 insertions(+), 51 deletions(-) diff --git a/tools/run_tests/filter_pull_request_tests.py b/tools/run_tests/filter_pull_request_tests.py index 55dab42f8a7..128370e1914 100644 --- a/tools/run_tests/filter_pull_request_tests.py +++ b/tools/run_tests/filter_pull_request_tests.py @@ -57,44 +57,68 @@ class TestSuite: self.triggers.append(trigger) # Create test suites -_core_test_suite = TestSuite(['_c_']) -_cpp_test_suite = TestSuite(['_c++_']) -_csharp_test_suite = TestSuite(['_csharp_']) -_node_test_suite = TestSuite(['_node_']) -_objc_test_suite = TestSuite(['_objc_']) -_php_test_suite = TestSuite(['_php_', '_php7_']) -_python_test_suite = TestSuite(['_python_']) -_ruby_test_suite = TestSuite(['_ruby']) -_all_test_suites = [_core_test_suite, _cpp_test_suite, _csharp_test_suite, - _node_test_suite, _objc_test_suite, _php_test_suite, - _python_test_suite, _ruby_test_suite] +_CORE_TEST_SUITE = TestSuite(['_c_']) +_CPP_TEST_SUITE = TestSuite(['_c++_']) +_CSHARP_TEST_SUITE = TestSuite(['_csharp_']) +_NODE_TEST_SUITE = TestSuite(['_node_']) +_OBJC_TEST_SUITE = TestSuite(['_objc_']) +_PHP_TEST_SUITE = TestSuite(['_php_', '_php7_']) +_PYTHON_TEST_SUITE = TestSuite(['_python_']) +_RUBY_TEST_SUITE = TestSuite(['_ruby']) +_ALL_TEST_SUITES = [_CORE_TEST_SUITE, _CPP_TEST_SUITE, _CSHARP_TEST_SUITE, + _NODE_TEST_SUITE, _OBJC_TEST_SUITE, _PHP_TEST_SUITE, + _PYTHON_TEST_SUITE, _RUBY_TEST_SUITE] # Dictionary of whitelistable files where the key is a regex matching changed files # and the value is a list of tests that should be run. An empty list means that # the changed files should not trigger any tests. Any changed file that does not # match any of these regexes will trigger all tests _WHITELIST_DICT = { - '^templates/.*': [], - '^doc/.*': [], - '^examples/.*': [], - '^summerofcode/.*': [], - '.*README.md$': [], - '.*LICENSE$': [], - '^src/cpp.*': [_cpp_test_suite], - '^src/csharp.*': [_csharp_test_suite], - '^src/node.*': [_node_test_suite], - '^src/objective-c.*': [_objc_test_suite], - '^src/php.*': [_php_test_suite], - '^src/python.*': [_python_test_suite], - '^src/ruby.*': [_ruby_test_suite], - '^test/core.*': [_core_test_suite], - '^test/cpp.*': [_cpp_test_suite], - '^test/distrib/cpp.*': [_cpp_test_suite], - '^test/distrib/csharp.*': [_csharp_test_suite], - '^test/distrib/node.*': [_node_test_suite], - '^test/distrib/php.*': [_php_test_suite], - '^test/distrib/python.*': [_python_test_suite], - '^test/distrib/ruby.*': [_ruby_test_suite] + #'^templates/.*': [_sanity_test_suite], + # todo(mattkwong): add sanity test suite + '^doc/': [], + '^examples/': [], + '^summerofcode/': [], + 'README\.md$': [], + 'CONTRIBUTING\.md$': [], + 'LICENSE$': [], + 'INSTALL\.md$': [], + 'MANIFEST\.md$': [], + 'PATENTS$': [], + 'binding\.grp$': [_NODE_TEST_SUITE], + 'gRPC\-Core\.podspec$': [_OBJC_TEST_SUITE], + 'gRPC\-ProtoRPC\.podspec$': [_OBJC_TEST_SUITE], + 'gRPC\-RxLibrary\.podspec$': [_OBJC_TEST_SUITE], + 'gRPC\.podspec$': [_OBJC_TEST_SUITE], + 'composer\.json$': [_PHP_TEST_SUITE], + 'config\.m4$': [_PHP_TEST_SUITE], + 'package\.json$': [_PHP_TEST_SUITE], + 'package\.xml$': [_PHP_TEST_SUITE], + 'PYTHON\-MANIFEST\.in$': [_PYTHON_TEST_SUITE], + 'requirements\.txt$': [_PYTHON_TEST_SUITE], + 'setup\.cfg$': [_PYTHON_TEST_SUITE], + 'setup\.py$': [_PYTHON_TEST_SUITE], + 'grpc\.gemspec$': [_RUBY_TEST_SUITE], + 'Gemfile$': [_RUBY_TEST_SUITE], + # 'grpc.def$': [_WINDOWS_TEST_SUITE], + '^src/cpp/': [_CPP_TEST_SUITE], + '^src/csharp/': [_CSHARP_TEST_SUITE], + '^src/node/': [_NODE_TEST_SUITE], + '^src/objective\-c/': [_OBJC_TEST_SUITE], + '^src/php/': [_PHP_TEST_SUITE], + '^src/python/': [_PYTHON_TEST_SUITE], + '^src/ruby/': [_RUBY_TEST_SUITE], + '^test/core/': [_CORE_TEST_SUITE], + '^test/cpp/': [_CPP_TEST_SUITE], + '^test/distrib/cpp/': [_CPP_TEST_SUITE], + '^test/distrib/csharp/': [_CSHARP_TEST_SUITE], + '^test/distrib/node/': [_NODE_TEST_SUITE], + '^test/distrib/php/': [_PHP_TEST_SUITE], + '^test/distrib/python/': [_PYTHON_TEST_SUITE], + '^test/distrib/ruby/': [_RUBY_TEST_SUITE], + '^include/grpc\+\+/': [_CPP_TEST_SUITE] + #'^vsprojects/': [_WINDOWS_TEST_SUITE] + # todo(mattkwong): add windows test suite } # Add all triggers to their respective test suites for trigger, test_suites in _WHITELIST_DICT.iteritems(): @@ -108,7 +132,7 @@ def _get_changed_files(base_branch): """ # git fetch might need to be called on Jenkins slave # todo(mattkwong): remove or uncomment below after seeing if Jenkins needs this - # call(['git', 'fetch']) + call(['git', 'fetch']) # Get file changes between branch and merge-base of specified branch # Not combined to be Windows friendly @@ -137,19 +161,7 @@ def _remove_irrelevant_tests(tests, tag): :return: list of relevant tests """ # todo(mattkwong): find a more reliable way to filter tests - don't use shortname - return [test for test in tests if tag not in test.shortname or - any(san_tag in test.shortname for san_tag in ['_asan', '_tsan', '_msan'])] - - -def _remove_sanitizer_tests(tests): - """ - Filters out sanitizer tests - :param tests: list of all tests generated by run_tests_matrix.py - :return: list of relevant tests - """ - # todo(mattkwong): find a more reliable way to filter tests - don't use shortname - return [test for test in tests if - all(san_tag not in test.shortname for san_tag in ['_asan', '_tsan', '_msan'])] + return [test for test in tests if tag not in test.shortname] def filter_tests(tests, base_branch): @@ -171,14 +183,10 @@ def filter_tests(tests, base_branch): if not re.match(all_triggers, changed_file): return(tests) # Filter out tests by language - for test_suite in _all_test_suites: + for test_suite in _ALL_TEST_SUITES: if _can_skip_tests(changed_files, test_suite.triggers): for tag in test_suite.tags: print(" Filtering %s tests" % tag) tests = _remove_irrelevant_tests(tests, tag) - # Sanitizer tests skipped if core and c++ are skipped - if _can_skip_tests(changed_files, _cpp_test_suite.triggers + _core_test_suite.triggers): - print(" Filtering Sanitizer tests") - tests = _remove_sanitizer_tests(tests) return tests From 213793b36aacbb6dca1421c436d8ee14bf449735 Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Wed, 19 Oct 2016 16:35:50 -0700 Subject: [PATCH 6/7] added platform test suites and other fixes --- tools/run_tests/filter_pull_request_tests.py | 119 ++++++++++--------- 1 file changed, 61 insertions(+), 58 deletions(-) diff --git a/tools/run_tests/filter_pull_request_tests.py b/tools/run_tests/filter_pull_request_tests.py index 128370e1914..e2027a23402 100644 --- a/tools/run_tests/filter_pull_request_tests.py +++ b/tools/run_tests/filter_pull_request_tests.py @@ -36,18 +36,16 @@ from subprocess import call, check_output class TestSuite: """ - Contains tag to identify job as belonging to this test suite and + Contains label to identify job as belonging to this test suite and triggers to identify if changed files are relevant """ - def __init__(self, tags): + def __init__(self, labels): """ - Build TestSuite to group tests by their tags - :param tag: string used to identify if a job belongs to this TestSuite - todo(mattkwong): Change the use of tag because do not want to depend on - job.shortname to identify what suite a test belongs to + Build TestSuite to group tests based on labeling + :param label: strings that should match a jobs's platform, config, language, or test group """ self.triggers = [] - self.tags = tags + self.labels = labels def add_trigger(self, trigger): """ @@ -56,51 +54,34 @@ class TestSuite: """ self.triggers.append(trigger) + # Create test suites -_CORE_TEST_SUITE = TestSuite(['_c_']) -_CPP_TEST_SUITE = TestSuite(['_c++_']) -_CSHARP_TEST_SUITE = TestSuite(['_csharp_']) -_NODE_TEST_SUITE = TestSuite(['_node_']) -_OBJC_TEST_SUITE = TestSuite(['_objc_']) -_PHP_TEST_SUITE = TestSuite(['_php_', '_php7_']) -_PYTHON_TEST_SUITE = TestSuite(['_python_']) -_RUBY_TEST_SUITE = TestSuite(['_ruby']) -_ALL_TEST_SUITES = [_CORE_TEST_SUITE, _CPP_TEST_SUITE, _CSHARP_TEST_SUITE, - _NODE_TEST_SUITE, _OBJC_TEST_SUITE, _PHP_TEST_SUITE, - _PYTHON_TEST_SUITE, _RUBY_TEST_SUITE] +_SANITY_TEST_SUITE = TestSuite(['sanity']) +_CORE_TEST_SUITE = TestSuite(['c']) +_CPP_TEST_SUITE = TestSuite(['c++']) +_CSHARP_TEST_SUITE = TestSuite(['csharp']) +_NODE_TEST_SUITE = TestSuite(['node']) +_OBJC_TEST_SUITE = TestSuite(['objc']) +_PHP_TEST_SUITE = TestSuite(['php', 'php7']) +_PYTHON_TEST_SUITE = TestSuite(['python']) +_RUBY_TEST_SUITE = TestSuite(['ruby']) +_LINUX_TEST_SUITE = TestSuite(['linux']) +_WINDOWS_TEST_SUITE = TestSuite(['windows']) +_MACOS_TEST_SUITE = TestSuite(['macos']) +_ALL_TEST_SUITES = [_SANITY_TEST_SUITE, _CORE_TEST_SUITE, _CPP_TEST_SUITE, + _CSHARP_TEST_SUITE, _NODE_TEST_SUITE, _OBJC_TEST_SUITE, + _PHP_TEST_SUITE, _PYTHON_TEST_SUITE, _RUBY_TEST_SUITE, + _LINUX_TEST_SUITE, _WINDOWS_TEST_SUITE, _MACOS_TEST_SUITE] # Dictionary of whitelistable files where the key is a regex matching changed files # and the value is a list of tests that should be run. An empty list means that # the changed files should not trigger any tests. Any changed file that does not # match any of these regexes will trigger all tests _WHITELIST_DICT = { - #'^templates/.*': [_sanity_test_suite], - # todo(mattkwong): add sanity test suite '^doc/': [], '^examples/': [], + '^include/grpc\+\+/': [_CPP_TEST_SUITE], '^summerofcode/': [], - 'README\.md$': [], - 'CONTRIBUTING\.md$': [], - 'LICENSE$': [], - 'INSTALL\.md$': [], - 'MANIFEST\.md$': [], - 'PATENTS$': [], - 'binding\.grp$': [_NODE_TEST_SUITE], - 'gRPC\-Core\.podspec$': [_OBJC_TEST_SUITE], - 'gRPC\-ProtoRPC\.podspec$': [_OBJC_TEST_SUITE], - 'gRPC\-RxLibrary\.podspec$': [_OBJC_TEST_SUITE], - 'gRPC\.podspec$': [_OBJC_TEST_SUITE], - 'composer\.json$': [_PHP_TEST_SUITE], - 'config\.m4$': [_PHP_TEST_SUITE], - 'package\.json$': [_PHP_TEST_SUITE], - 'package\.xml$': [_PHP_TEST_SUITE], - 'PYTHON\-MANIFEST\.in$': [_PYTHON_TEST_SUITE], - 'requirements\.txt$': [_PYTHON_TEST_SUITE], - 'setup\.cfg$': [_PYTHON_TEST_SUITE], - 'setup\.py$': [_PYTHON_TEST_SUITE], - 'grpc\.gemspec$': [_RUBY_TEST_SUITE], - 'Gemfile$': [_RUBY_TEST_SUITE], - # 'grpc.def$': [_WINDOWS_TEST_SUITE], '^src/cpp/': [_CPP_TEST_SUITE], '^src/csharp/': [_CSHARP_TEST_SUITE], '^src/node/': [_NODE_TEST_SUITE], @@ -108,6 +89,7 @@ _WHITELIST_DICT = { '^src/php/': [_PHP_TEST_SUITE], '^src/python/': [_PYTHON_TEST_SUITE], '^src/ruby/': [_RUBY_TEST_SUITE], + '^templates/': [_SANITY_TEST_SUITE], '^test/core/': [_CORE_TEST_SUITE], '^test/cpp/': [_CPP_TEST_SUITE], '^test/distrib/cpp/': [_CPP_TEST_SUITE], @@ -116,10 +98,31 @@ _WHITELIST_DICT = { '^test/distrib/php/': [_PHP_TEST_SUITE], '^test/distrib/python/': [_PYTHON_TEST_SUITE], '^test/distrib/ruby/': [_RUBY_TEST_SUITE], - '^include/grpc\+\+/': [_CPP_TEST_SUITE] - #'^vsprojects/': [_WINDOWS_TEST_SUITE] - # todo(mattkwong): add windows test suite + '^vsprojects/': [_WINDOWS_TEST_SUITE], + 'binding\.gyp$': [_NODE_TEST_SUITE], + 'composer\.json$': [_PHP_TEST_SUITE], + 'config\.m4$': [_PHP_TEST_SUITE], + 'CONTRIBUTING\.md$': [], + 'Gemfile$': [_RUBY_TEST_SUITE], + 'grpc.def$': [_WINDOWS_TEST_SUITE], + 'grpc\.gemspec$': [_RUBY_TEST_SUITE], + 'gRPC\.podspec$': [_OBJC_TEST_SUITE], + 'gRPC\-Core\.podspec$': [_OBJC_TEST_SUITE], + 'gRPC\-ProtoRPC\.podspec$': [_OBJC_TEST_SUITE], + 'gRPC\-RxLibrary\.podspec$': [_OBJC_TEST_SUITE], + 'INSTALL\.md$': [], + 'LICENSE$': [], + 'MANIFEST\.md$': [], + 'package\.json$': [_PHP_TEST_SUITE], + 'package\.xml$': [_PHP_TEST_SUITE], + 'PATENTS$': [], + 'PYTHON\-MANIFEST\.in$': [_PYTHON_TEST_SUITE], + 'README\.md$': [], + 'requirements\.txt$': [_PYTHON_TEST_SUITE], + 'setup\.cfg$': [_PYTHON_TEST_SUITE], + 'setup\.py$': [_PYTHON_TEST_SUITE] } + # Add all triggers to their respective test suites for trigger, test_suites in _WHITELIST_DICT.iteritems(): for test_suite in test_suites: @@ -130,10 +133,6 @@ def _get_changed_files(base_branch): """ Get list of changed files between current branch and base of target merge branch """ - # git fetch might need to be called on Jenkins slave - # todo(mattkwong): remove or uncomment below after seeing if Jenkins needs this - call(['git', 'fetch']) - # Get file changes between branch and merge-base of specified branch # Not combined to be Windows friendly base_commit = check_output(["git", "merge-base", base_branch, "HEAD"]).rstrip() @@ -153,15 +152,17 @@ def _can_skip_tests(file_names, triggers): return True -def _remove_irrelevant_tests(tests, tag): +def _remove_irrelevant_tests(tests, skippable_labels): """ Filters out tests by config or language - will not remove sanitizer tests :param tests: list of all tests generated by run_tests_matrix.py - :param tag: string representing language or config to filter - "_(language)_" or "_(config)" + :param skippable_labels: list of languages and platforms with skippable tests :return: list of relevant tests """ - # todo(mattkwong): find a more reliable way to filter tests - don't use shortname - return [test for test in tests if tag not in test.shortname] + # test.labels[0] is platform and test.labels[2] is language + # We skip a test if both are considered safe to skip + return [test for test in tests if test.labels[0] not in skippable_labels or \ + test.labels[2] not in skippable_labels] def filter_tests(tests, base_branch): @@ -170,7 +171,7 @@ def filter_tests(tests, base_branch): :param tests: list of all tests generated by run_tests_matrix.py :return: list of relevant tests """ - print("Finding file differences between %s repo and current branch...\n" % base_branch) + print("Finding file differences between gRPC %s branch and pull request...\n" % base_branch) changed_files = _get_changed_files(base_branch) for changed_file in changed_files: print(changed_file) @@ -182,11 +183,13 @@ def filter_tests(tests, base_branch): for changed_file in changed_files: if not re.match(all_triggers, changed_file): return(tests) - # Filter out tests by language + # Figure out which language and platform tests to run + skippable_labels = [] for test_suite in _ALL_TEST_SUITES: if _can_skip_tests(changed_files, test_suite.triggers): - for tag in test_suite.tags: - print(" Filtering %s tests" % tag) - tests = _remove_irrelevant_tests(tests, tag) + for label in test_suite.labels: + print(" Filtering %s tests" % label) + skippable_labels.append(label) + tests = _remove_irrelevant_tests(tests, skippable_labels) return tests From e9255d04e572a058189a63cf23c8475f1b3fb2dd Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Thu, 20 Oct 2016 19:08:57 -0700 Subject: [PATCH 7/7] fix sanity --- gRPC-Core.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index e59404932cd..1ca8119a109 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -191,7 +191,7 @@ Pod::Spec.new do |s| ss.header_mappings_dir = '.' ss.libraries = 'z' ss.dependency "#{s.name}/Interface", version - ss.dependency 'BoringSSL', '~> 7.0' + ss.dependency 'BoringSSL', '~> 6.0' # To save you from scrolling, this is the last part of the podspec. ss.source_files = 'src/core/lib/profiling/timers.h',