app/cache_rotate_test.go
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}