ic_testkit/pic/
standalone_recipe.rs1use std::io;
2
3use ic_platform_types::principal::ExternalPrincipal as Principal;
4
5use super::{
6 CachedPocketIcBaseline, CanisterSnapshotTarget, FailureDisposition, PocketIcBaselineRecipe,
7 PreparedBaseline, RebuildReason, ResetPolicies, ResetReceipt, ResetRequirements,
8 SnapshotRestoreFunding, StandaloneCanisterFixture, is_dead_pocket_ic_transport_error,
9};
10
11pub struct StandaloneCanisterRecipe<B> {
28 requirements: ResetRequirements,
29 build: B,
30}
31
32impl<B> StandaloneCanisterRecipe<B> {
33 #[must_use]
37 pub fn new(funding: SnapshotRestoreFunding, build: B) -> Self {
38 Self {
39 requirements: ResetRequirements {
40 funding,
41 policies: ResetPolicies::default(),
42 },
43 build,
44 }
45 }
46}
47
48impl<B> PocketIcBaselineRecipe for StandaloneCanisterRecipe<B>
49where
50 B: Fn() -> io::Result<StandaloneCanisterFixture> + Send + Sync + 'static,
51{
52 type Metadata = Principal;
53 type Error = io::Error;
55
56 fn reset_requirements(&self) -> &ResetRequirements {
57 &self.requirements
58 }
59
60 fn build(&self) -> Result<CachedPocketIcBaseline<Principal>, io::Error> {
61 let (pocket_ic, canister_id) = (self.build)()?.into_parts();
62 pocket_ic
63 .instance()
64 .stop_canister(canister_id, None)
65 .map_err(|source| {
66 io::Error::other(super::ControllerSnapshotError::CaptureFailed {
67 canister_id,
68 sender: None,
69 source: Box::new(source),
70 cleanup_failures: Vec::new(),
71 })
72 })?;
73 let baseline = CachedPocketIcBaseline::capture(
74 pocket_ic,
75 [CanisterSnapshotTarget {
76 canister_id,
77 sender: None,
78 }],
79 canister_id,
80 )
81 .map_err(io::Error::other)?;
82 self.drive_to_readiness(&baseline)?;
83 Ok(baseline)
84 }
85
86 fn reset_non_snapshot_state(
87 &self,
88 _baseline: &CachedPocketIcBaseline<Principal>,
89 ) -> Result<ResetReceipt, io::Error> {
90 Ok(ResetReceipt::default())
91 }
92
93 fn prepare_restore(
94 &self,
95 baseline: &CachedPocketIcBaseline<Principal>,
96 ) -> Result<(), io::Error> {
97 baseline
98 .pocket_ic()
99 .stop_canister(*baseline.metadata(), None)
100 .map_err(io::Error::other)
101 }
102
103 fn drive_to_readiness(
104 &self,
105 baseline: &CachedPocketIcBaseline<Principal>,
106 ) -> Result<(), io::Error> {
107 baseline
108 .pocket_ic()
109 .start_canister(*baseline.metadata(), None)
110 .map_err(io::Error::other)
111 }
112
113 fn validate(
114 &self,
115 _baseline: &CachedPocketIcBaseline<Principal>,
116 _preparation: &PreparedBaseline,
117 ) -> Result<(), io::Error> {
118 Ok(())
119 }
120
121 fn classify_failure(
122 &self,
123 _stage: super::BaselinePreparationStage,
124 error: &(dyn std::error::Error + 'static),
125 ) -> FailureDisposition {
126 if is_dead_pocket_ic_transport_error(error) {
127 FailureDisposition::Rebuild(RebuildReason::DeadPocketIcTransport)
128 } else {
129 FailureDisposition::Fatal
130 }
131 }
132}
133
134#[cfg(test)]
135mod tests;