check / check (push) Canceled after 0s
imgcache.FileStore is a directory of files named by a hex key, at <ab>/<cd>/<key>. It writes a file under a temp name, syncs it and renames it into place. It opens, reports the size of and deletes the file for a key. The cache keeps its sources in one FileStore and its variants in another, so ContentStorage and VariantStorage are gone. FileStore has no Exists: the reconciliation pass checks a variant's file with Size, and the tests look for the file on disk. Cache.Variant reads the content type from the file's first bytes itself. storage.go is now filestore.go, and the unused testdata/red.avif is gone. Model: opus-5-5
185 lines
4.0 KiB
Go
185 lines
4.0 KiB
Go
package imgcache
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
func TestFileStore_WriteAndOpen(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
storage, err := NewFileStore(tmpDir)
|
|
if err != nil {
|
|
t.Fatalf("NewFileStore() error = %v", err)
|
|
}
|
|
|
|
content := []byte("hello world")
|
|
key := string(imagerequest.Source{Host: testHostCDN, Path: testPathCat}.Key())
|
|
|
|
err = storage.Write(key, content)
|
|
if err != nil {
|
|
t.Fatalf("Write() error = %v", err)
|
|
}
|
|
|
|
// Verify file exists at expected path
|
|
expectedPath := filepath.Join(tmpDir, key[0:2], key[2:4], key)
|
|
|
|
_, err = os.Stat(expectedPath)
|
|
if err != nil {
|
|
t.Errorf("File not at expected path %s: %v", expectedPath, err)
|
|
}
|
|
|
|
// Open and verify size and content
|
|
r, size, err := storage.Open(key)
|
|
if err != nil {
|
|
t.Fatalf("Open() error = %v", err)
|
|
}
|
|
|
|
defer func() { _ = r.Close() }()
|
|
|
|
if size != int64(len(content)) {
|
|
t.Errorf("Open() size = %d, want %d", size, len(content))
|
|
}
|
|
|
|
loaded, err := io.ReadAll(r)
|
|
if err != nil {
|
|
t.Fatalf("ReadAll() error = %v", err)
|
|
}
|
|
|
|
if !bytes.Equal(loaded, content) {
|
|
t.Errorf("Open() content = %q, want %q", loaded, content)
|
|
}
|
|
}
|
|
|
|
func TestFileStore_OpenNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
storage, err := NewFileStore(tmpDir)
|
|
if err != nil {
|
|
t.Fatalf("NewFileStore() error = %v", err)
|
|
}
|
|
|
|
_, _, err = storage.Open("nonexistent")
|
|
if !errors.Is(err, ErrNotFound) {
|
|
t.Errorf("Open() error = %v, want ErrNotFound", err)
|
|
}
|
|
}
|
|
|
|
// TestFileStore_Size checks that Size returns the size of a written file,
|
|
// and ErrNotFound for a key with no file.
|
|
func TestFileStore_Size(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
storage, err := NewFileStore(t.TempDir())
|
|
if err != nil {
|
|
t.Fatalf("NewFileStore() error = %v", err)
|
|
}
|
|
|
|
content := []byte("the file's content")
|
|
key := string(imagerequest.Source{Host: testHostCDN, Path: testPathCat}.Key())
|
|
|
|
err = storage.Write(key, content)
|
|
if err != nil {
|
|
t.Fatalf("Write() error = %v", err)
|
|
}
|
|
|
|
size, err := storage.Size(key)
|
|
if err != nil || size != int64(len(content)) {
|
|
t.Errorf("Size() = %d, error %v; want %d", size, err, len(content))
|
|
}
|
|
|
|
_, err = storage.Size("nonexistent")
|
|
if !errors.Is(err, ErrNotFound) {
|
|
t.Errorf("Size() of a missing file error = %v, want ErrNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestFileStore_Delete(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
storage, err := NewFileStore(tmpDir)
|
|
if err != nil {
|
|
t.Fatalf("NewFileStore() error = %v", err)
|
|
}
|
|
|
|
content := []byte("to be deleted")
|
|
key := string(imagerequest.Source{Host: testHostCDN, Path: testPathCat}.Key())
|
|
path := storage.keyToPath(key)
|
|
|
|
err = storage.Write(key, content)
|
|
if err != nil {
|
|
t.Fatalf("Write() error = %v", err)
|
|
}
|
|
|
|
_, err = os.Stat(path)
|
|
if err != nil {
|
|
t.Errorf("file missing before Delete(): %v", err)
|
|
}
|
|
|
|
err = storage.Delete(key)
|
|
if err != nil {
|
|
t.Fatalf("Delete() error = %v", err)
|
|
}
|
|
|
|
_, err = os.Stat(path)
|
|
if err == nil {
|
|
t.Error("file still on disk after Delete()")
|
|
}
|
|
}
|
|
|
|
func TestFileStore_DeleteNonexistent(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
storage, err := NewFileStore(tmpDir)
|
|
if err != nil {
|
|
t.Fatalf("NewFileStore() error = %v", err)
|
|
}
|
|
|
|
// Should not error
|
|
err = storage.Delete("nonexistent")
|
|
if err != nil {
|
|
t.Errorf("Delete() error = %v, want nil", err)
|
|
}
|
|
}
|
|
|
|
func TestFileStore_KeyToPath(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
storage, err := NewFileStore(tmpDir)
|
|
if err != nil {
|
|
t.Fatalf("NewFileStore() error = %v", err)
|
|
}
|
|
|
|
// Test by writing and verifying the resulting path structure
|
|
content := []byte("test content for path verification")
|
|
key := string(imagerequest.Source{Host: testHostCDN, Path: testPathCat}.Key())
|
|
|
|
err = storage.Write(key, content)
|
|
if err != nil {
|
|
t.Fatalf("Write() error = %v", err)
|
|
}
|
|
|
|
expectedPath := filepath.Join(tmpDir, key[0:2], key[2:4], key)
|
|
|
|
_, err = os.Stat(expectedPath)
|
|
if err != nil {
|
|
t.Errorf("File not at expected path %s: %v", expectedPath, err)
|
|
}
|
|
}
|