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  }