Skip to content
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

[WIP] [nextest-runner] initial support for recording runs #1265

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
49 changes: 47 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 43 additions & 18 deletions cargo-nextest/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ use nextest_runner::{
platform::BuildPlatforms,
reporter::{structured, FinalStatusLevel, StatusLevel, TestOutputDisplay, TestReporterBuilder},
reuse_build::{archive_to_file, ArchiveReporter, MetadataOrPath, PathMapper, ReuseBuildInfo},
run_store::RunStore,
runner::{configure_handle_inheritance, RunStatsFailureKind, TestRunnerBuilder},
show_config::{ShowNextestVersion, ShowTestGroupSettings, ShowTestGroups, ShowTestGroupsMode},
signal::SignalHandlerKind,
target_runner::{PlatformRunner, TargetRunner},
test_filter::{RunIgnored, TestFilterBuilder},
test_output::CaptureStrategy,
};
use once_cell::sync::OnceCell;
use owo_colors::{OwoColorize, Stream, Style};
Expand Down Expand Up @@ -743,10 +745,7 @@ pub struct TestRunnerOpts {
}

impl TestRunnerOpts {
fn to_builder(
&self,
cap_strat: nextest_runner::test_output::CaptureStrategy,
) -> Option<TestRunnerBuilder> {
fn to_builder(&self, cap_strat: CaptureStrategy) -> Option<TestRunnerBuilder> {
if self.no_run {
return None;
}
Expand Down Expand Up @@ -1557,7 +1556,6 @@ impl App {
structured_reporter.set_libtest(libtest);
}
};
use nextest_runner::test_output::CaptureStrategy;

let cap_strat = if no_capture {
CaptureStrategy::None
Expand All @@ -1584,19 +1582,6 @@ impl App {
let output = output_writer.reporter_output();
let profile = profile.apply_build_platforms(&build_platforms);

let mut reporter = reporter_opts
.to_builder(no_capture)
.set_verbose(self.base.output.verbose)
.build(&test_list, &profile, output, structured_reporter);
if self
.base
.output
.color
.should_colorize(supports_color::Stream::Stderr)
{
reporter.colorize();
}

let handler = SignalHandlerKind::Standard;
let runner_builder = match runner_opts.to_builder(cap_strat) {
Some(runner_builder) => runner_builder,
Expand All @@ -1615,11 +1600,51 @@ impl App {
target_runner.clone(),
)?;

// Start recording runs if the environment variable is set.
{
const EXPERIMENTAL_ENV: &str = "NEXTEST_EXPERIMENTAL_RECORD_RUNS";
if std::env::var(EXPERIMENTAL_ENV).as_deref() == Ok("1") {
// For the record reporter, use the global store dir to share runs across profiles.
let store = RunStore::new(profile.global_store_dir())
.map_err(|err| ExpectedError::RunRecordError { err })?;
let locked_store = store
.lock_exclusive()
.map_err(|err| ExpectedError::RunRecordError { err })?;
let recorder = locked_store
.create_run_recorder(
runner.run_id(),
self.base.current_version.clone(),
runner.started_at().fixed_offset(),
)
.map_err(|err| ExpectedError::RunRecordError { err })?;

let record = structured::RecordReporter::new(recorder);
structured_reporter.set_record(record);
}
}

let mut reporter = reporter_opts
.to_builder(no_capture)
.set_verbose(self.base.output.verbose)
.build(&test_list, &profile, output, structured_reporter);
if self
.base
.output
.color
.should_colorize(supports_color::Stream::Stderr)
{
reporter.colorize();
}

configure_handle_inheritance(no_capture)?;
reporter.report_meta(&self.base.cargo_metadata_json, &test_list);

let run_stats = runner.try_execute(|event| {
// Write and flush the event.
reporter.report_event(event)
})?;
reporter.finish()?;

self.base
.check_version_config_final(version_only_config.nextest_version())?;
if !run_stats.is_success() {
Expand Down
10 changes: 10 additions & 0 deletions cargo-nextest/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ pub enum ExpectedError {
#[from]
err: FromMessagesError,
},
#[error("error recording test run")]
RunRecordError {
#[source]
err: RunStoreError,
},
#[error("create test list error")]
CreateTestListError {
#[source]
Expand Down Expand Up @@ -386,6 +391,7 @@ impl ExpectedError {
| Self::TestFilterBuilderError { .. }
| Self::UnknownHostPlatform { .. }
| Self::ArgumentFileReadError { .. }
| Self::RunRecordError { .. }
| Self::UnknownArchiveFormat { .. }
| Self::ArchiveExtractError { .. }
| Self::RustBuildMetaParseError { .. }
Expand Down Expand Up @@ -700,6 +706,10 @@ impl ExpectedError {
log::error!("failed to parse messages generated by Cargo");
Some(err as &dyn Error)
}
Self::RunRecordError { err } => {
log::error!("error recording run");
Some(err as &dyn Error)
}
Self::CreateTestListError { err } => {
log::error!("creating test list failed");
Some(err as &dyn Error)
Expand Down
1 change: 1 addition & 0 deletions nextest-metadata/src/test_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ impl TestListSummary {
rust_suites: BTreeMap::new(),
}
}

/// Parse JSON output from `cargo nextest list --message-format json`.
pub fn parse_json(json: impl AsRef<str>) -> Result<Self, serde_json::Error> {
serde_json::from_str(json.as_ref())
Expand Down
6 changes: 4 additions & 2 deletions nextest-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ config = { version = "0.13.4", default-features = false, features = [
] }
cargo_metadata = "0.18.1"
cfg-if = "1.0.0"
chrono = "0.4.33"
chrono = { version = "0.4.33", features = ["serde"] }
debug-ignore = "1.0.5"
display-error-chain = "0.2.0"
either = "1.9.0"
futures = "0.3.30"
fs4 = "0.7.0"
guppy = "0.17.4"
# Used to find the cargo root directory, which is needed in case the user has
# added a config.toml there
Expand Down Expand Up @@ -77,6 +78,7 @@ tokio = { version = "1.35.1", features = [
toml = "0.8.8"
toml_edit = { version = "0.21.0", features = ["serde"] }
xxhash-rust = { version = "0.8.8", features = ["xxh64"] }
zip = { version = "0.6.6", default-features = false, features = ["zstd"] }
zstd = { version = "0.13.0", features = ["zstdmt"] }

###
Expand All @@ -93,7 +95,7 @@ self_update = { version = "0.39.0", optional = true, default-features = false, f
nextest-filtering = { version = "0.7.1", path = "../nextest-filtering" }
nextest-metadata = { version = "0.10.0", path = "../nextest-metadata" }
quick-junit = { version = "0.3.5", path = "../quick-junit" }
uuid = { version = "1.7.0", features = ["v4"] }
uuid = { version = "1.7.0", features = ["v4", "serde"] }
console-subscriber = { version = "0.2.0", optional = true }
unicode-ident = "1.0.12"
unicode-normalization = "0.1.22"
Expand Down
Loading