use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use remora_domain::OpaqueId; use remora_durable::{PoolConfig, connect, migrate as durable_migrate}; use remora_result::{ MANIFEST_SCHEMA_VERSION, PageSize, ResultError, ResultInventory, ResultMember, migrate as result_migrate, }; use remora_target::{ ContentSha256, CreateObjectRequest, ObjectIdentity, TargetStore, TargetStoreConfig, hash_bytes, }; use serde_json::Value; use sqlx::PgPool; static NEXT_ID: AtomicU64 = AtomicU64::new(0); fn unique_id(kind: &str) -> OpaqueId { let nanos = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("system time") .as_nanos(); let sequence = NEXT_ID.fetch_add(1, Ordering::Relaxed); OpaqueId::parse(format!("{kind}-{nanos:x}-{sequence:x}")).expect("opaque id") } async fn test_pool() -> Option { let Some(url) = std::env::var("DATABASE_URL") .ok() .filter(|value| !value.is_empty()) else { if std::env::var("REMORA_RESULT_REQUIRE").is_ok() { panic!("DATABASE_URL is required when REMORA_RESULT_REQUIRE is set"); } return None; }; let pool = connect( &url, PoolConfig { max_connections: 8, acquire_timeout: Duration::from_secs(10), idle_timeout: Some(Duration::from_secs(30)), }, ) .await .expect("connect postgres"); durable_migrate(&pool).await.expect("durable migration"); result_migrate(&pool).await.expect("result migration"); Some(pool) } fn target_store() -> Option { if std::env::var("REMORA_TARGET_ENDPOINT").is_err() { if std::env::var("REMORA_RESULT_REQUIRE").is_ok() { panic!("target fixture is required when REMORA_RESULT_REQUIRE is set"); } return None; } TargetStore::connect(TargetStoreConfig::from_env().expect("target config")) .map(Some) .expect("connect target") } async fn stored_member( target: &TargetStore, attempt: &OpaqueId, path: &str, body: &[u8], ) -> ResultMember { let member_id = unique_id("member"); let stored = target .put_create_only( &CreateObjectRequest::for_attempt_object(attempt, &member_id, None), body.to_vec(), ) .await .expect("store member"); ResultMember::new( member_id, path, stored.size, stored.identity, stored.content_sha256, ) .expect("member") } #[tokio::test] async fn single_member_manifest_resolves_pages_and_exact_access() { let (Some(pool), Some(target)) = (test_pool().await, target_store()) else { return; }; let inventory = ResultInventory::new(pool); let attempt = unique_id("attempt"); inventory.create(&attempt).await.expect("create inventory"); let member = stored_member(&target, &attempt, "models/é.bin", b"member bytes").await; inventory .add_member(&attempt, &member) .await .expect("add member"); let committed = inventory .create_manifest(&attempt, &unique_id("manifest"), &target) .await .expect("create manifest"); assert_eq!(committed.schema_version, MANIFEST_SCHEMA_VERSION); assert_eq!(committed.member_count, 1); assert_eq!(committed.total_bytes, 12); inventory .validate_publication_input(&attempt, &committed) .await .expect("valid publication input"); let manifest_bytes = target .read_exact(&committed.manifest.identity) .await .expect("read exact manifest"); assert_eq!( hash_bytes(&manifest_bytes), committed.manifest.content_sha256 ); let manifest: Value = serde_json::from_slice(&manifest_bytes).expect("manifest JSON"); assert_eq!(manifest["schema_version"], 1); assert_eq!(manifest["member_count"], 1); assert_eq!(manifest["members"][0]["path"], "models/é.bin"); let page = inventory .page_members(&committed, None, PageSize::new(10).unwrap()) .await .expect("page members"); assert_eq!(page.items.len(), 1); assert_eq!(page.items[0], member); assert!(page.next_after.is_none()); let found = inventory .lookup_member(&committed, member.id()) .await .expect("lookup exact member"); assert_eq!(found, member); } #[tokio::test] async fn rejects_normalization_collision_and_closed_inventory_mutation() { let Some(pool) = test_pool().await else { return; }; let inventory = ResultInventory::new(pool); let attempt = unique_id("attempt"); inventory.create(&attempt).await.expect("create inventory"); let first = ResultMember::new( unique_id("member"), "café/file", 1, member_identity(&attempt, &unique_id("object")), hash_bytes(b"a"), ) .unwrap(); let collision = ResultMember::new( unique_id("member"), "cafe\u{301}/file", 1, member_identity(&attempt, &unique_id("object")), hash_bytes(b"b"), ) .unwrap(); inventory.add_member(&attempt, &first).await.unwrap(); assert!(matches!( inventory.add_member(&attempt, &collision).await, Err(ResultError::PathCollision) )); inventory.close(&attempt).await.unwrap(); assert!(matches!( inventory.add_member(&attempt, &collision).await, Err(ResultError::InventoryNotOpen) )); } #[tokio::test] async fn integrity_stale_attempt_and_descriptor_version_fail_closed() { let (Some(pool), Some(target)) = (test_pool().await, target_store()) else { return; }; let inventory = ResultInventory::new(pool); let attempt = unique_id("attempt"); inventory.create(&attempt).await.unwrap(); let stored = stored_member(&target, &attempt, "payload.bin", b"payload").await; let invalid = ResultMember::new( stored.id().clone(), stored.path(), stored.size() + 1, stored.exact_identity(), stored.content_sha256().clone(), ) .unwrap(); inventory.add_member(&attempt, &invalid).await.unwrap(); assert!(matches!( inventory .create_manifest(&attempt, &unique_id("manifest"), &target) .await, Err(ResultError::Integrity) )); let other_attempt = unique_id("attempt"); let stale = ResultMember::new( unique_id("member"), "stale.bin", 0, member_identity(&other_attempt, &unique_id("object")), hash_bytes(b""), ) .unwrap(); assert!(matches!( inventory.add_member(&attempt, &stale).await, Err(ResultError::StaleAttempt) )); let mut unsupported = placeholder_publication(&attempt); unsupported.schema_version = MANIFEST_SCHEMA_VERSION + 1; assert!(matches!( inventory.resolve_committed(&unsupported).await, Err(ResultError::UnsupportedManifestVersion(_)) )); } #[tokio::test] async fn pages_large_ordered_inventory_without_materializing_all_rows() { let Some(pool) = test_pool().await else { return; }; let inventory = ResultInventory::new(pool.clone()); let attempt = unique_id("attempt"); inventory.create(&attempt).await.unwrap(); let digest = hash_bytes(b""); for index in (0..2_500_u32).rev() { let member_id = OpaqueId::parse(format!("member-{index:08}")).unwrap(); let member = ResultMember::new( member_id, &format!("inventory/{index:08}"), 0, member_identity(&attempt, &unique_id("object")), digest.clone(), ) .unwrap(); inventory.add_member(&attempt, &member).await.unwrap(); } inventory.close(&attempt).await.unwrap(); let mut committed = placeholder_publication(&attempt); committed.member_count = 2_500; sqlx::query( "UPDATE result_inventories SET state = 'sealed', manifest_schema_version = $2, manifest_id = $3, manifest_store = $4, manifest_bucket = $5, manifest_key = $6, manifest_version_id = $7, manifest_sha256 = $8, manifest_size = $9 WHERE attempt_id = $1", ) .bind(attempt.as_str()) .bind(committed.schema_version as i32) .bind(committed.manifest_id.as_str()) .bind(&committed.manifest.identity.target_store_id) .bind(&committed.manifest.identity.bucket) .bind(&committed.manifest.identity.key) .bind(&committed.manifest.identity.version_id) .bind(committed.manifest.content_sha256.as_str()) .bind(committed.manifest.size as i64) .execute(&pool) .await .unwrap(); let mut after = None; let mut observed = 0_u32; loop { let page = inventory .page_members(&committed, after.as_deref(), PageSize::new(137).unwrap()) .await .unwrap(); for member in &page.items { assert_eq!(member.path(), format!("inventory/{observed:08}")); observed += 1; } let Some(next) = page.next_after else { break; }; after = Some(next); } assert_eq!(observed, 2_500); } fn member_identity(attempt: &OpaqueId, object: &OpaqueId) -> ObjectIdentity { ObjectIdentity { target_store_id: "fixture-store".into(), bucket: "fixture-bucket".into(), key: format!("_remora/a/{}/o/{}", attempt.as_str(), object.as_str()), version_id: None, } } fn placeholder_publication(attempt: &OpaqueId) -> remora_result::PublicationInput { let manifest_id = unique_id("manifest"); remora_result::PublicationInput { attempt_id: attempt.clone(), manifest_id: manifest_id.clone(), schema_version: MANIFEST_SCHEMA_VERSION, manifest: remora_target::StoredObject { identity: ObjectIdentity { target_store_id: "fixture-store".into(), bucket: "fixture-bucket".into(), key: remora_target::attempt_manifest_key(attempt, &manifest_id), version_id: None, }, content_sha256: ContentSha256::parse( "sha256:0000000000000000000000000000000000000000000000000000000000000000", ) .unwrap(), size: 0, }, member_count: 1, total_bytes: 0, } }