check / check (push) Canceled after 0s
A source is now one source_content row and one file named by its SourceKey, the SHA-256 of its host, path and query, made as the variant key is. A store writes the file, then upserts the row, and removes the file when the row cannot be written; an eviction deletes the row, then the file, with no lock. source_metadata, the JSON files under cache/metadata/, MetadataStorage, the content lock, the eviction transaction and its test hook are gone, as is the reconciliation pass that dropped a source row whose file is missing, so TestReconciliationReadsAPageAtATime now counts 15 rows read, not 20. Two source URLs serving the same bytes store them twice. The tests of the removed sharing and lock go with them; the two eviction cancellation tests no longer use the hook. Model: opus-5-5
152 lines
3.7 KiB
Go
152 lines
3.7 KiB
Go
package imgcache
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"log/slog"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
func TestContentStorage_LoadNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
storage, err := NewContentStorage(tmpDir)
|
|
if err != nil {
|
|
t.Fatalf("NewContentStorage() error = %v", err)
|
|
}
|
|
|
|
_, err = storage.Load(imagerequest.SourceKey("nonexistent"))
|
|
if !errors.Is(err, ErrNotFound) {
|
|
t.Errorf("Load() error = %v, want ErrNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestContentStorage_DeleteNonexistent(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
storage, err := NewContentStorage(tmpDir)
|
|
if err != nil {
|
|
t.Fatalf("NewContentStorage() error = %v", err)
|
|
}
|
|
|
|
// Should not error
|
|
err = storage.Delete(imagerequest.SourceKey("nonexistent"))
|
|
if err != nil {
|
|
t.Errorf("Delete() error = %v, want nil", err)
|
|
}
|
|
}
|
|
|
|
// TestVariantStorage_StoreLogsFailedMetaWrite verifies that a .meta write
|
|
// that fails is logged at warn and the store still succeeds.
|
|
func TestVariantStorage_StoreLogsFailedMetaWrite(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var logBuf bytes.Buffer
|
|
|
|
storage, err := NewVariantStorage(
|
|
t.TempDir(), slog.New(slog.NewJSONHandler(&logBuf, nil)))
|
|
if err != nil {
|
|
t.Fatalf("NewVariantStorage() error = %v", err)
|
|
}
|
|
|
|
key := imagerequest.CacheKey(&imagerequest.Request{
|
|
Source: imagerequest.Source{Host: testHostCDN, Path: testPathCat},
|
|
})
|
|
|
|
// A directory where the .meta file goes makes the .meta write fail.
|
|
err = os.MkdirAll(storage.keyToPath(key)+".meta", StorageDirPerm)
|
|
if err != nil {
|
|
t.Fatalf("failed to create directory: %v", err)
|
|
}
|
|
|
|
_, err = storage.Store(key, bytes.NewReader([]byte("variant data")), "image/webp")
|
|
if err != nil {
|
|
t.Fatalf("Store() error = %v, want nil", err)
|
|
}
|
|
|
|
want := `"level":"WARN","msg":"failed to write variant metadata sidecar"`
|
|
if !strings.Contains(logBuf.String(), want) {
|
|
t.Errorf("log missing %s; got %q", want, logBuf.String())
|
|
}
|
|
}
|
|
|
|
// storeTestVariant stores one variant, with its .meta file, in a new
|
|
// VariantStorage and returns the storage and the variant's key.
|
|
func storeTestVariant(t *testing.T) (*VariantStorage, imagerequest.VariantKey) {
|
|
t.Helper()
|
|
|
|
storage, err := NewVariantStorage(t.TempDir(), slog.New(slog.DiscardHandler))
|
|
if err != nil {
|
|
t.Fatalf("NewVariantStorage() error = %v", err)
|
|
}
|
|
|
|
key := imagerequest.CacheKey(&imagerequest.Request{
|
|
Source: imagerequest.Source{Host: testHostCDN, Path: testPathCat},
|
|
})
|
|
|
|
_, err = storage.Store(key, bytes.NewReader([]byte("variant data")), "image/webp")
|
|
if err != nil {
|
|
t.Fatalf("Store() error = %v", err)
|
|
}
|
|
|
|
return storage, key
|
|
}
|
|
|
|
// TestVariantStorage_DeleteRemovesMeta verifies that Delete removes the
|
|
// variant's .meta file along with the variant file.
|
|
func TestVariantStorage_DeleteRemovesMeta(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
storage, key := storeTestVariant(t)
|
|
metaPath := storage.keyToPath(key) + ".meta"
|
|
|
|
_, err := os.Stat(metaPath)
|
|
if err != nil {
|
|
t.Fatalf("Store() wrote no .meta file: %v", err)
|
|
}
|
|
|
|
err = storage.Delete(key)
|
|
if err != nil {
|
|
t.Fatalf("Delete() error = %v", err)
|
|
}
|
|
|
|
if storage.Exists(key) {
|
|
t.Error("Exists() = true after delete, want false")
|
|
}
|
|
|
|
_, err = os.Stat(metaPath)
|
|
if !os.IsNotExist(err) {
|
|
t.Errorf(".meta file left after Delete() (stat err=%v)", err)
|
|
}
|
|
}
|
|
|
|
// TestVariantStorage_DeleteWithoutMeta verifies that Delete succeeds for a
|
|
// variant whose .meta file is missing.
|
|
func TestVariantStorage_DeleteWithoutMeta(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
storage, key := storeTestVariant(t)
|
|
|
|
err := os.Remove(storage.keyToPath(key) + ".meta")
|
|
if err != nil {
|
|
t.Fatalf("removing .meta file: %v", err)
|
|
}
|
|
|
|
err = storage.Delete(key)
|
|
if err != nil {
|
|
t.Fatalf("Delete() error = %v, want nil", err)
|
|
}
|
|
|
|
if storage.Exists(key) {
|
|
t.Error("Exists() = true after delete, want false")
|
|
}
|
|
}
|