0

Proof of concept for test selection via GN

This CL implements gn based unittest filtering. The files in the rts_exclude_file are manually selected for this example, but will later be populated using the smart logic in rts-chromium.
These two cases (source_set and test template) cover most of the test files. I haven't seen any other templates with unittests, but even if there are some this would be a great start. This also doesn't cover webtests, but I think there's enough exclusion power here to save a lot of compute.
This also adds a linux-rts builder to the mb config to prepare the experimental builder.

Bug: 1145216
Change-Id: I7343249f3df0739e39cfe351e5714d7978059d86
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2551276
Commit-Queue: Gregory Guterman <guterman@google.com>
Reviewed-by: Dirk Pranke <dpranke@google.com>
Reviewed-by: Nodir Turakulov <nodir@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841248}
This commit is contained in:
Greg Guterman
2021-01-07 23:41:09 +00:00
committed by Chromium LUCI CQ
parent 927b1789db
commit 8da79b7118
5 changed files with 109 additions and 0 deletions

@ -162,6 +162,17 @@ declare_args() {
is_component_build = is_debug && current_os != "ios"
}
declare_args() {
# Regression Test Selection (RTS).
# https://chromium.googlesource.com/chromium/src/+/master/docs/testing/regression-test-selection.md
#
# Exclude unittest/browsertest files listed in this file.
#
# Entries should be newline separated.
# Each entry much be an source-absolute path starting with //.
rts_exclude_file = ""
}
assert(!(is_debug && is_official_build), "Can't do official debug builds")
# ==============================================================================
@ -575,3 +586,32 @@ set_defaults("component") {
configs = default_compiler_configs
}
}
# ==============================================================================
# Regression Test Selection (RTS)
# https://chromium.googlesource.com/chromium/src/+/master/docs/testing/regression-test-selection.md
# ==============================================================================
if (rts_exclude_file != "") {
rts_exclusions = read_file(rts_exclude_file, "list lines")
# Many tests are included in source_sets
template("source_set") {
_target_name = target_name
target("source_set", _target_name) {
forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
if (defined(sources) && sources != []) {
# Normalize paths
abs_paths = get_path_info(sources, "abspath")
# Filter
filtered_sources = filter_exclude(abs_paths, rts_exclusions)
# Do the replacement
sources = []
sources = filtered_sources
}
}
}
}

@ -0,0 +1,38 @@
# Regression test selection (RTS)
Regression Test Selection (RTS) is a technique to intellegently select tests to
run, without spending too many resources on testing, but still detecting bad
code changes.
[TOC]
## Current strategy
The current strategy is to skip files which we deem unaffected by the CL's
changelist. Affectedness is estimated using the heuristic that dependent files
are committed together. We look at git history and measure how often each file
A appears together each file B in the same commit. If A affects B,
and B affects C, we assume A also affects C. We represent these transitive
relationships in a graph where files are the nodes and the probability that the
two files affect each other are the weighted edges. The distance between two
nodes represents the (inverse) probability that these two files affect
each other. Finally, we skip tests in files that are farther than a
certain distance from the files in the CL.
## Skipping mechanism
Test skipping happens at the GN level in
[source_set](/build/config/BUILDCONFIG.gn) and [test](/testing/test.gni)
GN targets.
## Known failure mode
Consider a test file A that contains unit tests, as well as some variables
used in another file B. When our RTS strategy excludes A, but not B, a
compilation error will occur.
## Design Docs
- [File-level RTS](http://doc/1KWG82gNpkaRAchlp3jtENFdlefGvJxMHkAszlu9fo1c)
- [Chrome RTS](http://doc/10RP1XRw8ZSrvgVky1flH7ykAaIaG15RymM4gW7bFURQ)

@ -41,6 +41,20 @@ if (is_android) {
# Similar to the GN arg 'enable_run_ios_unittests_with_xctest' but
# for build targets.
template("test") {
# RTS
if (rts_exclude_file != "" && defined(invoker.sources) &&
invoker.sources != []) {
# Normalize paths
abs_paths = get_path_info(invoker.sources, "abspath")
# Filter
filtered_sources = filter_exclude(abs_paths, rts_exclusions)
# Do the replacement
invoker.sources = []
invoker.sources = filtered_sources
}
testonly = true
if (!is_ios) {
assert(!defined(invoker.is_xctest) || !invoker.is_xctest,

@ -994,6 +994,7 @@
'linux-perfetto-rel': 'perfetto_release_trybot',
'linux-rel': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_code_coverage',
'linux-rel-builderful': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_code_coverage',
'linux-rts': 'release_trybot_rts',
'linux-trusty-rel': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange',
'linux-viz-rel': 'release_trybot',
'linux-warmed': 'release_trybot_no_symbols_use_dummy_lastchange_code_coverage',
@ -2592,6 +2593,10 @@
'no_goma',
],
'release_trybot_rts': [
'release_bot', 'rts_bot',
],
'tsan_disable_nacl_debug_bot': [
'tsan', 'disable_nacl', 'debug_bot',
],
@ -3238,6 +3243,10 @@
'gn_args': 'enable_resource_allowlist_generation=true',
},
'rts_bot': {
'gn_args': 'rts_exclude_file="//testing/rts_exclude_file.txt"',
},
'shared': {
'gn_args': 'is_component_build=true',
},

@ -554,6 +554,14 @@
"use_goma": true
}
},
"linux-rts": {
"gn_args": {
"is_component_build": false,
"is_debug": false,
"rts_exclude_file": "//testing/rts_exclude_file.txt",
"use_goma": true
}
},
"linux-trusty-rel": {
"gn_args": {
"dcheck_always_on": true,