use std::path::{Path, PathBuf};
use std::process::Command;
fn scratch_dir(name: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!(
"cflx-openapi-cli-{name}-{}-{:?}",
std::process::id(),
std::thread::current().id()
));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).expect("scratch directory is creatable");
assert!(
!dir.join(".git").exists(),
"the scratch directory must not be a repository"
);
dir
}
fn cflx_openapi(workdir: &Path) -> std::process::Output {
Command::new(env!("CARGO_BIN_EXE_cflx"))
.arg("openapi")
.current_dir(workdir)
.env("HOME", workdir.join("home"))
.env("XDG_STATE_HOME", workdir.join("state"))
.output()
.expect("the cflx binary under test is runnable")
}
#[cfg(feature = "web-monitoring")]
mod available {
use super::*;
use serde_json::Value;
#[test]
fn exports_a_complete_document_outside_a_git_repository() {
let dir = scratch_dir("export");
let output = cflx_openapi(&dir);
assert!(
output.status.success(),
"cflx openapi must succeed outside a repository: status={:?} stderr={}",
output.status.code(),
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8(output.stdout).expect("the schema is UTF-8");
let document: Value =
serde_yaml::from_str(&stdout).expect("stdout must parse as a YAML document on its own");
assert_eq!(
document["openapi"], "3.1.0",
"the exported document must declare the OpenAPI version a generator reads"
);
assert!(
document["paths"]["/api/v2/state"].is_object(),
"the export must carry the served route surface, not a stub"
);
assert!(
document["paths"]["/api/v2/execution-status"].is_object(),
"the export must carry the execution-status resource"
);
assert!(
document["components"]["schemas"]["ExecutionPhase"]["enum"]
.as_array()
.is_some_and(|values| values.iter().any(|value| value == "acceptance")),
"the export must carry the closed phase vocabulary"
);
assert!(
document["components"]["schemas"]["CommandResult"].is_object(),
"the export must carry the typed command-result contract"
);
std::fs::remove_dir_all(&dir).expect("scratch dir is removable");
}
#[test]
fn says_nothing_on_standard_error_when_it_succeeds() {
let dir = scratch_dir("quiet");
let output = cflx_openapi(&dir);
assert!(output.status.success());
assert_eq!(
String::from_utf8_lossy(&output.stderr),
"",
"a successful export must not mix diagnostics into the operator's terminal"
);
std::fs::remove_dir_all(&dir).expect("scratch dir is removable");
}
#[test]
fn emits_exactly_the_generated_document() {
let dir = scratch_dir("bytes");
let output = cflx_openapi(&dir);
assert_eq!(
String::from_utf8(output.stdout).expect("the schema is UTF-8"),
conflux::web::openapi::document_yaml(),
"the CLI must emit the generated document unmodified"
);
std::fs::remove_dir_all(&dir).expect("scratch dir is removable");
}
#[test]
fn takes_no_repository_lock_and_opens_no_socket() {
let dir = scratch_dir("in-repo");
let git = |args: &[&str]| {
let status = Command::new("git")
.args(args)
.current_dir(&dir)
.env("HOME", dir.join("home"))
.status()
.expect("git is available");
assert!(status.success(), "git {args:?} failed");
};
git(&["init", "--quiet"]);
let output = cflx_openapi(&dir);
assert!(
output.status.success(),
"cflx openapi must succeed inside a repository too: stderr={}",
String::from_utf8_lossy(&output.stderr)
);
let git_dir = dir.join(".git");
assert!(
!git_dir.join("cflx-orchestration.lock").exists(),
"a read-only export must not take the repository orchestration lock"
);
assert!(
!git_dir.join("cflx-api.sock").exists(),
"a read-only export must not bind the local API socket"
);
std::fs::remove_dir_all(&dir).expect("scratch dir is removable");
}
}
#[cfg(not(feature = "web-monitoring"))]
mod unavailable {
use super::*;
#[test]
fn refuses_clearly_and_writes_no_schema() {
let dir = scratch_dir("unavailable");
let output = cflx_openapi(&dir);
assert!(
!output.status.success(),
"an unavailable contract must exit non-zero"
);
assert_eq!(
String::from_utf8_lossy(&output.stdout),
"",
"stdout must carry no partial schema when the document cannot be produced"
);
let stderr = String::from_utf8_lossy(&output.stderr).to_lowercase();
assert!(
stderr.contains("openapi") && stderr.contains("unavailable"),
"stderr must explain that OpenAPI support is unavailable, got: {stderr}"
);
assert!(
stderr.contains("web-monitoring"),
"stderr must name the feature that restores the command, got: {stderr}"
);
std::fs::remove_dir_all(&dir).expect("scratch dir is removable");
}
}