Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/gunnar-pktline/tests/sideband.rs

//! Sideband tests.
//!
//! The band byte lives *inside* the payload, so a full sideband line carries
//! `MAX_PAYLOAD - 1` bytes of data. Getting that off by one produces lines one
//! byte over the protocol maximum, and only for payloads that land exactly on
//! a chunk boundary, which no small fixture will ever hit. Hence the multi-chunk
//! cases below are sized to straddle the boundary deliberately.

use gunnar_pktline::*;

fn enc(band: u8, data: &[u8]) -> Vec<u8> {
    let mut out = Vec::new();
    write_sideband(&mut out, band, data).expect("sideband write failed");
    out
}

/// Split a sideband stream into its lines, asserting each one is well formed.
fn lines(wire: &[u8], band: u8) -> Vec<Vec<u8>> {
    let mut rest = wire;
    let mut out = Vec::new();
    while !rest.is_empty() {
        match decode(rest).expect("sideband line failed to decode") {
            Decoded::Packet(Packet::Data(payload), n) => {
                assert!(
                    payload.len() <= MAX_PAYLOAD,
                    "line payload {} exceeds MAX_PAYLOAD {MAX_PAYLOAD}",
                    payload.len()
                );
                assert!(
                    !payload.is_empty(),
                    "a sideband line always has its band byte"
                );
                assert_eq!(payload[0], band, "every line must be marked with the band");
                out.push(payload[1..].to_vec());
                rest = &rest[n..];
            }
            other => panic!("expected a data packet, got {other:?}"),
        }
    }
    out
}

#[test]
fn a_short_sideband_line_is_byte_exact() {
    assert_eq!(enc(BAND_PROGRESS, b"hi"), b"0007\x02hi".to_vec());
    assert_eq!(enc(BAND_PACK, b"PACK"), b"0009\x01PACK".to_vec());
    assert_eq!(
        enc(BAND_ERROR, b"fatal: no\n"),
        b"000f\x03fatal: no\n".to_vec()
    );
}

#[test]
fn an_empty_sideband_write_emits_nothing_at_all() {
    // Not a bare band byte, not a zero-length line: nothing. A lone band byte is
    // a frame announcing no data; on band 3, an error message with no message.
    assert!(enc(BAND_PACK, b"").is_empty());
    assert!(enc(BAND_PROGRESS, b"").is_empty());
    assert!(enc(BAND_ERROR, b"").is_empty());
}

#[test]
fn one_full_chunk_is_one_line_at_exactly_the_maximum() {
    let data = vec![b'x'; SIDEBAND_CHUNK];
    let wire = enc(BAND_PACK, &data);
    assert_eq!(
        &wire[..4],
        b"fff0",
        "a full sideband line is the largest legal line"
    );
    assert_eq!(wire.len(), MAX_LINE);
    assert_eq!(lines(&wire, BAND_PACK), vec![data]);
}

#[test]
fn one_byte_past_a_chunk_becomes_two_lines() {
    let data = vec![b'y'; SIDEBAND_CHUNK + 1];
    let wire = enc(BAND_PROGRESS, &data);
    let got = lines(&wire, BAND_PROGRESS);
    assert_eq!(got.len(), 2);
    assert_eq!(got[0].len(), SIDEBAND_CHUNK);
    assert_eq!(got[1].len(), 1);
    assert_eq!(got.concat(), data);
}

#[test]
fn an_exact_multiple_of_the_chunk_emits_no_trailing_empty_line() {
    // A chunker written as "while remaining >= CHUNK { … }" plus a final flush
    // emits a spurious zero-data line here, which reads as a band-marked packet
    // carrying nothing.
    let data = vec![b'z'; 2 * SIDEBAND_CHUNK];
    let wire = enc(BAND_PACK, &data);
    let got = lines(&wire, BAND_PACK);
    assert_eq!(got.len(), 2);
    assert_eq!(got[0].len(), SIDEBAND_CHUNK);
    assert_eq!(got[1].len(), SIDEBAND_CHUNK);
    assert_eq!(wire.len(), 2 * MAX_LINE);
    assert_eq!(got.concat(), data);
}

#[test]
fn a_payload_over_twice_the_maximum_splits_reassembles_and_stays_in_band() {
    let len = 2 * MAX_PAYLOAD + 7;
    // Content varies per byte so a reassembly that reorders or duplicates a
    // chunk cannot pass by looking identical.
    let data: Vec<u8> = (0..len).map(|i| (i % 251) as u8).collect();
    let wire = enc(BAND_PACK, &data);

    let expected_lines = len.div_ceil(SIDEBAND_CHUNK);
    assert_eq!(expected_lines, 3);
    let got = lines(&wire, BAND_PACK);
    assert_eq!(got.len(), expected_lines);
    assert_eq!(got[0].len(), SIDEBAND_CHUNK);
    assert_eq!(got[1].len(), SIDEBAND_CHUNK);
    assert_eq!(got[2].len(), len - 2 * SIDEBAND_CHUNK);
    assert_eq!(got.concat(), data, "reassembly must be byte-exact");
    // Total on the wire: every line paid its own 4-byte header and band byte.
    assert_eq!(wire.len(), len + 5 * expected_lines);
}

#[test]
fn bands_do_not_bleed_into_one_another() {
    let mut wire = Vec::new();
    write_sideband(&mut wire, BAND_PACK, b"packdata").unwrap();
    write_sideband(&mut wire, BAND_PROGRESS, b"counting objects\n").unwrap();
    write_sideband(&mut wire, BAND_PACK, b"more").unwrap();
    write_flush(&mut wire).unwrap();

    let mut d = Decoder::new();
    d.push(&wire);
    let packets = d.drain().unwrap();
    assert_eq!(packets.len(), 4);
    let mut pack = Vec::new();
    let mut progress = Vec::new();
    for p in &packets[..3] {
        let payload = p.payload().unwrap();
        match payload[0] {
            BAND_PACK => pack.extend_from_slice(&payload[1..]),
            BAND_PROGRESS => progress.extend_from_slice(&payload[1..]),
            b => panic!("unexpected band {b}"),
        }
    }
    assert_eq!(pack, b"packdatamore".to_vec());
    assert_eq!(progress, b"counting objects\n".to_vec());
    assert_eq!(packets[3], Packet::Flush);
}

#[test]
fn a_sideband_stream_survives_being_read_one_byte_at_a_time() {
    let data: Vec<u8> = (0..3 * SIDEBAND_CHUNK / 2)
        .map(|i| (i % 256) as u8)
        .collect();
    let wire = enc(BAND_PACK, &data);
    let mut d = Decoder::new();
    let mut reassembled = Vec::new();
    for b in &wire {
        d.push(&[*b]);
        while let Some(p) = d.next_packet().unwrap() {
            reassembled.extend_from_slice(&p.payload().unwrap()[1..]);
        }
    }
    assert!(d.is_empty());
    assert_eq!(reassembled, data);
}