Files
yms-daemon/internal/filestore/store_test.go
T
2026-08-15 02:30:36 +08:00

112 lines
3.2 KiB
Go

package filestore
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"errors"
"os"
"path/filepath"
"testing"
)
func TestStoreCommitsAndReusesImmutableFile(t *testing.T) {
t.Parallel()
store, err := New(t.TempDir())
if err != nil {
t.Fatalf("create file store: %v", err)
}
content := []byte("signed update package")
identity := identityOf(content)
committed, err := store.Commit("transactions/one/package.zip", bytes.NewReader(content), identity)
if err != nil {
t.Fatalf("commit file: %v", err)
}
if committed.Reused {
t.Fatal("new file reported as reused")
}
actual, err := os.ReadFile(committed.Path)
if err != nil || !bytes.Equal(actual, content) {
t.Fatalf("read committed file: content=%q err=%v", actual, err)
}
reused, err := store.Commit("transactions/one/package.zip", bytes.NewReader(content), identity)
if err != nil {
t.Fatalf("reuse committed file: %v", err)
}
if !reused.Reused || reused.Path != committed.Path {
t.Fatalf("unexpected reused file: %+v", reused)
}
}
func TestStoreRejectsMismatchAndNeverPublishesInvalidFile(t *testing.T) {
t.Parallel()
root := t.TempDir()
store, err := New(root)
if err != nil {
t.Fatalf("create file store: %v", err)
}
content := []byte("actual")
expected := identityOf([]byte("different"))
expected.Size = int64(len(content))
_, err = store.Commit("package.zip", bytes.NewReader(content), expected)
if err == nil {
t.Fatal("SHA-256 mismatch was accepted")
}
if _, statErr := os.Stat(filepath.Join(root, "package.zip")); !errors.Is(statErr, os.ErrNotExist) {
t.Fatalf("invalid destination was published: %v", statErr)
}
}
func TestStoreRejectsNilSource(t *testing.T) {
t.Parallel()
store, err := New(t.TempDir())
if err != nil {
t.Fatalf("create file store: %v", err)
}
if _, err := store.Commit("package.zip", nil, identityOf(nil)); err == nil {
t.Fatal("nil file source was accepted")
}
}
func TestStoreRejectsExistingDifferentContentAndPathEscape(t *testing.T) {
t.Parallel()
root := t.TempDir()
store, err := New(root)
if err != nil {
t.Fatalf("create file store: %v", err)
}
if err := os.WriteFile(filepath.Join(root, "package.zip"), []byte("old"), 0o640); err != nil {
t.Fatalf("seed destination: %v", err)
}
_, err = store.Commit("package.zip", bytes.NewReader([]byte("new")), identityOf([]byte("new")))
if !errors.Is(err, ErrDestinationConflict) {
t.Fatalf("expected destination conflict, got %v", err)
}
_, err = store.Commit("../outside", bytes.NewReader(nil), identityOf(nil))
if err == nil {
t.Fatal("path traversal was accepted")
}
}
func TestStoreRejectsSymlinkedParentOutsideRoot(t *testing.T) {
t.Parallel()
root := t.TempDir()
outside := t.TempDir()
if err := os.Symlink(outside, filepath.Join(root, "linked")); err != nil {
t.Fatalf("create parent symlink: %v", err)
}
store, err := New(root)
if err != nil {
t.Fatalf("create file store: %v", err)
}
_, err = store.Commit("linked/package.zip", bytes.NewReader(nil), identityOf(nil))
if err == nil {
t.Fatal("symlinked parent outside root was accepted")
}
}
func identityOf(content []byte) Identity {
digest := sha256.Sum256(content)
return Identity{Size: int64(len(content)), SHA256: hex.EncodeToString(digest[:])}
}