#![cfg(unix)]
use serde_json::Value;
use std::ffi::OsString;
use std::os::unix::ffi::OsStringExt;
use std::path::Path;
use std::process::{Command, Output};
const KACHE_BIN: &str = env!("CARGO_BIN_EXE_kache");
#[allow(dead_code)]
mod common;
use common::hermetic_command;
fn proxied_cargo(home: &Path, cache: &Path, target: &Path) -> Command {
let mut command = hermetic_command(KACHE_BIN, cache, Some(&cache.join("config.toml")));
command
.env("HOME", home)
.env("CARGO_HOME", home.join(".cargo"))
.env("CARGO_TARGET_DIR", target)
.env("CARGO_INCREMENTAL", "0")
.env("RUSTC_WRAPPER", KACHE_BIN)
.env("KACHE_LOG", "off")
.env_remove("RUSTFLAGS")
.env_remove("CARGO_ENCODED_RUSTFLAGS")
.env_remove("CARGO_BUILD_RUSTFLAGS")
.env_remove("CARGO_BUILD_BUILD_DIR");
command
}
#[test]
fn canonical_cargo_home_alias_keeps_existing_cargo_unit_fresh() {
let dir = tempfile::tempdir().unwrap();
let home = dir.path().join("home");
let project = home.join("work/project");
let cargo_home = home.join(".cargo");
let cache = dir.path().join("cache");
let cold_target = dir.path().join("target-cold");
std::fs::create_dir_all(project.join("src")).unwrap();
std::fs::create_dir_all(&cargo_home).unwrap();
std::fs::create_dir_all(&cache).unwrap();
std::fs::write(
project.join("Cargo.toml"),
"[package]\nname = \"proxy_fixture\"\nversion = \"0.1.0\"\nedition = \"2024\"\n",
)
.unwrap();
std::fs::write(project.join("src/lib.rs"), "pub fn answer() -> u8 { 42 }\n").unwrap();
std::fs::write(
cargo_home.join("config.toml"),
"[build]\nrustflags = [\"--cfg\", \"kache_proxy_fixture\"]\n",
)
.unwrap();
let mut cold = proxied_cargo(&home, &cache, &cold_target);
cold.args(["cargo", "--", "check", "--quiet"])
.current_dir(&project)
.env("KACHE_REAL_CARGO", env!("CARGO"));
let cold = cold.output().unwrap();
assert!(
cold.status.success(),
"cold cargo failed: {}",
String::from_utf8_lossy(&cold.stderr)
);
std::os::unix::fs::symlink(&cargo_home, home.join("work/.cargo")).unwrap();
let mut warm = proxied_cargo(&home, &cache, &cold_target);
warm.args(["cargo", "--", "check", "--verbose", "--color=never"])
.current_dir(&project)
.env("KACHE_REAL_CARGO", env!("CARGO"))
.env("CARGO_TERM_COLOR", "always");
let warm = warm.output().unwrap();
assert!(
warm.status.success(),
"proxied cargo failed: {}",
String::from_utf8_lossy(&warm.stderr)
);
assert!(
String::from_utf8_lossy(&warm.stderr).contains("Fresh proxy_fixture"),
"Cargo should keep the existing unit fresh: {}",
String::from_utf8_lossy(&warm.stderr)
);
let events: Vec<Value> = std::fs::read_to_string(cache.join("events.jsonl"))
.unwrap()
.lines()
.filter_map(|line| serde_json::from_str(line).ok())
.filter(|event: &Value| event["crate_name"] == "proxy_fixture")
.collect();
assert_eq!(
events.len(),
1,
"a fresh Cargo unit must not invoke the wrapper again: {events:#?}"
);
assert_eq!(events[0]["result"], "miss", "events: {events:#?}");
assert_eq!(events[0]["compiler_runs"], 1, "events: {events:#?}");
}
fn write_key_fixture(project: &Path) {
std::fs::create_dir_all(project.join("src")).unwrap();
std::fs::write(
project.join("Cargo.toml"),
"[package]\nname = \"proxy_key_fixture\"\nversion = \"0.1.0\"\nedition = \"2024\"\n",
)
.unwrap();
std::fs::write(
project.join("src/lib.rs"),
"#[cfg(not(kache_proxy_fixture))]\ncompile_error!(\"config rustflags were lost\");\n\
pub fn answer() -> u8 { 42 }\n",
)
.unwrap();
}
#[test]
fn collapsed_rustflags_stay_out_of_the_environment_cargo_passes_on() {
let dir = tempfile::tempdir().unwrap();
let root = dir.path().canonicalize().unwrap();
let home = root.join("home");
let cargo_home = home.join(".cargo");
let cache = root.join("cache");
let plain = home.join("plain/project");
let aliased = home.join("aliased/project");
std::fs::create_dir_all(&cargo_home).unwrap();
std::fs::create_dir_all(&cache).unwrap();
std::fs::write(
cargo_home.join("config.toml"),
"[build]\nrustflags = [\"--cfg\", \"kache_proxy_fixture\"]\n",
)
.unwrap();
write_key_fixture(&plain);
write_key_fixture(&aliased);
std::os::unix::fs::symlink(&cargo_home, home.join("aliased/.cargo")).unwrap();
for (project, target) in [(&plain, "target-plain"), (&aliased, "target-aliased")] {
let mut command = proxied_cargo(&home, &cache, &root.join(target));
command
.args(["cargo", "--", "check", "--quiet"])
.current_dir(project)
.env("KACHE_REAL_CARGO", env!("CARGO"));
let output = command.output().unwrap();
assert!(
output.status.success(),
"proxied cargo failed in {}: {}",
project.display(),
String::from_utf8_lossy(&output.stderr)
);
}
let events: Vec<Value> = std::fs::read_to_string(cache.join("events.jsonl"))
.unwrap()
.lines()
.filter_map(|line| serde_json::from_str(line).ok())
.filter(|event: &Value| event["crate_name"] == "proxy_key_fixture")
.collect();
assert_eq!(events.len(), 2, "events: {events:#?}");
assert_eq!(events[0]["result"], "miss", "events: {events:#?}");
assert_eq!(
events[1]["result"], "local_hit",
"the wrapper saw the proxy's rustflags in its environment: {events:#?}"
);
assert_eq!(events[0]["cache_key"], events[1]["cache_key"]);
}
#[test]
fn worktree_build_dir_stays_out_of_nested_cargo_builds() {
let dir = tempfile::tempdir().unwrap();
let root = dir.path().canonicalize().unwrap();
let home = root.join("home");
let cache = root.join("cache");
let guest = root.join("guest");
let host = root.join("host");
let nested_target = root.join("nested-target");
std::fs::create_dir_all(home.join(".cargo")).unwrap();
std::fs::create_dir_all(&cache).unwrap();
std::fs::create_dir_all(guest.join("src")).unwrap();
std::fs::create_dir_all(host.join("src")).unwrap();
std::fs::write(
guest.join("Cargo.toml"),
"[package]\nname = \"proxy_guest\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n[workspace]\n",
)
.unwrap();
std::fs::write(guest.join("src/lib.rs"), "pub fn guest() {}\n").unwrap();
std::fs::write(
host.join("Cargo.toml"),
"[package]\nname = \"proxy_host\"\nversion = \"0.1.0\"\nedition = \"2024\"\n",
)
.unwrap();
std::fs::write(host.join("src/lib.rs"), "pub fn host() {}\n").unwrap();
std::fs::write(
host.join("build.rs"),
format!(
"fn main() {{\n \
let status = std::process::Command::new(std::env::var_os(\"CARGO\").unwrap())\n \
.args([\"build\", \"--quiet\", \"--manifest-path\", {:?}, \"--target-dir\", {:?}])\n \
.status()\n \
.unwrap();\n \
assert!(status.success(), \"nested cargo failed\");\n\
}}\n",
guest.join("Cargo.toml"),
nested_target,
),
)
.unwrap();
let mut command = proxied_cargo(&home, &cache, &root.join("target"));
command
.args(["cargo", "--", "build", "--quiet"])
.current_dir(&host)
.env("KACHE_REAL_CARGO", env!("CARGO"))
.env_remove("RUSTC_WRAPPER");
let output = command.output().unwrap();
assert!(
output.status.success(),
"proxied cargo failed: {}",
String::from_utf8_lossy(&output.stderr)
);
assert!(
host.join("target/debug/.fingerprint").is_dir(),
"the proxied build keeps its own intermediates in the worktree"
);
assert!(
nested_target.join("debug/.fingerprint").is_dir(),
"the nested build must keep its intermediates where its build script put them"
);
assert!(
!guest.join("target").exists(),
"the proxy's build-dir redirected a nested Cargo build into its source tree"
);
}
#[test]
fn collapsed_single_use_rustc_option_passes_cargo_target_probe() {
let dir = tempfile::tempdir().unwrap();
let root = dir.path().canonicalize().unwrap();
let home = root.join("home");
let cargo_home = home.join(".cargo");
let cache = root.join("cache");
let project = home.join("work/project");
std::fs::create_dir_all(&cargo_home).unwrap();
std::fs::create_dir_all(&cache).unwrap();
std::fs::write(
cargo_home.join("config.toml"),
"[build]\nrustflags = [\"--diagnostic-width\", \"80\", \"--cfg\", \"kache_proxy_fixture\"]\n",
)
.unwrap();
write_key_fixture(&project);
std::os::unix::fs::symlink(&cargo_home, home.join("work/.cargo")).unwrap();
let mut command = proxied_cargo(&home, &cache, &root.join("target"));
command
.args(["cargo", "--", "check", "--quiet"])
.current_dir(&project)
.env("KACHE_REAL_CARGO", env!("CARGO"));
let output = command.output().unwrap();
assert!(
output.status.success(),
"proxied cargo failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
fn versioned_fake_cargo(path: &Path, version: &str) {
kache_fs::testutil::write_executable(
path,
format!(
"#!/bin/sh\ncase \"$*\" in\n \
'+new -V') echo 'cargo 1.91.0 (0000000 2025-10-10)' ;;\n \
*-V) echo 'cargo {version} (0000000 2020-01-01)' ;;\n \
*) printf '%s' \"$*\" > \"$KACHE_TEST_CAPTURE\" ;;\n\
esac\n"
),
);
}
#[test]
fn build_dir_override_needs_a_cargo_that_knows_the_key() {
let isolated = "--config build.build-dir=\"{workspace-root}/target\"";
for (args, version, expected) in [
(&["build"][..], "1.62.1", "build".to_string()),
(&["build"], "1.90.0", "build".to_string()),
(&["build"], "1.91.0", format!("{isolated} build")),
(
&["+new", "check"],
"1.62.1",
format!("+new {isolated} check"),
),
(&["build"], "unknown", "build".to_string()),
] {
let dir = tempfile::tempdir().unwrap();
let home = dir.path().join("home");
let project = dir.path().join("project");
let fake_cargo = dir.path().join("cargo");
let capture = dir.path().join("captured-args");
std::fs::create_dir_all(home.join(".cargo")).unwrap();
std::fs::create_dir_all(&project).unwrap();
versioned_fake_cargo(&fake_cargo, version);
let output = Command::new(KACHE_BIN)
.arg("cargo")
.arg("--")
.args(args)
.current_dir(&project)
.env("HOME", &home)
.env("CARGO_HOME", home.join(".cargo"))
.env("KACHE_REAL_CARGO", &fake_cargo)
.env("KACHE_TEST_CAPTURE", &capture)
.env_remove("CARGO_BUILD_BUILD_DIR")
.env_remove("RUSTFLAGS")
.env_remove("CARGO_ENCODED_RUSTFLAGS")
.env_remove("CARGO_BUILD_RUSTFLAGS")
.output()
.unwrap();
assert!(
output.status.success(),
"proxy failed: {}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(
std::fs::read_to_string(&capture).unwrap(),
expected,
"args {args:?} on Cargo {version}"
);
}
}
#[test]
fn explicit_rustflags_keep_their_cargo_precedence() {
let dir = tempfile::tempdir().unwrap();
let home = dir.path().join("home");
let project = home.join("work/project");
let cargo_home = home.join(".cargo");
let cache = dir.path().join("cache");
let target = dir.path().join("target");
std::fs::create_dir_all(project.join("src")).unwrap();
std::fs::create_dir_all(&cargo_home).unwrap();
std::fs::create_dir_all(&cache).unwrap();
std::fs::write(
project.join("Cargo.toml"),
"[package]\nname = \"proxy_env_fixture\"\nversion = \"0.1.0\"\nedition = \"2024\"\n",
)
.unwrap();
std::fs::write(
project.join("src/lib.rs"),
"#[cfg(not(from_env))]\ncompile_error!(\"explicit RUSTFLAGS was replaced\");\n",
)
.unwrap();
std::fs::write(
cargo_home.join("config.toml"),
"[build]\nrustflags = [\"--cfg\", \"from_config\"]\n",
)
.unwrap();
std::os::unix::fs::symlink(&cargo_home, home.join("work/.cargo")).unwrap();
let mut command = proxied_cargo(&home, &cache, &target);
command
.args(["cargo", "--", "check", "--quiet"])
.current_dir(&project)
.env("KACHE_REAL_CARGO", env!("CARGO"));
command.env("RUSTFLAGS", "--cfg from_env");
let output = command.output().unwrap();
assert!(
output.status.success(),
"explicit RUSTFLAGS lost precedence: {}",
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn non_utf8_cargo_argument_passes_through_without_cli_panic() {
let dir = tempfile::tempdir().unwrap();
let fake_cargo = dir.path().join("cargo");
kache_fs::testutil::write_executable(&fake_cargo, "#!/bin/sh\nexit 0\n");
let output = Command::new(KACHE_BIN)
.args(["cargo", "--", "build"])
.arg(OsString::from_vec(vec![b'f', b'o', 0x80]))
.env("KACHE_REAL_CARGO", &fake_cargo)
.output()
.unwrap();
assert!(
output.status.success(),
"non-UTF-8 passthrough failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn non_utf8_wrapper_argument_fails_closed_before_compiler_execution() {
let dir = tempfile::tempdir().unwrap();
let fake_rustc = dir.path().join("rustc");
let sentinel = dir.path().join("compiler-ran");
kache_fs::testutil::write_executable(
&fake_rustc,
format!("#!/bin/sh\ntouch '{}'\n", sentinel.display()),
);
let output = Command::new(KACHE_BIN)
.arg(&fake_rustc)
.arg(OsString::from_vec(vec![b's', b'r', b'c', b'/', 0x80]))
.env("RUSTC", &fake_rustc)
.output()
.unwrap();
assert!(!output.status.success());
assert!(!sentinel.exists(), "unsafe compiler fallback was executed");
assert!(
String::from_utf8_lossy(&output.stderr).contains("cannot be cached safely"),
"unexpected error: {}",
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn configured_build_dir_reaches_cargo_without_proxy_override() {
let dir = tempfile::tempdir().unwrap();
let home = dir.path().join("home");
let project = dir.path().join("project");
let config_dir = project.join(".cargo");
let fake_cargo = dir.path().join("cargo");
let capture = dir.path().join("captured-build-dir");
std::fs::create_dir_all(home.join(".cargo")).unwrap();
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(
config_dir.join("config.toml"),
"[build]\nbuild-dir = \"configured-build\"\n",
)
.unwrap();
kache_fs::testutil::write_executable(
&fake_cargo,
"#!/bin/sh\nprintf '%s %s' \"${CARGO_BUILD_BUILD_DIR-unset}\" \"$*\" > \"$KACHE_TEST_CAPTURE\"\n",
);
let output = Command::new(KACHE_BIN)
.args(["cargo", "--", "build"])
.current_dir(&project)
.env("HOME", &home)
.env("CARGO_HOME", home.join(".cargo"))
.env("KACHE_REAL_CARGO", &fake_cargo)
.env("KACHE_TEST_CAPTURE", &capture)
.env_remove("CARGO_BUILD_BUILD_DIR")
.output()
.unwrap();
assert!(
output.status.success(),
"proxy failed: {}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(
std::fs::read_to_string(capture).unwrap(),
"unset build",
"a config-defined build-dir must retain Cargo precedence"
);
}
fn write_shared_target_project(root: &Path, value: &str) {
std::fs::create_dir_all(root.join("src")).unwrap();
let manifest = root.join("Cargo.toml");
let source = root.join("src/main.rs");
std::fs::write(
&manifest,
"[package]\nname = \"proxy_shared_target\"\nversion = \"0.1.0\"\nedition = \"2024\"\n",
)
.unwrap();
std::fs::write(&source, format!("fn main() {{ print!({value:?}); }}\n")).unwrap();
let old = filetime::FileTime::from_unix_time(1_600_000_000, 0);
filetime::set_file_mtime(&manifest, old).unwrap();
filetime::set_file_mtime(&source, old).unwrap();
}
fn proxied_shared_target_build(project: &Path, home: &Path, cache: &Path, target: &Path) -> Output {
let mut command = proxied_cargo(home, cache, target);
command
.args(["cargo", "--", "build", "--quiet"])
.current_dir(project)
.env("KACHE_REAL_CARGO", env!("CARGO"))
.env("KACHE_CACHE_EXECUTABLES", "1");
command.output().unwrap()
}
fn run_shared_target_binary(target: &Path) -> String {
let mut binary = target.join("debug/proxy_shared_target");
if cfg!(windows) {
binary.set_extension("exe");
}
let output = Command::new(&binary).output().unwrap();
assert!(output.status.success(), "{} failed", binary.display());
String::from_utf8(output.stdout).unwrap()
}
#[test]
fn cargo_proxy_isolates_fingerprints_while_sharing_final_target_and_kache() {
let dir = tempfile::tempdir().unwrap();
let home = dir.path().join("home");
let cache = dir.path().join("cache");
let shared_target = dir.path().join("shared-target");
let worktree_a = dir.path().join("worktree-a");
let worktree_b = dir.path().join("worktree-b");
let worktree_c = dir.path().join("worktree-c");
std::fs::create_dir_all(&home).unwrap();
std::fs::create_dir_all(&cache).unwrap();
write_shared_target_project(&worktree_a, "alpha");
write_shared_target_project(&worktree_b, "bravo");
write_shared_target_project(&worktree_c, "alpha");
let first = proxied_shared_target_build(&worktree_a, &home, &cache, &shared_target);
assert!(
first.status.success(),
"worktree A failed: {}",
String::from_utf8_lossy(&first.stderr)
);
assert_eq!(run_shared_target_binary(&shared_target), "alpha");
let second = proxied_shared_target_build(&worktree_b, &home, &cache, &shared_target);
assert!(
second.status.success(),
"worktree B failed: {}",
String::from_utf8_lossy(&second.stderr)
);
assert_eq!(
run_shared_target_binary(&shared_target),
"bravo",
"Cargo reused worktree A's shared fingerprint without invoking Kache"
);
let back_to_a = proxied_shared_target_build(&worktree_a, &home, &cache, &shared_target);
assert!(back_to_a.status.success());
assert_eq!(
run_shared_target_binary(&shared_target),
"alpha",
"a Fresh worktree-local unit did not refresh the shared final artifact"
);
let relocated = proxied_shared_target_build(&worktree_c, &home, &cache, &shared_target);
assert!(relocated.status.success());
assert_eq!(run_shared_target_binary(&shared_target), "alpha");
for worktree in [&worktree_a, &worktree_b, &worktree_c] {
assert!(
worktree.join("target/debug/.fingerprint").is_dir(),
"intermediate fingerprints must be private to {}",
worktree.display()
);
}
assert!(
!shared_target.join("debug/.fingerprint").exists(),
"the shared final target must not contain Cargo fingerprint state"
);
let events: Vec<Value> = std::fs::read_to_string(cache.join("events.jsonl"))
.unwrap()
.lines()
.filter_map(|line| serde_json::from_str(line).ok())
.filter(|event: &Value| event["crate_name"] == "proxy_shared_target")
.collect();
assert_eq!(events.len(), 3, "events: {events:#?}");
assert_eq!(events[0]["result"], "miss");
assert_ne!(events[1]["result"], "local_hit");
assert_eq!(events[2]["result"], "local_hit", "events: {events:#?}");
assert_eq!(events[2]["compiler_runs"], 0, "events: {events:#?}");
assert_eq!(events[0]["cache_key"], events[2]["cache_key"]);
}