diff --git a/pkg/ingress/kube/secret/controller_test.go b/pkg/ingress/kube/secret/controller_test.go new file mode 100644 index 000000000..7651842e0 --- /dev/null +++ b/pkg/ingress/kube/secret/controller_test.go @@ -0,0 +1,160 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package secret + +import ( + "context" + "reflect" + "sync" + "testing" + "time" + + "istio.io/istio/pilot/pkg/model" + kubeclient "istio.io/istio/pkg/kube" + "istio.io/istio/pkg/test/util/retry" + corev1 "k8s.io/api/core/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/cache" + + "github.com/alibaba/higress/pkg/ingress/kube/util" +) + +const ( + secretFakeName = "fake-secret" + secretFakeKey = "fake-key" + secretInitValue = "init-value" + secretUpdatedValue = "updated-value" +) + +var period = time.Second + +func TestController(t *testing.T) { + client := kubeclient.NewFakeClient() + ctrl := NewController(client, "fake-cluster") + + stop := make(chan struct{}) + t.Cleanup(func() { + close(stop) + }) + + client.RunAndWait(stop) + + // store secret + store := sync.Map{} + + // add event handler + ctrl.AddEventHandler(func(name util.ClusterNamespacedName) { + t.Logf("event recived, clusterId: %s, namespacedName: %s", name.ClusterId, name.NamespacedName.String()) + + retry.UntilSuccessOrFail(t, func() error { + secret, err := ctrl.Lister().Secrets(name.NamespacedName.Namespace).Get(name.NamespacedName.Name) + if err != nil && !kerrors.IsNotFound(err) { + t.Logf("get secret %s error: %v", name.NamespacedName.String(), err) + return err + } + store.Store(name.NamespacedName.String(), secret.Data) + return nil + }) + }) + + // start controller + go ctrl.Run(stop) + + // wait for cache sync + cache.WaitForCacheSync(stop, ctrl.Informer().HasSynced) + + // init secret + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretFakeName, + }, + Type: corev1.SecretTypeOpaque, + Data: map[string][]byte{ + secretFakeKey: []byte(secretInitValue), + }, + } + + testCases := []struct { + name string + do func() error + expect string + }{ + { + name: "create secret", + do: func() error { + _, err := client.CoreV1().Secrets(metav1.NamespaceDefault).Create(context.Background(), + secret, metav1.CreateOptions{}) + return err + }, + expect: secretInitValue, + }, + { + name: "update secret", + do: func() error { + var getSecret *corev1.Secret + // get or create secret + getSecret, err := ctrl.Lister().Secrets(metav1.NamespaceDefault).Get(secretFakeName) + if err != nil { + if !kerrors.IsNotFound(err) { + return err + } + getSecret, err = client.CoreV1().Secrets(metav1.NamespaceDefault).Create(context.Background(), + secret, metav1.CreateOptions{}) + if err != nil { + return err + } + } + // update secret + getSecret.Data[secretFakeKey] = []byte(secretUpdatedValue) + _, err = client.CoreV1().Secrets(metav1.NamespaceDefault).Update(context.Background(), + getSecret, metav1.UpdateOptions{}) + return err + }, + expect: secretUpdatedValue, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + if err := testCase.do(); err != nil { + t.Fatalf("do %s error: %v", testCase.name, err) + } + + // controller Run() with setting period time to 1s. + time.Sleep(period) + + secretFullName := model.NamespacedName{ + Namespace: metav1.NamespaceDefault, + Name: secretFakeName, + }.String() + + valAny, ok := store.Load(secretFullName) + if !ok { + t.Fatalf("secret %s not found", secretFullName) + } + + val, ok := valAny.(map[string][]byte) + if !ok { + t.Fatalf("assert secret %s data type error", secretFullName) + } + + if !reflect.DeepEqual(val[secretFakeKey], []byte(testCase.expect)) { + t.Fatalf("secret %s data error, expect: %s, got: %s", + secretFullName, testCase.expect, string(val[secretFakeKey])) + } + }) + } +}