Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2025,8 +2025,6 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?}
cmd.arg("--verbose");
}

cmd.arg("--json");

if builder.config.rustc_debug_assertions {
cmd.arg("--with-rustc-debug-assertions");
}
Expand Down
10 changes: 1 addition & 9 deletions src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use camino::{Utf8Path, Utf8PathBuf};
use semver::Version;
use serde::de::{Deserialize, Deserializer, Error as _};

use crate::executor::{ColorConfig, OutputFormat};
use crate::executor::ColorConfig;
use crate::fatal;
use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum};

Expand Down Expand Up @@ -565,13 +565,6 @@ pub struct Config {
/// FIXME: this is *way* too coarse; the user can't select *which* info to verbosely dump.
pub verbose: bool,

/// (Useless) Adjust libtest output format.
///
/// FIXME: the hand-rolled executor does not support non-JSON output, because `compiletest` need
/// to package test outcome as `libtest`-esque JSON that `bootstrap` can intercept *anyway*.
/// However, now that we don't use the `libtest` executor, this is useless.
pub format: OutputFormat,

/// Whether to use colors in test output.
///
/// Note: the exact control mechanism is delegated to [`colored`].
Expand Down Expand Up @@ -768,7 +761,6 @@ impl Config {
adb_device_status: Default::default(),
lldb_python_dir: Default::default(),
verbose: Default::default(),
format: Default::default(),
color: Default::default(),
remote_test_client: Default::default(),
compare_mode: Default::default(),
Expand Down
22 changes: 7 additions & 15 deletions src/tools/compiletest/src/executor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
//! This module contains a reimplementation of the subset of libtest
//! functionality needed by compiletest.
//!
//! FIXME(Zalathar): Much of this code was originally designed to mimic libtest
//! as closely as possible, for ease of migration. Now that libtest is no longer
//! used, we can potentially redesign things to be a better fit for compiletest.
use std::borrow::Cow;
use std::collections::HashMap;
Expand Down Expand Up @@ -207,7 +211,7 @@ impl TestOutcome {
///
/// Adapted from `filter_tests` in libtest.
///
/// FIXME(#139660): After the libtest dependency is removed, redesign the whole filtering system to
/// FIXME(#139660): Now that libtest has been removed, redesign the whole filtering system to
/// do a better job of understanding and filtering _paths_, instead of being tied to libtest's
/// substring/exact matching behaviour.
fn filter_tests(opts: &Config, tests: Vec<CollectedTest>) -> Vec<CollectedTest> {
Expand Down Expand Up @@ -249,15 +253,15 @@ fn get_concurrency() -> usize {
}
}

/// Information needed to create a `test::TestDescAndFn`.
/// Information that was historically needed to create a libtest `TestDescAndFn`.
pub(crate) struct CollectedTest {
pub(crate) desc: CollectedTestDesc,
pub(crate) config: Arc<Config>,
pub(crate) testpaths: TestPaths,
pub(crate) revision: Option<String>,
}

/// Information needed to create a `test::TestDesc`.
/// Information that was historically needed to create a libtest `TestDesc`.
pub(crate) struct CollectedTestDesc {
pub(crate) name: String,
pub(crate) ignore: bool,
Expand All @@ -274,18 +278,6 @@ pub enum ColorConfig {
NeverColor,
}

/// Format of the test results output.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum OutputFormat {
/// Verbose output
Pretty,
/// Quiet output
#[default]
Terse,
/// JSON output
Json,
}

/// Whether test is expected to panic or not.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) enum ShouldPanic {
Expand Down
105 changes: 43 additions & 62 deletions src/tools/compiletest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use crate::common::{
expected_output_path, output_base_dir, output_relative_path,
};
use crate::directives::DirectivesCache;
use crate::executor::{CollectedTest, ColorConfig, OutputFormat};
use crate::executor::{CollectedTest, ColorConfig};
use crate::util::logv;

/// Creates the `Config` instance for this invocation of compiletest.
Expand Down Expand Up @@ -137,9 +137,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
"overwrite stderr/stdout files instead of complaining about a mismatch",
)
.optflag("", "fail-fast", "stop as soon as possible after any test fails")
.optflag("", "quiet", "print one character per test instead of one line")
.optopt("", "color", "coloring: auto, always, never", "WHEN")
.optflag("", "json", "emit json output instead of plaintext output")
.optopt("", "target", "the target to build for", "TARGET")
.optopt("", "host", "the host to build for", "HOST")
.optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH")
Expand Down Expand Up @@ -203,7 +201,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
"COMMAND",
)
.reqopt("", "minicore-path", "path to minicore aux library", "PATH")
.optflag("N", "no-new-executor", "disables the new test executor, and uses libtest instead")
.optopt(
"",
"debugger",
Expand Down Expand Up @@ -436,12 +433,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
&& !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
lldb_python_dir: matches.opt_str("lldb-python-dir"),
verbose: matches.opt_present("verbose"),
format: match (matches.opt_present("quiet"), matches.opt_present("json")) {
(true, true) => panic!("--quiet and --json are incompatible"),
(true, false) => OutputFormat::Terse,
(false, true) => OutputFormat::Json,
(false, false) => OutputFormat::Pretty,
},
only_modified: matches.opt_present("only-modified"),
color,
remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from),
Expand Down Expand Up @@ -527,7 +518,6 @@ pub fn log_config(config: &Config) {
logv(c, format!("target-linker: {:?}", config.target_linker));
logv(c, format!("host-linker: {:?}", config.host_linker));
logv(c, format!("verbose: {}", config.verbose));
logv(c, format!("format: {:?}", config.format));
logv(c, format!("minicore_path: {}", config.minicore_path));
logv(c, "\n".to_string());
}
Expand Down Expand Up @@ -601,7 +591,7 @@ pub fn run_tests(config: Arc<Config>) {
configs.push(config.clone());
};

// Discover all of the tests in the test suite directory, and build a libtest
// Discover all of the tests in the test suite directory, and build a `CollectedTest`
// structure for each test (or each revision of a multi-revision test).
let mut tests = Vec::new();
for c in configs {
Expand All @@ -613,50 +603,35 @@ pub fn run_tests(config: Arc<Config>) {
// Delegate to the executor to filter and run the big list of test structures
// created during test discovery. When the executor decides to run a test,
// it will return control to the rest of compiletest by calling `runtest::run`.
// FIXME(Zalathar): Once we're confident that we won't need to revert the
// removal of the libtest-based executor, remove this Result and other
// remnants of the old executor.
let res: io::Result<bool> = Ok(executor::run_tests(&config, tests));

// Check the outcome reported by libtest.
match res {
Ok(true) => {}
Ok(false) => {
// We want to report that the tests failed, but we also want to give
// some indication of just what tests we were running. Especially on
// CI, where there can be cross-compiled tests for a lot of
// architectures, without this critical information it can be quite
// easy to miss which tests failed, and as such fail to reproduce
// the failure locally.

let mut msg = String::from("Some tests failed in compiletest");
write!(msg, " suite={}", config.suite).unwrap();

if let Some(compare_mode) = config.compare_mode.as_ref() {
write!(msg, " compare_mode={}", compare_mode).unwrap();
}
let ok = executor::run_tests(&config, tests);

// Check the outcome reported by the executor.
if !ok {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe if ok { return; }?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, after seeing this comment I tried out the early return, but the end result didn't seem obviously better compared to the downside of having an early return that's relatively far from the top and bottom of the function.

So I think my preference here is to stick with if !ok for this PR to avoid scope-creep, and leave the question of further simplification for later.

// We want to report that the tests failed, but we also want to give
// some indication of just what tests we were running. Especially on
// CI, where there can be cross-compiled tests for a lot of
// architectures, without this critical information it can be quite
// easy to miss which tests failed, and as such fail to reproduce
// the failure locally.

let mut msg = String::from("Some tests failed in compiletest");
write!(msg, " suite={}", config.suite).unwrap();

if let Some(compare_mode) = config.compare_mode.as_ref() {
write!(msg, " compare_mode={}", compare_mode).unwrap();
}

if let Some(pass_mode) = config.force_pass_mode.as_ref() {
write!(msg, " pass_mode={}", pass_mode).unwrap();
}
if let Some(pass_mode) = config.force_pass_mode.as_ref() {
write!(msg, " pass_mode={}", pass_mode).unwrap();
}

write!(msg, " mode={}", config.mode).unwrap();
write!(msg, " host={}", config.host).unwrap();
write!(msg, " target={}", config.target).unwrap();
write!(msg, " mode={}", config.mode).unwrap();
write!(msg, " host={}", config.host).unwrap();
write!(msg, " target={}", config.target).unwrap();

println!("{msg}");
println!("{msg}");

std::process::exit(1);
}
Err(e) => {
// We don't know if tests passed or not, but if there was an error
// during testing we don't want to just succeed (we may not have
// tested something), so fail.
//
// This should realistically "never" happen, so don't try to make
// this a pretty error message.
panic!("I/O failure during tests: {:?}", e);
}
std::process::exit(1);
}
}

Expand Down Expand Up @@ -691,7 +666,11 @@ impl TestCollector {
///
/// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests),
/// regardless of whether any filters/tests were specified on the command-line,
/// because filtering is handled later by libtest.
/// because filtering is handled later by code that was copied from libtest.
///
/// FIXME(Zalathar): Now that we no longer rely on libtest, try to overhaul
/// test discovery to take into account the filters/tests specified on the
/// command-line, instead of having to enumerate everything.
pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest> {
debug!("making tests from {}", config.src_test_suite_root);
let common_inputs_stamp = common_inputs_stamp(&config);
Expand Down Expand Up @@ -805,7 +784,7 @@ fn modified_tests(config: &Config, dir: &Utf8Path) -> Result<Vec<Utf8PathBuf>, S
}

/// Recursively scans a directory to find test files and create test structures
/// that will be handed over to libtest.
/// that will be handed over to the executor.
fn collect_tests_from_dir(
cx: &TestCollectorCx,
dir: &Utf8Path,
Expand Down Expand Up @@ -871,7 +850,7 @@ fn collect_tests_from_dir(
if is_test(file_name)
&& (!cx.config.only_modified || cx.modified_tests.contains(&file_path))
{
// We found a test file, so create the corresponding libtest structures.
// We found a test file, so create the corresponding test structures.
debug!(%file_path, "found test file");

// Record the stem of the test file, to check for overlaps later.
Expand Down Expand Up @@ -915,7 +894,7 @@ pub fn is_test(file_name: &str) -> bool {
}

/// For a single test file, creates one or more test structures (one per revision) that can be
/// handed over to libtest to run, possibly in parallel.
/// handed over to the executor to run, possibly in parallel.
fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &TestPaths) {
// For run-make tests, each "test file" is actually a _directory_ containing an `rmake.rs`. But
// for the purposes of directive parsing, we want to look at that recipe file, not the directory
Expand All @@ -929,7 +908,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
// Scan the test file to discover its revisions, if any.
let early_props = EarlyProps::from_file(&cx.config, &test_path);

// Normally we create one libtest structure per revision, with two exceptions:
// Normally we create one structure per revision, with two exceptions:
// - If a test doesn't use revisions, create a dummy revision (None) so that
// the test can still run.
// - Incremental tests inherently can't run their revisions in parallel, so
Expand All @@ -944,12 +923,12 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
// For each revision (or the sole dummy revision), create and append a
// `CollectedTest` that can be handed over to the test executor.
collector.tests.extend(revisions.into_iter().map(|revision| {
// Create a test name and description to hand over to libtest.
// Create a test name and description to hand over to the executor.
let src_file = fs::File::open(&test_path).expect("open test file to parse ignores");
let test_name = make_test_name(&cx.config, testpaths, revision);
// Create a libtest description for the test/revision.
// Create a description struct for the test/revision.
// This is where `ignore-*`/`only-*`/`needs-*` directives are handled,
// because they need to set the libtest ignored flag.
// because they historically needed to set the libtest ignored flag.
let mut desc = make_test_description(
&cx.config,
&cx.cache,
Expand All @@ -961,10 +940,12 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
);

// If a test's inputs haven't changed since the last time it ran,
// mark it as ignored so that libtest will skip it.
// mark it as ignored so that the executor will skip it.
if !cx.config.force_rerun && is_up_to_date(cx, testpaths, &early_props, revision) {
desc.ignore = true;
// Keep this in sync with the "up-to-date" message detected by bootstrap.
// FIXME(Zalathar): Now that we are no longer tied to libtest, we could
// find a less fragile way to communicate this status to bootstrap.
desc.ignore_message = Some("up-to-date".into());
}

Expand Down Expand Up @@ -1104,7 +1085,7 @@ impl Stamp {
}
}

/// Creates a name for this test/revision that can be handed over to libtest.
/// Creates a name for this test/revision that can be handed over to the executor.
fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> String {
// Print the name of the file, relative to the sources root.
let path = testpaths.file.strip_prefix(&config.src_root).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2222,7 +2222,7 @@ impl<'test> TestCx<'test> {
.env("PAGER", "")
.stdin(File::open(&diff_filename).unwrap())
// Capture output and print it explicitly so it will in turn be
// captured by libtest.
// captured by output-capture.
.output()
.unwrap();
assert!(output.status.success());
Expand Down
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/runtest/run_make.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ impl TestCx<'_> {
let stdout = String::from_utf8_lossy(&stdout).into_owned();
let stderr = String::from_utf8_lossy(&stderr).into_owned();
// This conditions on `status.success()` so we don't print output twice on error.
// NOTE: this code is called from a libtest thread, so it's hidden by default unless --nocapture is passed.
// NOTE: this code is called from an executor thread, so it's hidden by default unless --no-capture is passed.
self.dump_output(status.success(), &cmd.get_program().to_string_lossy(), &stdout, &stderr);
if !status.success() {
let res = ProcRes { status, stdout, stderr, truncated, cmdline: format!("{:?}", cmd) };
Expand Down
Loading