Skip to main content

ic_testkit/pic/
diagnostics.rs

1use std::panic::{AssertUnwindSafe, catch_unwind};
2
3use candid::Principal;
4use pocket_ic::PocketIc;
5
6use super::startup;
7
8/// Reusable PocketIC failure diagnostics.
9pub trait PocketIcDiagnosticsExt {
10    /// Print status and canister-log context for a failed test operation.
11    fn dump_canister_debug(&self, canister_id: Principal, context: &str);
12}
13
14impl PocketIcDiagnosticsExt for PocketIc {
15    /// Dump basic PocketIC status and log context for one canister.
16    fn dump_canister_debug(&self, canister_id: Principal, context: &str) {
17        eprintln!("{context}: debug for canister {canister_id}");
18
19        match catch_unwind(AssertUnwindSafe(|| self.canister_status(canister_id, None))) {
20            Ok(Ok(status)) => eprintln!("canister_status: {status:?}"),
21            Ok(Err(err)) => {
22                let message = err.to_string();
23                if startup::is_dead_instance_transport_error(&message) {
24                    eprintln!("canister_status unavailable: PocketIC instance no longer reachable");
25                    return;
26                }
27                eprintln!("canister_status failed: {err:?}");
28            }
29            Err(payload) => {
30                let message = startup::panic_payload_to_string(payload.as_ref());
31                if startup::is_dead_instance_transport_error(&message) {
32                    eprintln!("canister_status unavailable: PocketIC instance no longer reachable");
33                    return;
34                }
35                eprintln!("canister_status panicked: {message}");
36            }
37        }
38
39        match catch_unwind(AssertUnwindSafe(|| {
40            self.fetch_canister_logs(canister_id, Principal::anonymous())
41        })) {
42            Ok(Ok(records)) => {
43                if records.is_empty() {
44                    eprintln!("canister logs: <empty>");
45                } else {
46                    for record in records {
47                        eprintln!("canister log: {record:?}");
48                    }
49                }
50            }
51            Ok(Err(err)) => {
52                let message = err.to_string();
53                if startup::is_dead_instance_transport_error(&message) {
54                    eprintln!(
55                        "fetch_canister_logs unavailable: PocketIC instance no longer reachable"
56                    );
57                    return;
58                }
59                eprintln!("fetch_canister_logs failed: {err:?}");
60            }
61            Err(payload) => {
62                let message = startup::panic_payload_to_string(payload.as_ref());
63                if startup::is_dead_instance_transport_error(&message) {
64                    eprintln!(
65                        "fetch_canister_logs unavailable: PocketIC instance no longer reachable"
66                    );
67                    return;
68                }
69                eprintln!("fetch_canister_logs panicked: {message}");
70            }
71        }
72    }
73}