One image request type instead of five (closes #307)
check / check (push) Canceled after 0s

The new package internal/imagerequest holds the request type, its two
parts Source and Transform, the Format and Fit types, the dimension and
fit checks, the /v1/image/ path parsing and the variant key; it imports
no other package of pixa. imgcache.ParsedURL, imgcache.ImageRequest,
signature.Request, imageprocessor.Request, the second Size, format and
fit types and the conversions between them are gone. The image
processor takes a Transform only. encurl keeps a private struct with the
token's CBOR field names, so tokens made before still decode. VariantKey
moves with the function that makes it. Tests follow the moved and
renamed code; the tests of the removed conversions go with them.

Model: opus-5-5
This commit is contained in:
2026-10-21 12:27:29 +00:00
parent 385c0ca76f
commit fece3b69c9
68 changed files with 2217 additions and 1978 deletions
+49 -34
View File
@@ -16,6 +16,7 @@ import (
_ "modernc.org/sqlite"
"sneak.berlin/go/pixa/internal/database"
"sneak.berlin/go/pixa/internal/httpfetcher"
"sneak.berlin/go/pixa/internal/imagerequest"
)
// sqliteTimestampFormat matches the format SQLite's CURRENT_TIMESTAMP
@@ -27,10 +28,10 @@ const sqliteTimestampFormat = "2006-01-02 15:04:05"
// keys reused across the eviction tests, in the order the tests store
// them.
const (
testVariantKeyOne VariantKey = "aabbccdd0001"
testVariantKeyTwo VariantKey = "aabbccdd0002"
testVariantKeyThree VariantKey = "aabbccdd0003"
testVariantKeyFour VariantKey = "aabbccdd0004"
testVariantKeyOne imagerequest.VariantKey = "aabbccdd0001"
testVariantKeyTwo imagerequest.VariantKey = "aabbccdd0002"
testVariantKeyThree imagerequest.VariantKey = "aabbccdd0003"
testVariantKeyFour imagerequest.VariantKey = "aabbccdd0004"
)
// evictionTestDB creates an in-memory SQLite database with the real
@@ -88,12 +89,16 @@ func storeEvictionTestSource(
) ContentHash {
t.Helper()
req := &ImageRequest{
SourceHost: host,
SourcePath: path,
Format: FormatJPEG,
Quality: 85,
FitMode: FitCover,
req := &imagerequest.Request{
Source: imagerequest.Source{
Host: host,
Path: path,
},
Transform: imagerequest.Transform{
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
},
}
result := &httpfetcher.FetchResult{
@@ -118,7 +123,7 @@ func storeEvictionTestSource(
// storeEvictionTestVariant stores content as a processed variant under
// the given cache key.
func storeEvictionTestVariant(
t *testing.T, cache *Cache, key VariantKey, content []byte,
t *testing.T, cache *Cache, key imagerequest.VariantKey, content []byte,
) {
t.Helper()
@@ -131,7 +136,7 @@ func storeEvictionTestVariant(
// setVariantLastAccessed backdates the last access time of a tracked
// variant, to make LRU ordering deterministic in tests.
func setVariantLastAccessed(
t *testing.T, cache *Cache, key VariantKey, when time.Time,
t *testing.T, cache *Cache, key imagerequest.VariantKey, when time.Time,
) {
t.Helper()
@@ -244,7 +249,7 @@ func assertNoDanglingReferences(t *testing.T, cache *Cache) {
t.Fatalf("failed to scan cache_key: %v", err)
}
if !cache.variants.Exists(VariantKey(key)) {
if !cache.variants.Exists(imagerequest.VariantKey(key)) {
t.Errorf("variant_content references key %s but the file is missing", key)
}
}
@@ -343,7 +348,7 @@ func TestEvictToLimitEvictsLeastRecentlyUsedFirst(t *testing.T) {
cache, _ := newEvictionTestCache(t, limit)
now := time.Now()
keys := []VariantKey{
keys := []imagerequest.VariantKey{
testVariantKeyOne, testVariantKeyTwo,
testVariantKeyThree, testVariantKeyFour,
}
@@ -516,12 +521,16 @@ func TestZeroMaxBytesDisablesDiskCache(t *testing.T) {
cache, tmpDir := newEvictionTestCache(t, 0)
req := &ImageRequest{
SourceHost: "src.example.com",
SourcePath: "/a.jpg",
Format: FormatJPEG,
Quality: 85,
FitMode: FitCover,
req := &imagerequest.Request{
Source: imagerequest.Source{
Host: "src.example.com",
Path: "/a.jpg",
},
Transform: imagerequest.Transform{
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
},
}
assertDisabledCacheWritesAreNoOps(t, cache, req)
@@ -533,14 +542,14 @@ func TestZeroMaxBytesDisablesDiskCache(t *testing.T) {
// assertDisabledCacheWritesAreNoOps verifies that stores against a
// disabled cache report success without recording anything.
func assertDisabledCacheWritesAreNoOps(
t *testing.T, cache *Cache, req *ImageRequest,
t *testing.T, cache *Cache, req *imagerequest.Request,
) {
t.Helper()
ctx := t.Context()
err := cache.StoreVariant(
ctx, CacheKey(req), bytes.NewReader([]byte("data")), "image/webp",
ctx, imagerequest.CacheKey(req), bytes.NewReader([]byte("data")), "image/webp",
)
if err != nil {
t.Fatalf("StoreVariant on disabled cache must be a no-op, got error: %v", err)
@@ -566,7 +575,7 @@ func assertDisabledCacheWritesAreNoOps(
// assertDisabledCacheReadsAlwaysMiss verifies that lookups against a
// disabled cache never report a hit.
func assertDisabledCacheReadsAlwaysMiss(
t *testing.T, cache *Cache, req *ImageRequest,
t *testing.T, cache *Cache, req *imagerequest.Request,
) {
t.Helper()
@@ -661,7 +670,7 @@ func TestEvictionRunsUnderWritePressure(t *testing.T) {
cache.StartEviction(time.Hour)
defer func() { _ = cache.StopEviction(t.Context()) }()
keys := []VariantKey{
keys := []imagerequest.VariantKey{
testVariantKeyOne, testVariantKeyTwo, testVariantKeyThree,
}
fills := []byte{0x11, 0x12, 0x13}
@@ -715,7 +724,7 @@ func TestEvictionRunsOnPeriodicSchedule(t *testing.T) {
time.Sleep(10 * time.Millisecond)
}
keys := []VariantKey{
keys := []imagerequest.VariantKey{
testVariantKeyOne, testVariantKeyTwo, testVariantKeyThree,
}
fills := []byte{0x21, 0x22, 0x23}
@@ -1308,9 +1317,11 @@ func TestEvictSourceBlobExcludesConcurrentStoreOfIdenticalContent(t *testing.T)
assertNoDanglingReferences(t, cache)
dupHash, _, err := cache.LookupSource(ctx, &ImageRequest{
SourceHost: "race.example.com",
SourcePath: "/dup.jpg",
dupHash, _, err := cache.LookupSource(ctx, &imagerequest.Request{
Source: imagerequest.Source{
Host: "race.example.com",
Path: "/dup.jpg",
},
})
if err != nil {
t.Fatalf("LookupSource failed: %v", err)
@@ -1336,12 +1347,16 @@ func storeIdenticalContentConcurrently(
storeDone := make(chan error, 1)
go func() {
req := &ImageRequest{
SourceHost: "race.example.com",
SourcePath: "/dup.jpg",
Format: FormatJPEG,
Quality: 85,
FitMode: FitCover,
req := &imagerequest.Request{
Source: imagerequest.Source{
Host: "race.example.com",
Path: "/dup.jpg",
},
Transform: imagerequest.Transform{
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
},
}
result := &httpfetcher.FetchResult{
StatusCode: 200,