observer-rust-lib 0.1.1

MIT-licensed Rust integration library for Observer
Documentation

observer-rust-lib

Minimal Rust-facing provider micro-library for Observer.

If you are new to this surface, start with HOWTO.md before reading the individual snippets and starters.

This wraps the existing low-level Rust provider crates with the same human-first DX shape already used in C and TypeScript:

  • authors write describe!(...), test!(...), it!(...), and expect(...)
  • default identity is derived deterministically from explicit suite path plus test title
  • optional id = ... provides a refactor-stable override when needed
  • observation is bounded and opt-in through ctx.observe().*
  • direct host and embedded observe dispatch are owned by the library

The common path stays human-first. The deterministic boundary stays explicit.

Files

  • HOWTO.md: detailed user manual covering authoring, determinism, host transport, inventory derivation, and end-to-end workflow
  • src/lib.rs: public API
  • examples/example_smoke.rs: tiny collection and execution example
  • examples/host_example.rs: tiny direct list and run host example
  • examples/host_embed_example.rs: own-main style observe namespace example
  • starter/: runnable project-shaped example with Cargo build, provider host build, inventory derivation, suite run, and snapshot verification
  • starter-embedded/: runnable app-shaped example where the application keeps main() and routes observe ... through its own CLI
  • starter-embedded-failure/: runnable failing companion for the embedded app-shaped path
  • starter-failure/: runnable failing companion showing the same provider flow with one intentionally failing exported test

If you want the full end-to-end workflow rather than isolated snippets, start with starter/, then read starter-embedded/, and then compare those with starter-failure/ and starter-embedded-failure/.

Minimal Shape

use observer_rust_lib::{collect_tests, describe, expect, test};

fn connect() -> bool {
    true
}

let tests = collect_tests(|| {
    describe!("database", {
        test!("access to the database", |ctx| {
            ctx.stdout("ok\n");
            expect(connect()).to_be_truthy();
        });
    });
})?;

When id is omitted, Observer derives a deterministic identity from suite path, test title, and duplicate occurrence order.

If a test wants a refactor-stable identity, it opts into id explicitly:

test!("access to the database", id = "database/access", |ctx| {
    expect(true).to_be_truthy();
});

If a test wants to emit observational data, it uses the author context directly:

test!("access to the database", id = "database/access", |ctx| {
    assert!(ctx.observe().metric("wall_time_ns", 104233.0));
    assert!(ctx.observe().vector("request_latency_ns", &[1000.0, 1100.0, 980.0]));
    assert!(ctx.observe().tag("resource_path", "fixtures/config.json"));
    expect(true).to_be_truthy();
});

Validation Rules

  • explicit id, when present, must be non-empty
  • resolved canonical identities must be unique
  • resolved targets must be unique
  • deterministic sorting is by canonical name, then target

In this first cut, the resolved identity is used for both canonical name and target.

Test

cargo test -p observer-rust-lib

Smoke Example

cargo run -q -p observer-rust-lib --example example_smoke

Host Example

cargo run -q -p observer-rust-lib --example host_example -- list
cargo run -q -p observer-rust-lib --example host_example -- observe --target pkg::smoke --timeout-ms 1000
cargo run -q -p observer-rust-lib --example host_example -- run --target pkg::fail --timeout-ms 1000

The library owns the standard provider host transport for Rust too. A direct host can stay nearly trivial:

use observer_rust_lib::{collect_tests, describe, expect, observer_host_main, test};

fn main() {
    let tests = collect_tests(|| {
        describe!("pkg", {
            test!("smoke test", id = "pkg::smoke", |ctx| {
                ctx.stdout("ok\n");
                expect(true).to_be_truthy();
            });
        });
    })
    .expect("collection should validate");

    let exit_code = match observer_host_main("rust", &tests) {
        Ok(()) => 0,
        Err(error) => {
            eprintln!("{error}");
            2
        }
    };
    std::process::exit(exit_code);
}

For developer-facing usage, prefer observe. run remains available for compatibility with the standardized outer provider contract.

Own Main Integration

If a project already owns its CLI, the library can also serve an embedded observe namespace:

use observer_rust_lib::{collect_tests, describe, expect, observer_host_dispatch_embedded, test};

fn app_main() {
    println!("app main");
}

fn main() {
    let tests = collect_tests(|| {
        describe!("pkg", {
            test!("embedded smoke test", id = "pkg::embedded-smoke", |ctx| {
                ctx.stdout("ok\n");
                expect(true).to_be_truthy();
            });
        });
    })
    .expect("collection should validate");

    let args = std::env::args().collect::<Vec<_>>();
    if args.get(1).map(String::as_str) == Some("observe") {
        let exit_code = match observer_host_dispatch_embedded("rust", "observe", &tests, args) {
            Ok(()) => 0,
            Err(error) => {
                eprintln!("{error}");
                2
            }
        };
        std::process::exit(exit_code);
    }

    app_main();
}

Compile and run that path with:

cargo run -q -p observer-rust-lib --example host_embed_example -- observe list
cargo run -q -p observer-rust-lib --example host_embed_example -- observe --target pkg::embedded-smoke --timeout-ms 1000
cargo run -q -p observer-rust-lib --example host_embed_example