Skip to content

Commit

Permalink
[nextest-runner] add run ID to JUnit reports
Browse files Browse the repository at this point in the history
This may help people. It is an extension to JUnit but not a huge one.
  • Loading branch information
sunshowers committed Jul 28, 2022
1 parent 39e9b70 commit 9c5bfac
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 5 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

12 changes: 10 additions & 2 deletions nextest-runner/src/reporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
mod aggregator;
pub use aggregator::heuristic_extract_description;
use uuid::Uuid;

use crate::{
config::NextestProfile,
Expand Down Expand Up @@ -618,7 +619,7 @@ impl<'a> TestReporterImpl<'a> {
writer: &mut impl Write,
) -> io::Result<()> {
match event {
TestEvent::RunStarted { test_list } => {
TestEvent::RunStarted { test_list, .. } => {
write!(writer, "{:>12} ", "Starting".style(self.styles.pass))?;

let count_style = self.styles.count;
Expand Down Expand Up @@ -757,6 +758,7 @@ impl<'a> TestReporterImpl<'a> {
start_time: _start_time,
elapsed,
run_stats,
..
} => {
let summary_style = if run_stats.any_failed() {
self.styles.fail
Expand Down Expand Up @@ -1225,8 +1227,11 @@ pub enum TestEvent<'a> {
RunStarted {
/// The list of tests that will be run.
///
/// The methods on the test list indicate the number of
/// The methods on the test list indicate the number of tests that will be run.
test_list: &'a TestList<'a>,

/// The UUID for this run.
run_id: Uuid,
},

// TODO: add events for BinaryStarted and BinaryFinished? May want a slightly different way to
Expand Down Expand Up @@ -1305,6 +1310,9 @@ pub enum TestEvent<'a> {

/// The test run finished.
RunFinished {
/// The unique ID for this run.
run_id: Uuid,

/// The time at which the run was started.
start_time: SystemTime,

Expand Down
2 changes: 2 additions & 0 deletions nextest-runner/src/reporter/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,15 @@ impl<'cfg> MetadataJunit<'cfg> {
}
TestEvent::RunBeginCancel { .. } => {}
TestEvent::RunFinished {
run_id,
start_time,
elapsed,
..
} => {
// Write out the report to the given file.
let mut report = Report::new(self.config.report_name());
report
.set_uuid(run_id)
.set_timestamp(to_datetime(start_time))
.set_time(elapsed)
.add_test_suites(self.test_suites.drain().map(|(_, testsuite)| testsuite));
Expand Down
17 changes: 14 additions & 3 deletions nextest-runner/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,12 @@ impl<'a> TestRunnerInner<'a> {
let canceled = AtomicBool::new(false);
let canceled_ref = &canceled;

let mut ctx = CallbackContext::new(callback, self.test_list.run_count(), self.fail_fast);
let mut ctx = CallbackContext::new(
callback,
self.run_id,
self.test_list.run_count(),
self.fail_fast,
);

// Send the initial event.
// (Don't need to set the canceled atomic if this fails because the run hasn't started
Expand Down Expand Up @@ -962,6 +967,7 @@ enum SignalForwardEvent {

struct CallbackContext<F, E> {
callback: F,
run_id: Uuid,
stopwatch: StopwatchStart,
run_stats: RunStats,
fail_fast: bool,
Expand All @@ -975,9 +981,10 @@ impl<'a, F, E> CallbackContext<F, E>
where
F: FnMut(TestEvent<'a>) -> Result<(), E> + Send,
{
fn new(callback: F, initial_run_count: usize, fail_fast: bool) -> Self {
fn new(callback: F, run_id: Uuid, initial_run_count: usize, fail_fast: bool) -> Self {
Self {
callback,
run_id,
stopwatch: StopwatchStart::now(),
run_stats: RunStats {
initial_run_count,
Expand All @@ -992,7 +999,10 @@ where
}

fn run_started(&mut self, test_list: &'a TestList) -> Result<(), E> {
(self.callback)(TestEvent::RunStarted { test_list })
(self.callback)(TestEvent::RunStarted {
test_list,
run_id: self.run_id,
})
}

fn handle_event(&mut self, event: InternalEvent<'a>) -> Result<(), InternalError<E>> {
Expand Down Expand Up @@ -1110,6 +1120,7 @@ where
let stopwatch_end = self.stopwatch.end();
(self.callback)(TestEvent::RunFinished {
start_time: stopwatch_end.start_time,
run_id: self.run_id,
elapsed: stopwatch_end.duration,
run_stats: self.run_stats,
})
Expand Down
1 change: 1 addition & 0 deletions quick-junit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ chrono = "0.4.19"
indexmap = "1.9.1"
quick-xml = "0.23.0"
thiserror = "1.0.31"
uuid = "1.1.2"
nextest-workspace-hack = { version = "0.1", path = "../workspace-hack" }

[dev-dependencies]
Expand Down
15 changes: 15 additions & 0 deletions quick-junit/src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ use crate::{serialize::serialize_report, SerializeError};
use chrono::{DateTime, FixedOffset};
use indexmap::map::IndexMap;
use std::{io, iter, time::Duration};
use uuid::Uuid;

/// The root element of a JUnit report.
#[derive(Clone, Debug)]
pub struct Report {
/// The name of this report.
pub name: String,

/// A unique identifier associated with this report.
///
/// This is an extension to the spec that's used by nextest.
pub uuid: Option<Uuid>,

/// The time at which the first test in this report began execution.
///
/// This is not part of the JUnit spec, but may be useful for some tools.
Expand Down Expand Up @@ -40,6 +46,7 @@ impl Report {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
uuid: None,
timestamp: None,
time: None,
tests: 0,
Expand All @@ -49,6 +56,14 @@ impl Report {
}
}

/// Sets a unique ID for this `Report`.
///
/// This is an extension that's used by nextest.
pub fn set_uuid(&mut self, uuid: Uuid) -> &mut Self {
self.uuid = Some(uuid);
self
}

/// Sets the start timestamp for the report.
pub fn set_timestamp(&mut self, timestamp: impl Into<DateTime<FixedOffset>>) -> &mut Self {
self.timestamp = Some(timestamp.into());
Expand Down
4 changes: 4 additions & 0 deletions quick-junit/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub(crate) fn serialize_report_impl(
// Use the destructuring syntax to ensure that all fields are handled.
let Report {
name,
uuid,
timestamp,
time,
tests,
Expand All @@ -67,6 +68,9 @@ pub(crate) fn serialize_report_impl(
("failures", failures.to_string().as_str()),
("errors", errors.to_string().as_str()),
]);
if let Some(uuid) = uuid {
testsuites_tag.push_attribute(("uuid", uuid.to_string().as_str()));
}
if let Some(timestamp) = timestamp {
serialize_timestamp(&mut testsuites_tag, timestamp);
}
Expand Down
1 change: 1 addition & 0 deletions workspace-hack/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ regex-syntax = { version = "0.6.27", features = ["unicode", "unicode-age", "unic
serde = { version = "1.0.140", features = ["derive", "serde_derive", "std"] }
serde_json = { version = "1.0.82", features = ["std", "unbounded_depth"] }
textwrap = { version = "0.15.0", features = ["smawk", "unicode-linebreak", "unicode-width"] }
uuid = { version = "1.1.2", features = ["private_getrandom", "rng", "std", "v4"] }

[build-dependencies]
cc = { version = "1.0.73", default-features = false, features = ["jobserver", "parallel"] }
Expand Down

0 comments on commit 9c5bfac

Please sign in to comment.