-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Record failed tests with --record, and rerun them with --rerun
#154586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| use std::collections::BTreeSet; | ||
| use std::fs::{self, File}; | ||
| use std::io::{BufRead, BufReader, ErrorKind}; | ||
| use std::path::{Path, PathBuf}; | ||
|
|
||
| use crate::core::builder::{Builder, ShouldRun, Step}; | ||
| use crate::t; | ||
|
|
||
| #[derive(Clone)] | ||
| pub struct RecordFailedTests { | ||
| failed_tests_path: Option<PathBuf>, | ||
| } | ||
|
|
||
| impl RecordFailedTests { | ||
| pub fn path(&self) -> Option<&Path> { | ||
| self.failed_tests_path.as_deref() | ||
| } | ||
| } | ||
|
|
||
| /// This step is run as a dependency of most testing steps. | ||
| /// Upon running, a file is created for failed tests to be recorded in if `--record` is passed on | ||
| /// the command line. | ||
| /// | ||
| /// This step is the only way to get access to a token type called [`RecordFailedTests`]. | ||
| /// Having this token type signifies the fact that a file was created to store failed tests in, | ||
| /// and is required to create a `Renderer`, the type that renders the outputs of tests. | ||
| /// | ||
| /// If `--rerun` isn't passed, or we're in dry-run mode, running this step is a no-op, | ||
| /// and the `RecordFailedTest` type doesn't (need to) signify anything. | ||
| #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] | ||
| pub struct SetupFailedTestsFile; | ||
|
jdonszelmann marked this conversation as resolved.
|
||
| impl Step for SetupFailedTestsFile { | ||
| type Output = RecordFailedTests; | ||
|
|
||
| fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | ||
| run.never() | ||
| } | ||
|
|
||
| fn run(self, builder: &Builder<'_>) -> Self::Output { | ||
| if !builder.config.cmd.record() || builder.config.dry_run() { | ||
| return RecordFailedTests { failed_tests_path: None }; | ||
| } | ||
|
|
||
| let failed_tests_path = builder.config.record_failed_tests_path.clone(); | ||
| println!( | ||
| "setting up tracking of failed tests in {} (`--record` was passed)", | ||
| failed_tests_path.display() | ||
| ); | ||
| if failed_tests_path.exists() { | ||
| println!("deleting previously recorded failed tests"); | ||
| t!(fs::remove_file(&failed_tests_path)); | ||
| } | ||
| RecordFailedTests { failed_tests_path: Some(failed_tests_path) } | ||
| } | ||
| } | ||
|
|
||
| pub fn collect_previously_failed_tests(failed_tests_file_path: &PathBuf) -> Vec<PathBuf> { | ||
| let mut paths = BTreeSet::new(); | ||
|
|
||
| println!( | ||
| "`--rerun` passed so looking for failed tests in {}", | ||
| failed_tests_file_path.display() | ||
| ); | ||
|
|
||
| let lines: Vec<String> = match File::open(failed_tests_file_path) { | ||
| Ok(f) => t!(BufReader::new(f).lines().collect()), | ||
| Err(e) if e.kind() == ErrorKind::NotFound => { | ||
| println!( | ||
| "WARNING: failed tests file doesn't exist: `--rerun` only makes sense after a previous test run with `--record`" | ||
| ); | ||
| return Vec::new(); | ||
| } | ||
| Err(e) => t!(Err(e)), | ||
| }; | ||
|
|
||
| const MAX_RERUN_PRINTS: usize = 10; | ||
|
|
||
| for line in lines { | ||
| let trimmed = line.as_str().trim(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion [TEST-HARNESS-JSON 2/2]: I don't feel like hard-blocking this fuctionality on [TEST-HARNESS-JSON 1/2] considerations, but can you please leave a FIXME to consider changing the compiletest-emitted JSON message formats, and maybe change the failed-tests file to have like JSON lines that looks like { "suite": "ui", "path": "tests/ui/foo.rs" }
{ "suite": "run-make", "path": "tests/run-make/hello-world/rmake.rs" } |
||
| let without_revision = | ||
| trimmed.rsplit_once("#").map(|(before, _)| before).unwrap_or(trimmed); | ||
| let without_suite_prefix = without_revision | ||
| .strip_prefix("[") | ||
| .and_then(|rest| rest.split_once("]")) | ||
| .map(|(_, after)| after.trim()) | ||
| .unwrap_or(without_revision); | ||
|
Comment on lines
+79
to
+86
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussion [TEST-HARNESS-JSON 1/2]: hm I thought about this. This is kinda doing a weird thing of post-processing compiletest-emitted test names, so we introduce an implicit dependency on compiletest test name formatting, which I can't say I'm a huge fan of. I guess this is not the end of the world... The caveat is that bootstrap captures test harness JSON output to then post-render the outcome messages. This can be from:
If we want to avoid taking on this implicit dependency, we probably will have to introduce separate variants for compiletest-emitted test outcome JSON versus that of libtest, which doesn't really feel that great IMO. That, or maybe we can introduce optional revision / test suite fields for the message variants (which will not be present from other libtest-emitted messages but will be for compiletest-emitted messages). NB. this was not possible previously, because previously compiletest also shelled out to libtest test executor so compiletest don't have control over the libtest executor emitted libtest JSON message format. But now compiletest uses its own executor and emits emulated libtest JSON messages. So technically I think it might be possible to change the emitted JSON format. cc @Zalathar (this may be of interest to you) |
||
|
|
||
| let failed_test_path = PathBuf::from(without_suite_prefix.to_string()); | ||
| if paths.insert(failed_test_path.clone()) { | ||
| if paths.len() == 1 { | ||
| println!("rerunning previously failed tests:"); | ||
| } | ||
| if paths.len() <= MAX_RERUN_PRINTS { | ||
| println!(" {}", failed_test_path.display()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if paths.len() > MAX_RERUN_PRINTS { | ||
| println!(" and {} more...", paths.len() - MAX_RERUN_PRINTS) | ||
| } | ||
|
|
||
| if paths.is_empty() { | ||
| println!( | ||
| "WARNING: failed tests file doesn't contain any failed tests: `--rerun` only makes sense after a previous test run with `--record`" | ||
| ); | ||
| } | ||
|
|
||
| paths.into_iter().collect() | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.