malvin 0.2.4

Non-interactive research and coding agent
use super::process_alive;
use super::read_orphan_pid;
use super::wait_for_init_reparent;
use std::io::Write;
use std::path::Path;
use std::process::{Child, ChildStdin, Command, Stdio};

pub fn spawn_user_shell_cooperator() -> (Child, ChildStdin) {
    let child_delay = super::hostile_script_delay_ms(200);
    let script = format!(
        "import os,sys,time\nwhile True:\n line=sys.stdin.readline()\n if not line:\n  break\n parts=line.strip().split()\n if len(parts)>=2 and parts[0]=='DAEMON':\n  pidfile=parts[1]\n  pid=os.fork()\n  if pid==0:\n   os.setsid()\n   g=os.fork()\n   if g==0:\n    open(pidfile,'w').write(str(os.getpid()))\n    os.execvp('sleep',['sleep','120'])\n   time.sleep({child_delay} / 1000)\n   os._exit(0)\n  os.waitpid(pid,0)\n",
    );
    let mut cmd = Command::new("python3");
    cmd.arg("-c").arg(script);
    cmd.stdin(Stdio::piped());
    cmd.stdout(Stdio::null());
    cmd.stderr(Stdio::null());
    let mut child = cmd.spawn().expect("spawn user shell cooperator");
    let stdin = child.stdin.take().expect("stdin");
    (child, stdin)
}

pub fn spawn_user_coincidental_daemon(user_shell_stdin: &mut ChildStdin, orphan_pid_file: &Path) {
    writeln!(user_shell_stdin, "DAEMON {}", orphan_pid_file.display())
        .expect("request user daemon spawn");
    user_shell_stdin.flush().expect("flush");
}

pub fn spawn_isolated_agent_sleep() -> (Child, u32) {
    use std::os::unix::process::CommandExt;
    let mut agent = Command::new("sleep");
    agent.arg("120").process_group(0);
    let child = agent.spawn().expect("spawn agent");
    let pgid = child.id();
    (child, pgid)
}

pub async fn setup_user_init_reparented_daemon(
    user_shell_stdin: &mut ChildStdin,
    orphan_pid_file: &Path,
) -> u32 {
    spawn_user_coincidental_daemon(user_shell_stdin, orphan_pid_file);
    let pid = read_orphan_pid(orphan_pid_file, None).await;
    wait_for_init_reparent(pid).await;
    assert!(process_alive(pid), "setup: user daemon should be running");
    pid
}

pub fn cleanup_user_coincidental_test(
    user_daemon_pid: u32,
    mut user_shell: Child,
    mut agent_child: Child,
) {
    let _ = Command::new("kill")
        .args(["-9", &user_daemon_pid.to_string()])
        .status();
    let _ = user_shell.kill();
    let _ = agent_child.kill();
    let _ = user_shell.wait();
    let _ = agent_child.wait();
}

#[cfg(test)]
mod kiss_cov_auto {
    use super::*;

    #[test]
    fn kiss_cov_spawn_isolated_agent_sleep() {
        let _ = spawn_isolated_agent_sleep;
    }

    #[test]
    fn kiss_cov_setup_user_init_reparented_daemon() {
        let _ = setup_user_init_reparented_daemon;
    }

    #[test]
    fn kiss_cov_cleanup_user_coincidental_test() {
        let _ = cleanup_user_coincidental_test;
    }
}