github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/go/internal/cache/cache_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package cache 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 "testing" 15 "time" 16 ) 17 18 func init() { 19 verify = false // even if GODEBUG is set 20 } 21 22 func TestBasic(t *testing.T) { 23 dir, err := ioutil.TempDir("", "cachetest-") 24 if err != nil { 25 t.Fatal(err) 26 } 27 defer os.RemoveAll(dir) 28 _, err = Open(filepath.Join(dir, "notexist")) 29 if err == nil { 30 t.Fatal(`Open("tmp/notexist") succeeded, want failure`) 31 } 32 33 cdir := filepath.Join(dir, "c1") 34 if err := os.Mkdir(cdir, 0777); err != nil { 35 t.Fatal(err) 36 } 37 38 c1, err := Open(cdir) 39 if err != nil { 40 t.Fatalf("Open(c1) (create): %v", err) 41 } 42 if err := c1.putIndexEntry(dummyID(1), dummyID(12), 13, true); err != nil { 43 t.Fatalf("addIndexEntry: %v", err) 44 } 45 if err := c1.putIndexEntry(dummyID(1), dummyID(2), 3, true); err != nil { // overwrite entry 46 t.Fatalf("addIndexEntry: %v", err) 47 } 48 if entry, err := c1.Get(dummyID(1)); err != nil || entry.OutputID != dummyID(2) || entry.Size != 3 { 49 t.Fatalf("c1.Get(1) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(2), 3) 50 } 51 52 c2, err := Open(cdir) 53 if err != nil { 54 t.Fatalf("Open(c2) (reuse): %v", err) 55 } 56 if entry, err := c2.Get(dummyID(1)); err != nil || entry.OutputID != dummyID(2) || entry.Size != 3 { 57 t.Fatalf("c2.Get(1) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(2), 3) 58 } 59 if err := c2.putIndexEntry(dummyID(2), dummyID(3), 4, true); err != nil { 60 t.Fatalf("addIndexEntry: %v", err) 61 } 62 if entry, err := c1.Get(dummyID(2)); err != nil || entry.OutputID != dummyID(3) || entry.Size != 4 { 63 t.Fatalf("c1.Get(2) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(3), 4) 64 } 65 } 66 67 func TestGrowth(t *testing.T) { 68 dir, err := ioutil.TempDir("", "cachetest-") 69 if err != nil { 70 t.Fatal(err) 71 } 72 defer os.RemoveAll(dir) 73 74 c, err := Open(dir) 75 if err != nil { 76 t.Fatalf("Open: %v", err) 77 } 78 79 n := 10000 80 if testing.Short() { 81 n = 1000 82 } 83 84 for i := 0; i < n; i++ { 85 if err := c.putIndexEntry(dummyID(i), dummyID(i*99), int64(i)*101, true); err != nil { 86 t.Fatalf("addIndexEntry: %v", err) 87 } 88 id := ActionID(dummyID(i)) 89 entry, err := c.Get(id) 90 if err != nil { 91 t.Fatalf("Get(%x): %v", id, err) 92 } 93 if entry.OutputID != dummyID(i*99) || entry.Size != int64(i)*101 { 94 t.Errorf("Get(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101) 95 } 96 } 97 for i := 0; i < n; i++ { 98 id := ActionID(dummyID(i)) 99 entry, err := c.Get(id) 100 if err != nil { 101 t.Fatalf("Get2(%x): %v", id, err) 102 } 103 if entry.OutputID != dummyID(i*99) || entry.Size != int64(i)*101 { 104 t.Errorf("Get2(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101) 105 } 106 } 107 } 108 109 func TestVerifyPanic(t *testing.T) { 110 os.Setenv("GODEBUG", "gocacheverify=1") 111 initEnv() 112 defer func() { 113 os.Unsetenv("GODEBUG") 114 verify = false 115 }() 116 117 if !verify { 118 t.Fatal("initEnv did not set verify") 119 } 120 121 dir, err := ioutil.TempDir("", "cachetest-") 122 if err != nil { 123 t.Fatal(err) 124 } 125 defer os.RemoveAll(dir) 126 127 c, err := Open(dir) 128 if err != nil { 129 t.Fatalf("Open: %v", err) 130 } 131 132 id := ActionID(dummyID(1)) 133 if err := c.PutBytes(id, []byte("abc")); err != nil { 134 t.Fatal(err) 135 } 136 137 defer func() { 138 if err := recover(); err != nil { 139 t.Log(err) 140 return 141 } 142 }() 143 c.PutBytes(id, []byte("def")) 144 t.Fatal("mismatched Put did not panic in verify mode") 145 } 146 147 func TestCacheLog(t *testing.T) { 148 dir, err := ioutil.TempDir("", "cachetest-") 149 if err != nil { 150 t.Fatal(err) 151 } 152 defer os.RemoveAll(dir) 153 154 c, err := Open(dir) 155 if err != nil { 156 t.Fatalf("Open: %v", err) 157 } 158 c.now = func() time.Time { return time.Unix(1e9, 0) } 159 160 id := ActionID(dummyID(1)) 161 c.Get(id) 162 c.PutBytes(id, []byte("abc")) 163 c.Get(id) 164 165 c, err = Open(dir) 166 if err != nil { 167 t.Fatalf("Open #2: %v", err) 168 } 169 c.now = func() time.Time { return time.Unix(1e9+1, 0) } 170 c.Get(id) 171 172 id2 := ActionID(dummyID(2)) 173 c.Get(id2) 174 c.PutBytes(id2, []byte("abc")) 175 c.Get(id2) 176 c.Get(id) 177 178 data, err := ioutil.ReadFile(filepath.Join(dir, "log.txt")) 179 if err != nil { 180 t.Fatal(err) 181 } 182 want := `1000000000 miss 0100000000000000000000000000000000000000000000000000000000000000 183 1000000000 put 0100000000000000000000000000000000000000000000000000000000000000 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 3 184 1000000000 get 0100000000000000000000000000000000000000000000000000000000000000 185 1000000001 get 0100000000000000000000000000000000000000000000000000000000000000 186 1000000001 miss 0200000000000000000000000000000000000000000000000000000000000000 187 1000000001 put 0200000000000000000000000000000000000000000000000000000000000000 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 3 188 1000000001 get 0200000000000000000000000000000000000000000000000000000000000000 189 1000000001 get 0100000000000000000000000000000000000000000000000000000000000000 190 ` 191 if string(data) != want { 192 t.Fatalf("log:\n%s\nwant:\n%s", string(data), want) 193 } 194 } 195 196 func dummyID(x int) [HashSize]byte { 197 var out [HashSize]byte 198 binary.LittleEndian.PutUint64(out[:], uint64(x)) 199 return out 200 } 201 202 func TestCacheTrim(t *testing.T) { 203 dir, err := ioutil.TempDir("", "cachetest-") 204 if err != nil { 205 t.Fatal(err) 206 } 207 defer os.RemoveAll(dir) 208 209 c, err := Open(dir) 210 if err != nil { 211 t.Fatalf("Open: %v", err) 212 } 213 const start = 1000000000 214 now := int64(start) 215 c.now = func() time.Time { return time.Unix(now, 0) } 216 217 checkTime := func(name string, mtime int64) { 218 t.Helper() 219 file := filepath.Join(c.dir, name[:2], name) 220 info, err := os.Stat(file) 221 if err != nil { 222 t.Fatal(err) 223 } 224 if info.ModTime().Unix() != mtime { 225 t.Fatalf("%s mtime = %d, want %d", name, info.ModTime().Unix(), mtime) 226 } 227 } 228 229 id := ActionID(dummyID(1)) 230 c.PutBytes(id, []byte("abc")) 231 entry, _ := c.Get(id) 232 c.PutBytes(ActionID(dummyID(2)), []byte("def")) 233 mtime := now 234 checkTime(fmt.Sprintf("%x-a", id), mtime) 235 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime) 236 237 // Get should not change recent mtimes. 238 now = start + 10 239 c.Get(id) 240 checkTime(fmt.Sprintf("%x-a", id), mtime) 241 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime) 242 243 // Get should change distant mtimes. 244 now = start + 5000 245 mtime2 := now 246 if _, err := c.Get(id); err != nil { 247 t.Fatal(err) 248 } 249 c.OutputFile(entry.OutputID) 250 checkTime(fmt.Sprintf("%x-a", id), mtime2) 251 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime2) 252 253 // Trim should leave everything alone: it's all too new. 254 c.Trim() 255 if _, err := c.Get(id); err != nil { 256 t.Fatal(err) 257 } 258 c.OutputFile(entry.OutputID) 259 data, err := ioutil.ReadFile(filepath.Join(dir, "trim.txt")) 260 if err != nil { 261 t.Fatal(err) 262 } 263 checkTime(fmt.Sprintf("%x-a", dummyID(2)), start) 264 265 // Trim less than a day later should not do any work at all. 266 now = start + 80000 267 c.Trim() 268 if _, err := c.Get(id); err != nil { 269 t.Fatal(err) 270 } 271 c.OutputFile(entry.OutputID) 272 data2, err := ioutil.ReadFile(filepath.Join(dir, "trim.txt")) 273 if err != nil { 274 t.Fatal(err) 275 } 276 if !bytes.Equal(data, data2) { 277 t.Fatalf("second trim did work: %q -> %q", data, data2) 278 } 279 280 // Fast forward and do another trim just before the 5 day cutoff. 281 // Note that because of usedQuantum the cutoff is actually 5 days + 1 hour. 282 // We used c.Get(id) just now, so 5 days later it should still be kept. 283 // On the other hand almost a full day has gone by since we wrote dummyID(2) 284 // and we haven't looked at it since, so 5 days later it should be gone. 285 now += 5 * 86400 286 checkTime(fmt.Sprintf("%x-a", dummyID(2)), start) 287 c.Trim() 288 if _, err := c.Get(id); err != nil { 289 t.Fatal(err) 290 } 291 c.OutputFile(entry.OutputID) 292 mtime3 := now 293 if _, err := c.Get(dummyID(2)); err == nil { // haven't done a Get for this since original write above 294 t.Fatalf("Trim did not remove dummyID(2)") 295 } 296 297 // The c.Get(id) refreshed id's mtime again. 298 // Check that another 5 days later it is still not gone, 299 // but check by using checkTime, which doesn't bring mtime forward. 300 now += 5 * 86400 301 c.Trim() 302 checkTime(fmt.Sprintf("%x-a", id), mtime3) 303 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3) 304 305 // Half a day later Trim should still be a no-op, because there was a Trim recently. 306 // Even though the entry for id is now old enough to be trimmed, 307 // it gets a reprieve until the time comes for a new Trim scan. 308 now += 86400 / 2 309 c.Trim() 310 checkTime(fmt.Sprintf("%x-a", id), mtime3) 311 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3) 312 313 // Another half a day later, Trim should actually run, and it should remove id. 314 now += 86400/2 + 1 315 c.Trim() 316 if _, err := c.Get(dummyID(1)); err == nil { 317 t.Fatal("Trim did not remove dummyID(1)") 318 } 319 }