Skip to main content

ic_testkit/pic/
standalone.rs

1use candid::{CandidType, Principal, utils::ArgumentEncoder};
2use serde::de::DeserializeOwned;
3
4use super::{
5    Pic, PicCallError, PicSerialGuard, StandaloneCanisterFixtureError,
6    try_acquire_pic_serial_guard, try_pic,
7};
8
9const DEFAULT_EXTRA_INSTALL_CYCLES: u128 = 0;
10
11///
12/// StandaloneCanisterFixture
13///
14
15pub struct StandaloneCanisterFixture {
16    pic: Pic,
17    canister_id: Principal,
18    _serial_guard: PicSerialGuard,
19}
20
21impl StandaloneCanisterFixture {
22    /// Borrow the PocketIC instance that owns this standalone fixture.
23    #[must_use]
24    pub const fn pic(&self) -> &Pic {
25        &self.pic
26    }
27
28    /// Mutably borrow the PocketIC instance that owns this standalone fixture.
29    #[must_use]
30    pub const fn pic_mut(&mut self) -> &mut Pic {
31        &mut self.pic
32    }
33
34    /// Read the installed canister id for this standalone fixture.
35    #[must_use]
36    pub const fn canister_id(&self) -> Principal {
37        self.canister_id
38    }
39
40    /// Consume the fixture and return the owned PocketIC instance and canister id.
41    #[must_use]
42    pub fn into_parts(self) -> (Pic, Principal) {
43        (self.pic, self.canister_id)
44    }
45
46    /// Forward one typed update call to this fixture's canister id.
47    pub fn update_call<T, A>(&self, method: &str, args: A) -> Result<T, PicCallError>
48    where
49        T: CandidType + DeserializeOwned,
50        A: ArgumentEncoder,
51    {
52        self.pic.update_call(self.canister_id, method, args)
53    }
54
55    /// Forward one typed update call with an explicit caller to this fixture's canister id.
56    pub fn update_call_as<T, A>(
57        &self,
58        caller: Principal,
59        method: &str,
60        args: A,
61    ) -> Result<T, PicCallError>
62    where
63        T: CandidType + DeserializeOwned,
64        A: ArgumentEncoder,
65    {
66        self.pic
67            .update_call_as(self.canister_id, caller, method, args)
68    }
69
70    /// Forward one typed query call to this fixture's canister id.
71    pub fn query_call<T, A>(&self, method: &str, args: A) -> Result<T, PicCallError>
72    where
73        T: CandidType + DeserializeOwned,
74        A: ArgumentEncoder,
75    {
76        self.pic.query_call(self.canister_id, method, args)
77    }
78
79    /// Forward one typed query call with an explicit caller to this fixture's canister id.
80    pub fn query_call_as<T, A>(
81        &self,
82        caller: Principal,
83        method: &str,
84        args: A,
85    ) -> Result<T, PicCallError>
86    where
87        T: CandidType + DeserializeOwned,
88        A: ArgumentEncoder,
89    {
90        self.pic
91            .query_call_as(self.canister_id, caller, method, args)
92    }
93}
94
95// Install one already-built wasm module into a fresh PocketIC instance with
96// caller-provided init args and no application-specific bootstrap assumptions.
97#[must_use]
98pub fn install_prebuilt_canister(wasm: Vec<u8>, init_bytes: Vec<u8>) -> StandaloneCanisterFixture {
99    try_install_prebuilt_canister(wasm, init_bytes)
100        .unwrap_or_else(|err| panic!("failed to install prebuilt canister fixture: {err}"))
101}
102
103// Install one already-built wasm module into a fresh PocketIC instance with
104// caller-provided init args and no application-specific bootstrap assumptions.
105pub fn try_install_prebuilt_canister(
106    wasm: Vec<u8>,
107    init_bytes: Vec<u8>,
108) -> Result<StandaloneCanisterFixture, StandaloneCanisterFixtureError> {
109    try_install_prebuilt_canister_with_cycles(wasm, init_bytes, DEFAULT_EXTRA_INSTALL_CYCLES)
110}
111
112// Install one already-built wasm module into a fresh PocketIC instance with
113// caller-provided init args and explicit install cycles.
114#[must_use]
115pub fn install_prebuilt_canister_with_cycles(
116    wasm: Vec<u8>,
117    init_bytes: Vec<u8>,
118    install_cycles: u128,
119) -> StandaloneCanisterFixture {
120    try_install_prebuilt_canister_with_cycles(wasm, init_bytes, install_cycles)
121        .unwrap_or_else(|err| panic!("failed to install prebuilt canister fixture: {err}"))
122}
123
124// Install one already-built wasm module into a fresh PocketIC instance with
125// caller-provided init args and explicit install cycles.
126pub fn try_install_prebuilt_canister_with_cycles(
127    wasm: Vec<u8>,
128    init_bytes: Vec<u8>,
129    install_cycles: u128,
130) -> Result<StandaloneCanisterFixture, StandaloneCanisterFixtureError> {
131    let serial_guard =
132        try_acquire_pic_serial_guard().map_err(StandaloneCanisterFixtureError::SerialGuard)?;
133    let pic = try_pic().map_err(StandaloneCanisterFixtureError::Start)?;
134    let canister_id = pic
135        .try_create_and_install_with_args(wasm, init_bytes, install_cycles)
136        .map_err(StandaloneCanisterFixtureError::Install)?;
137
138    Ok(StandaloneCanisterFixture {
139        pic,
140        canister_id,
141        _serial_guard: serial_guard,
142    })
143}