mirror of
https://github.com/Dvorinka/Primora.git
synced 2026-06-03 20:13:01 +00:00
initiall commit
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSanitizeObjectKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
valid, err := sanitizeObjectKey(" docs/readme.txt ")
|
||||
if err != nil {
|
||||
t.Fatalf("expected valid key, got error: %v", err)
|
||||
}
|
||||
if valid != "docs/readme.txt" {
|
||||
t.Fatalf("unexpected sanitized key: %s", valid)
|
||||
}
|
||||
|
||||
invalidKeys := []string{"", ".", "../secret", "/absolute/path", " /../../etc "}
|
||||
for _, key := range invalidKeys {
|
||||
if _, err := sanitizeObjectKey(key); err == nil {
|
||||
t.Fatalf("expected key %q to be invalid", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalStorePutOpenDeleteRoundTrip(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
root := t.TempDir()
|
||||
store, err := NewLocalStore(root)
|
||||
if err != nil {
|
||||
t.Fatalf("new local store: %v", err)
|
||||
}
|
||||
|
||||
content := []byte("hello primora")
|
||||
put, err := store.Put(context.Background(), "bucket-a", "docs/hello.txt", bytes.NewReader(content))
|
||||
if err != nil {
|
||||
t.Fatalf("put object: %v", err)
|
||||
}
|
||||
if put.SizeBytes != int64(len(content)) {
|
||||
t.Fatalf("unexpected size: %d", put.SizeBytes)
|
||||
}
|
||||
expectedDigest := sha256.Sum256(content)
|
||||
if put.SHA256Digest != hex.EncodeToString(expectedDigest[:]) {
|
||||
t.Fatalf("unexpected digest: %s", put.SHA256Digest)
|
||||
}
|
||||
|
||||
file, path, err := store.Open("bucket-a", "docs/hello.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("open object: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
if filepath.Clean(path) != filepath.Clean(put.Path) {
|
||||
t.Fatalf("path mismatch: got %s, want %s", path, put.Path)
|
||||
}
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
t.Fatalf("read object: %v", err)
|
||||
}
|
||||
if !bytes.Equal(data, content) {
|
||||
t.Fatalf("content mismatch: got %q, want %q", string(data), string(content))
|
||||
}
|
||||
|
||||
if err := store.Delete("bucket-a", "docs/hello.txt"); err != nil {
|
||||
t.Fatalf("delete object: %v", err)
|
||||
}
|
||||
if _, _, err := store.Open("bucket-a", "docs/hello.txt"); err == nil {
|
||||
t.Fatalf("expected open to fail after delete")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalStoreDeleteBucketRemovesAllFiles(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
root := t.TempDir()
|
||||
store, err := NewLocalStore(root)
|
||||
if err != nil {
|
||||
t.Fatalf("new local store: %v", err)
|
||||
}
|
||||
|
||||
if _, err := store.Put(context.Background(), "bucket-z", "a.txt", bytes.NewReader([]byte("a"))); err != nil {
|
||||
t.Fatalf("put a.txt: %v", err)
|
||||
}
|
||||
if _, err := store.Put(context.Background(), "bucket-z", "nested/b.txt", bytes.NewReader([]byte("b"))); err != nil {
|
||||
t.Fatalf("put b.txt: %v", err)
|
||||
}
|
||||
|
||||
if err := store.DeleteBucket("bucket-z"); err != nil {
|
||||
t.Fatalf("delete bucket: %v", err)
|
||||
}
|
||||
|
||||
_, err = os.Stat(filepath.Join(root, "bucket-z"))
|
||||
if !os.IsNotExist(err) {
|
||||
t.Fatalf("expected bucket path to be removed, stat err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalStoreMoveObject(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
root := t.TempDir()
|
||||
store, err := NewLocalStore(root)
|
||||
if err != nil {
|
||||
t.Fatalf("new local store: %v", err)
|
||||
}
|
||||
|
||||
content := []byte("rename me")
|
||||
if _, err := store.Put(context.Background(), "bucket-r", "source/name.txt", bytes.NewReader(content)); err != nil {
|
||||
t.Fatalf("put source object: %v", err)
|
||||
}
|
||||
|
||||
newPath, err := store.Move("bucket-r", "source/name.txt", "dest/renamed.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("move object: %v", err)
|
||||
}
|
||||
if filepath.Clean(newPath) != filepath.Clean(filepath.Join(root, "bucket-r", "dest/renamed.txt")) {
|
||||
t.Fatalf("unexpected moved path: %s", newPath)
|
||||
}
|
||||
|
||||
if _, _, err := store.Open("bucket-r", "source/name.txt"); err == nil {
|
||||
t.Fatalf("expected old key open to fail after move")
|
||||
}
|
||||
file, _, err := store.Open("bucket-r", "dest/renamed.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("open moved object: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
t.Fatalf("read moved object: %v", err)
|
||||
}
|
||||
if !bytes.Equal(data, content) {
|
||||
t.Fatalf("moved content mismatch: got %q, want %q", string(data), string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalStoreMoveObjectAcrossBuckets(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
root := t.TempDir()
|
||||
store, err := NewLocalStore(root)
|
||||
if err != nil {
|
||||
t.Fatalf("new local store: %v", err)
|
||||
}
|
||||
|
||||
content := []byte("cross bucket")
|
||||
if _, err := store.Put(context.Background(), "bucket-src", "folder/source.txt", bytes.NewReader(content)); err != nil {
|
||||
t.Fatalf("put source object: %v", err)
|
||||
}
|
||||
|
||||
newPath, err := store.MoveBetweenBuckets("bucket-src", "bucket-dst", "folder/source.txt", "archive/destination.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("move across buckets: %v", err)
|
||||
}
|
||||
if filepath.Clean(newPath) != filepath.Clean(filepath.Join(root, "bucket-dst", "archive/destination.txt")) {
|
||||
t.Fatalf("unexpected moved path: %s", newPath)
|
||||
}
|
||||
|
||||
if _, _, err := store.Open("bucket-src", "folder/source.txt"); err == nil {
|
||||
t.Fatalf("expected source key open to fail after move")
|
||||
}
|
||||
file, _, err := store.Open("bucket-dst", "archive/destination.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("open moved object: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
t.Fatalf("read moved object: %v", err)
|
||||
}
|
||||
if !bytes.Equal(data, content) {
|
||||
t.Fatalf("moved content mismatch: got %q, want %q", string(data), string(content))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user