knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/configmap/informer/synced_callback_test.go (about) 1 /* 2 Copyright 2021 The Knative 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 informer 18 19 import ( 20 "testing" 21 "time" 22 ) 23 24 func TestNamedWaitGroup(t *testing.T) { 25 nwg := newNamedWaitGroup() 26 27 // nothing has been added so wait returns immediately 28 initiallyDone := make(chan struct{}) 29 go func() { 30 defer close(initiallyDone) 31 nwg.Wait() 32 }() 33 select { 34 case <-time.After(1 * time.Second): 35 t.Fatalf("Wait should have returned immediately but still hadn't after timeout elapsed") 36 case <-initiallyDone: 37 // the Wait returned as expected since nothing was tracked 38 } 39 40 // Add some keys to track 41 nwg.Add("foo") 42 nwg.Add("bar") 43 // Adding keys multiple times shouldn't increment the counter again 44 nwg.Add("bar") 45 46 // Now that we've added keys, when we Wait, it should block 47 done := make(chan struct{}) 48 go func() { 49 defer close(done) 50 nwg.Wait() 51 }() 52 53 // Indicate that this key is done 54 nwg.Done("foo") 55 // Indicating done on a key that doesn't exist should do nothing 56 nwg.Done("doesnt exist") 57 58 // Only one of the tracked keys has completed, so the channel should not yet have closed 59 select { 60 case <-done: 61 t.Fatalf("Wait returned before all keys were done") 62 default: 63 // as expected, the channel is still open (waiting for the final key to be done) 64 } 65 66 // Indicate the final key is done 67 nwg.Done("bar") 68 69 // Now that all keys are done, the Wait should return 70 select { 71 case <-time.After(1 * time.Second): 72 t.Fatalf("Wait should have returned immediately but still hadn't after timeout elapsed") 73 case <-done: 74 // completed successfully 75 } 76 } 77 78 func TestSyncedCallback(t *testing.T) { 79 keys := []string{"foo", "bar"} 80 objs := []interface{}{"fooobj", "barobj"} 81 var seen []interface{} 82 callback := func(obj interface{}) { 83 seen = append(seen, obj) 84 } 85 sc := newSyncedCallback(keys, callback) 86 87 // Wait for the callback to be called for all of the keys 88 stopCh := make(chan struct{}) 89 done := make(chan struct{}) 90 go func() { 91 defer close(done) 92 sc.WaitForAllKeys(stopCh) 93 }() 94 95 // Call the callback for one of the keys 96 sc.Call(objs[0], "foo") 97 98 // Only one of the tracked keys has been synced so we should still be waiting 99 select { 100 case <-done: 101 t.Fatalf("Wait returned before all keys were done") 102 default: 103 // as expected, the channel is still open (waiting for the final key to be done) 104 } 105 106 // Call the callback for the other key 107 sc.Call(objs[1], "bar") 108 109 // Now that all keys are done, the Wait should return 110 select { 111 case <-time.After(1 * time.Second): 112 t.Fatalf("WaitForAllKeys should have returned but still hadn't after timeout elapsed") 113 case <-done: 114 // completed successfully 115 } 116 117 if len(seen) != 2 || seen[0] != objs[0] || seen[1] != objs[1] { 118 t.Errorf("callback wasn't called as expected, expected to see %v but saw %v", objs, seen) 119 } 120 } 121 122 func TestSyncedCallbackStops(t *testing.T) { 123 sc := newSyncedCallback([]string{"somekey"}, func(obj interface{}) {}) 124 125 // Wait for the callback to be called - which it won't be! 126 stopCh := make(chan struct{}) 127 done := make(chan struct{}) 128 go func() { 129 defer close(done) 130 sc.WaitForAllKeys(stopCh) 131 }() 132 133 // Nothing has been synced so we should still be waiting 134 select { 135 case <-done: 136 t.Fatalf("Wait returned before all keys were done") 137 default: 138 // as expected, the channel is still open 139 } 140 141 // signal to stop via the stop channel 142 close(stopCh) 143 144 // Even though the callback wasn't called, the Wait should return b/c of the stop channel 145 select { 146 case <-time.After(1 * time.Second): 147 t.Fatalf("WaitForAllKeys should have returned because of the stop channel but still hadn't after timeout elapsed") 148 case <-done: 149 // stopped successfully 150 } 151 }