istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/kube/watcher/configmapwatcher/configmapwatcher_test.go (about) 1 // Copyright Istio Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package configmapwatcher 16 17 import ( 18 "context" 19 "fmt" 20 "sync" 21 "testing" 22 "time" 23 24 . "github.com/onsi/gomega" 25 v1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 28 "istio.io/istio/pkg/kube" 29 ) 30 31 const ( 32 configMapNamespace string = "istio-system" 33 configMapName string = "watched" 34 ) 35 36 func makeConfigMap(name, resourceVersion string) *v1.ConfigMap { 37 return &v1.ConfigMap{ 38 ObjectMeta: metav1.ObjectMeta{ 39 Namespace: configMapNamespace, 40 Name: name, 41 ResourceVersion: resourceVersion, 42 }, 43 Data: map[string]string{ 44 "mesh": "trustDomain: cluster.local", 45 }, 46 } 47 } 48 49 var ( 50 mu sync.Mutex 51 called bool 52 newCM *v1.ConfigMap 53 ) 54 55 func callback(cm *v1.ConfigMap) { 56 mu.Lock() 57 defer mu.Unlock() 58 called = true 59 newCM = cm 60 } 61 62 func getCalled() bool { 63 mu.Lock() 64 defer mu.Unlock() 65 return called 66 } 67 68 func getCM() *v1.ConfigMap { 69 mu.Lock() 70 defer mu.Unlock() 71 return newCM 72 } 73 74 func resetCalled() { 75 called = false 76 newCM = nil 77 } 78 79 func Test_ConfigMapWatcher(t *testing.T) { 80 client := kube.NewFakeClient() 81 cm := makeConfigMap(configMapName, "1") 82 cm1 := makeConfigMap(configMapName, "2") 83 cm2 := makeConfigMap("not-watched", "1") 84 steps := []struct { 85 added *v1.ConfigMap 86 updated *v1.ConfigMap 87 deleted *v1.ConfigMap 88 expectCalled bool 89 expectCM *v1.ConfigMap 90 }{ 91 {added: cm2}, 92 {added: cm, expectCalled: true, expectCM: cm}, 93 {updated: cm}, 94 {updated: cm1, expectCalled: true, expectCM: cm1}, 95 {deleted: cm1, expectCalled: true}, 96 {deleted: cm2}, 97 } 98 99 stop := make(chan struct{}) 100 c := NewController(client, configMapNamespace, configMapName, callback) 101 go c.Run(stop) 102 kube.WaitForCacheSync("test", stop, c.HasSynced) 103 104 cms := client.Kube().CoreV1().ConfigMaps(configMapNamespace) 105 for i, step := range steps { 106 resetCalled() 107 108 t.Run(fmt.Sprintf("[%v]", i), func(t *testing.T) { 109 g := NewWithT(t) 110 111 switch { 112 case step.added != nil: 113 _, err := cms.Create(context.TODO(), step.added, metav1.CreateOptions{}) 114 g.Expect(err).Should(BeNil()) 115 case step.updated != nil: 116 _, err := cms.Update(context.TODO(), step.updated, metav1.UpdateOptions{}) 117 g.Expect(err).Should(BeNil()) 118 case step.deleted != nil: 119 g.Expect(cms.Delete(context.TODO(), step.deleted.Name, metav1.DeleteOptions{})). 120 Should(Succeed()) 121 } 122 123 if step.expectCalled { 124 g.Eventually(getCalled, time.Second).Should(Equal(true)) 125 g.Eventually(getCM, time.Second).Should(Equal(newCM)) 126 } else { 127 g.Consistently(getCalled).Should(Equal(false)) 128 } 129 }) 130 } 131 }