use serde::{Deserialize, Serialize};
use super::thresholds::SlaThresholds;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum SlaClass {
Bronze,
Silver,
Gold,
Platinum,
}
impl SlaClass {
pub fn thresholds(&self) -> SlaThresholds {
match self {
SlaClass::Bronze => SlaThresholds {
max_latency_p99_ms: 5_000,
max_concurrent_queries: 2,
bandwidth_mb_per_sec: 10.0,
token_refill_rate: 1.0,
token_bucket_capacity: 5.0,
},
SlaClass::Silver => SlaThresholds {
max_latency_p99_ms: 2_000,
max_concurrent_queries: 5,
bandwidth_mb_per_sec: 50.0,
token_refill_rate: 5.0,
token_bucket_capacity: 20.0,
},
SlaClass::Gold => SlaThresholds {
max_latency_p99_ms: 500,
max_concurrent_queries: 20,
bandwidth_mb_per_sec: 200.0,
token_refill_rate: 20.0,
token_bucket_capacity: 50.0,
},
SlaClass::Platinum => SlaThresholds {
max_latency_p99_ms: 100,
max_concurrent_queries: 100,
bandwidth_mb_per_sec: 1_000.0,
token_refill_rate: 100.0,
token_bucket_capacity: 200.0,
},
}
}
pub fn dispatch_priority(&self) -> u8 {
match self {
SlaClass::Bronze => 1,
SlaClass::Silver => 2,
SlaClass::Gold => 3,
SlaClass::Platinum => 4,
}
}
pub fn name(&self) -> &'static str {
match self {
SlaClass::Bronze => "bronze",
SlaClass::Silver => "silver",
SlaClass::Gold => "gold",
SlaClass::Platinum => "platinum",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_thresholds_monotonically_increasing() {
let bronze = SlaClass::Bronze.thresholds();
let silver = SlaClass::Silver.thresholds();
let gold = SlaClass::Gold.thresholds();
let platinum = SlaClass::Platinum.thresholds();
assert!(bronze.max_latency_p99_ms > silver.max_latency_p99_ms);
assert!(silver.max_latency_p99_ms > gold.max_latency_p99_ms);
assert!(gold.max_latency_p99_ms > platinum.max_latency_p99_ms);
assert!(bronze.max_concurrent_queries < silver.max_concurrent_queries);
assert!(silver.max_concurrent_queries < gold.max_concurrent_queries);
assert!(gold.max_concurrent_queries < platinum.max_concurrent_queries);
assert!(bronze.token_refill_rate < silver.token_refill_rate);
assert!(silver.token_refill_rate < gold.token_refill_rate);
assert!(gold.token_refill_rate < platinum.token_refill_rate);
assert!(bronze.token_bucket_capacity < silver.token_bucket_capacity);
assert!(silver.token_bucket_capacity < gold.token_bucket_capacity);
assert!(gold.token_bucket_capacity < platinum.token_bucket_capacity);
}
#[test]
fn test_dispatch_priority_ordered() {
assert!(SlaClass::Bronze.dispatch_priority() < SlaClass::Silver.dispatch_priority());
assert!(SlaClass::Silver.dispatch_priority() < SlaClass::Gold.dispatch_priority());
assert!(SlaClass::Gold.dispatch_priority() < SlaClass::Platinum.dispatch_priority());
}
#[test]
fn test_ord_derives_correctly() {
assert!(SlaClass::Bronze < SlaClass::Silver);
assert!(SlaClass::Silver < SlaClass::Gold);
assert!(SlaClass::Gold < SlaClass::Platinum);
assert!(SlaClass::Platinum > SlaClass::Bronze);
}
#[test]
fn test_names() {
assert_eq!(SlaClass::Bronze.name(), "bronze");
assert_eq!(SlaClass::Silver.name(), "silver");
assert_eq!(SlaClass::Gold.name(), "gold");
assert_eq!(SlaClass::Platinum.name(), "platinum");
}
#[test]
fn test_roundtrip_serialization() {
let original = SlaClass::Gold;
let json = serde_json::to_string(&original).expect("serialize");
let decoded: SlaClass = serde_json::from_str(&json).expect("deserialize");
assert_eq!(original, decoded);
}
}