audio2face3d-server 0.1.0

Audio2Face-3D compatible gRPC server
#![cfg(all(feature = "cli", feature = "mock"))]
use std::{
    process::{Child, Command, Stdio},
    time::{Duration, Instant},
};
struct Process(Child);
impl Drop for Process {
    fn drop(&mut self) {
        let _ = self.0.kill();
        let _ = self.0.wait();
    }
}
#[test]
fn cli_logs_append_and_preserve_typed_json_fields() {
    let root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../../temp/logging-work/cli-tests");
    std::fs::create_dir_all(&root).unwrap();
    let path = root.join(format!("{}.jsonl", std::process::id()));
    std::fs::write(&path, "{\"existing\":true}\n").unwrap();
    let mut command = Command::new(env!("CARGO_BIN_EXE_audio2face3d-server"));
    command
        .args([
            "--backend",
            "mock",
            "--listen",
            "127.0.0.1:0",
            "--log-format",
            "json",
            "--log-file",
        ])
        .arg(&path)
        .env("RUST_LOG", "off,audio2face3d_server=info")
        .env_remove("AUDIO2FACE3D_API_KEY")
        .stdout(Stdio::null())
        .stderr(Stdio::null());
    #[cfg(windows)]
    {
        use std::os::windows::process::CommandExt;
        command.creation_flags(0x08000000);
    }
    let mut child = Process(command.spawn().unwrap());
    let deadline = Instant::now() + Duration::from_secs(10);
    loop {
        let text = std::fs::read_to_string(&path).unwrap();
        let values: Vec<serde_json::Value> = text
            .lines()
            .filter_map(|line| serde_json::from_str(line).ok())
            .collect();
        if let Some(serving) = values.iter().find(|v| v["message"] == "serving") {
            assert_eq!(values[0]["existing"], true);
            assert!(serving["timestamp"].as_str().unwrap().ends_with("+00:00"));
            assert!(
                serving["fields"]["address"]
                    .as_str()
                    .unwrap()
                    .contains("127.0.0.1")
            );
            assert!(
                serving["fields"]["source"]
                    .as_str()
                    .unwrap()
                    .starts_with("audio2face3d_server")
            );
            break;
        }
        assert!(child.0.try_wait().unwrap().is_none(), "server exited");
        assert!(Instant::now() < deadline, "no startup record");
        std::thread::sleep(Duration::from_millis(10));
    }
}
#[test]
fn cli_reports_file_open_failure_and_help_lists_logging_options() {
    let binary = env!("CARGO_BIN_EXE_audio2face3d-server");
    let output = Command::new(binary)
        .args([
            "--backend",
            "mock",
            "--log-file",
            env!("CARGO_MANIFEST_DIR"),
        ])
        .env_remove("AUDIO2FACE3D_API_KEY")
        .output()
        .unwrap();
    assert!(!output.status.success());
    let output = Command::new(binary).arg("--help").output().unwrap();
    assert!(output.status.success());
    let text = String::from_utf8(output.stdout).unwrap();
    for option in [
        "--log-format",
        "--log-file",
        "--log-dir",
        "--log-timezone",
        "--log-overflow",
        "--log-queue-capacity",
    ] {
        assert!(text.contains(option));
    }
}