github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/greenhouse/diskcache/cache_test.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package diskcache 18 19 import ( 20 "bytes" 21 "crypto/rand" 22 "crypto/sha256" 23 "encoding/hex" 24 "io" 25 "io/ioutil" 26 "os" 27 "path/filepath" 28 "testing" 29 30 "k8s.io/apimachinery/pkg/util/sets" 31 ) 32 33 func hashBytes(b []byte) string { 34 hasher := sha256.New() 35 hasher.Write(b) 36 return hex.EncodeToString(hasher.Sum(nil)) 37 } 38 39 func makeRandomBytes(n int) (b []byte, err error) { 40 b = make([]byte, n) 41 _, err = rand.Read(b) 42 if err != nil { 43 return nil, err 44 } 45 return b, nil 46 } 47 48 // test cache.PathToKey and cache.KeyToPath 49 func TestPathToKeyKeyToPath(t *testing.T) { 50 cache := NewCache("/some/dir") 51 testCases := []struct { 52 Key string 53 ExpectedPath string 54 }{ 55 { 56 Key: "key", 57 ExpectedPath: filepath.Join("/some/dir", "key"), 58 }, 59 { 60 Key: "namespaced/key", 61 ExpectedPath: filepath.Join("/some/dir", "namespaced/key"), 62 }, 63 { 64 Key: "entry/nested/a/few/times", 65 ExpectedPath: filepath.Join("/some/dir", "entry/nested/a/few/times"), 66 }, 67 { 68 Key: "foobar/cas/asdf", 69 ExpectedPath: filepath.Join("/some/dir", "foobar/cas/asdf"), 70 }, 71 { 72 Key: "foobar/ac/asdf", 73 ExpectedPath: filepath.Join("/some/dir", "foobar/ac/asdf"), 74 }, 75 } 76 for _, tc := range testCases { 77 path := cache.KeyToPath(tc.Key) 78 if path != tc.ExpectedPath { 79 t.Fatalf("expected KeyToPath(%s) to be %s", tc.Key, path) 80 } 81 backToKey := cache.PathToKey(path) 82 if backToKey != tc.Key { 83 t.Fatalf("cache.KeyToPath(cache.PathToKey(%s)) was not idempotent, got %s", tc.Key, backToKey) 84 } 85 } 86 } 87 88 // test stateful cache methods 89 func TestCacheStorage(t *testing.T) { 90 // create a cache in a tempdir 91 dir, err := ioutil.TempDir("", "cache-tests") 92 if err != nil { 93 t.Fatalf("Failed to create tempdir for tests! %v", err) 94 } 95 defer os.RemoveAll(dir) 96 cache := NewCache(dir) 97 98 // sanity checks 99 if cache.DiskRoot() != dir { 100 t.Fatalf("Expected DiskRoot to be %v not %v", dir, cache.DiskRoot()) 101 } 102 // we haven't put anything yet, so get should return exists == false 103 err = cache.Get("some/key", func(exists bool, contents io.ReadSeeker) error { 104 if exists { 105 t.Fatal("no keys should exist yet!") 106 } 107 return nil 108 }) 109 if err != nil { 110 t.Fatalf("Got unexpected error testing non-existent key: %v", err) 111 } 112 113 // Test Put and Get together 114 // create 1 MB of random bytes 115 lotsOfRandomBytes, err := makeRandomBytes(1000000) 116 if err != nil { 117 t.Fatalf("Failed to create random test data: %v", err) 118 } 119 testCases := []struct { 120 Name string 121 Key string 122 Contents []byte 123 Hash string 124 PutShouldError bool 125 }{ 126 { 127 Name: "Normal", 128 Key: "foo", 129 Contents: []byte{1, 3, 3, 7}, 130 Hash: hashBytes([]byte{1, 3, 3, 7}), 131 PutShouldError: false, 132 }, 133 { 134 Name: "Bad Hash", 135 Key: "test/foo/baz", 136 Contents: []byte{1, 3, 3, 7}, 137 Hash: hashBytes([]byte{3, 1, 3, 3, 7}), 138 PutShouldError: true, 139 }, 140 { 141 Name: "Normal with Path Segments", 142 Key: "test/bar/baz", 143 Contents: []byte{107, 56, 115}, 144 Hash: hashBytes([]byte{107, 56, 115}), 145 PutShouldError: false, 146 }, 147 { 148 Name: "Lots of Random Bytes", 149 Key: "a/b/c", 150 Contents: lotsOfRandomBytes, 151 Hash: hashBytes(lotsOfRandomBytes), 152 PutShouldError: false, 153 }, 154 } 155 expectedKeys := sets.NewString() 156 for _, tc := range testCases { 157 err := cache.Put(tc.Key, bytes.NewReader(tc.Contents), tc.Hash) 158 if err != nil && !tc.PutShouldError { 159 t.Fatalf("Got error '%v' for test case '%s' and expected none.", err, tc.Name) 160 } else if err == nil && tc.PutShouldError { 161 t.Fatalf("Did not get error for test case '%s' and expected one.", tc.Name) 162 } else if err == nil { 163 expectedKeys.Insert(tc.Key) 164 } 165 166 err = cache.Get(tc.Key, func(exists bool, contents io.ReadSeeker) error { 167 if exists && tc.PutShouldError { 168 t.Fatalf("Got key exists for test case '%s' which should not.", tc.Name) 169 } else if !exists && !tc.PutShouldError { 170 t.Fatalf("Got key does not exist for test case '%s' which should.", tc.Name) 171 } 172 if exists { 173 read, err2 := ioutil.ReadAll(contents) 174 if err2 != nil { 175 t.Fatalf("Failed to read contents for test case '%s", tc.Name) 176 } 177 if !bytes.Equal(read, tc.Contents) { 178 t.Fatalf("Contents did not match expected for test case '%s' (got: %v expected: %v)", tc.Name, read, tc.Contents) 179 } 180 } 181 return nil 182 }) 183 if err != nil { 184 t.Fatalf("Got unepected error getting cache key for test case '%s': %v", tc.Name, err) 185 } 186 } 187 188 // test GetEntries 189 entries := cache.GetEntries() 190 receivedKeys := sets.NewString() 191 for _, entry := range entries { 192 receivedKeys.Insert(cache.PathToKey(entry.Path)) 193 } 194 if !expectedKeys.Equal(receivedKeys) { 195 t.Fatalf("entries %v does not equal expected: %v", receivedKeys, expectedKeys) 196 } 197 198 // test deleting all keys 199 for _, key := range expectedKeys.List() { 200 err = cache.Delete(key) 201 if err != nil { 202 t.Fatalf("failed to delete key: %v", err) 203 } 204 } 205 entries = cache.GetEntries() 206 if len(entries) != 0 { 207 t.Fatalf("cache.GetEntries() should be empty after deleting all keys, got: %v", entries) 208 } 209 }