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