autumn-cli 0.8.0

CLI tool for the Autumn web framework
use std::io::{Read, Write};
use std::net::TcpListener;
use std::process::{Command, Output};
use std::thread;

fn run_webhook_sim_against_status(status_line: &'static str, body: &'static str) -> Output {
    let listener = TcpListener::bind("127.0.0.1:0").expect("bind webhook capture server");
    let addr = listener.local_addr().expect("capture server local addr");
    let response = format!(
        "HTTP/1.1 {status_line}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}",
        body.len()
    );

    let handle = thread::spawn(move || {
        let (mut stream, _) = listener.accept().expect("accept simulated webhook");
        let mut raw_request = Vec::new();
        let mut buffer = [0_u8; 1024];

        loop {
            let bytes_read = stream
                .read(&mut buffer)
                .expect("read simulated webhook request");
            if bytes_read == 0 {
                break;
            }

            raw_request.extend_from_slice(&buffer[..bytes_read]);
            if raw_request.windows(4).any(|window| window == b"\r\n\r\n") {
                break;
            }
        }

        stream
            .write_all(response.as_bytes())
            .expect("write simulated webhook response");
    });

    let autumn_bin = env!("CARGO_BIN_EXE_autumn");
    let output = Command::new(autumn_bin)
        .args([
            "webhook",
            "sim",
            "generic",
            &format!("http://{addr}/webhook"),
            "--secret",
            "secret",
            "--payload",
            r#"{"ok":true}"#,
        ])
        .output()
        .expect("run autumn webhook sim");

    handle.join().expect("capture server should finish");
    output
}

#[test]
fn webhook_sim_exits_nonzero_when_endpoint_rejects_request() {
    let output = run_webhook_sim_against_status("409 Conflict", "duplicate delivery");
    let stdout = String::from_utf8_lossy(&output.stdout);
    let stderr = String::from_utf8_lossy(&output.stderr);

    assert!(
        !output.status.success(),
        "autumn webhook sim should fail on non-success HTTP status\nstdout:\n{stdout}\nstderr:\n{stderr}"
    );
    assert!(
        stderr.contains("409 Conflict"),
        "stderr should include rejected response status\nstdout:\n{stdout}\nstderr:\n{stderr}"
    );
    assert!(
        stderr.contains("duplicate delivery"),
        "stderr should include rejected response body\nstdout:\n{stdout}\nstderr:\n{stderr}"
    );
}