k8s.io/client-go@v0.22.2/tools/cache/expiration_cache_test.go (about) 1 /* 2 Copyright 2014 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 cache 18 19 import ( 20 "reflect" 21 "testing" 22 "time" 23 24 "k8s.io/apimachinery/pkg/util/clock" 25 "k8s.io/apimachinery/pkg/util/sets" 26 "k8s.io/apimachinery/pkg/util/wait" 27 ) 28 29 func TestTTLExpirationBasic(t *testing.T) { 30 testObj := testStoreObject{id: "foo", val: "bar"} 31 deleteChan := make(chan string, 1) 32 ttlStore := NewFakeExpirationStore( 33 testStoreKeyFunc, deleteChan, 34 &FakeExpirationPolicy{ 35 NeverExpire: sets.NewString(), 36 RetrieveKeyFunc: func(obj interface{}) (string, error) { 37 return obj.(*TimestampedEntry).Obj.(testStoreObject).id, nil 38 }, 39 }, 40 clock.RealClock{}, 41 ) 42 err := ttlStore.Add(testObj) 43 if err != nil { 44 t.Errorf("Unable to add obj %#v", testObj) 45 } 46 item, exists, err := ttlStore.Get(testObj) 47 if err != nil { 48 t.Errorf("Failed to get from store, %v", err) 49 } 50 if exists || item != nil { 51 t.Errorf("Got unexpected item %#v", item) 52 } 53 key, _ := testStoreKeyFunc(testObj) 54 select { 55 case delKey := <-deleteChan: 56 if delKey != key { 57 t.Errorf("Unexpected delete for key %s", key) 58 } 59 case <-time.After(wait.ForeverTestTimeout): 60 t.Errorf("Unexpected timeout waiting on delete") 61 } 62 close(deleteChan) 63 } 64 65 func TestReAddExpiredItem(t *testing.T) { 66 deleteChan := make(chan string, 1) 67 exp := &FakeExpirationPolicy{ 68 NeverExpire: sets.NewString(), 69 RetrieveKeyFunc: func(obj interface{}) (string, error) { 70 return obj.(*TimestampedEntry).Obj.(testStoreObject).id, nil 71 }, 72 } 73 ttlStore := NewFakeExpirationStore( 74 testStoreKeyFunc, deleteChan, exp, clock.RealClock{}) 75 testKey := "foo" 76 testObj := testStoreObject{id: testKey, val: "bar"} 77 err := ttlStore.Add(testObj) 78 if err != nil { 79 t.Errorf("Unable to add obj %#v", testObj) 80 } 81 82 // This get will expire the item. 83 item, exists, err := ttlStore.Get(testObj) 84 if err != nil { 85 t.Errorf("Failed to get from store, %v", err) 86 } 87 if exists || item != nil { 88 t.Errorf("Got unexpected item %#v", item) 89 } 90 91 key, _ := testStoreKeyFunc(testObj) 92 differentValue := "different_bar" 93 err = ttlStore.Add( 94 testStoreObject{id: testKey, val: differentValue}) 95 if err != nil { 96 t.Errorf("Failed to add second value") 97 } 98 99 select { 100 case delKey := <-deleteChan: 101 if delKey != key { 102 t.Errorf("Unexpected delete for key %s", key) 103 } 104 case <-time.After(wait.ForeverTestTimeout): 105 t.Errorf("Unexpected timeout waiting on delete") 106 } 107 exp.NeverExpire = sets.NewString(testKey) 108 item, exists, err = ttlStore.GetByKey(testKey) 109 if err != nil { 110 t.Errorf("Failed to get from store, %v", err) 111 } 112 if !exists || item == nil || item.(testStoreObject).val != differentValue { 113 t.Errorf("Got unexpected item %#v", item) 114 } 115 close(deleteChan) 116 } 117 118 func TestTTLList(t *testing.T) { 119 testObjs := []testStoreObject{ 120 {id: "foo", val: "bar"}, 121 {id: "foo1", val: "bar1"}, 122 {id: "foo2", val: "bar2"}, 123 } 124 expireKeys := sets.NewString(testObjs[0].id, testObjs[2].id) 125 deleteChan := make(chan string, len(testObjs)) 126 defer close(deleteChan) 127 128 ttlStore := NewFakeExpirationStore( 129 testStoreKeyFunc, deleteChan, 130 &FakeExpirationPolicy{ 131 NeverExpire: sets.NewString(testObjs[1].id), 132 RetrieveKeyFunc: func(obj interface{}) (string, error) { 133 return obj.(*TimestampedEntry).Obj.(testStoreObject).id, nil 134 }, 135 }, 136 clock.RealClock{}, 137 ) 138 for _, obj := range testObjs { 139 err := ttlStore.Add(obj) 140 if err != nil { 141 t.Errorf("Unable to add obj %#v", obj) 142 } 143 } 144 listObjs := ttlStore.List() 145 if len(listObjs) != 1 || !reflect.DeepEqual(listObjs[0], testObjs[1]) { 146 t.Errorf("List returned unexpected results %#v", listObjs) 147 } 148 149 // Make sure all our deletes come through in an acceptable rate (1/100ms) 150 for expireKeys.Len() != 0 { 151 select { 152 case delKey := <-deleteChan: 153 if !expireKeys.Has(delKey) { 154 t.Errorf("Unexpected delete for key %s", delKey) 155 } 156 expireKeys.Delete(delKey) 157 case <-time.After(wait.ForeverTestTimeout): 158 t.Errorf("Unexpected timeout waiting on delete") 159 return 160 } 161 } 162 } 163 164 func TestTTLPolicy(t *testing.T) { 165 fakeTime := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) 166 ttl := 30 * time.Second 167 exactlyOnTTL := fakeTime.Add(-ttl) 168 expiredTime := fakeTime.Add(-(ttl + 1)) 169 170 policy := TTLPolicy{ttl, clock.NewFakeClock(fakeTime)} 171 item := testStoreObject{id: "foo", val: "bar"} 172 itemkey, _ := testStoreKeyFunc(item) 173 fakeTimestampedEntry := &TimestampedEntry{Obj: item, Timestamp: exactlyOnTTL, key: itemkey} 174 if policy.IsExpired(fakeTimestampedEntry) { 175 t.Errorf("TTL cache should not expire entries exactly on ttl") 176 } 177 fakeTimestampedEntry.Timestamp = fakeTime 178 if policy.IsExpired(fakeTimestampedEntry) { 179 t.Errorf("TTL Cache should not expire entries before ttl") 180 } 181 fakeTimestampedEntry.Timestamp = expiredTime 182 if !policy.IsExpired(fakeTimestampedEntry) { 183 t.Errorf("TTL Cache should expire entries older than ttl") 184 } 185 for _, ttl = range []time.Duration{0, -1} { 186 policy.TTL = ttl 187 if policy.IsExpired(fakeTimestampedEntry) { 188 t.Errorf("TTL policy should only expire entries when initialized with a ttl > 0") 189 } 190 } 191 }