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

nordisk/holger

holperf/tests/head.rs

//! HOL-HEAD-1: every backend answers `HEAD` with the `GET` answer's status and
//! headers, a `Content-Length` naming the `GET` body's length, and no body.
//!
//! RED-when-broken: the znippy backends ignored the method (`let _ = (method, body)`),
//! so a `HEAD` read and returned the whole body (a 64 MiB artifact for a size
//! question), and the raw backend answered `HEAD` without a length.

use traits::RepositoryBackendTrait;

fn content_length(h: &[(String, String)]) -> Option<usize> {
    h.iter()
        .find(|(k, _)| k.eq_ignore_ascii_case("content-length"))
        .and_then(|(_, v)| v.trim().parse().ok())
}

fn check(format: &str, b: &dyn RepositoryBackendTrait, urls: &[String], bad: &mut Vec<String>) {
    for u in urls.iter().take(2) {
        let (gs, _, gb) = b
            .handle_http2_request("GET", u, &[])
            .unwrap_or_else(|e| panic!("{format} GET {u}: {e:#}"));
        let (hs, hh, hb) = b
            .handle_http2_request("HEAD", u, &[])
            .unwrap_or_else(|e| panic!("{format} HEAD {u}: {e:#}"));
        if hs != gs {
            bad.push(format!("{format} {u}: HEAD {hs}, GET {gs}"));
        }
        if !hb.is_empty() {
            bad.push(format!(
                "{format} {u}: HEAD returned a {} byte body",
                hb.len()
            ));
        }
        if gs == 200 && content_length(&hh) != Some(gb.len()) {
            bad.push(format!(
                "{format} {u}: HEAD Content-Length {:?}, the GET body is {}",
                content_length(&hh),
                gb.len()
            ));
        }
    }
}

#[test]
fn every_backend_answers_head_with_headers_and_no_body() {
    let _ = rustls::crypto::ring::default_provider().install_default();
    let dir = tempfile::tempdir().unwrap();
    let mut bad = Vec::new();
    let mut seen = Vec::new();
    for sc in holperf::seed::all(dir.path(), 4, 4096, 64 * 1024, None).unwrap() {
        let b = (sc.open)();
        for urls in [&sc.index, &sc.meta2, &sc.small, &sc.large] {
            check(sc.format, b.as_ref(), urls, &mut bad);
        }
        seen.push(sc.format);
    }
    let cs = holperf::chain::build(dir.path(), 2, 4096, 64 * 1024, None)
        .unwrap()
        .expect("the chain scenarios");
    for sc in &cs.scenarios {
        if !sc.format.starts_with("chain-") || matches!(sc.format, "chain-pip" | "chain-npm") {
            continue; // the production and npm doors are the bench's own adapters, not backends
        }
        let b = (sc.open)();
        for urls in [&sc.index, &sc.meta2, &sc.small, &sc.large] {
            check(sc.format, b.as_ref(), urls, &mut bad);
        }
        seen.push(sc.format);
    }
    assert!(seen.len() >= 18, "every seeded format was asked: {seen:?}");
    assert!(
        bad.is_empty(),
        "{} HEAD answers were wrong:\n{}",
        bad.len(),
        bad.join("\n")
    );
}