Skip to main content

ic_testkit/artifacts/
wasm.rs

1use std::path::{Path, PathBuf};
2
3/// Resolve one crate's Wasm artifact under a caller-selected Cargo target directory.
4#[must_use]
5pub fn wasm_path(target_dir: &Path, crate_name: &str, profile_target_dir: &str) -> PathBuf {
6    target_dir
7        .join("wasm32-unknown-unknown")
8        .join(profile_target_dir)
9        .join(format!("{crate_name}.wasm"))
10}
11
12/// Check whether every requested Wasm artifact is a regular file.
13#[must_use]
14pub fn wasm_artifacts_ready(
15    target_dir: &Path,
16    canisters: &[&str],
17    profile_target_dir: &str,
18) -> bool {
19    canisters
20        .iter()
21        .all(|name| wasm_path(target_dir, name, profile_target_dir).is_file())
22}
23
24/// Read a compiled Wasm artifact for one crate.
25///
26/// The caller supplies the maximum accepted artifact size. Reads and allocation
27/// are bounded by the shared host library; symbolic links remain allowed in
28/// caller-controlled target directories. This reads bytes without validating
29/// the Wasm module; use [`ic_host_tools::wasm::inspect`] for structural facts.
30///
31/// # Errors
32/// Returns the shared filesystem, non-regular-file, allocation or size-limit error.
33pub fn read_wasm(
34    target_dir: &Path,
35    crate_name: &str,
36    profile_target_dir: &str,
37    max_bytes: usize,
38) -> Result<Vec<u8>, ic_host_tools::artifact::ArtifactError> {
39    let path = wasm_path(target_dir, crate_name, profile_target_dir);
40    ic_host_tools::artifact::read_file(&path, max_bytes)
41}
42
43#[cfg(test)]
44mod tests {
45    use super::{read_wasm, wasm_path};
46    use crate::artifacts::test_support::unique_temp_directory;
47    use ic_host_tools::artifact::ArtifactError;
48    use std::fs;
49
50    #[test]
51    fn compiled_artifact_reads_use_selected_profile_and_explicit_limit() {
52        let root = unique_temp_directory("bounded-wasm");
53        let path = wasm_path(&root, "canister", "custom");
54        fs::create_dir_all(path.parent().unwrap()).unwrap();
55        let bytes = b"\0asm\x01\0\0\0";
56        fs::write(&path, bytes).unwrap();
57        assert_eq!(
58            read_wasm(&root, "canister", "custom", bytes.len()).unwrap(),
59            bytes
60        );
61        assert!(matches!(
62            read_wasm(&root, "canister", "custom", bytes.len() - 1),
63            Err(ArtifactError::LimitExceeded { .. })
64        ));
65        assert!(matches!(
66            read_wasm(&root, "canister", "other", bytes.len()),
67            Err(ArtifactError::Io(error)) if error.kind() == std::io::ErrorKind::NotFound
68        ));
69        fs::remove_file(&path).unwrap();
70        fs::create_dir(&path).unwrap();
71        assert!(matches!(
72            read_wasm(&root, "canister", "custom", bytes.len()),
73            Err(ArtifactError::NotRegularFile)
74        ));
75        fs::remove_dir_all(root).unwrap();
76    }
77}