package sync import ( "os" "path/filepath" "strings" "testing" ) func TestBlobDir(t *testing.T) { got := BlobDir("/tmp/vault") want := "/tmp/vault/.verstak/blobs" if got != want { t.Errorf("BlobDir() = %q, want %q", got, want) } } func TestBlobPath(t *testing.T) { sha := "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" got := BlobPath("/tmp/blobs", sha) want := "/tmp/blobs/ab/cd/abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" if got != want { t.Errorf("BlobPath() = %q, want %q", got, want) } } func TestHashBytes(t *testing.T) { got := HashBytes([]byte("hello")) // SHA-256 of "hello" want := "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" if got != want { t.Errorf("HashBytes() = %q, want %q", got, want) } gotEmpty := HashBytes([]byte{}) wantEmpty := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" if gotEmpty != wantEmpty { t.Errorf("HashBytes(empty) = %q, want %q", gotEmpty, wantEmpty) } } func TestHashFile(t *testing.T) { dir := t.TempDir() // Write a test file. path := filepath.Join(dir, "test.txt") if err := os.WriteFile(path, []byte("hello"), 0644); err != nil { t.Fatal(err) } got, err := HashFile(path) if err != nil { t.Fatal(err) } want := "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" if got != want { t.Errorf("HashFile() = %q, want %q", got, want) } // Hash a non-existent file. _, err = HashFile(filepath.Join(dir, "nonexistent")) if err == nil { t.Error("HashFile() expected error for non-existent file") } } func TestStoreBlob(t *testing.T) { dir := t.TempDir() blobsDir := BlobDir(dir) srcDir := t.TempDir() // Write source file. srcPath := filepath.Join(srcDir, "data.bin") if err := os.WriteFile(srcPath, []byte("hello world"), 0644); err != nil { t.Fatal(err) } // Store the blob. sha, err := StoreBlob(blobsDir, srcPath) if err != nil { t.Fatal(err) } wantSHA := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" if sha != wantSHA { t.Errorf("StoreBlob() sha = %q, want %q", sha, wantSHA) } // Verify file exists at the expected path. blobPath := BlobPath(blobsDir, sha) if _, err := os.Stat(blobPath); err != nil { t.Errorf("blob file not created at %s: %v", blobPath, err) } // Verify content. data, err := os.ReadFile(blobPath) if err != nil { t.Fatal(err) } if string(data) != "hello world" { t.Errorf("blob content = %q, want %q", string(data), "hello world") } } func TestStoreBlob_Deduplicate(t *testing.T) { dir := t.TempDir() blobsDir := BlobDir(dir) srcDir := t.TempDir() // Create two files with the same content. src1 := filepath.Join(srcDir, "a.txt") src2 := filepath.Join(srcDir, "b.txt") if err := os.WriteFile(src1, []byte("same content"), 0644); err != nil { t.Fatal(err) } if err := os.WriteFile(src2, []byte("same content"), 0644); err != nil { t.Fatal(err) } sha1, err := StoreBlob(blobsDir, src1) if err != nil { t.Fatal(err) } sha2, err := StoreBlob(blobsDir, src2) if err != nil { t.Fatal(err) } if sha1 != sha2 { t.Errorf("StoreBlob() deduplication failed: sha1=%q sha2=%q", sha1, sha2) } // Count files in the blob store — should only be 1. var count int filepath.Walk(blobsDir, func(p string, fi os.FileInfo, err error) error { if err == nil && !fi.IsDir() { count++ } return nil }) if count != 1 { t.Errorf("expected 1 blob file, got %d", count) } } func TestStoreBlob_LargeFile(t *testing.T) { dir := t.TempDir() blobsDir := BlobDir(dir) srcDir := t.TempDir() // Create a 1MB file. srcPath := filepath.Join(srcDir, "large.bin") data := make([]byte, 1024*1024) for i := range data { data[i] = byte(i % 256) } if err := os.WriteFile(srcPath, data, 0644); err != nil { t.Fatal(err) } sha, err := StoreBlob(blobsDir, srcPath) if err != nil { t.Fatal(err) } if len(sha) != 64 { t.Errorf("expected 64-char SHA-256, got %d chars", len(sha)) } blobPath := BlobPath(blobsDir, sha) stored, err := os.ReadFile(blobPath) if err != nil { t.Fatal(err) } if len(stored) != len(data) { t.Errorf("stored blob size = %d, want %d", len(stored), len(data)) } } func TestReadBlob(t *testing.T) { dir := t.TempDir() blobsDir := BlobDir(dir) srcDir := t.TempDir() srcPath := filepath.Join(srcDir, "data.txt") if err := os.WriteFile(srcPath, []byte("read test"), 0644); err != nil { t.Fatal(err) } sha, err := StoreBlob(blobsDir, srcPath) if err != nil { t.Fatal(err) } data, err := ReadBlob(blobsDir, sha) if err != nil { t.Fatal(err) } if string(data) != "read test" { t.Errorf("ReadBlob() = %q, want %q", string(data), "read test") } // Read non-existent blob. _, err = ReadBlob(blobsDir, strings.Repeat("a", 64)) if err == nil { t.Error("ReadBlob() expected error for non-existent blob") } }