#![cfg(unix)]
#![forbid(unsafe_code)]
use serde_json::json;
use std::error::Error;
use std::process::{Command, Stdio};
#[path = "support/stand_in.rs"]
mod support;
use support::{answer, stand_in};
type TestResult = Result<(), Box<dyn Error>>;
use haematite_cli::serve::protocol::NOT_APPLIED_REFUSALS as NOT_APPLIED;
#[test]
fn every_not_applied_refusal_exits_two_without_receipt_reconciliation() -> TestResult {
let mut failures = Vec::new();
for code in NOT_APPLIED {
let dir = tempfile::tempdir()?;
let refusal =
json!({"id":"haem-call","error":{"code":code,"message":"fixture refusal"}}).to_string();
let service = stand_in(dir.path(), 65_536, vec![vec![Some(refusal)]])?;
let output = Command::new(env!("CARGO_BIN_EXE_haematite"))
.args(["write", "--socket"])
.arg(dir.path().join("serve.sock"))
.args([
"--timeout-ms",
"1000",
"--branch",
"main",
"--expected",
"1.0",
"--request-id",
"refusal-contract",
"collection.put",
r#"{"collection":"records","schema":null}"#,
])
.output()?;
let frames = service.frames()?;
assert_eq!(frames.len(), 1, "unexpected request count for {code}");
let request: serde_json::Value =
serde_json::from_slice(frames[0].as_deref().ok_or("no mutation request")?)?;
assert_eq!(request["operation"]["method"], "mutation.apply");
let stderr = std::str::from_utf8(&output.stderr)?;
if output.status.code() != Some(2)
|| !stderr.contains(&format!("refused {code}:"))
|| !output.stdout.is_empty()
{
failures.push(format!(
"{code}: exit {:?}, stderr={stderr}",
output.status.code()
));
}
}
assert!(
failures.is_empty(),
"{} of {} not-applied codes were misclassified:\n{}",
failures.len(),
NOT_APPLIED.len(),
failures.join("\n")
);
Ok(())
}
#[test]
fn answered_but_unwritable_stdout_names_the_output_failure() -> TestResult {
let dir = tempfile::tempdir()?;
let service = stand_in(
dir.path(),
65_536,
vec![vec![Some(answer(r#"{"applied":true}"#))]],
)?;
let (destination, closed_reader) = std::os::unix::net::UnixStream::pair()?;
drop(closed_reader);
let output = Command::new(env!("CARGO_BIN_EXE_haematite"))
.args(["call", "--socket"])
.arg(dir.path().join("serve.sock"))
.args(["branches.list", "{}"])
.stdout(Stdio::from(std::os::fd::OwnedFd::from(destination)))
.stderr(Stdio::piped())
.output()?;
service.frames()?;
let stderr = std::str::from_utf8(&output.stderr)?;
assert_eq!(output.status.code(), Some(3), "{stderr}");
assert!(
stderr.contains("answer received") && stderr.contains("stdout"),
"output failure was not named: {stderr}"
);
assert!(
!stderr.contains("outcome is not known"),
"received answer described as unknown: {stderr}"
);
Ok(())
}