ic-testkit 0.85.0

PocketIC-oriented test utilities for IC canister tests
Documentation
use super::{ExitCode, command_exit_code, failure_exit_code};
use ic_testkit::pic::PocketIcStartupFailure;
use std::os::unix::process::ExitStatusExt as _;

#[test]
fn command_arguments_preserve_native_paths_empty_values_and_limits() {
    use std::{ffi::OsString, os::unix::ffi::OsStringExt as _, time::Duration};
    let executable = OsString::from_vec(vec![b'p', 255]);
    let child_argument = OsString::from_vec(vec![b'a', 254]);
    let mut arguments = [
        "run",
        "--ttl",
        "90",
        "--idle-ttl",
        "10",
        "--startup-timeout",
        "7",
        "--server-stdout",
        "stdout path",
        "--server-stderr",
        "stderr path",
        "--",
    ]
    .map(OsString::from)
    .to_vec();
    arguments.extend([
        executable.clone(),
        "--help".into(),
        "".into(),
        child_argument.clone(),
    ]);
    let super::Arguments::Run(arguments) = super::parse(arguments.into_iter()).unwrap() else {
        panic!("run arguments required");
    };
    assert_eq!(arguments.command[0].as_os_str(), &executable);
    assert_eq!(
        arguments.command[1..]
            .iter()
            .map(OsString::as_os_str)
            .collect::<Vec<_>>(),
        [
            std::ffi::OsStr::new("--help"),
            std::ffi::OsStr::new(""),
            child_argument.as_os_str()
        ]
    );
    assert_eq!(arguments.timeout, Duration::from_secs(7));
    assert_eq!(arguments.ttl, Some(Duration::from_secs(90)));
    assert_eq!(arguments.idle_ttl, Some(Duration::from_secs(10)));
    assert_eq!(
        arguments.server_stdout.zip(arguments.server_stderr),
        Some(("stdout path".into(), "stderr path".into()))
    );
}

#[test]
fn malformed_server_arguments_refuse_before_server_admission() {
    for arguments in [
        vec!["run", "--", ""],
        vec!["run", "command"],
        vec!["run", "--ttl", "0", "--", "command"],
        vec!["run", "--ttl", "1", "--ttl", "2", "--", "command"],
        vec!["run", "--server-stdout", "stdout", "--", "command"],
        vec!["run", "--server-stderr", "stderr", "--", "command"],
        vec!["check", "--directory", ""],
    ] {
        let error = super::parse(arguments.into_iter().map(Into::into))
            .err()
            .expect("invalid arguments");
        assert_eq!(error.exit_code(), 2);
    }
}

#[test]
fn server_help_and_defaults_are_admitted_without_provisioning() {
    for arguments in [vec!["--help"], vec!["--version"], vec!["run", "--help"]] {
        let error = super::parse(arguments.into_iter().map(Into::into))
            .err()
            .expect("display request");
        assert_eq!(error.exit_code(), 0);
    }
    let super::Arguments::Check { directory } = super::parse(
        ["check", "--directory", "-store"]
            .map(Into::into)
            .into_iter(),
    )
    .unwrap() else {
        panic!("check arguments required");
    };
    assert_eq!(directory, std::path::Path::new("-store"));
    let super::Arguments::Check { directory } =
        super::parse(["check"].map(Into::into).into_iter()).unwrap()
    else {
        panic!("check arguments required");
    };
    assert_eq!(
        directory,
        std::path::Path::new(super::server_assets::DEFAULT_DIRECTORY)
    );
    let super::Arguments::Run(arguments) =
        super::parse(["run", "--", "command"].map(Into::into).into_iter()).unwrap()
    else {
        panic!("run arguments required");
    };
    assert_eq!(arguments.timeout, std::time::Duration::from_secs(30));
    assert!(
        arguments.directory.is_none()
            && arguments.ttl.is_none()
            && arguments.idle_ttl.is_none()
            && arguments.server_stdout.is_none()
            && arguments.server_stderr.is_none()
    );
}

#[test]
fn secondary_server_cleanup_preserves_failed_command_status() {
    for (raw_status, expected) in [
        (0, 1),
        (23 << 8, 23),
        (255 << 8, 255),
        (15, 143),
        ((19 << 8) | 0x7f, 129),
    ] {
        assert_eq!(
            command_exit_code(std::process::ExitStatus::from_raw(raw_status)),
            ExitCode::from(if raw_status == 0 { 0 } else { expected })
        );
        let failure = PocketIcStartupFailure::ServerCleanup {
            command_status: std::process::ExitStatus::from_raw(raw_status),
        };
        assert_eq!(failure_exit_code(&failure), ExitCode::from(expected));
    }
    assert_eq!(
        failure_exit_code(&PocketIcStartupFailure::BuilderDisconnected),
        ExitCode::FAILURE
    );
}