Skip to main content

dev_flaky/
producer.rs

1//! [`Producer`] integration: wrap a [`FlakyRun`] and emit a [`Report`]
2//! every time the producer runs.
3//!
4//! [`Producer`]: dev_report::Producer
5//! [`Report`]: dev_report::Report
6
7use dev_report::{CheckResult, Producer, Report, Severity};
8
9use crate::FlakyRun;
10
11/// `Producer` adapter that drives a [`FlakyRun`] and converts the
12/// result into a `Report`.
13///
14/// Subprocess failures (missing `cargo`, compile error, IO error
15/// spawning the subprocess) map to a single failing `CheckResult`
16/// named `flaky::scan` with `Severity::Critical`. No panics.
17///
18/// # Example
19///
20/// ```no_run
21/// use dev_flaky::{FlakyProducer, FlakyRun};
22/// use dev_report::Producer;
23///
24/// let producer = FlakyProducer::new(
25///     FlakyRun::new("my-crate", "0.1.0").iterations(20),
26/// );
27/// let report = producer.produce();
28/// println!("{}", report.to_json().unwrap());
29/// ```
30pub struct FlakyProducer {
31    run: FlakyRun,
32}
33
34impl FlakyProducer {
35    /// Build a producer that drives the given [`FlakyRun`].
36    pub fn new(run: FlakyRun) -> Self {
37        Self { run }
38    }
39}
40
41impl Producer for FlakyProducer {
42    fn produce(&self) -> Report {
43        match self.run.execute() {
44            Ok(result) => result.into_report(),
45            Err(e) => {
46                let mut report = Report::new(self.run.subject(), self.run.subject_version())
47                    .with_producer("dev-flaky");
48                let check = CheckResult::fail("flaky::scan", Severity::Critical)
49                    .with_detail(e.to_string())
50                    .with_tag("flaky")
51                    .with_tag("subprocess");
52                report.push(check);
53                report.finish();
54                report
55            }
56        }
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    #[ignore = "spawns inner `cargo test` which deadlocks on the workspace target-dir lock when run from `cargo test`; run with CARGO_TARGET_DIR outside the workspace via `cargo test -- --ignored`"]
66    fn produce_returns_report_when_subprocess_fails() {
67        // The producer runs `cargo test` from CWD. The contract is
68        // "return a Report; never panic." Verified manually via the
69        // ignored execute_against_real_cargo smoke test.
70        let producer = FlakyProducer::new(FlakyRun::new("self", "0.0.0").iterations(2));
71        let report = producer.produce();
72        assert_eq!(report.subject, "self");
73        assert!(!report.checks.is_empty());
74    }
75}