native-ipc 0.5.0

One safe API for least-authority native shared memory: sealed memfd on Linux, Mach memory entries on macOS, exact-rights sections on Windows
use std::io::{Read, Write};
use std::time::Duration;

use static_assertions::assert_not_impl_any;

use super::*;

assert_not_impl_any!(BrokerTraceReportReceiver: Clone, Copy);
assert_not_impl_any!(AuthenticatedBrokerTraceReport: Clone, Copy);
assert_not_impl_any!(BrokerResumeSender: Clone, Copy);

fn binding() -> BrokerTraceReportBinding {
    BrokerTraceReportBinding::new(
        SupervisorDeadline::from_wire(u64::MAX - 1),
        91,
        1,
        501,
        20,
        [1; 32],
        [2; 32],
        [3; 32],
        [4; 32],
        [5; 32],
    )
}

#[test]
fn trace_report_codec_is_fixed_and_rejects_every_mutation() {
    let exact = encode_broker_trace_report(binding()).unwrap();
    assert_eq!(exact.len(), BROKER_TRACE_REPORT_BYTES);
    assert_eq!(
        ReceivedBrokerTraceReport::decode(&exact).unwrap(),
        binding()
    );

    for offset in [0, 8, 10, 12, 16, 24, 32, 40, 44, 48, 80, 112, 144, 176, 208] {
        let mut mutation = exact;
        mutation[offset] ^= 1;
        assert_ne!(
            ReceivedBrokerTraceReport::decode(&mutation),
            Ok(binding()),
            "offset {offset}"
        );
    }
}

#[test]
fn receiver_requires_exact_frame_eof_and_expected_binding() {
    let (mut writer, reader) = UnixStream::pair().unwrap();
    let mut receipt =
        BrokerTraceReportReceiver::new(reader, binding(), Instant::now() + Duration::from_secs(2))
            .unwrap();
    let exact = encode_broker_trace_report(binding()).unwrap();
    writer.write_all(&exact[..100]).unwrap();
    assert!(receipt.poll().unwrap().is_none());
    writer.write_all(&exact[100..]).unwrap();
    assert!(receipt.poll().unwrap().is_none());
    finish_broker_trace_report(&writer).unwrap();
    assert!(receipt.poll().unwrap().is_some());

    for bytes in [exact[..exact.len() - 1].to_vec(), {
        let mut extended = exact.to_vec();
        extended.push(1);
        extended
    }] {
        let (mut writer, reader) = UnixStream::pair().unwrap();
        let mut receipt = BrokerTraceReportReceiver::new(
            reader,
            binding(),
            Instant::now() + Duration::from_secs(2),
        )
        .unwrap();
        writer.write_all(&bytes).unwrap();
        finish_broker_trace_report(&writer).unwrap();
        assert!(receipt.poll().is_err());
    }

    let mut wrong = binding();
    wrong.session[31] ^= 1;
    let (mut writer, reader) = UnixStream::pair().unwrap();
    let mut receipt =
        BrokerTraceReportReceiver::new(reader, wrong, Instant::now() + Duration::from_secs(2))
            .unwrap();
    writer.write_all(&exact).unwrap();
    finish_broker_trace_report(&writer).unwrap();
    assert!(matches!(
        receipt.poll(),
        Err(BrokerTraceReportError::Binding)
    ));

    let (_writer, reader) = UnixStream::pair().unwrap();
    assert!(matches!(
        BrokerTraceReportReceiver::new(reader, binding(), Instant::now()),
        Err(BrokerTraceReportError::DeadlineExpired)
    ));
}

#[test]
fn reverse_resume_commit_is_exact_one_byte_plus_eof() {
    let (service, mut broker) = UnixStream::pair().unwrap();
    service.set_nonblocking(true).unwrap();
    let mut resume_sender = BrokerResumeSender {
        stream: Some(service),
    };
    resume_sender.commit_after_ready().unwrap();
    let mut resume = [0_u8; 2];
    assert_eq!(broker.read(&mut resume).unwrap(), 1);
    assert_eq!(resume[0], BROKER_RESUME_BYTE[0]);
    assert_eq!(broker.read(&mut resume).unwrap(), 0);
}