pub mod execution_settlement;
pub mod execution_workflow;
pub mod ic_mutation;
pub mod ic_observation;
pub mod ic_snapshot_download;
pub mod ic_snapshot_metadata;
pub mod ic_snapshot_upload;
pub mod ic_snapshot_upload_data_observation;
pub mod operation_plan;
pub mod provider;
pub mod ready;
pub mod response_fault;
pub mod restore_safety;
pub mod retained_reply;
pub mod schema;
pub mod update;
pub fn hex_bytes(hex: &str) -> Vec<u8> {
let (pairs, remainder) = hex.as_bytes().as_chunks::<2>();
assert!(
remainder.is_empty(),
"fixture hex must contain complete bytes"
);
pairs
.iter()
.map(|pair| {
u8::from_str_radix(
std::str::from_utf8(pair).expect("fixture hex must be ASCII"),
16,
)
.expect("invalid fixture hex byte")
})
.collect()
}
#[test]
fn fixture_hex_admits_exact_bytes_and_rejects_partial_or_malformed_input() {
assert_eq!(hex_bytes("00ff80AB"), [0, 255, 128, 171]);
assert_eq!(hex_bytes(""), [] as [u8; 0]);
for invalid in ["0", "abc", "0g", "é", "000Z"] {
assert!(
std::panic::catch_unwind(|| hex_bytes(invalid)).is_err(),
"{invalid}"
);
}
}
#[cfg(unix)]
use std::{
fs,
os::unix::fs::{FileTypeExt, PermissionsExt},
path::Path,
process::{Child, Command},
time::Duration,
};
use std::path::PathBuf;
#[cfg(unix)]
const CRASH_BARRIER_TIMEOUT: Duration = Duration::from_secs(30);
pub fn temp_dir(prefix: &str) -> PathBuf {
let parent = std::env::var_os("TMPDIR").map_or_else(
|| {
let parent = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.ancestors()
.nth(2)
.unwrap()
.join("target/tmp");
std::fs::create_dir_all(&parent).expect("create workspace fixture parent");
parent
},
PathBuf::from,
);
let selected_temp = parent
.canonicalize()
.expect("resolve selected fixture parent");
ic_host_fs::testing::create_fixture_directory(&selected_temp, prefix)
.expect("allocate fixture directory")
}
#[cfg(unix)]
pub fn create_private_fifo(path: &Path) {
assert!(
Command::new("mkfifo")
.args(["-m", "600"])
.arg(path)
.status()
.expect("host mkfifo utility")
.success(),
"create private fixture FIFO"
);
let metadata = fs::symlink_metadata(path).expect("fixture FIFO metadata");
assert!(metadata.file_type().is_fifo());
assert_eq!(metadata.permissions().mode() & 0o777, 0o600);
}
#[cfg(unix)]
pub fn kill_child_at_acknowledged_barrier(child: &mut Child, root: &Path) {
ic_host_process::testing::crash_barrier::kill_child_at_acknowledged_barrier(
child,
root,
CRASH_BARRIER_TIMEOUT,
)
.expect("kill and reap child at acknowledged barrier");
}
#[cfg(unix)]
pub fn hold_at_acknowledged_barrier(root: &Path) -> ! {
ic_host_process::testing::crash_barrier::hold_at_acknowledged_barrier(
root,
CRASH_BARRIER_TIMEOUT,
)
}
#[cfg(unix)]
pub fn wait_for_child_path(child: &mut Child, path: &Path, description: &str) {
ic_host_process::testing::crash_barrier::wait_for_child_path(
child,
path,
description,
CRASH_BARRIER_TIMEOUT,
)
.expect("wait for direct child marker");
}
pub(crate) fn create_json_durable(
path: &std::path::Path,
value: &impl serde::Serialize,
) -> Result<(), crate::ops::persistence::PersistenceError> {
let bytes = crate::ops::persistence::json::encode_json(value, 16 * 1024 * 1024)?;
crate::ops::persistence::json::create_encoded(path, &bytes)
}
pub(crate) fn write_json_durable(
path: &std::path::Path,
value: &impl serde::Serialize,
) -> Result<(), crate::ops::persistence::PersistenceError> {
let bytes = crate::ops::persistence::json::encode_json(value, 16 * 1024 * 1024)?;
crate::ops::persistence::json::write_encoded(path, &bytes)
}
pub(crate) const WIRE_ORACLE_LIMITS: ic_platform::candid_codec::decoder::Limits =
ic_platform::candid_codec::decoder::Limits {
bytes: 64 * 1024 * 1024,
work: 512 * 1024 * 1024,
allocation: 512 * 1024 * 1024,
types: 4096,
header: 64 * 1024,
};
pub(crate) fn encode_fixture(
value: impl ic_platform::candid_codec::Encode,
) -> Result<Vec<u8>, ic_platform::candid_codec::Error> {
ic_platform::candid_codec::encode_one(&value, WIRE_ORACLE_LIMITS.bytes)
}
pub(crate) fn encode_fixture_args(
value: &impl ic_platform::candid_codec::arguments::EncodeArgs,
) -> Result<Vec<u8>, ic_platform::candid_codec::Error> {
ic_platform::candid_codec::arguments::encode_args(value, WIRE_ORACLE_LIMITS.bytes)
}