github.com/mjibson/goon@v1.1.0/cache_test.go (about) 1 /* 2 * Copyright (c) 2012 The Goon Authors 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 package goon 18 19 import ( 20 "bytes" 21 "reflect" 22 "testing" 23 "unsafe" 24 ) 25 26 func TestCacheBasics(t *testing.T) { 27 items := []*cacheItem{} 28 items = append(items, &cacheItem{key: "foo", value: []byte{1, 2, 3}}) 29 items = append(items, &cacheItem{key: "bar", value: []byte{4, 5, 6}}) 30 31 keys := make([]string, 0, len(items)) 32 for _, item := range items { 33 keys = append(keys, item.key) 34 } 35 36 c := newCache(defaultCacheLimit) 37 38 for i := range items { 39 if v := c.Get(items[i].key); v != nil { 40 t.Fatalf("Expected nil for items[%d] but got %v", i, v) 41 } 42 43 c.Set(items[i]) 44 45 if v := c.Get(items[i].key); !bytes.Equal(v, items[i].value) { 46 t.Fatalf("Invalid bytes for items[%d]! %x vs %x", i, v, items[i].value) 47 } 48 49 c.Delete(items[i].key) 50 51 if v := c.Get(items[i].key); v != nil { 52 t.Fatalf("Expected nil for items[%d] but got %v", i, v) 53 } 54 55 if c.size != 0 { 56 t.Fatalf("Expected size to be zero, but got %v", c.size) 57 } 58 } 59 60 if vs := c.GetMulti(keys); !reflect.DeepEqual(vs, [][]byte{nil, nil}) { 61 t.Fatalf("Expected nils but got %+v", vs) 62 } 63 64 c.SetMulti(items) 65 66 if vs := c.GetMulti(keys); !reflect.DeepEqual(vs, [][]byte{items[0].value, items[1].value}) { 67 t.Fatalf("Invalid bytes for items! %+v", vs) 68 } 69 70 c.DeleteMulti(keys) 71 72 if vs := c.GetMulti(keys); !reflect.DeepEqual(vs, [][]byte{nil, nil}) { 73 t.Fatalf("Expected nils but got %+v", vs) 74 } 75 76 if c.size != 0 { 77 t.Fatalf("Expected size to be zero, but got %v", c.size) 78 } 79 80 c.Set(items[0]) 81 c.Flush() 82 if v := c.Get(items[0].key); v != nil { 83 t.Fatalf("Expected nil after flush but got %v", v) 84 } 85 86 c.Set(items[0]) 87 c.Set(&cacheItem{key: items[0].key, value: []byte{7, 7, 7}}) 88 if v := c.Get(items[0].key); !bytes.Equal(v, []byte{7, 7, 7}) { 89 t.Fatalf("Invalid bytes for value change! Got %x", v) 90 } 91 } 92 93 func TestCacheKeyLeak(t *testing.T) { 94 ak, bk := string([]byte{'f', 'o', 'o'}), string([]byte{'f', 'o', 'o'}) 95 av, bv := []byte{1, 2, 3}, []byte{4, 5, 6} 96 97 c := newCache(defaultCacheLimit) 98 99 // Set the original value 100 c.Set(&cacheItem{key: ak, value: av}) 101 if v := c.Get(ak); !bytes.Equal(v, av) { 102 t.Fatalf("Invalid bytes! %v", v) 103 } 104 105 // Rewrite it with a different value, and also a different key but same key contents 106 c.Set(&cacheItem{key: bk, value: bv}) 107 if v := c.Get(bk); !bytes.Equal(v, bv) { 108 t.Fatalf("Invalid bytes! %v", v) 109 } 110 111 // Modify the new key contents without changing the pointer 112 *(*byte)(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&bk)))) = 'g' 113 if bk != "goo" { 114 t.Fatalf("Expected key to be 'goo' but it's %v", bk) 115 } 116 117 // Make sure that we can no longer retrieve the value with the new key, 118 // as that will only be possible via pointer equality, which means that 119 // the cache is still holding on to the new key, which doubles key storage 120 if v := c.Get(bk); v != nil { 121 t.Fatalf("Cache is leaking memory by keeping around the new key pointer! %v", v) 122 } 123 // Also make sure that we can retrieve the correct new value 124 // by using an unrelated key pointer that just matches the key contents 125 if v := c.Get("foo"); !bytes.Equal(v, bv) { 126 t.Fatalf("Invalid bytes! %v", v) 127 } 128 129 // Inspect the internals of the cache too, which contains only a single entry with ak as key 130 keyAddr := *(*uintptr)(unsafe.Pointer(&ak)) 131 for key, elem := range c.elements { 132 if ka := *(*uintptr)(unsafe.Pointer(&key)); ka != keyAddr { 133 t.Fatalf("map key has wrong pointer! %x vs %x", ka, keyAddr) 134 } 135 if ka := *(*uintptr)(unsafe.Pointer(&(elem.Value.(*cacheItem)).key)); ka != keyAddr { 136 t.Fatalf("element key has wrong pointer! %x vs %x", ka, keyAddr) 137 } 138 } 139 } 140 141 func TestCacheLimit(t *testing.T) { 142 c := newCache(defaultCacheLimit) 143 144 items := []*cacheItem{} 145 items = append(items, &cacheItem{key: "foo", value: []byte{1, 2, 3}}) 146 items = append(items, &cacheItem{key: "bar", value: []byte{4, 5, 6}}) 147 148 keys := make([]string, 0, len(items)) 149 for _, item := range items { 150 keys = append(keys, item.key) 151 } 152 153 if vs := c.GetMulti(keys); !reflect.DeepEqual(vs, [][]byte{nil, nil}) { 154 t.Fatalf("Expected nils but got %+v", vs) 155 } 156 157 c.SetMulti(items) 158 159 if vs := c.GetMulti(keys); !reflect.DeepEqual(vs, [][]byte{items[0].value, items[1].value}) { 160 t.Fatalf("Invalid bytes for items! %+v", vs) 161 } 162 163 c.setLimit(0) 164 165 if vs := c.GetMulti(keys); !reflect.DeepEqual(vs, [][]byte{nil, nil}) { 166 t.Fatalf("Expected nils but got %+v", vs) 167 } 168 169 if c.size != 0 { 170 t.Fatalf("Expected size to be zero, but got %v", c.size) 171 } 172 173 c.setLimit(cachedValueOverhead + len(items[1].key) + cap(items[1].value)) 174 175 c.SetMulti(items) 176 177 if vs := c.GetMulti(keys); !reflect.DeepEqual(vs, [][]byte{nil, items[1].value}) { 178 t.Fatalf("Invalid bytes for items! %+v", vs) 179 } 180 }