1use serde::{Deserialize, Serialize};
8
9use super::thresholds::SlaThresholds;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
20pub enum SlaClass {
21 Bronze,
23 Silver,
25 Gold,
27 Platinum,
29}
30
31impl SlaClass {
32 pub fn thresholds(&self) -> SlaThresholds {
34 match self {
35 SlaClass::Bronze => SlaThresholds {
36 max_latency_p99_ms: 5_000,
37 max_concurrent_queries: 2,
38 bandwidth_mb_per_sec: 10.0,
39 token_refill_rate: 1.0,
40 token_bucket_capacity: 5.0,
41 },
42 SlaClass::Silver => SlaThresholds {
43 max_latency_p99_ms: 2_000,
44 max_concurrent_queries: 5,
45 bandwidth_mb_per_sec: 50.0,
46 token_refill_rate: 5.0,
47 token_bucket_capacity: 20.0,
48 },
49 SlaClass::Gold => SlaThresholds {
50 max_latency_p99_ms: 500,
51 max_concurrent_queries: 20,
52 bandwidth_mb_per_sec: 200.0,
53 token_refill_rate: 20.0,
54 token_bucket_capacity: 50.0,
55 },
56 SlaClass::Platinum => SlaThresholds {
57 max_latency_p99_ms: 100,
58 max_concurrent_queries: 100,
59 bandwidth_mb_per_sec: 1_000.0,
60 token_refill_rate: 100.0,
61 token_bucket_capacity: 200.0,
62 },
63 }
64 }
65
66 pub fn dispatch_priority(&self) -> u8 {
70 match self {
71 SlaClass::Bronze => 1,
72 SlaClass::Silver => 2,
73 SlaClass::Gold => 3,
74 SlaClass::Platinum => 4,
75 }
76 }
77
78 pub fn name(&self) -> &'static str {
80 match self {
81 SlaClass::Bronze => "bronze",
82 SlaClass::Silver => "silver",
83 SlaClass::Gold => "gold",
84 SlaClass::Platinum => "platinum",
85 }
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_thresholds_monotonically_increasing() {
95 let bronze = SlaClass::Bronze.thresholds();
96 let silver = SlaClass::Silver.thresholds();
97 let gold = SlaClass::Gold.thresholds();
98 let platinum = SlaClass::Platinum.thresholds();
99
100 assert!(bronze.max_latency_p99_ms > silver.max_latency_p99_ms);
102 assert!(silver.max_latency_p99_ms > gold.max_latency_p99_ms);
103 assert!(gold.max_latency_p99_ms > platinum.max_latency_p99_ms);
104
105 assert!(bronze.max_concurrent_queries < silver.max_concurrent_queries);
107 assert!(silver.max_concurrent_queries < gold.max_concurrent_queries);
108 assert!(gold.max_concurrent_queries < platinum.max_concurrent_queries);
109
110 assert!(bronze.token_refill_rate < silver.token_refill_rate);
111 assert!(silver.token_refill_rate < gold.token_refill_rate);
112 assert!(gold.token_refill_rate < platinum.token_refill_rate);
113
114 assert!(bronze.token_bucket_capacity < silver.token_bucket_capacity);
115 assert!(silver.token_bucket_capacity < gold.token_bucket_capacity);
116 assert!(gold.token_bucket_capacity < platinum.token_bucket_capacity);
117 }
118
119 #[test]
120 fn test_dispatch_priority_ordered() {
121 assert!(SlaClass::Bronze.dispatch_priority() < SlaClass::Silver.dispatch_priority());
122 assert!(SlaClass::Silver.dispatch_priority() < SlaClass::Gold.dispatch_priority());
123 assert!(SlaClass::Gold.dispatch_priority() < SlaClass::Platinum.dispatch_priority());
124 }
125
126 #[test]
127 fn test_ord_derives_correctly() {
128 assert!(SlaClass::Bronze < SlaClass::Silver);
129 assert!(SlaClass::Silver < SlaClass::Gold);
130 assert!(SlaClass::Gold < SlaClass::Platinum);
131 assert!(SlaClass::Platinum > SlaClass::Bronze);
132 }
133
134 #[test]
135 fn test_names() {
136 assert_eq!(SlaClass::Bronze.name(), "bronze");
137 assert_eq!(SlaClass::Silver.name(), "silver");
138 assert_eq!(SlaClass::Gold.name(), "gold");
139 assert_eq!(SlaClass::Platinum.name(), "platinum");
140 }
141
142 #[test]
143 fn test_roundtrip_serialization() {
144 let original = SlaClass::Gold;
145 let json = serde_json::to_string(&original).expect("serialize");
146 let decoded: SlaClass = serde_json::from_str(&json).expect("deserialize");
147 assert_eq!(original, decoded);
148 }
149}