mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 23:34:47 -05:00
refactor(cli/tools/test_runner): make test reporters stateless (#11357)
This collects summary information in the event collector and passes it to the reporter instead of having this embedded in each reporter which leads to a lot of duplication.
This commit is contained in:
parent
9cb48bd8fe
commit
56635d3b52
1 changed files with 76 additions and 73 deletions
|
@ -31,6 +31,7 @@ use std::path::PathBuf;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use swc_common::comments::CommentKind;
|
use swc_common::comments::CommentKind;
|
||||||
|
|
||||||
|
@ -66,36 +67,51 @@ pub struct TestEvent {
|
||||||
pub message: TestMessage,
|
pub message: TestMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct TestSummary {
|
||||||
|
pub total: usize,
|
||||||
|
pub passed: usize,
|
||||||
|
pub failed: usize,
|
||||||
|
pub ignored: usize,
|
||||||
|
pub filtered_out: usize,
|
||||||
|
pub measured: usize,
|
||||||
|
pub failures: Vec<(String, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestSummary {
|
||||||
|
fn new() -> TestSummary {
|
||||||
|
TestSummary {
|
||||||
|
total: 0,
|
||||||
|
passed: 0,
|
||||||
|
failed: 0,
|
||||||
|
ignored: 0,
|
||||||
|
filtered_out: 0,
|
||||||
|
measured: 0,
|
||||||
|
failures: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_failed(&self) -> bool {
|
||||||
|
self.failed > 0 || !self.failures.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_pending(&self) -> bool {
|
||||||
|
self.total - self.passed - self.failed - self.ignored > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trait TestReporter {
|
trait TestReporter {
|
||||||
fn visit_event(&mut self, event: TestEvent);
|
fn visit_event(&mut self, event: TestEvent);
|
||||||
fn done(&mut self);
|
fn done(&mut self, summary: &TestSummary, elapsed: &Duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PrettyTestReporter {
|
struct PrettyTestReporter {
|
||||||
time: Instant,
|
|
||||||
failed: usize,
|
|
||||||
filtered_out: usize,
|
|
||||||
ignored: usize,
|
|
||||||
passed: usize,
|
|
||||||
measured: usize,
|
|
||||||
pending: usize,
|
|
||||||
failures: Vec<(String, String)>,
|
|
||||||
concurrent: bool,
|
concurrent: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyTestReporter {
|
impl PrettyTestReporter {
|
||||||
fn new(concurrent: bool) -> PrettyTestReporter {
|
fn new(concurrent: bool) -> PrettyTestReporter {
|
||||||
PrettyTestReporter {
|
PrettyTestReporter { concurrent }
|
||||||
time: Instant::now(),
|
|
||||||
failed: 0,
|
|
||||||
filtered_out: 0,
|
|
||||||
ignored: 0,
|
|
||||||
passed: 0,
|
|
||||||
measured: 0,
|
|
||||||
pending: 0,
|
|
||||||
failures: Vec::new(),
|
|
||||||
concurrent,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +120,7 @@ impl TestReporter for PrettyTestReporter {
|
||||||
match &event.message {
|
match &event.message {
|
||||||
TestMessage::Plan {
|
TestMessage::Plan {
|
||||||
pending,
|
pending,
|
||||||
filtered,
|
filtered: _,
|
||||||
only: _,
|
only: _,
|
||||||
} => {
|
} => {
|
||||||
if *pending == 1 {
|
if *pending == 1 {
|
||||||
|
@ -112,9 +128,6 @@ impl TestReporter for PrettyTestReporter {
|
||||||
} else {
|
} else {
|
||||||
println!("running {} tests from {}", pending, event.origin);
|
println!("running {} tests from {}", pending, event.origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pending += pending;
|
|
||||||
self.filtered_out += filtered;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestMessage::Wait { name } => {
|
TestMessage::Wait { name } => {
|
||||||
|
@ -128,8 +141,6 @@ impl TestReporter for PrettyTestReporter {
|
||||||
duration,
|
duration,
|
||||||
result,
|
result,
|
||||||
} => {
|
} => {
|
||||||
self.pending -= 1;
|
|
||||||
|
|
||||||
if self.concurrent {
|
if self.concurrent {
|
||||||
print!("test {} ...", name);
|
print!("test {} ...", name);
|
||||||
}
|
}
|
||||||
|
@ -141,49 +152,44 @@ impl TestReporter for PrettyTestReporter {
|
||||||
colors::green("ok"),
|
colors::green("ok"),
|
||||||
colors::gray(format!("({}ms)", duration))
|
colors::gray(format!("({}ms)", duration))
|
||||||
);
|
);
|
||||||
|
|
||||||
self.passed += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestResult::Ignored => {
|
TestResult::Ignored => {
|
||||||
println!(
|
println!(
|
||||||
" {} {}",
|
" {} {}",
|
||||||
colors::yellow("ignored"),
|
colors::yellow("ignored"),
|
||||||
colors::gray(format!("({}ms)", duration))
|
colors::gray(format!("({}ms)", duration))
|
||||||
);
|
);
|
||||||
|
|
||||||
self.ignored += 1;
|
|
||||||
}
|
}
|
||||||
TestResult::Failed(error) => {
|
|
||||||
|
TestResult::Failed(_) => {
|
||||||
println!(
|
println!(
|
||||||
" {} {}",
|
" {} {}",
|
||||||
colors::red("FAILED"),
|
colors::red("FAILED"),
|
||||||
colors::gray(format!("({}ms)", duration))
|
colors::gray(format!("({}ms)", duration))
|
||||||
);
|
);
|
||||||
|
|
||||||
self.failed += 1;
|
|
||||||
self.failures.push((name.to_string(), error.to_string()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn done(&mut self) {
|
fn done(&mut self, summary: &TestSummary, elapsed: &Duration) {
|
||||||
if !self.failures.is_empty() {
|
if !summary.failures.is_empty() {
|
||||||
println!("\nfailures:\n");
|
println!("\nfailures:\n");
|
||||||
for (name, error) in &self.failures {
|
for (name, error) in &summary.failures {
|
||||||
println!("{}", name);
|
println!("{}", name);
|
||||||
println!("{}", error);
|
println!("{}", error);
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("failures:\n");
|
println!("failures:\n");
|
||||||
for (name, _) in &self.failures {
|
for (name, _) in &summary.failures {
|
||||||
println!("\t{}", name);
|
println!("\t{}", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = if self.pending > 0 || !self.failures.is_empty() {
|
let status = if summary.has_failed() || summary.has_pending() {
|
||||||
colors::red("FAILED").to_string()
|
colors::red("FAILED").to_string()
|
||||||
} else {
|
} else {
|
||||||
colors::green("ok").to_string()
|
colors::green("ok").to_string()
|
||||||
|
@ -192,12 +198,12 @@ impl TestReporter for PrettyTestReporter {
|
||||||
println!(
|
println!(
|
||||||
"\ntest result: {}. {} passed; {} failed; {} ignored; {} measured; {} filtered out {}\n",
|
"\ntest result: {}. {} passed; {} failed; {} ignored; {} measured; {} filtered out {}\n",
|
||||||
status,
|
status,
|
||||||
self.passed,
|
summary.passed,
|
||||||
self.failed,
|
summary.failed,
|
||||||
self.ignored,
|
summary.ignored,
|
||||||
self.measured,
|
summary.measured,
|
||||||
self.filtered_out,
|
summary.filtered_out,
|
||||||
colors::gray(format!("({}ms)", self.time.elapsed().as_millis())),
|
colors::gray(format!("({}ms)", elapsed.as_millis())),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -511,69 +517,66 @@ pub async fn run_tests(
|
||||||
let mut reporter = create_reporter(concurrent_jobs > 1);
|
let mut reporter = create_reporter(concurrent_jobs > 1);
|
||||||
let handler = {
|
let handler = {
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let earlier = Instant::now();
|
||||||
|
let mut summary = TestSummary::new();
|
||||||
let mut used_only = false;
|
let mut used_only = false;
|
||||||
let mut has_error = false;
|
|
||||||
let mut planned = 0;
|
|
||||||
let mut reported = 0;
|
|
||||||
let mut failed = 0;
|
|
||||||
|
|
||||||
for event in receiver.iter() {
|
for event in receiver.iter() {
|
||||||
match event.message.clone() {
|
match event.message.clone() {
|
||||||
TestMessage::Plan {
|
TestMessage::Plan {
|
||||||
pending,
|
pending,
|
||||||
filtered: _,
|
filtered,
|
||||||
only,
|
only,
|
||||||
} => {
|
} => {
|
||||||
|
summary.total += pending;
|
||||||
|
summary.filtered_out += filtered;
|
||||||
|
|
||||||
if only {
|
if only {
|
||||||
used_only = true;
|
used_only = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
planned += pending;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestMessage::Result {
|
TestMessage::Result {
|
||||||
name: _,
|
name,
|
||||||
duration: _,
|
duration: _,
|
||||||
result,
|
result,
|
||||||
} => {
|
} => match result {
|
||||||
reported += 1;
|
TestResult::Ok => {
|
||||||
|
summary.passed += 1;
|
||||||
if let TestResult::Failed(_) = result {
|
|
||||||
has_error = true;
|
|
||||||
failed += 1;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
TestResult::Ignored => {
|
||||||
|
summary.ignored += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult::Failed(error) => {
|
||||||
|
summary.failed += 1;
|
||||||
|
summary.failures.push((name.clone(), error.clone()));
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
reporter.visit_event(event);
|
reporter.visit_event(event);
|
||||||
|
|
||||||
if let Some(x) = fail_fast {
|
if let Some(x) = fail_fast {
|
||||||
if failed >= x {
|
if summary.failed >= x {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if planned > reported {
|
let elapsed = Instant::now().duration_since(earlier);
|
||||||
has_error = true;
|
reporter.done(&summary, &elapsed);
|
||||||
}
|
|
||||||
|
|
||||||
reporter.done();
|
|
||||||
|
|
||||||
if planned > reported {
|
|
||||||
has_error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if used_only {
|
if used_only {
|
||||||
println!(
|
println!(
|
||||||
"{} because the \"only\" option was used\n",
|
"{} because the \"only\" option was used\n",
|
||||||
colors::red("FAILED")
|
colors::red("FAILED")
|
||||||
);
|
);
|
||||||
|
|
||||||
has_error = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
has_error
|
used_only || summary.failed > 0
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue