github.com/oam-dev/kubevela@v1.9.11/pkg/controller/core.oam.dev/v1beta1/application/suite_test.go (about) 1 /* 2 Copyright 2021 The KubeVela 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 application 18 19 import ( 20 "context" 21 "fmt" 22 "math/rand" 23 "os" 24 "path/filepath" 25 "strconv" 26 "testing" 27 "time" 28 29 "github.com/crossplane/crossplane-runtime/pkg/event" 30 terraformv1beta2 "github.com/oam-dev/terraform-controller/api/v1beta2" 31 . "github.com/onsi/ginkgo/v2" 32 . "github.com/onsi/gomega" 33 "github.com/pkg/errors" 34 corev1 "k8s.io/api/core/v1" 35 crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 36 "k8s.io/apimachinery/pkg/api/meta" 37 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 38 "k8s.io/apimachinery/pkg/runtime" 39 "k8s.io/client-go/kubernetes/scheme" 40 "k8s.io/client-go/rest" 41 "k8s.io/utils/pointer" 42 ctrl "sigs.k8s.io/controller-runtime" 43 "sigs.k8s.io/controller-runtime/pkg/client" 44 "sigs.k8s.io/controller-runtime/pkg/envtest" 45 logf "sigs.k8s.io/controller-runtime/pkg/log" 46 "sigs.k8s.io/controller-runtime/pkg/log/zap" 47 48 "github.com/kubevela/workflow/pkg/cue/packages" 49 50 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 51 "github.com/oam-dev/kubevela/pkg/appfile" 52 "github.com/oam-dev/kubevela/pkg/multicluster" 53 // +kubebuilder:scaffold:imports 54 ) 55 56 // These tests use Ginkgo (BDD-style Go testing framework). Refer to 57 // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 58 var cfg *rest.Config 59 var recorder = NewFakeRecorder(10000) 60 var k8sClient client.Client 61 var testEnv *envtest.Environment 62 var testScheme = runtime.NewScheme() 63 var reconciler *Reconciler 64 var appParser *appfile.Parser 65 var controllerDone context.CancelFunc 66 var mgr ctrl.Manager 67 var appRevisionLimit = 5 68 69 func TestAPIs(t *testing.T) { 70 RegisterFailHandler(Fail) 71 72 RunSpecs(t, "Controller Suite") 73 } 74 75 var _ = BeforeSuite(func() { 76 logf.SetLogger(zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter))) 77 rand.Seed(time.Now().UnixNano()) 78 By("bootstrapping test environment") 79 var yamlPath string 80 if _, set := os.LookupEnv("COMPATIBILITY_TEST"); set { 81 yamlPath = "../../../../../test/compatibility-test/testdata" 82 } else { 83 yamlPath = filepath.Join("../../../../..", "charts", "vela-core", "crds") 84 } 85 logf.Log.Info("start application suit test", "yaml_path", yamlPath) 86 testEnv = &envtest.Environment{ 87 ControlPlaneStartTimeout: time.Minute, 88 ControlPlaneStopTimeout: time.Minute, 89 UseExistingCluster: pointer.Bool(false), 90 CRDDirectoryPaths: []string{yamlPath, "./testdata/crds/terraform.core.oam.dev_configurations.yaml"}, 91 } 92 93 var err error 94 cfg, err = testEnv.Start() 95 Expect(err).ToNot(HaveOccurred()) 96 Expect(cfg).ToNot(BeNil()) 97 98 err = v1beta1.SchemeBuilder.AddToScheme(testScheme) 99 Expect(err).NotTo(HaveOccurred()) 100 101 err = scheme.AddToScheme(testScheme) 102 Expect(err).NotTo(HaveOccurred()) 103 104 terraformv1beta2.AddToScheme(testScheme) 105 106 crdv1.AddToScheme(testScheme) 107 108 // +kubebuilder:scaffold:scheme 109 k8sClient, err = client.New(cfg, client.Options{Scheme: testScheme}) 110 Expect(err).ToNot(HaveOccurred()) 111 Expect(k8sClient).ToNot(BeNil()) 112 pd, err := packages.NewPackageDiscover(cfg) 113 Expect(err).To(BeNil()) 114 115 appParser = appfile.NewApplicationParser(k8sClient, pd) 116 117 reconciler = &Reconciler{ 118 Client: k8sClient, 119 Scheme: testScheme, 120 pd: pd, 121 Recorder: event.NewAPIRecorder(recorder), 122 } 123 124 reconciler.appRevisionLimit = appRevisionLimit 125 // setup the controller manager since we need the component handler to run in the background 126 mgr, err = ctrl.NewManager(cfg, ctrl.Options{ 127 Scheme: testScheme, 128 MetricsBindAddress: "0", 129 LeaderElection: false, 130 LeaderElectionNamespace: "default", 131 LeaderElectionID: "test", 132 }) 133 Expect(err).NotTo(HaveOccurred()) 134 definitionNs := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}} 135 Expect(k8sClient.Create(context.Background(), definitionNs.DeepCopy())).Should(BeNil()) 136 137 var ctx context.Context 138 ctx, controllerDone = context.WithCancel(context.Background()) 139 // start the controller in the background so that new componentRevisions are created 140 go func() { 141 err = mgr.Start(ctx) 142 Expect(err).NotTo(HaveOccurred()) 143 }() 144 multicluster.InitClusterInfo(cfg) 145 }) 146 147 var _ = AfterSuite(func() { 148 By("tearing down the test environment") 149 if controllerDone != nil { 150 controllerDone() 151 } 152 err := testEnv.Stop() 153 Expect(err).ToNot(HaveOccurred()) 154 }) 155 156 type FakeRecorder struct { 157 Events chan string 158 Message map[string][]*Events 159 } 160 161 type Events struct { 162 Name string 163 Namespace string 164 EventType string 165 Reason string 166 Message string 167 } 168 169 func (f *FakeRecorder) Event(object runtime.Object, eventtype, reason, message string) { 170 if f.Events != nil { 171 objectMeta, err := meta.Accessor(object) 172 if err != nil { 173 return 174 } 175 176 event := &Events{ 177 Name: objectMeta.GetName(), 178 Namespace: objectMeta.GetNamespace(), 179 EventType: eventtype, 180 Reason: reason, 181 Message: message, 182 } 183 184 records, ok := f.Message[objectMeta.GetName()] 185 if !ok { 186 f.Message[objectMeta.GetName()] = []*Events{event} 187 return 188 } 189 190 records = append(records, event) 191 f.Message[objectMeta.GetName()] = records 192 193 } 194 } 195 196 func (f *FakeRecorder) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) { 197 f.Event(object, eventtype, reason, messageFmt) 198 } 199 200 func (f *FakeRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) { 201 f.Eventf(object, eventtype, reason, messageFmt, args...) 202 } 203 204 func (f *FakeRecorder) GetEventsWithName(name string) ([]*Events, error) { 205 records, ok := f.Message[name] 206 if !ok { 207 return nil, errors.New("not found events") 208 } 209 210 return records, nil 211 } 212 213 // NewFakeRecorder creates new fake event recorder with event channel with 214 // buffer of given size. 215 func NewFakeRecorder(bufferSize int) *FakeRecorder { 216 return &FakeRecorder{ 217 Events: make(chan string, bufferSize), 218 Message: make(map[string][]*Events), 219 } 220 } 221 222 // randomNamespaceName generates a random name based on the basic name. 223 // Running each ginkgo case in a new namespace with a random name can avoid 224 // waiting a long time to GC namespace. 225 func randomNamespaceName(basic string) string { 226 return fmt.Sprintf("%s-%s", basic, strconv.FormatInt(rand.Int63(), 16)) 227 }