github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-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 = 10 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 dummyID(x int) [HashSize]byte { 148 var out [HashSize]byte 149 binary.LittleEndian.PutUint64(out[:], uint64(x)) 150 return out 151 } 152 153 func TestCacheTrim(t *testing.T) { 154 dir, err := ioutil.TempDir("", "cachetest-") 155 if err != nil { 156 t.Fatal(err) 157 } 158 defer os.RemoveAll(dir) 159 160 c, err := Open(dir) 161 if err != nil { 162 t.Fatalf("Open: %v", err) 163 } 164 const start = 1000000000 165 now := int64(start) 166 c.now = func() time.Time { return time.Unix(now, 0) } 167 168 checkTime := func(name string, mtime int64) { 169 t.Helper() 170 file := filepath.Join(c.dir, name[:2], name) 171 info, err := os.Stat(file) 172 if err != nil { 173 t.Fatal(err) 174 } 175 if info.ModTime().Unix() != mtime { 176 t.Fatalf("%s mtime = %d, want %d", name, info.ModTime().Unix(), mtime) 177 } 178 } 179 180 id := ActionID(dummyID(1)) 181 c.PutBytes(id, []byte("abc")) 182 entry, _ := c.Get(id) 183 c.PutBytes(ActionID(dummyID(2)), []byte("def")) 184 mtime := now 185 checkTime(fmt.Sprintf("%x-a", id), mtime) 186 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime) 187 188 // Get should not change recent mtimes. 189 now = start + 10 190 c.Get(id) 191 checkTime(fmt.Sprintf("%x-a", id), mtime) 192 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime) 193 194 // Get should change distant mtimes. 195 now = start + 5000 196 mtime2 := now 197 if _, err := c.Get(id); err != nil { 198 t.Fatal(err) 199 } 200 c.OutputFile(entry.OutputID) 201 checkTime(fmt.Sprintf("%x-a", id), mtime2) 202 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime2) 203 204 // Trim should leave everything alone: it's all too new. 205 c.Trim() 206 if _, err := c.Get(id); err != nil { 207 t.Fatal(err) 208 } 209 c.OutputFile(entry.OutputID) 210 data, err := ioutil.ReadFile(filepath.Join(dir, "trim.txt")) 211 if err != nil { 212 t.Fatal(err) 213 } 214 checkTime(fmt.Sprintf("%x-a", dummyID(2)), start) 215 216 // Trim less than a day later should not do any work at all. 217 now = start + 80000 218 c.Trim() 219 if _, err := c.Get(id); err != nil { 220 t.Fatal(err) 221 } 222 c.OutputFile(entry.OutputID) 223 data2, err := ioutil.ReadFile(filepath.Join(dir, "trim.txt")) 224 if err != nil { 225 t.Fatal(err) 226 } 227 if !bytes.Equal(data, data2) { 228 t.Fatalf("second trim did work: %q -> %q", data, data2) 229 } 230 231 // Fast forward and do another trim just before the 5 day cutoff. 232 // Note that because of usedQuantum the cutoff is actually 5 days + 1 hour. 233 // We used c.Get(id) just now, so 5 days later it should still be kept. 234 // On the other hand almost a full day has gone by since we wrote dummyID(2) 235 // and we haven't looked at it since, so 5 days later it should be gone. 236 now += 5 * 86400 237 checkTime(fmt.Sprintf("%x-a", dummyID(2)), start) 238 c.Trim() 239 if _, err := c.Get(id); err != nil { 240 t.Fatal(err) 241 } 242 c.OutputFile(entry.OutputID) 243 mtime3 := now 244 if _, err := c.Get(dummyID(2)); err == nil { // haven't done a Get for this since original write above 245 t.Fatalf("Trim did not remove dummyID(2)") 246 } 247 248 // The c.Get(id) refreshed id's mtime again. 249 // Check that another 5 days later it is still not gone, 250 // but check by using checkTime, which doesn't bring mtime forward. 251 now += 5 * 86400 252 c.Trim() 253 checkTime(fmt.Sprintf("%x-a", id), mtime3) 254 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3) 255 256 // Half a day later Trim should still be a no-op, because there was a Trim recently. 257 // Even though the entry for id is now old enough to be trimmed, 258 // it gets a reprieve until the time comes for a new Trim scan. 259 now += 86400 / 2 260 c.Trim() 261 checkTime(fmt.Sprintf("%x-a", id), mtime3) 262 checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3) 263 264 // Another half a day later, Trim should actually run, and it should remove id. 265 now += 86400/2 + 1 266 c.Trim() 267 if _, err := c.Get(dummyID(1)); err == nil { 268 t.Fatal("Trim did not remove dummyID(1)") 269 } 270 }