1use candid::{encode_args, encode_one};
2use canic::{
3 Error,
4 cdk::types::TC,
5 dto::{
6 abi::v1::CanisterInitPayload,
7 env::EnvBootstrapArgs,
8 subnet::SubnetIdentity,
9 topology::{AppDirectoryArgs, SubnetDirectoryArgs},
10 },
11 ids::CanisterRole,
12};
13use pocket_ic::{PocketIc, PocketIcBuilder};
14use std::ops::{Deref, DerefMut};
15
16mod baseline;
17mod calls;
18mod diagnostics;
19mod errors;
20mod lifecycle;
21mod process_lock;
22mod readiness;
23mod snapshot;
24mod standalone;
25mod startup;
26
27pub use baseline::{
28 CachedPicBaseline, CachedPicBaselineGuard, ControllerSnapshots,
29 restore_or_rebuild_cached_pic_baseline,
30};
31pub use errors::{PicInstallError, StandaloneCanisterFixtureError};
32pub use process_lock::{
33 PicSerialGuard, PicSerialGuardError, acquire_pic_serial_guard, try_acquire_pic_serial_guard,
34};
35pub use readiness::{role_pid, wait_until_ready};
36pub use startup::PicStartError;
37const INSTALL_CYCLES: u128 = 500 * TC;
38
39pub use standalone::{
40 StandaloneCanisterFixture, install_prebuilt_canister, install_prebuilt_canister_with_cycles,
41 install_standalone_canister, try_install_prebuilt_canister,
42 try_install_prebuilt_canister_with_cycles,
43};
44
45#[must_use]
54pub fn pic() -> Pic {
55 try_pic().unwrap_or_else(|err| panic!("failed to start PocketIC: {err}"))
56}
57
58pub fn try_pic() -> Result<Pic, PicStartError> {
60 PicBuilder::new().with_application_subnet().try_build()
61}
62
63pub struct PicBuilder(PocketIcBuilder);
74
75#[expect(clippy::new_without_default)]
76impl PicBuilder {
77 #[must_use]
79 pub fn new() -> Self {
80 Self(PocketIcBuilder::new())
81 }
82
83 #[must_use]
85 pub fn with_application_subnet(mut self) -> Self {
86 self.0 = self.0.with_application_subnet();
87 self
88 }
89
90 #[must_use]
92 pub fn with_ii_subnet(mut self) -> Self {
93 self.0 = self.0.with_ii_subnet();
94 self
95 }
96
97 #[must_use]
99 pub fn with_nns_subnet(mut self) -> Self {
100 self.0 = self.0.with_nns_subnet();
101 self
102 }
103
104 #[must_use]
106 pub fn build(self) -> Pic {
107 self.try_build()
108 .unwrap_or_else(|err| panic!("failed to start PocketIC: {err}"))
109 }
110
111 pub fn try_build(self) -> Result<Pic, PicStartError> {
113 startup::try_build_pic(self.0)
114 }
115}
116pub struct Pic {
125 inner: PocketIc,
126}
127
128impl Pic {
129 #[must_use]
131 pub fn current_time_nanos(&self) -> u64 {
132 self.inner.get_time().as_nanos_since_unix_epoch()
133 }
134
135 pub fn restore_time_nanos(&self, nanos_since_epoch: u64) {
137 let restored = pocket_ic::Time::from_nanos_since_unix_epoch(nanos_since_epoch);
138 self.inner.set_time(restored);
139 self.inner.set_certified_time(restored);
140 }
141}
142
143impl Deref for Pic {
144 type Target = PocketIc;
145
146 fn deref(&self) -> &Self::Target {
147 &self.inner
148 }
149}
150
151impl DerefMut for Pic {
152 fn deref_mut(&mut self) -> &mut Self::Target {
153 &mut self.inner
154 }
155}
156
157fn install_args(role: CanisterRole) -> Result<Vec<u8>, Error> {
172 if role.is_root() {
173 install_root_args()
174 } else {
175 let env = EnvBootstrapArgs {
178 prime_root_pid: None,
179 subnet_role: None,
180 subnet_pid: None,
181 root_pid: None,
182 canister_role: Some(role),
183 parent_pid: None,
184 };
185
186 let payload = CanisterInitPayload {
189 env,
190 app_directory: AppDirectoryArgs(Vec::new()),
191 subnet_directory: SubnetDirectoryArgs(Vec::new()),
192 };
193
194 encode_args::<(CanisterInitPayload, Option<Vec<u8>>)>((payload, None))
195 .map_err(|err| Error::internal(format!("encode_args failed: {err}")))
196 }
197}
198
199fn install_root_args() -> Result<Vec<u8>, Error> {
200 encode_one(SubnetIdentity::Manual)
201 .map_err(|err| Error::internal(format!("encode_one failed: {err}")))
202}
203
204