Remove the unused cache lifetime setting (closes #69)
check / check (push) Waiting to run

CacheConfig.CacheTTL was set to DefaultCacheTTL (24 hours) and never
read, so cached images never expired. Remove the field, the constant
and the line that set it. Cached source and transformed images stay
until eviction removes them to keep the cache within cache_max_bytes.

A new test checks that a source and a transformed image cached two
days ago are still served from the cache without a new upstream fetch.

Existing tests lose only the CacheTTL line of their cache config; no
test's checks change.

Model: opus-5-5
This commit is contained in:
2026-10-13 03:06:42 +00:00
parent 162a2a33ef
commit 6ff59fd5f6
14 changed files with 90 additions and 18 deletions
@@ -2,7 +2,9 @@ package imgcache
import (
"context"
"encoding/json"
"io"
"os"
"testing"
"time"
@@ -430,6 +432,89 @@ func TestService_Get_Caching(t *testing.T) {
}
}
// TestService_Get_ServesSourceAndVariantCachedTwoDaysAgo caches a source and
// a variant of it, sets their stored fetch and creation times back two days,
// and checks that the variant is still served from the cache and that a new
// variant is made from the cached source without fetching it again.
func TestService_Get_ServesSourceAndVariantCachedTwoDaysAgo(t *testing.T) {
t.Parallel()
svc, fixtures := SetupTestService(t)
variant := photoVariant(fixtures, 85, FitCover)
resp, err := svc.Get(t.Context(), variant)
if err != nil {
t.Fatalf("Get() first request error = %v", err)
}
_ = resp.Content.Close()
for _, statement := range []string{
`UPDATE source_metadata SET fetched_at = datetime('now', '-2 days')`,
`UPDATE source_content SET fetched_at = datetime('now', '-2 days')`,
`UPDATE variant_content SET created_at = datetime('now', '-2 days')`,
} {
result, err := svc.cache.db.ExecContext(t.Context(), statement)
if err != nil {
t.Fatalf("%s: %v", statement, err)
}
rows, err := result.RowsAffected()
if err != nil || rows != 1 {
t.Fatalf("%s: rows = %d, error = %v, want 1 row", statement, rows, err)
}
}
// The variant's creation time is also its file's modification time
// and the created_at in its .meta file
twoDaysAgo := time.Now().AddDate(0, 0, -2)
variantPath := svc.cache.variants.keyToPath(CacheKey(variant))
err = os.Chtimes(variantPath, twoDaysAgo, twoDaysAgo)
if err != nil {
t.Fatalf("setting the variant file's modification time back: %v", err)
}
meta, err := json.Marshal(VariantMeta{
ContentType: resp.ContentType,
Size: resp.ContentLength,
CreatedAt: twoDaysAgo.Unix(),
})
if err != nil {
t.Fatalf("encoding .meta file: %v", err)
}
err = os.WriteFile(variantPath+".meta", meta, StorageFilePerm)
if err != nil {
t.Fatalf("writing .meta file: %v", err)
}
resp, err = svc.Get(t.Context(), variant)
if err != nil {
t.Fatalf("Get() of the cached variant error = %v", err)
}
_ = resp.Content.Close()
if resp.CacheStatus != CacheHit {
t.Errorf("cached variant CacheStatus = %q, want %q",
resp.CacheStatus, CacheHit)
}
// Another quality is a new variant, made from the cached source
resp, err = svc.Get(t.Context(), photoVariant(fixtures, 40, FitCover))
if err != nil {
t.Fatalf("Get() of a new variant error = %v", err)
}
_ = resp.Content.Close()
fetches := readCacheStatsCounters(t, svc.cache).upstreamFetchCount
if fetches != 1 {
t.Errorf("upstream fetches = %d, want 1", fetches)
}
}
func TestService_Get_DifferentSizes(t *testing.T) {
t.Parallel()