1 //! f0rge #66: build must not read every blob fully into memory. A blob2 //! over the inline cap is streamed to `raw/`; its page is a placeholder3 //! and the build still succeeds.4 5 use std::sync::atomic::{AtomicU64, Ordering};6 7 static SEQ: AtomicU64 = AtomicU64::new(0);8 9 use std::path::{Path, PathBuf};10 use std::process::Command;11 12 fn git(repo: &Path, args: &[&str]) {13 let st = Command::new("git")14 .arg("-C")15 .arg(repo)16 .args(args)17 .status()18 .expect("spawn git");19 assert!(st.success(), "git {args:?} failed");20 }21 22 fn fresh_dir(prefix: &str) -> PathBuf {23 let dir = std::env::temp_dir().join(format!(24 "hu13-large-{prefix}-{}-{}",25 std::process::id(),26 std::time::SystemTime::now()27 .duration_since(std::time::UNIX_EPOCH)28 .map(|d| d.as_nanos())29 .unwrap_or(0)30 .wrapping_add(u128::from(SEQ.fetch_add(1, Ordering::Relaxed)))31 ));32 std::fs::create_dir_all(&dir).unwrap();33 dir34 }35 36 #[test]37 fn oversized_blob_is_streamed_and_never_aborts() {38 let repo = fresh_dir("repo");39 let out = fresh_dir("out");40 git(&repo, &["init", "-b", "main"]);41 git(&repo, &["config", "user.name", "hu13-test"]);42 git(&repo, &["config", "user.email", "[email protected]"]);43 git(&repo, &["config", "commit.gpgsign", "false"]);44 std::fs::write(repo.join("README.md"), "# large blob\n").unwrap();45 // 12 MiB of text: above MAX_INLINE_BLOB (8 MiB), compressible enough46 // for the test to stay fast.47 let big = vec![b'a'; 12 * 1024 * 1024];48 std::fs::write(repo.join("big.txt"), &big).unwrap();49 git(&repo, &["add", "-A"]);50 git(&repo, &["commit", "-m", "big"]);51 52 let produced = Command::new(env!("CARGO_BIN_EXE_hu13"))53 .arg("build")54 .arg(&repo)55 .arg("-o")56 .arg(&out)57 .output()58 .expect("spawn hu13 build");59 let stderr = String::from_utf8_lossy(&produced.stderr);60 assert!(produced.status.success(), "build failed: {stderr}");61 62 // Raw copy is byte-identical.63 let raw = std::fs::read(out.join("raw/big.txt")).expect("raw big.txt");64 assert_eq!(raw.len(), big.len());65 assert!(raw.iter().all(|b| *b == b'a'));66 67 // Page is a placeholder, not 12 MiB of spans.68 let page = std::fs::read_to_string(out.join("files/big.txt.html")).expect("page");69 assert!(page.contains("too large to preview"), "placeholder shown");70 assert!(page.contains("download the raw file"));71 assert!(page.len() < 200_000, "page stayed small: {}", page.len());72 73 // A normal file still gets a real preview.74 let readme = std::fs::read_to_string(out.join("files/README.md.html")).expect("readme");75 assert!(readme.contains("<h1>README.md</h1>") || readme.contains("README.md"));76 }