Skip to main content

canic_core/dto/
runtime.rs

1use crate::dto::prelude::*;
2use crate::ids::BuildNetwork;
3
4pub use crate::domain::runtime::{
5    FailureSeverity, HealthStatus, ReadinessStatus, RuntimeCheckStatus, RuntimeDiagnosticSeverity,
6    RuntimeFieldVisibility, RuntimeStateDomainStatus, RuntimeStatus, TimerExecutionOutcome,
7    TimerProcessCondition, TimerRegistrationStatus, TimerSchedulingMode,
8};
9
10pub const RUNTIME_INTROSPECTION_SCHEMA_VERSION: u32 = 1;
11
12//
13// CanicHealthStatus
14//
15
16#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
17pub struct CanicHealthStatus {
18    pub schema_version: u32,
19    pub status: HealthStatus,
20    pub observed_at_ns: Option<u64>,
21    pub checks: Vec<RuntimeCheck>,
22}
23
24//
25// CanicReadinessStatus
26//
27
28#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
29pub struct CanicReadinessStatus {
30    pub schema_version: u32,
31    pub role: Option<String>,
32    pub status: ReadinessStatus,
33    pub observed_at_ns: u64,
34    pub checks: Vec<RuntimeCheck>,
35    pub blockers: Vec<RuntimeDiagnostic>,
36    pub warnings: Vec<RuntimeDiagnostic>,
37}
38
39//
40// CanicRuntimeStatus
41//
42
43#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
44pub struct CanicRuntimeStatus {
45    pub schema_version: u32,
46    pub observed_at_ns: u64,
47    pub canister_id: Principal,
48    pub role: Option<String>,
49    pub root: Option<Principal>,
50    pub build_network: Option<BuildNetwork>,
51    pub build: RuntimeBuildInfo,
52    pub features: Vec<RuntimeFeatureStatus>,
53    pub topology: Option<RuntimeTopologyStatus>,
54    pub timers: Vec<CanicTimerStatus>,
55    pub state: Option<RuntimeStateSummary>,
56    pub auth: Option<RuntimeAuthStatusSummary>,
57    pub blob_storage: Option<RuntimeBlobStorageStatusSummary>,
58    pub recent_failures: Vec<RecentFailure>,
59    pub visibility: Vec<RuntimeVisibilityEntry>,
60    pub readiness: CanicReadinessStatus,
61    pub status: RuntimeStatus,
62}
63
64//
65// RuntimeBuildInfo
66//
67
68#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
69pub struct RuntimeBuildInfo {
70    pub package_name: String,
71    pub package_version: String,
72    pub canic_version: String,
73    pub canister_version: u64,
74}
75
76//
77// RuntimeCheck
78//
79
80#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
81pub struct RuntimeCheck {
82    pub category: String,
83    pub code: String,
84    pub status: RuntimeCheckStatus,
85    pub subject: String,
86    pub detail: String,
87    pub next: Option<String>,
88    pub source: String,
89}
90
91//
92// RuntimeDiagnostic
93//
94
95#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
96pub struct RuntimeDiagnostic {
97    pub category: String,
98    pub code: String,
99    pub severity: RuntimeDiagnosticSeverity,
100    pub subject: String,
101    pub detail: String,
102    pub next: Option<String>,
103    pub source: String,
104}
105
106//
107// RuntimeFeatureStatus
108//
109
110#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
111pub struct RuntimeFeatureStatus {
112    pub name: String,
113    pub enabled: bool,
114    pub visibility: RuntimeFieldVisibility,
115    pub source: String,
116}
117
118//
119// RuntimeTopologyStatus
120//
121
122#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
123pub struct RuntimeTopologyStatus {
124    pub root: Option<Principal>,
125    pub parent: Option<Principal>,
126    pub subnet: Option<Principal>,
127    pub source: String,
128}
129
130//
131// CanicTimerStatus
132//
133
134#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
135pub struct CanicTimerStatus {
136    pub name: String,
137    pub subsystem: String,
138    pub scheduling_mode: TimerSchedulingMode,
139    pub registration: TimerRegistrationStatus,
140    pub condition: TimerProcessCondition,
141    pub enabled: bool,
142    pub generation: u64,
143    pub next_due_at_ns: Option<u64>,
144    pub last_outcome: Option<TimerExecutionOutcome>,
145    pub last_work_count: u64,
146    pub last_success_at_ns: Option<u64>,
147    pub last_failure_at_ns: Option<u64>,
148    pub consecutive_expected_failures: u64,
149    pub schedules_since_runtime_start: u64,
150    pub executions_since_runtime_start: u64,
151    pub successes_since_runtime_start: u64,
152    pub expected_failures_since_runtime_start: u64,
153    pub invariant_failures_since_runtime_start: u64,
154    pub stale_callbacks_since_runtime_start: u64,
155}
156
157//
158// RuntimeStateSummary
159//
160
161#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
162pub struct RuntimeStateSummary {
163    pub manifest_schema_version: u32,
164    pub domains: Vec<RuntimeStateDomainSummary>,
165    pub total_stable_memory_pages: Option<u64>,
166}
167
168//
169// RuntimeStateDomainSummary
170//
171
172#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
173pub struct RuntimeStateDomainSummary {
174    pub domain: String,
175    pub version: u32,
176    pub storage: String,
177    pub memory_id: Option<u8>,
178    pub status: RuntimeStateDomainStatus,
179}
180
181//
182// RuntimeAuthStatusSummary
183//
184
185#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
186pub struct RuntimeAuthStatusSummary {
187    pub auth_features: Vec<RuntimeFeatureStatus>,
188}
189
190//
191// RuntimeBlobStorageStatusSummary
192//
193
194#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
195pub struct RuntimeBlobStorageStatusSummary {
196    pub blob_storage_features: Vec<RuntimeFeatureStatus>,
197}
198
199//
200// RecentFailure
201//
202
203#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
204pub struct RecentFailure {
205    pub occurred_at_ns: u64,
206    pub subsystem: String,
207    pub code: String,
208    pub severity: FailureSeverity,
209    pub summary: String,
210    pub correlation_id: Option<String>,
211    pub redacted: bool,
212}
213
214//
215// RuntimeVisibilityEntry
216//
217
218#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
219pub struct RuntimeVisibilityEntry {
220    pub field: String,
221    pub visibility: RuntimeFieldVisibility,
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227    use candid::{Decode, Encode};
228    use serde::Serialize;
229    use serde::de::DeserializeOwned;
230    use std::fmt::Debug;
231
232    #[test]
233    fn runtime_enums_roundtrip_candid_with_canonical_variant_labels() {
234        assert_enum_candid_contract(HealthStatus::Unknown);
235        assert_enum_candid_contract(ReadinessStatus::NotEvaluated);
236        assert_enum_candid_contract(RuntimeStatus::Failing);
237        assert_enum_candid_contract(TimerRegistrationStatus::Unregistered);
238        assert_enum_candid_contract(TimerProcessCondition::MissingRegistration);
239        assert_enum_candid_contract(TimerSchedulingMode::AfterCompletion);
240        assert_enum_candid_contract(TimerExecutionOutcome::InvariantFailure);
241        assert_enum_candid_contract(FailureSeverity::Critical);
242        assert_enum_candid_contract(RuntimeCheckStatus::NotEvaluated);
243        assert_enum_candid_contract(RuntimeDiagnosticSeverity::Unsupported);
244        assert_enum_candid_contract(RuntimeFieldVisibility::OperatorOnly);
245        assert_enum_candid_contract(RuntimeStateDomainStatus::NotEvaluated);
246    }
247
248    #[test]
249    fn runtime_enums_serialize_canonical_snake_case_labels() {
250        assert_enum_serde_contract(HealthStatus::Healthy, HealthStatus::Healthy.label());
251        assert_enum_serde_contract(HealthStatus::Degraded, HealthStatus::Degraded.label());
252        assert_enum_serde_contract(HealthStatus::Unhealthy, HealthStatus::Unhealthy.label());
253        assert_enum_serde_contract(HealthStatus::Unknown, HealthStatus::Unknown.label());
254
255        assert_enum_serde_contract(ReadinessStatus::Ready, ReadinessStatus::Ready.label());
256        assert_enum_serde_contract(ReadinessStatus::Degraded, ReadinessStatus::Degraded.label());
257        assert_enum_serde_contract(ReadinessStatus::NotReady, ReadinessStatus::NotReady.label());
258        assert_enum_serde_contract(
259            ReadinessStatus::NotEvaluated,
260            ReadinessStatus::NotEvaluated.label(),
261        );
262
263        assert_enum_serde_contract(RuntimeStatus::Ok, RuntimeStatus::Ok.label());
264        assert_enum_serde_contract(RuntimeStatus::Degraded, RuntimeStatus::Degraded.label());
265        assert_enum_serde_contract(RuntimeStatus::Failing, RuntimeStatus::Failing.label());
266        assert_enum_serde_contract(RuntimeStatus::Unknown, RuntimeStatus::Unknown.label());
267
268        assert_enum_serde_contract(
269            TimerRegistrationStatus::Unregistered,
270            TimerRegistrationStatus::Unregistered.label(),
271        );
272        assert_enum_serde_contract(
273            TimerProcessCondition::MissingRegistration,
274            TimerProcessCondition::MissingRegistration.label(),
275        );
276        assert_enum_serde_contract(
277            TimerSchedulingMode::AfterCompletion,
278            TimerSchedulingMode::AfterCompletion.label(),
279        );
280        assert_enum_serde_contract(
281            TimerExecutionOutcome::InvariantFailure,
282            TimerExecutionOutcome::InvariantFailure.label(),
283        );
284
285        assert_enum_serde_contract(FailureSeverity::Info, FailureSeverity::Info.label());
286        assert_enum_serde_contract(FailureSeverity::Warning, FailureSeverity::Warning.label());
287        assert_enum_serde_contract(FailureSeverity::Error, FailureSeverity::Error.label());
288        assert_enum_serde_contract(FailureSeverity::Critical, FailureSeverity::Critical.label());
289
290        assert_enum_serde_contract(RuntimeCheckStatus::Pass, RuntimeCheckStatus::Pass.label());
291        assert_enum_serde_contract(RuntimeCheckStatus::Warn, RuntimeCheckStatus::Warn.label());
292        assert_enum_serde_contract(RuntimeCheckStatus::Fail, RuntimeCheckStatus::Fail.label());
293        assert_enum_serde_contract(
294            RuntimeCheckStatus::NotEvaluated,
295            RuntimeCheckStatus::NotEvaluated.label(),
296        );
297
298        assert_enum_serde_contract(
299            RuntimeDiagnosticSeverity::Info,
300            RuntimeDiagnosticSeverity::Info.label(),
301        );
302        assert_enum_serde_contract(
303            RuntimeDiagnosticSeverity::Warning,
304            RuntimeDiagnosticSeverity::Warning.label(),
305        );
306        assert_enum_serde_contract(
307            RuntimeDiagnosticSeverity::Blocked,
308            RuntimeDiagnosticSeverity::Blocked.label(),
309        );
310        assert_enum_serde_contract(
311            RuntimeDiagnosticSeverity::Unsupported,
312            RuntimeDiagnosticSeverity::Unsupported.label(),
313        );
314
315        assert_enum_serde_contract(
316            RuntimeFieldVisibility::PublicSafe,
317            RuntimeFieldVisibility::PublicSafe.label(),
318        );
319        assert_enum_serde_contract(
320            RuntimeFieldVisibility::OperatorOnly,
321            RuntimeFieldVisibility::OperatorOnly.label(),
322        );
323        assert_enum_serde_contract(
324            RuntimeFieldVisibility::ControllerOnly,
325            RuntimeFieldVisibility::ControllerOnly.label(),
326        );
327        assert_enum_serde_contract(
328            RuntimeFieldVisibility::FeatureGated,
329            RuntimeFieldVisibility::FeatureGated.label(),
330        );
331        assert_enum_serde_contract(
332            RuntimeFieldVisibility::Disabled,
333            RuntimeFieldVisibility::Disabled.label(),
334        );
335
336        assert_enum_serde_contract(
337            RuntimeStateDomainStatus::Ok,
338            RuntimeStateDomainStatus::Ok.label(),
339        );
340        assert_enum_serde_contract(
341            RuntimeStateDomainStatus::Warning,
342            RuntimeStateDomainStatus::Warning.label(),
343        );
344        assert_enum_serde_contract(
345            RuntimeStateDomainStatus::Failing,
346            RuntimeStateDomainStatus::Failing.label(),
347        );
348        assert_enum_serde_contract(
349            RuntimeStateDomainStatus::NotEvaluated,
350            RuntimeStateDomainStatus::NotEvaluated.label(),
351        );
352    }
353
354    fn assert_enum_candid_contract<T>(value: T)
355    where
356        T: CandidType + Clone + Debug + DeserializeOwned + Eq,
357    {
358        let bytes = Encode!(&value).expect("encode runtime enum");
359        let decoded = Decode!(&bytes, T).expect("decode runtime enum");
360
361        assert_eq!(decoded, value);
362    }
363
364    fn assert_enum_serde_contract<T>(value: T, label: &str)
365    where
366        T: Clone + Debug + DeserializeOwned + Eq + Serialize,
367    {
368        let encoded = crate::cdk::serialize::serialize(&value).expect("encode runtime enum label");
369        let serialized_label: String =
370            crate::cdk::serialize::deserialize(&encoded).expect("decode runtime enum label");
371        assert_eq!(serialized_label, label);
372
373        let label_bytes =
374            crate::cdk::serialize::serialize(&label).expect("encode canonical runtime enum label");
375        let decoded: T = crate::cdk::serialize::deserialize(&label_bytes)
376            .expect("decode canonical runtime enum label");
377        assert_eq!(decoded, value);
378    }
379}