Skip to content

Commit

Permalink
[nextest-runner] wrap test events in TestEventKind
Browse files Browse the repository at this point in the history
All test events now also carry a total time elapsed. This will be useful
for DTrace support if/when we get to it.
  • Loading branch information
sunshowers committed Sep 20, 2023
1 parent b6da7ef commit cd6f445
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 48 deletions.
49 changes: 31 additions & 18 deletions nextest-runner/src/reporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,14 +389,14 @@ impl<'a> TestReporter<'a> {
}

fn update_progress_bar(event: &TestEvent<'_>, styles: &Styles, progress_bar: &ProgressBar) {
match event {
TestEvent::TestStarted {
match &event.kind {

Check warning on line 392 in nextest-runner/src/reporter.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter.rs#L392

Added line #L392 was not covered by tests
TestEventKind::TestStarted {
current_stats,
running,
cancel_state,
..
}
| TestEvent::TestFinished {
| TestEventKind::TestFinished {
current_stats,
running,
cancel_state,
Expand All @@ -410,7 +410,7 @@ fn update_progress_bar(event: &TestEvent<'_>, styles: &Styles, progress_bar: &Pr
progress_bar.set_length(current_stats.initial_run_count as u64);
progress_bar.set_position(current_stats.finished_count as u64);
}
TestEvent::RunBeginCancel { reason, .. } => {
TestEventKind::RunBeginCancel { reason, .. } => {

Check warning on line 413 in nextest-runner/src/reporter.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter.rs#L413

Added line #L413 was not covered by tests
let running_state = RunningState::Canceling(*reason);
progress_bar.set_prefix(running_state.progress_bar_prefix(styles));
}
Expand Down Expand Up @@ -564,8 +564,8 @@ impl<'a> TestReporterImpl<'a> {
event: &TestEvent<'a>,
writer: &mut impl Write,
) -> io::Result<()> {
match event {
TestEvent::RunStarted { test_list, .. } => {
match &event.kind {
TestEventKind::RunStarted { test_list, .. } => {
write!(writer, "{:>12} ", "Starting".style(self.styles.pass))?;

let count_style = self.styles.count;
Expand Down Expand Up @@ -596,7 +596,7 @@ impl<'a> TestReporterImpl<'a> {

writeln!(writer)?;
}
TestEvent::TestStarted { test_instance, .. } => {
TestEventKind::TestStarted { test_instance, .. } => {
// In no-capture mode, print out a test start event.
if self.no_capture {
// The spacing is to align test instances.
Expand All @@ -609,7 +609,7 @@ impl<'a> TestReporterImpl<'a> {
writeln!(writer)?;
}
}
TestEvent::TestSlow {
TestEventKind::TestSlow {
test_instance,
retry_data,
elapsed,
Expand Down Expand Up @@ -647,7 +647,7 @@ impl<'a> TestReporterImpl<'a> {
writeln!(writer)?;
}

TestEvent::TestAttemptFailedWillRetry {
TestEventKind::TestAttemptFailedWillRetry {
test_instance,
run_status,
delay_before_next_attempt,
Expand Down Expand Up @@ -701,7 +701,7 @@ impl<'a> TestReporterImpl<'a> {
}
}
}
TestEvent::TestRetryStarted {
TestEventKind::TestRetryStarted {
test_instance,
retry_data:
RetryData {
Expand All @@ -719,7 +719,7 @@ impl<'a> TestReporterImpl<'a> {
self.write_instance(*test_instance, writer)?;
writeln!(writer)?;
}
TestEvent::TestFinished {
TestEventKind::TestFinished {
test_instance,
success_output,
failure_output,
Expand Down Expand Up @@ -759,7 +759,7 @@ impl<'a> TestReporterImpl<'a> {
));
}
}
TestEvent::TestSkipped {
TestEventKind::TestSkipped {
test_instance,
reason,
} => {
Expand All @@ -771,7 +771,7 @@ impl<'a> TestReporterImpl<'a> {
.push((*test_instance, FinalOutput::Skipped(*reason)));
}
}
TestEvent::RunBeginCancel { running, reason } => {
TestEventKind::RunBeginCancel { running, reason } => {

Check warning on line 774 in nextest-runner/src/reporter.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter.rs#L774

Added line #L774 was not covered by tests
self.cancel_status = self.cancel_status.max(Some(*reason));

write!(writer, "{:>12} ", "Canceling".style(self.styles.fail))?;
Expand All @@ -789,7 +789,7 @@ impl<'a> TestReporterImpl<'a> {
running.style(self.styles.count)
)?;
}
TestEvent::RunPaused { running } => {
TestEventKind::RunPaused { running } => {

Check warning on line 792 in nextest-runner/src/reporter.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter.rs#L792

Added line #L792 was not covered by tests
writeln!(
writer,
"{:>12} {} running tests due to {}",
Expand All @@ -798,7 +798,7 @@ impl<'a> TestReporterImpl<'a> {
"signal".style(self.styles.count),
)?;
}
TestEvent::RunContinued { running } => {
TestEventKind::RunContinued { running } => {

Check warning on line 801 in nextest-runner/src/reporter.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter.rs#L801

Added line #L801 was not covered by tests
writeln!(
writer,
"{:>12} {} running tests due to {}",
Expand All @@ -807,7 +807,7 @@ impl<'a> TestReporterImpl<'a> {
"signal".style(self.styles.count),
)?;
}
TestEvent::RunFinished {
TestEventKind::RunFinished {
start_time: _start_time,
elapsed,
run_stats,
Expand Down Expand Up @@ -1292,9 +1292,22 @@ fn short_status_str(result: ExecutionResult) -> Cow<'static, str> {

/// A test event.
///
/// Events are produced by a [`TestRunner`](crate::runner::TestRunner) and consumed by a [`TestReporter`].
/// Events are produced by a [`TestRunner`](crate::runner::TestRunner) and consumed by a
/// [`TestReporter`].
#[derive(Clone, Debug)]
pub enum TestEvent<'a> {
pub struct TestEvent<'a> {
/// The amount of time elapsed since the start of the test run.
pub elapsed: Duration,

/// The kind of test event this is.
pub kind: TestEventKind<'a>,
}

/// The kind of test event this is.
///
/// Forms part of [`TestEvent`].
#[derive(Clone, Debug)]

Check warning on line 1309 in nextest-runner/src/reporter.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter.rs#L1309

Added line #L1309 was not covered by tests
pub enum TestEventKind<'a> {
/// The test run started.
RunStarted {
/// The list of tests that will be run.
Expand Down
26 changes: 14 additions & 12 deletions nextest-runner/src/reporter/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

//! Metadata management.
use super::TestEvent;
#[cfg(any(unix, windows))]
use crate::runner::AbortStatus;
use crate::{
config::{NextestJunitConfig, NextestProfile},
errors::WriteEventError,
list::TestInstance,
reporter::TestEvent,
reporter::TestEventKind,
runner::{ExecuteStatus, ExecutionDescription, ExecutionResult},
};
use camino::Utf8PathBuf;
Expand Down Expand Up @@ -60,16 +61,17 @@ impl<'cfg> MetadataJunit<'cfg> {
}

pub(crate) fn write_event(&mut self, event: TestEvent<'cfg>) -> Result<(), WriteEventError> {
match event {
TestEvent::RunStarted { .. }
| TestEvent::RunPaused { .. }
| TestEvent::RunContinued { .. } => {}
TestEvent::TestStarted { .. } => {}
TestEvent::TestSlow { .. } => {}
TestEvent::TestAttemptFailedWillRetry { .. } | TestEvent::TestRetryStarted { .. } => {
match event.kind {

Check warning on line 64 in nextest-runner/src/reporter/aggregator.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter/aggregator.rs#L64

Added line #L64 was not covered by tests
TestEventKind::RunStarted { .. }
| TestEventKind::RunPaused { .. }
| TestEventKind::RunContinued { .. } => {}
TestEventKind::TestStarted { .. } => {}
TestEventKind::TestSlow { .. } => {}

Check warning on line 69 in nextest-runner/src/reporter/aggregator.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter/aggregator.rs#L67-L69

Added lines #L67 - L69 were not covered by tests
TestEventKind::TestAttemptFailedWillRetry { .. }
| TestEventKind::TestRetryStarted { .. } => {

Check warning on line 71 in nextest-runner/src/reporter/aggregator.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter/aggregator.rs#L71

Added line #L71 was not covered by tests
// Retries are recorded in TestFinished.
}
TestEvent::TestFinished {
TestEventKind::TestFinished {
test_instance,
run_statuses,
junit_store_success_output,
Expand Down Expand Up @@ -189,7 +191,7 @@ impl<'cfg> MetadataJunit<'cfg> {

testsuite.add_test_case(testcase);
}
TestEvent::TestSkipped { .. } => {
TestEventKind::TestSkipped { .. } => {

Check warning on line 194 in nextest-runner/src/reporter/aggregator.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter/aggregator.rs#L194

Added line #L194 was not covered by tests
// TODO: report skipped tests? causes issues if we want to aggregate runs across
// skipped and non-skipped tests. Probably needs to be made configurable.

Expand All @@ -201,8 +203,8 @@ impl<'cfg> MetadataJunit<'cfg> {
//
// testsuite.add_testcase(testcase);
}
TestEvent::RunBeginCancel { .. } => {}
TestEvent::RunFinished {
TestEventKind::RunBeginCancel { .. } => {}

Check warning on line 206 in nextest-runner/src/reporter/aggregator.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/reporter/aggregator.rs#L206

Added line #L206 was not covered by tests
TestEventKind::RunFinished {
run_id,
start_time,
elapsed,
Expand Down
40 changes: 26 additions & 14 deletions nextest-runner/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use crate::{
double_spawn::DoubleSpawnInfo,
errors::{ConfigureHandleInheritanceError, TestRunnerBuildError},
list::{TestExecuteContext, TestInstance, TestList},
reporter::{CancelReason, FinalStatusLevel, StatusLevel, TestEvent, TestOutputDisplay},
reporter::{
CancelReason, FinalStatusLevel, StatusLevel, TestEvent, TestEventKind, TestOutputDisplay,
},
signal::{JobControlEvent, ShutdownEvent, SignalEvent, SignalHandler, SignalHandlerKind},
target_runner::TargetRunner,
time::{StopwatchEnd, StopwatchStart},
Expand Down Expand Up @@ -1262,17 +1264,27 @@ where
}

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

#[inline]
fn basic_callback(&mut self, kind: TestEventKind<'a>) -> Result<(), E> {
let event = TestEvent {
elapsed: self.stopwatch.elapsed(),
kind,
};
(self.callback)(event)
}

#[inline]
fn callback(
&mut self,
test_event: TestEvent<'a>,
kind: TestEventKind<'a>,
) -> Result<Option<JobControlEvent>, InternalError<E>> {
(self.callback)(test_event).map_err(InternalError::Error)?;
self.basic_callback(kind).map_err(InternalError::Error)?;
Ok(None)
}

Expand All @@ -1283,7 +1295,7 @@ where
match event {
InternalEvent::Test(InternalTestEvent::Started { test_instance }) => {
self.running += 1;
self.callback(TestEvent::TestStarted {
self.callback(TestEventKind::TestStarted {
test_instance,
current_stats: self.run_stats,
running: self.running,
Expand All @@ -1295,7 +1307,7 @@ where
retry_data,
elapsed,
will_terminate,
}) => self.callback(TestEvent::TestSlow {
}) => self.callback(TestEventKind::TestSlow {
test_instance,
retry_data,
elapsed,
Expand All @@ -1306,7 +1318,7 @@ where
failure_output,
run_status,
delay_before_next_attempt,
}) => self.callback(TestEvent::TestAttemptFailedWillRetry {
}) => self.callback(TestEventKind::TestAttemptFailedWillRetry {
test_instance,
failure_output,
run_status,
Expand All @@ -1315,7 +1327,7 @@ where
InternalEvent::Test(InternalTestEvent::RetryStarted {
test_instance,
retry_data,
}) => self.callback(TestEvent::TestRetryStarted {
}) => self.callback(TestEventKind::TestRetryStarted {
test_instance,
retry_data,
}),
Expand All @@ -1333,7 +1345,7 @@ where
// should this run be canceled because of a failure?
let fail_cancel = self.fail_fast && !run_statuses.last_status().result.is_success();

self.callback(TestEvent::TestFinished {
self.callback(TestEventKind::TestFinished {
test_instance,
success_output,
failure_output,
Expand All @@ -1359,7 +1371,7 @@ where
reason,
}) => {
self.run_stats.skipped += 1;
self.callback(TestEvent::TestSkipped {
self.callback(TestEventKind::TestSkipped {
test_instance,
reason,
})
Expand All @@ -1383,7 +1395,7 @@ where
InternalEvent::Signal(SignalEvent::JobControl(JobControlEvent::Stop)) => {
// Debounce stop signals.
if !self.stopwatch.is_paused() {
self.callback(TestEvent::RunPaused {
self.callback(TestEventKind::RunPaused {

Check warning on line 1398 in nextest-runner/src/runner.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/runner.rs#L1398

Added line #L1398 was not covered by tests
running: self.running,
})?;
self.stopwatch.pause();
Expand All @@ -1397,7 +1409,7 @@ where
// Debounce continue signals.
if self.stopwatch.is_paused() {
self.stopwatch.resume();
self.callback(TestEvent::RunContinued {
self.callback(TestEventKind::RunContinued {

Check warning on line 1412 in nextest-runner/src/runner.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/runner.rs#L1412

Added line #L1412 was not covered by tests
running: self.running,
})?;
Ok(Some(JobControlEvent::Continue))
Expand Down Expand Up @@ -1426,7 +1438,7 @@ where
fn begin_cancel(&mut self, reason: CancelReason) -> Result<(), E> {
if self.cancel_state < Some(reason) {
self.cancel_state = Some(reason);
(self.callback)(TestEvent::RunBeginCancel {
self.basic_callback(TestEventKind::RunBeginCancel {

Check warning on line 1441 in nextest-runner/src/runner.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/runner.rs#L1441

Added line #L1441 was not covered by tests
running: self.running,
reason,
})?;
Expand All @@ -1436,7 +1448,7 @@ where

fn run_finished(&mut self) -> Result<(), E> {
let stopwatch_end = self.stopwatch.end();
(self.callback)(TestEvent::RunFinished {
self.basic_callback(TestEventKind::RunFinished {
start_time: stopwatch_end.start_time,
run_id: self.run_id,
elapsed: stopwatch_end.duration,
Expand Down
4 changes: 4 additions & 0 deletions nextest-runner/src/time/stopwatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ impl StopwatchStart {
}
}

pub(crate) fn elapsed(&self) -> Duration {
self.instant.elapsed() - self.paused_time
}

pub(crate) fn end(&self) -> StopwatchEnd {
StopwatchEnd {
start_time: self.start_time,
Expand Down
8 changes: 4 additions & 4 deletions nextest-runner/tests/integration/fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use nextest_runner::{
list::{
BinaryList, RustBuildMeta, RustTestArtifact, TestExecuteContext, TestList, TestListState,
},
reporter::TestEvent,
reporter::TestEventKind,
reuse_build::PathMapper,
runner::{
configure_handle_inheritance, AbortStatus, ExecutionResult, ExecutionStatuses, RunStats,
Expand Down Expand Up @@ -416,12 +416,12 @@ pub(crate) fn execute_collect(
let mut instance_statuses = HashMap::new();
configure_handle_inheritance(false).expect("configuring handle inheritance on Windows failed");
let run_stats = runner.execute(|event| {
let (test_instance, status) = match event {
TestEvent::TestSkipped {
let (test_instance, status) = match event.kind {
TestEventKind::TestSkipped {
test_instance,
reason,
} => (test_instance, InstanceStatus::Skipped(reason)),
TestEvent::TestFinished {
TestEventKind::TestFinished {
test_instance,
run_statuses,
..
Expand Down

0 comments on commit cd6f445

Please sign in to comment.