ic_testkit/pic/baseline.rs
1use super::{
2 CanisterSnapshotTarget, ControllerSnapshotError, ControllerSnapshots, PocketIcInstance,
3 PocketIcSnapshotExt, SnapshotRestoreFunding,
4};
5use ic_platform::pocket_ic::PocketIc;
6use ic_platform::principal::ExternalPrincipal as Principal;
7
8/// One owned `PocketIC` instance/server record with snapshots and caller metadata.
9///
10/// The value contains no synchronization. A [`super::PocketIcBaselineRecipe`]
11/// can own it as its fixture in a [`super::CachedPocketIcBaselinePool`].
12pub struct CachedPocketIcBaseline<T> {
13 instance: PocketIcInstance<PocketIc>,
14 snapshots: ControllerSnapshots,
15 metadata: T,
16}
17
18impl<T> CachedPocketIcBaseline<T> {
19 /// Capture a cached baseline with an explicit sender for every canister.
20 ///
21 /// Empty inputs are rejected before capture. Capture is ordered and transactional as documented by
22 /// [`PocketIcSnapshotExt::capture_snapshots`]. No sender fallback is performed.
23 /// The caller stops/drains every target before capture and restarts only
24 /// after the entire capture succeeds. Automatic progress must be disabled.
25 ///
26 /// # Errors
27 /// Returns a controller snapshot error if target admission or snapshot capture fails.
28 pub fn capture<I>(
29 instance: PocketIcInstance<PocketIc>,
30 targets: I,
31 metadata: T,
32 ) -> Result<Self, ControllerSnapshotError>
33 where
34 I: IntoIterator<Item = CanisterSnapshotTarget>,
35 {
36 let mut targets = targets.into_iter().peekable();
37 if targets.peek().is_none() {
38 return Err(ControllerSnapshotError::EmptyCanisterSet);
39 }
40 let snapshots = instance.instance().capture_snapshots(targets)?;
41 Ok(Self {
42 instance,
43 snapshots,
44 metadata,
45 })
46 }
47
48 /// Restore with exactly the captured senders and selected cycle funding.
49 /// Success means the complete captured set was restored.
50 /// Stop/drain the entire set first; restart after complete restore/reset.
51 /// Absolute captured timers and hook state are restored; current time is not.
52 ///
53 /// # Errors
54 /// Returns a controller snapshot error if funding or snapshot restoration fails.
55 pub fn restore(&self, funding: SnapshotRestoreFunding) -> Result<(), ControllerSnapshotError> {
56 self.instance
57 .instance()
58 .restore_snapshots(&self.snapshots, funding)
59 }
60
61 /// Borrow the owned `PocketIC` instance behind this cached baseline.
62 #[must_use]
63 pub const fn pocket_ic(&self) -> &PocketIc {
64 self.instance.instance()
65 }
66
67 /// Return the number of canisters captured by this baseline.
68 #[must_use]
69 pub fn snapshot_count(&self) -> usize {
70 self.snapshots.len()
71 }
72
73 /// Iterate over captured canister ids in deterministic principal order.
74 pub fn snapshot_canister_ids(&self) -> impl Iterator<Item = Principal> + '_ {
75 self.snapshots.canister_ids()
76 }
77
78 /// Borrow the captured metadata associated with this cached baseline.
79 #[must_use]
80 pub const fn metadata(&self) -> &T {
81 &self.metadata
82 }
83
84 /// Mutably borrow the captured metadata associated with this cached baseline.
85 #[must_use]
86 pub const fn metadata_mut(&mut self) -> &mut T {
87 &mut self.metadata
88 }
89}