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  }