From 31f5f8477bf7a8ddf4aba61d251bfc41ac4828fb Mon Sep 17 00:00:00 2001 From: zackzhang Date: Mon, 1 Feb 2021 09:59:04 +0800 Subject: [PATCH] add application unit test files Signed-off-by: zackzhang --- .../application_controller_test.go | 183 ++++++++++++++++++ .../application/application_suit_test.go | 106 ++++++++++ 2 files changed, 289 insertions(+) create mode 100644 pkg/controller/application/application_suit_test.go diff --git a/pkg/controller/application/application_controller_test.go b/pkg/controller/application/application_controller_test.go index 4456c6928..723fc2e8c 100644 --- a/pkg/controller/application/application_controller_test.go +++ b/pkg/controller/application/application_controller_test.go @@ -15,3 +15,186 @@ limitations under the License. */ package application + +import ( + "context" + "fmt" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + v1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "kubesphere.io/kubesphere/pkg/controller/utils/servicemesh" + "sigs.k8s.io/application/api/v1beta1" + "time" +) + +var replicas = int32(2) +var _ = Describe("Application", func() { + + const timeout = time.Second * 30 + const interval = time.Second * 1 + + ctx := context.TODO() + + service := newService("productpage") + app := newAppliation(service) + deployments := []*v1.Deployment{newDeployments(service, "v1")} + + BeforeEach(func() { + + // Create application service and deployment + Expect(k8sClient.Create(ctx, app)).Should(Succeed()) + Expect(k8sClient.Create(ctx, service)).Should(Succeed()) + for i := range deployments { + deployment := deployments[i] + Expect(k8sClient.Create(ctx, deployment)).Should(Succeed()) + } + }) + + // Add Tests for OpenAPI validation (or additonal CRD features) specified in + // your API definition. + // Avoid adding tests for vanilla CRUD operations because they would + // test Kubernetes API server, which isn't the goal here. + Context("Application Controller", func() { + It("Should create successfully", func() { + + By("Reconcile Application successfully") + // application should have "kubesphere.io/last-updated" annotation + Eventually(func() bool { + app := &v1beta1.Application{} + _ = k8sClient.Get(ctx, types.NamespacedName{Name: service.Labels[servicemesh.ApplicationNameLabel], Namespace: metav1.NamespaceDefault}, app) + time, ok := app.Annotations["kubesphere.io/last-updated"] + return len(time) > 0 && ok + }, timeout, interval).Should(BeTrue()) + }) + }) +}) + +func newDeployments(service *corev1.Service, version string) *v1.Deployment { + lbs := service.Labels + lbs["version"] = version + + deployment := &v1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", service.Name, version), + Namespace: metav1.NamespaceDefault, + Labels: lbs, + Annotations: map[string]string{servicemesh.ServiceMeshEnabledAnnotation: "true"}, + }, + Spec: v1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: lbs, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: lbs, + Annotations: service.Annotations, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "c1", + Image: "nginx:latest", + Ports: []corev1.ContainerPort{ + { + Name: "http", + ContainerPort: 80, + Protocol: corev1.ProtocolTCP, + }, + { + Name: "https", + ContainerPort: 443, + Protocol: corev1.ProtocolTCP, + }, + { + Name: "mysql", + ContainerPort: 3306, + Protocol: corev1.ProtocolTCP, + }, + }, + }, + }, + }, + }, + }, + Status: v1.DeploymentStatus{ + AvailableReplicas: replicas, + ReadyReplicas: replicas, + Replicas: replicas, + }, + } + + return deployment +} + +func newService(name string) *corev1.Service { + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: metav1.NamespaceDefault, + Labels: map[string]string{ + "app.kubernetes.io/name": "bookinfo", + "app.kubernetes.io/version": "1", + "app": name, + }, + Annotations: map[string]string{ + "servicemesh.kubesphere.io/enabled": "true", + }, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Name: "http", + Port: 80, + Protocol: corev1.ProtocolTCP, + }, + { + Name: "https", + Port: 443, + Protocol: corev1.ProtocolTCP, + }, + { + Name: "mysql", + Port: 3306, + Protocol: corev1.ProtocolTCP, + }, + }, + Selector: map[string]string{ + "app.kubernetes.io/name": "bookinfo", + "app.kubernetes.io/version": "1", + "app": "foo", + }, + Type: corev1.ServiceTypeClusterIP, + }, + Status: corev1.ServiceStatus{}, + } + return svc +} + +func newAppliation(service *corev1.Service) *v1beta1.Application { + app := &v1beta1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: service.Labels[servicemesh.ApplicationNameLabel], + Namespace: metav1.NamespaceDefault, + Labels: service.Labels, + Annotations: map[string]string{servicemesh.ServiceMeshEnabledAnnotation: "true"}, + }, + Spec: v1beta1.ApplicationSpec{ + ComponentGroupKinds: []metav1.GroupKind{ + { + Group: "", + Kind: "Service", + }, + { + Group: "apps", + Kind: "Deployment", + }, + }, + AddOwnerRef: true, + }, + } + return app +} diff --git a/pkg/controller/application/application_suit_test.go b/pkg/controller/application/application_suit_test.go new file mode 100644 index 000000000..4885d1a4f --- /dev/null +++ b/pkg/controller/application/application_suit_test.go @@ -0,0 +1,106 @@ +/* +Copyright 2020 KubeSphere Authors + +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 application + +import ( + "github.com/onsi/gomega/gexec" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/klog" + "k8s.io/klog/klogr" + "kubesphere.io/kubesphere/pkg/apis" + "os" + "path/filepath" + appv1beta1 "sigs.k8s.io/application/api/v1beta1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "testing" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var k8sClient client.Client +var k8sManager ctrl.Manager +var testEnv *envtest.Environment + +func TestApplicationController(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecsWithDefaultAndCustomReporters(t, + "Application Controller Test Suite", + []Reporter{printer.NewlineReporter{}}) +} + +var _ = BeforeSuite(func(done Done) { + logf.SetLogger(klogr.New()) + + By("bootstrapping test environment") + t := true + if os.Getenv("TEST_USE_EXISTING_CLUSTER") == "true" { + testEnv = &envtest.Environment{ + UseExistingCluster: &t, + } + } else { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")}, + AttachControlPlaneOutput: false, + } + } + + sch := scheme.Scheme + err := appv1beta1.AddToScheme(sch) + Expect(err).NotTo(HaveOccurred()) + err = apis.AddToScheme(sch) + Expect(err).NotTo(HaveOccurred()) + + cfg, err := testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + + k8sManager, err = ctrl.NewManager(cfg, ctrl.Options{ + Scheme: sch, + MetricsBindAddress: "0", + }) + Expect(err).ToNot(HaveOccurred()) + + err = Add(k8sManager) + Expect(err).ToNot(HaveOccurred()) + + go func() { + err = k8sManager.Start(ctrl.SetupSignalHandler()) + klog.Error(err) + Expect(err).ToNot(HaveOccurred()) + }() + + k8sClient = k8sManager.GetClient() + Expect(k8sClient).ToNot(BeNil()) + + close(done) +}, 60) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + gexec.KillAndWait(5 * time.Second) + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +})