app/cache_rotate_test.go

main
skunky-art/app/cache_rotate_test.go history · blame · raw

90 lines · 2504 bytes

 1package app
 2
 3import (
 4	"os"
 5	"path/filepath"
 6	"testing"
 7	"time"
 8)
 9
10// seed writes a cache file of size bytes with the given age.
11func seed(t *testing.T, dir, name string, size int, age time.Duration, now time.Time) {
12	t.Helper()
13	p := filepath.Join(dir, name)
14	if err := os.WriteFile(p, make([]byte, size), 0600); err != nil {
15		t.Fatal(err)
16	}
17	if err := os.Chtimes(p, now.Add(-age), now.Add(-age)); err != nil {
18		t.Fatal(err)
19	}
20}
21
22func names(t *testing.T, dir string) []string {
23	t.Helper()
24	entries, err := os.ReadDir(dir)
25	if err != nil {
26		t.Fatal(err)
27	}
28	var out []string
29	for _, e := range entries {
30		out = append(out, e.Name())
31	}
32	return out
33}
34
35func TestRotateCacheDropsExpiredFiles(t *testing.T) {
36	dir, now := t.TempDir(), time.Now()
37	seed(t, dir, "old", 10, 2*time.Hour, now)
38	seed(t, dir, "new", 10, time.Minute, now)
39
40	if err := rotateCache(dir, time.Hour, 0, now); err != nil {
41		t.Fatal(err)
42	}
43	if got := names(t, dir); len(got) != 1 || got[0] != "new" {
44		t.Errorf("files after rotation: %v, want only new", got)
45	}
46}
47
48// TestRotateCacheTrimsOldestToTheCap is the regression test for #36: over the
49// cap the oldest files go until the rest fit, and the directory itself is
50// never removed.
51func TestRotateCacheTrimsOldestToTheCap(t *testing.T) {
52	dir, now := t.TempDir(), time.Now()
53	seed(t, dir, "oldest", 100, 3*time.Hour, now)
54	seed(t, dir, "middle", 100, 2*time.Hour, now)
55	seed(t, dir, "newest", 100, time.Hour, now)
56
57	if err := rotateCache(dir, 0, 250, now); err != nil {
58		t.Fatal(err)
59	}
60	got := names(t, dir)
61	if len(got) != 2 || got[0] != "middle" || got[1] != "newest" {
62		t.Errorf("files after rotation: %v, want middle and newest", got)
63	}
64	if _, err := os.Stat(dir); err != nil {
65		t.Errorf("cache directory removed: %v", err)
66	}
67}
68
69func TestRotateCacheExpiredFilesDoNotCountTowardTheCap(t *testing.T) {
70	dir, now := t.TempDir(), time.Now()
71	seed(t, dir, "expired", 200, 2*time.Hour, now)
72	seed(t, dir, "kept", 100, time.Minute, now)
73
74	if err := rotateCache(dir, time.Hour, 150, now); err != nil {
75		t.Fatal(err)
76	}
77	if got := names(t, dir); len(got) != 1 || got[0] != "kept" {
78		t.Errorf("files after rotation: %v, want only kept (the expired file must not push it over the cap)", got)
79	}
80}
81
82func TestRotateCacheCreatesAMissingDirectory(t *testing.T) {
83	dir := filepath.Join(t.TempDir(), "cache")
84	if err := rotateCache(dir, 0, 0, time.Now()); err != nil {
85		t.Fatal(err)
86	}
87	if _, err := os.Stat(dir); err != nil {
88		t.Errorf("directory not created: %v", err)
89	}
90}