prikk-store 0.18.2

Prikk storage crate scaffold.
Documentation
//! Final containing-directory sync propagation and retry classification.

use prikk_object::{ObjectEnvelope, ObjectType};

use crate::fsutil::{TestFailPoint, fail_after_for_test, fail_once_for_test};
use crate::test_support::{
    dummy_signature, signed_empty_block_envelope, signed_patch_envelope, signed_ref_state_envelope,
    signed_ref_update_envelope, unique_temp_dir,
};
use crate::worktree::materialize_manifest_entries;
use crate::{
    ActiveLock, FileObjectStore, ObjectWriter, RefPublication, RefStore, RepoPath,
    RepositoryLayout, SnapshotEntry, SnapshotManifest, Wal, write_active_ref_metadata,
};

#[test]
fn repository_format_parent_sync_failure_retains_and_retries() -> prikk_error::Result<()> {
    let root = unique_temp_dir("repository-sync-matrix");
    fail_once_for_test(TestFailPoint::MutableParentSync);
    assert!(RepositoryLayout::init(root.clone()).is_err());
    assert!(root.join(".prikk/FORMAT").is_file());
    assert!(RepositoryLayout::init(root.clone()).is_ok());
    let _ = std::fs::remove_dir_all(root);
    Ok(())
}

#[test]
fn immutable_object_install_sync_failure_retains_and_classifies() -> prikk_error::Result<()> {
    let root = unique_temp_dir("object-sync-matrix");
    let layout = RepositoryLayout::init(root.clone())?;
    let mut object = ObjectEnvelope::unsigned(ObjectType::Blob, 1, b"sync".to_vec());
    object.add_signature(dummy_signature())?;
    let object_id = object.object_id();
    let object_path = layout.object_path(ObjectType::Blob, object_id);
    let mut store = FileObjectStore::new(layout);
    fail_once_for_test(TestFailPoint::ImmutableInstallSync);
    assert!(store.write_object(&object).is_err());
    assert!(object_path.is_file());
    assert_eq!(store.write_object(&object)?, object_id);
    let _ = std::fs::remove_dir_all(root);
    Ok(())
}

#[test]
fn wal_parent_sync_failure_retains_one_record_and_retries() -> prikk_error::Result<()> {
    let root = unique_temp_dir("wal-sync-matrix");
    let layout = RepositoryLayout::init(root.clone())?;
    let wal = Wal::for_layout(&layout);
    let patch = signed_patch_envelope();
    fail_once_for_test(TestFailPoint::RequiredDirectorySync);
    assert!(wal.append_patch(&patch).is_err());
    assert_eq!(wal.replay()?.records.len(), 1);
    assert_eq!(wal.append_patch(&patch)?, 1);
    assert_eq!(wal.replay()?.records.len(), 1);
    let _ = std::fs::remove_dir_all(root);
    Ok(())
}

#[test]
fn active_metadata_parent_sync_failure_retains_and_retries() -> prikk_error::Result<()> {
    let root = unique_temp_dir("active-sync-matrix");
    let layout = RepositoryLayout::init(root.clone())?;
    fail_once_for_test(TestFailPoint::MutableParentSync);
    assert!(write_active_ref_metadata(&layout, "heads/main").is_err());
    assert!(layout.default_active_ref_name_path().is_file());
    assert!(write_active_ref_metadata(&layout, "heads/main").is_ok());
    let _ = std::fs::remove_dir_all(root);
    Ok(())
}

#[test]
fn ref_log_parent_sync_failure_retains_one_update_and_retries() -> prikk_error::Result<()> {
    let root = unique_temp_dir("ref-sync-matrix");
    let layout = RepositoryLayout::init(root.clone())?;
    let mut objects = FileObjectStore::new(layout.clone());
    let target = objects.write_object(&signed_empty_block_envelope())?;
    let ref_state = signed_ref_state_envelope("heads/main", None, target, 1);
    let ref_state_id = ref_state.object_id();
    let publication = RefPublication {
        ref_name: "heads/main".to_string(),
        expected_previous_ref_state_id: None,
        ref_update: signed_ref_update_envelope("heads/main", None, ref_state_id, target, 1),
        ref_state,
    };
    let store = RefStore::new(layout);
    fail_after_for_test(TestFailPoint::RequiredDirectorySync, 1);
    assert!(store.publish(&publication).is_err());
    assert_eq!(store.replay_log("heads/main")?.records.len(), 1);
    assert_eq!(store.publish(&publication)?, ref_state_id);
    assert_eq!(store.replay_log("heads/main")?.records.len(), 1);
    let _ = std::fs::remove_dir_all(root);
    Ok(())
}

#[test]
fn lock_parent_sync_failure_retains_stale_state_until_explicit_cleanup() -> prikk_error::Result<()>
{
    let root = unique_temp_dir("lock-sync-matrix");
    let layout = RepositoryLayout::init(root.clone())?;
    let lock_path = layout.default_active_lock_path();
    fail_once_for_test(TestFailPoint::RequiredDirectorySync);
    assert!(ActiveLock::acquire(&layout).is_err());
    assert!(lock_path.is_file());
    assert!(ActiveLock::acquire(&layout).is_err());
    std::fs::remove_file(&lock_path)?;
    assert!(ActiveLock::acquire(&layout).is_ok());
    let _ = std::fs::remove_dir_all(root);
    Ok(())
}

#[test]
fn worktree_parent_sync_failure_is_repaired_before_unchanged_success() -> prikk_error::Result<()> {
    let root = unique_temp_dir("worktree-sync-matrix");
    let layout = RepositoryLayout::init(root.clone())?;
    let manifest = SnapshotManifest {
        files: vec![SnapshotEntry {
            path: RepoPath::parse("file.txt")?,
            bytes: b"content".to_vec(),
        }],
    };
    fail_once_for_test(TestFailPoint::MutableParentSync);
    assert!(materialize_manifest_entries(&layout, &manifest).is_err());
    assert_eq!(std::fs::read(root.join("file.txt"))?, b"content");
    fail_once_for_test(TestFailPoint::RequiredDirectorySync);
    assert!(materialize_manifest_entries(&layout, &manifest).is_err());
    assert!(materialize_manifest_entries(&layout, &manifest).is_ok());
    let _ = std::fs::remove_dir_all(root);
    Ok(())
}