camber 0.2.2

Opinionated async Rust for IO-bound services on top of Tokio
Documentation
use std::io::Write;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use crate::common::{is_private_child, run_signal_contract_exact};

const SIGNAL_TIMEOUT: Duration = Duration::from_secs(5);

#[test]
fn signal_watcher_sets_flag_on_ctrl_c() {
    run_signal_contract(
        "runtime_signals::signal_watcher_sets_flag_on_ctrl_c",
        "phase5-signal-sigint",
        "PHASE5_SIGINT_OBSERVED",
        signal_hook::consts::SIGINT,
    );
}

#[test]
fn signal_watcher_sets_flag_on_sigterm() {
    run_signal_contract(
        "runtime_signals::signal_watcher_sets_flag_on_sigterm",
        "phase5-signal-sigterm",
        "PHASE5_SIGTERM_OBSERVED",
        signal_hook::consts::SIGTERM,
    );
}

fn run_signal_contract(test_name: &str, mode: &str, marker: &str, signal: i32) {
    if is_private_child(mode) {
        let runtime = tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .build()
            .unwrap();
        runtime.block_on(async {
            let shutdown = Arc::new(AtomicBool::new(false));
            let notify = Arc::new(tokio::sync::Notify::new());
            let watcher = camber::signals::spawn_signal_watcher(Arc::clone(&shutdown), notify);
            signal_hook::low_level::raise(signal).unwrap();
            tokio::time::timeout(SIGNAL_TIMEOUT, watcher)
                .await
                .unwrap()
                .unwrap();
            assert!(shutdown.load(Ordering::Acquire));
        });
        println!("{marker}");
        std::io::stdout().flush().unwrap();
        return;
    }

    let parent_id = std::process::id();
    let run = run_signal_contract_exact(test_name, mode, marker, SIGNAL_TIMEOUT).unwrap();
    assert!(
        run.success(),
        "signal child failed\nstdout: {}\nstderr: {}",
        String::from_utf8_lossy(run.stdout()),
        String::from_utf8_lossy(run.stderr())
    );
    assert_eq!(std::process::id(), parent_id);
}