app
Adom Video Post-Production
Public Made by Adomby adom
AI-driven studio for finishing demo videos: review every captured clip, flag and re-record the weak ones, speed up dead air, narrate, mux and auto-level, validate the final cut, and publish straight to the wiki, driven end to end by your AI.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
//! End-to-end test for `adom-video-post publish`.
//!
//! It generates a tiny real mp4, runs the actual `publish` subcommand against a
//! live wiki page, then curls the URL the command returns to confirm the file
//! serves as a valid `ftyp` mp4 over HTTP.
//!
//! It needs network + a writable wiki page, so it is gated behind an env var and
//! is a no-op (passes) under a plain `cargo test`:
//!
//! VIDEO_POST_TEST_PAGE=adom/adom-video-post cargo test --test publish_serves -- --nocapture
//!
//! Requires `ffmpeg`, `adom-wiki`, and `curl` on PATH.
use std::process::Command;
const BIN: &str = env!("CARGO_BIN_EXE_adom-video-post");
const TEST_FILE: &str = "_video-post-selftest.mp4";
#[test]
fn publish_pushes_and_serves_a_valid_mp4() {
let page = match std::env::var("VIDEO_POST_TEST_PAGE") {
Ok(p) if !p.trim().is_empty() => p,
_ => {
eprintln!(
"skipping: set VIDEO_POST_TEST_PAGE=<owner>/<slug> to run the live publish test"
);
return;
}
};
// 1. Generate a tiny but real mp4 named so the served URL is predictable.
let mp4 = std::env::temp_dir().join(TEST_FILE);
let _ = std::fs::remove_file(&mp4);
let ff = Command::new("ffmpeg")
.args(["-y", "-f", "lavfi", "-i", "color=c=teal:s=128x128:d=1", "-r", "8"])
.arg(&mp4)
.output()
.expect("spawn ffmpeg");
assert!(
ff.status.success(),
"ffmpeg failed: {}",
String::from_utf8_lossy(&ff.stderr)
);
assert!(mp4.exists(), "ffmpeg produced no file at {}", mp4.display());
// 2. Run the real publish subcommand.
let out = Command::new(BIN)
.args(["publish", "--input"])
.arg(&mp4)
.args(["--page", &page, "--caption", "video-post publish self-test"])
.output()
.expect("spawn adom-video-post");
let stdout = String::from_utf8_lossy(&out.stdout);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
out.status.success(),
"publish failed:\nstdout: {stdout}\nstderr: {stderr}"
);
// 3. Extract the served URL the command printed (strip ANSI color codes).
let plain = strip_ansi(&stdout);
let url = plain
.split_whitespace()
.find(|t| t.starts_with("https://") && t.ends_with(".mp4"))
.unwrap_or_else(|| panic!("no served mp4 URL in output:\n{plain}"))
.to_string();
eprintln!("served URL: {url}");
// 4. Curl the URL and confirm it serves a valid ftyp mp4.
let head = Command::new("curl")
.args(["-s", "--max-time", "60", &url])
.output()
.expect("spawn curl");
assert!(head.status.success(), "curl failed for {url}");
let body = head.stdout;
assert!(body.len() > 64, "served body too small ({} bytes)", body.len());
// ISO base-media files carry the `ftyp` box marker at bytes 4..8.
let marker = &body[4..8.min(body.len())];
assert_eq!(
marker, b"ftyp",
"served bytes are not a valid mp4 (expected ftyp at offset 4, got {:?})",
String::from_utf8_lossy(marker)
);
// 5. Best-effort cleanup: remove the test file from the page repo.
let _ = Command::new("adom-wiki")
.args(["repo", "rm", &page, TEST_FILE])
.output();
let _ = std::fs::remove_file(&mp4);
}
fn strip_ansi(s: &str) -> String {
let mut out = String::with_capacity(s.len());
let bytes = s.as_bytes();
let mut i = 0;
while i < bytes.len() {
if bytes[i] == 0x1b {
// Skip CSI sequence: ESC '[' ... final byte in 0x40..=0x7e
i += 1;
if i < bytes.len() && bytes[i] == b'[' {
i += 1;
while i < bytes.len() && !(0x40..=0x7e).contains(&bytes[i]) {
i += 1;
}
i += 1; // consume final byte
}
} else {
out.push(bytes[i] as char);
i += 1;
}
}
out
}