Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fea/api ergonomics #20

Merged
merged 4 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 1 addition & 48 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +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"
futures = "0.3.30"
delegate = "0.13.1"
maplit = "1.0.2"
mime = "0.3.17"
serde = { version = "1.0.210", features = ["derive"] }
Expand Down Expand Up @@ -46,47 +43,3 @@ rand = "0.8.5"
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"]

[[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_run_skip"
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"]
44 changes: 15 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,11 @@ See [The Cargo Book](https://doc.rust-lang.org/cargo/index.html) for more detail

The [specification](https://github.com/opencomputeproject/ocp-diag-core/tree/main/json_spec) does not impose any particular level of usage. To be compliant, a diagnostic package just needs output the correct artifact messages in the correct format. However, any particular such diagnostic is free to choose what aspects it needs to use/output; eg. a simple validation test may not output any measurements, opting to just have a final Diagnosis outcome.

This crate provides the "boxed-scopes" feature. It guarantees to emit the close message every time is needed (i.e. TestRun, TestStep, etc.).
To enable the feature in Cargo.toml:

```toml
[dependencies]
ocptv = { version = "0.1.0", features = ["boxed-scopes"] }
```

If the feature is not used, is up to the user to close correctly all the API that need it.

**Full API reference is available [here](https://docs.rs/ocptv).**

A very simple starter example, which just outputs a diagnosis:
```rust
use anyhow::Result;
use futures::FutureExt;

use ocptv::output as tv;
use ocptv::{ocptv_diagnosis_fail, ocptv_diagnosis_pass};
Expand Down Expand Up @@ -89,6 +78,7 @@ async fn run_diagnosis_macros_step(
) -> Result<TestStatus, tv::OcptvError> {
let fan_speed = get_fan_speed();

/// using the macro, the source location is filled automatically
if fan_speed >= 1600 {
ocptv_diagnosis_pass!(step, "fan_ok").await?;
} else {
Expand All @@ -104,23 +94,19 @@ async fn main() -> Result<()> {

tv::TestRun::builder("simple measurement", "1.0")
.build()
.scope(dut, |r| {
async move {
/// add diagnosis without source location
r.add_step("step0")
.scope(|s| run_diagnosis_step(s).boxed())
.await?;
/// using the macro, the source location is filled automatically
r.add_step("step1")
.scope(|s| run_diagnosis_macros_step(s).boxed())
.await?;

Ok(tv::TestRunOutcome {
status: TestStatus::Complete,
result: TestResult::Pass,
})
}
.boxed()
.scope(dut, |r| async move {
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,
result: TestResult::Pass,
})
})
.await?;

Expand Down Expand Up @@ -179,7 +165,7 @@ The examples in [examples folder](https://github.com/opencomputeproject/ocp-diag

```bash
# run diagnosis example
$ cargo run --example diagnosis --features="boxed-scopes"
$ cargo run --example diagnosis
```

### Developer notes
Expand Down
18 changes: 7 additions & 11 deletions examples/custom_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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?;

Expand Down
28 changes: 9 additions & 19 deletions examples/diagnosis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -17,7 +16,7 @@ fn get_fan_speed() -> i32 {
rng.gen_range(1500..1700)
}

async fn run_diagnosis_step(step: &tv::StartedTestStep) -> Result<TestStatus, tv::OcptvError> {
async fn run_diagnosis_step(step: tv::ScopedTestStep) -> Result<TestStatus, tv::OcptvError> {
let fan_speed = get_fan_speed();

if fan_speed >= 1600 {
Expand All @@ -31,9 +30,7 @@ async fn run_diagnosis_step(step: &tv::StartedTestStep) -> Result<TestStatus, tv
Ok(TestStatus::Complete)
}

async fn run_diagnosis_macros_step(
step: &tv::StartedTestStep,
) -> Result<TestStatus, tv::OcptvError> {
async fn run_diagnosis_macros_step(step: tv::ScopedTestStep) -> Result<TestStatus, tv::OcptvError> {
let fan_speed = get_fan_speed();

if fan_speed >= 1600 {
Expand All @@ -52,21 +49,14 @@ 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(run_diagnosis_step).await?;
r.add_step("step1").scope(run_diagnosis_macros_step).await?;

Ok(tv::TestRunOutcome {
status: TestStatus::Complete,
result: TestResult::Pass,
})
}
.boxed()
Ok(tv::TestRunOutcome {
status: TestStatus::Complete,
result: TestResult::Pass,
})
})
.await?;

Expand Down
27 changes: 11 additions & 16 deletions examples/error_with_dut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -21,24 +20,20 @@ async fn main() -> Result<()> {
.build(),
);

#[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?;

Expand Down
18 changes: 7 additions & 11 deletions examples/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// https://opensource.org/licenses/MIT.

use anyhow::Result;
use futures::FutureExt;
use serde::Serialize;

use ocptv::output as tv;
Expand All @@ -25,7 +24,7 @@ struct ComplexExtension {
subtypes: Vec<u32>,
}

async fn step0(s: &tv::StartedTestStep) -> Result<TestStatus, tv::OcptvError> {
async fn step0(s: tv::ScopedTestStep) -> Result<TestStatus, tv::OcptvError> {
s.add_extension("simple", "extension_identifier").await?;

s.add_extension(
Expand All @@ -48,16 +47,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(step0).await?;

Ok(tv::TestRunOutcome {
status: TestStatus::Complete,
result: TestResult::Pass,
})
}
.boxed()
Ok(tv::TestRunOutcome {
status: TestStatus::Complete,
result: TestResult::Pass,
})
})
.await?;

Expand Down
22 changes: 8 additions & 14 deletions examples/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TestStatus, tv::OcptvError> {
async fn run_file_step(step: tv::ScopedTestStep) -> Result<TestStatus, tv::OcptvError> {
let uri = tv::Uri::from_str("file:///root/mem_cfg_log").unwrap();
step.add_file("mem_cfg_log", uri).await?;

Expand All @@ -26,18 +25,13 @@ 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(run_file_step).await?;

Ok(tv::TestRunOutcome {
status: TestStatus::Complete,
result: TestResult::Pass,
})
})
.await?;

Expand Down
Loading
Loading