use serde::{Deserialize, Serialize};
pub const DEFAULT_REQUEST_LEDGER_RETENTION_DAYS: u32 = 30;
pub const MAX_REQUEST_LEDGER_RETENTION_DAYS: u32 = 366;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum RequestLedgerWriteFailure {
Fail,
#[default]
Continue,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct RequestLedgerConfig {
pub enabled: bool,
pub write_failure: RequestLedgerWriteFailure,
pub retention_days: u32,
}
impl Default for RequestLedgerConfig {
fn default() -> Self {
Self {
enabled: false,
write_failure: RequestLedgerWriteFailure::Continue,
retention_days: DEFAULT_REQUEST_LEDGER_RETENTION_DAYS,
}
}
}
impl RequestLedgerConfig {
pub fn merge(self, other: Self) -> Self {
if other == Self::default() {
self
} else {
other
}
}
pub fn validate(&self) -> Result<(), String> {
if self.retention_days == 0 || self.retention_days > MAX_REQUEST_LEDGER_RETENTION_DAYS {
return Err(format!(
"storage.request_ledger.retention_days must be between 1 and {MAX_REQUEST_LEDGER_RETENTION_DAYS}"
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_disabled_continue_with_bounded_retention() {
let config = RequestLedgerConfig::default();
assert!(!config.enabled);
assert_eq!(config.write_failure, RequestLedgerWriteFailure::Continue);
assert_eq!(config.retention_days, DEFAULT_REQUEST_LEDGER_RETENTION_DAYS);
assert!(config.validate().is_ok());
}
#[test]
fn deserializes_fail_policy() {
let config: RequestLedgerConfig =
serde_yml::from_str("enabled: true\nwrite_failure: fail\nretention_days: 7\n")
.expect("valid request ledger yaml");
assert!(config.enabled);
assert_eq!(config.write_failure, RequestLedgerWriteFailure::Fail);
assert_eq!(config.retention_days, 7);
}
#[test]
fn rejects_unbounded_retention() {
let config = RequestLedgerConfig {
retention_days: 0,
..RequestLedgerConfig::default()
};
assert!(config.validate().is_err());
}
}