krabka_verified/
registration.rs1use creusot_std::prelude::*;
4
5#[krabka_macros::model_type]
11pub enum BrokerHeartbeatDecision {
12 Missing,
14 Stale,
16 Current { caught_up: bool },
20}
21
22#[ensures(match result {
26 BrokerHeartbeatDecision::Missing => registered_epoch == None,
27 BrokerHeartbeatDecision::Stale => exists<epoch: i64>
28 registered_epoch == Some(epoch) && request_epoch != epoch,
29 BrokerHeartbeatDecision::Current { caught_up } => exists<epoch: i64>
30 registered_epoch == Some(epoch)
31 && request_epoch == epoch
32 && caught_up == (metadata_offset@ >= epoch@),
33})]
34#[must_use]
35pub fn broker_heartbeat_decision(
36 registered_epoch: Option<i64>,
37 request_epoch: i64,
38 metadata_offset: i64,
39) -> BrokerHeartbeatDecision {
40 match registered_epoch {
41 None => BrokerHeartbeatDecision::Missing,
42 Some(epoch) if request_epoch != epoch => BrokerHeartbeatDecision::Stale,
43 Some(epoch) => BrokerHeartbeatDecision::Current {
44 caught_up: metadata_offset >= epoch,
45 },
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use {
52 super::{BrokerHeartbeatDecision as D, broker_heartbeat_decision},
53 assert2::assert,
54 };
55
56 #[test]
57 fn heartbeat_fences_exact_epochs_and_reports_catch_up() {
58 let cases = [
59 ("unregistered broker", None, 7, 7, D::Missing),
60 ("older epoch", Some(7), 6, i64::MAX, D::Stale),
61 ("newer epoch", Some(7), 8, i64::MAX, D::Stale),
62 ("behind its registration", Some(7), 7, 6, D::Current {
63 caught_up: false,
64 }),
65 ("at its registration", Some(7), 7, 7, D::Current {
66 caught_up: true,
67 }),
68 ("past its registration", Some(7), 7, 9, D::Current {
69 caught_up: true,
70 }),
71 ];
72 for (case, registered_epoch, request_epoch, metadata_offset, expected) in cases {
73 assert!(
74 broker_heartbeat_decision(registered_epoch, request_epoch, metadata_offset)
75 == expected,
76 "{case}"
77 );
78 }
79 }
80}