Transaction Science open standards monorepo. Each subdirectory is a self-contained reference protocol with its own README and licence. - openpay/ Apache-2.0 payment-acceptance stack (Rust, 26 crates) - smart-byte/ CC-BY-4.0 content-addressed value carrier (spec) - eoc/ CC-BY-4.0 energy-optimised compute (spec) The wire format and the right to fork are public. The optional hosted services are the offer; the protocols are not.
80 lines
2.8 KiB
Rust
80 lines
2.8 KiB
Rust
//! End-to-end test: spin up an `op-server` on an ephemeral port,
|
|
//! drive the CLI's `health` and `readiness` subcommands through the
|
|
//! library entry point, assert they succeed and parse the JSON
|
|
//! envelope the server actually returns.
|
|
//!
|
|
//! The test runs the axum server inside a `tokio::spawn` on a
|
|
//! multi-thread runtime; the CLI side is fully blocking (it uses
|
|
//! `reqwest::blocking`). Mixing the two only works because the
|
|
//! reqwest call lives on a *separate* OS thread, so it never blocks
|
|
//! the runtime that's hosting axum.
|
|
|
|
use std::net::SocketAddr;
|
|
|
|
use op_cli::{Client, Command, dispatch};
|
|
use op_server::{AppState, router};
|
|
|
|
/// Helper: bind to `127.0.0.1:0`, start axum on the returned port
|
|
/// inside a `tokio::spawn`, return the bound address. The task is
|
|
/// detached — it will be killed when the runtime is dropped at end
|
|
/// of test.
|
|
async fn start_server() -> SocketAddr {
|
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:0")
|
|
.await
|
|
.expect("bind ephemeral port");
|
|
let addr = listener.local_addr().expect("local addr");
|
|
let app = router(AppState::new_in_memory());
|
|
tokio::spawn(async move {
|
|
// axum::serve returns a future that resolves only on
|
|
// shutdown; here we just let it run until the runtime exits.
|
|
let _ = axum::serve(listener, app).await;
|
|
});
|
|
addr
|
|
}
|
|
|
|
#[test]
|
|
fn cli_health_against_real_server() {
|
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
|
.enable_all()
|
|
.build()
|
|
.expect("tokio rt");
|
|
|
|
let addr = rt.block_on(start_server());
|
|
|
|
// Drive the CLI side on a regular OS thread so the blocking
|
|
// reqwest call doesn't stall the tokio reactor.
|
|
let base = format!("http://{addr}");
|
|
let client = Client::new(base, None);
|
|
|
|
let health = dispatch(&client, Command::Health).expect("health ok");
|
|
assert_eq!(
|
|
health.get("status").and_then(|v| v.as_str()),
|
|
Some("ok"),
|
|
"health response shape: {health}"
|
|
);
|
|
|
|
let readiness = dispatch(&client, Command::Readiness).expect("readiness ok");
|
|
assert_eq!(
|
|
readiness.get("status").and_then(|v| v.as_str()),
|
|
Some("ready"),
|
|
"readiness response shape: {readiness}"
|
|
);
|
|
// The readiness response includes store counts; they all start at 0.
|
|
assert_eq!(
|
|
readiness.get("refunds").and_then(serde_json::Value::as_u64),
|
|
Some(0)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn cli_network_error_when_no_server() {
|
|
// Pick a port that almost certainly has nothing listening.
|
|
let client = Client::new("http://127.0.0.1:1", None);
|
|
let err = dispatch(&client, Command::Health).expect_err("must fail");
|
|
match err {
|
|
op_cli::Error::Network { url, .. } => {
|
|
assert!(url.contains("127.0.0.1:1"), "url was {url}");
|
|
}
|
|
other => panic!("expected Network error, got {other:?}"),
|
|
}
|
|
}
|