package diskv_test import ( "reflect" "runtime" "strings" "testing" "github.com/peterbourgon/diskv" ) var ( keysTestData = map[string]string{ "ab01cd01": "When we started building CoreOS", "ab01cd02": "we looked at all the various components available to us", "ab01cd03": "re-using the best tools", "ef01gh04": "and building the ones that did not exist", "ef02gh05": "We believe strongly in the Unix philosophy", "xxxxxxxx": "tools should be independently useful", } prefixes = []string{ "", // all "a", "ab", "ab0", "ab01", "ab01cd0", "ab01cd01", "ab01cd01x", // none "b", // none "b0", // none "0", // none "01", // none "e", "ef", "efx", // none "ef01gh0", "ef01gh04", "ef01gh05", "ef01gh06", // none } ) func TestKeysFlat(t *testing.T) { transform := func(s string) []string { if s == "" { t.Fatalf(`transform should not be called with ""`) } return []string{} } d := diskv.New(diskv.Options{ BasePath: "test-data", Transform: transform, }) defer d.EraseAll() for k, v := range keysTestData { d.Write(k, []byte(v)) } checkKeys(t, d.Keys(nil), keysTestData) } func TestKeysNested(t *testing.T) { d := diskv.New(diskv.Options{ BasePath: "test-data", Transform: blockTransform(2), }) defer d.EraseAll() for k, v := range keysTestData { d.Write(k, []byte(v)) } checkKeys(t, d.Keys(nil), keysTestData) } func TestKeysPrefixFlat(t *testing.T) { d := diskv.New(diskv.Options{ BasePath: "test-data", }) defer d.EraseAll() for k, v := range keysTestData { d.Write(k, []byte(v)) } for _, prefix := range prefixes { checkKeys(t, d.KeysPrefix(prefix, nil), filterPrefix(keysTestData, prefix)) } } func TestKeysPrefixNested(t *testing.T) { d := diskv.New(diskv.Options{ BasePath: "test-data", Transform: blockTransform(2), }) defer d.EraseAll() for k, v := range keysTestData { d.Write(k, []byte(v)) } for _, prefix := range prefixes { checkKeys(t, d.KeysPrefix(prefix, nil), filterPrefix(keysTestData, prefix)) } } func TestKeysCancel(t *testing.T) { d := diskv.New(diskv.Options{ BasePath: "test-data", }) defer d.EraseAll() for k, v := range keysTestData { d.Write(k, []byte(v)) } var ( cancel = make(chan struct{}) received = 0 cancelAfter = len(keysTestData) / 2 ) for key := range d.Keys(cancel) { received++ if received >= cancelAfter { close(cancel) runtime.Gosched() // allow walker to detect cancel } t.Logf("received %d: %q", received, key) } if want, have := cancelAfter, received; want != have { t.Errorf("want %d, have %d") } } func checkKeys(t *testing.T, c <-chan string, want map[string]string) { for k := range c { if _, ok := want[k]; !ok { t.Errorf("%q yielded but not expected", k) continue } delete(want, k) t.Logf("%q yielded OK", k) } if len(want) != 0 { t.Errorf("%d expected key(s) not yielded: %s", len(want), strings.Join(flattenKeys(want), ", ")) } } func blockTransform(blockSize int) func(string) []string { return func(s string) []string { var ( sliceSize = len(s) / blockSize pathSlice = make([]string, sliceSize) ) for i := 0; i < sliceSize; i++ { from, to := i*blockSize, (i*blockSize)+blockSize pathSlice[i] = s[from:to] } return pathSlice } } func filterPrefix(in map[string]string, prefix string) map[string]string { out := map[string]string{} for k, v := range in { if strings.HasPrefix(k, prefix) { out[k] = v } } return out } func TestFilterPrefix(t *testing.T) { input := map[string]string{ "all": "", "and": "", "at": "", "available": "", "best": "", "building": "", "components": "", "coreos": "", "did": "", "exist": "", "looked": "", "not": "", "ones": "", "re-using": "", "started": "", "that": "", "the": "", "to": "", "tools": "", "us": "", "various": "", "we": "", "when": "", } for prefix, want := range map[string]map[string]string{ "a": map[string]string{"all": "", "and": "", "at": "", "available": ""}, "al": map[string]string{"all": ""}, "all": map[string]string{"all": ""}, "alll": map[string]string{}, "c": map[string]string{"components": "", "coreos": ""}, "co": map[string]string{"components": "", "coreos": ""}, "com": map[string]string{"components": ""}, } { have := filterPrefix(input, prefix) if !reflect.DeepEqual(want, have) { t.Errorf("%q: want %v, have %v", prefix, flattenKeys(want), flattenKeys(have)) } } } func flattenKeys(m map[string]string) []string { a := make([]string, 0, len(m)) for k := range m { a = append(a, k) } return a }