sigs.k8s.io/cluster-api-provider-azure@v1.14.3/util/cache/ttllru/ttllru_test.go (about)

     1  /*
     2  Copyright 2020 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 ttllru
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  	"time"
    23  
    24  	. "github.com/onsi/gomega"
    25  	"go.uber.org/mock/gomock"
    26  	gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock"
    27  	mockttllru "sigs.k8s.io/cluster-api-provider-azure/util/cache/ttllru/mocks"
    28  )
    29  
    30  const (
    31  	defaultCacheDuration = 30 * time.Second
    32  )
    33  
    34  func TestNew(t *testing.T) {
    35  	g := NewWithT(t)
    36  	subject, err := New(128, defaultCacheDuration)
    37  	g.Expect(err).NotTo(HaveOccurred())
    38  	g.Expect(subject).ShouldNot(BeNil())
    39  }
    40  
    41  func TestCache_Add(t *testing.T) {
    42  	g := NewWithT(t)
    43  	mockCtrl := gomock.NewController(t)
    44  	mockCache := mockttllru.NewMockCacher(mockCtrl)
    45  	defer mockCtrl.Finish()
    46  	subject, err := newCache(defaultCacheDuration, mockCache)
    47  	g.Expect(err).NotTo(HaveOccurred())
    48  
    49  	key, value := "foo", "bar"
    50  	mockCache.EXPECT().Add(gomock.Eq(key), gomockinternal.CustomMatcher(
    51  		func(val interface{}, state map[string]interface{}) bool {
    52  			ttl, ok := val.(*timeToLiveItem)
    53  			if !ok {
    54  				state["error"] = "value was not a time to live item"
    55  				return false
    56  			}
    57  
    58  			if ttl.Value != value || time.Since(ttl.LastTouch) >= defaultCacheDuration {
    59  				state["error"] = fmt.Sprintf("failed matching %+v", ttl)
    60  				return false
    61  			}
    62  
    63  			return true
    64  		},
    65  		func(state map[string]interface{}) string {
    66  			return state["error"].(string)
    67  		},
    68  	))
    69  	subject.Add(key, value)
    70  }
    71  
    72  func TestCache_Get(t *testing.T) {
    73  	const (
    74  		key   = "key"
    75  		value = "value"
    76  	)
    77  
    78  	cases := []struct {
    79  		Name     string
    80  		TestCase func(g *GomegaWithT, subject PeekingCacher, mock *mockttllru.MockCacher)
    81  	}{
    82  		{
    83  			Name: "NoItemsInCache",
    84  			TestCase: func(g *GomegaWithT, subject PeekingCacher, mock *mockttllru.MockCacher) {
    85  				key := "not_there"
    86  				mock.EXPECT().Get(key).Return(nil, false)
    87  				val, ok := subject.Get(key)
    88  				g.Expect(ok).To(BeFalse())
    89  				g.Expect(val).To(BeNil())
    90  			},
    91  		},
    92  		{
    93  			Name: "ExistingItemNotExpired",
    94  			TestCase: func(g *GomegaWithT, subject PeekingCacher, mock *mockttllru.MockCacher) {
    95  				mock.EXPECT().Get(key).Return(&timeToLiveItem{
    96  					LastTouch: time.Now(),
    97  					Value:     value,
    98  				}, true)
    99  				val, ok := subject.Get(key)
   100  				g.Expect(ok).To(BeTrue())
   101  				g.Expect(val).To(Equal(value))
   102  			},
   103  		},
   104  		{
   105  			Name: "ExistingItemExpired",
   106  			TestCase: func(g *GomegaWithT, subject PeekingCacher, mock *mockttllru.MockCacher) {
   107  				mock.EXPECT().Get(key).Return(&timeToLiveItem{
   108  					LastTouch: time.Now().Add(-(10*time.Second + defaultCacheDuration)),
   109  					Value:     value,
   110  				}, true)
   111  				mock.EXPECT().Remove(key).Return(false)
   112  				val, ok := subject.Get(key)
   113  				g.Expect(ok).To(BeFalse())
   114  				g.Expect(val).To(BeNil())
   115  			},
   116  		},
   117  		{
   118  			Name: "ExistingItemGetAdvancesLastTouch",
   119  			TestCase: func(g *GomegaWithT, subject PeekingCacher, mock *mockttllru.MockCacher) {
   120  				lastTouch := time.Now().Add(defaultCacheDuration - 10*time.Second)
   121  				item := &timeToLiveItem{
   122  					LastTouch: lastTouch,
   123  					Value:     value,
   124  				}
   125  
   126  				mock.EXPECT().Get(key).Return(item, true)
   127  				val, ok := subject.Get(key)
   128  				g.Expect(ok).To(BeTrue())
   129  				g.Expect(val).To(Equal(value))
   130  				g.Expect(lastTouch.After(item.LastTouch)).To(BeTrue())
   131  			},
   132  		},
   133  		{
   134  			Name: "ExistingItemIsNotTTLItem",
   135  			TestCase: func(g *GomegaWithT, subject PeekingCacher, mock *mockttllru.MockCacher) {
   136  				item := &struct {
   137  					Value string
   138  				}{
   139  					Value: value,
   140  				}
   141  
   142  				mock.EXPECT().Get(key).Return(item, true)
   143  				val, ok := subject.Get(key)
   144  				g.Expect(ok).To(BeFalse())
   145  				g.Expect(val).To(BeNil())
   146  			},
   147  		},
   148  	}
   149  
   150  	for _, c := range cases {
   151  		c := c
   152  		t.Run(c.Name, func(t *testing.T) {
   153  			g := NewWithT(t)
   154  			mockCtrl := gomock.NewController(t)
   155  			mockCache := mockttllru.NewMockCacher(mockCtrl)
   156  			defer mockCtrl.Finish()
   157  			subject, err := newCache(defaultCacheDuration, mockCache)
   158  			g.Expect(err).NotTo(HaveOccurred())
   159  			c.TestCase(g, subject, mockCache)
   160  		})
   161  	}
   162  }