github.com/peterbourgon/diskv@v2.0.1+incompatible/keys_test.go (about) 1 package diskv_test 2 3 import ( 4 "reflect" 5 "runtime" 6 "strings" 7 "testing" 8 9 "github.com/peterbourgon/diskv" 10 ) 11 12 var ( 13 keysTestData = map[string]string{ 14 "ab01cd01": "When we started building CoreOS", 15 "ab01cd02": "we looked at all the various components available to us", 16 "ab01cd03": "re-using the best tools", 17 "ef01gh04": "and building the ones that did not exist", 18 "ef02gh05": "We believe strongly in the Unix philosophy", 19 "xxxxxxxx": "tools should be independently useful", 20 } 21 22 prefixes = []string{ 23 "", // all 24 "a", 25 "ab", 26 "ab0", 27 "ab01", 28 "ab01cd0", 29 "ab01cd01", 30 "ab01cd01x", // none 31 "b", // none 32 "b0", // none 33 "0", // none 34 "01", // none 35 "e", 36 "ef", 37 "efx", // none 38 "ef01gh0", 39 "ef01gh04", 40 "ef01gh05", 41 "ef01gh06", // none 42 } 43 ) 44 45 func TestKeysFlat(t *testing.T) { 46 transform := func(s string) []string { 47 if s == "" { 48 t.Fatalf(`transform should not be called with ""`) 49 } 50 return []string{} 51 } 52 d := diskv.New(diskv.Options{ 53 BasePath: "test-data", 54 Transform: transform, 55 }) 56 defer d.EraseAll() 57 58 for k, v := range keysTestData { 59 d.Write(k, []byte(v)) 60 } 61 62 checkKeys(t, d.Keys(nil), keysTestData) 63 } 64 65 func TestKeysNested(t *testing.T) { 66 d := diskv.New(diskv.Options{ 67 BasePath: "test-data", 68 Transform: blockTransform(2), 69 }) 70 defer d.EraseAll() 71 72 for k, v := range keysTestData { 73 d.Write(k, []byte(v)) 74 } 75 76 checkKeys(t, d.Keys(nil), keysTestData) 77 } 78 79 func TestKeysPrefixFlat(t *testing.T) { 80 d := diskv.New(diskv.Options{ 81 BasePath: "test-data", 82 }) 83 defer d.EraseAll() 84 85 for k, v := range keysTestData { 86 d.Write(k, []byte(v)) 87 } 88 89 for _, prefix := range prefixes { 90 checkKeys(t, d.KeysPrefix(prefix, nil), filterPrefix(keysTestData, prefix)) 91 } 92 } 93 94 func TestKeysPrefixNested(t *testing.T) { 95 d := diskv.New(diskv.Options{ 96 BasePath: "test-data", 97 Transform: blockTransform(2), 98 }) 99 defer d.EraseAll() 100 101 for k, v := range keysTestData { 102 d.Write(k, []byte(v)) 103 } 104 105 for _, prefix := range prefixes { 106 checkKeys(t, d.KeysPrefix(prefix, nil), filterPrefix(keysTestData, prefix)) 107 } 108 } 109 110 func TestKeysCancel(t *testing.T) { 111 d := diskv.New(diskv.Options{ 112 BasePath: "test-data", 113 }) 114 defer d.EraseAll() 115 116 for k, v := range keysTestData { 117 d.Write(k, []byte(v)) 118 } 119 120 var ( 121 cancel = make(chan struct{}) 122 received = 0 123 cancelAfter = len(keysTestData) / 2 124 ) 125 126 for key := range d.Keys(cancel) { 127 received++ 128 129 if received >= cancelAfter { 130 close(cancel) 131 runtime.Gosched() // allow walker to detect cancel 132 } 133 134 t.Logf("received %d: %q", received, key) 135 } 136 137 if want, have := cancelAfter, received; want != have { 138 t.Errorf("want %d, have %d") 139 } 140 } 141 142 func checkKeys(t *testing.T, c <-chan string, want map[string]string) { 143 for k := range c { 144 if _, ok := want[k]; !ok { 145 t.Errorf("%q yielded but not expected", k) 146 continue 147 } 148 149 delete(want, k) 150 t.Logf("%q yielded OK", k) 151 } 152 153 if len(want) != 0 { 154 t.Errorf("%d expected key(s) not yielded: %s", len(want), strings.Join(flattenKeys(want), ", ")) 155 } 156 } 157 158 func blockTransform(blockSize int) func(string) []string { 159 return func(s string) []string { 160 var ( 161 sliceSize = len(s) / blockSize 162 pathSlice = make([]string, sliceSize) 163 ) 164 for i := 0; i < sliceSize; i++ { 165 from, to := i*blockSize, (i*blockSize)+blockSize 166 pathSlice[i] = s[from:to] 167 } 168 return pathSlice 169 } 170 } 171 172 func filterPrefix(in map[string]string, prefix string) map[string]string { 173 out := map[string]string{} 174 for k, v := range in { 175 if strings.HasPrefix(k, prefix) { 176 out[k] = v 177 } 178 } 179 return out 180 } 181 182 func TestFilterPrefix(t *testing.T) { 183 input := map[string]string{ 184 "all": "", 185 "and": "", 186 "at": "", 187 "available": "", 188 "best": "", 189 "building": "", 190 "components": "", 191 "coreos": "", 192 "did": "", 193 "exist": "", 194 "looked": "", 195 "not": "", 196 "ones": "", 197 "re-using": "", 198 "started": "", 199 "that": "", 200 "the": "", 201 "to": "", 202 "tools": "", 203 "us": "", 204 "various": "", 205 "we": "", 206 "when": "", 207 } 208 209 for prefix, want := range map[string]map[string]string{ 210 "a": map[string]string{"all": "", "and": "", "at": "", "available": ""}, 211 "al": map[string]string{"all": ""}, 212 "all": map[string]string{"all": ""}, 213 "alll": map[string]string{}, 214 "c": map[string]string{"components": "", "coreos": ""}, 215 "co": map[string]string{"components": "", "coreos": ""}, 216 "com": map[string]string{"components": ""}, 217 } { 218 have := filterPrefix(input, prefix) 219 if !reflect.DeepEqual(want, have) { 220 t.Errorf("%q: want %v, have %v", prefix, flattenKeys(want), flattenKeys(have)) 221 } 222 } 223 } 224 225 func flattenKeys(m map[string]string) []string { 226 a := make([]string, 0, len(m)) 227 for k := range m { 228 a = append(a, k) 229 } 230 return a 231 }