From 2db3e47f0b0add35170cf24088c902ee269ebad7 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Sat, 12 Oct 2024 13:39:42 +0100 Subject: [PATCH 1/3] resolve the typestate scope in a different way - context: `end()` methods need to consume self so that the user must not use the contextual object after having emitted the end artifact. However, this introduces an issue in `scope()` methods, in that we need to pass the run object both to the async lambda and to call end, which forces the lambda to capture by reference. We cannot move into the lambda because we need to consume self in `end()`, so the lambda must receive a reference. This leads to needing to use a boxed future, because rust syntax doesn't have a way to specify captured lifetimes in async anon. - since `end()` is the only contentious method, make a new type `ScopedTestRun` which has everything except `end` and pass that with lifetime 'static into the lambda. This removes the need for the boxed future since no shorter refs are captured. Signed-off-by: mimir-d --- Cargo.lock | 12 ++++++ Cargo.toml | 15 +------ examples/custom_writer.rs | 18 ++++----- examples/diagnosis.rs | 25 +++++------- examples/error_with_dut.rs | 26 +++++------- examples/extensions.rs | 15 +++---- examples/file.rs | 21 +++++----- examples/measurement_series.rs | 39 +++++++++--------- examples/measurement_single.rs | 21 +++++----- examples/measurement_subcomponent.rs | 19 ++++----- examples/measurement_validators.rs | 19 ++++----- examples/simple_run_skip.rs | 2 - examples/simple_step_fail.rs | 37 ++++++++--------- src/output/mod.rs | 2 +- src/output/run.rs | 60 +++++++++++++++++++++------- tests/output/error.rs | 4 +- tests/output/fixture.rs | 19 ++++++--- tests/output/log.rs | 4 +- tests/output/run.rs | 18 ++++----- tests/output/step.rs | 2 +- 20 files changed, 190 insertions(+), 188 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 934cbb4..a68e694 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -289,6 +289,17 @@ dependencies = [ "syn", ] +[[package]] +name = "delegate" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc2323e10c92e1cf4d86e11538512e6dc03ceb586842970b6332af3d4046a046" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "deranged" version = "0.3.11" @@ -682,6 +693,7 @@ dependencies = [ "async-trait", "chrono", "chrono-tz", + "delegate", "futures", "maplit", "mime", diff --git a/Cargo.toml b/Cargo.toml index dd23e91..1635da7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ boxed-scopes = [] async-trait = "0.1.83" chrono = "0.4.38" chrono-tz = "0.10.0" +delegate = "0.13.1" futures = "0.3.30" maplit = "1.0.2" mime = "0.3.17" @@ -47,14 +48,6 @@ unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(coverage,coverage_nightly)', ] } -[[example]] -name = "custom_writer" -required-features = ["boxed-scopes"] - -[[example]] -name = "error_with_dut" -required-features = ["boxed-scopes"] - [[example]] name = "extensions" required-features = ["boxed-scopes"] @@ -75,10 +68,6 @@ required-features = ["boxed-scopes"] name = "measurement_validators" required-features = ["boxed-scopes"] -[[example]] -name = "simple_run_skip" -required-features = ["boxed-scopes"] - [[example]] name = "simple_step_fail" required-features = ["boxed-scopes"] @@ -89,4 +78,4 @@ required-features = ["boxed-scopes"] [[example]] name = "file" -required-features = ["boxed-scopes"] \ No newline at end of file +required-features = ["boxed-scopes"] diff --git a/examples/custom_writer.rs b/examples/custom_writer.rs index bc2dee4..ad73ea3 100644 --- a/examples/custom_writer.rs +++ b/examples/custom_writer.rs @@ -8,7 +8,6 @@ use std::io; use anyhow::Result; use async_trait::async_trait; -use futures::FutureExt; use tokio::sync::mpsc; use ocptv::ocptv_log_debug; @@ -45,16 +44,13 @@ async fn main() -> Result<()> { tv::TestRun::builder("extensions", "1.0") .config(config) .build() - .scope(dut, |r| { - async move { - ocptv_log_debug!(r, "log debug").await?; - - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + .scope(dut, |r| async move { + ocptv_log_debug!(r, "log debug").await?; + + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/examples/diagnosis.rs b/examples/diagnosis.rs index dbdc5ec..f351df6 100644 --- a/examples/diagnosis.rs +++ b/examples/diagnosis.rs @@ -52,21 +52,18 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_step("step0") - .scope(|s| run_diagnosis_step(s).boxed()) - .await?; - r.add_step("step1") - .scope(|s| run_diagnosis_macros_step(s).boxed()) - .await?; + .scope(dut, |r| async move { + r.add_step("step0") + .scope(|s| run_diagnosis_step(s).boxed()) + .await?; + r.add_step("step1") + .scope(|s| run_diagnosis_macros_step(s).boxed()) + .await?; - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/examples/error_with_dut.rs b/examples/error_with_dut.rs index 76284fe..c855d7d 100644 --- a/examples/error_with_dut.rs +++ b/examples/error_with_dut.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use ocptv::output as tv; use tv::{SoftwareType, TestResult, TestStatus}; @@ -24,21 +23,18 @@ async fn main() -> Result<()> { #[cfg(feature = "boxed-scopes")] tv::TestRun::builder("run error with dut", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_error_detail( - tv::Error::builder("power-fail") - .add_software_info(&sw_info) - .build(), - ) - .await?; + .scope(dut, |r| async move { + r.add_error_detail( + tv::Error::builder("power-fail") + .add_software_info(&sw_info) + .build(), + ) + .await?; - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Fail, - }) - } - .boxed() + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Fail, + }) }) .await?; diff --git a/examples/extensions.rs b/examples/extensions.rs index 1b46a3f..d718069 100644 --- a/examples/extensions.rs +++ b/examples/extensions.rs @@ -48,16 +48,13 @@ async fn main() -> Result<()> { tv::TestRun::builder("extensions", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_step("step0").scope(|s| step0(s).boxed()).await?; + .scope(dut, |r| async move { + r.add_step("step0").scope(|s| step0(s).boxed()).await?; - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/examples/file.rs b/examples/file.rs index 0188b17..2bef304 100644 --- a/examples/file.rs +++ b/examples/file.rs @@ -26,18 +26,15 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_step("step0") - .scope(|s| run_file_step(s).boxed()) - .await?; - - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + .scope(dut, |r| async move { + r.add_step("step0") + .scope(|s| run_file_step(s).boxed()) + .await?; + + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/examples/measurement_series.rs b/examples/measurement_series.rs index 06c00d5..70b5e33 100644 --- a/examples/measurement_series.rs +++ b/examples/measurement_series.rs @@ -97,27 +97,24 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_step("step0") - .scope(|s| step0_measurements(s).boxed()) - .await?; - - #[cfg(feature = "boxed-scopes")] - r.add_step("step1") - .scope(|s| step1_measurements(s).boxed()) - .await?; - - r.add_step("step2") - .scope(|s| step2_measurements(s).boxed()) - .await?; - - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + .scope(dut, |r| async move { + r.add_step("step0") + .scope(|s| step0_measurements(s).boxed()) + .await?; + + #[cfg(feature = "boxed-scopes")] + r.add_step("step1") + .scope(|s| step1_measurements(s).boxed()) + .await?; + + r.add_step("step2") + .scope(|s| step2_measurements(s).boxed()) + .await?; + + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/examples/measurement_single.rs b/examples/measurement_single.rs index e4160f4..5a64527 100644 --- a/examples/measurement_single.rs +++ b/examples/measurement_single.rs @@ -29,18 +29,15 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_step("step0") - .scope(|s| run_measure_step(s).boxed()) - .await?; - - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + .scope(dut, |r| async move { + r.add_step("step0") + .scope(|s| run_measure_step(s).boxed()) + .await?; + + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/examples/measurement_subcomponent.rs b/examples/measurement_subcomponent.rs index 63b14e0..61aeb7a 100644 --- a/examples/measurement_subcomponent.rs +++ b/examples/measurement_subcomponent.rs @@ -88,18 +88,15 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_step("step0") - .scope(|s| run_measure_step(s, ram0).boxed()) - .await?; + .scope(dut, |r| async move { + r.add_step("step0") + .scope(|s| run_measure_step(s, ram0).boxed()) + .await?; - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/examples/measurement_validators.rs b/examples/measurement_validators.rs index 3b71e94..20bac17 100644 --- a/examples/measurement_validators.rs +++ b/examples/measurement_validators.rs @@ -59,18 +59,15 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_step("step0") - .scope(|s| run_measure_step(s).boxed()) - .await?; + .scope(dut, |r| async move { + r.add_step("step0") + .scope(|s| run_measure_step(s).boxed()) + .await?; - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/examples/simple_run_skip.rs b/examples/simple_run_skip.rs index c8b5d6d..5a1d650 100644 --- a/examples/simple_run_skip.rs +++ b/examples/simple_run_skip.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use ocptv::output as tv; use tv::{TestResult, TestStatus}; @@ -26,7 +25,6 @@ async fn main() -> Result<()> { result: TestResult::NotApplicable, }); } - .boxed() }) .await?; diff --git a/examples/simple_step_fail.rs b/examples/simple_step_fail.rs index a0e9c75..af6387e 100644 --- a/examples/simple_step_fail.rs +++ b/examples/simple_step_fail.rs @@ -19,28 +19,25 @@ async fn main() -> Result<()> { tv::TestRun::builder("step fail", "1.0") .build() - .scope(dut, |r| { - async move { - r.add_step("step0") - .scope(|s| { - async move { - ocptv_log_info!(s, "info log").await?; - Ok(TestStatus::Complete) - } - .boxed() - }) - .await?; + .scope(dut, |r| async move { + r.add_step("step0") + .scope(|s| { + async move { + ocptv_log_info!(s, "info log").await?; + Ok(TestStatus::Complete) + } + .boxed() + }) + .await?; - r.add_step("step1") - .scope(|_s| async move { Ok(TestStatus::Error) }.boxed()) - .await?; + r.add_step("step1") + .scope(|_s| async move { Ok(TestStatus::Error) }.boxed()) + .await?; - Ok(tv::TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Fail, - }) - } - .boxed() + Ok(tv::TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Fail, + }) }) .await?; diff --git a/src/output/mod.rs b/src/output/mod.rs index 83e865e..101ad0b 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -38,7 +38,7 @@ pub use measure::{ MeasurementSeries, MeasurementSeriesDetail, MeasurementSeriesDetailBuilder, StartedMeasurementSeries, Validator, ValidatorBuilder, }; -pub use run::{StartedTestRun, TestRun, TestRunBuilder, TestRunOutcome}; +pub use run::{ScopedTestRun, StartedTestRun, TestRun, TestRunBuilder, TestRunOutcome}; pub use step::{StartedTestStep, TestStep}; pub use writer::{BufferWriter, FileWriter, StdoutWriter, Writer}; diff --git a/src/output/run.rs b/src/output/run.rs index 3b5856d..0245a20 100644 --- a/src/output/run.rs +++ b/src/output/run.rs @@ -4,15 +4,16 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -#[cfg(feature = "boxed-scopes")] -use futures::future::BoxFuture; use std::collections::BTreeMap; use std::env; +use std::future::Future; use std::sync::{ atomic::{self, Ordering}, Arc, }; +use delegate::delegate; + use crate::output as tv; use crate::spec; use tv::step::TestStep; @@ -128,14 +129,17 @@ impl TestRun { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - #[cfg(feature = "boxed-scopes")] - pub async fn scope(self, dut: dut::DutInfo, func: F) -> Result<(), tv::OcptvError> + pub async fn scope(self, dut: dut::DutInfo, func: F) -> Result<(), tv::OcptvError> where - F: FnOnce(&StartedTestRun) -> BoxFuture<'_, Result>, + R: Future> + Send + 'static, + F: FnOnce(ScopedTestRun) -> R, { - let run = self.start(dut).await?; - let outcome = func(&run).await?; - run.end(outcome.status, outcome.result).await?; + let run = Arc::new(self.start(dut).await?); + let outcome = func(ScopedTestRun { + run: Arc::clone(&run), + }) + .await?; + run.end_impl(outcome.status, outcome.result).await?; Ok(()) } @@ -302,6 +306,21 @@ impl StartedTestRun { } } + // note: keep the self-consuming method for crate api, but use this one internally, + // since `StartedTestRun::end` only needs to take ownership for syntactic reasons + async fn end_impl( + &self, + status: spec::TestStatus, + result: spec::TestResult, + ) -> Result<(), tv::OcptvError> { + let end = spec::RootImpl::TestRunArtifact(spec::TestRunArtifact { + artifact: spec::TestRunArtifactImpl::TestRunEnd(spec::TestRunEnd { status, result }), + }); + + self.run.emitter.emit(&end).await?; + Ok(()) + } + /// Ends the test run. /// /// ref: @@ -323,12 +342,7 @@ impl StartedTestRun { status: spec::TestStatus, result: spec::TestResult, ) -> Result<(), tv::OcptvError> { - let end = spec::RootImpl::TestRunArtifact(spec::TestRunArtifact { - artifact: spec::TestRunArtifactImpl::TestRunEnd(spec::TestRunEnd { status, result }), - }); - - self.run.emitter.emit(&end).await?; - Ok(()) + self.end_impl(status, result).await } /// Emits a Log message. @@ -503,3 +517,21 @@ impl StartedTestRun { TestStep::new(&step_id, name, Arc::clone(&self.run.emitter)) } } + +/// TODO: docs +pub struct ScopedTestRun { + run: Arc, +} + +impl ScopedTestRun { + delegate! { + to self.run { + pub async fn add_log(&self, severity: spec::LogSeverity, msg: &str) -> Result<(), tv::OcptvError>; + pub async fn add_log_detail(&self, log: log::Log) -> Result<(), tv::OcptvError>; + pub async fn add_error(&self, symptom: &str) -> Result<(), tv::OcptvError>; + pub async fn add_error_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError>; + pub async fn add_error_detail(&self, error: error::Error) -> Result<(), tv::OcptvError>; + pub fn add_step(&self, name: &str) -> TestStep; + } + } +} diff --git a/tests/output/error.rs b/tests/output/error.rs index ce647d4..2134c26 100644 --- a/tests/output/error.rs +++ b/tests/output/error.rs @@ -30,7 +30,7 @@ async fn test_testrun_with_error() -> Result<()> { ]; check_output_run(&expected, |r, _| { - async { r.add_error("symptom").await }.boxed() + async move { r.add_error("symptom").await }.boxed() }) .await } @@ -54,7 +54,7 @@ async fn test_testrun_with_error_with_message() -> Result<()> { ]; check_output_run(&expected, |r, _| { - async { r.add_error_msg("symptom", "Error message").await }.boxed() + async move { r.add_error_msg("symptom", "Error message").await }.boxed() }) .await } diff --git a/tests/output/fixture.rs b/tests/output/fixture.rs index ff21d32..5c038b8 100644 --- a/tests/output/fixture.rs +++ b/tests/output/fixture.rs @@ -10,11 +10,12 @@ use anyhow::Result; use assert_json_diff::assert_json_eq; use futures::future::BoxFuture; use futures::future::Future; +use ocptv::output::TestRunOutcome; use serde_json::json; use tokio::sync::Mutex; use ocptv::output::{ - Config, DutInfo, HardwareInfo, Ident, OcptvError, SoftwareInfo, SoftwareType, StartedTestRun, + Config, DutInfo, HardwareInfo, Ident, OcptvError, ScopedTestRun, SoftwareInfo, SoftwareType, StartedTestStep, TestResult, TestRun, TestRunBuilder, TestStatus, TimestampProvider, SPEC_VERSION, }; @@ -152,16 +153,22 @@ where Ok(()) } -pub async fn check_output_run(expected: &[serde_json::Value], test_fn: F) -> Result<()> +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>>, + R: Future> + Send + 'static, + F: FnOnce(ScopedTestRun, DutInfo) -> R + Send + 'static, { 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?; + run.scope(dut.clone(), |run| async move { + test_fn(run, dut).await?; + Ok(TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) + }) + .await?; Ok(()) }) diff --git a/tests/output/log.rs b/tests/output/log.rs index e3ae311..0a1826b 100644 --- a/tests/output/log.rs +++ b/tests/output/log.rs @@ -31,7 +31,7 @@ async fn test_testrun_with_log() -> Result<()> { ]; check_output_run(&expected, |r, _| { - async { + async move { r.add_log( LogSeverity::Info, "This is a log message with INFO severity", @@ -66,7 +66,7 @@ async fn test_testrun_with_log_with_details() -> Result<()> { ]; check_output_run(&expected, |r, _| { - async { + async move { r.add_log_detail( Log::builder("This is a log message with INFO severity") .severity(LogSeverity::Info) diff --git a/tests/output/run.rs b/tests/output/run.rs index 1da27f3..bf0ac79 100644 --- a/tests/output/run.rs +++ b/tests/output/run.rs @@ -8,7 +8,6 @@ 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; @@ -24,7 +23,7 @@ async fn test_testrun_start_and_end() -> Result<()> { json_run_pass(2), ]; - check_output_run(&expected, |_, _| async { Ok(()) }.boxed()).await + check_output_run(&expected, |_, _| async { Ok(()) }).await } #[cfg(feature = "boxed-scopes")] @@ -51,16 +50,13 @@ async fn test_testrun_with_scope() -> Result<()> { 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?; + run.scope(dut, |r| async move { + r.add_log(LogSeverity::Info, "First message").await?; - Ok(TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, - }) - } - .boxed() + Ok(TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) .await?; diff --git a/tests/output/step.rs b/tests/output/step.rs index b74026d..bd9c3a3 100644 --- a/tests/output/step.rs +++ b/tests/output/step.rs @@ -53,7 +53,7 @@ async fn test_testrun_step_scope_log() -> Result<()> { ]; check_output_run(&expected, |r, _| { - async { + async move { r.add_step("first step") .scope(|s| { async move { From 53a6e23772c170e30f5c932321adcb7e789d6751 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Sat, 12 Oct 2024 14:18:56 +0100 Subject: [PATCH 2/3] refactor scopes for step + measurement series - similar to previous commit, this removes the dependency on boxed futures; remove the cargo dependency as well, and the feature flag Signed-off-by: mimir-d --- Cargo.toml | 36 ------- examples/diagnosis.rs | 15 +-- examples/error_with_dut.rs | 1 - examples/extensions.rs | 5 +- examples/file.rs | 5 +- examples/measurement_series.rs | 16 ++- examples/measurement_single.rs | 5 +- examples/measurement_subcomponent.rs | 14 +-- examples/measurement_validators.rs | 16 +-- examples/simple_step_fail.rs | 12 +-- src/output/measure.rs | 64 ++++++++---- src/output/mod.rs | 2 +- src/output/run.rs | 2 + src/output/step.rs | 144 ++++++++++++++++++--------- tests/output/diagnosis.rs | 11 +- tests/output/error.rs | 99 ++++++++---------- tests/output/file.rs | 29 ++---- tests/output/fixture.rs | 45 ++++----- tests/output/log.rs | 73 ++++++-------- tests/output/measure.rs | 104 ++++++++----------- tests/output/run.rs | 1 - tests/output/step.rs | 91 +++++++++-------- 22 files changed, 372 insertions(+), 418 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1635da7..35f5686 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,11 @@ repository = "https://github.com/opencomputeproject/ocp-diag-core-rust" license = "MIT" edition = "2021" -[features] -boxed-scopes = [] - [dependencies] async-trait = "0.1.83" chrono = "0.4.38" chrono-tz = "0.10.0" delegate = "0.13.1" -futures = "0.3.30" maplit = "1.0.2" mime = "0.3.17" serde = { version = "1.0.210", features = ["derive"] } @@ -47,35 +43,3 @@ rand = "0.8.5" unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(coverage,coverage_nightly)', ] } - -[[example]] -name = "extensions" -required-features = ["boxed-scopes"] - -[[example]] -name = "measurement_series" -required-features = ["boxed-scopes"] - -[[example]] -name = "measurement_single" -required-features = ["boxed-scopes"] - -[[example]] -name = "measurement_subcomponent" -required-features = ["boxed-scopes"] - -[[example]] -name = "measurement_validators" -required-features = ["boxed-scopes"] - -[[example]] -name = "simple_step_fail" -required-features = ["boxed-scopes"] - -[[example]] -name = "diagnosis" -required-features = ["boxed-scopes"] - -[[example]] -name = "file" -required-features = ["boxed-scopes"] diff --git a/examples/diagnosis.rs b/examples/diagnosis.rs index f351df6..59c23a6 100644 --- a/examples/diagnosis.rs +++ b/examples/diagnosis.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use ocptv::output as tv; use ocptv::{ocptv_diagnosis_fail, ocptv_diagnosis_pass}; @@ -17,7 +16,7 @@ fn get_fan_speed() -> i32 { rng.gen_range(1500..1700) } -async fn run_diagnosis_step(step: &tv::StartedTestStep) -> Result { +async fn run_diagnosis_step(step: tv::ScopedTestStep) -> Result { let fan_speed = get_fan_speed(); if fan_speed >= 1600 { @@ -31,9 +30,7 @@ async fn run_diagnosis_step(step: &tv::StartedTestStep) -> Result Result { +async fn run_diagnosis_macros_step(step: tv::ScopedTestStep) -> Result { let fan_speed = get_fan_speed(); if fan_speed >= 1600 { @@ -53,12 +50,8 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() .scope(dut, |r| async move { - r.add_step("step0") - .scope(|s| run_diagnosis_step(s).boxed()) - .await?; - r.add_step("step1") - .scope(|s| run_diagnosis_macros_step(s).boxed()) - .await?; + r.add_step("step0").scope(run_diagnosis_step).await?; + r.add_step("step1").scope(run_diagnosis_macros_step).await?; Ok(tv::TestRunOutcome { status: TestStatus::Complete, diff --git a/examples/error_with_dut.rs b/examples/error_with_dut.rs index c855d7d..9194802 100644 --- a/examples/error_with_dut.rs +++ b/examples/error_with_dut.rs @@ -20,7 +20,6 @@ async fn main() -> Result<()> { .build(), ); - #[cfg(feature = "boxed-scopes")] tv::TestRun::builder("run error with dut", "1.0") .build() .scope(dut, |r| async move { diff --git a/examples/extensions.rs b/examples/extensions.rs index d718069..f78886f 100644 --- a/examples/extensions.rs +++ b/examples/extensions.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use serde::Serialize; use ocptv::output as tv; @@ -25,7 +24,7 @@ struct ComplexExtension { subtypes: Vec, } -async fn step0(s: &tv::StartedTestStep) -> Result { +async fn step0(s: tv::ScopedTestStep) -> Result { s.add_extension("simple", "extension_identifier").await?; s.add_extension( @@ -49,7 +48,7 @@ async fn main() -> Result<()> { tv::TestRun::builder("extensions", "1.0") .build() .scope(dut, |r| async move { - r.add_step("step0").scope(|s| step0(s).boxed()).await?; + r.add_step("step0").scope(step0).await?; Ok(tv::TestRunOutcome { status: TestStatus::Complete, diff --git a/examples/file.rs b/examples/file.rs index 2bef304..4ee475e 100644 --- a/examples/file.rs +++ b/examples/file.rs @@ -7,12 +7,11 @@ use std::str::FromStr; use anyhow::Result; -use futures::FutureExt; use ocptv::output as tv; use tv::{TestResult, TestStatus}; -async fn run_file_step(step: &tv::StartedTestStep) -> Result { +async fn run_file_step(step: tv::ScopedTestStep) -> Result { let uri = tv::Uri::from_str("file:///root/mem_cfg_log").unwrap(); step.add_file("mem_cfg_log", uri).await?; @@ -28,7 +27,7 @@ async fn main() -> Result<()> { .build() .scope(dut, |r| async move { r.add_step("step0") - .scope(|s| run_file_step(s).boxed()) + .scope(run_file_step) .await?; Ok(tv::TestRunOutcome { diff --git a/examples/measurement_series.rs b/examples/measurement_series.rs index 70b5e33..7a325b9 100644 --- a/examples/measurement_series.rs +++ b/examples/measurement_series.rs @@ -7,12 +7,11 @@ use anyhow::Result; use chrono::Duration; -use futures::FutureExt; use ocptv::output::{self as tv}; use tv::{TestResult, TestStatus}; -async fn step0_measurements(step: &tv::StartedTestStep) -> Result { +async fn step0_measurements(step: tv::ScopedTestStep) -> Result { let fan_speed = step .add_measurement_series_detail( tv::MeasurementSeriesDetail::builder("fan_speed") @@ -30,8 +29,7 @@ async fn step0_measurements(step: &tv::StartedTestStep) -> Result Result { +async fn step1_measurements(step: tv::ScopedTestStep) -> Result { step.add_measurement_series_detail( tv::MeasurementSeriesDetail::builder("temp0") .unit("C") @@ -51,14 +49,13 @@ async fn step1_measurements(step: &tv::StartedTestStep) -> Result Result { +async fn step2_measurements(step: tv::ScopedTestStep) -> Result { let freq0 = step .add_measurement_series_detail( tv::MeasurementSeriesDetail::builder("freq0") @@ -99,16 +96,15 @@ async fn main() -> Result<()> { .build() .scope(dut, |r| async move { r.add_step("step0") - .scope(|s| step0_measurements(s).boxed()) + .scope(step0_measurements) .await?; - #[cfg(feature = "boxed-scopes")] r.add_step("step1") - .scope(|s| step1_measurements(s).boxed()) + .scope(step1_measurements) .await?; r.add_step("step2") - .scope(|s| step2_measurements(s).boxed()) + .scope(step2_measurements) .await?; Ok(tv::TestRunOutcome { diff --git a/examples/measurement_single.rs b/examples/measurement_single.rs index 5a64527..c39b984 100644 --- a/examples/measurement_single.rs +++ b/examples/measurement_single.rs @@ -5,12 +5,11 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use ocptv::output as tv; use tv::{TestResult, TestStatus}; -async fn run_measure_step(step: &tv::StartedTestStep) -> Result { +async fn run_measure_step(step: tv::ScopedTestStep) -> Result { step.add_measurement("temperature", 42.5.into()).await?; step.add_measurement_detail( tv::Measurement::builder("fan_speed", 1200.into()) @@ -31,7 +30,7 @@ async fn main() -> Result<()> { .build() .scope(dut, |r| async move { r.add_step("step0") - .scope(|s| run_measure_step(s).boxed()) + .scope(run_measure_step) .await?; Ok(tv::TestRunOutcome { diff --git a/examples/measurement_subcomponent.rs b/examples/measurement_subcomponent.rs index 61aeb7a..755547a 100644 --- a/examples/measurement_subcomponent.rs +++ b/examples/measurement_subcomponent.rs @@ -7,12 +7,11 @@ use anyhow::Result; -use futures::FutureExt; use ocptv::output as tv; use tv::{SubcomponentType, TestResult, TestStatus}; async fn run_measure_step( - step: &tv::StartedTestStep, + step: tv::ScopedTestStep, ram0: tv::DutHardwareInfo, ) -> Result { step.add_measurement_detail( @@ -40,13 +39,10 @@ async fn run_measure_step( ); chip1_temp - .scope(|s| { - async move { - s.add_measurement(79.into()).await?; + .scope(|s| async move { + s.add_measurement(79.into()).await?; - Ok(()) - } - .boxed() + Ok(()) }) .await?; @@ -90,7 +86,7 @@ async fn main() -> Result<()> { .build() .scope(dut, |r| async move { r.add_step("step0") - .scope(|s| run_measure_step(s, ram0).boxed()) + .scope(|s| run_measure_step(s, ram0)) .await?; Ok(tv::TestRunOutcome { diff --git a/examples/measurement_validators.rs b/examples/measurement_validators.rs index 20bac17..f8655cd 100644 --- a/examples/measurement_validators.rs +++ b/examples/measurement_validators.rs @@ -6,12 +6,11 @@ // #![allow(warnings)] use anyhow::Result; -use futures::FutureExt; use ocptv::output as tv; use tv::{TestResult, TestStatus, ValidatorType}; -async fn run_measure_step(step: &tv::StartedTestStep) -> Result { +async fn run_measure_step(step: tv::ScopedTestStep) -> Result { step.add_measurement_detail( tv::Measurement::builder("temp", 40.into()) .add_validator( @@ -31,13 +30,10 @@ async fn run_measure_step(step: &tv::StartedTestStep) -> Result Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() .scope(dut, |r| async move { - r.add_step("step0") - .scope(|s| run_measure_step(s).boxed()) - .await?; + r.add_step("step0").scope(run_measure_step).await?; Ok(tv::TestRunOutcome { status: TestStatus::Complete, diff --git a/examples/simple_step_fail.rs b/examples/simple_step_fail.rs index af6387e..eba2402 100644 --- a/examples/simple_step_fail.rs +++ b/examples/simple_step_fail.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use ocptv::ocptv_log_info; use ocptv::output as tv; @@ -21,17 +20,14 @@ async fn main() -> Result<()> { .build() .scope(dut, |r| async move { r.add_step("step0") - .scope(|s| { - async move { - ocptv_log_info!(s, "info log").await?; - Ok(TestStatus::Complete) - } - .boxed() + .scope(|s| async move { + ocptv_log_info!(s, "info log").await?; + Ok(TestStatus::Complete) }) .await?; r.add_step("step1") - .scope(|_s| async move { Ok(TestStatus::Error) }.boxed()) + .scope(|_s| async move { Ok(TestStatus::Error) }) .await?; Ok(tv::TestRunOutcome { diff --git a/src/output/measure.rs b/src/output/measure.rs index 11620de..f397a01 100644 --- a/src/output/measure.rs +++ b/src/output/measure.rs @@ -5,11 +5,11 @@ // https://opensource.org/licenses/MIT. use std::collections::BTreeMap; +use std::future::Future; use std::sync::atomic::{self, Ordering}; use std::sync::Arc; -#[cfg(feature = "boxed-scopes")] -use futures::future::BoxFuture; +use delegate::delegate; use crate::output as tv; use crate::output::trait_ext::{MapExt, VecExt}; @@ -117,14 +117,17 @@ impl MeasurementSeries { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - #[cfg(feature = "boxed-scopes")] - pub async fn scope(self, func: F) -> Result<(), tv::OcptvError> + pub async fn scope(self, func: F) -> Result<(), tv::OcptvError> where - F: FnOnce(&StartedMeasurementSeries) -> BoxFuture<'_, Result<(), tv::OcptvError>>, + R: Future> + Send + 'static, + F: FnOnce(ScopedMeasurementSeries) -> R + Send + 'static, { - let series = self.start().await?; - func(&series).await?; - series.end().await?; + let series = Arc::new(self.start().await?); + func(ScopedMeasurementSeries { + series: Arc::clone(&series), + }) + .await?; + series.end_impl().await?; Ok(()) } @@ -142,6 +145,22 @@ impl StartedMeasurementSeries { self.seqno.fetch_add(1, Ordering::AcqRel) } + // note: keep the self-consuming method for crate api, but use this one internally, + // since `StartedMeasurementSeries::end` only needs to take ownership for syntactic reasons + async fn end_impl(&self) -> Result<(), tv::OcptvError> { + let end = spec::MeasurementSeriesEnd { + series_id: self.parent.id.clone(), + total_count: self.seqno.load(Ordering::Acquire), + }; + + self.parent + .emitter + .emit(&spec::TestStepArtifactImpl::MeasurementSeriesEnd(end)) + .await?; + + Ok(()) + } + /// Ends the measurement series. /// /// ref: @@ -162,17 +181,7 @@ impl StartedMeasurementSeries { /// # }); /// ``` pub async fn end(self) -> Result<(), tv::OcptvError> { - let end = spec::MeasurementSeriesEnd { - series_id: self.parent.id.clone(), - total_count: self.seqno.load(Ordering::Acquire), - }; - - self.parent - .emitter - .emit(&spec::TestStepArtifactImpl::MeasurementSeriesEnd(end)) - .await?; - - Ok(()) + self.end_impl().await } /// Adds a measurement element to the measurement series. @@ -248,6 +257,23 @@ impl StartedMeasurementSeries { } } +/// TODO: docs +pub struct ScopedMeasurementSeries { + series: Arc, +} + +impl ScopedMeasurementSeries { + delegate! { + to self.series { + pub async fn add_measurement(&self, value: tv::Value) -> Result<(), tv::OcptvError>; + pub async fn add_measurement_detail( + &self, + element: MeasurementElementDetail, + ) -> Result<(), tv::OcptvError>; + } + } +} + /// TODO: docs #[derive(Default)] pub struct MeasurementElementDetail { diff --git a/src/output/mod.rs b/src/output/mod.rs index 101ad0b..39668e1 100644 --- a/src/output/mod.rs +++ b/src/output/mod.rs @@ -39,7 +39,7 @@ pub use measure::{ StartedMeasurementSeries, Validator, ValidatorBuilder, }; pub use run::{ScopedTestRun, StartedTestRun, TestRun, TestRunBuilder, TestRunOutcome}; -pub use step::{StartedTestStep, TestStep}; +pub use step::{ScopedTestStep, StartedTestStep, TestStep}; pub use writer::{BufferWriter, FileWriter, StdoutWriter, Writer}; // re-export these as a public types we present diff --git a/src/output/run.rs b/src/output/run.rs index 0245a20..4bd0f41 100644 --- a/src/output/run.rs +++ b/src/output/run.rs @@ -528,9 +528,11 @@ impl ScopedTestRun { to self.run { pub async fn add_log(&self, severity: spec::LogSeverity, msg: &str) -> Result<(), tv::OcptvError>; pub async fn add_log_detail(&self, log: log::Log) -> Result<(), tv::OcptvError>; + pub async fn add_error(&self, symptom: &str) -> Result<(), tv::OcptvError>; pub async fn add_error_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError>; pub async fn add_error_detail(&self, error: error::Error) -> Result<(), tv::OcptvError>; + pub fn add_step(&self, name: &str) -> TestStep; } } diff --git a/src/output/step.rs b/src/output/step.rs index ec27871..67c322a 100644 --- a/src/output/step.rs +++ b/src/output/step.rs @@ -4,12 +4,12 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +use std::future::Future; use std::io; use std::sync::atomic::{self, Ordering}; use std::sync::Arc; -#[cfg(feature = "boxed-scopes")] -use futures::future::BoxFuture; +use delegate::delegate; use crate::output as tv; use crate::spec::{self, TestStepArtifactImpl}; @@ -97,14 +97,17 @@ impl TestStep { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - #[cfg(feature = "boxed-scopes")] - pub async fn scope(self, func: F) -> Result<(), tv::OcptvError> + pub async fn scope(self, func: F) -> Result<(), tv::OcptvError> where - F: FnOnce(&StartedTestStep) -> BoxFuture<'_, Result>, + R: Future> + Send + 'static, + F: FnOnce(ScopedTestStep) -> R + Send + 'static, { - let step = self.start().await?; - let status = func(&step).await?; - step.end(status).await?; + let step = Arc::new(self.start().await?); + let status = func(ScopedTestStep { + step: Arc::clone(&step), + }) + .await?; + step.end_impl(status).await?; Ok(()) } @@ -117,6 +120,15 @@ pub struct StartedTestStep { } impl StartedTestStep { + // note: keep the self-consuming method for crate api, but use this one internally, + // since `StartedTestStep::end` only needs to take ownership for syntactic reasons + async fn end_impl(&self, status: tv::TestStatus) -> Result<(), tv::OcptvError> { + let end = TestStepArtifactImpl::TestStepEnd(spec::TestStepEnd { status }); + + self.step.emitter.emit(&end).await?; + Ok(()) + } + /// Ends the test step. /// /// ref: @@ -135,11 +147,8 @@ impl StartedTestStep { /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn end(self, status: spec::TestStatus) -> Result<(), tv::OcptvError> { - let end = TestStepArtifactImpl::TestStepEnd(spec::TestStepEnd { status }); - - self.step.emitter.emit(&end).await?; - Ok(()) + pub async fn end(self, status: tv::TestStatus) -> Result<(), tv::OcptvError> { + self.end_impl(status).await } /// Emits Log message. @@ -367,41 +376,6 @@ impl StartedTestStep { Ok(()) } - /// Emits an extension message; - /// - /// 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?; - /// - /// #[derive(serde::Serialize)] - /// struct Ext { i: u32 } - /// - /// step.add_extension("ext_name", Ext { i: 42 }).await?; - /// - /// # Ok::<(), OcptvError>(()) - /// # }); - /// ``` - pub async fn add_extension( - &self, - name: &str, - any: S, - ) -> Result<(), tv::OcptvError> { - let ext = TestStepArtifactImpl::Extension(spec::Extension { - name: name.to_owned(), - content: serde_json::to_value(&any).map_err(|e| OcptvError::Format(Box::new(e)))?, - }); - - self.step.emitter.emit(&ext).await?; - Ok(()) - } - /// Emits a Measurement message. /// /// ref: @@ -684,6 +658,80 @@ impl StartedTestStep { Ok(()) } + + /// Emits an extension message; + /// + /// 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?; + /// + /// #[derive(serde::Serialize)] + /// struct Ext { i: u32 } + /// + /// step.add_extension("ext_name", Ext { i: 42 }).await?; + /// + /// # Ok::<(), OcptvError>(()) + /// # }); + /// ``` + pub async fn add_extension( + &self, + name: &str, + any: S, + ) -> Result<(), tv::OcptvError> { + let ext = TestStepArtifactImpl::Extension(spec::Extension { + name: name.to_owned(), + content: serde_json::to_value(&any).map_err(|e| OcptvError::Format(Box::new(e)))?, + }); + + self.step.emitter.emit(&ext).await?; + Ok(()) + } +} + +/// TODO: docs +pub struct ScopedTestStep { + step: Arc, +} + +impl ScopedTestStep { + delegate! { + to self.step { + pub async fn add_log(&self, severity: spec::LogSeverity, msg: &str) -> Result<(), tv::OcptvError>; + pub async fn add_log_detail(&self, log: log::Log) -> Result<(), tv::OcptvError>; + + pub async fn add_error(&self, symptom: &str) -> Result<(), tv::OcptvError>; + pub async fn add_error_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError>; + pub async fn add_error_detail(&self, error: error::Error) -> Result<(), tv::OcptvError>; + + pub async fn add_measurement(&self, name: &str, value: tv::Value) -> Result<(), tv::OcptvError>; + pub async fn add_measurement_detail(&self, detail: measure::Measurement) -> Result<(), tv::OcptvError>; + + pub fn add_measurement_series(&self, name: &str) -> tv::MeasurementSeries; + pub fn add_measurement_series_detail( + &self, + detail: measure::MeasurementSeriesDetail, + ) -> tv::MeasurementSeries; + + pub async fn add_diagnosis( + &self, + verdict: &str, + diagnosis_type: spec::DiagnosisType, + ) -> Result<(), tv::OcptvError>; + pub async fn add_diagnosis_detail(&self, diagnosis: diagnosis::Diagnosis) -> Result<(), tv::OcptvError>; + + pub async fn add_file(&self, name: &str, uri: tv::Uri) -> Result<(), tv::OcptvError>; + pub async fn add_file_detail(&self, file: file::File) -> Result<(), tv::OcptvError>; + + pub async fn add_extension(&self, name: &str, any: S) -> Result<(), tv::OcptvError>; + } + } } pub struct StepEmitter { diff --git a/tests/output/diagnosis.rs b/tests/output/diagnosis.rs index b2e7786..ecd439a 100644 --- a/tests/output/diagnosis.rs +++ b/tests/output/diagnosis.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use serde_json::json; use ocptv::output::{Diagnosis, DiagnosisType, Subcomponent}; @@ -33,13 +32,10 @@ async fn test_step_with_diagnosis() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, _| { - async { - s.add_diagnosis("verdict", DiagnosisType::Pass).await?; + check_output_step(&expected, |s, _| async move { + s.add_diagnosis("verdict", DiagnosisType::Pass).await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -81,7 +77,6 @@ async fn test_step_with_diagnosis_builder() -> Result<()> { Ok(()) } - .boxed() }) .await } diff --git a/tests/output/error.rs b/tests/output/error.rs index 2134c26..19e55b4 100644 --- a/tests/output/error.rs +++ b/tests/output/error.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use serde_json::json; use ocptv::output::Error; @@ -29,9 +28,10 @@ async fn test_testrun_with_error() -> Result<()> { json_run_pass(3), ]; - check_output_run(&expected, |r, _| { - async move { r.add_error("symptom").await }.boxed() - }) + check_output_run( + &expected, + |r, _| async move { r.add_error("symptom").await }, + ) .await } @@ -53,8 +53,8 @@ async fn test_testrun_with_error_with_message() -> Result<()> { json_run_pass(3), ]; - check_output_run(&expected, |r, _| { - async move { r.add_error_msg("symptom", "Error message").await }.boxed() + check_output_run(&expected, |r, _| async move { + r.add_error_msg("symptom", "Error message").await }) .await } @@ -95,7 +95,6 @@ async fn test_testrun_with_error_with_details() -> Result<()> { ) .await } - .boxed() }) .await } @@ -115,14 +114,11 @@ async fn test_testrun_with_error_before_start() -> Result<()> { }), ]; - check_output(&expected, |run_builder, _| { - async move { - let run = run_builder.build(); - run.add_error("no-dut").await?; + check_output(&expected, |run_builder, _| async move { + let run = run_builder.build(); + run.add_error("no-dut").await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -143,14 +139,11 @@ 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_msg("no-dut", "failed to find dut").await?; + check_output(&expected, |run_builder, _| async move { + let run = run_builder.build(); + run.add_error_msg("no-dut", "failed to find dut").await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -175,20 +168,17 @@ 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_detail( - Error::builder("no-dut") - .message("failed to find dut") - .source("file", 1) - .build(), - ) - .await?; + check_output(&expected, |run_builder, _| async move { + let run = run_builder.build(); + run.add_error_detail( + Error::builder("no-dut") + .message("failed to find dut") + .source("file", 1) + .build(), + ) + .await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -213,13 +203,10 @@ async fn test_testrun_step_error() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, _| { - async { - s.add_error("symptom").await?; + check_output_step(&expected, |s, _| async move { + s.add_error("symptom").await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -245,13 +232,10 @@ async fn test_testrun_step_error_with_message() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, _| { - async { - s.add_error_msg("symptom", "Error message").await?; + check_output_step(&expected, |s, _| async move { + s.add_error_msg("symptom", "Error message").await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -284,20 +268,17 @@ async fn test_testrun_step_error_with_details() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, dut| { - async move { - s.add_error_detail( - Error::builder("symptom") - .message("Error message") - .source("file", 1) - .add_software_info(dut.software_info("sw0").unwrap()) - .build(), - ) - .await?; + check_output_step(&expected, |s, dut| async move { + s.add_error_detail( + Error::builder("symptom") + .message("Error message") + .source("file", 1) + .add_software_info(dut.software_info("sw0").unwrap()) + .build(), + ) + .await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } diff --git a/tests/output/file.rs b/tests/output/file.rs index d9d9065..bc0ce98 100644 --- a/tests/output/file.rs +++ b/tests/output/file.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use serde_json::json; use ocptv::output::{File, Uri}; @@ -35,13 +34,10 @@ async fn test_step_with_file() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, _| { - async { - s.add_file("name", uri).await?; + check_output_step(&expected, |s, _| async move { + s.add_file("name", uri).await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -74,18 +70,15 @@ async fn test_step_with_file_builder() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, _| { - async { - let file = File::builder("name", uri) - .content_type(mime::TEXT_PLAIN) - .description("description") - .add_metadata("key", "value".into()) - .build(); - s.add_file_detail(file).await?; + check_output_step(&expected, |s, _| async move { + let file = File::builder("name", uri) + .content_type(mime::TEXT_PLAIN) + .description("description") + .add_metadata("key", "value".into()) + .build(); + s.add_file_detail(file).await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } diff --git a/tests/output/fixture.rs b/tests/output/fixture.rs index 5c038b8..1c25a8c 100644 --- a/tests/output/fixture.rs +++ b/tests/output/fixture.rs @@ -8,16 +8,14 @@ use std::sync::Arc; use anyhow::Result; use assert_json_diff::assert_json_eq; -use futures::future::BoxFuture; use futures::future::Future; -use ocptv::output::TestRunOutcome; use serde_json::json; use tokio::sync::Mutex; use ocptv::output::{ - Config, DutInfo, HardwareInfo, Ident, OcptvError, ScopedTestRun, SoftwareInfo, SoftwareType, - StartedTestStep, TestResult, TestRun, TestRunBuilder, TestStatus, TimestampProvider, - SPEC_VERSION, + Config, DutInfo, HardwareInfo, Ident, OcptvError, ScopedTestRun, ScopedTestStep, SoftwareInfo, + SoftwareType, TestResult, TestRun, TestRunBuilder, TestRunOutcome, TestStatus, + TimestampProvider, SPEC_VERSION, }; pub const DATETIME: chrono::DateTime = @@ -159,34 +157,35 @@ where F: FnOnce(ScopedTestRun, DutInfo) -> R + Send + 'static, { check_output(expected, |run_builder, dut| async move { - let run = run_builder.build(); - - run.scope(dut.clone(), |run| async move { - test_fn(run, dut).await?; - Ok(TestRunOutcome { - status: TestStatus::Complete, - result: TestResult::Pass, + run_builder + .build() + .scope(dut.clone(), |run| async move { + test_fn(run, dut).await?; + Ok(TestRunOutcome { + status: TestStatus::Complete, + result: TestResult::Pass, + }) }) - }) - .await?; + .await?; Ok(()) }) .await } -pub async fn check_output_step(expected: &[serde_json::Value], test_fn: F) -> Result<()> +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>>, + R: Future> + Send + 'static, + F: FnOnce(ScopedTestStep, DutInfo) -> R + Send + 'static, { - check_output(expected, |run_builder, dut| async move { - let run = run_builder.build().start(dut.clone()).await?; + check_output_run(expected, |run, dut| async move { + run.add_step("first step") + .scope(|step| async move { + test_fn(step, dut).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(TestStatus::Complete) + }) + .await?; Ok(()) }) diff --git a/tests/output/log.rs b/tests/output/log.rs index 0a1826b..cc8fc2c 100644 --- a/tests/output/log.rs +++ b/tests/output/log.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use serde_json::json; use ocptv::output::{Log, LogSeverity}; @@ -30,15 +29,12 @@ async fn test_testrun_with_log() -> Result<()> { json_run_pass(3), ]; - check_output_run(&expected, |r, _| { - async move { - r.add_log( - LogSeverity::Info, - "This is a log message with INFO severity", - ) - .await - } - .boxed() + check_output_run(&expected, |r, _| async move { + r.add_log( + LogSeverity::Info, + "This is a log message with INFO severity", + ) + .await }) .await } @@ -65,17 +61,14 @@ async fn test_testrun_with_log_with_details() -> Result<()> { json_run_pass(3), ]; - check_output_run(&expected, |r, _| { - async move { - r.add_log_detail( - Log::builder("This is a log message with INFO severity") - .severity(LogSeverity::Info) - .source("file", 1) - .build(), - ) - .await - } - .boxed() + check_output_run(&expected, |r, _| async move { + r.add_log_detail( + Log::builder("This is a log message with INFO severity") + .severity(LogSeverity::Info) + .source("file", 1) + .build(), + ) + .await }) .await } @@ -101,17 +94,14 @@ async fn test_testrun_step_log() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, _| { - async { - s.add_log( - LogSeverity::Info, - "This is a log message with INFO severity", - ) - .await?; + check_output_step(&expected, |s, _| async move { + s.add_log( + LogSeverity::Info, + "This is a log message with INFO severity", + ) + .await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -141,19 +131,16 @@ async fn test_testrun_step_log_with_details() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, _| { - async { - s.add_log_detail( - Log::builder("This is a log message with INFO severity") - .severity(LogSeverity::Info) - .source("file", 1) - .build(), - ) - .await?; + check_output_step(&expected, |s, _| async move { + s.add_log_detail( + Log::builder("This is a log message with INFO severity") + .severity(LogSeverity::Info) + .source("file", 1) + .build(), + ) + .await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } diff --git a/tests/output/measure.rs b/tests/output/measure.rs index 61b037d..e3da99b 100644 --- a/tests/output/measure.rs +++ b/tests/output/measure.rs @@ -5,7 +5,6 @@ // https://opensource.org/licenses/MIT. use anyhow::Result; -use futures::FutureExt; use serde_json::json; use ocptv::output::{ @@ -36,13 +35,10 @@ async fn test_step_with_measurement() -> Result<()> { json_run_pass(5), ]; - check_output_step(&expected, |s, _| { - async { - s.add_measurement("name", 50.into()).await?; + check_output_step(&expected, |s, _| async move { + s.add_measurement("name", 50.into()).await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -95,7 +91,6 @@ async fn test_step_with_measurement_builder() -> Result<()> { Ok(()) } - .boxed() }) .await } @@ -132,14 +127,11 @@ async fn test_step_with_measurement_series() -> Result<()> { json_run_pass(6), ]; - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - series.end().await?; + check_output_step(&expected, |s, _| async move { + let series = s.add_measurement_series("name").start().await?; + series.end().await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -198,17 +190,14 @@ async fn test_step_with_multiple_measurement_series() -> Result<()> { json_run_pass(8), ]; - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - series.end().await?; + check_output_step(&expected, |s, _| async move { + 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?; + let series_2 = s.add_measurement_series("name").start().await?; + series_2.end().await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -280,7 +269,6 @@ async fn test_step_with_measurement_series_with_details() -> Result<()> { Ok(()) } - .boxed() }) .await } @@ -330,15 +318,12 @@ async fn test_step_with_measurement_series_element() -> Result<()> { 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?; + check_output_step(&expected, |s, _| async move { + let series = s.add_measurement_series("name").start().await?; + series.add_measurement(60.into()).await?; + series.end().await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } @@ -415,7 +400,7 @@ async fn test_step_with_measurement_series_element_index_no() -> Result<()> { ]; check_output_step(&expected, |s, _| { - async { + async move { 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?; @@ -425,7 +410,6 @@ async fn test_step_with_measurement_series_element_index_no() -> Result<()> { Ok(()) } - .boxed() }) .await } @@ -479,11 +463,10 @@ async fn test_step_with_measurement_series_element_with_details() -> Result<()> json_run_pass(7), ]; - check_output_step(&expected, |s, _| { - async { - let series = s.add_measurement_series("name").start().await?; - series - .add_measurement_detail( + check_output_step(&expected, |s, _| async move { + s.add_measurement_series("name") + .scope(|s| async move { + s.add_measurement_detail( MeasurementElementDetail::builder(60.into()) .timestamp(DATETIME.with_timezone(&chrono_tz::UTC)) .add_metadata("key", "value".into()) @@ -491,11 +474,12 @@ async fn test_step_with_measurement_series_element_with_details() -> Result<()> .build(), ) .await?; - series.end().await?; - Ok(()) - } - .boxed() + Ok(()) + }) + .await?; + + Ok(()) }) .await } @@ -575,7 +559,7 @@ async fn test_step_with_measurement_series_element_with_metadata_index_no() -> R ]; check_output_step(&expected, |s, _| { - async { + async move { let series = s.add_measurement_series("name").start().await?; // add more than one element to check the index increments correctly series @@ -603,12 +587,10 @@ async fn test_step_with_measurement_series_element_with_metadata_index_no() -> R Ok(()) } - .boxed() }) .await } -#[cfg(feature = "boxed-scopes")] #[tokio::test] async fn test_step_with_measurement_series_scope() -> Result<()> { let expected = [ @@ -680,25 +662,19 @@ async fn test_step_with_measurement_series_scope() -> Result<()> { 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?; + check_output_step(&expected, |s, _| async move { + 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(()) + }) + .await?; - Ok(()) - } - .boxed() + Ok(()) }) .await } diff --git a/tests/output/run.rs b/tests/output/run.rs index bf0ac79..3ca1677 100644 --- a/tests/output/run.rs +++ b/tests/output/run.rs @@ -26,7 +26,6 @@ async fn test_testrun_start_and_end() -> Result<()> { check_output_run(&expected, |_, _| async { Ok(()) }).await } -#[cfg(feature = "boxed-scopes")] #[tokio::test] async fn test_testrun_with_scope() -> Result<()> { use ocptv::output::{LogSeverity, TestResult, TestRunOutcome, TestStatus}; diff --git a/tests/output/step.rs b/tests/output/step.rs index bd9c3a3..bf0b358 100644 --- a/tests/output/step.rs +++ b/tests/output/step.rs @@ -7,11 +7,10 @@ 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 ocptv::output::{Config, DutInfo, OcptvError, TestRun, TestStatus}; use super::fixture::*; @@ -20,15 +19,38 @@ 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!({ + "testStepArtifact": { + "testStepId": "step0", + "testStepStart": { + "name": "first step" + } + }, + "sequenceNumber": 2, + "timestamp": DATETIME_FORMATTED + }), + json!({ + "testStepArtifact": { + "testStepId": "step0", + "testStepEnd": { + "status": "COMPLETE" + } + }, + "sequenceNumber": 3, + "timestamp": DATETIME_FORMATTED + }), json_run_pass(4), ]; - check_output_step(&expected, |_, _| async { Ok(()) }.boxed()).await + check_output_run(&expected, |r, _| async move { + let step = r.add_step("first step").start().await?; + step.end(TestStatus::Complete).await?; + + Ok(()) + }) + .await } -#[cfg(feature = "boxed-scopes")] #[tokio::test] async fn test_testrun_step_scope_log() -> Result<()> { use ocptv::output::{LogSeverity, TestStatus}; @@ -52,24 +74,18 @@ async fn test_testrun_step_scope_log() -> Result<()> { json_run_pass(5), ]; - check_output_run(&expected, |r, _| { - async move { - 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() + check_output_run(&expected, |r, _| async move { + 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) + }) + .await }) .await } @@ -109,21 +125,18 @@ async fn test_step_with_extension() -> Result<()> { 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() + check_output_step(&expected, |s, _| async move { + s.add_extension( + "extension", + Ext { + r#type: "TestExtension".to_owned(), + string_field: "string".to_owned(), + number_field: 42, + }, + ) + .await?; + + Ok(()) }) .await } From 60b96330d4fc2474ccf86fc59f5c7c97f64524d4 Mon Sep 17 00:00:00 2001 From: mimir-d Date: Sat, 12 Oct 2024 14:39:27 +0100 Subject: [PATCH 3/3] remove the boilerplate needed for tv::Value - this commit adds template args such that the users dont need to manually covert their values into `tv::Value` - applies for measurements, metadata and run start params Signed-off-by: mimir-d --- examples/file.rs | 4 +- examples/measurement_series.rs | 50 ++++++-------- examples/measurement_single.rs | 8 +-- examples/measurement_subcomponent.rs | 4 +- examples/measurement_validators.rs | 12 ++-- src/output/dut.rs | 8 +-- src/output/file.rs | 12 ++-- src/output/log.rs | 2 + src/output/measure.rs | 100 ++++++++++++++------------- src/output/run.rs | 14 ++-- src/output/step.rs | 16 ++--- tests/output/file.rs | 2 +- tests/output/measure.rs | 48 ++++++------- tests/output/run.rs | 8 +-- 14 files changed, 141 insertions(+), 147 deletions(-) diff --git a/examples/file.rs b/examples/file.rs index 4ee475e..9b29ca1 100644 --- a/examples/file.rs +++ b/examples/file.rs @@ -26,9 +26,7 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() .scope(dut, |r| async move { - r.add_step("step0") - .scope(run_file_step) - .await?; + r.add_step("step0").scope(run_file_step).await?; Ok(tv::TestRunOutcome { status: TestStatus::Complete, diff --git a/examples/measurement_series.rs b/examples/measurement_series.rs index 7a325b9..c707148 100644 --- a/examples/measurement_series.rs +++ b/examples/measurement_series.rs @@ -21,9 +21,9 @@ async fn step0_measurements(step: tv::ScopedTestStep) -> Result Result Result Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() .scope(dut, |r| async move { - r.add_step("step0") - .scope(step0_measurements) - .await?; + r.add_step("step0").scope(step0_measurements).await?; - r.add_step("step1") - .scope(step1_measurements) - .await?; + r.add_step("step1").scope(step1_measurements).await?; - r.add_step("step2") - .scope(step2_measurements) - .await?; + r.add_step("step2").scope(step2_measurements).await?; Ok(tv::TestRunOutcome { status: TestStatus::Complete, diff --git a/examples/measurement_single.rs b/examples/measurement_single.rs index c39b984..41c2f7e 100644 --- a/examples/measurement_single.rs +++ b/examples/measurement_single.rs @@ -10,9 +10,9 @@ use ocptv::output as tv; use tv::{TestResult, TestStatus}; async fn run_measure_step(step: tv::ScopedTestStep) -> Result { - step.add_measurement("temperature", 42.5.into()).await?; + step.add_measurement("temperature", 42.5).await?; step.add_measurement_detail( - tv::Measurement::builder("fan_speed", 1200.into()) + tv::Measurement::builder("fan_speed", 1200) .unit("rpm") .build(), ) @@ -29,9 +29,7 @@ async fn main() -> Result<()> { tv::TestRun::builder("simple measurement", "1.0") .build() .scope(dut, |r| async move { - r.add_step("step0") - .scope(run_measure_step) - .await?; + r.add_step("step0").scope(run_measure_step).await?; Ok(tv::TestRunOutcome { status: TestStatus::Complete, diff --git a/examples/measurement_subcomponent.rs b/examples/measurement_subcomponent.rs index 755547a..d9a3d87 100644 --- a/examples/measurement_subcomponent.rs +++ b/examples/measurement_subcomponent.rs @@ -15,7 +15,7 @@ async fn run_measure_step( ram0: tv::DutHardwareInfo, ) -> Result { step.add_measurement_detail( - tv::Measurement::builder("temp0", 100.5.into()) + tv::Measurement::builder("temp0", 100.5) .unit("F") .hardware_info(&ram0) .subcomponent(tv::Subcomponent::builder("chip0").build()) @@ -40,7 +40,7 @@ async fn run_measure_step( chip1_temp .scope(|s| async move { - s.add_measurement(79.into()).await?; + s.add_measurement(79).await?; Ok(()) }) diff --git a/examples/measurement_validators.rs b/examples/measurement_validators.rs index f8655cd..23650f4 100644 --- a/examples/measurement_validators.rs +++ b/examples/measurement_validators.rs @@ -12,9 +12,9 @@ use tv::{TestResult, TestStatus, ValidatorType}; async fn run_measure_step(step: tv::ScopedTestStep) -> Result { step.add_measurement_detail( - tv::Measurement::builder("temp", 40.into()) + tv::Measurement::builder("temp", 40) .add_validator( - tv::Validator::builder(ValidatorType::GreaterThan, 30.into()) + tv::Validator::builder(ValidatorType::GreaterThan, 30) .name("gt_30") .build(), ) @@ -25,20 +25,18 @@ async fn run_measure_step(step: tv::ScopedTestStep) -> Result Self { - self.metadata.insert(key.to_string(), value); + pub fn add_metadata>(mut self, key: &str, value: V) -> Self { + self.metadata.insert(key.to_string(), value.into()); self } @@ -518,8 +518,8 @@ mod tests { fn test_dut_builder() -> Result<()> { let mut dut = DutInfo::builder("1234") .name("dut") - .add_metadata("key", "value".into()) - .add_metadata("key2", "value2".into()) + .add_metadata("key", "value") + .add_metadata("key2", "value2") .add_platform_info(PlatformInfo::builder("platform_info").build()) .build(); diff --git a/src/output/file.rs b/src/output/file.rs index dab09f7..8c72dea 100644 --- a/src/output/file.rs +++ b/src/output/file.rs @@ -35,7 +35,7 @@ use crate::spec; /// .is_snapshot(true) /// .description("description") /// .content_type(mime::TEXT_PLAIN) -/// .add_metadata("key", "value".into()) +/// .add_metadata("key", "value") /// .build(); /// ``` pub struct File { @@ -79,7 +79,7 @@ impl File { /// let file = File::builder("name", uri) /// .description("description") /// .content_type(mime::TEXT_PLAIN) - /// .add_metadata("key", "value".into()) + /// .add_metadata("key", "value") /// .build(); /// ``` pub fn builder(name: &str, uri: tv::Uri) -> FileBuilder { @@ -119,7 +119,7 @@ impl File { /// let builder = File::builder("name", uri) /// .description("description") /// .content_type(mime::TEXT_PLAIN) -/// .add_metadata("key", "value".into()); +/// .add_metadata("key", "value"); /// let file = builder.build(); /// ``` pub struct FileBuilder { @@ -199,10 +199,10 @@ impl FileBuilder { /// /// let uri = Uri::parse("file:///tmp/foo").unwrap(); /// let builder = File::builder("name", uri) - /// .add_metadata("key", "value".into()); + /// .add_metadata("key", "value"); /// ``` - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> FileBuilder { - self.metadata.insert(key.to_string(), value); + pub fn add_metadata>(mut self, key: &str, value: V) -> FileBuilder { + self.metadata.insert(key.to_string(), value.into()); self } diff --git a/src/output/log.rs b/src/output/log.rs index f39ad90..b5e933a 100644 --- a/src/output/log.rs +++ b/src/output/log.rs @@ -43,10 +43,12 @@ impl LogBuilder { source_location: None, } } + pub fn severity(mut self, value: spec::LogSeverity) -> Self { self.severity = value; self } + pub fn source(mut self, file: &str, line: i32) -> Self { self.source_location = Some(spec::SourceLocation { file: file.to_string(), diff --git a/src/output/measure.rs b/src/output/measure.rs index f397a01..030a323 100644 --- a/src/output/measure.rs +++ b/src/output/measure.rs @@ -107,9 +107,9 @@ impl MeasurementSeries { /// let series = step.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?; + /// s.add_measurement(60).await?; + /// s.add_measurement(70).await?; + /// s.add_measurement(80).await?; /// Ok(()) /// }.boxed() /// }).await?; @@ -198,14 +198,17 @@ impl StartedMeasurementSeries { /// let step = run.add_step("step_name").start().await?; /// /// let series = step.add_measurement_series("name").start().await?; - /// series.add_measurement(60.into()).await?; + /// series.add_measurement(60).await?; /// /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_measurement(&self, value: tv::Value) -> Result<(), tv::OcptvError> { + pub async fn add_measurement>( + &self, + value: V, + ) -> Result<(), tv::OcptvError> { self.add_measurement_detail(MeasurementElementDetail { - value, + value: value.into(), ..Default::default() }) .await @@ -226,7 +229,7 @@ impl StartedMeasurementSeries { /// let step = run.add_step("step_name").start().await?; /// /// let series = step.add_measurement_series("name").start().await?; - /// let elem = MeasurementElementDetail::builder(60.into()).add_metadata("key", "value".into()).build(); + /// let elem = MeasurementElementDetail::builder(60).add_metadata("key", "value").build(); /// series.add_measurement_detail(elem).await?; /// /// # Ok::<(), OcptvError>(()) @@ -265,7 +268,7 @@ pub struct ScopedMeasurementSeries { impl ScopedMeasurementSeries { delegate! { to self.series { - pub async fn add_measurement(&self, value: tv::Value) -> Result<(), tv::OcptvError>; + pub async fn add_measurement>(&self, value: V) -> Result<(), tv::OcptvError>; pub async fn add_measurement_detail( &self, element: MeasurementElementDetail, @@ -284,8 +287,8 @@ pub struct MeasurementElementDetail { } impl MeasurementElementDetail { - pub fn builder(value: tv::Value) -> MeasurementElementDetailBuilder { - MeasurementElementDetailBuilder::new(value) + pub fn builder>(value: V) -> MeasurementElementDetailBuilder { + MeasurementElementDetailBuilder::new(value.into()) } } @@ -311,8 +314,8 @@ impl MeasurementElementDetailBuilder { self } - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { - self.metadata.insert(key.to_string(), value); + pub fn add_metadata>(mut self, key: &str, value: V) -> Self { + self.metadata.insert(key.to_string(), value.into()); self } @@ -335,8 +338,11 @@ pub struct Validator { } impl Validator { - pub fn builder(validator_type: spec::ValidatorType, value: tv::Value) -> ValidatorBuilder { - ValidatorBuilder::new(validator_type, value) + pub fn builder>( + validator_type: spec::ValidatorType, + value: V, + ) -> ValidatorBuilder { + ValidatorBuilder::new(validator_type, value.into()) } pub fn to_spec(&self) -> spec::Validator { @@ -374,8 +380,8 @@ impl ValidatorBuilder { self } - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { - self.metadata.insert(key.to_string(), value); + pub fn add_metadata>(mut self, key: &str, value: V) -> Self { + self.metadata.insert(key.to_string(), value.into()); self } @@ -398,7 +404,7 @@ impl ValidatorBuilder { /// /// ``` /// # use ocptv::output::*; -/// let measurement = Measurement::new("name", 50.into()); +/// let measurement = Measurement::new("name", 50); /// ``` /// /// ## Create a Measurement object with the `builder` method @@ -408,9 +414,9 @@ impl ValidatorBuilder { /// let mut dut = DutInfo::new("dut0"); /// 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_metadata("key", "value".into()) +/// let measurement = Measurement::builder("name", 50) +/// .add_validator(Validator::builder(ValidatorType::Equal, 30).build()) +/// .add_metadata("key", "value") /// .hardware_info(&hw_info) /// .subcomponent(Subcomponent::builder("name").build()) /// .build(); @@ -436,12 +442,12 @@ impl Measurement { /// /// ``` /// # use ocptv::output::*; - /// let measurement = Measurement::new("name", 50.into()); + /// let measurement = Measurement::new("name", 50); /// ``` - pub fn new(name: &str, value: tv::Value) -> Self { + pub fn new>(name: &str, value: V) -> Self { Measurement { name: name.to_string(), - value, + value: value.into(), ..Default::default() } } @@ -456,15 +462,15 @@ impl Measurement { /// let mut dut = DutInfo::new("dut0"); /// 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_metadata("key", "value".into()) + /// let measurement = Measurement::builder("name", 50) + /// .add_validator(Validator::builder(ValidatorType::Equal, 30).build()) + /// .add_metadata("key", "value") /// .hardware_info(&hw_info) /// .subcomponent(Subcomponent::builder("name").build()) /// .build(); /// ``` - pub fn builder(name: &str, value: tv::Value) -> MeasurementBuilder { - MeasurementBuilder::new(name, value) + pub fn builder>(name: &str, value: V) -> MeasurementBuilder { + MeasurementBuilder::new(name, value.into()) } /// Creates an artifact from a Measurement object. @@ -473,7 +479,7 @@ impl Measurement { /// /// ``` /// # use ocptv::output::*; - /// let measurement = Measurement::new("name", 50.into()); + /// let measurement = Measurement::new("name", 50); /// let _ = measurement.to_artifact(); /// ``` pub fn to_artifact(&self) -> spec::Measurement { @@ -504,9 +510,9 @@ impl Measurement { /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// -/// let builder = Measurement::builder("name", 50.into()) -/// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()) -/// .add_metadata("key", "value".into()) +/// let builder = Measurement::builder("name", 50) +/// .add_validator(Validator::builder(ValidatorType::Equal, 30).build()) +/// .add_metadata("key", "value") /// .hardware_info(&hw_info) /// .subcomponent(Subcomponent::builder("name").build()); /// let measurement = builder.build(); @@ -540,8 +546,8 @@ impl MeasurementBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = Measurement::builder("name", 50.into()) - /// .add_validator(Validator::builder(ValidatorType::Equal, 30.into()).build()); + /// let builder = Measurement::builder("name", 50) + /// .add_validator(Validator::builder(ValidatorType::Equal, 30).build()); /// ``` pub fn add_validator(mut self, validator: Validator) -> Self { self.validators.push(validator.clone()); @@ -557,7 +563,7 @@ impl MeasurementBuilder { /// let mut dut = DutInfo::new("dut0"); /// let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); /// - /// let builder = Measurement::builder("name", 50.into()) + /// let builder = Measurement::builder("name", 50) /// .hardware_info(&hw_info); /// ``` pub fn hardware_info(mut self, hardware_info: &dut::DutHardwareInfo) -> Self { @@ -571,7 +577,7 @@ impl MeasurementBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = Measurement::builder("name", 50.into()) + /// let builder = Measurement::builder("name", 50) /// .subcomponent(Subcomponent::builder("name").build()); /// ``` pub fn subcomponent(mut self, subcomponent: dut::Subcomponent) -> Self { @@ -586,10 +592,10 @@ impl MeasurementBuilder { /// ``` /// # use ocptv::output::*; /// let builder = - /// Measurement::builder("name", 50.into()).add_metadata("key", "value".into()); + /// Measurement::builder("name", 50).add_metadata("key", "value"); /// ``` - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { - self.metadata.insert(key.to_string(), value); + pub fn add_metadata>(mut self, key: &str, value: V) -> Self { + self.metadata.insert(key.to_string(), value.into()); self } @@ -599,7 +605,7 @@ impl MeasurementBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = Measurement::builder("name", 50000.into()).unit("RPM"); + /// let builder = Measurement::builder("name", 50000).unit("RPM"); /// ``` pub fn unit(mut self, unit: &str) -> MeasurementBuilder { self.unit = Some(unit.to_string()); @@ -612,7 +618,7 @@ impl MeasurementBuilder { /// /// ``` /// # use ocptv::output::*; - /// let builder = Measurement::builder("name", 50.into()); + /// let builder = Measurement::builder("name", 50); /// let measurement = builder.build(); /// ``` pub fn build(self) -> Measurement { @@ -703,8 +709,8 @@ impl MeasurementSeriesDetailBuilder { self } - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { - self.metadata.insert(key.to_string(), value); + pub fn add_metadata>(mut self, key: &str, value: V) -> Self { + self.metadata.insert(key.to_string(), value.into()); self } @@ -762,7 +768,7 @@ mod tests { let name = "name".to_owned(); let value = tv::Value::from(50000); let hw_info = dut.add_hardware_info(HardwareInfo::builder("name").build()); - let validator = Validator::builder(spec::ValidatorType::Equal, 30.into()).build(); + let validator = Validator::builder(spec::ValidatorType::Equal, 30).build(); let meta_key = "key"; let meta_value = tv::Value::from("value"); @@ -801,10 +807,10 @@ mod tests { #[test] fn test_validator() -> Result<()> { - let validator = Validator::builder(ValidatorType::Equal, 30.into()) + let validator = Validator::builder(ValidatorType::Equal, 30) .name("validator") - .add_metadata("key", "value".into()) - .add_metadata("key2", "value2".into()) + .add_metadata("key", "value") + .add_metadata("key2", "value2") .build(); let spec_validator = validator.to_spec(); diff --git a/src/output/run.rs b/src/output/run.rs index 4bd0f41..596be44 100644 --- a/src/output/run.rs +++ b/src/output/run.rs @@ -102,7 +102,7 @@ impl TestRun { } /// Builds a scope in the [`TestRun`] object, taking care of starting and - /// ending it. View [`TestRun::start`] and [`TestRun::end`] methods. + /// ending it. View [`TestRun::start`] and [`StartedTestRun::end`] methods. /// After the scope is constructed, additional objects may be added to it. /// This is the preferred usage for the [`TestRun`], since it guarantees /// all the messages are emitted between the start and end messages, the order @@ -218,11 +218,11 @@ impl TestRunBuilder { /// ```rust /// # use ocptv::output::*; /// let run = TestRun::builder("run_name", "1.0") - /// .add_parameter("param1", "value1".into()) + /// .add_parameter("param1", "value1") /// .build(); /// ``` - pub fn add_parameter(mut self, key: &str, value: tv::Value) -> Self { - self.parameters.insert(key.to_string(), value); + pub fn add_parameter>(mut self, key: &str, value: V) -> Self { + self.parameters.insert(key.to_string(), value.into()); self } @@ -265,11 +265,11 @@ impl TestRunBuilder { /// # use ocptv::output::*; /// /// let run = TestRun::builder("run_name", "1.0") - /// .add_metadata("meta1", "value1".into()) + /// .add_metadata("meta1", "value1") /// .build(); /// ``` - pub fn add_metadata(mut self, key: &str, value: tv::Value) -> Self { - self.metadata.insert(key.to_string(), value); + pub fn add_metadata>(mut self, key: &str, value: V) -> Self { + self.metadata.insert(key.to_string(), value.into()); self } diff --git a/src/output/step.rs b/src/output/step.rs index 67c322a..b9d4cba 100644 --- a/src/output/step.rs +++ b/src/output/step.rs @@ -389,16 +389,16 @@ impl StartedTestStep { /// let run = TestRun::new("diagnostic_name", "1.0").start(dut).await?; /// /// let step = run.add_step("step_name").start().await?; - /// step.add_measurement("name", 50.into()).await?; + /// step.add_measurement("name", 50).await?; /// step.end(TestStatus::Complete).await?; /// /// # Ok::<(), OcptvError>(()) /// # }); /// ``` - pub async fn add_measurement( + pub async fn add_measurement>( &self, name: &str, - value: tv::Value, + value: V, ) -> Result<(), tv::OcptvError> { let measurement = measure::Measurement::new(name, value); @@ -427,9 +427,9 @@ impl StartedTestStep { /// let run = TestRun::builder("diagnostic_name", "1.0").build().start(dut).await?; /// 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_metadata("key", "value".into()) + /// let measurement = Measurement::builder("name", 5000) + /// .add_validator(Validator::builder(ValidatorType::Equal, 30).build()) + /// .add_metadata("key", "value") /// .hardware_info(&hw_info) /// .subcomponent(Subcomponent::builder("name").build()) /// .build(); @@ -642,7 +642,7 @@ impl StartedTestStep { /// let file = File::builder("name", uri) /// .description("description") /// .content_type(mime::TEXT_PLAIN) - /// .add_metadata("key", "value".into()) + /// .add_metadata("key", "value") /// .build(); /// step.add_file_detail(file).await?; /// step.end(TestStatus::Complete).await?; @@ -710,7 +710,7 @@ impl ScopedTestStep { pub async fn add_error_msg(&self, symptom: &str, msg: &str) -> Result<(), tv::OcptvError>; pub async fn add_error_detail(&self, error: error::Error) -> Result<(), tv::OcptvError>; - pub async fn add_measurement(&self, name: &str, value: tv::Value) -> Result<(), tv::OcptvError>; + pub async fn add_measurement>(&self, name: &str, value: V) -> Result<(), tv::OcptvError>; pub async fn add_measurement_detail(&self, detail: measure::Measurement) -> Result<(), tv::OcptvError>; pub fn add_measurement_series(&self, name: &str) -> tv::MeasurementSeries; diff --git a/tests/output/file.rs b/tests/output/file.rs index bc0ce98..abab281 100644 --- a/tests/output/file.rs +++ b/tests/output/file.rs @@ -74,7 +74,7 @@ async fn test_step_with_file_builder() -> Result<()> { let file = File::builder("name", uri) .content_type(mime::TEXT_PLAIN) .description("description") - .add_metadata("key", "value".into()) + .add_metadata("key", "value") .build(); s.add_file_detail(file).await?; diff --git a/tests/output/measure.rs b/tests/output/measure.rs index e3da99b..371c16c 100644 --- a/tests/output/measure.rs +++ b/tests/output/measure.rs @@ -36,7 +36,7 @@ async fn test_step_with_measurement() -> Result<()> { ]; check_output_step(&expected, |s, _| async move { - s.add_measurement("name", 50.into()).await?; + s.add_measurement("name", 50).await?; Ok(()) }) @@ -80,10 +80,10 @@ async fn test_step_with_measurement_builder() -> Result<()> { 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()) + let measurement = Measurement::builder("name", 50) + .add_validator(Validator::builder(ValidatorType::Equal, 30).build()) + .add_metadata("key", "value") + .add_metadata("key2", "value2") .hardware_info(hw_info) .subcomponent(Subcomponent::builder("name").build()) .build(); @@ -256,9 +256,9 @@ async fn test_step_with_measurement_series_with_details() -> Result<()> { MeasurementSeriesDetail::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()) + .add_metadata("key", "value") + .add_metadata("key2", "value2") + .add_validator(Validator::builder(ValidatorType::Equal, 30).build()) .hardware_info(hw_info) .subcomponent(Subcomponent::builder("name").build()) .build(), @@ -320,7 +320,7 @@ async fn test_step_with_measurement_series_element() -> Result<()> { check_output_step(&expected, |s, _| async move { let series = s.add_measurement_series("name").start().await?; - series.add_measurement(60.into()).await?; + series.add_measurement(60).await?; series.end().await?; Ok(()) @@ -403,9 +403,9 @@ async fn test_step_with_measurement_series_element_index_no() -> Result<()> { async move { 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.add_measurement(60).await?; + series.add_measurement(70).await?; + series.add_measurement(80).await?; series.end().await?; Ok(()) @@ -467,10 +467,10 @@ async fn test_step_with_measurement_series_element_with_details() -> Result<()> s.add_measurement_series("name") .scope(|s| async move { s.add_measurement_detail( - MeasurementElementDetail::builder(60.into()) + MeasurementElementDetail::builder(60) .timestamp(DATETIME.with_timezone(&chrono_tz::UTC)) - .add_metadata("key", "value".into()) - .add_metadata("key2", "value2".into()) + .add_metadata("key", "value") + .add_metadata("key2", "value2") .build(), ) .await?; @@ -564,22 +564,22 @@ async fn test_step_with_measurement_series_element_with_metadata_index_no() -> R // add more than one element to check the index increments correctly series .add_measurement_detail( - MeasurementElementDetail::builder(60.into()) - .add_metadata("key", "value".into()) + MeasurementElementDetail::builder(60) + .add_metadata("key", "value") .build(), ) .await?; series .add_measurement_detail( - MeasurementElementDetail::builder(70.into()) - .add_metadata("key2", "value2".into()) + MeasurementElementDetail::builder(70) + .add_metadata("key2", "value2") .build(), ) .await?; series .add_measurement_detail( - MeasurementElementDetail::builder(80.into()) - .add_metadata("key3", "value3".into()) + MeasurementElementDetail::builder(80) + .add_metadata("key3", "value3") .build(), ) .await?; @@ -666,9 +666,9 @@ async fn test_step_with_measurement_series_scope() -> Result<()> { 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?; + s.add_measurement(60).await?; + s.add_measurement(70).await?; + s.add_measurement(80).await?; Ok(()) }) diff --git a/tests/output/run.rs b/tests/output/run.rs index 3ca1677..c7e8af3 100644 --- a/tests/output/run.rs +++ b/tests/output/run.rs @@ -122,7 +122,7 @@ async fn test_testrun_metadata() -> Result<()> { check_output(&expected, |run_builder, dut| async { let run = run_builder - .add_metadata("key", "value".into()) + .add_metadata("key", "value") .build() .start(dut) .await?; @@ -174,9 +174,9 @@ async fn test_testrun_builder() -> Result<()> { 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()) + .add_metadata("key", "value") + .add_metadata("key2", "value2") + .add_parameter("key", "value") .command_line("cmd_line") .build() .start(dut)