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  }