github.com/cilium/cilium@v1.16.2/pkg/k8s/synced/resources_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package synced 5 6 import ( 7 "fmt" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/assert" 12 13 "github.com/cilium/cilium/pkg/lock" 14 ) 15 16 // waitForCacheTest is a table test case for testing WaitForCacheSyncWithTimeout. 17 // Each test case will similate waiting for sync of every key in resourceNamesToSyncDuration 18 // with their respective timeout duration. 19 type waitForCacheTest struct { 20 timeout time.Duration 21 // This maps resource names (ex. "core/v1::Pods") onto the duration the simulated 22 // cache sync will take to complete. 23 resourceNamesToSyncDuration map[string]time.Duration 24 // Maps resource names to a duration to wait after init upon which an "event" will 25 // be emitted. Used to test cases where events cause pushing out of timeout. 26 resourceNamesToEvent map[string]time.Duration 27 // Array which is passed to WaitForCacheSync... function. 28 // Only resources in this array should cause return of timeout error when doing test. 29 resourceNames []string 30 expectErr error 31 // Used to test edge cases where controller doesn't actually invoke BlockWaitGroupToSyncResources. 32 dontStartBlockWaitGroupToSyncResources bool 33 } 34 35 func TestWaitForCacheSyncWithTimeout(t *testing.T) { 36 unit := func(d int) time.Duration { return syncedPollPeriod * time.Duration(d) } 37 for msg, test := range map[string]waitForCacheTest{ 38 "Should complete due to event causing timeout to be extended past initial timeout": { 39 timeout: unit(5), 40 resourceNamesToSyncDuration: map[string]time.Duration{ 41 "foo": unit(7), 42 "bar": unit(7), 43 }, 44 resourceNamesToEvent: map[string]time.Duration{ 45 "foo": unit(4), 46 }, 47 resourceNames: []string{"foo"}, 48 }, 49 "Should timeout due to watched resource exceeding timeout": { 50 timeout: unit(1), 51 resourceNamesToSyncDuration: map[string]time.Duration{ 52 "foo": unit(3), 53 }, 54 resourceNamesToEvent: map[string]time.Duration{}, 55 resourceNames: []string{"foo"}, 56 expectErr: fmt.Errorf("timed out after 100ms, never received event for resource \"foo\""), 57 }, 58 "Any one timeout should cause error": { 59 timeout: unit(5), 60 resourceNamesToSyncDuration: map[string]time.Duration{ 61 "foo": unit(3), 62 "bar": unit(7), 63 }, 64 resourceNamesToEvent: map[string]time.Duration{ 65 "foo": unit(4), 66 }, 67 resourceNames: []string{"foo", "bar"}, 68 expectErr: fmt.Errorf("timed out after 500ms, never received event for resource \"bar\""), 69 }, 70 "Waiting for no resources should always sync": { 71 timeout: unit(5), 72 resourceNamesToSyncDuration: map[string]time.Duration{ 73 "foo": unit(10), 74 "bar": unit(10), 75 }, 76 }, 77 // One expectation of the BlockWaitGroupToSyncResources is that waits without starting 78 // the controller sync will complete without waiting. 79 "Not invoking BlockWaitGroupToSyncResources should cause wait to succeed immediately": { 80 timeout: unit(60), 81 resourceNamesToSyncDuration: map[string]time.Duration{ 82 "foo": unit(360), 83 "bar": unit(360), 84 }, 85 resourceNames: []string{"foo", "bar"}, 86 dontStartBlockWaitGroupToSyncResources: true, 87 }, 88 } { 89 func(test waitForCacheTest) { 90 t.Run(msg, func(t *testing.T) { 91 t.Parallel() 92 93 assert := assert.New(t) 94 r := &Resources{CacheStatus: make(CacheStatus)} 95 stop := make(chan struct{}) 96 swg := lock.NewStoppableWaitGroup() 97 start := time.Now() 98 // Create synced functions that will begin to return true after the resource timeout duration. 99 for resourceName, syncDurations := range test.resourceNamesToSyncDuration { 100 hasSyncedFn := func(d time.Duration) func() bool { 101 return func() bool { 102 return time.Now().After(start.Add(d)) 103 } 104 }(syncDurations) 105 if test.dontStartBlockWaitGroupToSyncResources { 106 continue 107 } 108 r.BlockWaitGroupToSyncResources( 109 stop, 110 swg, 111 hasSyncedFn, 112 resourceName, 113 ) 114 } 115 116 // Schedule resource events to happen after specified duration. 117 for resourceName, waitForEvent := range test.resourceNamesToEvent { 118 // schedule an event. 119 time.AfterFunc(waitForEvent, func() { 120 r.SetEventTimestamp(resourceName) 121 }) 122 } 123 124 err := r.WaitForCacheSyncWithTimeout(test.timeout, test.resourceNames...) 125 if test.expectErr == nil { 126 assert.NoError(err) 127 } else { 128 assert.EqualError(err, test.expectErr.Error()) 129 } 130 }) 131 }(test) 132 } 133 }