[RTS] Add back in RTS support to GNI
- Add use_rts bool flag to ensure that a .filter file exists or creates a dummy file while waiting for the file to be written. RTS = Regression Test Selection Re-land of https://crrev.com/c/4859614 Bug: 375000947 Change-Id: I425e0891ac895ae043855e0372be8a0e43a96f0f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5954865 Reviewed-by: Dirk Pranke <dpranke@google.com> Reviewed-by: Struan Shrimpton <sshrimp@google.com> Commit-Queue: Tony Seaward <seawardt@google.com> Cr-Commit-Position: refs/heads/main@{#1374746}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
1f8199ca92
commit
37c51bc8d9
53
build/add_rts_filters.py
Executable file
53
build/add_rts_filters.py
Executable file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2024 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
"""Creates a dummy RTS filter file if a real ones do not exist yet.
|
||||
Real filter files are generated for suites with skippable tests.
|
||||
Not every test suite will have filter data to use and therefore
|
||||
no filter file will be created. This ensures that a file exists
|
||||
to avoid file not found errors. The files will contain no skippable
|
||||
tests, so there is no effect.
|
||||
|
||||
Implementation uses try / except because the filter files are written
|
||||
relatively close to when this code creates the dummy files.
|
||||
|
||||
The following type of implementation would have a race condition:
|
||||
if not os.path.isfile(filter_file):
|
||||
open(filter_file, 'w') as fp:
|
||||
fp.write('*')
|
||||
"""
|
||||
import errno
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
filter_file = sys.argv[1]
|
||||
# '*' is a dummy that means run everything
|
||||
write_filter_file(filter_file, '*')
|
||||
|
||||
|
||||
def write_filter_file(filter_file, filter_string):
|
||||
directory = os.path.dirname(filter_file)
|
||||
try:
|
||||
os.makedirs(directory)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EEXIST:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
try:
|
||||
fp = os.open(filter_file, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EEXIST:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
with os.fdopen(fp, 'w') as file_obj:
|
||||
file_obj.write(filter_string)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -6,6 +6,7 @@ import("//build/config/android/abi.gni")
|
||||
import("//build/config/android/copy_ex.gni")
|
||||
import("//build/config/chrome_build.gni")
|
||||
import("//build/config/clang/clang.gni")
|
||||
import("//build/config/rts.gni")
|
||||
import("//build/config/sanitizers/sanitizers.gni")
|
||||
import("//build_overrides/build.gni")
|
||||
|
||||
@ -3629,6 +3630,14 @@ if (!is_robolectric && enable_java_templates) {
|
||||
# apk_under_test: ":bar"
|
||||
# }
|
||||
template("instrumentation_test_runner") {
|
||||
if (use_rts) {
|
||||
action("${invoker.target_name}__rts_filters") {
|
||||
script = "//build/add_rts_filters.py"
|
||||
rts_file = "${root_build_dir}/gen/rts/${invoker.target_name}.filter"
|
||||
args = [ rebase_path(rts_file, root_build_dir) ]
|
||||
outputs = [ rts_file ]
|
||||
}
|
||||
}
|
||||
_incremental_apk = !(defined(invoker.never_incremental) &&
|
||||
invoker.never_incremental) && incremental_install
|
||||
_apk_operations_target_name = "${target_name}__apk_operations"
|
||||
@ -3742,6 +3751,12 @@ if (!is_robolectric && enable_java_templates) {
|
||||
if (defined(invoker.additional_apks)) {
|
||||
public_deps += invoker.additional_apks
|
||||
}
|
||||
if (use_rts) {
|
||||
if (!defined(data_deps)) {
|
||||
data_deps = []
|
||||
}
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
7
build/config/rts.gni
Normal file
7
build/config/rts.gni
Normal file
@ -0,0 +1,7 @@
|
||||
declare_args() {
|
||||
# Regression Test Selection (RTS) will use a ML model
|
||||
# to predict what test cases can be excluded from a
|
||||
# given test suite based on historical data when using
|
||||
# a .filter file.
|
||||
use_rts = false
|
||||
}
|
@ -10,6 +10,7 @@ import("//build/config/chromeos/args.gni")
|
||||
import("//build/config/chromeos/ui_mode.gni")
|
||||
import("//build/config/devtools.gni")
|
||||
import("//build/config/gclient_args.gni")
|
||||
import("//build/config/rts.gni")
|
||||
import("//build/rust/rust_static_library.gni")
|
||||
import("//build_overrides/build.gni")
|
||||
|
||||
@ -362,6 +363,17 @@ template("mixed_test") {
|
||||
# This should be a list of the test names, for example
|
||||
# fuzztests = [ "MyTestClass.MyTestName" ]
|
||||
template("test") {
|
||||
# Ensures a test filter file exists and if not, creates a dummy file.
|
||||
# The Regression Test Selection (rts) flag is passed in mb.py and used
|
||||
# to filter out test cases. Flag ensures that a file exists.
|
||||
if (use_rts) {
|
||||
action("${target_name}__rts_filters") {
|
||||
script = "//build/add_rts_filters.py"
|
||||
rts_file = "${root_build_dir}/gen/rts/${invoker.target_name}.filter"
|
||||
args = [ rebase_path(rts_file, root_build_dir) ]
|
||||
outputs = [ rts_file ]
|
||||
}
|
||||
}
|
||||
testonly = true
|
||||
if (!is_ios) {
|
||||
assert(!defined(invoker.is_xctest) || !invoker.is_xctest,
|
||||
@ -460,6 +472,10 @@ template("test") {
|
||||
|
||||
# Don't output to the root or else conflict with the group() below.
|
||||
output_name = rebase_path(_exec_output, root_out_dir)
|
||||
|
||||
if (use_rts) {
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
|
||||
create_native_executable_dist(_dist_target) {
|
||||
@ -469,6 +485,12 @@ template("test") {
|
||||
if (defined(invoker.extra_dist_files)) {
|
||||
extra_files = invoker.extra_dist_files
|
||||
}
|
||||
if (use_rts) {
|
||||
if (!defined(data_deps)) {
|
||||
data_deps = []
|
||||
}
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_library_target_name = "${target_name}__library"
|
||||
@ -598,6 +620,10 @@ template("test") {
|
||||
if (defined(_unwind_table_asset_name)) {
|
||||
deps += [ ":${_unwind_table_asset_name}" ]
|
||||
}
|
||||
|
||||
if (use_rts) {
|
||||
data_deps = [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,6 +644,9 @@ template("test") {
|
||||
test_name = _output_name
|
||||
test_suite = _output_name
|
||||
test_type = "gtest"
|
||||
if (use_rts) {
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
|
||||
# Create a wrapper script rather than using a group() in order to ensure
|
||||
@ -652,6 +681,9 @@ template("test") {
|
||||
if (tests_have_location_tags) {
|
||||
data = [ "//testing/location_tags.json" ]
|
||||
}
|
||||
if (use_rts) {
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
} else if (is_fuchsia) {
|
||||
assert(!defined(invoker.use_xvfb) || !invoker.use_xvfb)
|
||||
@ -928,6 +960,9 @@ template("test") {
|
||||
# Include the generate_wrapper as part of data_deps
|
||||
data_deps += [ ":${_wrapper_output_name}" ]
|
||||
write_runtime_deps = _runtime_deps_file
|
||||
if (use_rts) {
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
if (!defined(deps)) {
|
||||
deps = []
|
||||
}
|
||||
@ -955,6 +990,9 @@ template("test") {
|
||||
if (tests_have_location_tags) {
|
||||
data = [ "//testing/location_tags.json" ]
|
||||
}
|
||||
if (use_rts) {
|
||||
data_deps = [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -981,6 +1019,9 @@ template("test") {
|
||||
}
|
||||
|
||||
data_deps += [ "//testing:test_scripts_shared" ]
|
||||
if (use_rts) {
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
} else if (!is_nacl) {
|
||||
if (is_mac || is_win) {
|
||||
@ -1031,6 +1072,9 @@ template("test") {
|
||||
if (fail_on_san_warnings) {
|
||||
executable_args += [ "--fail-san=1" ]
|
||||
}
|
||||
if (use_rts) {
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
|
||||
mixed_test(target_name) {
|
||||
@ -1056,6 +1100,9 @@ template("test") {
|
||||
}
|
||||
|
||||
data_deps += [ "//testing:test_scripts_shared" ]
|
||||
if (use_rts) {
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# This is a catch-all clause for NaCl toolchains and other random
|
||||
@ -1076,6 +1123,9 @@ template("test") {
|
||||
}
|
||||
|
||||
data_deps += [ "//testing:test_scripts_shared" ]
|
||||
if (use_rts) {
|
||||
data_deps += [ ":${invoker.target_name}__rts_filters" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1110,6 +1160,15 @@ template("script_test") {
|
||||
assert(!(_enable_logdog_wrapper && _enable_cros_wrapper),
|
||||
"The logdog and cros_test wrappers are mutually exclusive")
|
||||
|
||||
if (use_rts) {
|
||||
action("${target_name}__rts_filters") {
|
||||
script = "//build/add_rts_filters.py"
|
||||
rts_file = "${root_build_dir}/gen/rts/${invoker.target_name}.filter"
|
||||
args = [ rebase_path(rts_file, root_build_dir) ]
|
||||
outputs = [ rts_file ]
|
||||
}
|
||||
}
|
||||
|
||||
_shared_data = [ invoker.script ]
|
||||
if (defined(invoker.data)) {
|
||||
_shared_data += invoker.data
|
||||
|
Reference in New Issue
Block a user