mod common;
use std::io::Cursor;
use std::path::PathBuf;
use ::common::crypto::SecretKey;
use ::common::mount::{Mount, MountError};
use ::common::peer::BlobsStore;
use tempfile::TempDir;
const TEST_PATH: &str = "/file.txt";
async fn setup_mount_with_mirror(
content: &[u8],
) -> (Mount, BlobsStore, SecretKey, SecretKey, TempDir) {
let (mut mount, blobs, owner_key, temp_dir) = common::setup_test_env().await;
mount
.add(&PathBuf::from(TEST_PATH), Cursor::new(content.to_vec()))
.await
.unwrap();
let mirror_key = SecretKey::generate();
mount.add_mirror(mirror_key.public()).await;
(mount, blobs, owner_key, mirror_key, temp_dir)
}
#[tokio::test]
async fn test_mirror_cannot_mount_unpublished_bucket() {
let (mount, blobs, _, mirror_key, _temp) = setup_mount_with_mirror(b"secret data").await;
let (link, _, _) = mount.save(&blobs, None).await.unwrap();
let result = Mount::load(&link, &mirror_key, &blobs).await;
assert!(
matches!(result, Err(MountError::MirrorCannotMount)),
"Mirror should not be able to mount unpublished bucket"
);
}
#[tokio::test]
async fn test_mirror_can_mount_published_bucket() {
let (mount, blobs, _, mirror_key, _temp) = setup_mount_with_mirror(b"published data").await;
let (link, _, _) = mount.publish().await.unwrap();
let mirror_mount = Mount::load(&link, &mirror_key, &blobs)
.await
.expect("Mirror should be able to mount published bucket");
let data = mirror_mount.cat(&PathBuf::from(TEST_PATH)).await.unwrap();
assert_eq!(data, b"published data");
}
#[tokio::test]
async fn test_owner_can_always_mount() {
let (mount, blobs, owner_key, _, _temp) = setup_mount_with_mirror(b"owner data").await;
let (link, _, _) = mount.save(&blobs, None).await.unwrap();
let owner_mount = Mount::load(&link, &owner_key, &blobs)
.await
.expect("Owner should always be able to mount");
let data = owner_mount.cat(&PathBuf::from(TEST_PATH)).await.unwrap();
assert_eq!(data, b"owner data");
}
#[tokio::test]
async fn test_save_preserves_publish_status() {
let (mut mount, blobs, _, mirror_key, _temp) = setup_mount_with_mirror(b"initial data").await;
let (link1, _, _) = mount.publish().await.unwrap();
let mirror_mount = Mount::load(&link1, &mirror_key, &blobs)
.await
.expect("Mirror should be able to mount published bucket");
assert!(mirror_mount.is_published().await);
mount
.add(
&PathBuf::from("/new_file.txt"),
Cursor::new(b"new data".to_vec()),
)
.await
.unwrap();
let (link2, _, _) = mount.save(&blobs, None).await.unwrap();
let mirror_mount2 = Mount::load(&link2, &mirror_key, &blobs)
.await
.expect("Mirror should mount after save() on published bucket");
assert!(mirror_mount2.is_published().await);
let data = mirror_mount2
.cat(&PathBuf::from("/new_file.txt"))
.await
.unwrap();
assert_eq!(data, b"new data");
}
#[tokio::test]
async fn test_unpublish_clears_public_secret() {
let (mount, blobs, owner_key, mirror_key, _temp) =
setup_mount_with_mirror(b"initial data").await;
let (link1, _, _) = mount.publish().await.unwrap();
let mirror_mount = Mount::load(&link1, &mirror_key, &blobs)
.await
.expect("Mirror should be able to mount published bucket");
assert!(mirror_mount.is_published().await);
let owner_mount = Mount::load(&link1, &owner_key, &blobs).await.unwrap();
let (link2, _, _) = owner_mount.unpublish().await.unwrap();
let result = Mount::load(&link2, &mirror_key, &blobs).await;
assert!(
matches!(&result, Err(MountError::MirrorCannotMount)),
"Mirror should not mount after unpublish: {:?}",
result.err()
);
let owner_mount2 = Mount::load(&link2, &owner_key, &blobs).await.unwrap();
assert!(!owner_mount2.is_published().await);
}
#[tokio::test]
async fn test_mirror_can_mount_after_mv_on_published_bucket() {
let (mut mount, blobs, _, mirror_key, _temp) = setup_mount_with_mirror(b"file content").await;
mount
.add(
&PathBuf::from("/docs/readme.md"),
Cursor::new(b"readme".to_vec()),
)
.await
.unwrap();
let (link1, _, _) = mount.publish().await.unwrap();
let mirror_mount = Mount::load(&link1, &mirror_key, &blobs)
.await
.expect("Mirror should be able to mount published bucket");
assert!(mirror_mount.is_published().await);
mount
.mv(&PathBuf::from(TEST_PATH), &PathBuf::from("/docs/moved.txt"))
.await
.unwrap();
let (link2, _, _) = mount.save(&blobs, None).await.unwrap();
let mirror_mount2 = Mount::load(&link2, &mirror_key, &blobs)
.await
.expect("Mirror should mount after mv on published bucket");
assert!(
mirror_mount2.is_published().await,
"Bucket should remain published after save()"
);
let data = mirror_mount2
.cat(&PathBuf::from("/docs/moved.txt"))
.await
.unwrap();
assert_eq!(data, b"file content");
}
#[tokio::test]
async fn test_full_fixture_flow() {
let (mut mount, blobs, owner_key, _temp_dir) = common::setup_test_env().await;
mount
.add(
&PathBuf::from("/hello.txt"),
Cursor::new(b"hello world".to_vec()),
)
.await
.unwrap();
mount
.add(
&PathBuf::from("/docs/readme.md"),
Cursor::new(b"readme content".to_vec()),
)
.await
.unwrap();
let (_, _, _) = mount.save(&blobs, None).await.unwrap();
let mirror_owner_key = SecretKey::generate();
mount.add_owner(mirror_owner_key.public()).await.unwrap();
let (_, _, _) = mount.save(&blobs, None).await.unwrap();
let mirror_key = SecretKey::generate();
mount.add_mirror(mirror_key.public()).await;
let (_, _, _) = mount.save(&blobs, None).await.unwrap();
let (link_published, _, _) = mount.publish().await.unwrap();
let mirror_mount = Mount::load(&link_published, &mirror_key, &blobs)
.await
.expect("Mirror should mount published bucket");
assert!(mirror_mount.is_published().await);
mount
.mv(
&PathBuf::from("/hello.txt"),
&PathBuf::from("/docs/hello.txt"),
)
.await
.unwrap();
let (link_after_mv, _, _) = mount.save(&blobs, None).await.unwrap();
let mirror_head = Mount::load(&link_after_mv, &mirror_key, &blobs)
.await
.expect("Mirror should mount HEAD since publish is preserved");
assert!(mirror_head.is_published().await);
let data = mirror_head
.cat(&PathBuf::from("/docs/hello.txt"))
.await
.unwrap();
assert_eq!(data, b"hello world");
let owner_mount = Mount::load(&link_after_mv, &owner_key, &blobs)
.await
.expect("Owner should always mount");
assert!(owner_mount.is_published().await, "HEAD should be published");
let (link_unpublished, _, _) = owner_mount.unpublish().await.unwrap();
let result = Mount::load(&link_unpublished, &mirror_key, &blobs).await;
assert!(
matches!(&result, Err(MountError::MirrorCannotMount)),
"Mirror should NOT mount after unpublish: {:?}",
result.err()
);
}