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#[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#[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#[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 receipt_capacity: Option<RuntimeReceiptCapacityStatus>,
59 pub recent_failures: Vec<RecentFailure>,
60 pub visibility: Vec<RuntimeVisibilityEntry>,
61 pub readiness: CanicReadinessStatus,
62 pub status: RuntimeStatus,
63}
64
65#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
70pub struct RuntimeBuildInfo {
71 pub package_name: String,
72 pub package_version: String,
73 pub canic_version: String,
74 pub canister_version: u64,
75}
76
77#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
82pub struct RuntimeCheck {
83 pub category: String,
84 pub code: String,
85 pub status: RuntimeCheckStatus,
86 pub subject: String,
87 pub detail: String,
88 pub next: Option<String>,
89 pub source: String,
90}
91
92#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
97pub struct RuntimeDiagnostic {
98 pub category: String,
99 pub code: String,
100 pub severity: RuntimeDiagnosticSeverity,
101 pub subject: String,
102 pub detail: String,
103 pub next: Option<String>,
104 pub source: String,
105}
106
107#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
112pub struct RuntimeFeatureStatus {
113 pub name: String,
114 pub enabled: bool,
115 pub visibility: RuntimeFieldVisibility,
116 pub source: String,
117}
118
119#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
124pub struct RuntimeTopologyStatus {
125 pub root: Option<Principal>,
126 pub parent: Option<Principal>,
127 pub subnet: Option<Principal>,
128 pub source: String,
129}
130
131#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
136pub struct CanicTimerStatus {
137 pub name: String,
138 pub subsystem: String,
139 pub scheduling_mode: TimerSchedulingMode,
140 pub registration: TimerRegistrationStatus,
141 pub condition: TimerProcessCondition,
142 pub enabled: bool,
143 pub generation: u64,
144 pub next_due_at_ns: Option<u64>,
145 pub last_outcome: Option<TimerExecutionOutcome>,
146 pub last_work_count: u64,
147 pub last_success_at_ns: Option<u64>,
148 pub last_failure_at_ns: Option<u64>,
149 pub consecutive_expected_failures: u64,
150 pub schedules_since_runtime_start: u64,
151 pub executions_since_runtime_start: u64,
152 pub successes_since_runtime_start: u64,
153 pub expected_failures_since_runtime_start: u64,
154 pub invariant_failures_since_runtime_start: u64,
155 pub stale_callbacks_since_runtime_start: u64,
156}
157
158#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
163pub struct RuntimeStateSummary {
164 pub manifest_schema_version: u32,
165 pub domains: Vec<RuntimeStateDomainSummary>,
166 pub total_stable_memory_pages: Option<u64>,
167}
168
169#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
174pub struct RuntimeStateDomainSummary {
175 pub domain: String,
176 pub version: u32,
177 pub storage: String,
178 pub memory_id: Option<u8>,
179 pub status: RuntimeStateDomainStatus,
180}
181
182#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
187pub struct RuntimeAuthStatusSummary {
188 pub auth_features: Vec<RuntimeFeatureStatus>,
189}
190
191#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
196pub struct RuntimeBlobStorageStatusSummary {
197 pub blob_storage_features: Vec<RuntimeFeatureStatus>,
198}
199
200#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
205pub struct RuntimeReceiptCapacityStatus {
206 pub status: RuntimeCheckStatus,
207 pub receipt_records: u64,
208 pub application_receipt_records: u64,
209 pub canic_owned_receipt_records: u64,
210 pub pending_application_receipt_records: u64,
211 pub terminal_application_receipt_records: u64,
212 pub receipt_record_limit: u64,
213 pub remaining_receipt_record_headroom: u64,
214 pub resource_total_records: u64,
215 pub resource_total_record_limit: u64,
216 pub remaining_resource_total_headroom: u64,
217 pub warning_headroom_threshold: u64,
218 pub reserved_terminal_slots: u64,
219 pub reserved_terminal_pages: u64,
220 pub next_terminal_eligibility_at_ns: Option<u64>,
221 pub source: String,
222}
223
224#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
229pub struct RecentFailure {
230 pub occurred_at_ns: u64,
231 pub subsystem: String,
232 pub code: String,
233 pub severity: FailureSeverity,
234 pub summary: String,
235 pub correlation_id: Option<String>,
236 pub redacted: bool,
237}
238
239#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
244pub struct RuntimeVisibilityEntry {
245 pub field: String,
246 pub visibility: RuntimeFieldVisibility,
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252 use candid::{Decode, Encode};
253 use serde::Serialize;
254 use serde::de::DeserializeOwned;
255 use std::fmt::Debug;
256
257 #[test]
258 fn runtime_enums_roundtrip_candid_with_canonical_variant_labels() {
259 assert_enum_candid_contract(HealthStatus::Unknown);
260 assert_enum_candid_contract(ReadinessStatus::NotEvaluated);
261 assert_enum_candid_contract(RuntimeStatus::Failing);
262 assert_enum_candid_contract(TimerRegistrationStatus::Unregistered);
263 assert_enum_candid_contract(TimerProcessCondition::MissingRegistration);
264 assert_enum_candid_contract(TimerSchedulingMode::AfterCompletion);
265 assert_enum_candid_contract(TimerExecutionOutcome::InvariantFailure);
266 assert_enum_candid_contract(FailureSeverity::Critical);
267 assert_enum_candid_contract(RuntimeCheckStatus::NotEvaluated);
268 assert_enum_candid_contract(RuntimeDiagnosticSeverity::Unsupported);
269 assert_enum_candid_contract(RuntimeFieldVisibility::OperatorOnly);
270 assert_enum_candid_contract(RuntimeStateDomainStatus::NotEvaluated);
271 }
272
273 #[test]
274 fn runtime_enums_serialize_canonical_snake_case_labels() {
275 assert_enum_serde_contract(HealthStatus::Healthy, HealthStatus::Healthy.label());
276 assert_enum_serde_contract(HealthStatus::Degraded, HealthStatus::Degraded.label());
277 assert_enum_serde_contract(HealthStatus::Unhealthy, HealthStatus::Unhealthy.label());
278 assert_enum_serde_contract(HealthStatus::Unknown, HealthStatus::Unknown.label());
279
280 assert_enum_serde_contract(ReadinessStatus::Ready, ReadinessStatus::Ready.label());
281 assert_enum_serde_contract(ReadinessStatus::Degraded, ReadinessStatus::Degraded.label());
282 assert_enum_serde_contract(ReadinessStatus::NotReady, ReadinessStatus::NotReady.label());
283 assert_enum_serde_contract(
284 ReadinessStatus::NotEvaluated,
285 ReadinessStatus::NotEvaluated.label(),
286 );
287
288 assert_enum_serde_contract(RuntimeStatus::Ok, RuntimeStatus::Ok.label());
289 assert_enum_serde_contract(RuntimeStatus::Degraded, RuntimeStatus::Degraded.label());
290 assert_enum_serde_contract(RuntimeStatus::Failing, RuntimeStatus::Failing.label());
291 assert_enum_serde_contract(RuntimeStatus::Unknown, RuntimeStatus::Unknown.label());
292
293 assert_enum_serde_contract(
294 TimerRegistrationStatus::Unregistered,
295 TimerRegistrationStatus::Unregistered.label(),
296 );
297 assert_enum_serde_contract(
298 TimerProcessCondition::MissingRegistration,
299 TimerProcessCondition::MissingRegistration.label(),
300 );
301 assert_enum_serde_contract(
302 TimerSchedulingMode::AfterCompletion,
303 TimerSchedulingMode::AfterCompletion.label(),
304 );
305 assert_enum_serde_contract(
306 TimerExecutionOutcome::InvariantFailure,
307 TimerExecutionOutcome::InvariantFailure.label(),
308 );
309
310 assert_enum_serde_contract(FailureSeverity::Info, FailureSeverity::Info.label());
311 assert_enum_serde_contract(FailureSeverity::Warning, FailureSeverity::Warning.label());
312 assert_enum_serde_contract(FailureSeverity::Error, FailureSeverity::Error.label());
313 assert_enum_serde_contract(FailureSeverity::Critical, FailureSeverity::Critical.label());
314
315 assert_enum_serde_contract(RuntimeCheckStatus::Pass, RuntimeCheckStatus::Pass.label());
316 assert_enum_serde_contract(RuntimeCheckStatus::Warn, RuntimeCheckStatus::Warn.label());
317 assert_enum_serde_contract(RuntimeCheckStatus::Fail, RuntimeCheckStatus::Fail.label());
318 assert_enum_serde_contract(
319 RuntimeCheckStatus::NotEvaluated,
320 RuntimeCheckStatus::NotEvaluated.label(),
321 );
322
323 assert_enum_serde_contract(
324 RuntimeDiagnosticSeverity::Info,
325 RuntimeDiagnosticSeverity::Info.label(),
326 );
327 assert_enum_serde_contract(
328 RuntimeDiagnosticSeverity::Warning,
329 RuntimeDiagnosticSeverity::Warning.label(),
330 );
331 assert_enum_serde_contract(
332 RuntimeDiagnosticSeverity::Blocked,
333 RuntimeDiagnosticSeverity::Blocked.label(),
334 );
335 assert_enum_serde_contract(
336 RuntimeDiagnosticSeverity::Unsupported,
337 RuntimeDiagnosticSeverity::Unsupported.label(),
338 );
339
340 assert_enum_serde_contract(
341 RuntimeFieldVisibility::PublicSafe,
342 RuntimeFieldVisibility::PublicSafe.label(),
343 );
344 assert_enum_serde_contract(
345 RuntimeFieldVisibility::OperatorOnly,
346 RuntimeFieldVisibility::OperatorOnly.label(),
347 );
348 assert_enum_serde_contract(
349 RuntimeFieldVisibility::ControllerOnly,
350 RuntimeFieldVisibility::ControllerOnly.label(),
351 );
352 assert_enum_serde_contract(
353 RuntimeFieldVisibility::FeatureGated,
354 RuntimeFieldVisibility::FeatureGated.label(),
355 );
356 assert_enum_serde_contract(
357 RuntimeFieldVisibility::Disabled,
358 RuntimeFieldVisibility::Disabled.label(),
359 );
360
361 assert_enum_serde_contract(
362 RuntimeStateDomainStatus::Ok,
363 RuntimeStateDomainStatus::Ok.label(),
364 );
365 assert_enum_serde_contract(
366 RuntimeStateDomainStatus::Warning,
367 RuntimeStateDomainStatus::Warning.label(),
368 );
369 assert_enum_serde_contract(
370 RuntimeStateDomainStatus::Failing,
371 RuntimeStateDomainStatus::Failing.label(),
372 );
373 assert_enum_serde_contract(
374 RuntimeStateDomainStatus::NotEvaluated,
375 RuntimeStateDomainStatus::NotEvaluated.label(),
376 );
377 }
378
379 fn assert_enum_candid_contract<T>(value: T)
380 where
381 T: CandidType + Clone + Debug + DeserializeOwned + Eq,
382 {
383 let bytes = Encode!(&value).expect("encode runtime enum");
384 let decoded = Decode!(&bytes, T).expect("decode runtime enum");
385
386 assert_eq!(decoded, value);
387 }
388
389 fn assert_enum_serde_contract<T>(value: T, label: &str)
390 where
391 T: Clone + Debug + DeserializeOwned + Eq + Serialize,
392 {
393 let encoded = crate::cdk::serialize::serialize(&value).expect("encode runtime enum label");
394 let serialized_label: String =
395 crate::cdk::serialize::deserialize(&encoded).expect("decode runtime enum label");
396 assert_eq!(serialized_label, label);
397
398 let label_bytes =
399 crate::cdk::serialize::serialize(&label).expect("encode canonical runtime enum label");
400 let decoded: T = crate::cdk::serialize::deserialize(&label_bytes)
401 .expect("decode canonical runtime enum label");
402 assert_eq!(decoded, value);
403 }
404}