codeberg.org/gruf/go-cache/v3@v3.5.7/simple/cache_test.go (about) 1 package simple_test 2 3 import ( 4 "net/url" 5 "reflect" 6 "testing" 7 "time" 8 "unsafe" 9 10 "codeberg.org/gruf/go-cache/v3/ttl" 11 "github.com/google/go-cmp/cmp" 12 ) 13 14 var testEntries = map[string]interface{}{ 15 "key1": "value1", 16 "key2": 2, 17 "a": 'a', 18 "b": '0', 19 "c": []string{"a", "b", "c"}, 20 "map": map[string]string{"a": "a"}, 21 "iface": interface{}(nil), 22 "weird": unsafe.Pointer(&ttl.Cache[string, string]{}), 23 "float": 2.4, 24 "url": url.URL{}, 25 } 26 27 func TestCache(t *testing.T) { 28 // Prepare cache 29 c := ttl.Cache[string, any]{} 30 c.Init( 31 len(testEntries), 32 len(testEntries)+1, 33 time.Second*5, 34 ) 35 36 // Ensure we can start and stop it 37 if !c.Start(time.Second * 10) { 38 t.Fatal("failed to start cache eviction routine") 39 } 40 41 done := make(chan struct{}) 42 go func() { 43 for { 44 // Return if done 45 select { 46 case <-done: 47 return 48 default: 49 } 50 51 // Continually loop checking keys 52 for key := range testEntries { 53 c.Has(key) 54 } 55 } 56 }() 57 58 // Track callbacks set 59 callbacks := map[string]interface{}{} 60 c.SetInvalidateCallback(func(key string, value interface{}) { 61 callbacks[key] = value 62 }) 63 64 // Add all entries to cache 65 for key, val := range testEntries { 66 t.Logf("Cache.Add(%s, %v)", key, val) 67 if !c.Add(key, val) { 68 t.Fatalf("failed adding key to cache: %s", key) 69 } 70 } 71 72 // Ensure all entries are expected 73 for key, val := range testEntries { 74 check, ok := c.Get(key) 75 t.Logf("Cache.Get() => %s, %v", key, val) 76 if !ok { 77 t.Fatalf("key unexpectedly not found in cache: %s", key) 78 } else if !cmp.Equal(val, check) { 79 t.Fatalf("value not as expected for key in cache: %s", key) 80 } 81 } 82 83 // Update entries via CAS to ensure callback 84 for key, val := range testEntries { 85 t.Logf("Cache.CAS(%s, %v, nil)", key, val) 86 if !c.CAS(key, val, nil, reflect.DeepEqual) && val != nil { 87 t.Fatalf("CAS failed for: %s", key) 88 } else if _, ok := callbacks[key]; !ok { 89 t.Fatalf("invalidate callback not called for: %s", key) 90 } 91 } 92 93 // Check values were updated 94 for key := range testEntries { 95 check, ok := c.Get(key) 96 t.Logf("Cache.Get() => %s, %v", key, check) 97 if !ok { 98 t.Fatalf("key unexpectedly not found in cache: %s", key) 99 } else if check != nil { 100 t.Fatalf("value not as expected after update for key in cache: %s", key) 101 } 102 } 103 104 // Clear callbacks, force invalidate and recheck 105 callbacks = map[string]interface{}{} 106 for key := range testEntries { 107 t.Logf("Cache.Invalidate(%s)", key) 108 c.Invalidate(key) 109 if _, ok := callbacks[key]; !ok { 110 t.Fatalf("invalidate callback unexpectedly not called for: %s", key) 111 } 112 } 113 114 // Checking cache is off expected size 115 t.Logf("Checking cache is of expected size (0)") 116 if sz := c.Len(); sz != 0 { 117 t.Fatalf("unexpected cache size: %d", sz) 118 } 119 }