#[cfg(all(
target_os = "linux",
target_env = "gnu",
any(target_arch = "x86_64", target_arch = "aarch64"),
))]
#[test]
fn ktstr_binary_dynamic_deps_pinned() {
let binary = env!("CARGO_BIN_EXE_ktstr");
let output = std::process::Command::new("ldd")
.arg(binary)
.output()
.expect("ldd must be available on the host");
assert!(
output.status.success(),
"ldd failed on {binary}: {}",
String::from_utf8_lossy(&output.stderr),
);
let stdout = String::from_utf8_lossy(&output.stdout);
let deps: Vec<&str> = stdout
.lines()
.filter(|l| !l.contains("linux-vdso.so"))
.filter(|l| !l.contains("ld-linux-") && !l.contains("/ld.so"))
.filter(|l| !l.trim().is_empty())
.collect();
const EXPECTED_DEPS: usize = 5;
assert_eq!(
deps.len(),
EXPECTED_DEPS,
"ktstr binary dynamic-dep count drifted from {EXPECTED_DEPS}:\nldd output:\n{stdout}\n\
Filtered deps ({} entries):\n{}",
deps.len(),
deps.join("\n"),
);
let expected_names = ["libgcc_s.so", "libm.so", "libc.so"];
for name in &expected_names {
assert!(
deps.iter().any(|l| l.contains(name)),
"expected dynamic dep {name:?} not found in ldd output:\n{stdout}",
);
}
let libgcc_line = deps
.iter()
.find(|l| l.contains("libgcc_s.so"))
.expect("libgcc_s.so line must be in the filtered deps — checked above");
assert!(
libgcc_line.contains("=>") && !libgcc_line.contains("not found"),
"libgcc_s line does not show a successful `name => path` \
resolution: {libgcc_line:?}\nfull ldd output:\n{stdout}",
);
if let Some(after_arrow) = libgcc_line.split("=>").nth(1) {
let resolved_path = after_arrow.split_whitespace().next().unwrap_or("");
if !resolved_path.is_empty() {
let p = std::path::Path::new(resolved_path);
assert!(
p.exists() && p.is_file(),
"libgcc_s resolved path {resolved_path:?} does not \
exist or is not a regular file. Runner image is \
likely corrupt or missing the libgcc runtime.\n\
full ldd output:\n{stdout}",
);
}
}
}