use domain::entities::{ IngestSession, IngestStatus, LibraryPath, OwnershipPolicy, QuotaDefinition, StorageVolume, TimePeriod, UsageType, }; use domain::errors::DomainError; use domain::value_objects::{Checksum, SystemId}; // --- StorageVolume --- #[test] fn creates_read_only_volume() { let vol = StorageVolume::new("archive", "s3://bucket/", false); assert_eq!(vol.volume_name, "archive"); assert_eq!(vol.uri_prefix, "s3://bucket/"); assert!(!vol.is_writable); assert_eq!(vol.available_bytes, 0); } // --- LibraryPath --- #[test] fn user_owned_path() { let vol = SystemId::new(); let owner = SystemId::new(); let lp = LibraryPath::new_user_owned(vol, "/photos", owner, true); assert_eq!(lp.ownership_policy, OwnershipPolicy::UserOwned); assert_eq!(lp.designated_owner_id, Some(owner)); assert!(lp.is_ingest_destination); assert_eq!(lp.volume_id, vol); } // --- IngestSession --- fn make_session() -> IngestSession { let checksum = Checksum::new("a".repeat(64)).unwrap(); IngestSession::new( SystemId::new(), "device-1", "photo.jpg", checksum, SystemId::new(), ) } #[test] fn valid_state_transitions() { let mut s = make_session(); assert_eq!(s.status, IngestStatus::Uploading); s.advance_to(IngestStatus::AwaitingProcessing).unwrap(); assert_eq!(s.status, IngestStatus::AwaitingProcessing); s.advance_to(IngestStatus::Processing).unwrap(); assert_eq!(s.status, IngestStatus::Processing); s.advance_to(IngestStatus::Completed).unwrap(); assert_eq!(s.status, IngestStatus::Completed); } #[test] fn invalid_transition_rejected() { let mut s = make_session(); let result = s.advance_to(IngestStatus::Completed); assert!(matches!(result, Err(DomainError::Validation(_)))); } #[test] fn can_fail_from_any_non_terminal() { for target in [ IngestStatus::Uploading, IngestStatus::AwaitingProcessing, IngestStatus::Processing, ] { let mut s = make_session(); if target == IngestStatus::AwaitingProcessing || target == IngestStatus::Processing { s.advance_to(IngestStatus::AwaitingProcessing).unwrap(); } if target == IngestStatus::Processing { s.advance_to(IngestStatus::Processing).unwrap(); } s.advance_to(IngestStatus::Failed).unwrap(); assert_eq!(s.status, IngestStatus::Failed); } } // --- Quota --- #[test] fn quota_with_rules() { let mut q = QuotaDefinition::new(SystemId::new()); assert!(q.is_enforced); assert!(q.rules.is_empty()); q.add_rule(UsageType::StorageBytes, 1_000_000, TimePeriod::Monthly); q.add_unlimited_rule(UsageType::ApiCalls); assert_eq!(q.rules.len(), 2); assert!(!q.rules[0].is_unlimited); assert_eq!(q.rules[0].limit_value, 1_000_000); assert!(q.rules[1].is_unlimited); }