1
2
3
4
5 package cache
6
7 import (
8 "bytes"
9 "encoding/binary"
10 "fmt"
11 "internal/testenv"
12 "os"
13 "path/filepath"
14 "testing"
15 "time"
16 )
17
18 func init() {
19 verify = false
20 }
21
22 func TestBasic(t *testing.T) {
23 dir := t.TempDir()
24 _, err := Open(filepath.Join(dir, "notexist"))
25 if err == nil {
26 t.Fatal(`Open("tmp/notexist") succeeded, want failure`)
27 }
28
29 cdir := filepath.Join(dir, "c1")
30 if err := os.Mkdir(cdir, 0777); err != nil {
31 t.Fatal(err)
32 }
33
34 c1, err := Open(cdir)
35 if err != nil {
36 t.Fatalf("Open(c1) (create): %v", err)
37 }
38 if err := c1.putIndexEntry(dummyID(1), dummyID(12), 13, true); err != nil {
39 t.Fatalf("addIndexEntry: %v", err)
40 }
41 if err := c1.putIndexEntry(dummyID(1), dummyID(2), 3, true); err != nil {
42 t.Fatalf("addIndexEntry: %v", err)
43 }
44 if entry, err := c1.Get(dummyID(1)); err != nil || entry.OutputID != dummyID(2) || entry.Size != 3 {
45 t.Fatalf("c1.Get(1) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(2), 3)
46 }
47
48 c2, err := Open(cdir)
49 if err != nil {
50 t.Fatalf("Open(c2) (reuse): %v", err)
51 }
52 if entry, err := c2.Get(dummyID(1)); err != nil || entry.OutputID != dummyID(2) || entry.Size != 3 {
53 t.Fatalf("c2.Get(1) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(2), 3)
54 }
55 if err := c2.putIndexEntry(dummyID(2), dummyID(3), 4, true); err != nil {
56 t.Fatalf("addIndexEntry: %v", err)
57 }
58 if entry, err := c1.Get(dummyID(2)); err != nil || entry.OutputID != dummyID(3) || entry.Size != 4 {
59 t.Fatalf("c1.Get(2) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(3), 4)
60 }
61 }
62
63 func TestGrowth(t *testing.T) {
64 c, err := Open(t.TempDir())
65 if err != nil {
66 t.Fatalf("Open: %v", err)
67 }
68
69 n := 10000
70 if testing.Short() {
71 n = 10
72 }
73
74 for i := 0; i < n; i++ {
75 if err := c.putIndexEntry(dummyID(i), dummyID(i*99), int64(i)*101, true); err != nil {
76 t.Fatalf("addIndexEntry: %v", err)
77 }
78 id := ActionID(dummyID(i))
79 entry, err := c.Get(id)
80 if err != nil {
81 t.Fatalf("Get(%x): %v", id, err)
82 }
83 if entry.OutputID != dummyID(i*99) || entry.Size != int64(i)*101 {
84 t.Errorf("Get(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101)
85 }
86 }
87 for i := 0; i < n; i++ {
88 id := ActionID(dummyID(i))
89 entry, err := c.Get(id)
90 if err != nil {
91 t.Fatalf("Get2(%x): %v", id, err)
92 }
93 if entry.OutputID != dummyID(i*99) || entry.Size != int64(i)*101 {
94 t.Errorf("Get2(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101)
95 }
96 }
97 }
98
99 func TestVerifyPanic(t *testing.T) {
100 os.Setenv("GODEBUG", "gocacheverify=1")
101 initEnv()
102 defer func() {
103 os.Unsetenv("GODEBUG")
104 verify = false
105 }()
106
107 if !verify {
108 t.Fatal("initEnv did not set verify")
109 }
110
111 c, err := Open(t.TempDir())
112 if err != nil {
113 t.Fatalf("Open: %v", err)
114 }
115
116 id := ActionID(dummyID(1))
117 if err := PutBytes(c, id, []byte("abc")); err != nil {
118 t.Fatal(err)
119 }
120
121 defer func() {
122 if err := recover(); err != nil {
123 t.Log(err)
124 return
125 }
126 }()
127 PutBytes(c, id, []byte("def"))
128 t.Fatal("mismatched Put did not panic in verify mode")
129 }
130
131 func dummyID(x int) [HashSize]byte {
132 var out [HashSize]byte
133 binary.LittleEndian.PutUint64(out[:], uint64(x))
134 return out
135 }
136
137 func TestCacheTrim(t *testing.T) {
138 dir := t.TempDir()
139 c, err := Open(dir)
140 if err != nil {
141 t.Fatalf("Open: %v", err)
142 }
143 const start = 1000000000
144 now := int64(start)
145 c.now = func() time.Time { return time.Unix(now, 0) }
146
147 checkTime := func(name string, mtime int64) {
148 t.Helper()
149 file := filepath.Join(c.dir, name[:2], name)
150 info, err := os.Stat(file)
151 if err != nil {
152 t.Fatal(err)
153 }
154 if info.ModTime().Unix() != mtime {
155 t.Fatalf("%s mtime = %d, want %d", name, info.ModTime().Unix(), mtime)
156 }
157 }
158
159 id := ActionID(dummyID(1))
160 PutBytes(c, id, []byte("abc"))
161 entry, _ := c.Get(id)
162 PutBytes(c, ActionID(dummyID(2)), []byte("def"))
163 mtime := now
164 checkTime(fmt.Sprintf("%x-a", id), mtime)
165 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime)
166
167
168 now = start + 10
169 c.Get(id)
170 checkTime(fmt.Sprintf("%x-a", id), mtime)
171 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime)
172
173
174 now = start + 5000
175 mtime2 := now
176 if _, err := c.Get(id); err != nil {
177 t.Fatal(err)
178 }
179 c.OutputFile(entry.OutputID)
180 checkTime(fmt.Sprintf("%x-a", id), mtime2)
181 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime2)
182
183
184 if err := c.Trim(); err != nil {
185 if testenv.SyscallIsNotSupported(err) {
186 t.Skipf("skipping: Trim is unsupported (%v)", err)
187 }
188 t.Fatal(err)
189 }
190 if _, err := c.Get(id); err != nil {
191 t.Fatal(err)
192 }
193 c.OutputFile(entry.OutputID)
194 data, err := os.ReadFile(filepath.Join(dir, "trim.txt"))
195 if err != nil {
196 t.Fatal(err)
197 }
198 checkTime(fmt.Sprintf("%x-a", dummyID(2)), start)
199
200
201 now = start + 80000
202 if err := c.Trim(); err != nil {
203 t.Fatal(err)
204 }
205 if _, err := c.Get(id); err != nil {
206 t.Fatal(err)
207 }
208 c.OutputFile(entry.OutputID)
209 data2, err := os.ReadFile(filepath.Join(dir, "trim.txt"))
210 if err != nil {
211 t.Fatal(err)
212 }
213 if !bytes.Equal(data, data2) {
214 t.Fatalf("second trim did work: %q -> %q", data, data2)
215 }
216
217
218
219
220
221
222 now += 5 * 86400
223 checkTime(fmt.Sprintf("%x-a", dummyID(2)), start)
224 if err := c.Trim(); err != nil {
225 t.Fatal(err)
226 }
227 if _, err := c.Get(id); err != nil {
228 t.Fatal(err)
229 }
230 c.OutputFile(entry.OutputID)
231 mtime3 := now
232 if _, err := c.Get(dummyID(2)); err == nil {
233 t.Fatalf("Trim did not remove dummyID(2)")
234 }
235
236
237
238
239 now += 5 * 86400
240 if err := c.Trim(); err != nil {
241 t.Fatal(err)
242 }
243 checkTime(fmt.Sprintf("%x-a", id), mtime3)
244 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3)
245
246
247
248
249 now += 86400 / 2
250 if err := c.Trim(); err != nil {
251 t.Fatal(err)
252 }
253 checkTime(fmt.Sprintf("%x-a", id), mtime3)
254 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3)
255
256
257 now += 86400/2 + 1
258 if err := c.Trim(); err != nil {
259 t.Fatal(err)
260 }
261 if _, err := c.Get(dummyID(1)); err == nil {
262 t.Fatal("Trim did not remove dummyID(1)")
263 }
264 }
265
View as plain text