view tests/comm.rs @ 26:0feab4f4c2ce

Relax version requirements and update MSRV The MSRV was accidentally increased without documentation. Increase itself is fine since it satisfies "latest stable Debian" condition but given there are soundness issues this relaxes the version requirements to work on 1.48 and also documents it.
author Martin Habovstiak <martin.habovstiak@gmail.com>
date Fri, 28 Feb 2025 23:10:11 +0100
parents 1941e9d9819c
children cfef4593e207
line wrap: on
line source

use std::process::Child;
use std::ffi::OsStr;
use std::io::{self, Read, Write};

pub trait Test {
    const SOCKET_ADDR: &'static str;

    fn spawn_slave(program_name: &OsStr) -> io::Result<Child>;
}

const REQUEST: &[u8] = b"orange coin";
const RESPONSE: &[u8] = b"good";

fn main_master(slave: io::Result<Child>) {
    let mut slave = slave.expect("failed to run a child");

    // give slave some time to bind the socket just to be sure
    std::thread::sleep(std::time::Duration::from_secs(5));

    if let Some(exited) = slave.try_wait().expect("failed to check if the child exited") {
        panic!("child exited unexpectedly: {}", exited);
    }

    let mut client_socket = std::net::TcpStream::connect("localhost:4242").expect("Failed to connect to 127.0.0.1:4242");
    client_socket.write_all(REQUEST).expect("failed to send data");
    let mut buf = [0u8; RESPONSE.len()];
    client_socket.read_exact(&mut buf).expect("failed to read response");
    assert_eq!(buf, RESPONSE);

    let status = slave.wait().expect("faild to wait for slave");
    if !status.success() {
        panic!("slave did not exit with succcess, status: {}", status);
    }
}

fn main_slave(addr: &str) {
    use systemd_socket::SocketAddr;

    // SAFETY: this is the only thread that's going to mess with systemd sockets.
    unsafe {
        systemd_socket::init_unprotected().unwrap();
    }

    let socket = addr
        .parse::<SocketAddr>()
        .expect("failed to parse socket")
        .bind()
        .expect("failed to bind");

    let (mut client_socket, _) = socket.accept().expect("failed to accept");
    let mut buf = [0u8; REQUEST.len()];
    client_socket.read_exact(&mut buf).expect("failed to read response");
    assert_eq!(buf, REQUEST);
    client_socket.write_all(RESPONSE).expect("failed to send data");
}

pub fn main<T: Test>() {
    let mut args = std::env::args_os();
    let program_name = args.next().expect("missing program name");

    match std::env::var_os("SYSTEMD_SOCKET_INTEGRATION_TEST") {
        None => main_master(T::spawn_slave(&program_name)),
        Some(arg) if arg == "slave" => main_slave(T::SOCKET_ADDR),
        Some(arg) => panic!("Unknown argument '{:?}'", arg),
    }
}