canic_testkit/artifacts/
wasm.rs1use std::{
2 fs,
3 path::{Path, PathBuf},
4 process::Command,
5};
6
7pub const INTERNAL_TEST_ENDPOINTS_ENV: (&str, &str) = ("CANIC_INTERNAL_TEST_ENDPOINTS", "1");
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub enum WasmBuildProfile {
15 Debug,
16 Fast,
17 Release,
18}
19
20impl WasmBuildProfile {
21 #[must_use]
23 pub const fn cargo_args(self) -> &'static [&'static str] {
24 match self {
25 Self::Debug => &[],
26 Self::Fast => &["--profile", "fast"],
27 Self::Release => &["--release"],
28 }
29 }
30
31 #[must_use]
33 pub const fn target_dir_name(self) -> &'static str {
34 match self {
35 Self::Debug => "debug",
36 Self::Fast => "fast",
37 Self::Release => "release",
38 }
39 }
40
41 #[must_use]
43 pub const fn canic_wasm_profile_value(self) -> &'static str {
44 match self {
45 Self::Debug => "debug",
46 Self::Fast => "fast",
47 Self::Release => "release",
48 }
49 }
50}
51
52#[must_use]
54pub fn wasm_path(target_dir: &Path, crate_name: &str, profile: WasmBuildProfile) -> PathBuf {
55 target_dir
56 .join("wasm32-unknown-unknown")
57 .join(profile.target_dir_name())
58 .join(format!("{crate_name}.wasm"))
59}
60
61#[must_use]
63pub fn wasm_artifacts_ready(
64 target_dir: &Path,
65 canisters: &[&str],
66 profile: WasmBuildProfile,
67) -> bool {
68 canisters
69 .iter()
70 .all(|name| wasm_path(target_dir, name, profile).is_file())
71}
72
73#[must_use]
75pub fn read_wasm(target_dir: &Path, crate_name: &str, profile: WasmBuildProfile) -> Vec<u8> {
76 let path = wasm_path(target_dir, crate_name, profile);
77 fs::read(&path).unwrap_or_else(|err| panic!("failed to read {crate_name} wasm: {err}"))
78}
79
80pub fn build_wasm_canisters(
82 workspace_root: &Path,
83 target_dir: &Path,
84 packages: &[&str],
85 profile: WasmBuildProfile,
86 extra_env: &[(&str, &str)],
87) {
88 let mut cmd = cargo_command();
89 cmd.current_dir(workspace_root);
90 cmd.env("CARGO_TARGET_DIR", target_dir);
91 cmd.env("DFX_NETWORK", "local");
92 cmd.args(["build", "--target", "wasm32-unknown-unknown"]);
93 cmd.args(profile.cargo_args());
94
95 for (key, value) in extra_env {
96 cmd.env(key, value);
97 }
98
99 for name in packages {
100 cmd.args(["-p", name]);
101 }
102
103 let output = cmd.output().expect("failed to run cargo build");
104 assert!(
105 output.status.success(),
106 "cargo build failed: {}",
107 String::from_utf8_lossy(&output.stderr)
108 );
109}
110
111fn cargo_command() -> Command {
112 let cargo = std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into());
113 let mut command = Command::new(cargo);
114
115 if let Some(toolchain) = std::env::var_os("RUSTUP_TOOLCHAIN") {
116 command.env("RUSTUP_TOOLCHAIN", toolchain);
117 }
118
119 command
120}
121
122pub fn build_internal_test_wasm_canisters(
124 workspace_root: &Path,
125 target_dir: &Path,
126 packages: &[&str],
127 profile: WasmBuildProfile,
128) {
129 build_wasm_canisters(
130 workspace_root,
131 target_dir,
132 packages,
133 profile,
134 &[INTERNAL_TEST_ENDPOINTS_ENV],
135 );
136}
137
138pub fn build_internal_test_wasm_canisters_with_env<'a>(
141 workspace_root: &Path,
142 target_dir: &Path,
143 packages: &[&str],
144 profile: WasmBuildProfile,
145 extra_env: &[(&'a str, &'a str)],
146) {
147 let mut build_env = Vec::with_capacity(extra_env.len() + 1);
148 build_env.push(INTERNAL_TEST_ENDPOINTS_ENV);
149 build_env.extend_from_slice(extra_env);
150 build_wasm_canisters(workspace_root, target_dir, packages, profile, &build_env);
151}