From 9e2da56efa9d861a14fcc30080c36062528d50d6 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 01:58:37 +0100 Subject: [PATCH 1/9] fix doc formatting - fix formatting and add placeholders for missing docs - add an action to check that docs.rs will build correctly Signed-off-by: mimir-d --- .github/workflows/check.yaml | 12 ++ src/output/config.rs | 4 +- src/output/diagnosis.rs | 20 +-- src/output/dut.rs | 13 +- src/output/error.rs | 2 + src/output/log.rs | 2 + src/output/macros.rs | 130 +++++++++--------- src/output/measure.rs | 63 ++++----- src/output/mod.rs | 1 + src/output/run.rs | 46 +++---- src/output/step.rs | 76 ++++------- src/output/writer.rs | 4 + src/spec.rs | 257 +++++++++++++++++++++++------------ 13 files changed, 344 insertions(+), 286 deletions(-) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index ae2b71f..cd816e3 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -63,3 +63,15 @@ jobs: uses: taiki-e/install-action@cargo-hack - name: cargo hack run: cargo hack --feature-powerset --no-dev-deps check + + doc: + runs-on: ubuntu-latest + name: nightly / doc + steps: + - uses: actions/checkout@v4 + - name: Install nightly + uses: dtolnay/rust-toolchain@nightly + - name: Install cargo-docs-rs + uses: dtolnay/install@cargo-docs-rs + - name: cargo docs-rs + run: cargo docs-rs diff --git a/src/output/config.rs b/src/output/config.rs index 35c0278..984ba91 100644 --- a/src/output/config.rs +++ b/src/output/config.rs @@ -25,7 +25,6 @@ impl Config { /// # Examples /// ```rust /// # use ocptv::output::*; - /// /// let builder = Config::builder(); /// ``` pub fn builder() -> ConfigBuilder { @@ -47,7 +46,7 @@ impl ConfigBuilder { } } - // TODO: docs for all these + /// TODO: docs for all these pub fn timezone(mut self, timezone: chrono_tz::Tz) -> Self { self.timestamp_provider = Box::new(ConfiguredTzProvider { tz: timezone }); self @@ -92,6 +91,7 @@ impl ConfigBuilder { } } +/// TODO: docs pub trait TimestampProvider { fn now(&self) -> chrono::DateTime; } diff --git a/src/output/diagnosis.rs b/src/output/diagnosis.rs index f9b59ed..89c0507 100644 --- a/src/output/diagnosis.rs +++ b/src/output/diagnosis.rs @@ -9,7 +9,8 @@ use crate::spec; use tv::dut; /// This structure represents a Diagnosis message. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#diagnosis +/// +/// ref: /// /// Information about the source file and line number are not automatically added. /// Add them using the builder or the macros octptv_diagnosis_* @@ -20,7 +21,6 @@ use tv::dut; /// /// ``` /// # use ocptv::output::*; -/// /// let diagnosis = Diagnosis::new("verdict", DiagnosisType::Pass); /// ``` /// @@ -28,7 +28,6 @@ use tv::dut; /// /// ``` /// # use ocptv::output::*; -/// /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// @@ -73,7 +72,6 @@ impl Diagnosis { /// /// ``` /// # use ocptv::output::*; - /// /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// @@ -94,7 +92,6 @@ impl Diagnosis { /// /// ``` /// # use ocptv::output::*; - /// /// let diagnosis = Diagnosis::new("verdict", DiagnosisType::Pass); /// let _ = diagnosis.to_artifact(); /// ``` @@ -122,7 +119,6 @@ impl Diagnosis { /// /// ``` /// # use ocptv::output::*; -/// /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// @@ -152,7 +148,6 @@ impl DiagnosisBuilder { /// /// ``` /// # use ocptv::output::*; - /// /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass); /// ``` pub fn new(verdict: &str, diagnosis_type: spec::DiagnosisType) -> Self { @@ -169,7 +164,6 @@ impl DiagnosisBuilder { /// /// ``` /// # use ocptv::output::*; - /// /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass) /// .message("message"); /// ``` @@ -178,13 +172,12 @@ impl DiagnosisBuilder { self } - /// Add a [`HardwareInfo`] to a [`DiagnosisBuilder`]. + /// Add a [`dut::HardwareInfo`] to a [`DiagnosisBuilder`]. /// /// # Examples /// /// ``` /// # use ocptv::output::*; - /// /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// @@ -196,13 +189,12 @@ impl DiagnosisBuilder { self } - /// Add a [`Subcomponent`] to a [`DiagnosisBuilder`]. + /// Add a [`dut::Subcomponent`] to a [`DiagnosisBuilder`]. /// /// # Examples /// /// ``` /// # use ocptv::output::*; - /// /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass) /// .subcomponent(&Subcomponent::builder("name").build()); /// ``` @@ -211,13 +203,12 @@ impl DiagnosisBuilder { self } - /// Add a [`SourceLocation`] to a [`DiagnosisBuilder`]. + /// Add a source location to a [`DiagnosisBuilder`]. /// /// # Examples /// /// ``` /// # use ocptv::output::*; - /// /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass) /// .source("file.rs", 1); /// ``` @@ -235,7 +226,6 @@ impl DiagnosisBuilder { /// /// ``` /// # use ocptv::output::*; - /// /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass); /// let diagnosis = builder.build(); /// ``` diff --git a/src/output/dut.rs b/src/output/dut.rs index ed8777a..cf5607d 100644 --- a/src/output/dut.rs +++ b/src/output/dut.rs @@ -11,7 +11,7 @@ use crate::output as tv; use crate::spec; use tv::trait_ext::VecExt; -// TODO: docs +/// TODO: docs #[derive(Clone, Debug, PartialEq, Default)] pub enum Ident { #[default] @@ -83,6 +83,7 @@ impl DutInfo { } } +/// TODO: docs #[derive(Default)] pub struct DutInfoBuilder { id: String, @@ -133,6 +134,7 @@ impl DutInfoBuilder { } } +/// TODO: docs #[derive(Debug, Clone)] pub struct Subcomponent { subcomponent_type: Option, @@ -157,6 +159,7 @@ impl Subcomponent { } } +/// TODO: docs #[derive(Debug)] pub struct SubcomponentBuilder { subcomponent_type: Option, @@ -204,6 +207,7 @@ impl SubcomponentBuilder { } } +/// TODO: docs #[derive(Debug, Clone, PartialEq)] pub struct PlatformInfo { info: String, @@ -227,6 +231,7 @@ impl PlatformInfo { } } +/// TODO: docs #[derive(Debug)] pub struct PlatformInfoBuilder { info: String, @@ -244,6 +249,7 @@ impl PlatformInfoBuilder { } } +/// TODO: docs #[derive(Debug, Clone)] pub struct SoftwareInfo { id: tv::Ident, @@ -260,6 +266,7 @@ impl SoftwareInfo { } } +/// TODO: docs #[derive(Debug, Clone)] pub struct DutSoftwareInfo { id: String, @@ -287,6 +294,7 @@ impl PartialEq for DutSoftwareInfo { } } +/// TODO: docs #[derive(Debug, Default)] pub struct SoftwareInfoBuilder { id: tv::Ident, @@ -343,6 +351,7 @@ impl SoftwareInfoBuilder { } } +/// TODO: docs #[derive(Debug, Clone)] pub struct HardwareInfo { id: Ident, @@ -367,6 +376,7 @@ impl HardwareInfo { } } +/// TODO: docs #[derive(Debug, Clone)] pub struct DutHardwareInfo { id: String, @@ -400,6 +410,7 @@ impl PartialEq for DutHardwareInfo { } } +/// TODO: docs #[derive(Debug, Default)] pub struct HardwareInfoBuilder { id: tv::Ident, diff --git a/src/output/error.rs b/src/output/error.rs index ab5fa61..e7a3e72 100644 --- a/src/output/error.rs +++ b/src/output/error.rs @@ -8,6 +8,7 @@ use crate::output as tv; use crate::spec; use tv::{dut, trait_ext::VecExt, DutSoftwareInfo}; +/// TODO: docs pub struct Error { symptom: String, message: Option, @@ -30,6 +31,7 @@ impl Error { } } +/// TODO: docs #[derive(Debug, Default)] pub struct ErrorBuilder { symptom: String, diff --git a/src/output/log.rs b/src/output/log.rs index baf8635..dec9d4a 100644 --- a/src/output/log.rs +++ b/src/output/log.rs @@ -6,6 +6,7 @@ use crate::spec; +/// TODO: docs pub struct Log { severity: spec::LogSeverity, message: String, @@ -26,6 +27,7 @@ impl Log { } } +/// TODO: docs #[derive(Debug)] pub struct LogBuilder { severity: spec::LogSeverity, diff --git a/src/output/macros.rs b/src/output/macros.rs index ba4196c..d56acc0 100644 --- a/src/output/macros.rs +++ b/src/output/macros.rs @@ -9,10 +9,11 @@ //! This module contains a set of macros which are exported from the ocptv //! library. -/// Emits an artifact of type Error. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#error +/// Emit an artifact of type Error. /// -/// Equivalent to the crate::runner::TestRun::error_with_details method. +/// ref: +/// +/// Equivalent to the [`$crate::StartedTestRun::error_with_details`] method. /// /// It accepts both a symptom and a message, or just a symptom. /// Information about the source file and line number is automatically added. @@ -24,7 +25,6 @@ /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; -/// /// use ocptv::ocptv_error; /// /// let dut = DutInfo::new("my_dut"); @@ -72,37 +72,36 @@ macro_rules! ocptv_error { }; } -/// The following macros emit an artifact of type Log. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#log -/// -/// Equivalent to the crate::runner::TestRun::log_with_details method. -/// -/// They accept message as only parameter. -/// Information about the source file and line number is automatically added. -/// -/// There is one macro for each severity level: DEBUG, INFO, WARNING, ERROR, and FATAL. -/// -/// # Examples -/// -/// ## DEBUG -/// -/// ```rust -/// # tokio_test::block_on(async { -/// # use ocptv::output::*; -/// -/// use ocptv::ocptv_log_debug; -/// -/// let dut = DutInfo::new("my_dut"); -/// let run = TestRun::new("run_name", "1.0").start(dut).await?; -/// ocptv_log_debug!(run, "Log message"); -/// run.end(TestStatus::Complete, TestResult::Pass).await?; -/// -/// # Ok::<(), OcptvError>(()) -/// # }); -/// ``` - macro_rules! ocptv_log { ($name:ident, $severity:ident) => { + /// Emit an artifact of type Log. + /// + /// ref: + /// + /// Equivalent to the [`$crate::StartedTestRun::log_with_details`] method. + /// + /// They accept message as only parameter. + /// Information about the source file and line number is automatically added. + /// + /// There is one macro for each severity level: DEBUG, INFO, WARNING, ERROR, and FATAL. + /// + /// # Examples + /// + /// ## DEBUG + /// + /// ```rust + /// # tokio_test::block_on(async { + /// # use ocptv::output::*; + /// use ocptv::ocptv_log_debug; + /// + /// let dut = DutInfo::new("my_dut"); + /// let run = TestRun::new("run_name", "1.0").start(dut).await?; + /// ocptv_log_debug!(run, "Log message"); + /// run.end(TestStatus::Complete, TestResult::Pass).await?; + /// + /// # Ok::<(), OcptvError>(()) + /// # }); + /// ``` #[macro_export] macro_rules! $name { ($artifact:expr, $msg:expr) => { @@ -123,41 +122,40 @@ ocptv_log!(ocptv_log_warning, Warning); ocptv_log!(ocptv_log_error, Error); ocptv_log!(ocptv_log_fatal, Fatal); -/// The following macros emit an artifact of type Diagnosis. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#diagnosis -/// -/// Equivalent to the crate::output::StartedTestStep::diagnosis_with_details method. -/// -/// They accept verdict as only parameter. -/// Information about the source file and line number is automatically added. -/// -/// There is one macro for each DiagnosisType variant: Pass, Fail, Unknown. -/// -/// # Examples -/// -/// ## DEBUG -/// -/// ```rust -/// # tokio_test::block_on(async { -/// # use ocptv::output::*; -/// -/// use ocptv::ocptv_diagnosis_pass; -/// -/// let dut = DutInfo::new("my dut"); -/// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; -/// -/// let step = run.add_step("step_name").start().await?; -/// ocptv_diagnosis_pass!(step, "verdict"); -/// step.end(TestStatus::Complete).await?; -/// -/// run.end(TestStatus::Complete, TestResult::Pass).await?; -/// -/// # Ok::<(), OcptvError>(()) -/// # }); -/// ``` - macro_rules! ocptv_diagnosis { ($name:ident, $diagnosis_type:path) => { + /// Emit an artifact of type Diagnosis. + /// + /// ref: + /// + /// Equivalent to the [`$crate::StartedTestStep::diagnosis_with_details`] method. + /// + /// They accept verdict as only parameter. + /// Information about the source file and line number is automatically added. + /// + /// There is one macro for each DiagnosisType variant: Pass, Fail, Unknown. + /// + /// # Examples + /// + /// ## DEBUG + /// + /// ```rust + /// # tokio_test::block_on(async { + /// # use ocptv::output::*; + /// use ocptv::ocptv_diagnosis_pass; + /// + /// let dut = DutInfo::new("my dut"); + /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; + /// + /// let step = run.add_step("step_name").start().await?; + /// ocptv_diagnosis_pass!(step, "verdict"); + /// step.end(TestStatus::Complete).await?; + /// + /// run.end(TestStatus::Complete, TestResult::Pass).await?; + /// + /// # Ok::<(), OcptvError>(()) + /// # }); + /// ``` #[macro_export] macro_rules! $name { ($artifact:expr, $verdict:expr) => { diff --git a/src/output/measure.rs b/src/output/measure.rs index 4661945..6394ef6 100644 --- a/src/output/measure.rs +++ b/src/output/measure.rs @@ -21,7 +21,7 @@ use super::trait_ext::VecExt; /// The measurement series. /// A Measurement Series is a time-series list of measurements. /// -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementseriesstart +/// ref: pub struct MeasurementSeries { id: String, info: MeasurementSeriesInfo, @@ -46,14 +46,13 @@ impl MeasurementSeries { /// Starts the measurement series. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementseriesstart + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -91,7 +90,7 @@ impl MeasurementSeries { } /// Builds a scope in the [`MeasurementSeries`] object, taking care of starting and - /// ending it. View [`MeasurementSeries::start`] and [`MeasurementSeries::end`] methods. + /// ending it. View [`MeasurementSeries::start`] and [`StartedMeasurementSeries::end`] methods. /// After the scope is constructed, additional objects may be added to it. /// This is the preferred usage for the [`MeasurementSeries`], since it guarantees /// all the messages are emitted between the start and end messages, the order @@ -103,7 +102,6 @@ impl MeasurementSeries { /// # tokio_test::block_on(async { /// # use futures::FutureExt; /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -134,6 +132,7 @@ impl MeasurementSeries { } } +/// TODO: docs pub struct StartedMeasurementSeries { parent: MeasurementSeries, @@ -147,14 +146,13 @@ impl StartedMeasurementSeries { /// Ends the measurement series. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementseriesend + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -181,14 +179,13 @@ impl StartedMeasurementSeries { /// Adds a measurement element to the measurement series. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementserieselement + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -210,14 +207,13 @@ impl StartedMeasurementSeries { /// Adds a measurement element to the measurement series. /// This method accepts a full set of details for the measurement element. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementserieselement + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -254,6 +250,7 @@ impl StartedMeasurementSeries { } } +/// TODO: docs #[derive(Default)] pub struct MeasurementSeriesElemDetails { value: tv::Value, @@ -268,6 +265,7 @@ impl MeasurementSeriesElemDetails { } } +/// TODO: docs #[derive(Default)] pub struct MeasurementSeriesElemDetailsBuilder { value: tv::Value, @@ -311,6 +309,7 @@ impl MeasurementSeriesElemDetailsBuilder { } } +/// TODO: docs #[derive(Clone)] pub struct Validator { name: Option, @@ -333,6 +332,7 @@ impl Validator { } } +/// TODO: docs #[derive(Debug)] pub struct ValidatorBuilder { name: Option, @@ -378,16 +378,14 @@ impl ValidatorBuilder { } /// This structure represents a Measurement message. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurement +/// ref: /// /// # Examples /// /// ## Create a Measurement object with the `new` method /// /// ``` -/// use ocptv::output::Measurement; -/// use ocptv::output::Value; -/// +/// # use ocptv::output::*; /// let measurement = Measurement::new("name", 50.into()); /// ``` /// @@ -395,7 +393,6 @@ impl ValidatorBuilder { /// /// ``` /// # use ocptv::output::*; -/// /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// @@ -425,9 +422,7 @@ impl Measurement { /// # Examples /// /// ``` - /// use ocptv::output::Measurement; - /// use ocptv::output::Value; - /// + /// # use ocptv::output::*; /// let measurement = Measurement::new("name", 50.into()); /// ``` pub fn new(name: &str, value: tv::Value) -> Self { @@ -468,9 +463,7 @@ impl Measurement { /// # Examples /// /// ``` - /// use ocptv::output::Measurement; - /// use ocptv::output::Value; - /// + /// # use ocptv::output::*; /// let measurement = Measurement::new("name", 50.into()); /// let _ = measurement.to_artifact(); /// ``` @@ -502,7 +495,6 @@ impl Measurement { /// /// ``` /// # use ocptv::output::*; -/// /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// @@ -532,9 +524,7 @@ impl MeasurementBuilder { /// # Examples /// /// ``` - /// use ocptv::output::MeasurementBuilder; - /// use ocptv::output::Value; - /// + /// # use ocptv::output::*; /// let builder = MeasurementBuilder::new("name", 50.into()); /// ``` pub fn new(name: &str, value: tv::Value) -> Self { @@ -555,7 +545,6 @@ impl MeasurementBuilder { /// /// ``` /// # use ocptv::output::*; - /// /// let builder = MeasurementBuilder::new("name", 50.into()) /// .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()); /// ``` @@ -570,13 +559,12 @@ impl MeasurementBuilder { self } - /// Add a [`HardwareInfo`] to a [`MeasurementBuilder`]. + /// Add a [`tv::HardwareInfo`] to a [`MeasurementBuilder`]. /// /// # Examples /// /// ``` /// # use ocptv::output::*; - /// /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// @@ -588,15 +576,12 @@ impl MeasurementBuilder { self } - /// Add a [`Subcomponent`] to a [`MeasurementBuilder`]. + /// Add a [`tv::Subcomponent`] to a [`MeasurementBuilder`]. /// /// # Examples /// /// ``` - /// use ocptv::output::MeasurementBuilder; - /// use ocptv::output::Subcomponent; - /// use ocptv::output::Value; - /// + /// # use ocptv::output::*; /// let builder = MeasurementBuilder::new("name", 50.into()) /// .subcomponent(&Subcomponent::builder("name").build()); /// ``` @@ -610,9 +595,7 @@ impl MeasurementBuilder { /// # Examples /// /// ``` - /// use ocptv::output::MeasurementBuilder; - /// use ocptv::output::Value; - /// + /// # use ocptv::output::*; /// let builder = /// MeasurementBuilder::new("name", 50.into()).add_metadata("key", "value".into()); /// ``` @@ -635,9 +618,7 @@ impl MeasurementBuilder { /// # Examples /// /// ``` - /// use ocptv::output::MeasurementBuilder; - /// use ocptv::output::Value; - /// + /// # use ocptv::output::*; /// let builder = MeasurementBuilder::new("name", 50000.into()).unit("RPM"); /// ``` pub fn unit(mut self, unit: &str) -> MeasurementBuilder { @@ -669,6 +650,7 @@ impl MeasurementBuilder { } } +/// TODO: docs pub struct MeasurementSeriesInfo { // note: this object is crate public and we need access to this field // when making a new series in `StartedTestStep.add_measurement_series*` @@ -694,6 +676,7 @@ impl MeasurementSeriesInfo { } } +/// TODO: docs #[derive(Default)] pub struct MeasurementSeriesInfoBuilder { id: tv::Ident, diff --git a/src/output/mod.rs b/src/output/mod.rs index a785466..25970f2 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -43,6 +43,7 @@ pub use writer::{BufferWriter, FileWriter, StdoutWriter, Writer}; // re-export this as a public type we present pub use serde_json::Value; +/// TODO: docs #[derive(Debug, thiserror::Error)] #[non_exhaustive] pub enum OcptvError { diff --git a/src/output/run.rs b/src/output/run.rs index e91ed4a..2cc4b49 100644 --- a/src/output/run.rs +++ b/src/output/run.rs @@ -49,7 +49,6 @@ impl TestRun { /// /// ```rust /// # use ocptv::output::*; - /// /// let run = TestRun::new("diagnostic_name", "1.0"); /// ``` pub fn new(name: &str, version: &str) -> TestRun { @@ -62,7 +61,6 @@ impl TestRun { /// /// ```rust /// # use ocptv::output::*; - /// /// let builder = TestRun::builder("run_name", "1.0"); /// ``` pub fn builder(name: &str, version: &str) -> TestRunBuilder { @@ -71,15 +69,13 @@ impl TestRun { /// Starts the test run. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#schemaversion - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#testrunstart + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let run = TestRun::new("diagnostic_name", "1.0"); /// let dut = DutInfo::builder("my_dut").build(); /// run.start(dut).await?; @@ -117,7 +113,6 @@ impl TestRun { /// # tokio_test::block_on(async { /// # use futures::FutureExt; /// # use ocptv::output::*; - /// /// let run = TestRun::new("diagnostic_name", "1.0"); /// let dut = DutInfo::builder("my_dut").build(); /// run.scope(dut, |r| { @@ -217,7 +212,6 @@ impl TestRunBuilder { /// /// ```rust /// # use ocptv::output::*; - /// /// let run = TestRunBuilder::new("run_name", "1.0") /// .add_parameter("param1", "value1".into()) /// .build(); @@ -227,14 +221,13 @@ impl TestRunBuilder { self } - /// Adds the command line used to run the test session to the future + /// Adds the command line used to run the test session to the future /// [`TestRun`] object. /// /// # Examples /// /// ```rust /// # use ocptv::output::*; - /// /// let run = TestRunBuilder::new("run_name", "1.0") /// .command_line("my_diag --arg value") /// .build(); @@ -250,7 +243,6 @@ impl TestRunBuilder { /// /// ```rust /// # use ocptv::output::*; - /// /// let run = TestRunBuilder::new("run_name", "1.0") /// .config(Config::builder().build()) /// .build(); @@ -302,7 +294,7 @@ impl TestRunBuilder { /// A test run that was started. /// -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#testrunstart +/// ref: pub struct StartedTestRun { run: TestRun, @@ -319,14 +311,13 @@ impl StartedTestRun { /// Ends the test run. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#testrunend + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::builder("my_dut").build(); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// run.end(TestStatus::Complete, TestResult::Pass).await?; @@ -348,17 +339,16 @@ impl StartedTestRun { } /// Emits a Log message. - /// This method accepts a [`models::LogSeverity`] to define the severity - /// and a [`std::string::String`] for the message. + /// This method accepts a [`tv::LogSeverity`] to define the severity + /// and a [`String`] for the message. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#log + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::builder("my_dut").build(); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// run.add_log( @@ -389,16 +379,15 @@ impl StartedTestRun { } /// Emits a Log message. - /// This method accepts a [`objects::Log`] object. + /// This method accepts a [`tv::Log`] object. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#log + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::builder("my_dut").build(); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// run.add_log_with_details( @@ -425,16 +414,15 @@ impl StartedTestRun { } /// Emits a Error message. - /// This method accepts a [`std::string::String`] to define the symptom. + /// This method accepts a [`String`] to define the symptom. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#error + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::builder("my_dut").build(); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// run.add_error("symptom").await?; @@ -451,17 +439,16 @@ impl StartedTestRun { } /// Emits a Error message. - /// This method accepts a [`std::string::String`] to define the symptom and - /// another [`std::string::String`] as error message. + /// This method accepts a [`String`] to define the symptom and + /// another [`String`] as error message. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#error + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::builder("my_dut").build(); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// run.add_error_with_msg("symptom", "error messasge").await?; @@ -478,16 +465,15 @@ impl StartedTestRun { } /// Emits a Error message. - /// This method accepts an [`error::Error`] object. + /// This method accepts an [`tv::Error`] object. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#error + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let mut dut = DutInfo::new("my_dut"); /// let sw_info = dut.add_software_info(SoftwareInfo::builder("name").build()); /// let run = TestRun::builder("diagnostic_name", "1.0").build().start(dut).await?; diff --git a/src/output/step.rs b/src/output/step.rs index 9669125..301f4fc 100644 --- a/src/output/step.rs +++ b/src/output/step.rs @@ -16,9 +16,9 @@ use crate::spec::{self, TestStepArtifactImpl}; use tv::OcptvError; use tv::{config, diagnosis, emitter, error, log, measure, Ident}; -/// A single test step in the scope of a [`TestRun`]. +/// A single test step in the scope of a [`tv::TestRun`]. /// -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#test-step-artifacts +/// ref: pub struct TestStep { name: String, @@ -40,14 +40,13 @@ impl TestStep { /// Starts the test step. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#teststepstart + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -69,7 +68,7 @@ impl TestStep { } /// Builds a scope in the [`TestStep`] object, taking care of starting and - /// ending it. View [`TestStep::start`] and [`TestStep::end`] methods. + /// ending it. View [`TestStep::start`] and [`StartedTestStep::end`] methods. /// After the scope is constructed, additional objects may be added to it. /// This is the preferred usage for the [`TestStep`], since it guarantees /// all the messages are emitted between the start and end messages, the order @@ -81,7 +80,6 @@ impl TestStep { /// # tokio_test::block_on(async { /// # use futures::FutureExt; /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// @@ -112,6 +110,7 @@ impl TestStep { } } +/// TODO: docs pub struct StartedTestStep { step: TestStep, measurement_seqno: Arc, @@ -120,14 +119,13 @@ pub struct StartedTestStep { impl StartedTestStep { /// Ends the test step. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#teststepend + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// @@ -145,17 +143,16 @@ impl StartedTestStep { } /// Emits Log message. - /// This method accepts a [`models::LogSeverity`] to define the severity - /// and a [`std::string::String`] for the message. + /// This method accepts a [`tv::LogSeverity`] to define the severity + /// and a [`String`] for the message. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#log + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// @@ -174,7 +171,6 @@ impl StartedTestStep { /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// use ocptv::ocptv_log_info; /// /// let dut = DutInfo::new("my_dut"); @@ -203,16 +199,15 @@ impl StartedTestStep { } /// Emits Log message. - /// This method accepts a [`objects::Log`] object. + /// This method accepts a [`tv::Log`] object. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#log + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// @@ -238,16 +233,15 @@ impl StartedTestStep { } /// Emits an Error symptom. - /// This method accepts a [`std::string::String`] to define the symptom. + /// This method accepts a [`String`] to define the symptom. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#error + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// @@ -264,7 +258,6 @@ impl StartedTestStep { /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// use ocptv::ocptv_error; /// /// let dut = DutInfo::new("my_dut"); @@ -289,17 +282,16 @@ impl StartedTestStep { } /// Emits an Error message. - /// This method accepts a [`std::string::String`] to define the symptom and - /// another [`std::string::String`] as error message. + /// This method accepts a [`String`] to define the symptom and + /// another [`String`] as error message. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#error + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// @@ -316,7 +308,6 @@ impl StartedTestStep { /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// use ocptv::ocptv_error; /// /// let dut = DutInfo::new("my_dut"); @@ -341,16 +332,15 @@ impl StartedTestStep { } /// Emits a Error message. - /// This method accepts a [`objects::Error`] object. + /// This method accepts a [`tv::Error`] object. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#error + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let mut dut = DutInfo::new("my_dut"); /// let sw_info = dut.add_software_info(SoftwareInfo::builder("name").build()); /// let run = TestRun::builder("diagnostic_name", "1.0").build().start(dut).await?; @@ -379,14 +369,13 @@ impl StartedTestStep { /// Emits an extension message; /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#extension + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -415,14 +404,13 @@ impl StartedTestStep { /// Emits a Measurement message. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurement + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// @@ -451,16 +439,15 @@ impl StartedTestStep { } /// Emits a Measurement message. - /// This method accepts a [`objects::Error`] object. + /// This method accepts a [`tv::Error`] object. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurement + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let mut dut = DutInfo::new("my_dut"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("fan").build()); /// let run = TestRun::builder("diagnostic_name", "1.0").build().start(dut).await?; @@ -494,17 +481,15 @@ impl StartedTestStep { } /// Create a Measurement Series (a time-series list of measurements). - /// This method accepts a [`std::string::String`] as series ID and - /// a [`std::string::String`] as series name. + /// This method accepts a [`String`] as series ID and a [`String`] as series name. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementseriesstart + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -518,16 +503,15 @@ impl StartedTestStep { } /// Create a Measurement Series (a time-series list of measurements). - /// This method accepts a [`objects::MeasurementSeriesStart`] object. + /// This method accepts a [`tv::MeasurementSeriesInfo`] object. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementseriesstart + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my_dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; @@ -558,14 +542,13 @@ impl StartedTestStep { /// Emits a Diagnosis message. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#diagnosis + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let dut = DutInfo::new("my dut"); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// @@ -592,16 +575,15 @@ impl StartedTestStep { } /// Emits a Diagnosis message. - /// This method accepts a [`objects::Error`] object. + /// This method accepts a [`tv::Error`] object. /// - /// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#diagnosis + /// ref: /// /// # Examples /// /// ```rust /// # tokio_test::block_on(async { /// # use ocptv::output::*; - /// /// let mut dut = DutInfo::new("my_dut"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("fan").build()); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; diff --git a/src/output/writer.rs b/src/output/writer.rs index 8c2cca1..0905075 100644 --- a/src/output/writer.rs +++ b/src/output/writer.rs @@ -14,6 +14,7 @@ use tokio::fs; use tokio::io::AsyncWriteExt; use tokio::sync::Mutex; +/// TODO: docs #[async_trait] pub trait Writer { async fn write(&self, s: &str) -> Result<(), io::Error>; @@ -28,6 +29,7 @@ pub enum WriterType { Custom(Box), } +/// TODO: docs pub struct FileWriter { file: Arc>, } @@ -53,6 +55,7 @@ impl FileWriter { } } +/// TODO: docs #[derive(Debug)] pub struct BufferWriter { buffer: Arc>>, @@ -69,6 +72,7 @@ impl BufferWriter { } } +/// TODO: docs #[derive(Debug, Clone)] pub struct StdoutWriter {} diff --git a/src/spec.rs b/src/spec.rs index a4bc678..8424fe9 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -2,7 +2,7 @@ // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. +// use std::collections::BTreeMap; @@ -13,6 +13,7 @@ use serde_with::serde_as; use crate::output as tv; +/// TODO: docs pub const SPEC_VERSION: (i8, i8) = (2, 0); mod rfc3339_format { @@ -58,6 +59,7 @@ mod serialize_ids { } } +/// TODO: docs #[derive(Debug, Serialize, Clone, PartialEq)] #[non_exhaustive] pub enum ValidatorType { @@ -83,6 +85,7 @@ pub enum ValidatorType { NotInSet, } +/// TODO: docs #[derive(Debug, Serialize, Clone, PartialEq)] #[non_exhaustive] pub enum SubcomponentType { @@ -101,9 +104,12 @@ pub enum SubcomponentType { } /// Outcome of a diagnosis operation. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#diagnosistype -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/diagnosis.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/diagnosis/$defs/type +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, PartialEq, Clone, Default)] pub enum DiagnosisType { #[serde(rename = "PASS")] @@ -116,9 +122,12 @@ pub enum DiagnosisType { } /// Represents the final execution status of a test. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#teststatus -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_status.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testStatus +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "testStatus")] #[non_exhaustive] @@ -132,9 +141,12 @@ pub enum TestStatus { } /// Represents the final outcome of a test execution. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#testresult -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_run_end.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testRunEnd/$defs/testResult +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "testResult")] #[non_exhaustive] @@ -148,9 +160,12 @@ pub enum TestResult { } /// Known log severity variants. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#severity -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/log.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/log/$defs/severity +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[non_exhaustive] pub enum LogSeverity { @@ -167,9 +182,12 @@ pub enum LogSeverity { } /// Type specification for a software component of the DUT. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#softwaretype -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/dut_info.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/dutInfo/$defs/softwareInfo/properties/softwareType +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "softwareType")] #[non_exhaustive] @@ -212,9 +230,12 @@ pub enum RootImpl { /// Low-level model for the `schemaVersion` spec object. /// Specifies the version that should be used to interpret following json outputs. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#schemaversion -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/root.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/output/$defs/schemaVersion +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "schemaVersion")] pub struct SchemaVersion { @@ -236,9 +257,12 @@ impl Default for SchemaVersion { /// Low-level model for the `testRunArtifact` spec object. /// Container for the run level artifacts. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#test-run-artifacts -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_run_artifact.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testRunArtifact +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, PartialEq, Clone)] pub struct TestRunArtifact { #[serde(flatten)] @@ -262,9 +286,12 @@ pub enum TestRunArtifactImpl { /// Low-level model for the `testRunStart` spec object. /// Start marker for the beginning of a diagnostic test. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#testrunstart -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_run_start.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testRunStart +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "testRunStart")] pub struct TestRunStart { @@ -290,9 +317,12 @@ pub struct TestRunStart { /// Low-level model for the `dutInfo` spec object. /// Contains all relevant information describing the DUT. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#dutinfo -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/dut_info.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/dutInfo +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Default, Clone, PartialEq)] #[serde(rename = "dutInfo")] pub struct DutInfo { @@ -322,9 +352,12 @@ pub struct DutInfo { /// Low-level model for the `platformInfo` spec object. /// Describe platform specific attributes of the DUT. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#platforminfo -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/dut_info.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/dutInfo/$defs/platformInfo +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Default, Clone, PartialEq)] #[serde(rename = "platformInfo")] pub struct PlatformInfo { @@ -334,9 +367,12 @@ pub struct PlatformInfo { /// Low-level model for the `softwareInfo` spec object. /// Represents information of a discovered or exercised software component of the DUT. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#softwareinfo -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/dut_info.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/dutInfo/$defs/softwareInfo +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "softwareInfo")] pub struct SoftwareInfo { @@ -371,9 +407,12 @@ impl serialize_ids::IdGetter for SoftwareInfo { /// Low-level model for the `hardwareInfo` spec object. /// Represents information of an enumerated or exercised hardware component of the DUT. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#hardwareinfo -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/dut_info.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/dutInfo/$defs/hardwareInfo +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Default, Clone, PartialEq)] #[serde(rename = "hardwareInfo")] pub struct HardwareInfo { @@ -432,9 +471,12 @@ impl serialize_ids::IdGetter for HardwareInfo { /// Low-level model for the `testRunEnd` spec object. /// End marker signaling the finality of a diagnostic test. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#testrunend -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_run_end.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testRunEnd +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "testRunEnd")] pub struct TestRunEnd { @@ -448,9 +490,12 @@ pub struct TestRunEnd { /// Low-level model for the `error` spec object. /// Represents an error encountered by the diagnostic software. It may refer to a DUT /// component or the diagnostic itself. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#error -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/error.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/error +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[serde_as] #[derive(Debug, Serialize, Default, Clone, PartialEq)] #[serde(rename = "error")] @@ -474,9 +519,12 @@ pub struct Error { /// Low-level model for `log` spec object. /// Is currently relevant for test run and test step artifact types. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#log -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/log.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/log +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "log")] pub struct Log { @@ -493,9 +541,12 @@ pub struct Log { /// Provides information about which file/line of the source code in /// the diagnostic package generated the output. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#sourcelocation -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/source_location.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/sourceLocation +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, Default, PartialEq)] #[serde(rename = "sourceLocation")] pub struct SourceLocation { @@ -508,9 +559,12 @@ pub struct SourceLocation { /// Low-level model for the `testStepArtifact` spec object. /// Container for the step level artifacts. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#test-step-artifacts -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_step_artifact.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testStepArtifact +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, PartialEq, Clone)] pub struct TestStepArtifact { #[serde(rename = "testStepId")] @@ -559,9 +613,12 @@ pub enum TestStepArtifactImpl { /// Low-level model for the `testStepStart` spec object. /// Start marker for a test step inside a diagnosis run. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#teststepstart -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_step_start.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testStepStart +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, PartialEq, Clone)] #[serde(rename = "testStepStart")] pub struct TestStepStart { @@ -571,9 +628,12 @@ pub struct TestStepStart { /// Low-level model for the `testStepEnd` spec object. /// End marker for a test step inside a diagnosis run. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#teststepend -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_step_end.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testStepEnd +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, PartialEq, Clone)] #[serde(rename = "testStepEnd")] pub struct TestStepEnd { @@ -583,9 +643,12 @@ pub struct TestStepEnd { /// Low-level model for the `measurement` spec object. /// Represents an individual measurement taken by the diagnostic regarding the DUT. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurement -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/measurement.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/measurement +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[serde_as] #[derive(Debug, Serialize, PartialEq, Clone)] #[serde(rename = "measurement")] @@ -620,9 +683,12 @@ pub struct Measurement { /// Low-level model for the `validator` spec object. /// Contains the validation logic that the diagnostic applied for a specific measurement. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#validator -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/validator.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/validator +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "validator")] pub struct Validator { @@ -643,9 +709,12 @@ pub struct Validator { /// Low-level model for the `subcomponent` spec object. /// Represents a physical subcomponent of a DUT hardware element. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#subcomponent -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/subcomponent.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/subcomponent +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Clone, PartialEq)] #[serde(rename = "subcomponent")] pub struct Subcomponent { @@ -671,9 +740,12 @@ pub struct Subcomponent { /// Low-level model for the `measurementSeriesStart` spec object. /// Start marker for a time based series of measurements. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementseriesstart -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/measurement_series_start.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/measurementSeriesStart +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[serde_as] #[derive(Debug, Serialize, PartialEq, Clone)] #[serde(rename = "measurementSeriesStart")] @@ -708,9 +780,12 @@ pub struct MeasurementSeriesStart { /// Low-level model for the `measurementSeriesEnd` spec object. /// End marker for a time based series of measurements. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementseriesend -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/measurement_series_end.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/measurementSeriesEnd +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, PartialEq, Clone)] #[serde(rename = "measurementSeriesEnd")] pub struct MeasurementSeriesEnd { @@ -723,9 +798,12 @@ pub struct MeasurementSeriesEnd { /// Low-level model for the `measurementSeriesElement` spec object. /// Equivalent to the `Measurement` model but inside a time based series. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#measurementserieselement -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/measurement_series_element.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/measurementSeriesElement +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] #[serde(rename = "measurementSeriesElement")] pub struct MeasurementSeriesElement { @@ -748,9 +826,12 @@ pub struct MeasurementSeriesElement { /// Low-level model for the `diagnosis` spec object. /// Contains the verdict given by the diagnostic regarding the DUT that was inspected. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#diagnosis -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/diagnosis.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/diagnosis +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[serde_as] #[derive(Debug, Serialize, PartialEq, Clone)] #[serde(rename = "diagnosis")] @@ -781,9 +862,12 @@ pub struct Diagnosis { /// Low-level model for the `file` spec object. /// Represents a file artifact that was generated by running the diagnostic. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#file -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/file.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/file +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, PartialEq, Clone)] #[serde(rename = "file")] pub struct File { @@ -811,9 +895,12 @@ pub struct File { /// Low-level model for the `extension` spec object. /// Left as an implementation detail, the `Extension` just has a name and arbitrary data. -/// ref: https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec#extension -/// schema url: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/output/test_step_artifact.json -/// schema ref: https://github.com/opencomputeproject/ocp-diag-core/testStepArtifact/$defs/extension +/// +/// ref: +/// +/// schema url: +/// +/// schema ref: #[derive(Debug, Serialize, PartialEq, Clone)] #[serde(rename = "extension")] pub struct Extension { From 5db1db4603b61a56c2b44e12977bebc9293fea5d Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 12:24:49 +0100 Subject: [PATCH 2/9] use full path in all macros - for consistency with diagnosis macros Signed-off-by: mimir-d --- src/output/macros.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/output/macros.rs b/src/output/macros.rs index d56acc0..d3d6dce 100644 --- a/src/output/macros.rs +++ b/src/output/macros.rs @@ -73,7 +73,7 @@ macro_rules! ocptv_error { } macro_rules! ocptv_log { - ($name:ident, $severity:ident) => { + ($name:ident, $severity:path) => { /// Emit an artifact of type Log. /// /// ref: @@ -107,7 +107,7 @@ macro_rules! ocptv_log { ($artifact:expr, $msg:expr) => { $artifact.add_log_with_details( &$crate::output::Log::builder($msg) - .severity($crate::output::LogSeverity::$severity) + .severity($severity) .source(file!(), line!() as i32) .build(), ) @@ -116,11 +116,11 @@ macro_rules! ocptv_log { }; } -ocptv_log!(ocptv_log_debug, Debug); -ocptv_log!(ocptv_log_info, Info); -ocptv_log!(ocptv_log_warning, Warning); -ocptv_log!(ocptv_log_error, Error); -ocptv_log!(ocptv_log_fatal, Fatal); +ocptv_log!(ocptv_log_debug, ocptv::output::LogSeverity::Debug); +ocptv_log!(ocptv_log_info, ocptv::output::LogSeverity::Info); +ocptv_log!(ocptv_log_warning, ocptv::output::LogSeverity::Warning); +ocptv_log!(ocptv_log_error, ocptv::output::LogSeverity::Error); +ocptv_log!(ocptv_log_fatal, ocptv::output::LogSeverity::Fatal); macro_rules! ocptv_diagnosis { ($name:ident, $diagnosis_type:path) => { From bcf73ca2010a2cbe30beee12a37fc8c92e73d5c3 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 12:48:20 +0100 Subject: [PATCH 3/9] reduce the code size for metadata inputs - at some cost for semantics, overload the meaning of an empty map to be Option::None. This however removes a bunch of boilerplate code all over the place - arguably, this can be fully avoided by not using Option in spec.rs, but in that case, it's clearer to match the Option with the non-mandatory in the spec in an 1:1 fashion Signed-off-by: mimir-d --- src/output/dut.rs | 19 +++------ src/output/measure.rs | 87 ++++++++++++----------------------------- src/output/run.rs | 25 +++++------- src/output/trait_ext.rs | 12 ++++++ 4 files changed, 50 insertions(+), 93 deletions(-) diff --git a/src/output/dut.rs b/src/output/dut.rs index cf5607d..a5a6c3e 100644 --- a/src/output/dut.rs +++ b/src/output/dut.rs @@ -4,12 +4,11 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -use maplit::{btreemap, convert_args}; use std::collections::BTreeMap; use crate::output as tv; +use crate::output::trait_ext::{MapExt, VecExt}; use crate::spec; -use tv::trait_ext::VecExt; /// TODO: docs #[derive(Clone, Debug, PartialEq, Default)] @@ -29,7 +28,7 @@ pub struct DutInfo { software_infos: Vec, hardware_infos: Vec, - metadata: Option>, + metadata: BTreeMap, } impl DutInfo { @@ -78,7 +77,7 @@ impl DutInfo { platform_infos: self.platform_infos.map_option(PlatformInfo::to_spec), software_infos: self.software_infos.map_option(DutSoftwareInfo::to_spec), hardware_infos: self.hardware_infos.map_option(DutHardwareInfo::to_spec), - metadata: self.metadata.clone(), + metadata: self.metadata.option(), } } } @@ -89,7 +88,7 @@ pub struct DutInfoBuilder { id: String, name: Option, platform_infos: Vec, - metadata: Option>, + metadata: BTreeMap, } impl DutInfoBuilder { @@ -111,15 +110,7 @@ impl DutInfoBuilder { } pub fn add_metadata(mut self, key: &str, value: tv::Value) -> DutInfoBuilder { - self.metadata = match self.metadata { - Some(mut metadata) => { - metadata.insert(key.to_string(), value.clone()); - Some(metadata) - } - None => Some(convert_args!(btreemap!( - key => value - ))), - }; + self.metadata.insert(key.to_string(), value.clone()); self } diff --git a/src/output/measure.rs b/src/output/measure.rs index 6394ef6..06581e3 100644 --- a/src/output/measure.rs +++ b/src/output/measure.rs @@ -10,14 +10,12 @@ use std::sync::Arc; #[cfg(feature = "boxed-scopes")] use futures::future::BoxFuture; -use maplit::{btreemap, convert_args}; use crate::output as tv; +use crate::output::trait_ext::{MapExt, VecExt}; use crate::spec; use tv::{dut, step, Ident}; -use super::trait_ext::VecExt; - /// The measurement series. /// A Measurement Series is a time-series list of measurements. /// @@ -76,7 +74,7 @@ impl MeasurementSeries { .as_ref() .map(dut::DutHardwareInfo::to_spec), subcomponent: info.subcomponent.as_ref().map(dut::Subcomponent::to_spec), - metadata: info.metadata.clone(), + metadata: info.metadata.option(), }; self.emitter @@ -236,7 +234,7 @@ impl StartedMeasurementSeries { .timestamp .unwrap_or(self.parent.emitter.timestamp_provider().now()), series_id: self.parent.id.clone(), - metadata: details.metadata, + metadata: details.metadata.option(), }; self.parent @@ -256,7 +254,7 @@ pub struct MeasurementSeriesElemDetails { value: tv::Value, timestamp: Option>, - metadata: Option>, + metadata: BTreeMap, } impl MeasurementSeriesElemDetails { @@ -271,7 +269,7 @@ pub struct MeasurementSeriesElemDetailsBuilder { value: tv::Value, timestamp: Option>, - metadata: Option>, + metadata: BTreeMap, } impl MeasurementSeriesElemDetailsBuilder { @@ -288,15 +286,7 @@ impl MeasurementSeriesElemDetailsBuilder { } pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { - self.metadata = match self.metadata { - Some(mut metadata) => { - metadata.insert(key.to_string(), value); - Some(metadata) - } - None => Some(convert_args!(btreemap!( - key => value, - ))), - }; + self.metadata.insert(key.to_string(), value); self } @@ -315,7 +305,7 @@ pub struct Validator { name: Option, validator_type: spec::ValidatorType, value: tv::Value, - metadata: Option>, + metadata: BTreeMap, } impl Validator { @@ -327,7 +317,7 @@ impl Validator { name: self.name.clone(), validator_type: self.validator_type.clone(), value: self.value.clone(), - metadata: self.metadata.clone(), + metadata: self.metadata.option(), } } } @@ -338,7 +328,8 @@ pub struct ValidatorBuilder { name: Option, validator_type: spec::ValidatorType, value: tv::Value, - metadata: Option>, + + metadata: BTreeMap, } impl ValidatorBuilder { @@ -347,7 +338,7 @@ impl ValidatorBuilder { validator_type, value: value.clone(), name: None, - metadata: None, + metadata: BTreeMap::new(), } } pub fn name(mut self, value: &str) -> ValidatorBuilder { @@ -355,15 +346,7 @@ impl ValidatorBuilder { self } pub fn add_metadata(mut self, key: &str, value: tv::Value) -> ValidatorBuilder { - self.metadata = match self.metadata { - Some(mut metadata) => { - metadata.insert(key.to_string(), value.clone()); - Some(metadata) - } - None => Some(convert_args!(btreemap!( - key => value, - ))), - }; + self.metadata.insert(key.to_string(), value.clone()); self } @@ -403,6 +386,7 @@ impl ValidatorBuilder { /// .subcomponent(&Subcomponent::builder("name").build()) /// .build(); /// ``` +#[derive(Default)] pub struct Measurement { name: String, @@ -413,7 +397,7 @@ pub struct Measurement { hardware_info: Option, subcomponent: Option, - metadata: Option>, + metadata: BTreeMap, } impl Measurement { @@ -429,11 +413,7 @@ impl Measurement { Measurement { name: name.to_string(), value: value.clone(), - unit: None, - validators: None, - hardware_info: None, - subcomponent: None, - metadata: None, + ..Default::default() } } @@ -484,7 +464,7 @@ impl Measurement { .subcomponent .as_ref() .map(|subcomponent| subcomponent.to_spec()), - metadata: self.metadata.clone(), + metadata: self.metadata.option(), } } } @@ -505,6 +485,7 @@ impl Measurement { /// .subcomponent(&Subcomponent::builder("name").build()); /// let measurement = builder.build(); /// ``` +#[derive(Default)] pub struct MeasurementBuilder { name: String, @@ -515,7 +496,7 @@ pub struct MeasurementBuilder { hardware_info: Option, subcomponent: Option, - metadata: Option>, + metadata: BTreeMap, } impl MeasurementBuilder { @@ -531,11 +512,7 @@ impl MeasurementBuilder { MeasurementBuilder { name: name.to_string(), value: value.clone(), - unit: None, - validators: None, - hardware_info: None, - subcomponent: None, - metadata: None, + ..Default::default() } } @@ -600,16 +577,7 @@ impl MeasurementBuilder { /// MeasurementBuilder::new("name", 50.into()).add_metadata("key", "value".into()); /// ``` pub fn add_metadata(mut self, key: &str, value: tv::Value) -> MeasurementBuilder { - match self.metadata { - Some(ref mut metadata) => { - metadata.insert(key.to_string(), value.clone()); - } - None => { - self.metadata = Some(convert_args!(btreemap!( - key => value, - ))); - } - }; + self.metadata.insert(key.to_string(), value.clone()); self } @@ -663,7 +631,7 @@ pub struct MeasurementSeriesInfo { hardware_info: Option, subcomponent: Option, - metadata: Option>, + metadata: BTreeMap, } impl MeasurementSeriesInfo { @@ -688,7 +656,7 @@ pub struct MeasurementSeriesInfoBuilder { hardware_info: Option, subcomponent: Option, - metadata: Option>, + metadata: BTreeMap, } impl MeasurementSeriesInfoBuilder { @@ -732,15 +700,7 @@ impl MeasurementSeriesInfoBuilder { } pub fn add_metadata(mut self, key: &str, value: tv::Value) -> MeasurementSeriesInfoBuilder { - self.metadata = match self.metadata { - Some(mut metadata) => { - metadata.insert(key.to_string(), value.clone()); - Some(metadata) - } - None => Some(convert_args!(btreemap!( - key => value - ))), - }; + self.metadata.insert(key.to_string(), value.clone()); self } @@ -762,6 +722,7 @@ mod tests { use super::*; use crate::output as tv; use crate::spec; + use maplit::{btreemap, convert_args}; use tv::dut::*; use tv::ValidatorType; diff --git a/src/output/run.rs b/src/output/run.rs index 2cc4b49..6d184b1 100644 --- a/src/output/run.rs +++ b/src/output/run.rs @@ -13,13 +13,13 @@ use std::sync::{ Arc, }; -use maplit::{btreemap, convert_args}; - use crate::output as tv; use crate::spec; use tv::step::TestStep; use tv::{config, dut, emitter, error, log}; +use super::trait_ext::MapExt; + /// The outcome of a TestRun. /// It's returned when the scope method of the [`TestRun`] object is used. pub struct TestRunOutcome { @@ -37,7 +37,7 @@ pub struct TestRun { version: String, parameters: BTreeMap, command_line: String, - metadata: Option>, + metadata: BTreeMap, emitter: Arc, } @@ -90,7 +90,7 @@ impl TestRun { version: self.version.clone(), command_line: self.command_line.clone(), parameters: self.parameters.clone(), - metadata: self.metadata.clone(), + metadata: self.metadata.option(), dut_info: dut.to_spec(), }), }); @@ -185,13 +185,15 @@ impl TestRun { } /// Builder for the [`TestRun`] object. +#[derive(Default)] pub struct TestRunBuilder { name: String, version: String, parameters: BTreeMap, command_line: String, - metadata: Option>, + config: Option, + metadata: BTreeMap, } impl TestRunBuilder { @@ -201,8 +203,7 @@ impl TestRunBuilder { version: version.to_string(), parameters: BTreeMap::new(), command_line: env::args().collect::>()[1..].join(" "), - metadata: None, - config: None, + ..Default::default() } } @@ -264,15 +265,7 @@ impl TestRunBuilder { /// .build(); /// ``` pub fn add_metadata(mut self, key: &str, value: tv::Value) -> TestRunBuilder { - self.metadata = match self.metadata { - Some(mut metadata) => { - metadata.insert(key.to_string(), value.clone()); - Some(metadata) - } - None => Some(convert_args!(btreemap!( - key => value, - ))), - }; + self.metadata.insert(key.to_string(), value.clone()); self } diff --git a/src/output/trait_ext.rs b/src/output/trait_ext.rs index b3aae93..ce4e69e 100644 --- a/src/output/trait_ext.rs +++ b/src/output/trait_ext.rs @@ -4,6 +4,8 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +use std::collections::BTreeMap; + pub trait VecExt { fn map_option(&self, func: F) -> Option> where @@ -18,3 +20,13 @@ impl VecExt for Vec { (!self.is_empty()).then_some(self.iter().map(func).collect()) } } + +pub trait MapExt { + fn option(&self) -> Option>; +} + +impl MapExt for BTreeMap { + fn option(&self) -> Option> { + (!self.is_empty()).then_some(self.clone()) + } +} From 28099de54c78644e45431b39c595f451907d3d98 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 12:51:35 +0100 Subject: [PATCH 4/9] add a script to run the CI checks - this should make it easier to discover breakages before github gets to run the same commands; this script is relatively stable, but should be updated if the gh actions are changed Signed-off-by: mimir-d --- scripts/check.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 scripts/check.sh diff --git a/scripts/check.sh b/scripts/check.sh new file mode 100755 index 0000000..c598031 --- /dev/null +++ b/scripts/check.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -eo pipefail + +# (c) Meta Platforms, Inc. and affiliates. +# +# Use of this source code is governed by an MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT. + +echo "Running CI checks..." + +cargo fmt --check + +# ensure the tests run ok with all features disabled +cargo test + +cargo test --locked --all-features + +# docs-rs supersedes cargo doc +cargo +nightly docs-rs + +# finish with coverage, so we get an output to check +cargo llvm-cov --locked --all-features From 92c2788dba90adc95b8eadf039c747157eb82961 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 13:18:40 +0100 Subject: [PATCH 5/9] split runner.rs into multiple smaller topics - no functional changes Signed-off-by: mimir-d --- tests/output/config.rs | 88 ++ tests/output/diagnosis.rs | 87 ++ tests/output/error.rs | 304 +++++++ tests/output/fixture.rs | 187 ++++ tests/output/log.rs | 159 ++++ tests/output/main.rs | 9 +- tests/output/measure.rs | 704 +++++++++++++++ tests/output/run.rs | 194 ++++ tests/output/runner.rs | 1800 ------------------------------------- tests/output/step.rs | 178 ++++ 10 files changed, 1909 insertions(+), 1801 deletions(-) create mode 100644 tests/output/config.rs create mode 100644 tests/output/diagnosis.rs create mode 100644 tests/output/error.rs create mode 100644 tests/output/fixture.rs create mode 100644 tests/output/log.rs create mode 100644 tests/output/measure.rs create mode 100644 tests/output/run.rs delete mode 100644 tests/output/runner.rs create mode 100644 tests/output/step.rs diff --git a/tests/output/config.rs b/tests/output/config.rs new file mode 100644 index 0000000..75f0531 --- /dev/null +++ b/tests/output/config.rs @@ -0,0 +1,88 @@ +// (c) Meta Platforms, Inc. and affiliates. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +#[cfg(coverage)] +use anyhow::Result; + +// reasoning: the coverage(off) attribute is experimental in llvm-cov, so because we cannot +// disable the coverage itself, only run this test when in coverage mode because assert_fs +// does ultimately assume there's a real filesystem somewhere +#[cfg(coverage)] +#[tokio::test] +async fn test_config_builder_with_file() -> Result<()> { + use std::fs; + + use assert_fs::prelude::*; + use assert_json_diff::assert_json_include; + use predicates::prelude::*; + use serde_json::json; + + use ocptv::output::{Config, DutInfo, TestResult, TestRun, TestStatus}; + + use super::fixture::*; + + let expected = [ + json_schema_version(), + json!({ + "testRunArtifact": { + "testRunStart": { + "dutInfo": { + "dutInfoId": "dut_id" + }, + "name": "run_name", + "parameters": {}, + "version": "1.0", + "commandLine": "" + } + }, + "sequenceNumber": 1, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testRunArtifact": { + "error": { + "message": "Error message", + "symptom": "symptom" + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(3), + ]; + + let fs = assert_fs::TempDir::new()?; + let output_file = fs.child("output.jsonl"); + + let dut = DutInfo::builder("dut_id").build(); + + let run = TestRun::builder("run_name", "1.0") + .config( + Config::builder() + .timezone(chrono_tz::Europe::Rome) + .with_timestamp_provider(Box::new(FixedTsProvider {})) + .with_file_output(output_file.path()) + .await? + .build(), + ) + .build() + .start(dut) + .await?; + + run.add_error_with_msg("symptom", "Error message").await?; + + run.end(TestStatus::Complete, TestResult::Pass).await?; + + output_file.assert(predicate::path::exists()); + let content = fs::read_to_string(output_file.path())?; + + for (idx, entry) in content.lines().enumerate() { + let value = serde_json::from_str::(entry).unwrap(); + assert_json_include!(actual: value, expected: &expected[idx]); + } + + Ok(()) +} diff --git a/tests/output/diagnosis.rs b/tests/output/diagnosis.rs new file mode 100644 index 0000000..22bef87 --- /dev/null +++ b/tests/output/diagnosis.rs @@ -0,0 +1,87 @@ +// (c) Meta Platforms, Inc. and affiliates. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +use anyhow::Result; +use futures::FutureExt; +use serde_json::json; + +use ocptv::output::{Diagnosis, DiagnosisType, Subcomponent}; + +use super::fixture::*; + +#[tokio::test] +async fn test_step_with_diagnosis() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "diagnosis": { + "verdict": "verdict", + "type": "PASS" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, _| { + async { + s.diagnosis("verdict", DiagnosisType::Pass).await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_diagnosis_builder() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "diagnosis": { + "verdict": "verdict", + "type": "PASS", + "message": "message", + "hardwareInfoId": "hw0", + "subcomponent": { + "name": "name" + }, + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, dut| { + async move { + let diagnosis = Diagnosis::builder("verdict", DiagnosisType::Pass) + .hardware_info(dut.hardware_info("hw0").unwrap()) // must exist + .subcomponent(&Subcomponent::builder("name").build()) + .message("message") + .build(); + s.diagnosis_with_details(&diagnosis).await?; + + Ok(()) + } + .boxed() + }) + .await +} diff --git a/tests/output/error.rs b/tests/output/error.rs new file mode 100644 index 0000000..3f5370b --- /dev/null +++ b/tests/output/error.rs @@ -0,0 +1,304 @@ +// (c) Meta Platforms, Inc. and affiliates. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +use anyhow::Result; +use futures::FutureExt; +use serde_json::json; + +use ocptv::output::Error; + +use super::fixture::*; + +#[tokio::test] +async fn test_testrun_with_error() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json!({ + "testRunArtifact": { + "error": { + "symptom": "symptom" + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(3), + ]; + + check_output_run(&expected, |r, _| { + async { r.add_error("symptom").await }.boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_with_error_with_message() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json!({ + "testRunArtifact": { + "error": { + "message": "Error message", + "symptom": "symptom" + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(3), + ]; + + check_output_run(&expected, |r, _| { + async { r.add_error_with_msg("symptom", "Error message").await }.boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_with_error_with_details() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json!({ + "testRunArtifact": { + "error": { + "message": "Error message", + "softwareInfoIds": [ + "sw0" + ], + "sourceLocation": { + "file": "file", + "line": 1 + }, + "symptom": "symptom" + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(3), + ]; + + check_output_run(&expected, |r, dut| { + async move { + r.add_error_with_details( + &Error::builder("symptom") + .message("Error message") + .source("file", 1) + .add_software_info(dut.software_info("sw0").unwrap()) // must exist + .build(), + ) + .await + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_with_error_before_start() -> Result<()> { + let expected = [ + json_schema_version(), + json!({ + "testRunArtifact": { + "error": { + "symptom": "no-dut", + } + }, + "sequenceNumber": 1, + "timestamp": DATETIME_FORMATTED + }), + ]; + + check_output(&expected, |run_builder, _| { + async move { + let run = run_builder.build(); + run.add_error("no-dut").await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_with_error_with_message_before_start() -> Result<()> { + let expected = [ + json_schema_version(), + json!({ + "testRunArtifact": { + "error": { + "symptom": "no-dut", + "message": "failed to find dut", + } + }, + "sequenceNumber": 1, + "timestamp": DATETIME_FORMATTED + }), + ]; + + check_output(&expected, |run_builder, _| { + async move { + let run = run_builder.build(); + run.add_error_with_msg("no-dut", "failed to find dut") + .await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_with_error_with_details_before_start() -> Result<()> { + let expected = [ + json_schema_version(), + json!({ + "testRunArtifact": { + "error": { + "message": "failed to find dut", + "sourceLocation": { + "file": "file", + "line": 1 + }, + "symptom": "no-dut" + } + }, + "sequenceNumber": 1, + "timestamp": DATETIME_FORMATTED + }), + ]; + + check_output(&expected, |run_builder, _| { + async move { + let run = run_builder.build(); + run.add_error_with_details( + &Error::builder("no-dut") + .message("failed to find dut") + .source("file", 1) + .build(), + ) + .await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_step_error() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "error": { + "symptom": "symptom" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, _| { + async { + s.add_error("symptom").await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_step_error_with_message() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "error": { + "message": "Error message", + "symptom": "symptom" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, _| { + async { + s.add_error_with_msg("symptom", "Error message").await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_step_error_with_details() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "error": { + "message": "Error message", + "softwareInfoIds": [ + "sw0" + ], + "sourceLocation": { + "file": "file", + "line": 1 + }, + "symptom": "symptom" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, dut| { + async move { + s.add_error_with_details( + &Error::builder("symptom") + .message("Error message") + .source("file", 1) + .add_software_info(dut.software_info("sw0").unwrap()) + .build(), + ) + .await?; + + Ok(()) + } + .boxed() + }) + .await +} diff --git a/tests/output/fixture.rs b/tests/output/fixture.rs new file mode 100644 index 0000000..ff21d32 --- /dev/null +++ b/tests/output/fixture.rs @@ -0,0 +1,187 @@ +// (c) Meta Platforms, Inc. and affiliates. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +use std::sync::Arc; + +use anyhow::Result; +use assert_json_diff::assert_json_eq; +use futures::future::BoxFuture; +use futures::future::Future; +use serde_json::json; +use tokio::sync::Mutex; + +use ocptv::output::{ + Config, DutInfo, HardwareInfo, Ident, OcptvError, SoftwareInfo, SoftwareType, StartedTestRun, + StartedTestStep, TestResult, TestRun, TestRunBuilder, TestStatus, TimestampProvider, + SPEC_VERSION, +}; + +pub const DATETIME: chrono::DateTime = + chrono::DateTime::from_timestamp_nanos(0); +pub const DATETIME_FORMATTED: &str = "1970-01-01T00:00:00.000Z"; +pub struct FixedTsProvider {} + +impl TimestampProvider for FixedTsProvider { + fn now(&self) -> chrono::DateTime { + // all cases will use time 0 but this is configurable + DATETIME.with_timezone(&chrono_tz::UTC) + } +} + +pub fn json_schema_version() -> serde_json::Value { + // seqno for schemaVersion is always 0 + json!({ + "schemaVersion": { + "major": SPEC_VERSION.0, + "minor": SPEC_VERSION.1 + }, + "sequenceNumber": 0, + "timestamp": DATETIME_FORMATTED + }) +} + +pub fn json_run_default_start() -> serde_json::Value { + // seqno for the default test run start is always 1 + json!({ + "testRunArtifact": { + "testRunStart": { + "dutInfo": { + "dutInfoId": "dut_id", + "softwareInfos": [{ + "softwareInfoId": "sw0", + "name": "ubuntu", + "version": "22", + "softwareType": "SYSTEM", + }], + "hardwareInfos": [{ + "hardwareInfoId": "hw0", + "name": "fan", + "location": "board0/fan" + }] + }, + "name": "run_name", + "parameters": {}, + "version": "1.0", + "commandLine": "" + } + }, + "sequenceNumber": 1, + "timestamp": DATETIME_FORMATTED + }) +} + +pub fn json_run_pass(seqno: i32) -> serde_json::Value { + json!({ + "testRunArtifact": { + "testRunEnd": { + "result": "PASS", + "status": "COMPLETE" + } + }, + "sequenceNumber": seqno, + "timestamp": DATETIME_FORMATTED + }) +} + +pub fn json_step_default_start() -> serde_json::Value { + // seqno for the default test run start is always 2 + json!({ + "testStepArtifact": { + "testStepId": "step0", + "testStepStart": { + "name": "first step" + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }) +} + +pub fn json_step_complete(seqno: i32) -> serde_json::Value { + json!({ + "testStepArtifact": { + "testStepId": "step0", + "testStepEnd": { + "status": "COMPLETE" + } + }, + "sequenceNumber": seqno, + "timestamp": DATETIME_FORMATTED + }) +} + +pub async fn check_output(expected: &[serde_json::Value], test_fn: F) -> Result<()> +where + R: Future>, + F: FnOnce(TestRunBuilder, DutInfo) -> R, +{ + let buffer: Arc>> = Arc::new(Mutex::new(vec![])); + let mut dut = DutInfo::builder("dut_id").build(); + dut.add_software_info( + SoftwareInfo::builder("ubuntu") + .id(Ident::Exact("sw0".to_owned())) // name is important as fixture + .version("22") + .software_type(SoftwareType::System) + .build(), + ); + dut.add_hardware_info( + HardwareInfo::builder("fan") + .id(Ident::Exact("hw0".to_owned())) + .location("board0/fan") + .build(), + ); + + let run_builder = TestRun::builder("run_name", "1.0").config( + Config::builder() + .with_buffer_output(Arc::clone(&buffer)) + .with_timestamp_provider(Box::new(FixedTsProvider {})) + .build(), + ); + + // run the main test closure + test_fn(run_builder, dut).await?; + + for (i, entry) in buffer.lock().await.iter().enumerate() { + let value = serde_json::from_str::(entry)?; + assert_json_eq!(value, expected[i]); + } + + Ok(()) +} + +pub async fn check_output_run(expected: &[serde_json::Value], test_fn: F) -> Result<()> +where + F: for<'a> FnOnce(&'a StartedTestRun, DutInfo) -> BoxFuture<'a, Result<(), OcptvError>>, +{ + check_output(expected, |run_builder, dut| async move { + let run = run_builder.build(); + + let run = run.start(dut.clone()).await?; + test_fn(&run, dut).await?; + run.end(TestStatus::Complete, TestResult::Pass).await?; + + Ok(()) + }) + .await +} + +pub async fn check_output_step(expected: &[serde_json::Value], test_fn: F) -> Result<()> +where + F: for<'a> FnOnce(&'a StartedTestStep, DutInfo) -> BoxFuture<'a, Result<(), OcptvError>>, +{ + check_output(expected, |run_builder, dut| async move { + let run = run_builder.build().start(dut.clone()).await?; + + let step = run.add_step("first step").start().await?; + test_fn(&step, dut).await?; + step.end(TestStatus::Complete).await?; + + run.end(TestStatus::Complete, TestResult::Pass).await?; + + Ok(()) + }) + .await +} diff --git a/tests/output/log.rs b/tests/output/log.rs new file mode 100644 index 0000000..9f54392 --- /dev/null +++ b/tests/output/log.rs @@ -0,0 +1,159 @@ +// (c) Meta Platforms, Inc. and affiliates. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +use anyhow::Result; +use futures::FutureExt; +use serde_json::json; + +use ocptv::output::{Log, LogSeverity}; + +use super::fixture::*; + +#[tokio::test] +async fn test_testrun_with_log() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json!({ + "testRunArtifact": { + "log": { + "message": "This is a log message with INFO severity", + "severity": "INFO" + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(3), + ]; + + check_output_run(&expected, |r, _| { + async { + r.add_log( + LogSeverity::Info, + "This is a log message with INFO severity", + ) + .await + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_with_log_with_details() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json!({ + "testRunArtifact": { + "log": { + "message": "This is a log message with INFO severity", + "severity": "INFO", + "sourceLocation": { + "file": "file", + "line": 1 + } + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(3), + ]; + + check_output_run(&expected, |r, _| { + async { + r.add_log_with_details( + &Log::builder("This is a log message with INFO severity") + .severity(LogSeverity::Info) + .source("file", 1) + .build(), + ) + .await + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_step_log() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "log": { + "message": "This is a log message with INFO severity", + "severity": "INFO" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, _| { + async { + s.add_log( + LogSeverity::Info, + "This is a log message with INFO severity", + ) + .await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_testrun_step_log_with_details() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "log": { + "message": "This is a log message with INFO severity", + "severity": "INFO", + "sourceLocation": { + "file": "file", + "line": 1 + } + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, _| { + async { + s.add_log_with_details( + &Log::builder("This is a log message with INFO severity") + .severity(LogSeverity::Info) + .source("file", 1) + .build(), + ) + .await?; + + Ok(()) + } + .boxed() + }) + .await +} diff --git a/tests/output/main.rs b/tests/output/main.rs index c07310d..f5d7506 100644 --- a/tests/output/main.rs +++ b/tests/output/main.rs @@ -4,5 +4,12 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +mod config; +mod diagnosis; +mod error; +mod fixture; +mod log; mod macros; -mod runner; +mod measure; +mod run; +mod step; diff --git a/tests/output/measure.rs b/tests/output/measure.rs new file mode 100644 index 0000000..d0fa0a0 --- /dev/null +++ b/tests/output/measure.rs @@ -0,0 +1,704 @@ +// (c) Meta Platforms, Inc. and affiliates. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +use anyhow::Result; +use futures::FutureExt; +use serde_json::json; + +use ocptv::output::{ + Ident, Measurement, MeasurementSeriesElemDetails, MeasurementSeriesInfo, Subcomponent, + Validator, ValidatorType, +}; + +use super::fixture::*; + +#[tokio::test] +async fn test_step_with_measurement() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurement": { + "name": "name", + "value": 50 + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, _| { + async { + s.add_measurement("name", 50.into()).await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_measurement_builder() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurement": { + "name": "name", + "value": 50, + "validators": [{ + "type": "EQUAL", + "value": 30 + }], + "hardwareInfoId": "hw0", + "subcomponent": { + "name": "name" + }, + "metadata": { + "key": "value", + "key2": "value2" + } + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_step(&expected, |s, dut| { + async move { + let hw_info = dut.hardware_info("hw0").unwrap(); // must exist + + let measurement = Measurement::builder("name", 50.into()) + .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) + .add_metadata("key", "value".into()) + .add_metadata("key2", "value2".into()) + .hardware_info(hw_info) + .subcomponent(&Subcomponent::builder("name").build()) + .build(); + s.add_measurement_with_details(&measurement).await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_measurement_series() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "step0_series0", + "name": "name" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "step0_series0", + "totalCount": 0 + } + }, + "sequenceNumber": 4, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(5), + json_run_pass(6), + ]; + + check_output_step(&expected, |s, _| { + async { + let series = s.add_measurement_series("name").start().await?; + series.end().await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_multiple_measurement_series() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "step0_series0", + "name": "name" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "step0_series0", + "totalCount": 0 + } + }, + "sequenceNumber": 4, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "step0_series1", + "name": "name" + } + }, + "sequenceNumber": 5, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "step0_series1", + "totalCount": 0 + } + }, + "sequenceNumber": 6, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(7), + json_run_pass(8), + ]; + + check_output_step(&expected, |s, _| { + async { + let series = s.add_measurement_series("name").start().await?; + series.end().await?; + + let series_2 = s.add_measurement_series("name").start().await?; + series_2.end().await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_measurement_series_with_details() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "series_id", + "name": "name", + "unit": "unit", + "validators": [{ + "type": "EQUAL", + "value": 30 + }], + "hardwareInfoId": "hw0", + "subcomponent": { + "name": "name" + }, + "metadata": { + "key": "value", + "key2": "value2" + } + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "series_id", + "totalCount": 0 + } + }, + "sequenceNumber": 4, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(5), + json_run_pass(6), + ]; + + check_output_step(&expected, |s, dut| { + async move { + let hw_info = dut.hardware_info("hw0").unwrap(); // must exist + + let series = s + .add_measurement_series_with_details( + MeasurementSeriesInfo::builder("name") + .id(Ident::Exact("series_id".to_owned())) + .unit("unit") + .add_metadata("key", "value".into()) + .add_metadata("key2", "value2".into()) + .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) + .hardware_info(hw_info) + .subcomponent(&Subcomponent::builder("name").build()) + .build(), + ) + .start() + .await?; + series.end().await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_measurement_series_element() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "step0_series0", + "name": "name" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 0, + "measurementSeriesId": "step0_series0", + "value": 60, + "timestamp": DATETIME_FORMATTED + } + }, + "sequenceNumber": 4, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "step0_series0", + "totalCount": 1 + } + }, + "sequenceNumber": 5, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(6), + json_run_pass(7), + ]; + + check_output_step(&expected, |s, _| { + async { + let series = s.add_measurement_series("name").start().await?; + series.add_measurement(60.into()).await?; + series.end().await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_measurement_series_element_index_no() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "step0_series0", + "name": "name" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 0, + "measurementSeriesId": "step0_series0", + "value": 60, + "timestamp": DATETIME_FORMATTED + } + }, + "sequenceNumber": 4, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 1, + "measurementSeriesId": "step0_series0", + "value": 70, + "timestamp": DATETIME_FORMATTED + } + }, + "sequenceNumber": 5, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 2, + "measurementSeriesId": "step0_series0", + "value": 80, + "timestamp": DATETIME_FORMATTED + } + }, + "sequenceNumber": 6, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "step0_series0", + "totalCount": 3 + } + }, + "sequenceNumber": 7, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(8), + json_run_pass(9), + ]; + + check_output_step(&expected, |s, _| { + async { + let series = s.add_measurement_series("name").start().await?; + // add more than one element to check the index increments correctly + series.add_measurement(60.into()).await?; + series.add_measurement(70.into()).await?; + series.add_measurement(80.into()).await?; + series.end().await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_measurement_series_element_with_details() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "step0_series0", + "name": "name" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 0, + "measurementSeriesId": "step0_series0", + "metadata": { + "key": "value", + "key2": "value2" + }, + "value": 60, + "timestamp": DATETIME_FORMATTED, + } + }, + "sequenceNumber": 4, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "step0_series0", + "totalCount": 1 + } + }, + "sequenceNumber": 5, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(6), + json_run_pass(7), + ]; + + check_output_step(&expected, |s, _| { + async { + let series = s.add_measurement_series("name").start().await?; + series + .add_measurement_with_details( + MeasurementSeriesElemDetails::builder(60.into()) + .timestamp(DATETIME.with_timezone(&chrono_tz::UTC)) + .add_metadata("key", "value".into()) + .add_metadata("key2", "value2".into()) + .build(), + ) + .await?; + series.end().await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_measurement_series_element_with_metadata_index_no() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "step0_series0", + "name": "name" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 0, + "measurementSeriesId": "step0_series0", + "metadata": {"key": "value"}, + "value": 60, + "timestamp": DATETIME_FORMATTED, + } + }, + "sequenceNumber": 4, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 1, + "measurementSeriesId": "step0_series0", + "metadata": {"key2": "value2"}, + "value": 70, + "timestamp": DATETIME_FORMATTED, + } + }, + "sequenceNumber": 5, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 2, + "measurementSeriesId": "step0_series0", + "metadata": {"key3": "value3"}, + "value": 80, + "timestamp": DATETIME_FORMATTED, + } + }, + "sequenceNumber": 6, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "step0_series0", + "totalCount": 3 + } + }, + "sequenceNumber": 7, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(8), + json_run_pass(9), + ]; + + check_output_step(&expected, |s, _| { + async { + let series = s.add_measurement_series("name").start().await?; + // add more than one element to check the index increments correctly + series + .add_measurement_with_details( + MeasurementSeriesElemDetails::builder(60.into()) + .add_metadata("key", "value".into()) + .build(), + ) + .await?; + series + .add_measurement_with_details( + MeasurementSeriesElemDetails::builder(70.into()) + .add_metadata("key2", "value2".into()) + .build(), + ) + .await?; + series + .add_measurement_with_details( + MeasurementSeriesElemDetails::builder(80.into()) + .add_metadata("key3", "value3".into()) + .build(), + ) + .await?; + series.end().await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[cfg(feature = "boxed-scopes")] +#[tokio::test] +async fn test_step_with_measurement_series_scope() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesStart": { + "measurementSeriesId": "step0_series0", + "name": "name" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 0, + "measurementSeriesId": "step0_series0", + "value": 60, + "timestamp": DATETIME_FORMATTED + } + }, + "sequenceNumber": 4, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 1, + "measurementSeriesId": "step0_series0", + "value": 70, + "timestamp": DATETIME_FORMATTED + } + }, + "sequenceNumber": 5, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesElement": { + "index": 2, + "measurementSeriesId": "step0_series0", + "value": 80, + "timestamp": DATETIME_FORMATTED + } + }, + "sequenceNumber": 6, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "measurementSeriesEnd": { + "measurementSeriesId": "step0_series0", + "totalCount": 3 + } + }, + "sequenceNumber": 7, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(8), + json_run_pass(9), + ]; + + check_output_step(&expected, |s, _| { + async { + let series = s.add_measurement_series("name"); + series + .scope(|s| { + async move { + s.add_measurement(60.into()).await?; + s.add_measurement(70.into()).await?; + s.add_measurement(80.into()).await?; + + Ok(()) + } + .boxed() + }) + .await?; + + Ok(()) + } + .boxed() + }) + .await +} diff --git a/tests/output/run.rs b/tests/output/run.rs new file mode 100644 index 0000000..1da27f3 --- /dev/null +++ b/tests/output/run.rs @@ -0,0 +1,194 @@ +// (c) Meta Platforms, Inc. and affiliates. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +use std::sync::Arc; + +use anyhow::Result; +use assert_json_diff::assert_json_include; +use futures::FutureExt; +use serde_json::json; +use tokio::sync::Mutex; + +use ocptv::output::{DutInfo, TestResult, TestRun, TestStatus}; + +use super::fixture::*; + +#[tokio::test] +async fn test_testrun_start_and_end() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_run_pass(2), + ]; + + check_output_run(&expected, |_, _| async { Ok(()) }.boxed()).await +} + +#[cfg(feature = "boxed-scopes")] +#[tokio::test] +async fn test_testrun_with_scope() -> Result<()> { + use ocptv::output::{LogSeverity, TestResult, TestRunOutcome, TestStatus}; + + let expected = [ + json_schema_version(), + json_run_default_start(), + json!({ + "testRunArtifact": { + "log": { + "message": "First message", + "severity": "INFO" + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(3), + ]; + + check_output(&expected, |run_builder, dut| async { + let run = run_builder.build(); + + run.scope(dut, |r| { + async move { + r.add_log(LogSeverity::Info, "First message").await?; + + Ok(TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) + } + .boxed() + }) + .await?; + + Ok(()) + }) + .await +} + +#[tokio::test] +async fn test_testrun_instantiation_with_new() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_run_pass(2), + ]; + let buffer: Arc>> = Arc::new(Mutex::new(vec![])); + + let dut = DutInfo::builder("dut_id").build(); + let run = TestRun::new("run_name", "1.0").start(dut).await?; + run.end(TestStatus::Complete, TestResult::Pass).await?; + + for (idx, entry) in buffer.lock().await.iter().enumerate() { + let value = serde_json::from_str::(entry)?; + assert_json_include!(actual: value, expected: &expected[idx]); + } + + Ok(()) +} + +#[tokio::test] +async fn test_testrun_metadata() -> Result<()> { + let expected = [ + json_schema_version(), + json!({ + "testRunArtifact": { + "testRunStart": { + "dutInfo": { + "dutInfoId": "dut_id", + "softwareInfos": [{ + "softwareInfoId": "sw0", + "name": "ubuntu", + "version": "22", + "softwareType": "SYSTEM", + }], + "hardwareInfos": [{ + "hardwareInfoId": "hw0", + "name": "fan", + "location": "board0/fan" + }] + }, + "metadata": {"key": "value"}, + "name": "run_name", + "parameters": {}, + "version": "1.0", + + "commandLine": "", + } + }, + "sequenceNumber": 1, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(2), + ]; + + check_output(&expected, |run_builder, dut| async { + let run = run_builder + .add_metadata("key", "value".into()) + .build() + .start(dut) + .await?; + + run.end(TestStatus::Complete, TestResult::Pass).await?; + Ok(()) + }) + .await +} + +#[tokio::test] +async fn test_testrun_builder() -> Result<()> { + let expected = [ + json_schema_version(), + json!({ + "testRunArtifact": { + "testRunStart": { + "commandLine": "cmd_line", + "dutInfo": { + "dutInfoId": "dut_id", + "softwareInfos": [{ + "softwareInfoId": "sw0", + "name": "ubuntu", + "version": "22", + "softwareType": "SYSTEM", + }], + "hardwareInfos": [{ + "hardwareInfoId": "hw0", + "name": "fan", + "location": "board0/fan" + }] + }, + "metadata": { + "key": "value", + "key2": "value2" + }, + "name": "run_name", + "parameters": { + "key": "value" + }, + "version": "1.0" + } + }, + "sequenceNumber": 1, + "timestamp": DATETIME_FORMATTED + }), + json_run_pass(2), + ]; + + check_output(&expected, |run_builder, dut| async { + let run = run_builder + .add_metadata("key", "value".into()) + .add_metadata("key2", "value2".into()) + .add_parameter("key", "value".into()) + .command_line("cmd_line") + .build() + .start(dut) + .await?; + + run.end(TestStatus::Complete, TestResult::Pass).await?; + Ok(()) + }) + .await +} diff --git a/tests/output/runner.rs b/tests/output/runner.rs deleted file mode 100644 index cd8df6c..0000000 --- a/tests/output/runner.rs +++ /dev/null @@ -1,1800 +0,0 @@ -// (c) Meta Platforms, Inc. and affiliates. -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. - -use std::sync::Arc; - -use anyhow::Result; - -use assert_json_diff::{assert_json_eq, assert_json_include}; -use futures::future::BoxFuture; -use futures::future::Future; -use futures::FutureExt; -use serde_json::json; -use tokio::sync::Mutex; - -use ocptv::output as tv; -use ocptv::output::OcptvError; -#[cfg(feature = "boxed-scopes")] -use tv::TestRunOutcome; -use tv::{ - Config, Diagnosis, DutInfo, Error, HardwareInfo, Ident, Log, LogSeverity, Measurement, - MeasurementSeriesElemDetails, MeasurementSeriesInfo, SoftwareInfo, SoftwareType, - StartedTestRun, StartedTestStep, Subcomponent, TestResult, TestRun, TestRunBuilder, TestStatus, - TimestampProvider, Validator, ValidatorType, -}; - -const DATETIME: chrono::DateTime = chrono::DateTime::from_timestamp_nanos(0); -const DATETIME_FORMATTED: &str = "1970-01-01T00:00:00.000Z"; -struct FixedTsProvider {} - -impl TimestampProvider for FixedTsProvider { - fn now(&self) -> chrono::DateTime { - // all cases will use time 0 but this is configurable - DATETIME.with_timezone(&chrono_tz::UTC) - } -} - -fn json_schema_version() -> serde_json::Value { - // seqno for schemaVersion is always 0 - json!({ - "schemaVersion": { - "major": tv::SPEC_VERSION.0, - "minor": tv::SPEC_VERSION.1 - }, - "sequenceNumber": 0, - "timestamp": DATETIME_FORMATTED - }) -} - -fn json_run_default_start() -> serde_json::Value { - // seqno for the default test run start is always 1 - json!({ - "testRunArtifact": { - "testRunStart": { - "dutInfo": { - "dutInfoId": "dut_id", - "softwareInfos": [{ - "softwareInfoId": "sw0", - "name": "ubuntu", - "version": "22", - "softwareType": "SYSTEM", - }], - "hardwareInfos": [{ - "hardwareInfoId": "hw0", - "name": "fan", - "location": "board0/fan" - }] - }, - "name": "run_name", - "parameters": {}, - "version": "1.0", - "commandLine": "" - } - }, - "sequenceNumber": 1, - "timestamp": DATETIME_FORMATTED - }) -} - -fn json_run_pass(seqno: i32) -> serde_json::Value { - json!({ - "testRunArtifact": { - "testRunEnd": { - "result": "PASS", - "status": "COMPLETE" - } - }, - "sequenceNumber": seqno, - "timestamp": DATETIME_FORMATTED - }) -} - -fn json_step_default_start() -> serde_json::Value { - // seqno for the default test run start is always 2 - json!({ - "testStepArtifact": { - "testStepId": "step0", - "testStepStart": { - "name": "first step" - } - }, - "sequenceNumber": 2, - "timestamp": DATETIME_FORMATTED - }) -} - -fn json_step_complete(seqno: i32) -> serde_json::Value { - json!({ - "testStepArtifact": { - "testStepId": "step0", - "testStepEnd": { - "status": "COMPLETE" - } - }, - "sequenceNumber": seqno, - "timestamp": DATETIME_FORMATTED - }) -} - -async fn check_output(expected: &[serde_json::Value], test_fn: F) -> Result<()> -where - R: Future>, - F: FnOnce(TestRunBuilder, DutInfo) -> R, -{ - let buffer: Arc>> = Arc::new(Mutex::new(vec![])); - let mut dut = DutInfo::builder("dut_id").build(); - dut.add_software_info( - SoftwareInfo::builder("ubuntu") - .id(Ident::Exact("sw0".to_owned())) // name is important as fixture - .version("22") - .software_type(SoftwareType::System) - .build(), - ); - dut.add_hardware_info( - HardwareInfo::builder("fan") - .id(Ident::Exact("hw0".to_owned())) - .location("board0/fan") - .build(), - ); - - let run_builder = TestRun::builder("run_name", "1.0").config( - Config::builder() - .with_buffer_output(Arc::clone(&buffer)) - .with_timestamp_provider(Box::new(FixedTsProvider {})) - .build(), - ); - - // run the main test closure - test_fn(run_builder, dut).await?; - - for (i, entry) in buffer.lock().await.iter().enumerate() { - let value = serde_json::from_str::(entry)?; - assert_json_eq!(value, expected[i]); - } - - Ok(()) -} - -async fn check_output_run(expected: &[serde_json::Value], test_fn: F) -> Result<()> -where - F: for<'a> FnOnce(&'a StartedTestRun, DutInfo) -> BoxFuture<'a, Result<(), tv::OcptvError>>, -{ - check_output(expected, |run_builder, dut| async move { - let run = run_builder.build(); - - let run = run.start(dut.clone()).await?; - test_fn(&run, dut).await?; - run.end(TestStatus::Complete, TestResult::Pass).await?; - - Ok(()) - }) - .await -} - -async fn check_output_step(expected: &[serde_json::Value], test_fn: F) -> Result<()> -where - F: for<'a> FnOnce(&'a StartedTestStep, DutInfo) -> BoxFuture<'a, Result<(), tv::OcptvError>>, -{ - check_output(expected, |run_builder, dut| async move { - let run = run_builder.build().start(dut.clone()).await?; - - let step = run.add_step("first step").start().await?; - test_fn(&step, dut).await?; - step.end(TestStatus::Complete).await?; - - run.end(TestStatus::Complete, TestResult::Pass).await?; - - Ok(()) - }) - .await -} - -#[tokio::test] -async fn test_testrun_start_and_end() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_run_pass(2), - ]; - - check_output_run(&expected, |_, _| async { Ok(()) }.boxed()).await -} - -#[tokio::test] -async fn test_testrun_with_log() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json!({ - "testRunArtifact": { - "log": { - "message": "This is a log message with INFO severity", - "severity": "INFO" - } - }, - "sequenceNumber": 2, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(3), - ]; - - check_output_run(&expected, |r, _| { - async { - r.add_log( - LogSeverity::Info, - "This is a log message with INFO severity", - ) - .await - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_with_log_with_details() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json!({ - "testRunArtifact": { - "log": { - "message": "This is a log message with INFO severity", - "severity": "INFO", - "sourceLocation": { - "file": "file", - "line": 1 - } - } - }, - "sequenceNumber": 2, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(3), - ]; - - check_output_run(&expected, |r, _| { - async { - r.add_log_with_details( - &Log::builder("This is a log message with INFO severity") - .severity(LogSeverity::Info) - .source("file", 1) - .build(), - ) - .await - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_with_error() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json!({ - "testRunArtifact": { - "error": { - "symptom": "symptom" - } - }, - "sequenceNumber": 2, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(3), - ]; - - check_output_run(&expected, |r, _| { - async { r.add_error("symptom").await }.boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_with_error_with_message() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json!({ - "testRunArtifact": { - "error": { - "message": "Error message", - "symptom": "symptom" - } - }, - "sequenceNumber": 2, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(3), - ]; - - check_output_run(&expected, |r, _| { - async { r.add_error_with_msg("symptom", "Error message").await }.boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_with_error_with_details() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json!({ - "testRunArtifact": { - "error": { - "message": "Error message", - "softwareInfoIds": [ - "sw0" - ], - "sourceLocation": { - "file": "file", - "line": 1 - }, - "symptom": "symptom" - } - }, - "sequenceNumber": 2, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(3), - ]; - - check_output_run(&expected, |r, dut| { - async move { - r.add_error_with_details( - &Error::builder("symptom") - .message("Error message") - .source("file", 1) - .add_software_info(dut.software_info("sw0").unwrap()) // must exist - .build(), - ) - .await - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_with_error_before_start() -> Result<()> { - let expected = [ - json_schema_version(), - json!({ - "testRunArtifact": { - "error": { - "symptom": "no-dut", - } - }, - "sequenceNumber": 1, - "timestamp": DATETIME_FORMATTED - }), - ]; - - check_output(&expected, |run_builder, _| { - async move { - let run = run_builder.build(); - run.add_error("no-dut").await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_with_error_with_message_before_start() -> Result<()> { - let expected = [ - json_schema_version(), - json!({ - "testRunArtifact": { - "error": { - "symptom": "no-dut", - "message": "failed to find dut", - } - }, - "sequenceNumber": 1, - "timestamp": DATETIME_FORMATTED - }), - ]; - - check_output(&expected, |run_builder, _| { - async move { - let run = run_builder.build(); - run.add_error_with_msg("no-dut", "failed to find dut") - .await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_with_error_with_details_before_start() -> Result<()> { - let expected = [ - json_schema_version(), - json!({ - "testRunArtifact": { - "error": { - "message": "failed to find dut", - "sourceLocation": { - "file": "file", - "line": 1 - }, - "symptom": "no-dut" - } - }, - "sequenceNumber": 1, - "timestamp": DATETIME_FORMATTED - }), - ]; - - check_output(&expected, |run_builder, _| { - async move { - let run = run_builder.build(); - run.add_error_with_details( - &Error::builder("no-dut") - .message("failed to find dut") - .source("file", 1) - .build(), - ) - .await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[cfg(feature = "boxed-scopes")] -#[tokio::test] -async fn test_testrun_with_scope() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json!({ - "testRunArtifact": { - "log": { - "message": "First message", - "severity": "INFO" - } - }, - "sequenceNumber": 2, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(3), - ]; - - check_output(&expected, |run_builder, dut| async { - let run = run_builder.build(); - - run.scope(dut, |r| { - async move { - r.add_log(LogSeverity::Info, "First message").await?; - - Ok(TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() - }) - .await?; - - Ok(()) - }) - .await -} - -#[tokio::test] -async fn test_testrun_with_step() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json_step_complete(3), - json_run_pass(4), - ]; - - check_output_step(&expected, |_, _| async { Ok(()) }.boxed()).await -} - -#[tokio::test] -async fn test_testrun_step_log() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "log": { - "message": "This is a log message with INFO severity", - "severity": "INFO" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, _| { - async { - s.add_log( - LogSeverity::Info, - "This is a log message with INFO severity", - ) - .await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_step_log_with_details() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "log": { - "message": "This is a log message with INFO severity", - "severity": "INFO", - "sourceLocation": { - "file": "file", - "line": 1 - } - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, _| { - async { - s.add_log_with_details( - &Log::builder("This is a log message with INFO severity") - .severity(LogSeverity::Info) - .source("file", 1) - .build(), - ) - .await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_step_error() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "error": { - "symptom": "symptom" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, _| { - async { - s.add_error("symptom").await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_step_error_with_message() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "error": { - "message": "Error message", - "symptom": "symptom" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, _| { - async { - s.add_error_with_msg("symptom", "Error message").await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_testrun_step_error_with_details() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "error": { - "message": "Error message", - "softwareInfoIds": [ - "sw0" - ], - "sourceLocation": { - "file": "file", - "line": 1 - }, - "symptom": "symptom" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, dut| { - async move { - s.add_error_with_details( - &Error::builder("symptom") - .message("Error message") - .source("file", 1) - .add_software_info(dut.software_info("sw0").unwrap()) - .build(), - ) - .await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[cfg(feature = "boxed-scopes")] -#[tokio::test] -async fn test_testrun_step_scope_log() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "log": { - "message": "This is a log message with INFO severity", - "severity": "INFO" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_run(&expected, |r, _| { - async { - r.add_step("first step") - .scope(|s| { - async move { - s.add_log( - LogSeverity::Info, - "This is a log message with INFO severity", - ) - .await?; - - Ok(TestStatus::Complete) - } - .boxed() - }) - .await - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_measurement() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurement": { - "name": "name", - "value": 50 - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, _| { - async { - s.add_measurement("name", 50.into()).await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_measurement_builder() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurement": { - "name": "name", - "value": 50, - "validators": [{ - "type": "EQUAL", - "value": 30 - }], - "hardwareInfoId": "hw0", - "subcomponent": { - "name": "name" - }, - "metadata": { - "key": "value", - "key2": "value2" - } - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, dut| { - async move { - let hw_info = dut.hardware_info("hw0").unwrap(); // must exist - - let measurement = Measurement::builder("name", 50.into()) - .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) - .add_metadata("key", "value".into()) - .add_metadata("key2", "value2".into()) - .hardware_info(hw_info) - .subcomponent(&Subcomponent::builder("name").build()) - .build(); - s.add_measurement_with_details(&measurement).await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_measurement_series() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "step0_series0", - "name": "name" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "step0_series0", - "totalCount": 0 - } - }, - "sequenceNumber": 4, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(5), - json_run_pass(6), - ]; - - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - series.end().await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_multiple_measurement_series() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "step0_series0", - "name": "name" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "step0_series0", - "totalCount": 0 - } - }, - "sequenceNumber": 4, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "step0_series1", - "name": "name" - } - }, - "sequenceNumber": 5, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "step0_series1", - "totalCount": 0 - } - }, - "sequenceNumber": 6, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(7), - json_run_pass(8), - ]; - - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - series.end().await?; - - let series_2 = s.add_measurement_series("name").start().await?; - series_2.end().await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_measurement_series_with_details() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "series_id", - "name": "name", - "unit": "unit", - "validators": [{ - "type": "EQUAL", - "value": 30 - }], - "hardwareInfoId": "hw0", - "subcomponent": { - "name": "name" - }, - "metadata": { - "key": "value", - "key2": "value2" - } - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "series_id", - "totalCount": 0 - } - }, - "sequenceNumber": 4, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(5), - json_run_pass(6), - ]; - - check_output_step(&expected, |s, dut| { - async move { - let hw_info = dut.hardware_info("hw0").unwrap(); // must exist - - let series = s - .add_measurement_series_with_details( - MeasurementSeriesInfo::builder("name") - .id(Ident::Exact("series_id".to_owned())) - .unit("unit") - .add_metadata("key", "value".into()) - .add_metadata("key2", "value2".into()) - .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) - .hardware_info(hw_info) - .subcomponent(&Subcomponent::builder("name").build()) - .build(), - ) - .start() - .await?; - series.end().await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_measurement_series_element() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "step0_series0", - "name": "name" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 0, - "measurementSeriesId": "step0_series0", - "value": 60, - "timestamp": DATETIME_FORMATTED - } - }, - "sequenceNumber": 4, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "step0_series0", - "totalCount": 1 - } - }, - "sequenceNumber": 5, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(6), - json_run_pass(7), - ]; - - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - series.add_measurement(60.into()).await?; - series.end().await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_measurement_series_element_index_no() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "step0_series0", - "name": "name" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 0, - "measurementSeriesId": "step0_series0", - "value": 60, - "timestamp": DATETIME_FORMATTED - } - }, - "sequenceNumber": 4, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 1, - "measurementSeriesId": "step0_series0", - "value": 70, - "timestamp": DATETIME_FORMATTED - } - }, - "sequenceNumber": 5, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 2, - "measurementSeriesId": "step0_series0", - "value": 80, - "timestamp": DATETIME_FORMATTED - } - }, - "sequenceNumber": 6, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "step0_series0", - "totalCount": 3 - } - }, - "sequenceNumber": 7, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(8), - json_run_pass(9), - ]; - - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - // add more than one element to check the index increments correctly - series.add_measurement(60.into()).await?; - series.add_measurement(70.into()).await?; - series.add_measurement(80.into()).await?; - series.end().await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_measurement_series_element_with_details() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "step0_series0", - "name": "name" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 0, - "measurementSeriesId": "step0_series0", - "metadata": { - "key": "value", - "key2": "value2" - }, - "value": 60, - "timestamp": DATETIME_FORMATTED, - } - }, - "sequenceNumber": 4, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "step0_series0", - "totalCount": 1 - } - }, - "sequenceNumber": 5, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(6), - json_run_pass(7), - ]; - - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - series - .add_measurement_with_details( - MeasurementSeriesElemDetails::builder(60.into()) - .timestamp(DATETIME.with_timezone(&chrono_tz::UTC)) - .add_metadata("key", "value".into()) - .add_metadata("key2", "value2".into()) - .build(), - ) - .await?; - series.end().await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_measurement_series_element_with_metadata_index_no() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "step0_series0", - "name": "name" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 0, - "measurementSeriesId": "step0_series0", - "metadata": {"key": "value"}, - "value": 60, - "timestamp": DATETIME_FORMATTED, - } - }, - "sequenceNumber": 4, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 1, - "measurementSeriesId": "step0_series0", - "metadata": {"key2": "value2"}, - "value": 70, - "timestamp": DATETIME_FORMATTED, - } - }, - "sequenceNumber": 5, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 2, - "measurementSeriesId": "step0_series0", - "metadata": {"key3": "value3"}, - "value": 80, - "timestamp": DATETIME_FORMATTED, - } - }, - "sequenceNumber": 6, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "step0_series0", - "totalCount": 3 - } - }, - "sequenceNumber": 7, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(8), - json_run_pass(9), - ]; - - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - // add more than one element to check the index increments correctly - series - .add_measurement_with_details( - MeasurementSeriesElemDetails::builder(60.into()) - .add_metadata("key", "value".into()) - .build(), - ) - .await?; - series - .add_measurement_with_details( - MeasurementSeriesElemDetails::builder(70.into()) - .add_metadata("key2", "value2".into()) - .build(), - ) - .await?; - series - .add_measurement_with_details( - MeasurementSeriesElemDetails::builder(80.into()) - .add_metadata("key3", "value3".into()) - .build(), - ) - .await?; - series.end().await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_diagnosis() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "diagnosis": { - "verdict": "verdict", - "type": "PASS" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, _| { - async { - s.diagnosis("verdict", tv::DiagnosisType::Pass).await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_diagnosis_builder() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "diagnosis": { - "verdict": "verdict", - "type": "PASS", - "message": "message", - "hardwareInfoId": "hw0", - "subcomponent": { - "name": "name" - }, - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - check_output_step(&expected, |s, dut| { - async move { - let diagnosis = Diagnosis::builder("verdict", tv::DiagnosisType::Pass) - .hardware_info(dut.hardware_info("hw0").unwrap()) // must exist - .subcomponent(&Subcomponent::builder("name").build()) - .message("message") - .build(); - s.diagnosis_with_details(&diagnosis).await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[cfg(feature = "boxed-scopes")] -#[tokio::test] -async fn test_step_with_measurement_series_scope() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesStart": { - "measurementSeriesId": "step0_series0", - "name": "name" - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 0, - "measurementSeriesId": "step0_series0", - "value": 60, - "timestamp": DATETIME_FORMATTED - } - }, - "sequenceNumber": 4, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 1, - "measurementSeriesId": "step0_series0", - "value": 70, - "timestamp": DATETIME_FORMATTED - } - }, - "sequenceNumber": 5, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesElement": { - "index": 2, - "measurementSeriesId": "step0_series0", - "value": 80, - "timestamp": DATETIME_FORMATTED - } - }, - "sequenceNumber": 6, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "measurementSeriesEnd": { - "measurementSeriesId": "step0_series0", - "totalCount": 3 - } - }, - "sequenceNumber": 7, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(8), - json_run_pass(9), - ]; - - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name"); - series - .scope(|s| { - async move { - s.add_measurement(60.into()).await?; - s.add_measurement(70.into()).await?; - s.add_measurement(80.into()).await?; - - Ok(()) - } - .boxed() - }) - .await?; - - Ok(()) - } - .boxed() - }) - .await -} - -// reasoning: the coverage(off) attribute is experimental in llvm-cov, so because we cannot -// disable the coverage itself, only run this test when in coverage mode because assert_fs -// does ultimately assume there's a real filesystem somewhere -#[cfg(coverage)] -#[tokio::test] -async fn test_config_builder_with_file() -> Result<()> { - use assert_fs::prelude::*; - use predicates::prelude::*; - use std::fs; - - let expected = [ - json_schema_version(), - json!({ - "testRunArtifact": { - "testRunStart": { - "dutInfo": { - "dutInfoId": "dut_id" - }, - "name": "run_name", - "parameters": {}, - "version": "1.0", - "commandLine": "" - } - }, - "sequenceNumber": 1, - "timestamp": DATETIME_FORMATTED - }), - json!({ - "testRunArtifact": { - "error": { - "message": "Error message", - "symptom": "symptom" - } - }, - "sequenceNumber": 2, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(3), - ]; - - let fs = assert_fs::TempDir::new()?; - let output_file = fs.child("output.jsonl"); - - let dut = DutInfo::builder("dut_id").build(); - - let run = TestRun::builder("run_name", "1.0") - .config( - Config::builder() - .timezone(chrono_tz::Europe::Rome) - .with_timestamp_provider(Box::new(FixedTsProvider {})) - .with_file_output(output_file.path()) - .await? - .build(), - ) - .build() - .start(dut) - .await?; - - run.add_error_with_msg("symptom", "Error message").await?; - - run.end(TestStatus::Complete, TestResult::Pass).await?; - - output_file.assert(predicate::path::exists()); - let content = fs::read_to_string(output_file.path())?; - - for (idx, entry) in content.lines().enumerate() { - let value = serde_json::from_str::(entry).unwrap(); - assert_json_include!(actual: value, expected: &expected[idx]); - } - - Ok(()) -} - -#[tokio::test] -async fn test_step_with_extension() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_step_default_start(), - json!({ - "testStepArtifact": { - "testStepId": "step0", - "extension": { - "name": "extension", - "content": { - "@type": "TestExtension", - "stringField": "string", - "numberField": 42 - } - } - }, - "sequenceNumber": 3, - "timestamp": DATETIME_FORMATTED - }), - json_step_complete(4), - json_run_pass(5), - ]; - - #[derive(serde::Serialize)] - struct Ext { - #[serde(rename = "@type")] - r#type: String, - #[serde(rename = "stringField")] - string_field: String, - #[serde(rename = "numberField")] - number_field: u32, - } - - check_output_step(&expected, |s, _| { - async { - s.add_extension( - "extension", - Ext { - r#type: "TestExtension".to_owned(), - string_field: "string".to_owned(), - number_field: 42, - }, - ) - .await?; - - Ok(()) - } - .boxed() - }) - .await -} - -#[tokio::test] -async fn test_step_with_extension_which_fails() -> Result<()> { - #[derive(thiserror::Error, Debug, PartialEq)] - enum TestError { - #[error("test_error_fail")] - Fail, - } - - fn fail_serialize(_: &u32, _serializer: S) -> Result - where - S: serde::Serializer, - { - Err(serde::ser::Error::custom(TestError::Fail)) - } - - #[derive(serde::Serialize)] - struct Ext { - #[serde(serialize_with = "fail_serialize")] - i: u32, - } - - let buffer: Arc>> = Arc::new(Mutex::new(vec![])); - let dut = DutInfo::builder("dut_id").build(); - let run = TestRun::builder("run_name", "1.0") - .config( - Config::builder() - .with_buffer_output(Arc::clone(&buffer)) - .with_timestamp_provider(Box::new(FixedTsProvider {})) - .build(), - ) - .build() - .start(dut) - .await?; - let step = run.add_step("first step").start().await?; - - let result = step.add_extension("extension", Ext { i: 0 }).await; - - match result { - Err(OcptvError::Format(e)) => { - // `to_string` is the only way to check this error. `serde_json::Error` only - // implements source/cause for io errors, and this is a string - assert_eq!(e.to_string(), "test_error_fail"); - } - _ => panic!("unexpected ocptv error type"), - } - - Ok(()) -} - -#[tokio::test] -async fn test_testrun_instantiation_with_new() -> Result<()> { - let expected = [ - json_schema_version(), - json_run_default_start(), - json_run_pass(2), - ]; - let buffer: Arc>> = Arc::new(Mutex::new(vec![])); - - let dut = DutInfo::builder("dut_id").build(); - let run = TestRun::new("run_name", "1.0").start(dut).await?; - run.end(TestStatus::Complete, TestResult::Pass).await?; - - for (idx, entry) in buffer.lock().await.iter().enumerate() { - let value = serde_json::from_str::(entry)?; - assert_json_include!(actual: value, expected: &expected[idx]); - } - - Ok(()) -} - -#[tokio::test] -async fn test_testrun_metadata() -> Result<()> { - let expected = [ - json_schema_version(), - json!({ - "testRunArtifact": { - "testRunStart": { - "dutInfo": { - "dutInfoId": "dut_id", - "softwareInfos": [{ - "softwareInfoId": "sw0", - "name": "ubuntu", - "version": "22", - "softwareType": "SYSTEM", - }], - "hardwareInfos": [{ - "hardwareInfoId": "hw0", - "name": "fan", - "location": "board0/fan" - }] - }, - "metadata": {"key": "value"}, - "name": "run_name", - "parameters": {}, - "version": "1.0", - - "commandLine": "", - } - }, - "sequenceNumber": 1, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(2), - ]; - - check_output(&expected, |run_builder, dut| async { - let run = run_builder - .add_metadata("key", "value".into()) - .build() - .start(dut) - .await?; - - run.end(TestStatus::Complete, TestResult::Pass).await?; - Ok(()) - }) - .await -} - -#[tokio::test] -async fn test_testrun_builder() -> Result<()> { - let expected = [ - json_schema_version(), - json!({ - "testRunArtifact": { - "testRunStart": { - "commandLine": "cmd_line", - "dutInfo": { - "dutInfoId": "dut_id", - "softwareInfos": [{ - "softwareInfoId": "sw0", - "name": "ubuntu", - "version": "22", - "softwareType": "SYSTEM", - }], - "hardwareInfos": [{ - "hardwareInfoId": "hw0", - "name": "fan", - "location": "board0/fan" - }] - }, - "metadata": { - "key": "value", - "key2": "value2" - }, - "name": "run_name", - "parameters": { - "key": "value" - }, - "version": "1.0" - } - }, - "sequenceNumber": 1, - "timestamp": DATETIME_FORMATTED - }), - json_run_pass(2), - ]; - - check_output(&expected, |run_builder, dut| async { - let run = run_builder - .add_metadata("key", "value".into()) - .add_metadata("key2", "value2".into()) - .add_parameter("key", "value".into()) - .command_line("cmd_line") - .build() - .start(dut) - .await?; - - run.end(TestStatus::Complete, TestResult::Pass).await?; - Ok(()) - }) - .await -} diff --git a/tests/output/step.rs b/tests/output/step.rs new file mode 100644 index 0000000..b74026d --- /dev/null +++ b/tests/output/step.rs @@ -0,0 +1,178 @@ +// (c) Meta Platforms, Inc. and affiliates. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +use std::sync::Arc; + +use anyhow::Result; +use futures::FutureExt; +use serde_json::json; +use tokio::sync::Mutex; + +use ocptv::output::{Config, DutInfo, OcptvError, TestRun}; + +use super::fixture::*; + +#[tokio::test] +async fn test_testrun_with_step() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json_step_complete(3), + json_run_pass(4), + ]; + + check_output_step(&expected, |_, _| async { Ok(()) }.boxed()).await +} + +#[cfg(feature = "boxed-scopes")] +#[tokio::test] +async fn test_testrun_step_scope_log() -> Result<()> { + use ocptv::output::{LogSeverity, TestStatus}; + + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "log": { + "message": "This is a log message with INFO severity", + "severity": "INFO" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + check_output_run(&expected, |r, _| { + async { + r.add_step("first step") + .scope(|s| { + async move { + s.add_log( + LogSeverity::Info, + "This is a log message with INFO severity", + ) + .await?; + + Ok(TestStatus::Complete) + } + .boxed() + }) + .await + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_extension() -> Result<()> { + let expected = [ + json_schema_version(), + json_run_default_start(), + json_step_default_start(), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "extension": { + "name": "extension", + "content": { + "@type": "TestExtension", + "stringField": "string", + "numberField": 42 + } + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), + json_step_complete(4), + json_run_pass(5), + ]; + + #[derive(serde::Serialize)] + struct Ext { + #[serde(rename = "@type")] + r#type: String, + #[serde(rename = "stringField")] + string_field: String, + #[serde(rename = "numberField")] + number_field: u32, + } + + check_output_step(&expected, |s, _| { + async { + s.add_extension( + "extension", + Ext { + r#type: "TestExtension".to_owned(), + string_field: "string".to_owned(), + number_field: 42, + }, + ) + .await?; + + Ok(()) + } + .boxed() + }) + .await +} + +#[tokio::test] +async fn test_step_with_extension_which_fails() -> Result<()> { + #[derive(thiserror::Error, Debug, PartialEq)] + enum TestError { + #[error("test_error_fail")] + Fail, + } + + fn fail_serialize(_: &u32, _serializer: S) -> Result + where + S: serde::Serializer, + { + Err(serde::ser::Error::custom(TestError::Fail)) + } + + #[derive(serde::Serialize)] + struct Ext { + #[serde(serialize_with = "fail_serialize")] + i: u32, + } + + let buffer: Arc>> = Arc::new(Mutex::new(vec![])); + let dut = DutInfo::builder("dut_id").build(); + let run = TestRun::builder("run_name", "1.0") + .config( + Config::builder() + .with_buffer_output(Arc::clone(&buffer)) + .with_timestamp_provider(Box::new(FixedTsProvider {})) + .build(), + ) + .build() + .start(dut) + .await?; + let step = run.add_step("first step").start().await?; + + let result = step.add_extension("extension", Ext { i: 0 }).await; + + match result { + Err(OcptvError::Format(e)) => { + // `to_string` is the only way to check this error. `serde_json::Error` only + // implements source/cause for io errors, and this is a string + assert_eq!(e.to_string(), "test_error_fail"); + } + _ => panic!("unexpected ocptv error type"), + } + + Ok(()) +} From f9753db5b429d88e109d28a6b97fdb2def9cfeba Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 13:32:34 +0100 Subject: [PATCH 6/9] improve api ergonomics; remove refs - remove ref requirement for some objects that are frequently consumed, without any need to keep additional objects around (or if so, they're Clone) - remove a bunch of unnecessary `.clone()` Signed-off-by: mimir-d --- examples/error_with_dut.rs | 2 +- examples/measurement_single.rs | 2 +- examples/measurement_subcomponent.rs | 8 ++-- examples/measurement_validators.rs | 8 ++-- src/output/dut.rs | 8 ++-- src/output/error.rs | 1 + src/output/macros.rs | 8 ++-- src/output/measure.rs | 68 ++++++++++++---------------- src/output/run.rs | 22 ++++----- src/output/step.rs | 20 ++++---- tests/output/diagnosis.rs | 2 +- tests/output/error.rs | 6 +-- tests/output/log.rs | 4 +- tests/output/measure.rs | 10 ++-- 14 files changed, 79 insertions(+), 90 deletions(-) diff --git a/examples/error_with_dut.rs b/examples/error_with_dut.rs index 652e0cf..6983090 100644 --- a/examples/error_with_dut.rs +++ b/examples/error_with_dut.rs @@ -27,7 +27,7 @@ async fn main() -> Result<()> { .scope(dut, |r| { async move { r.add_error_with_details( - &tv::Error::builder("power-fail") + tv::Error::builder("power-fail") .add_software_info(&sw_info) .build(), ) diff --git a/examples/measurement_single.rs b/examples/measurement_single.rs index 962bbd4..364e1fa 100644 --- a/examples/measurement_single.rs +++ b/examples/measurement_single.rs @@ -13,7 +13,7 @@ use tv::{TestResult, TestStatus}; async fn run_measure_step(step: &tv::StartedTestStep) -> Result { step.add_measurement("temperature", 42.5.into()).await?; step.add_measurement_with_details( - &tv::Measurement::builder("fan_speed", 1200.into()) + tv::Measurement::builder("fan_speed", 1200.into()) .unit("rpm") .build(), ) diff --git a/examples/measurement_subcomponent.rs b/examples/measurement_subcomponent.rs index 515f5c4..cceafef 100644 --- a/examples/measurement_subcomponent.rs +++ b/examples/measurement_subcomponent.rs @@ -16,10 +16,10 @@ async fn run_measure_step( ram0: tv::DutHardwareInfo, ) -> Result { step.add_measurement_with_details( - &tv::Measurement::builder("temp0", 100.5.into()) + tv::Measurement::builder("temp0", 100.5.into()) .unit("F") .hardware_info(&ram0) - .subcomponent(&tv::Subcomponent::builder("chip0").build()) + .subcomponent(tv::Subcomponent::builder("chip0").build()) .build(), ) .await?; @@ -29,7 +29,7 @@ async fn run_measure_step( .unit("C") .hardware_info(&ram0) .subcomponent( - &tv::Subcomponent::builder("chip1") + tv::Subcomponent::builder("chip1") .location("U11") .version("1") .revision("1") @@ -59,7 +59,7 @@ async fn run_measure_step( async fn main() -> Result<()> { let mut dut = tv::DutInfo::builder("dut0") .name("host0.example.com") - .add_platform_info(&tv::PlatformInfo::new("memory-optimized")) + .add_platform_info(tv::PlatformInfo::new("memory-optimized")) .build(); dut.add_software_info( diff --git a/examples/measurement_validators.rs b/examples/measurement_validators.rs index 54202c6..a1e0299 100644 --- a/examples/measurement_validators.rs +++ b/examples/measurement_validators.rs @@ -13,9 +13,9 @@ use tv::{TestResult, TestStatus, ValidatorType}; async fn run_measure_step(step: &tv::StartedTestStep) -> Result { step.add_measurement_with_details( - &tv::Measurement::builder("temp", 40.into()) + tv::Measurement::builder("temp", 40.into()) .add_validator( - &tv::Validator::builder(ValidatorType::GreaterThan, 30.into()) + tv::Validator::builder(ValidatorType::GreaterThan, 30.into()) .name("gt_30") .build(), ) @@ -27,7 +27,7 @@ async fn run_measure_step(step: &tv::StartedTestStep) -> Result Result DutInfoBuilder { - self.platform_infos.push(platform_info.clone()); + pub fn add_platform_info(mut self, platform_info: PlatformInfo) -> DutInfoBuilder { + self.platform_infos.push(platform_info); self } pub fn add_metadata(mut self, key: &str, value: tv::Value) -> DutInfoBuilder { - self.metadata.insert(key.to_string(), value.clone()); + self.metadata.insert(key.to_string(), value); self } @@ -520,7 +520,7 @@ mod tests { .name("dut") .add_metadata("key", "value".into()) .add_metadata("key2", "value2".into()) - .add_platform_info(&PlatformInfo::builder("platform_info").build()) + .add_platform_info(PlatformInfo::builder("platform_info").build()) .build(); dut.add_software_info( diff --git a/src/output/error.rs b/src/output/error.rs index e7a3e72..3589cf4 100644 --- a/src/output/error.rs +++ b/src/output/error.rs @@ -9,6 +9,7 @@ use crate::spec; use tv::{dut, trait_ext::VecExt, DutSoftwareInfo}; /// TODO: docs +#[derive(Clone)] pub struct Error { symptom: String, message: Option, diff --git a/src/output/macros.rs b/src/output/macros.rs index d3d6dce..6993197 100644 --- a/src/output/macros.rs +++ b/src/output/macros.rs @@ -56,7 +56,7 @@ macro_rules! ocptv_error { ($runner:expr, $symptom:expr, $msg:expr) => { $runner.add_error_with_details( - &$crate::output::Error::builder($symptom) + $crate::output::Error::builder($symptom) .message($msg) .source(file!(), line!() as i32) .build(), @@ -65,7 +65,7 @@ macro_rules! ocptv_error { ($runner:expr, $symptom:expr) => { $runner.add_error_with_details( - &$crate::output::Error::builder($symptom) + $crate::output::Error::builder($symptom) .source(file!(), line!() as i32) .build(), ) @@ -106,7 +106,7 @@ macro_rules! ocptv_log { macro_rules! $name { ($artifact:expr, $msg:expr) => { $artifact.add_log_with_details( - &$crate::output::Log::builder($msg) + $crate::output::Log::builder($msg) .severity($severity) .source(file!(), line!() as i32) .build(), @@ -160,7 +160,7 @@ macro_rules! ocptv_diagnosis { macro_rules! $name { ($artifact:expr, $verdict:expr) => { $artifact.diagnosis_with_details( - &$crate::output::Diagnosis::builder($verdict, $diagnosis_type) + $crate::output::Diagnosis::builder($verdict, $diagnosis_type) .source(file!(), line!() as i32) .build(), ) diff --git a/src/output/measure.rs b/src/output/measure.rs index 06581e3..a697925 100644 --- a/src/output/measure.rs +++ b/src/output/measure.rs @@ -336,7 +336,7 @@ impl ValidatorBuilder { fn new(validator_type: spec::ValidatorType, value: tv::Value) -> Self { ValidatorBuilder { validator_type, - value: value.clone(), + value, name: None, metadata: BTreeMap::new(), } @@ -346,7 +346,7 @@ impl ValidatorBuilder { self } pub fn add_metadata(mut self, key: &str, value: tv::Value) -> ValidatorBuilder { - self.metadata.insert(key.to_string(), value.clone()); + self.metadata.insert(key.to_string(), value); self } @@ -380,10 +380,10 @@ impl ValidatorBuilder { /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// /// let measurement = Measurement::builder("name", 50.into()) -/// .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) +/// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()) /// .add_metadata("key", "value".into()) /// .hardware_info(&hw_info) -/// .subcomponent(&Subcomponent::builder("name").build()) +/// .subcomponent(Subcomponent::builder("name").build()) /// .build(); /// ``` #[derive(Default)] @@ -392,7 +392,7 @@ pub struct Measurement { value: tv::Value, unit: Option, - validators: Option>, + validators: Vec, hardware_info: Option, subcomponent: Option, @@ -412,7 +412,7 @@ impl Measurement { pub fn new(name: &str, value: tv::Value) -> Self { Measurement { name: name.to_string(), - value: value.clone(), + value, ..Default::default() } } @@ -428,10 +428,10 @@ impl Measurement { /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// /// let measurement = Measurement::builder("name", 50.into()) - /// .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) + /// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()) /// .add_metadata("key", "value".into()) /// .hardware_info(&hw_info) - /// .subcomponent(&Subcomponent::builder("name").build()) + /// .subcomponent(Subcomponent::builder("name").build()) /// .build(); /// ``` pub fn builder(name: &str, value: tv::Value) -> MeasurementBuilder { @@ -452,10 +452,7 @@ impl Measurement { name: self.name.clone(), unit: self.unit.clone(), value: self.value.clone(), - validators: self - .validators - .clone() - .map(|vals| vals.iter().map(|val| val.to_spec()).collect()), + validators: self.validators.map_option(Validator::to_spec), hardware_info: self .hardware_info .as_ref() @@ -479,10 +476,10 @@ impl Measurement { /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// /// let builder = MeasurementBuilder::new("name", 50.into()) -/// .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) +/// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()) /// .add_metadata("key", "value".into()) /// .hardware_info(&hw_info) -/// .subcomponent(&Subcomponent::builder("name").build()); +/// .subcomponent(Subcomponent::builder("name").build()); /// let measurement = builder.build(); /// ``` #[derive(Default)] @@ -491,7 +488,7 @@ pub struct MeasurementBuilder { value: tv::Value, unit: Option, - validators: Option>, + validators: Vec, hardware_info: Option, subcomponent: Option, @@ -511,7 +508,7 @@ impl MeasurementBuilder { pub fn new(name: &str, value: tv::Value) -> Self { MeasurementBuilder { name: name.to_string(), - value: value.clone(), + value, ..Default::default() } } @@ -523,16 +520,10 @@ impl MeasurementBuilder { /// ``` /// # use ocptv::output::*; /// let builder = MeasurementBuilder::new("name", 50.into()) - /// .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()); + /// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()); /// ``` - pub fn add_validator(mut self, validator: &Validator) -> MeasurementBuilder { - self.validators = match self.validators { - Some(mut validators) => { - validators.push(validator.clone()); - Some(validators) - } - None => Some(vec![validator.clone()]), - }; + pub fn add_validator(mut self, validator: Validator) -> MeasurementBuilder { + self.validators.push(validator.clone()); self } @@ -560,10 +551,10 @@ impl MeasurementBuilder { /// ``` /// # use ocptv::output::*; /// let builder = MeasurementBuilder::new("name", 50.into()) - /// .subcomponent(&Subcomponent::builder("name").build()); + /// .subcomponent(Subcomponent::builder("name").build()); /// ``` - pub fn subcomponent(mut self, subcomponent: &dut::Subcomponent) -> MeasurementBuilder { - self.subcomponent = Some(subcomponent.clone()); + pub fn subcomponent(mut self, subcomponent: dut::Subcomponent) -> MeasurementBuilder { + self.subcomponent = Some(subcomponent); self } @@ -577,7 +568,7 @@ impl MeasurementBuilder { /// MeasurementBuilder::new("name", 50.into()).add_metadata("key", "value".into()); /// ``` pub fn add_metadata(mut self, key: &str, value: tv::Value) -> MeasurementBuilder { - self.metadata.insert(key.to_string(), value.clone()); + self.metadata.insert(key.to_string(), value); self } @@ -678,8 +669,8 @@ impl MeasurementSeriesInfoBuilder { self } - pub fn add_validator(mut self, validator: &Validator) -> MeasurementSeriesInfoBuilder { - self.validators.push(validator.clone()); + pub fn add_validator(mut self, validator: Validator) -> MeasurementSeriesInfoBuilder { + self.validators.push(validator); self } @@ -691,16 +682,13 @@ impl MeasurementSeriesInfoBuilder { self } - pub fn subcomponent( - mut self, - subcomponent: &dut::Subcomponent, - ) -> MeasurementSeriesInfoBuilder { - self.subcomponent = Some(subcomponent.clone()); + pub fn subcomponent(mut self, subcomponent: dut::Subcomponent) -> MeasurementSeriesInfoBuilder { + self.subcomponent = Some(subcomponent); self } pub fn add_metadata(mut self, key: &str, value: tv::Value) -> MeasurementSeriesInfoBuilder { - self.metadata.insert(key.to_string(), value.clone()); + self.metadata.insert(key.to_string(), value); self } @@ -771,10 +759,10 @@ mod tests { let unit = "RPM"; let measurement = Measurement::builder(&name, value.clone()) .unit(unit) - .add_validator(&validator) - .add_validator(&validator) + .add_validator(validator.clone()) + .add_validator(validator.clone()) .hardware_info(&hw_info) - .subcomponent(&subcomponent) + .subcomponent(subcomponent.clone()) .add_metadata(meta_key, meta_value.clone()) .build(); diff --git a/src/output/run.rs b/src/output/run.rs index 6d184b1..b938304 100644 --- a/src/output/run.rs +++ b/src/output/run.rs @@ -149,7 +149,7 @@ impl TestRun { pub async fn add_error(&self, symptom: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).build(); - self.add_error_with_details(&error).await?; + self.add_error_with_details(error).await?; Ok(()) } @@ -162,7 +162,7 @@ impl TestRun { pub async fn add_error_with_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).message(msg).build(); - self.add_error_with_details(&error).await?; + self.add_error_with_details(error).await?; Ok(()) } @@ -172,7 +172,7 @@ impl TestRun { /// (eg. failing to discover a DUT). /// /// See: [`StartedTestRun::add_error_with_details`] for details and examples. - pub async fn add_error_with_details(&self, error: &error::Error) -> Result<(), tv::OcptvError> { + pub async fn add_error_with_details(&self, error: error::Error) -> Result<(), tv::OcptvError> { let artifact = spec::TestRunArtifact { artifact: spec::TestRunArtifactImpl::Error(error.to_artifact()), }; @@ -218,7 +218,7 @@ impl TestRunBuilder { /// .build(); /// ``` pub fn add_parameter(mut self, key: &str, value: tv::Value) -> TestRunBuilder { - self.parameters.insert(key.to_string(), value.clone()); + self.parameters.insert(key.to_string(), value); self } @@ -265,7 +265,7 @@ impl TestRunBuilder { /// .build(); /// ``` pub fn add_metadata(mut self, key: &str, value: tv::Value) -> TestRunBuilder { - self.metadata.insert(key.to_string(), value.clone()); + self.metadata.insert(key.to_string(), value); self } @@ -384,7 +384,7 @@ impl StartedTestRun { /// let dut = DutInfo::builder("my_dut").build(); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// run.add_log_with_details( - /// &Log::builder("This is a log message with INFO severity") + /// Log::builder("This is a log message with INFO severity") /// .severity(LogSeverity::Info) /// .source("file", 1) /// .build(), @@ -394,7 +394,7 @@ impl StartedTestRun { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_log_with_details(&self, log: &log::Log) -> Result<(), tv::OcptvError> { + pub async fn add_log_with_details(&self, log: log::Log) -> Result<(), tv::OcptvError> { let artifact = spec::TestRunArtifact { artifact: spec::TestRunArtifactImpl::Log(log.to_artifact()), }; @@ -427,7 +427,7 @@ impl StartedTestRun { pub async fn add_error(&self, symptom: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).build(); - self.add_error_with_details(&error).await?; + self.add_error_with_details(error).await?; Ok(()) } @@ -453,7 +453,7 @@ impl StartedTestRun { pub async fn add_error_with_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).message(msg).build(); - self.add_error_with_details(&error).await?; + self.add_error_with_details(error).await?; Ok(()) } @@ -472,7 +472,7 @@ impl StartedTestRun { /// let run = TestRun::builder("diagnostic_name", "1.0").build().start(dut).await?; /// /// run.add_error_with_details( - /// &Error::builder("symptom") + /// Error::builder("symptom") /// .message("Error message") /// .source("file", 1) /// .add_software_info(&sw_info) @@ -484,7 +484,7 @@ impl StartedTestRun { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_error_with_details(&self, error: &error::Error) -> Result<(), tv::OcptvError> { + pub async fn add_error_with_details(&self, error: error::Error) -> Result<(), tv::OcptvError> { let artifact = spec::TestRunArtifact { artifact: spec::TestRunArtifactImpl::Error(error.to_artifact()), }; diff --git a/src/output/step.rs b/src/output/step.rs index 301f4fc..54c75d7 100644 --- a/src/output/step.rs +++ b/src/output/step.rs @@ -213,7 +213,7 @@ impl StartedTestStep { /// /// let step = run.add_step("step_name").start().await?; /// step.add_log_with_details( - /// &Log::builder("This is a log message with INFO severity") + /// Log::builder("This is a log message with INFO severity") /// .severity(LogSeverity::Info) /// .source("file", 1) /// .build(), @@ -223,7 +223,7 @@ impl StartedTestStep { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_log_with_details(&self, log: &log::Log) -> Result<(), tv::OcptvError> { + pub async fn add_log_with_details(&self, log: log::Log) -> Result<(), tv::OcptvError> { self.step .emitter .emit(&TestStepArtifactImpl::Log(log.to_artifact())) @@ -347,7 +347,7 @@ impl StartedTestStep { /// /// let step = run.add_step("step_name").start().await?; /// step.add_error_with_details( - /// &Error::builder("symptom") + /// Error::builder("symptom") /// .message("Error message") /// .source("file", 1) /// .add_software_info(&sw_info) @@ -358,7 +358,7 @@ impl StartedTestStep { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_error_with_details(&self, error: &error::Error) -> Result<(), tv::OcptvError> { + pub async fn add_error_with_details(&self, error: error::Error) -> Result<(), tv::OcptvError> { self.step .emitter .emit(&TestStepArtifactImpl::Error(error.to_artifact())) @@ -454,12 +454,12 @@ impl StartedTestStep { /// let step = run.add_step("step_name").start().await?; /// /// let measurement = Measurement::builder("name", 5000.into()) - /// .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) + /// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()) /// .add_metadata("key", "value".into()) /// .hardware_info(&hw_info) - /// .subcomponent(&Subcomponent::builder("name").build()) + /// .subcomponent(Subcomponent::builder("name").build()) /// .build(); - /// step.add_measurement_with_details(&measurement).await?; + /// step.add_measurement_with_details(measurement).await?; /// /// step.end(TestStatus::Complete).await?; /// @@ -468,7 +468,7 @@ impl StartedTestStep { /// ``` pub async fn add_measurement_with_details( &self, - measurement: &measure::Measurement, + measurement: measure::Measurement, ) -> Result<(), tv::OcptvError> { self.step .emitter @@ -595,7 +595,7 @@ impl StartedTestStep { /// .subcomponent(&Subcomponent::builder("name").build()) /// .source("file.rs", 1) /// .build(); - /// step.diagnosis_with_details(&diagnosis).await?; + /// step.diagnosis_with_details(diagnosis).await?; /// /// step.end(TestStatus::Complete).await?; /// @@ -604,7 +604,7 @@ impl StartedTestStep { /// ``` pub async fn diagnosis_with_details( &self, - diagnosis: &diagnosis::Diagnosis, + diagnosis: diagnosis::Diagnosis, ) -> Result<(), tv::OcptvError> { self.step .emitter diff --git a/tests/output/diagnosis.rs b/tests/output/diagnosis.rs index 22bef87..ba43c10 100644 --- a/tests/output/diagnosis.rs +++ b/tests/output/diagnosis.rs @@ -77,7 +77,7 @@ async fn test_step_with_diagnosis_builder() -> Result<()> { .subcomponent(&Subcomponent::builder("name").build()) .message("message") .build(); - s.diagnosis_with_details(&diagnosis).await?; + s.diagnosis_with_details(diagnosis).await?; Ok(()) } diff --git a/tests/output/error.rs b/tests/output/error.rs index 3f5370b..2ce389c 100644 --- a/tests/output/error.rs +++ b/tests/output/error.rs @@ -87,7 +87,7 @@ async fn test_testrun_with_error_with_details() -> Result<()> { check_output_run(&expected, |r, dut| { async move { r.add_error_with_details( - &Error::builder("symptom") + Error::builder("symptom") .message("Error message") .source("file", 1) .add_software_info(dut.software_info("sw0").unwrap()) // must exist @@ -180,7 +180,7 @@ async fn test_testrun_with_error_with_details_before_start() -> Result<()> { async move { let run = run_builder.build(); run.add_error_with_details( - &Error::builder("no-dut") + Error::builder("no-dut") .message("failed to find dut") .source("file", 1) .build(), @@ -288,7 +288,7 @@ async fn test_testrun_step_error_with_details() -> Result<()> { check_output_step(&expected, |s, dut| { async move { s.add_error_with_details( - &Error::builder("symptom") + Error::builder("symptom") .message("Error message") .source("file", 1) .add_software_info(dut.software_info("sw0").unwrap()) diff --git a/tests/output/log.rs b/tests/output/log.rs index 9f54392..97cc5ec 100644 --- a/tests/output/log.rs +++ b/tests/output/log.rs @@ -68,7 +68,7 @@ async fn test_testrun_with_log_with_details() -> Result<()> { check_output_run(&expected, |r, _| { async { r.add_log_with_details( - &Log::builder("This is a log message with INFO severity") + Log::builder("This is a log message with INFO severity") .severity(LogSeverity::Info) .source("file", 1) .build(), @@ -144,7 +144,7 @@ async fn test_testrun_step_log_with_details() -> Result<()> { check_output_step(&expected, |s, _| { async { s.add_log_with_details( - &Log::builder("This is a log message with INFO severity") + Log::builder("This is a log message with INFO severity") .severity(LogSeverity::Info) .source("file", 1) .build(), diff --git a/tests/output/measure.rs b/tests/output/measure.rs index d0fa0a0..fa08c6b 100644 --- a/tests/output/measure.rs +++ b/tests/output/measure.rs @@ -85,13 +85,13 @@ async fn test_step_with_measurement_builder() -> Result<()> { let hw_info = dut.hardware_info("hw0").unwrap(); // must exist let measurement = Measurement::builder("name", 50.into()) - .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) + .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()) .add_metadata("key", "value".into()) .add_metadata("key2", "value2".into()) .hardware_info(hw_info) - .subcomponent(&Subcomponent::builder("name").build()) + .subcomponent(Subcomponent::builder("name").build()) .build(); - s.add_measurement_with_details(&measurement).await?; + s.add_measurement_with_details(measurement).await?; Ok(()) } @@ -269,9 +269,9 @@ async fn test_step_with_measurement_series_with_details() -> Result<()> { .unit("unit") .add_metadata("key", "value".into()) .add_metadata("key2", "value2".into()) - .add_validator(&Validator::builder(ValidatorType::Equal, 30.into()).build()) + .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()) .hardware_info(hw_info) - .subcomponent(&Subcomponent::builder("name").build()) + .subcomponent(Subcomponent::builder("name").build()) .build(), ) .start() From b4358a0ae52cc4683562f3597fb1de19d207e58d Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 13:54:47 +0100 Subject: [PATCH 7/9] disallow user to instantiate builders directly - this simplifies the api by providing a single way to make builders Signed-off-by: mimir-d --- src/output/diagnosis.rs | 28 +++++++------------ src/output/dut.rs | 48 +++++++++++++++---------------- src/output/error.rs | 6 ++-- src/output/log.rs | 4 +-- src/output/measure.rs | 62 +++++++++++++++++------------------------ src/output/mod.rs | 6 ++-- src/output/run.rs | 18 ++++++------ 7 files changed, 77 insertions(+), 95 deletions(-) diff --git a/src/output/diagnosis.rs b/src/output/diagnosis.rs index 89c0507..9333427 100644 --- a/src/output/diagnosis.rs +++ b/src/output/diagnosis.rs @@ -142,15 +142,7 @@ pub struct DiagnosisBuilder { } impl DiagnosisBuilder { - /// Creates a new DiagnosisBuilder. - /// - /// # Examples - /// - /// ``` - /// # use ocptv::output::*; - /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass); - /// ``` - pub fn new(verdict: &str, diagnosis_type: spec::DiagnosisType) -> Self { + fn new(verdict: &str, diagnosis_type: spec::DiagnosisType) -> Self { DiagnosisBuilder { verdict: verdict.to_owned(), diagnosis_type, @@ -164,10 +156,10 @@ impl DiagnosisBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass) + /// let builder = Diagnosis::builder("verdict", DiagnosisType::Pass) /// .message("message"); /// ``` - pub fn message(mut self, message: &str) -> DiagnosisBuilder { + pub fn message(mut self, message: &str) -> Self { self.message = Some(message.to_owned()); self } @@ -181,10 +173,10 @@ impl DiagnosisBuilder { /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// - /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass) + /// let builder = Diagnosis::builder("verdict", DiagnosisType::Pass) /// .hardware_info(&hw_info); /// ``` - pub fn hardware_info(mut self, hardware_info: &dut::DutHardwareInfo) -> DiagnosisBuilder { + pub fn hardware_info(mut self, hardware_info: &dut::DutHardwareInfo) -> Self { self.hardware_info = Some(hardware_info.clone()); self } @@ -195,10 +187,10 @@ impl DiagnosisBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass) + /// let builder = Diagnosis::builder("verdict", DiagnosisType::Pass) /// .subcomponent(&Subcomponent::builder("name").build()); /// ``` - pub fn subcomponent(mut self, subcomponent: &dut::Subcomponent) -> DiagnosisBuilder { + pub fn subcomponent(mut self, subcomponent: &dut::Subcomponent) -> Self { self.subcomponent = Some(subcomponent.clone()); self } @@ -209,10 +201,10 @@ impl DiagnosisBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass) + /// let builder = Diagnosis::builder("verdict", DiagnosisType::Pass) /// .source("file.rs", 1); /// ``` - pub fn source(mut self, file: &str, line: i32) -> DiagnosisBuilder { + pub fn source(mut self, file: &str, line: i32) -> Self { self.source_location = Some(spec::SourceLocation { file: file.to_owned(), line, @@ -226,7 +218,7 @@ impl DiagnosisBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = DiagnosisBuilder::new("verdict", DiagnosisType::Pass); + /// let builder = Diagnosis::builder("verdict", DiagnosisType::Pass); /// let diagnosis = builder.build(); /// ``` pub fn build(self) -> Diagnosis { diff --git a/src/output/dut.rs b/src/output/dut.rs index 4a82a5a..f49a99e 100644 --- a/src/output/dut.rs +++ b/src/output/dut.rs @@ -92,24 +92,24 @@ pub struct DutInfoBuilder { } impl DutInfoBuilder { - pub fn new(id: &str) -> DutInfoBuilder { + fn new(id: &str) -> Self { DutInfoBuilder { id: id.to_string(), ..Default::default() } } - pub fn name(mut self, value: &str) -> DutInfoBuilder { + pub fn name(mut self, value: &str) -> Self { self.name = Some(value.to_string()); self } - pub fn add_platform_info(mut self, platform_info: PlatformInfo) -> DutInfoBuilder { + pub fn add_platform_info(mut self, platform_info: PlatformInfo) -> Self { self.platform_infos.push(platform_info); self } - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> DutInfoBuilder { + pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { self.metadata.insert(key.to_string(), value); self } @@ -170,19 +170,19 @@ impl SubcomponentBuilder { revision: None, } } - pub fn subcomponent_type(mut self, value: spec::SubcomponentType) -> SubcomponentBuilder { + pub fn subcomponent_type(mut self, value: spec::SubcomponentType) -> Self { self.subcomponent_type = Some(value); self } - pub fn version(mut self, value: &str) -> SubcomponentBuilder { + pub fn version(mut self, value: &str) -> Self { self.version = Some(value.to_string()); self } - pub fn location(mut self, value: &str) -> SubcomponentBuilder { + pub fn location(mut self, value: &str) -> Self { self.location = Some(value.to_string()); self } - pub fn revision(mut self, value: &str) -> SubcomponentBuilder { + pub fn revision(mut self, value: &str) -> Self { self.revision = Some(value.to_string()); self } @@ -305,27 +305,27 @@ impl SoftwareInfoBuilder { } } - pub fn id(mut self, value: tv::Ident) -> SoftwareInfoBuilder { + pub fn id(mut self, value: tv::Ident) -> Self { self.id = value; self } - pub fn version(mut self, value: &str) -> SoftwareInfoBuilder { + pub fn version(mut self, value: &str) -> Self { self.version = Some(value.to_string()); self } - pub fn revision(mut self, value: &str) -> SoftwareInfoBuilder { + pub fn revision(mut self, value: &str) -> Self { self.revision = Some(value.to_string()); self } - pub fn software_type(mut self, value: spec::SoftwareType) -> SoftwareInfoBuilder { + pub fn software_type(mut self, value: spec::SoftwareType) -> Self { self.software_type = Some(value); self } - pub fn computer_system(mut self, value: &str) -> SoftwareInfoBuilder { + pub fn computer_system(mut self, value: &str) -> Self { self.computer_system = Some(value.to_string()); self } @@ -428,57 +428,57 @@ impl HardwareInfoBuilder { } } - pub fn id(mut self, value: tv::Ident) -> HardwareInfoBuilder { + pub fn id(mut self, value: tv::Ident) -> Self { self.id = value; self } - pub fn version(mut self, value: &str) -> HardwareInfoBuilder { + pub fn version(mut self, value: &str) -> Self { self.version = Some(value.to_string()); self } - pub fn revision(mut self, value: &str) -> HardwareInfoBuilder { + pub fn revision(mut self, value: &str) -> Self { self.revision = Some(value.to_string()); self } - pub fn location(mut self, value: &str) -> HardwareInfoBuilder { + pub fn location(mut self, value: &str) -> Self { self.location = Some(value.to_string()); self } - pub fn serial_no(mut self, value: &str) -> HardwareInfoBuilder { + pub fn serial_no(mut self, value: &str) -> Self { self.serial_no = Some(value.to_string()); self } - pub fn part_no(mut self, value: &str) -> HardwareInfoBuilder { + pub fn part_no(mut self, value: &str) -> Self { self.part_no = Some(value.to_string()); self } - pub fn manufacturer(mut self, value: &str) -> HardwareInfoBuilder { + pub fn manufacturer(mut self, value: &str) -> Self { self.manufacturer = Some(value.to_string()); self } - pub fn manufacturer_part_no(mut self, value: &str) -> HardwareInfoBuilder { + pub fn manufacturer_part_no(mut self, value: &str) -> Self { self.manufacturer_part_no = Some(value.to_string()); self } - pub fn odata_id(mut self, value: &str) -> HardwareInfoBuilder { + pub fn odata_id(mut self, value: &str) -> Self { self.odata_id = Some(value.to_string()); self } - pub fn computer_system(mut self, value: &str) -> HardwareInfoBuilder { + pub fn computer_system(mut self, value: &str) -> Self { self.computer_system = Some(value.to_string()); self } - pub fn manager(mut self, value: &str) -> HardwareInfoBuilder { + pub fn manager(mut self, value: &str) -> Self { self.manager = Some(value.to_string()); self } diff --git a/src/output/error.rs b/src/output/error.rs index 3589cf4..764a96c 100644 --- a/src/output/error.rs +++ b/src/output/error.rs @@ -49,12 +49,12 @@ impl ErrorBuilder { } } - pub fn message(mut self, value: &str) -> ErrorBuilder { + pub fn message(mut self, value: &str) -> Self { self.message = Some(value.to_string()); self } - pub fn source(mut self, file: &str, line: i32) -> ErrorBuilder { + pub fn source(mut self, file: &str, line: i32) -> Self { self.source_location = Some(spec::SourceLocation { file: file.to_string(), line, @@ -62,7 +62,7 @@ impl ErrorBuilder { self } - pub fn add_software_info(mut self, software_info: &dut::DutSoftwareInfo) -> ErrorBuilder { + pub fn add_software_info(mut self, software_info: &dut::DutSoftwareInfo) -> Self { self.software_infos.push(software_info.clone()); self } diff --git a/src/output/log.rs b/src/output/log.rs index dec9d4a..f39ad90 100644 --- a/src/output/log.rs +++ b/src/output/log.rs @@ -43,11 +43,11 @@ impl LogBuilder { source_location: None, } } - pub fn severity(mut self, value: spec::LogSeverity) -> LogBuilder { + pub fn severity(mut self, value: spec::LogSeverity) -> Self { self.severity = value; self } - pub fn source(mut self, file: &str, line: i32) -> LogBuilder { + pub fn source(mut self, file: &str, line: i32) -> Self { self.source_location = Some(spec::SourceLocation { file: file.to_string(), line, diff --git a/src/output/measure.rs b/src/output/measure.rs index a697925..cc32d55 100644 --- a/src/output/measure.rs +++ b/src/output/measure.rs @@ -273,7 +273,7 @@ pub struct MeasurementSeriesElemDetailsBuilder { } impl MeasurementSeriesElemDetailsBuilder { - pub fn new(value: tv::Value) -> Self { + fn new(value: tv::Value) -> Self { Self { value, ..Default::default() @@ -312,6 +312,7 @@ impl Validator { pub fn builder(validator_type: spec::ValidatorType, value: tv::Value) -> ValidatorBuilder { ValidatorBuilder::new(validator_type, value) } + pub fn to_spec(&self) -> spec::Validator { spec::Validator { name: self.name.clone(), @@ -341,11 +342,13 @@ impl ValidatorBuilder { metadata: BTreeMap::new(), } } - pub fn name(mut self, value: &str) -> ValidatorBuilder { + + pub fn name(mut self, value: &str) -> Self { self.name = Some(value.to_string()); self } - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> ValidatorBuilder { + + pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { self.metadata.insert(key.to_string(), value); self } @@ -475,7 +478,7 @@ impl Measurement { /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// -/// let builder = MeasurementBuilder::new("name", 50.into()) +/// let builder = Measurement::builder("name", 50.into()) /// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()) /// .add_metadata("key", "value".into()) /// .hardware_info(&hw_info) @@ -497,15 +500,7 @@ pub struct MeasurementBuilder { } impl MeasurementBuilder { - /// Creates a new MeasurementBuilder. - /// - /// # Examples - /// - /// ``` - /// # use ocptv::output::*; - /// let builder = MeasurementBuilder::new("name", 50.into()); - /// ``` - pub fn new(name: &str, value: tv::Value) -> Self { + fn new(name: &str, value: tv::Value) -> Self { MeasurementBuilder { name: name.to_string(), value, @@ -519,10 +514,10 @@ impl MeasurementBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = MeasurementBuilder::new("name", 50.into()) + /// let builder = Measurement::builder("name", 50.into()) /// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()); /// ``` - pub fn add_validator(mut self, validator: Validator) -> MeasurementBuilder { + pub fn add_validator(mut self, validator: Validator) -> Self { self.validators.push(validator.clone()); self } @@ -536,10 +531,10 @@ impl MeasurementBuilder { /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// - /// let builder = MeasurementBuilder::new("name", 50.into()) + /// let builder = Measurement::builder("name", 50.into()) /// .hardware_info(&hw_info); /// ``` - pub fn hardware_info(mut self, hardware_info: &dut::DutHardwareInfo) -> MeasurementBuilder { + pub fn hardware_info(mut self, hardware_info: &dut::DutHardwareInfo) -> Self { self.hardware_info = Some(hardware_info.clone()); self } @@ -550,10 +545,10 @@ impl MeasurementBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = MeasurementBuilder::new("name", 50.into()) + /// let builder = Measurement::builder("name", 50.into()) /// .subcomponent(Subcomponent::builder("name").build()); /// ``` - pub fn subcomponent(mut self, subcomponent: dut::Subcomponent) -> MeasurementBuilder { + pub fn subcomponent(mut self, subcomponent: dut::Subcomponent) -> Self { self.subcomponent = Some(subcomponent); self } @@ -565,9 +560,9 @@ impl MeasurementBuilder { /// ``` /// # use ocptv::output::*; /// let builder = - /// MeasurementBuilder::new("name", 50.into()).add_metadata("key", "value".into()); + /// Measurement::builder("name", 50.into()).add_metadata("key", "value".into()); /// ``` - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> MeasurementBuilder { + pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { self.metadata.insert(key.to_string(), value); self } @@ -578,7 +573,7 @@ impl MeasurementBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = MeasurementBuilder::new("name", 50000.into()).unit("RPM"); + /// let builder = Measurement::builder("name", 50000.into()).unit("RPM"); /// ``` pub fn unit(mut self, unit: &str) -> MeasurementBuilder { self.unit = Some(unit.to_string()); @@ -590,10 +585,8 @@ impl MeasurementBuilder { /// # Examples /// /// ``` - /// use ocptv::output::MeasurementBuilder; - /// use ocptv::output::Value; - /// - /// let builder = MeasurementBuilder::new("name", 50.into()); + /// # use ocptv::output::*; + /// let builder = Measurement::builder("name", 50.into()); /// let measurement = builder.build(); /// ``` pub fn build(self) -> Measurement { @@ -651,7 +644,7 @@ pub struct MeasurementSeriesInfoBuilder { } impl MeasurementSeriesInfoBuilder { - pub fn new(name: &str) -> Self { + fn new(name: &str) -> Self { MeasurementSeriesInfoBuilder { id: Ident::Auto, name: name.to_string(), @@ -659,35 +652,32 @@ impl MeasurementSeriesInfoBuilder { } } - pub fn id(mut self, id: tv::Ident) -> MeasurementSeriesInfoBuilder { + pub fn id(mut self, id: tv::Ident) -> Self { self.id = id; self } - pub fn unit(mut self, unit: &str) -> MeasurementSeriesInfoBuilder { + pub fn unit(mut self, unit: &str) -> Self { self.unit = Some(unit.to_string()); self } - pub fn add_validator(mut self, validator: Validator) -> MeasurementSeriesInfoBuilder { + pub fn add_validator(mut self, validator: Validator) -> Self { self.validators.push(validator); self } - pub fn hardware_info( - mut self, - hardware_info: &dut::DutHardwareInfo, - ) -> MeasurementSeriesInfoBuilder { + pub fn hardware_info(mut self, hardware_info: &dut::DutHardwareInfo) -> Self { self.hardware_info = Some(hardware_info.clone()); self } - pub fn subcomponent(mut self, subcomponent: dut::Subcomponent) -> MeasurementSeriesInfoBuilder { + pub fn subcomponent(mut self, subcomponent: dut::Subcomponent) -> Self { self.subcomponent = Some(subcomponent); self } - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> MeasurementSeriesInfoBuilder { + pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { self.metadata.insert(key.to_string(), value); self } diff --git a/src/output/mod.rs b/src/output/mod.rs index 25970f2..27c2d20 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -33,8 +33,8 @@ pub use error::{Error, ErrorBuilder}; pub use log::{Log, LogBuilder}; pub use measure::{ Measurement, MeasurementBuilder, MeasurementSeries, MeasurementSeriesElemDetails, - MeasurementSeriesInfo, MeasurementSeriesInfoBuilder, StartedMeasurementSeries, Validator, - ValidatorBuilder, + MeasurementSeriesElemDetailsBuilder, MeasurementSeriesInfo, MeasurementSeriesInfoBuilder, + StartedMeasurementSeries, Validator, ValidatorBuilder, }; pub use run::{StartedTestRun, TestRun, TestRunBuilder, TestRunOutcome}; pub use step::{StartedTestStep, TestStep}; @@ -43,7 +43,7 @@ pub use writer::{BufferWriter, FileWriter, StdoutWriter, Writer}; // re-export this as a public type we present pub use serde_json::Value; -/// TODO: docs +// TODO: docs #[derive(Debug, thiserror::Error)] #[non_exhaustive] pub enum OcptvError { diff --git a/src/output/run.rs b/src/output/run.rs index b938304..66f5d7c 100644 --- a/src/output/run.rs +++ b/src/output/run.rs @@ -197,7 +197,7 @@ pub struct TestRunBuilder { } impl TestRunBuilder { - pub fn new(name: &str, version: &str) -> Self { + fn new(name: &str, version: &str) -> Self { Self { name: name.to_string(), version: version.to_string(), @@ -213,11 +213,11 @@ impl TestRunBuilder { /// /// ```rust /// # use ocptv::output::*; - /// let run = TestRunBuilder::new("run_name", "1.0") + /// let run = TestRun::builder("run_name", "1.0") /// .add_parameter("param1", "value1".into()) /// .build(); /// ``` - pub fn add_parameter(mut self, key: &str, value: tv::Value) -> TestRunBuilder { + pub fn add_parameter(mut self, key: &str, value: tv::Value) -> Self { self.parameters.insert(key.to_string(), value); self } @@ -229,11 +229,11 @@ impl TestRunBuilder { /// /// ```rust /// # use ocptv::output::*; - /// let run = TestRunBuilder::new("run_name", "1.0") + /// let run = TestRun::builder("run_name", "1.0") /// .command_line("my_diag --arg value") /// .build(); /// ``` - pub fn command_line(mut self, cmd: &str) -> TestRunBuilder { + pub fn command_line(mut self, cmd: &str) -> Self { self.command_line = cmd.to_string(); self } @@ -244,11 +244,11 @@ impl TestRunBuilder { /// /// ```rust /// # use ocptv::output::*; - /// let run = TestRunBuilder::new("run_name", "1.0") + /// let run = TestRun::builder("run_name", "1.0") /// .config(Config::builder().build()) /// .build(); /// ``` - pub fn config(mut self, value: config::Config) -> TestRunBuilder { + pub fn config(mut self, value: config::Config) -> Self { self.config = Some(value); self } @@ -260,11 +260,11 @@ impl TestRunBuilder { /// ```rust /// # use ocptv::output::*; /// - /// let run = TestRunBuilder::new("run_name", "1.0") + /// let run = TestRun::builder("run_name", "1.0") /// .add_metadata("meta1", "value1".into()) /// .build(); /// ``` - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> TestRunBuilder { + pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { self.metadata.insert(key.to_string(), value); self } From d419646475c867e75624cf1164d890f7879fdbf9 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 13:56:26 +0100 Subject: [PATCH 8/9] make all the spec enums non_exhaustive - this was missing from a publicly exported DiagnosisType, which means that it risks breaking crate api if changed - for safety reasons, just make all the enums (private or public) non_exhaustive Signed-off-by: mimir-d --- src/spec.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/spec.rs b/src/spec.rs index 8424fe9..a0cb26a 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -111,6 +111,7 @@ pub enum SubcomponentType { /// /// schema ref: #[derive(Debug, Serialize, PartialEq, Clone, Default)] +#[non_exhaustive] pub enum DiagnosisType { #[serde(rename = "PASS")] #[default] @@ -217,6 +218,7 @@ pub struct Root { } #[derive(Debug, Serialize, PartialEq, Clone)] +#[non_exhaustive] pub enum RootImpl { #[serde(rename = "schemaVersion")] SchemaVersion(SchemaVersion), @@ -270,6 +272,7 @@ pub struct TestRunArtifact { } #[derive(Debug, Serialize, PartialEq, Clone)] +#[non_exhaustive] pub enum TestRunArtifactImpl { #[serde(rename = "testRunStart")] TestRunStart(TestRunStart), @@ -576,6 +579,7 @@ pub struct TestStepArtifact { #[allow(clippy::large_enum_variant)] #[derive(Debug, Serialize, PartialEq, Clone)] +#[non_exhaustive] pub enum TestStepArtifactImpl { #[serde(rename = "testStepStart")] TestStepStart(TestStepStart), From 359c60b9c807f5c1121f3cc30e7b3504ed668409 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Fri, 11 Oct 2024 14:13:05 +0100 Subject: [PATCH 9/9] shorten some method names - a bit less verbose - diagnosis was missing a verb Signed-off-by: mimir-d --- examples/error_with_dut.rs | 2 +- examples/measurement_series.rs | 20 ++++----- examples/measurement_single.rs | 2 +- examples/measurement_subcomponent.rs | 6 +-- examples/measurement_validators.rs | 8 ++-- src/output/macros.rs | 8 ++-- src/output/measure.rs | 62 ++++++++++++++-------------- src/output/mod.rs | 4 +- src/output/run.rs | 28 ++++++------- src/output/step.rs | 42 +++++++++---------- tests/output/config.rs | 2 +- tests/output/diagnosis.rs | 4 +- tests/output/error.rs | 13 +++--- tests/output/log.rs | 4 +- tests/output/measure.rs | 26 ++++++------ 15 files changed, 115 insertions(+), 116 deletions(-) diff --git a/examples/error_with_dut.rs b/examples/error_with_dut.rs index 6983090..76284fe 100644 --- a/examples/error_with_dut.rs +++ b/examples/error_with_dut.rs @@ -26,7 +26,7 @@ async fn main() -> Result<()> { .build() .scope(dut, |r| { async move { - r.add_error_with_details( + r.add_error_detail( tv::Error::builder("power-fail") .add_software_info(&sw_info) .build(), diff --git a/examples/measurement_series.rs b/examples/measurement_series.rs index cfb046a..06c00d5 100644 --- a/examples/measurement_series.rs +++ b/examples/measurement_series.rs @@ -14,8 +14,8 @@ use tv::{TestResult, TestStatus}; async fn step0_measurements(step: &tv::StartedTestStep) -> Result { let fan_speed = step - .add_measurement_series_with_details( - tv::MeasurementSeriesInfo::builder("fan_speed") + .add_measurement_series_detail( + tv::MeasurementSeriesDetail::builder("fan_speed") .unit("rpm") .build(), ) @@ -32,8 +32,8 @@ async fn step0_measurements(step: &tv::StartedTestStep) -> Result Result { - step.add_measurement_series_with_details( - tv::MeasurementSeriesInfo::builder("temp0") + step.add_measurement_series_detail( + tv::MeasurementSeriesDetail::builder("temp0") .unit("C") .build(), ) @@ -41,8 +41,8 @@ async fn step1_measurements(step: &tv::StartedTestStep) -> Result Result Result { let freq0 = step - .add_measurement_series_with_details( - tv::MeasurementSeriesInfo::builder("freq0") + .add_measurement_series_detail( + tv::MeasurementSeriesDetail::builder("freq0") .unit("hz") .build(), ) @@ -69,8 +69,8 @@ async fn step2_measurements(step: &tv::StartedTestStep) -> Result Result { step.add_measurement("temperature", 42.5.into()).await?; - step.add_measurement_with_details( + step.add_measurement_detail( tv::Measurement::builder("fan_speed", 1200.into()) .unit("rpm") .build(), diff --git a/examples/measurement_subcomponent.rs b/examples/measurement_subcomponent.rs index cceafef..63b14e0 100644 --- a/examples/measurement_subcomponent.rs +++ b/examples/measurement_subcomponent.rs @@ -15,7 +15,7 @@ async fn run_measure_step( step: &tv::StartedTestStep, ram0: tv::DutHardwareInfo, ) -> Result { - step.add_measurement_with_details( + step.add_measurement_detail( tv::Measurement::builder("temp0", 100.5.into()) .unit("F") .hardware_info(&ram0) @@ -24,8 +24,8 @@ async fn run_measure_step( ) .await?; - let chip1_temp = step.add_measurement_series_with_details( - tv::MeasurementSeriesInfo::builder("temp1") + let chip1_temp = step.add_measurement_series_detail( + tv::MeasurementSeriesDetail::builder("temp1") .unit("C") .hardware_info(&ram0) .subcomponent( diff --git a/examples/measurement_validators.rs b/examples/measurement_validators.rs index a1e0299..3b71e94 100644 --- a/examples/measurement_validators.rs +++ b/examples/measurement_validators.rs @@ -12,7 +12,7 @@ use ocptv::output as tv; use tv::{TestResult, TestStatus, ValidatorType}; async fn run_measure_step(step: &tv::StartedTestStep) -> Result { - step.add_measurement_with_details( + step.add_measurement_detail( tv::Measurement::builder("temp", 40.into()) .add_validator( tv::Validator::builder(ValidatorType::GreaterThan, 30.into()) @@ -23,8 +23,8 @@ async fn run_measure_step(step: &tv::StartedTestStep) -> Result Result { - $runner.add_error_with_details( + $runner.add_error_detail( $crate::output::Error::builder($symptom) .message($msg) .source(file!(), line!() as i32) @@ -64,7 +64,7 @@ macro_rules! ocptv_error { }; ($runner:expr, $symptom:expr) => { - $runner.add_error_with_details( + $runner.add_error_detail( $crate::output::Error::builder($symptom) .source(file!(), line!() as i32) .build(), @@ -105,7 +105,7 @@ macro_rules! ocptv_log { #[macro_export] macro_rules! $name { ($artifact:expr, $msg:expr) => { - $artifact.add_log_with_details( + $artifact.add_log_detail( $crate::output::Log::builder($msg) .severity($severity) .source(file!(), line!() as i32) @@ -159,7 +159,7 @@ macro_rules! ocptv_diagnosis { #[macro_export] macro_rules! $name { ($artifact:expr, $verdict:expr) => { - $artifact.diagnosis_with_details( + $artifact.add_diagnosis_detail( $crate::output::Diagnosis::builder($verdict, $diagnosis_type) .source(file!(), line!() as i32) .build(), diff --git a/src/output/measure.rs b/src/output/measure.rs index cc32d55..11620de 100644 --- a/src/output/measure.rs +++ b/src/output/measure.rs @@ -22,7 +22,7 @@ use tv::{dut, step, Ident}; /// ref: pub struct MeasurementSeries { id: String, - info: MeasurementSeriesInfo, + detail: MeasurementSeriesDetail, emitter: Arc, } @@ -32,12 +32,12 @@ impl MeasurementSeries { // instances through the `StartedTestStep.add_measurement_series_*` apis pub(crate) fn new( series_id: &str, - info: MeasurementSeriesInfo, + info: MeasurementSeriesDetail, emitter: Arc, ) -> Self { Self { id: series_id.to_owned(), - info, + detail: info, emitter, } } @@ -62,7 +62,7 @@ impl MeasurementSeries { /// # }); /// ``` pub async fn start(self) -> Result { - let info = &self.info; + let info = &self.detail; let start = spec::MeasurementSeriesStart { name: info.name.clone(), @@ -195,7 +195,7 @@ impl StartedMeasurementSeries { /// # }); /// ``` pub async fn add_measurement(&self, value: tv::Value) -> Result<(), tv::OcptvError> { - self.add_measurement_with_details(MeasurementSeriesElemDetails { + self.add_measurement_detail(MeasurementElementDetail { value, ..Default::default() }) @@ -217,24 +217,24 @@ impl StartedMeasurementSeries { /// let step = run.add_step("step_name").start().await?; /// /// let series = step.add_measurement_series("name").start().await?; - /// let elem = MeasurementSeriesElemDetails::builder(60.into()).add_metadata("key", "value".into()).build(); - /// series.add_measurement_with_details(elem).await?; + /// let elem = MeasurementElementDetail::builder(60.into()).add_metadata("key", "value".into()).build(); + /// series.add_measurement_detail(elem).await?; /// /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_measurement_with_details( + pub async fn add_measurement_detail( &self, - details: MeasurementSeriesElemDetails, + element: MeasurementElementDetail, ) -> Result<(), tv::OcptvError> { let element = spec::MeasurementSeriesElement { index: self.incr_seqno(), - value: details.value, - timestamp: details + value: element.value, + timestamp: element .timestamp .unwrap_or(self.parent.emitter.timestamp_provider().now()), series_id: self.parent.id.clone(), - metadata: details.metadata.option(), + metadata: element.metadata.option(), }; self.parent @@ -250,29 +250,29 @@ impl StartedMeasurementSeries { /// TODO: docs #[derive(Default)] -pub struct MeasurementSeriesElemDetails { +pub struct MeasurementElementDetail { value: tv::Value, timestamp: Option>, metadata: BTreeMap, } -impl MeasurementSeriesElemDetails { - pub fn builder(value: tv::Value) -> MeasurementSeriesElemDetailsBuilder { - MeasurementSeriesElemDetailsBuilder::new(value) +impl MeasurementElementDetail { + pub fn builder(value: tv::Value) -> MeasurementElementDetailBuilder { + MeasurementElementDetailBuilder::new(value) } } /// TODO: docs #[derive(Default)] -pub struct MeasurementSeriesElemDetailsBuilder { +pub struct MeasurementElementDetailBuilder { value: tv::Value, timestamp: Option>, metadata: BTreeMap, } -impl MeasurementSeriesElemDetailsBuilder { +impl MeasurementElementDetailBuilder { fn new(value: tv::Value) -> Self { Self { value, @@ -290,8 +290,8 @@ impl MeasurementSeriesElemDetailsBuilder { self } - pub fn build(self) -> MeasurementSeriesElemDetails { - MeasurementSeriesElemDetails { + pub fn build(self) -> MeasurementElementDetail { + MeasurementElementDetail { value: self.value, timestamp: self.timestamp, metadata: self.metadata, @@ -603,7 +603,7 @@ impl MeasurementBuilder { } /// TODO: docs -pub struct MeasurementSeriesInfo { +pub struct MeasurementSeriesDetail { // note: this object is crate public and we need access to this field // when making a new series in `StartedTestStep.add_measurement_series*` pub(crate) id: tv::Ident, @@ -618,19 +618,19 @@ pub struct MeasurementSeriesInfo { metadata: BTreeMap, } -impl MeasurementSeriesInfo { - pub fn new(name: &str) -> MeasurementSeriesInfo { - MeasurementSeriesInfoBuilder::new(name).build() +impl MeasurementSeriesDetail { + pub fn new(name: &str) -> MeasurementSeriesDetail { + MeasurementSeriesDetailBuilder::new(name).build() } - pub fn builder(name: &str) -> MeasurementSeriesInfoBuilder { - MeasurementSeriesInfoBuilder::new(name) + pub fn builder(name: &str) -> MeasurementSeriesDetailBuilder { + MeasurementSeriesDetailBuilder::new(name) } } /// TODO: docs #[derive(Default)] -pub struct MeasurementSeriesInfoBuilder { +pub struct MeasurementSeriesDetailBuilder { id: tv::Ident, name: String, @@ -643,9 +643,9 @@ pub struct MeasurementSeriesInfoBuilder { metadata: BTreeMap, } -impl MeasurementSeriesInfoBuilder { +impl MeasurementSeriesDetailBuilder { fn new(name: &str) -> Self { - MeasurementSeriesInfoBuilder { + MeasurementSeriesDetailBuilder { id: Ident::Auto, name: name.to_string(), ..Default::default() @@ -682,8 +682,8 @@ impl MeasurementSeriesInfoBuilder { self } - pub fn build(self) -> MeasurementSeriesInfo { - MeasurementSeriesInfo { + pub fn build(self) -> MeasurementSeriesDetail { + MeasurementSeriesDetail { id: self.id, name: self.name, unit: self.unit, diff --git a/src/output/mod.rs b/src/output/mod.rs index 27c2d20..362c9b2 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -32,8 +32,8 @@ pub use dut::{ pub use error::{Error, ErrorBuilder}; pub use log::{Log, LogBuilder}; pub use measure::{ - Measurement, MeasurementBuilder, MeasurementSeries, MeasurementSeriesElemDetails, - MeasurementSeriesElemDetailsBuilder, MeasurementSeriesInfo, MeasurementSeriesInfoBuilder, + Measurement, MeasurementBuilder, MeasurementElementDetail, MeasurementElementDetailBuilder, + MeasurementSeries, MeasurementSeriesDetail, MeasurementSeriesDetailBuilder, StartedMeasurementSeries, Validator, ValidatorBuilder, }; pub use run::{StartedTestRun, TestRun, TestRunBuilder, TestRunOutcome}; diff --git a/src/output/run.rs b/src/output/run.rs index 66f5d7c..3b5856d 100644 --- a/src/output/run.rs +++ b/src/output/run.rs @@ -149,7 +149,7 @@ impl TestRun { pub async fn add_error(&self, symptom: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).build(); - self.add_error_with_details(error).await?; + self.add_error_detail(error).await?; Ok(()) } @@ -158,11 +158,11 @@ impl TestRun { /// This operation is useful in such cases when there is an error before starting the test. /// (eg. failing to discover a DUT). /// - /// See: [`StartedTestRun::add_error_with_msg`] for details and examples. - pub async fn add_error_with_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError> { + /// See: [`StartedTestRun::add_error_msg`] for details and examples. + pub async fn add_error_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).message(msg).build(); - self.add_error_with_details(error).await?; + self.add_error_detail(error).await?; Ok(()) } @@ -171,8 +171,8 @@ impl TestRun { /// This operation is useful in such cases when there is an error before starting the test. /// (eg. failing to discover a DUT). /// - /// See: [`StartedTestRun::add_error_with_details`] for details and examples. - pub async fn add_error_with_details(&self, error: error::Error) -> Result<(), tv::OcptvError> { + /// See: [`StartedTestRun::add_error_detail`] for details and examples. + pub async fn add_error_detail(&self, error: error::Error) -> Result<(), tv::OcptvError> { let artifact = spec::TestRunArtifact { artifact: spec::TestRunArtifactImpl::Error(error.to_artifact()), }; @@ -383,7 +383,7 @@ impl StartedTestRun { /// # use ocptv::output::*; /// let dut = DutInfo::builder("my_dut").build(); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; - /// run.add_log_with_details( + /// run.add_log_detail( /// Log::builder("This is a log message with INFO severity") /// .severity(LogSeverity::Info) /// .source("file", 1) @@ -394,7 +394,7 @@ impl StartedTestRun { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_log_with_details(&self, log: log::Log) -> Result<(), tv::OcptvError> { + pub async fn add_log_detail(&self, log: log::Log) -> Result<(), tv::OcptvError> { let artifact = spec::TestRunArtifact { artifact: spec::TestRunArtifactImpl::Log(log.to_artifact()), }; @@ -427,7 +427,7 @@ impl StartedTestRun { pub async fn add_error(&self, symptom: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).build(); - self.add_error_with_details(error).await?; + self.add_error_detail(error).await?; Ok(()) } @@ -444,16 +444,16 @@ impl StartedTestRun { /// # use ocptv::output::*; /// let dut = DutInfo::builder("my_dut").build(); /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; - /// run.add_error_with_msg("symptom", "error messasge").await?; + /// run.add_error_msg("symptom", "error messasge").await?; /// run.end(TestStatus::Complete, TestResult::Pass).await?; /// /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_error_with_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError> { + pub async fn add_error_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).message(msg).build(); - self.add_error_with_details(error).await?; + self.add_error_detail(error).await?; Ok(()) } @@ -471,7 +471,7 @@ impl StartedTestRun { /// let sw_info = dut.add_software_info(SoftwareInfo::builder("name").build()); /// let run = TestRun::builder("diagnostic_name", "1.0").build().start(dut).await?; /// - /// run.add_error_with_details( + /// run.add_error_detail( /// Error::builder("symptom") /// .message("Error message") /// .source("file", 1) @@ -484,7 +484,7 @@ impl StartedTestRun { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_error_with_details(&self, error: error::Error) -> Result<(), tv::OcptvError> { + pub async fn add_error_detail(&self, error: error::Error) -> Result<(), tv::OcptvError> { let artifact = spec::TestRunArtifact { artifact: spec::TestRunArtifactImpl::Error(error.to_artifact()), }; diff --git a/src/output/step.rs b/src/output/step.rs index 54c75d7..5bb1488 100644 --- a/src/output/step.rs +++ b/src/output/step.rs @@ -212,7 +212,7 @@ impl StartedTestStep { /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// /// let step = run.add_step("step_name").start().await?; - /// step.add_log_with_details( + /// step.add_log_detail( /// Log::builder("This is a log message with INFO severity") /// .severity(LogSeverity::Info) /// .source("file", 1) @@ -223,7 +223,7 @@ impl StartedTestStep { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_log_with_details(&self, log: log::Log) -> Result<(), tv::OcptvError> { + pub async fn add_log_detail(&self, log: log::Log) -> Result<(), tv::OcptvError> { self.step .emitter .emit(&TestStepArtifactImpl::Log(log.to_artifact())) @@ -296,7 +296,7 @@ impl StartedTestStep { /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// /// let step = run.add_step("step_name").start().await?; - /// step.add_error_with_msg("symptom", "error message").await?; + /// step.add_error_msg("symptom", "error message").await?; /// step.end(TestStatus::Complete).await?; /// /// # Ok::<(), OcptvError>(()) @@ -320,7 +320,7 @@ impl StartedTestStep { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_error_with_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError> { + pub async fn add_error_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError> { let error = error::Error::builder(symptom).message(msg).build(); self.step @@ -346,7 +346,7 @@ impl StartedTestStep { /// let run = TestRun::builder("diagnostic_name", "1.0").build().start(dut).await?; /// /// let step = run.add_step("step_name").start().await?; - /// step.add_error_with_details( + /// step.add_error_detail( /// Error::builder("symptom") /// .message("Error message") /// .source("file", 1) @@ -358,7 +358,7 @@ impl StartedTestStep { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_error_with_details(&self, error: error::Error) -> Result<(), tv::OcptvError> { + pub async fn add_error_detail(&self, error: error::Error) -> Result<(), tv::OcptvError> { self.step .emitter .emit(&TestStepArtifactImpl::Error(error.to_artifact())) @@ -459,21 +459,21 @@ impl StartedTestStep { /// .hardware_info(&hw_info) /// .subcomponent(Subcomponent::builder("name").build()) /// .build(); - /// step.add_measurement_with_details(measurement).await?; + /// step.add_measurement_detail(measurement).await?; /// /// step.end(TestStatus::Complete).await?; /// /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_measurement_with_details( + pub async fn add_measurement_detail( &self, - measurement: measure::Measurement, + detail: measure::Measurement, ) -> Result<(), tv::OcptvError> { self.step .emitter .emit(&spec::TestStepArtifactImpl::Measurement( - measurement.to_artifact(), + detail.to_artifact(), )) .await?; @@ -499,11 +499,11 @@ impl StartedTestStep { /// # }); /// ``` pub fn add_measurement_series(&self, name: &str) -> tv::MeasurementSeries { - self.add_measurement_series_with_details(tv::MeasurementSeriesInfo::new(name)) + self.add_measurement_series_detail(tv::MeasurementSeriesDetail::new(name)) } /// Create a Measurement Series (a time-series list of measurements). - /// This method accepts a [`tv::MeasurementSeriesInfo`] object. + /// This method accepts a [`tv::MeasurementSeriesDetail`] object. /// /// ref: /// @@ -516,19 +516,19 @@ impl StartedTestStep { /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// let step = run.add_step("step_name").start().await?; /// let series = - /// step.add_measurement_series_with_details(MeasurementSeriesInfo::new("name")); + /// step.add_measurement_series_detail(MeasurementSeriesDetail::new("name")); /// /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub fn add_measurement_series_with_details( + pub fn add_measurement_series_detail( &self, - info: measure::MeasurementSeriesInfo, + detail: measure::MeasurementSeriesDetail, ) -> tv::MeasurementSeries { // spec says this identifier is unique in the scope of the test run, so create it from // the step identifier and a counter // ref: https://github.com/opencomputeproject/ocp-diag-core/blob/main/json_spec/README.md#measurementseriesstart - let series_id = match &info.id { + let series_id = match &detail.id { Ident::Auto => format!( "{}_series{}", self.step.emitter.step_id, @@ -537,7 +537,7 @@ impl StartedTestStep { Ident::Exact(value) => value.to_owned(), }; - tv::MeasurementSeries::new(&series_id, info, Arc::clone(&self.step.emitter)) + tv::MeasurementSeries::new(&series_id, detail, Arc::clone(&self.step.emitter)) } /// Emits a Diagnosis message. @@ -553,13 +553,13 @@ impl StartedTestStep { /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// /// let step = run.add_step("step_name").start().await?; - /// step.diagnosis("verdict", DiagnosisType::Pass).await?; + /// step.add_diagnosis("verdict", DiagnosisType::Pass).await?; /// step.end(TestStatus::Complete).await?; /// /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn diagnosis( + pub async fn add_diagnosis( &self, verdict: &str, diagnosis_type: spec::DiagnosisType, @@ -595,14 +595,14 @@ impl StartedTestStep { /// .subcomponent(&Subcomponent::builder("name").build()) /// .source("file.rs", 1) /// .build(); - /// step.diagnosis_with_details(diagnosis).await?; + /// step.add_diagnosis_detail(diagnosis).await?; /// /// step.end(TestStatus::Complete).await?; /// /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn diagnosis_with_details( + pub async fn add_diagnosis_detail( &self, diagnosis: diagnosis::Diagnosis, ) -> Result<(), tv::OcptvError> { diff --git a/tests/output/config.rs b/tests/output/config.rs index 75f0531..81f0c57 100644 --- a/tests/output/config.rs +++ b/tests/output/config.rs @@ -72,7 +72,7 @@ async fn test_config_builder_with_file() -> Result<()> { .start(dut) .await?; - run.add_error_with_msg("symptom", "Error message").await?; + run.add_error_msg("symptom", "Error message").await?; run.end(TestStatus::Complete, TestResult::Pass).await?; diff --git a/tests/output/diagnosis.rs b/tests/output/diagnosis.rs index ba43c10..b2e7786 100644 --- a/tests/output/diagnosis.rs +++ b/tests/output/diagnosis.rs @@ -35,7 +35,7 @@ async fn test_step_with_diagnosis() -> Result<()> { check_output_step(&expected, |s, _| { async { - s.diagnosis("verdict", DiagnosisType::Pass).await?; + s.add_diagnosis("verdict", DiagnosisType::Pass).await?; Ok(()) } @@ -77,7 +77,7 @@ async fn test_step_with_diagnosis_builder() -> Result<()> { .subcomponent(&Subcomponent::builder("name").build()) .message("message") .build(); - s.diagnosis_with_details(diagnosis).await?; + s.add_diagnosis_detail(diagnosis).await?; Ok(()) } diff --git a/tests/output/error.rs b/tests/output/error.rs index 2ce389c..ce647d4 100644 --- a/tests/output/error.rs +++ b/tests/output/error.rs @@ -54,7 +54,7 @@ async fn test_testrun_with_error_with_message() -> Result<()> { ]; check_output_run(&expected, |r, _| { - async { r.add_error_with_msg("symptom", "Error message").await }.boxed() + async { r.add_error_msg("symptom", "Error message").await }.boxed() }) .await } @@ -86,7 +86,7 @@ async fn test_testrun_with_error_with_details() -> Result<()> { check_output_run(&expected, |r, dut| { async move { - r.add_error_with_details( + r.add_error_detail( Error::builder("symptom") .message("Error message") .source("file", 1) @@ -146,8 +146,7 @@ async fn test_testrun_with_error_with_message_before_start() -> Result<()> { check_output(&expected, |run_builder, _| { async move { let run = run_builder.build(); - run.add_error_with_msg("no-dut", "failed to find dut") - .await?; + run.add_error_msg("no-dut", "failed to find dut").await?; Ok(()) } @@ -179,7 +178,7 @@ async fn test_testrun_with_error_with_details_before_start() -> Result<()> { check_output(&expected, |run_builder, _| { async move { let run = run_builder.build(); - run.add_error_with_details( + run.add_error_detail( Error::builder("no-dut") .message("failed to find dut") .source("file", 1) @@ -248,7 +247,7 @@ async fn test_testrun_step_error_with_message() -> Result<()> { check_output_step(&expected, |s, _| { async { - s.add_error_with_msg("symptom", "Error message").await?; + s.add_error_msg("symptom", "Error message").await?; Ok(()) } @@ -287,7 +286,7 @@ async fn test_testrun_step_error_with_details() -> Result<()> { check_output_step(&expected, |s, dut| { async move { - s.add_error_with_details( + s.add_error_detail( Error::builder("symptom") .message("Error message") .source("file", 1) diff --git a/tests/output/log.rs b/tests/output/log.rs index 97cc5ec..e3ae311 100644 --- a/tests/output/log.rs +++ b/tests/output/log.rs @@ -67,7 +67,7 @@ async fn test_testrun_with_log_with_details() -> Result<()> { check_output_run(&expected, |r, _| { async { - r.add_log_with_details( + r.add_log_detail( Log::builder("This is a log message with INFO severity") .severity(LogSeverity::Info) .source("file", 1) @@ -143,7 +143,7 @@ async fn test_testrun_step_log_with_details() -> Result<()> { check_output_step(&expected, |s, _| { async { - s.add_log_with_details( + s.add_log_detail( Log::builder("This is a log message with INFO severity") .severity(LogSeverity::Info) .source("file", 1) diff --git a/tests/output/measure.rs b/tests/output/measure.rs index fa08c6b..61b037d 100644 --- a/tests/output/measure.rs +++ b/tests/output/measure.rs @@ -9,8 +9,8 @@ use futures::FutureExt; use serde_json::json; use ocptv::output::{ - Ident, Measurement, MeasurementSeriesElemDetails, MeasurementSeriesInfo, Subcomponent, - Validator, ValidatorType, + Ident, Measurement, MeasurementElementDetail, MeasurementSeriesDetail, Subcomponent, Validator, + ValidatorType, }; use super::fixture::*; @@ -91,7 +91,7 @@ async fn test_step_with_measurement_builder() -> Result<()> { .hardware_info(hw_info) .subcomponent(Subcomponent::builder("name").build()) .build(); - s.add_measurement_with_details(measurement).await?; + s.add_measurement_detail(measurement).await?; Ok(()) } @@ -263,8 +263,8 @@ async fn test_step_with_measurement_series_with_details() -> Result<()> { let hw_info = dut.hardware_info("hw0").unwrap(); // must exist let series = s - .add_measurement_series_with_details( - MeasurementSeriesInfo::builder("name") + .add_measurement_series_detail( + MeasurementSeriesDetail::builder("name") .id(Ident::Exact("series_id".to_owned())) .unit("unit") .add_metadata("key", "value".into()) @@ -483,8 +483,8 @@ async fn test_step_with_measurement_series_element_with_details() -> Result<()> async { let series = s.add_measurement_series("name").start().await?; series - .add_measurement_with_details( - MeasurementSeriesElemDetails::builder(60.into()) + .add_measurement_detail( + MeasurementElementDetail::builder(60.into()) .timestamp(DATETIME.with_timezone(&chrono_tz::UTC)) .add_metadata("key", "value".into()) .add_metadata("key2", "value2".into()) @@ -579,22 +579,22 @@ async fn test_step_with_measurement_series_element_with_metadata_index_no() -> R let series = s.add_measurement_series("name").start().await?; // add more than one element to check the index increments correctly series - .add_measurement_with_details( - MeasurementSeriesElemDetails::builder(60.into()) + .add_measurement_detail( + MeasurementElementDetail::builder(60.into()) .add_metadata("key", "value".into()) .build(), ) .await?; series - .add_measurement_with_details( - MeasurementSeriesElemDetails::builder(70.into()) + .add_measurement_detail( + MeasurementElementDetail::builder(70.into()) .add_metadata("key2", "value2".into()) .build(), ) .await?; series - .add_measurement_with_details( - MeasurementSeriesElemDetails::builder(80.into()) + .add_measurement_detail( + MeasurementElementDetail::builder(80.into()) .add_metadata("key3", "value3".into()) .build(), )