check / check (push) Canceled after 0s
The five counts the cache_stats table held are now Prometheus counters in memory, as fields of the cache. NewCache makes them and registers them on the registry it is given. pixad gives it Prometheus' default registry, which /metrics serves; each test gives it a new one. The Increment methods add to their cache's counters, so counting makes no database call. cache_stats, Cache.Stats, Service.Stats, CacheStats and the pending counts are gone, with their tests. The background goroutine now writes only access times, and its names say so: StartPendingAccessTimeWrites, StopPendingAccessTimeWrites and pendingaccesstimes.go. The two stop tests whose write under way was a count now use access times. Model: opus-5-5
127 lines
2.6 KiB
Go
127 lines
2.6 KiB
Go
package imgcache
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
func setupTestDB(t *testing.T) *sql.DB {
|
|
t.Helper()
|
|
|
|
db, err := sql.Open("sqlite", ":memory:")
|
|
if err != nil {
|
|
t.Fatalf("failed to open test db: %v", err)
|
|
}
|
|
|
|
// Create schema
|
|
schema := `
|
|
CREATE TABLE source_content (
|
|
source_key TEXT PRIMARY KEY,
|
|
size_bytes INTEGER NOT NULL,
|
|
last_accessed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
CREATE TABLE negative_cache (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
source_host TEXT NOT NULL,
|
|
source_path TEXT NOT NULL,
|
|
source_query TEXT NOT NULL DEFAULT '',
|
|
expires_at DATETIME NOT NULL,
|
|
UNIQUE(source_host, source_path, source_query)
|
|
);
|
|
`
|
|
|
|
_, err = db.ExecContext(t.Context(), schema)
|
|
if err != nil {
|
|
t.Fatalf("failed to create schema: %v", err)
|
|
}
|
|
|
|
return db
|
|
}
|
|
|
|
func TestCache_CleanExpired(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
db := setupTestDB(t)
|
|
|
|
cache, _ := NewCache(db, CacheConfig{
|
|
StateDir: tmpDir,
|
|
NegativeTTL: 1 * time.Millisecond,
|
|
}, prometheus.NewRegistry())
|
|
|
|
ctx := context.Background()
|
|
|
|
// Insert expired negative cache entry directly
|
|
_, err := db.ExecContext(ctx, `
|
|
INSERT INTO negative_cache
|
|
(source_host, source_path, source_query, expires_at)
|
|
VALUES ('example.com', '/old.jpg', '', datetime('now', '-1 hour'))
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("failed to insert test data: %v", err)
|
|
}
|
|
|
|
// Verify it exists
|
|
var count int
|
|
|
|
err = db.QueryRowContext(ctx, `SELECT COUNT(*) FROM negative_cache`).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("failed to count negative cache entries: %v", err)
|
|
}
|
|
|
|
if count != 1 {
|
|
t.Fatalf("expected 1 negative cache entry, got %d", count)
|
|
}
|
|
|
|
// Clean expired
|
|
err = cache.CleanExpired(ctx)
|
|
if err != nil {
|
|
t.Fatalf("CleanExpired() error = %v", err)
|
|
}
|
|
|
|
// Verify it's gone
|
|
err = db.QueryRowContext(ctx, `SELECT COUNT(*) FROM negative_cache`).Scan(&count)
|
|
if err != nil {
|
|
t.Fatalf("failed to count negative cache entries: %v", err)
|
|
}
|
|
|
|
if count != 0 {
|
|
t.Errorf("expected 0 negative cache entries after clean, got %d", count)
|
|
}
|
|
}
|
|
|
|
func TestCache_StorageDirectoriesCreated(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
db := setupTestDB(t)
|
|
|
|
_, err := NewCache(db, CacheConfig{
|
|
StateDir: tmpDir,
|
|
}, prometheus.NewRegistry())
|
|
if err != nil {
|
|
t.Fatalf("NewCache() error = %v", err)
|
|
}
|
|
|
|
// Verify directories were created
|
|
dirs := []string{
|
|
"cache/sources",
|
|
"cache/variants",
|
|
}
|
|
|
|
for _, dir := range dirs {
|
|
path := tmpDir + "/" + dir
|
|
|
|
_, err := os.Stat(path)
|
|
if os.IsNotExist(err) {
|
|
t.Errorf("directory %s was not created", dir)
|
|
}
|
|
}
|
|
}
|