istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/kube/inject/watcher_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 inject
    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  	"istio.io/istio/pkg/test"
    30  )
    31  
    32  const (
    33  	namespace string = "istio-system"
    34  	cmName    string = "istio-sidecar-injector"
    35  	configKey string = "config"
    36  	valuesKey string = "values"
    37  )
    38  
    39  func makeConfigMap(resourceVersion string, data map[string]string) *v1.ConfigMap {
    40  	return &v1.ConfigMap{
    41  		ObjectMeta: metav1.ObjectMeta{
    42  			Namespace:       namespace,
    43  			Name:            cmName,
    44  			ResourceVersion: resourceVersion,
    45  		},
    46  		Data: data,
    47  	}
    48  }
    49  
    50  func TestNewConfigMapWatcher(t *testing.T) {
    51  	configYaml := "policy: enabled"
    52  	c, err := UnmarshalConfig([]byte(configYaml))
    53  	if err != nil {
    54  		t.Fatal(err)
    55  	}
    56  	valuesConfig := "sidecarInjectorWebhook: {}"
    57  
    58  	cm := makeConfigMap("1", map[string]string{
    59  		configKey: configYaml,
    60  		valuesKey: valuesConfig,
    61  	})
    62  	badCM := makeConfigMap("2", map[string]string{
    63  		configKey: configYaml,
    64  	})
    65  	badCM2 := makeConfigMap("3", map[string]string{
    66  		valuesKey: valuesConfig,
    67  	})
    68  	badCM3 := makeConfigMap("4", map[string]string{
    69  		configKey: "bad yaml",
    70  		valuesKey: valuesConfig,
    71  	})
    72  
    73  	var mu sync.Mutex
    74  	var newConfig *Config
    75  	var newValues string
    76  
    77  	client := kube.NewFakeClient()
    78  	w := NewConfigMapWatcher(client, namespace, cmName, configKey, valuesKey)
    79  	w.SetHandler(func(config *Config, values string) error {
    80  		mu.Lock()
    81  		defer mu.Unlock()
    82  		newConfig = config
    83  		newValues = values
    84  		return nil
    85  	})
    86  	stop := test.NewStop(t)
    87  	go w.Run(stop)
    88  	controller := w.(*configMapWatcher).c
    89  	client.RunAndWait(stop)
    90  	kube.WaitForCacheSync("test", stop, controller.HasSynced)
    91  
    92  	cms := client.Kube().CoreV1().ConfigMaps(namespace)
    93  	steps := []struct {
    94  		added   *v1.ConfigMap
    95  		updated *v1.ConfigMap
    96  		deleted *v1.ConfigMap
    97  	}{
    98  		{added: cm},
    99  
   100  		// Handle misconfiguration errors.
   101  		{updated: badCM},
   102  		{updated: cm},
   103  		{updated: badCM2},
   104  		{updated: badCM},
   105  		{updated: cm},
   106  		{updated: badCM3},
   107  		{updated: cm},
   108  
   109  		// Handle deletion.
   110  		{deleted: cm},
   111  		{added: cm},
   112  	}
   113  
   114  	for i, step := range steps {
   115  		t.Run(fmt.Sprintf("[%v]", i), func(t *testing.T) {
   116  			g := NewWithT(t)
   117  
   118  			switch {
   119  			case step.added != nil:
   120  				_, err := cms.Create(context.TODO(), step.added, metav1.CreateOptions{})
   121  				g.Expect(err).Should(BeNil())
   122  			case step.updated != nil:
   123  				_, err := cms.Update(context.TODO(), step.updated, metav1.UpdateOptions{})
   124  				g.Expect(err).Should(BeNil())
   125  			case step.deleted != nil:
   126  				g.Expect(cms.Delete(context.TODO(), step.deleted.Name, metav1.DeleteOptions{})).
   127  					Should(Succeed())
   128  			}
   129  
   130  			g.Eventually(func() *Config {
   131  				mu.Lock()
   132  				defer mu.Unlock()
   133  				return newConfig
   134  			}, time.Second).Should(Equal(&c))
   135  			g.Eventually(func() string {
   136  				mu.Lock()
   137  				defer mu.Unlock()
   138  				return newValues
   139  			}, time.Second).Should(Equal(valuesConfig))
   140  		})
   141  	}
   142  }