Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

agent/cli/tests/integration_artifactory_bench_twin.rs

//! Downscaled correctness twin of the `holger.artifactory_load` Bencher.
//!
//! Bench:  xtask/examples/nornir-bench.rs :: ArtifactoryLoad ("holger.artifactory_load")
//! Sibling of: integration_nexus_bench_twin.rs
//!
//! This is the FAST, small-scale correctness check for the JFrog Artifactory OSS
//! head-to-head: it exercises the exact same
//! `holger_bench_scenarios::artifactory::artifactory_load` workload the full-scale
//! bench runs, but at a tiny `Scale`. The full-scale MB/s / ops/s measurement lives
//! in the bench so it lands in `bench_history`.
//!
//! ## Why this test exists (the Artifactory-OSS fix it guards)
//!
//! Artifactory OSS used to *always* skip: it can't create repos over REST
//! (Pro-only), so the rival cell was forever EMPTY. The scenario now deploys into
//! a pre-seeded generic-local repo and fetches it back with auth. This twin asserts
//! the Artifactory backend actually reached a **healthy/serving** state when a
//! container is present — `artifactory_ok_ops > 0` and `artifactory_served_mbs > 0`
//! — i.e. a real served number, NOT an empty cell.
//!
//! ## Fixture gate
//!
//! The Artifactory OSS testcontainer is a *fixture gate*: when no container runtime
//! is reachable the scenario returns an `is_skip` error and this twin records a SKIP
//! (still passes). It only asserts real numbers when a container is actually present.
//! Marked `#[ignore]` (container = heavy) exactly like the Nexus twin, so it runs
//! under `--ignored` / the `--heavy` bench pass and never blocks a plain
//! `cargo test`.

use holger_bench_scenarios::{artifactory, Scale};

use traits::test_support::fstatus;

/// Tiny scale for the twin: a handful of entries, a 1s loop.
fn twin_scale() -> Scale {
    Scale {
        entries: 16,
        bench_secs: 1,
        threads_mt: 2,
        // entry-driven twin bench (not byte-budgeted)
        target_bytes: None,
    }
}

// Multi-thread runtime is REQUIRED: `artifactory_load` stands up an in-process
// Holger HTTP gateway and drives it with a blocking GET pool; on a single-thread
// runtime the pool would starve the gateway's accept loop. Mirrors xtask's
// multi-thread `rt()`.
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
#[ignore = "heavy: needs Docker/Podman + Artifactory OSS container (fixture-gated, runs under --heavy)"]
async fn test_artifactory_load_twin_small_scale() {
    let scale = twin_scale();
    match artifactory::artifactory_load(&scale).await {
        Ok(o) => {
            // Container present → assert the workload produced real numbers AND that
            // the Artifactory backend reached a HEALTHY/SERVING state (not an empty
            // rival cell — the bug this scenario fixes).
            assert_eq!(
                o.concurrency, scale.threads_mt,
                "concurrency must reflect scale"
            );
            assert!(o.holger_files > 0, "Holger archive must contain files");
            assert!(
                o.ops_per_sec > 0.0,
                "Holger must serve at least one op/sec over HTTP"
            );
            assert!(
                o.holger_served_mbs > 0.0,
                "Holger served MB/s must be positive"
            );

            // THE CORE ASSERTION: Artifactory actually served the corpus.
            assert!(
                !o.artifactory_repo.is_empty(),
                "Artifactory must have a discovered deploy repo"
            );
            assert!(
                o.artifactory_ok_ops > 0,
                "Artifactory must serve >0 successful GETs (healthy, non-empty rival cell)"
            );
            assert!(
                o.artifactory_served_mbs > 0.0,
                "Artifactory served MB/s must be positive (not an empty cell)"
            );
            assert!(
                o.artifactory_ops_per_sec > 0.0,
                "Artifactory served ops/sec must be positive"
            );

            // Internal ceiling is still produced (Holger-vs-Holger only).
            assert!(
                o.holger_inprocess_read_ceiling_mbs > 0.0,
                "in-process read ceiling must be positive"
            );
            assert!(o.elapsed_ms > 0.0, "elapsed must be positive");
            fstatus(
                "agent-bench",
                "artifactory_load_twin",
                true,
                &format!(
                    "served: holger={:.1} MB/s artifactory={:.1} MB/s \
                     (ok_ops={} ops/s={:.0} repo={}) | inprocess_ceiling={:.1} MB/s files={}",
                    o.holger_served_mbs,
                    o.artifactory_served_mbs,
                    o.artifactory_ok_ops,
                    o.artifactory_ops_per_sec,
                    o.artifactory_repo,
                    o.holger_inprocess_read_ceiling_mbs,
                    o.holger_files
                ),
            );
        }
        Err(e) => {
            // Fixture gate: no Docker/Podman/Artifactory → recorded skip, NOT a
            // failure. A NON-skip error (e.g. the empty-cell guard tripping) IS a
            // failure and fails the test — exactly what we want.
            assert!(
                artifactory::is_skip(&e),
                "non-skip error from artifactory_load twin (empty/unhealthy rival cell?): {e:#}"
            );
            eprintln!("artifactory_load twin skipped (fixture gate): {e}");
            fstatus(
                "agent-bench",
                "artifactory_load_twin",
                true,
                &format!("skipped: {e}"),
            );
        }
    }
}