Files
sausage/cli/tests/plugins/activation/src/main.rs
T
surma c926f3bc72 tests: remove the singleton stress test; #[ignore] means disabled again
128 fast activate/revert cycles are not a realistic load. restarts_service
covers the restart of a service after an upgrade. nix flake check runs
the normal tests only.
2026-10-23 08:31:48 +01:00

115 lines
4.5 KiB
Rust

//! Raw discovery and lifecycle guest for activation protocol tests.
use serde_json::{Value, json};
use std::io::{self, BufRead, Write};
/// Emits one flushed JSON-RPC response.
fn send(value: Value) {
println!("{value}");
io::stdout().flush().unwrap();
}
/// Calls a provider after activation releases an old consumer process.
fn deferred(request: &Value, plugin: &str, lines: &mut impl Iterator<Item = io::Result<String>>) {
send(
json!({"jsonrpc":"2.0","id":request["id"],"result":std::env::var("SAUSAGE_PID").unwrap()}),
);
let before = std::time::Instant::now();
while !std::path::Path::new(&format!("/state/{plugin}/release-call")).exists() {
assert!(before.elapsed() < std::time::Duration::from_secs(30));
}
send(json!({"jsonrpc":"2.0","id":"deferred","method":"notes.legacy","params":{}}));
for line in lines {
let response: Value = serde_json::from_str(&line.unwrap()).unwrap();
if response["id"] == "deferred" {
std::fs::write(format!("/state/{plugin}/call-result"), response.to_string()).unwrap();
break;
}
}
}
/// Answers a method that version two removes from its interface.
fn legacy(request: &Value, document: &Value, version: &str) {
if document["methods"]
.as_array()
.unwrap()
.iter()
.any(|m| m["name"] == "legacy")
{
send(json!({"jsonrpc":"2.0","id":request["id"],"result":version}));
} else {
send(
json!({"jsonrpc":"2.0","id":request["id"],"error":{"code":-32601,"message":"legacy removed","data":{"version":version}}}),
);
}
}
/// Reads a version-specific discovery document without the SDK.
fn main() {
let version = env!("FIXTURE_VERSION");
let plugin = std::env::var("SAUSAGE_PLUGIN").unwrap();
let mut lines = io::stdin().lock().lines();
let request: Value = serde_json::from_str(&lines.next().unwrap().unwrap()).unwrap();
let document: Value =
serde_json::from_slice(&std::fs::read(format!("/state/{plugin}/{version}.json")).unwrap())
.unwrap();
let result = match request["method"].as_str().unwrap() {
"deferred" => {
deferred(&request, &plugin, &mut lines);
return;
}
"legacy" => {
legacy(&request, &document, version);
return;
}
"rpc.discover" => {
if document["x-test-no-answer"] == true {
for _ in &mut lines {}
return;
}
if document["x-test-wait"] == true {
std::fs::write(format!("/state/{plugin}/discover-started"), "ready").unwrap();
let before = std::time::Instant::now();
while !std::path::Path::new(&format!("/state/{plugin}/discover-release")).exists() {
assert!(before.elapsed() < std::time::Duration::from_secs(30));
}
}
document
}
"read" => {
let text =
std::fs::read_to_string(request["params"]["path"].as_str().unwrap()).unwrap();
serde_json::from_str(&text).unwrap_or(json!(text))
}
"rpc.retired" => {
std::fs::write(
format!("/state/{plugin}/retired"),
request["params"]["previous"].as_str().unwrap(),
)
.unwrap();
json!({"retired":version})
}
"serve" | "hold" => {
send(json!({"jsonrpc":"2.0","id":request["id"],"result":{"version":version}}));
if request["method"] == "serve" {
std::fs::write(format!("/state/{plugin}/service"), version).unwrap();
}
for _ in lines {}
std::fs::write(format!("/state/{plugin}/ended-{version}"), "ended").unwrap();
return;
}
_ => json!({"version":version}),
};
send(json!({"jsonrpc":"2.0","id":request["id"],"result":result}));
if request["method"] == "rpc.discover" && result["x-test-linger"] == true {
if result["x-test-stubborn"] == true {
let before = std::time::Instant::now();
while !std::path::Path::new(&format!("/state/{plugin}/discovery-exit")).exists() {
assert!(before.elapsed() < std::time::Duration::from_secs(30));
}
} else {
for _ in lines {}
}
std::fs::write(
format!("/state/{plugin}/discovery-ended-{version}"),
"ended",
)
.unwrap();
}
}