#![allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReplicationTier {
pub on_site_copies: u32,
pub off_site_copies: u32,
}
impl ReplicationTier {
#[must_use]
pub fn new(on_site_copies: u32, off_site_copies: u32) -> Self {
Self {
on_site_copies,
off_site_copies,
}
}
#[must_use]
pub fn total_copies(&self) -> u32 {
self.on_site_copies + self.off_site_copies
}
#[must_use]
pub fn satisfies_321_rule(&self) -> bool {
self.total_copies() >= 3 && self.on_site_copies >= 2 && self.off_site_copies >= 1
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FixitySchedule {
Daily,
Weekly,
Monthly,
Quarterly,
Annually,
}
impl FixitySchedule {
#[must_use]
pub fn interval_days(&self) -> u32 {
match self {
FixitySchedule::Daily => 1,
FixitySchedule::Weekly => 7,
FixitySchedule::Monthly => 30,
FixitySchedule::Quarterly => 90,
FixitySchedule::Annually => 365,
}
}
}
#[derive(Debug, Clone)]
pub struct PreservationPolicy {
pub name: String,
pub description: String,
pub replication: ReplicationTier,
pub fixity_schedule: FixitySchedule,
pub retention_years: u32,
pub requires_format_migration: bool,
}
impl PreservationPolicy {
#[must_use]
pub fn new(
name: impl Into<String>,
description: impl Into<String>,
replication: ReplicationTier,
fixity_schedule: FixitySchedule,
retention_years: u32,
requires_format_migration: bool,
) -> Self {
Self {
name: name.into(),
description: description.into(),
replication,
fixity_schedule,
retention_years,
requires_format_migration,
}
}
#[must_use]
pub fn is_gold_tier(&self) -> bool {
self.replication.satisfies_321_rule()
&& self.fixity_schedule.interval_days() <= 30
&& self.retention_years >= 10
}
#[must_use]
pub fn total_fixity_checks(&self) -> u64 {
let days = u64::from(self.retention_years) * 365;
let interval = u64::from(self.fixity_schedule.interval_days()).max(1);
days / interval
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_replication_total_copies() {
let tier = ReplicationTier::new(2, 1);
assert_eq!(tier.total_copies(), 3);
}
#[test]
fn test_replication_321_satisfied() {
let tier = ReplicationTier::new(2, 1);
assert!(tier.satisfies_321_rule());
}
#[test]
fn test_replication_321_not_satisfied_low_total() {
let tier = ReplicationTier::new(1, 1);
assert!(!tier.satisfies_321_rule());
}
#[test]
fn test_replication_321_not_satisfied_no_offsite() {
let tier = ReplicationTier::new(3, 0);
assert!(!tier.satisfies_321_rule());
}
#[test]
fn test_replication_321_not_satisfied_one_onsite() {
let tier = ReplicationTier::new(1, 2);
assert!(!tier.satisfies_321_rule());
}
#[test]
fn test_replication_fields() {
let tier = ReplicationTier::new(3, 2);
assert_eq!(tier.on_site_copies, 3);
assert_eq!(tier.off_site_copies, 2);
}
#[test]
fn test_fixity_daily_interval() {
assert_eq!(FixitySchedule::Daily.interval_days(), 1);
}
#[test]
fn test_fixity_weekly_interval() {
assert_eq!(FixitySchedule::Weekly.interval_days(), 7);
}
#[test]
fn test_fixity_monthly_interval() {
assert_eq!(FixitySchedule::Monthly.interval_days(), 30);
}
#[test]
fn test_fixity_quarterly_interval() {
assert_eq!(FixitySchedule::Quarterly.interval_days(), 90);
}
#[test]
fn test_fixity_annually_interval() {
assert_eq!(FixitySchedule::Annually.interval_days(), 365);
}
#[test]
fn test_policy_gold_tier_yes() {
let policy = PreservationPolicy::new(
"Gold",
"Highest grade policy",
ReplicationTier::new(2, 1),
FixitySchedule::Monthly,
25,
true,
);
assert!(policy.is_gold_tier());
}
#[test]
fn test_policy_gold_tier_no_quarterly() {
let policy = PreservationPolicy::new(
"Silver",
"Not gold",
ReplicationTier::new(2, 1),
FixitySchedule::Quarterly,
25,
false,
);
assert!(!policy.is_gold_tier());
}
#[test]
fn test_policy_gold_tier_no_short_retention() {
let policy = PreservationPolicy::new(
"Bronze",
"Short retention",
ReplicationTier::new(2, 1),
FixitySchedule::Monthly,
5,
false,
);
assert!(!policy.is_gold_tier());
}
#[test]
fn test_policy_total_fixity_checks() {
let policy = PreservationPolicy::new(
"Test",
"Policy",
ReplicationTier::new(2, 1),
FixitySchedule::Monthly,
10,
false,
);
let checks = policy.total_fixity_checks();
assert_eq!(checks, 10 * 365 / 30);
}
#[test]
fn test_policy_name_field() {
let policy = PreservationPolicy::new(
"MyPolicy",
"Desc",
ReplicationTier::new(2, 1),
FixitySchedule::Weekly,
5,
false,
);
assert_eq!(policy.name, "MyPolicy");
}
}