Skip to main content

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}