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}"),
);
}
}
}