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

nordisk/gunnar

crates/gunnar-loadbench/Cargo.toml

# gunnar's **estate load bench** — a detached crate with its own `[workspace]`,
# exactly like `installtest/` and `crates/gunnar-growbench/`, so gunnar's own
# `Cargo.lock` never learns about a harness.
#
# ## What it measures
#
# How the THREE-VM gunnar.rs estate behaves under a declared concurrency and a
# declared request rate:
#
#   * the front's public pages (`/health`, `/login`), served by Caddy + the
#     console's axum BFF on 95.111.204.164;
#   * the console BFF's UNAUTHENTICATED read endpoints (`/auth/status`, and
#     `/login/repos`, which is the only public route that goes all the way
#     through to gunnar's gRPC control plane and back);
#   * gunnar's git SSH front door on `:2222` — an SSH transport handshake
#     (banner + KEXINIT algorithm negotiation) against the real
#     `SSH-2.0-gunnar_*` listener, and, with `--features git-ssh`, a real
#     protocol-v2 `ls-refs` through `gunnar_client::ls_remote` (russh, pure
#     Rust, no `git` subprocess).
#
# For every probe it collects p50/p90/p99/max latency, achieved throughput, and
# refusals COUNTED BY REASON. A refusal is a measurement, never a panic: a 503
# `{"code":"maintenance"}`, a 401, a read timeout and a connection reset are
# four different facts and are counted in four different buckets.
#
# ## Why a detached crate and not a workspace member
#
# The same two reasons `installtest/Cargo.toml` records:
#
#  1. a workspace member takes part in resolver-2 feature unification, so a
#     dependency here could switch a feature on inside the appliance build;
#  2. a member's dev-dependencies are built by `cargo test --workspace`, which
#     would drag a load generator into gunnar's ordinary test run.
#
# ## The engine
#
# `gatling` (published as `rotaryengine`) — the constellation's ONE shared
# no-barrier worker-pool engine. `gatling_for_each(n, workers, f)` is exactly
# the shape a closed-loop load generator wants: all `n` requests are known up
# front, ONE output slot per request is pre-allocated before a single packet
# moves, and `workers` threads drain a shared atomic cursor with no lock and no
# barrier. rayon is forbidden by the law and is not here.
[package]
name = "gunnar-loadbench"
version = "0.0.0"
edition = "2021"
publish = false
description = "Load/capacity bench for the gunnar.rs estate: front, console BFF, gRPC-through-BFF, git SSH"

[workspace]

[features]
default = []
# The REAL git read verb over `:2222`, through `gunnar_client::ls_remote`
# (protocol-v2 ls-refs over russh). Off by default because it pulls the whole
# client half of the estate — russh, gix, nornir-git, tokio — into the build,
# which is minutes and gigabytes. Without it the SSH probe is still real: it
# speaks RFC 4253 §4.2/§7.1 down to KEXINIT with nothing but `std::net`.
git-ssh = ["dep:gunnar-client"]

[dependencies]
# The worker engine. See the header. `gatling` is the LIBRARY name; the crate
# is published as `rotaryengine` because `gatling` is squatted on crates.io.
gatling = { package = "rotaryengine", version = "0.1.12" }
# HTTP. The SAME line `private-gunnar-ops/xtask` uses for the UpCloud API, so
# there is one HTTP client and one TLS stack in the estate's tooling.
ureq = { version = "3", default-features = false, features = ["rustls", "json"] }
# The UpCloud API, for `--from-upcloud`: the constellation's ONE UpCloud surface
# (edda), never a second client — it had its own `const API` and `get` until
# 2026-09-21, which a mock run could not reach.
upcloud-api = "0.1.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# The git read verb over SSH, feature-gated. A path dep on the workspace member
# beside this crate: there is exactly one russh dialler in the estate and this
# bench must not grow a second one.
gunnar-client = { path = "../gunnar-client", optional = true }

[[bin]]
name = "gunnar-loadbench"
path = "src/main.rs"

# TEMPORARY (release-3 merge, 2026-10-03), the same table the root carries: this
# detached workspace reaches gunnar's crates by path, and they ride edda's
# gix-0.88 / russh-0.63 crates until edda publishes them. Delete with the root's.
[patch.crates-io]
gunnar-pack = { path = "../../../edda/crates/gunnar-pack" }
gunnar-delta = { path = "../../../edda/crates/gunnar-delta" }
gunnar-sendpack = { path = "../../../edda/crates/gunnar-sendpack" }
gunnar-pktline = { path = "../../../edda/crates/gunnar-pktline" }
nornir-git = { path = "../../../edda/crates/nornir-git" }