Add more runner events to the reporter and refine the structure

This commit is contained in:
Omar Abdulla
2025-08-24 20:13:48 +03:00
parent cbb6a11404
commit 4d7d7ed843
6 changed files with 88 additions and 22 deletions
@@ -7,6 +7,15 @@ macro_rules! impl_for_wrapper {
} }
} }
}; };
(FromStr, $ident: ident) => {
impl std::str::FromStr for $ident {
type Err = anyhow::Error;
fn from_str(s: &str) -> anyhow::Result<Self> {
s.parse().map(Self).map_err(Into::into)
}
}
};
} }
/// Defines wrappers around types. /// Defines wrappers around types.
+11 -11
View File
@@ -71,7 +71,8 @@ fn main() -> anyhow::Result<()> {
let (reporter, report_aggregator_task) = ReportAggregator::new(args.clone()).into_task(); let (reporter, report_aggregator_task) = ReportAggregator::new(args.clone()).into_task();
let body = async { let number_of_threads = args.number_of_threads;
let body = async move {
let tests = collect_corpora(&args)? let tests = collect_corpora(&args)?
.into_iter() .into_iter()
.inspect(|(corpus, _)| { .inspect(|(corpus, _)| {
@@ -83,7 +84,7 @@ fn main() -> anyhow::Result<()> {
.inspect(|metadata_file| { .inspect(|metadata_file| {
reporter reporter
.report_metadata_file_discovery_event( .report_metadata_file_discovery_event(
metadata_file.metadata_file_path.as_path(), metadata_file.metadata_file_path.clone(),
metadata_file.content.clone(), metadata_file.content.clone(),
) )
.expect("Can't fail") .expect("Can't fail")
@@ -100,7 +101,7 @@ fn main() -> anyhow::Result<()> {
}; };
tokio::runtime::Builder::new_multi_thread() tokio::runtime::Builder::new_multi_thread()
.worker_threads(args.number_of_threads) .worker_threads(number_of_threads)
.enable_all() .enable_all()
.build() .build()
.expect("Failed building the Runtime") .expect("Failed building the Runtime")
@@ -183,16 +184,15 @@ where
let (report_tx, report_rx) = mpsc::unbounded_channel::<(Test<'_>, CaseResult)>(); let (report_tx, report_rx) = mpsc::unbounded_channel::<(Test<'_>, CaseResult)>();
let tests = prepare_tests::<L, F>(args, metadata_files); let tests = prepare_tests::<L, F>(args, metadata_files);
let driver_task = start_driver_task::<L, F>(args, tests, report_tx) let driver_task = start_driver_task::<L, F>(args, tests, report_tx).await?;
.await?
.inspect(|_| {
reporter
.report_execution_completed_event()
.expect("Failed to inform the report aggregator of the task finishing")
});
let status_reporter_task = start_reporter_task(report_rx); let status_reporter_task = start_reporter_task(report_rx);
let (_, _, rtn) = tokio::join!(status_reporter_task, driver_task, report_aggregator_task); drop(reporter);
let (_, _, rtn) = tokio::join!(
status_reporter_task.inspect(|_| info!("Status reporter completed")),
driver_task.inspect(|_| info!("Driver completed")),
report_aggregator_task.inspect(|_| info!("Report aggregator completed"))
);
rtn?; rtn?;
Ok(()) Ok(())
+1 -1
View File
@@ -73,5 +73,5 @@ define_wrapper_type!(
/// A wrapper type for the index of test cases found in metadata file. /// A wrapper type for the index of test cases found in metadata file.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)] #[serde(transparent)]
pub struct CaseIdx(usize) impl Display; pub struct CaseIdx(usize) impl Display, FromStr;
); );
+37 -6
View File
@@ -2,23 +2,25 @@
//! reporters and combines them into a single unified report. //! reporters and combines them into a single unified report.
use std::{ use std::{
collections::BTreeSet, collections::{BTreeSet, HashMap, HashSet},
fs::OpenOptions, fs::OpenOptions,
path::PathBuf,
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
use anyhow::Result; use anyhow::Result;
use revive_dt_compiler::Mode;
use revive_dt_config::Arguments; use revive_dt_config::Arguments;
use revive_dt_format::corpus::Corpus; use revive_dt_format::{case::CaseIdx, corpus::Corpus};
use serde::Serialize; use serde::Serialize;
use serde_with::{DisplayFromStr, serde_as};
use tokio::sync::{ use tokio::sync::{
broadcast::{Sender, channel}, broadcast::{Sender, channel},
mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel}, mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel},
}; };
use crate::{ use crate::{
SubscribeToEventsEvent, SubscribeToEventsEvent, TestIgnoredEvent,
common::MetadataFilePath,
reporter_event::ReporterEvent, reporter_event::ReporterEvent,
runner_event::{CorpusFileDiscoveryEvent, MetadataFileDiscoveryEvent, Reporter, RunnerEvent}, runner_event::{CorpusFileDiscoveryEvent, MetadataFileDiscoveryEvent, Reporter, RunnerEvent},
}; };
@@ -26,6 +28,7 @@ use crate::{
pub struct ReportAggregator { pub struct ReportAggregator {
/* Internal Report State */ /* Internal Report State */
report: Report, report: Report,
remaining_cases: HashMap<MetadataFilePath, HashSet<CaseIdx>>,
/* Channels */ /* Channels */
runner_tx: Option<UnboundedSender<RunnerEvent>>, runner_tx: Option<UnboundedSender<RunnerEvent>>,
runner_rx: UnboundedReceiver<RunnerEvent>, runner_rx: UnboundedReceiver<RunnerEvent>,
@@ -38,6 +41,7 @@ impl ReportAggregator {
let (listener_tx, _) = channel::<ReporterEvent>(1024); let (listener_tx, _) = channel::<ReporterEvent>(1024);
Self { Self {
report: Report::new(config), report: Report::new(config),
remaining_cases: Default::default(),
runner_tx: Some(runner_tx), runner_tx: Some(runner_tx),
runner_rx, runner_rx,
listener_tx, listener_tx,
@@ -66,6 +70,9 @@ impl ReportAggregator {
RunnerEvent::MetadataFileDiscovery(event) => { RunnerEvent::MetadataFileDiscovery(event) => {
self.handle_metadata_file_discovery_event(*event); self.handle_metadata_file_discovery_event(*event);
} }
RunnerEvent::TestIgnored(event) => {
self.handle_test_ignored_event(*event);
}
} }
} }
@@ -96,10 +103,26 @@ impl ReportAggregator {
} }
fn handle_metadata_file_discovery_event(&mut self, event: MetadataFileDiscoveryEvent) { fn handle_metadata_file_discovery_event(&mut self, event: MetadataFileDiscoveryEvent) {
self.report.metadata_files.insert(event.path); self.report.metadata_files.insert(event.path.clone());
self.remaining_cases.insert(
event.path,
event
.metadata
.cases
.iter()
.enumerate()
.map(|(id, _)| id)
.map(CaseIdx::new)
.collect(),
);
}
fn handle_test_ignored_event(&mut self, _: TestIgnoredEvent) {
todo!()
} }
} }
#[serde_as]
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
pub struct Report { pub struct Report {
/// The configuration that the tool was started up with. /// The configuration that the tool was started up with.
@@ -107,7 +130,11 @@ pub struct Report {
/// The list of corpus files that the tool found. /// The list of corpus files that the tool found.
pub corpora: Vec<Corpus>, pub corpora: Vec<Corpus>,
/// The list of metadata files that were found by the tool. /// The list of metadata files that were found by the tool.
pub metadata_files: BTreeSet<PathBuf>, pub metadata_files: BTreeSet<MetadataFilePath>,
/// Information relating to each test case.
#[serde_as(as = "HashMap<_, HashMap<DisplayFromStr, HashMap<DisplayFromStr, _>>>")]
pub test_case_information:
HashMap<MetadataFilePath, HashMap<Mode, HashMap<CaseIdx, TestCaseReport>>>,
} }
impl Report { impl Report {
@@ -116,6 +143,10 @@ impl Report {
config, config,
corpora: Default::default(), corpora: Default::default(),
metadata_files: Default::default(), metadata_files: Default::default(),
test_case_information: Default::default(),
} }
} }
} }
#[derive(Clone, Debug, Serialize)]
pub struct TestCaseReport {}
+1
View File
@@ -10,6 +10,7 @@ use serde_with::{DisplayFromStr, serde_as};
define_wrapper_type!( define_wrapper_type!(
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct MetadataFilePath(PathBuf); pub struct MetadataFilePath(PathBuf);
); );
+29 -4
View File
@@ -1,12 +1,11 @@
//! The types associated with the events sent by the runner to the reporter. //! The types associated with the events sent by the runner to the reporter.
#![allow(dead_code)]
use std::path::PathBuf;
use revive_dt_format::corpus::Corpus; use revive_dt_format::corpus::Corpus;
use revive_dt_format::metadata::Metadata; use revive_dt_format::metadata::Metadata;
use tokio::sync::{broadcast, oneshot}; use tokio::sync::{broadcast, oneshot};
use crate::ReporterEvent; use crate::{ReporterEvent, common::MetadataFilePath};
macro_rules! keep_if_doc { macro_rules! keep_if_doc {
(#[doc = $doc:expr]) => { (#[doc = $doc:expr]) => {
@@ -91,6 +90,16 @@ macro_rules! define_event {
} }
impl [< $ident Reporter >] { impl [< $ident Reporter >] {
pub fn test_specific_reporter(
&self,
test_specifier: impl Into<std::sync::Arc<crate::common::TestSpecifier>>
) -> [< $ident TestSpecificReporter >] {
[< $ident TestSpecificReporter >] {
reporter: self.clone(),
test_specifier: test_specifier.into(),
}
}
fn report(&self, event: impl Into<$ident>) -> anyhow::Result<()> { fn report(&self, event: impl Into<$ident>) -> anyhow::Result<()> {
self.0.send(event.into()).map_err(Into::into) self.0.send(event.into()).map_err(Into::into)
} }
@@ -104,6 +113,18 @@ macro_rules! define_event {
} }
)* )*
} }
/// A reporter that's tied to a specific test case.
pub struct [< $ident TestSpecificReporter >] {
$vis reporter: [< $ident Reporter >],
$vis test_specifier: std::sync::Arc<crate::common::TestSpecifier>,
}
impl [< $ident TestSpecificReporter >] {
fn report(&self, event: impl Into<$ident>) -> anyhow::Result<()> {
self.reporter.report(event)
}
}
} }
}; };
} }
@@ -125,9 +146,13 @@ define_event! {
/// An event emitted by runners when they've discovered a metadata file. /// An event emitted by runners when they've discovered a metadata file.
MetadataFileDiscovery { MetadataFileDiscovery {
/// The path of the metadata file discovered. /// The path of the metadata file discovered.
path: PathBuf, path: MetadataFilePath,
/// The content of the metadata file. /// The content of the metadata file.
metadata: Metadata metadata: Metadata
},
/// An event emitted by the runners when a test case is ignored.
TestIgnored {
}, },
/// An event emitted by the runners when the execution is completed and the aggregator can /// An event emitted by the runners when the execution is completed and the aggregator can
/// stop. /// stop.