diff --git a/Makefile b/Makefile index 8fd2b341..c44222c7 100644 --- a/Makefile +++ b/Makefile @@ -353,7 +353,7 @@ e2e_init: make -C test deploy_metallb make -C test deploy_contour make -C test deploy_project - make -C test install_example_app + make -C test install_apiserver_token diff --git a/test/Makefile b/test/Makefile index c214f86e..d2f6080a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -159,6 +159,7 @@ deploy_project: HELM_OPTION+=" --set kdoctorAgent.ingress.enable=false " ; \ fi ; \ HELM_OPTION+=" --set feature.aggregateReport.enabled=true " ; \ + HELM_OPTION+=" --set feature.nethttp_defaultConcurrency=10 " ; \ HELM_OPTION+=" --set feature.aggregateReport.controller.reportHostPath=/var/run/kdoctor/controller " ; \ HELM_OPTION+=" --set kdoctorAgent.debug.logLevel=debug --set kdoctorController.debug.logLevel=debug " ; \ HELM_OPTION+=" --set kdoctorAgent.prometheus.enabled=true --set kdoctorController.prometheus.enabled=true " ; \ @@ -506,26 +507,12 @@ install_nginx: #========================== -# test kind is ok -.PHONY: install_example_app -install_example_app: KIND_KUBECONFIG ?= $(E2E_KIND_KUBECONFIG_PATH) -install_example_app: KIND_CLUSTER_NAME ?= $(E2E_KIND_CLUSTER_NAME) -install_example_app: IMAGE_TAG ?= $(GIT_COMMIT_VERSION) -install_example_app: - @echo "---------- install example app" - sed 's?<>?ghcr.io/kdoctor-io/kdoctor-agent:'$(IMAGE_TAG)'?' yaml/testpod.yaml | kubectl --kubeconfig=$(KIND_KUBECONFIG) apply -f - - @ if ! kubectl rollout status daemonset/kdoctor-test -n kube-system --kubeconfig $(KIND_KUBECONFIG) -w --timeout=120s ; then \ - kubectl get pod -A ; \ - echo "error, failed to create a test pod" ; \ - exit 1 ; \ - fi ; \ - echo "succeeded to deploy test deployment " - @echo "========================================================" - @echo " deploy kind cluster $(KIND_CLUSTER_NAME) " - @echo " export KUBECONFIG=$(KIND_KUBECONFIG) " - @echo " kubectl get pod -o wide -A " - @echo "========================================================" - @ KUBECONFIG=$(KIND_KUBECONFIG) kubectl get pod -o wide -A +.PHONY: install_apiserver_token +install_apiserver_token: KIND_KUBECONFIG ?= $(E2E_KIND_KUBECONFIG_PATH) +install_apiserver_token: KIND_CLUSTER_NAME ?= $(E2E_KIND_CLUSTER_NAME) +install_apiserver_token: + @echo "---------- install apiserver token" + sed 's?<>?$(E2E_INSTALL_NAMESPACE)?' yaml/kdoctortoken.yaml | kubectl --kubeconfig=$(KIND_KUBECONFIG) apply -f - .PHONY: clean @@ -551,6 +538,9 @@ e2e_test: echo "find cluster node: $${NODE_LIST}" ; \ export E2E_KIND_CLUSTER_NODE_LIST="$${NODE_LIST}" ; \ export E2E_CLUSTER_NAME=$(KIND_CLUSTER_NAME) ; \ + export APISERVER=`kubectl config view --kubeconfig $(KIND_KUBECONFIG) |grep server | awk '{print $$2}'` ;\ + export E2E_INSTALL_NAMESPACE=$(E2E_INSTALL_NAMESPACE) ;\ + export GIT_COMMIT_VERSION=$(GIT_COMMIT_VERSION) ;\ if [ "$(E2E_IP_FAMILY)" == "ipv4" ] ; then \ export E2E_IPV4_ENABLED=true ; export E2E_IPV6_ENABLED=false ; \ elif [ "$(E2E_IP_FAMILY)" == "ipv6" ] ; then \ diff --git a/test/docs/AppHttpHealth.md b/test/docs/AppHttpHealth.md new file mode 100644 index 00000000..eecb747f --- /dev/null +++ b/test/docs/AppHttpHealth.md @@ -0,0 +1,18 @@ +# E2E Cases for AppHttpHealth + +| Case ID | Title | Priority | Smoke | Status | Other | +|---------|-----------------------------------------------------------------------------|----------|-------|--------|-------------| +| A00001 | Successfully http testing appHttpHealth method GET case | p1 | | done | | +| A00002 | Failed http testing appHttpHealth due to status code case | p1 | | done | | +| A00003 | Failed http testing appHttpHealth due to delay case | p1 | | done | | +| A00004 | Successfully https testing appHttpHealth method GET case | p1 | | done | | +| A00005 | Failed https testing appHttpHealth due to tls case | p1 | | done | | +| A00006 | Successfully http testing appHttpHealth method PUT case | p1 | | done | | +| A00007 | Successfully http testing appHttpHealth method POST With Body case | p1 | | done | | +| A00008 | Successfully http testing appHttpHealth method HEAD case | p1 | | done | | +| A00009 | Successfully http testing appHttpHealth method PATCH case | p1 | | done | | +| A000010 | Successfully http testing appHttpHealth method OPTIONS case | p1 | | done | | +| A000011 | After QPS is specified, the number of requests meets the requirements case | p1 | | done | | +| A000012 | Successfully http testing appHttpHealth due to success rate case | p1 | | done | | +| A000013 | Successfully https testing appHttpHealth method GET Protocol Http2 case | p1 | | done | | +| A000014 | Report request count equal real request count case | p1 | | done | | diff --git a/test/docs/NetReach.md b/test/docs/NetReach.md new file mode 100644 index 00000000..ca5ad742 --- /dev/null +++ b/test/docs/NetReach.md @@ -0,0 +1,6 @@ +# E2E Cases for IP NetReach + +| Case ID | Title | Priority | Smoke | Status | Other | +|---------|--------------------------------------------------------|----------|-------|--------|-------------| +| B00001 | Successfully testing netReach case | p1 | | done | | + diff --git a/test/docs/schedule.md b/test/docs/schedule.md new file mode 100644 index 00000000..12fa397f --- /dev/null +++ b/test/docs/schedule.md @@ -0,0 +1,9 @@ +# E2E Cases for IP schedule + +| Case ID | Title | Priority | Smoke | Status | Other | +|---------|-------------------------------------------------|----------|-------|--------|-------------| +| C00001 | Successfully testing NetReach crontab case | p1 | | done | | +| C00002 | Successfully testing AppHttpHealth crontab case | p1 | | done | | +| C00003 | Successfully testing NetReach sample case | p1 | | done | | +| C00004 | Successfully testing AppHttpHealth sample case | p1 | | done | | + diff --git a/test/e2e/apphttphealth/apphttphealth_suite_test.go b/test/e2e/apphttphealth/apphttphealth_suite_test.go new file mode 100644 index 00000000..2ae6f20d --- /dev/null +++ b/test/e2e/apphttphealth/apphttphealth_suite_test.go @@ -0,0 +1,134 @@ +// Copyright 2023 Authors of kdoctor-io +// SPDX-License-Identifier: Apache-2.0 + +package apphttphealth_test + +import ( + "context" + kdoctor_v1beta1 "github.com/kdoctor-io/kdoctor/pkg/k8s/apis/kdoctor.io/v1beta1" + "github.com/kdoctor-io/kdoctor/test/e2e/common" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + e2e "github.com/spidernet-io/e2eframework/framework" + "github.com/spidernet-io/e2eframework/tools" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "testing" + "time" +) + +func TestNetReach(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "AppHttpHealth Suite") +} + +var frame *e2e.Framework + +var commonSvcIP string +var countSvcIP string +var commonPodIPs = make([]string, 0) +var countPodIPs = make([]string, 0) + +var httpPort = 80 +var httpsPort = 443 +var bodyConfigMapName string +var commonTestDsName string +var countTestDsName string + +var _ = BeforeSuite(func() { + defer GinkgoRecover() + var e error + frame, e = e2e.NewFramework(GinkgoT(), []func(*runtime.Scheme) error{kdoctor_v1beta1.AddToScheme}) + Expect(e).NotTo(HaveOccurred()) + + // test request body + bodyConfigMapName = "kdoctor-test-body-" + tools.RandomName() + cm := new(v1.ConfigMap) + cm.SetName(bodyConfigMapName) + cm.SetNamespace(common.TestNameSpace) + body := make(map[string]string, 0) + body["test1"] = "test1" + body["test2"] = "test2" + cm.Data = body + e = frame.CreateConfigmap(cm) + Expect(e).NotTo(HaveOccurred(), "create test body configmap") + + // test pod + commonTestDsName = "kdoctor-test-server-" + tools.RandomName() + commonKey := metav1.ObjectMeta{ + Name: commonTestDsName, + Namespace: common.TestNameSpace, + Labels: map[string]string{"app": commonTestDsName}, + } + e = common.CreateDaemonSetAndService(frame, commonKey, true, false) + Expect(e).NotTo(HaveOccurred(), "create common test daemonSet and service") + + // count test pod + countTestDsName = "kdoctor-test-server-" + tools.RandomName() + countKey := metav1.ObjectMeta{ + Name: countTestDsName, + Namespace: common.TestNameSpace, + Labels: map[string]string{"app": countTestDsName}, + } + e = common.CreateDaemonSetAndService(frame, countKey, true, true) + Expect(e).NotTo(HaveOccurred(), "create count test daemonSet and service") + // wait test ds ready + ctx, cancel := context.WithTimeout(context.Background(), time.Second*60) + defer cancel() + _, e = frame.WaitDaemonSetReady(commonTestDsName, common.TestNameSpace, ctx) + Expect(e).NotTo(HaveOccurred(), "wait common test daemonSet and service ready") + ctx2, cancel2 := context.WithTimeout(context.Background(), time.Second*60) + defer cancel2() + _, e = frame.WaitDaemonSetReady(countTestDsName, common.TestNameSpace, ctx2) + Expect(e).NotTo(HaveOccurred(), "wait count test daemonSet and service ready") + + // get common test service ip and pod ip + commonSvc, e := frame.GetService(commonTestDsName, common.TestNameSpace) + Expect(e).NotTo(HaveOccurred(), "get kdoctor common test service") + commonSvcIP = commonSvc.Spec.ClusterIP + GinkgoWriter.Printf("get common service ip %v \n", commonSvcIP) + + commonDs, e := frame.GetDaemonSet(commonTestDsName, common.TestNameSpace) + Expect(e).NotTo(HaveOccurred(), "get kdoctor common test daemonset") + + commonPods, e := frame.GetDaemonSetPodList(commonDs) + Expect(e).NotTo(HaveOccurred(), "get kdoctor common test pod list") + + for _, v := range commonPods.Items { + commonPodIPs = append(commonPodIPs, v.Status.PodIP) + } + + GinkgoWriter.Printf("get common test pod ips %v \n", commonPodIPs) + + // get count test service ip and pod ip + countSvc, e := frame.GetService(countTestDsName, common.TestNameSpace) + Expect(e).NotTo(HaveOccurred(), "get kdoctor count test service") + countSvcIP = countSvc.Spec.ClusterIP + GinkgoWriter.Printf("get count service ip %v \n", countSvcIP) + + countDs, e := frame.GetDaemonSet(countTestDsName, common.TestNameSpace) + Expect(e).NotTo(HaveOccurred(), "get kdoctor count test daemonset") + + countPods, e := frame.GetDaemonSetPodList(countDs) + Expect(e).NotTo(HaveOccurred(), "get kdoctor count test pod list") + + for _, v := range countPods.Items { + countPodIPs = append(countPodIPs, v.Status.PodIP) + } + + GinkgoWriter.Printf("get count test pod ips %v \n", countPodIPs) + +}) + +var _ = AfterSuite(func() { + defer GinkgoRecover() + _ = frame.DeleteConfigmap(bodyConfigMapName, common.TestNameSpace) + // common + _ = frame.DeleteDaemonSet(commonTestDsName, common.TestNameSpace) + _ = frame.DeleteService(commonTestDsName, common.TestNameSpace) + // count + _ = frame.DeleteDaemonSet(countTestDsName, common.TestNameSpace) + _ = frame.DeleteService(countTestDsName, common.TestNameSpace) + +}) diff --git a/test/e2e/apphttphealth/apphttphealth_test.go b/test/e2e/apphttphealth/apphttphealth_test.go new file mode 100644 index 00000000..603fcdd1 --- /dev/null +++ b/test/e2e/apphttphealth/apphttphealth_test.go @@ -0,0 +1,823 @@ +// Copyright 2023 Authors of kdoctor-io +// SPDX-License-Identifier: Apache-2.0 + +package apphttphealth_test + +import ( + "fmt" + "github.com/kdoctor-io/kdoctor/pkg/k8s/apis/kdoctor.io/v1beta1" + "github.com/kdoctor-io/kdoctor/pkg/pluginManager" + plugintypes "github.com/kdoctor-io/kdoctor/pkg/pluginManager/types" + "github.com/kdoctor-io/kdoctor/test/e2e/common" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/spidernet-io/e2eframework/tools" + "time" +) + +var _ = Describe("testing appHttpHealth test ", Label("appHttpHealth"), func() { + + It("success http testing appHttpHealth method GET", Label("A00001"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-get" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "GET" + target.Host = fmt.Sprintf("http://%s:%d", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + }) + + It("failed http testing appHttpHealth due to status code", Label("A00002"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + expectStatusCode := 205 + appHttpHealthName := "apphttphealth-get" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + successCondition.StatusCode = &expectStatusCode + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "GET" + target.Host = fmt.Sprintf("http://%s:%d", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultFail), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("Failed http testing appHttpHealth due to delay ", Label("A00003"), func() { + var e error + successRate := float64(1) + successMean := int64(200) + crontab := "0 1" + appHttpHealthName := "apphttphealth-get" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "GET" + target.Host = fmt.Sprintf("http://%s:%d/?delay=1", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultFail), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("success https testing appHttpHealth method GET", Label("A00004"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-get" + tools.RandomName() + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "GET" + target.Host = fmt.Sprintf("https://%s", commonPodIPs[0]) + target.TlsSecretName = &common.TlsClientName + target.TlsSecretNamespace = &common.TestNameSpace + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("failed https testing appHttpHealth due to tls", Label("A00005"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-get" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "GET" + // The service IP is not signed in the test pod, so using the service IP will fail certificate validation + target.Host = fmt.Sprintf("https://%s:%d", commonSvcIP, httpsPort) + target.TlsSecretName = &common.TlsClientName + target.TlsSecretNamespace = &common.TestNameSpace + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultFail), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("Successfully http testing appHttpHealth method PUT ", Label("A00006"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-put" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "PUT" + target.Host = fmt.Sprintf("http://%s:%d", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("Successfully http testing appHttpHealth method POST With Body", Label("A00007"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-post" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "POST" + target.Host = fmt.Sprintf("http://%s:%d", commonSvcIP, httpPort) + target.BodyConfigName = &bodyConfigMapName + target.BodyConfigNamespace = &common.TestNameSpace + target.Header = []string{"Content-Type: application/json"} + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + }) + + It("Successfully http testing appHttpHealth method HEAD", Label("A00008"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-head" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "HEAD" + target.Host = fmt.Sprintf("http://%s:%d", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("Successfully http testing appHttpHealth method PATCH", Label("A00009"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-patch" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "PATCH" + target.Host = fmt.Sprintf("http://%s:%d", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("Successfully http testing appHttpHealth method OPTIONS", Label("A00010"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-options" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "OPTIONS" + target.Host = fmt.Sprintf("http://%s:%d", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("After QPS is specified, the number of requests meets the requirements", Label("A000011"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-head" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "GET" + target.Host = fmt.Sprintf("http://%s:%d", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + TPS: float64(request.QPS), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("Successfully http testing appHttpHealth due to success rate", Label("A000012"), func() { + var e error + successRate := float64(0.2) + successMean := int64(1200) + crontab := "0 1" + appHttpHealthName := "apphttphealth-get" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "GET" + target.Host = fmt.Sprintf("http://%s:%d/delay?=1", commonSvcIP, httpPort) + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) + + It("Successfully https testing appHttpHealth method GET Protocol Http2", Label("A000013"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + appHttpHealthName := "apphttphealth-get" + tools.RandomName() + + appHttpHealth := new(v1beta1.AppHttpHealthy) + appHttpHealth.Name = appHttpHealthName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + appHttpHealth.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.AppHttpHealthyTarget) + target.Method = "GET" + target.Host = fmt.Sprintf("http://%s:%d", commonPodIPs[0], httpPort) + target.TlsSecretName = &common.TlsClientName + target.TlsSecretNamespace = &common.TestNameSpace + target.Http2 = true + appHttpHealth.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + appHttpHealth.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + appHttpHealth.Spec.Schedule = Schedule + + e = frame.CreateResource(appHttpHealth) + Expect(e).NotTo(HaveOccurred(), "create appHttpHealth resource") + + e = common.WaitKdoctorTaskDone(frame, appHttpHealth, pluginManager.KindNameAppHttpHealthy, 120) + Expect(e).NotTo(HaveOccurred(), "wait appHttpHealth task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, appHttpHealthName) + Expect(e).NotTo(HaveOccurred(), "get appHttpHealth task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) +}) diff --git a/test/e2e/common/constants.go b/test/e2e/common/constants.go new file mode 100644 index 00000000..ba2f5d40 --- /dev/null +++ b/test/e2e/common/constants.go @@ -0,0 +1,36 @@ +// Copyright 2023 Authors of kdoctor-io +// SPDX-License-Identifier: Apache-2.0 + +package common + +import "os" + +const ( + ImageRegistry = "ghcr.io/kdoctor-io/kdoctor-agent" + PluginReportPath = "/apis/system.kdoctor.io/v1beta1/namespaces/default/pluginreports/" + + KDoctorAgentDSName = "kdoctor-agent" + KdoctorTestTokenSecretName = "kdoctor-test-token" +) + +var ( + TlsClientName = "kdoctor-client-cert" + KdoctroTestToken = "" + APISERVICEADDR = "" + TestNameSpace = "kube-system" + TestImageTag = "v0.1.0" + TestIPv4 = false + TestIPv6 = false +) + +func init() { + APISERVICEADDR = os.Getenv("APISERVER") + TestNameSpace = os.Getenv("E2E_INSTALL_NAMESPACE") + TestImageTag = os.Getenv("GIT_COMMIT_VERSION") + if os.Getenv("E2E_IPV4_ENABLED") == "true" { + TestIPv4 = true + } + if os.Getenv("E2E_IPV6_ENABLED") == "true" { + TestIPv6 = true + } +} diff --git a/test/e2e/common/tools.go b/test/e2e/common/tools.go new file mode 100644 index 00000000..9f81fcba --- /dev/null +++ b/test/e2e/common/tools.go @@ -0,0 +1,473 @@ +// Copyright 2023 Authors of kdoctor-io +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "context" + "crypto/tls" + "encoding/json" + "fmt" + "github.com/onsi/ginkgo/v2" + "io" + appsv1 "k8s.io/api/apps/v1" + "net/http" + "time" + + "github.com/kdoctor-io/kdoctor/pkg/k8s/apis/kdoctor.io/v1beta1" + Plugin_v1 "github.com/kdoctor-io/kdoctor/pkg/k8s/apis/system/v1beta1" + "github.com/kdoctor-io/kdoctor/pkg/pluginManager" + frame "github.com/spidernet-io/e2eframework/framework" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func WaitKdoctorTaskDone(f *frame.Framework, task client.Object, taskKind string, timeout int) error { + interval := time.Duration(10) + switch taskKind { + case pluginManager.KindNameNetReach: + fake := &v1beta1.NetReach{ + ObjectMeta: metav1.ObjectMeta{ + Name: task.GetName(), + }, + } + key := client.ObjectKeyFromObject(fake) + after := time.After(time.Duration(timeout) * time.Second) + + for { + select { + case <-after: + return fmt.Errorf("timeout wait task NetReach %s finish", task.GetName()) + default: + rs := &v1beta1.NetReach{} + if err := f.GetResource(key, rs); err != nil { + return fmt.Errorf("failed get resource NetReach %s", task.GetName()) + } + if rs.Status.Finish { + return nil + } + time.Sleep(time.Second * interval) + } + } + case pluginManager.KindNameAppHttpHealthy: + fake := &v1beta1.AppHttpHealthy{ + ObjectMeta: metav1.ObjectMeta{ + Name: task.GetName(), + }, + } + key := client.ObjectKeyFromObject(fake) + after := time.After(time.Duration(timeout) * time.Second) + + for { + select { + case <-after: + return fmt.Errorf("timeout wait task AppHttpHealthy %s finish", task.GetName()) + default: + rs := &v1beta1.AppHttpHealthy{} + if err := f.GetResource(key, rs); err != nil { + return fmt.Errorf("failed get resource AppHttpHealthy %s", task.GetName()) + } + if rs.Status.Finish { + return nil + } + time.Sleep(time.Second * interval) + } + } + case pluginManager.KindNameNetdns: + fake := &v1beta1.Netdns{ + ObjectMeta: metav1.ObjectMeta{ + Name: task.GetName(), + }, + } + key := client.ObjectKeyFromObject(fake) + after := time.After(time.Duration(timeout) * time.Second) + + for { + select { + case <-after: + return fmt.Errorf("timeout wait task Netdns %s finish", task.GetName()) + default: + rs := &v1beta1.NetReach{} + if err := f.GetResource(key, rs); err != nil { + return fmt.Errorf("failed get resource Netdns %s", task.GetName()) + } + if rs.Status.Finish { + return nil + } + time.Sleep(time.Second * interval) + } + } + default: + return fmt.Errorf("unknown task type: %s", task.GetObjectKind().GroupVersionKind().Kind) + } + +} + +func GetKdoctorToken(f *frame.Framework) (string, error) { + + if KdoctroTestToken != "" { + return KdoctroTestToken, nil + } + + fake := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: KdoctorTestTokenSecretName, + Namespace: TestNameSpace, + }, + } + key := client.ObjectKeyFromObject(fake) + + s := &corev1.Secret{} + if err := f.KClient.Get(context.TODO(), key, s); err != nil { + return "", fmt.Errorf("get kdoctor token secret failed, err: %v", err) + } + KdoctroTestToken = string(s.Data["token"]) + + return KdoctroTestToken, nil +} + +func GetPluginReportResult(f *frame.Framework, n string) (*Plugin_v1.PluginReport, error) { + var err error + url := fmt.Sprintf("%s%s%s", APISERVICEADDR, PluginReportPath, n) + ginkgo.GinkgoWriter.Println(url) + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + tr.TLSNextProto = make(map[string]func(string, *tls.Conn) http.RoundTripper) + c := &http.Client{Transport: tr} + req, _ := http.NewRequest("GET", url, nil) + token, err := GetKdoctorToken(f) + if err != nil { + return nil, fmt.Errorf("get kdoctor test token failed,err : %v", err) + } + v := fmt.Sprintf("Bearer %s", token) + req.Header.Set("Authorization", v) + + resp, err := c.Do(req) + if err != nil { + return nil, fmt.Errorf("get plugin report failed,err : %v", err) + } + + body, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + return nil, fmt.Errorf("read plugin report body failed,err : %v", err) + } + report := new(Plugin_v1.PluginReport) + + err = json.Unmarshal(body, report) + if err != nil { + return nil, fmt.Errorf("unmarshal plugin report failed,err : %v", err) + } + + return report, nil +} + +type TaskResult struct { + Success []string + MeanDelay []float32 + SucceedRate []float64 + TimeDuration []time.Duration + RequestCount []int64 + TPS []float64 + RoundNumber []int64 +} + +type TargetResult struct { + Success string + MeanDelay float32 + SucceedRate float64 + TimeDuration time.Duration + RequestCount int64 + TPS float64 + RoundNumber int64 +} + +func CompareTaskResult(report *Plugin_v1.PluginReport, t TargetResult) bool { + r := aggregationResult(report) + + for _, v := range r.Success { + if v != t.Success { + return false + } + } + + for _, v := range r.MeanDelay { + if t.MeanDelay == 0 { + break + } + if v > t.MeanDelay { + return false + } + } + + for _, v := range r.SucceedRate { + if t.SucceedRate == 0 { + break + } + if v > t.SucceedRate { + return false + } + } + + for _, v := range r.TimeDuration { + if t.TimeDuration == 0 { + break + } + if v > t.TimeDuration { + return false + } + } + + for _, v := range r.TPS { + if t.TPS == 0 { + break + } + if (v-t.TPS)/v > 0.05 { + return false + } + } + + for _, v := range r.RoundNumber { + if t.RoundNumber == 0 { + break + } + if v != t.RoundNumber { + return false + } + } + // request count + var count int64 + for _, v := range r.RequestCount { + if t.RequestCount == 0 { + break + } + count += v + } + + return t.RequestCount == count +} + +func aggregationResult(report *Plugin_v1.PluginReport) TaskResult { + r := TaskResult{} + + // success + for _, v := range *report.Spec.Report { + r.Success = append(r.Success, v.RoundResult) + } + + // meanDelay + for _, v := range *report.Spec.Report { + if v.HttpAppHealthyTask != nil { + for _, m := range v.HttpAppHealthyTask.Detail { + r.MeanDelay = append(r.MeanDelay, m.MeanDelay) + } + } + if v.NetReachTask != nil { + for _, m := range v.NetReachTask.Detail { + r.MeanDelay = append(r.MeanDelay, m.MeanDelay) + } + } + + if v.NetDNSTask != nil { + for _, m := range v.NetReachTask.Detail { + r.MeanDelay = append(r.MeanDelay, m.MeanDelay) + } + } + } + + // SucceedRate + for _, v := range *report.Spec.Report { + if v.HttpAppHealthyTask != nil { + for _, m := range v.HttpAppHealthyTask.Detail { + r.SucceedRate = append(r.SucceedRate, m.SucceedRate) + } + } + if v.NetReachTask != nil { + for _, m := range v.NetReachTask.Detail { + r.SucceedRate = append(r.SucceedRate, m.SucceedRate) + } + } + + if v.NetDNSTask != nil { + for _, m := range v.NetReachTask.Detail { + r.SucceedRate = append(r.SucceedRate, m.SucceedRate) + } + } + } + + // TimeDuration + for _, v := range *report.Spec.Report { + if v.HttpAppHealthyTask != nil { + for _, m := range v.HttpAppHealthyTask.Detail { + d, _ := time.ParseDuration(m.Metrics.Duration) + r.TimeDuration = append(r.TimeDuration, d) + } + } + if v.NetReachTask != nil { + for _, m := range v.NetReachTask.Detail { + d, _ := time.ParseDuration(m.Metrics.Duration) + r.TimeDuration = append(r.TimeDuration, d) + } + } + + if v.NetDNSTask != nil { + for _, m := range v.NetReachTask.Detail { + d, _ := time.ParseDuration(m.Metrics.Duration) + r.TimeDuration = append(r.TimeDuration, d) + } + } + } + + // RequestCount + for _, v := range *report.Spec.Report { + if v.HttpAppHealthyTask != nil { + for _, m := range v.HttpAppHealthyTask.Detail { + r.RequestCount = append(r.RequestCount, m.Metrics.RequestCounts) + } + } + if v.NetReachTask != nil { + for _, m := range v.NetReachTask.Detail { + r.RequestCount = append(r.RequestCount, m.Metrics.RequestCounts) + } + } + + if v.NetDNSTask != nil { + for _, m := range v.NetReachTask.Detail { + r.RequestCount = append(r.RequestCount, m.Metrics.RequestCounts) + } + } + } + + // TPS + for _, v := range *report.Spec.Report { + if v.HttpAppHealthyTask != nil { + for _, m := range v.HttpAppHealthyTask.Detail { + r.TPS = append(r.TPS, m.Metrics.TPS) + } + } + if v.NetReachTask != nil { + for _, m := range v.NetReachTask.Detail { + r.TPS = append(r.TPS, m.Metrics.TPS) + } + } + + if v.NetDNSTask != nil { + for _, m := range v.NetReachTask.Detail { + r.TPS = append(r.TPS, m.Metrics.TPS) + } + } + } + + // round number + for _, v := range *report.Spec.Report { + r.RoundNumber = append(r.RoundNumber, v.RoundNumber) + } + + return r +} + +func GetTaskFailReason(report *Plugin_v1.PluginReport) []string { + reason := make([]string, 0) + for _, v := range *report.Spec.Report { + if v.HttpAppHealthyTask != nil { + for _, m := range v.HttpAppHealthyTask.Detail { + for j := range m.Metrics.Errors { + reason = append(reason, j) + } + } + } + + if v.NetReachTask != nil { + for _, m := range v.NetReachTask.Detail { + for j := range m.Metrics.Errors { + reason = append(reason, j) + } + } + } + + if v.NetDNSTask != nil { + for _, m := range v.NetDNSTask.Detail { + for j := range m.Metrics.Errors { + reason = append(reason, j) + } + } + } + } + return reason +} + +func CreateDaemonSetAndService(f *frame.Framework, key metav1.ObjectMeta, app, insecure bool) error { + ds := new(appsv1.DaemonSet) + svc := new(corev1.Service) + // daemonSet + ds.ObjectMeta = key + ds.Spec.Selector = &metav1.LabelSelector{MatchLabels: key.Labels} + ds.Spec.Template.ObjectMeta = key + ds.Spec.Template.Spec.Volumes = []corev1.Volume{ + {Name: "tls", VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "kdoctor-ca", + Items: []corev1.KeyToPath{ + {Key: "tls.key", Path: "ca.key"}, + {Key: "tls.crt", Path: "ca.crt"}, + }, + }, + }}, + } + + container := corev1.Container{} + container.Name = key.Name + container.Image = ImageRegistry + ":" + TestImageTag + container.ImagePullPolicy = corev1.PullIfNotPresent + container.Command = []string{"/usr/bin/agent"} + container.Args = []string{"--tls-ca-cert=/etc/tls/ca.crt", "--tls-ca-key=/etc/tls/ca.key"} + if app { + container.Args = append(container.Args, "--app-mode=true") + } + if !insecure { + container.Args = append(container.Args, "--tls-insecure=true") + } + container.VolumeMounts = []corev1.VolumeMount{{MountPath: "/etc/tls", Name: "tls"}} + + ds.Spec.Template.Spec.Containers = append(ds.Spec.Template.Spec.Containers, container) + + // service + svc.ObjectMeta = key + svc.Spec.Selector = key.Labels + svc.Spec.Type = corev1.ServiceTypeClusterIP + svc.Spec.Ports = []corev1.ServicePort{ + {Name: "http", Port: 80, TargetPort: intstr.IntOrString{IntVal: 80}}, + {Name: "https", Port: 443, TargetPort: intstr.IntOrString{IntVal: 443}}, + } + if !TestIPv4 && TestIPv6 { + svc.Spec.IPFamilies = []corev1.IPFamily{corev1.IPv6Protocol} + } else { + svc.Spec.IPFamilies = []corev1.IPFamily{corev1.IPv4Protocol} + } + e := f.CreateDaemonSet(ds) + if e != nil { + return fmt.Errorf("create test daemonset failed ,reason=%v", e) + } + + e = f.CreateService(svc) + if e != nil { + return fmt.Errorf("create test service failed ,reason=%v", e) + } + return nil +} + +func GetRequestCount(ip string) (int64, error) { + var err error + return 0, err +} + +func CleanRequestCount(ip string) error { + + return nil + +} diff --git a/test/e2e/example/example_suite_test.go b/test/e2e/example/example_suite_test.go deleted file mode 100644 index f676830e..00000000 --- a/test/e2e/example/example_suite_test.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2023 Authors of kdoctor-io -// SPDX-License-Identifier: Apache-2.0 -package example_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - e2e "github.com/spidernet-io/e2eframework/framework" - // "k8s.io/apimachinery/pkg/runtime" -) - -func TestAssignIP(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "example Suite") -} - -var frame *e2e.Framework - -var _ = BeforeSuite(func() { - defer GinkgoRecover() - var e error - frame, e = e2e.NewFramework(GinkgoT(), nil) - Expect(e).NotTo(HaveOccurred()) - -}) diff --git a/test/e2e/example/example_test.go b/test/e2e/example/example_test.go deleted file mode 100644 index 4fbcc688..00000000 --- a/test/e2e/example/example_test.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2023 Authors of kdoctor-io -// SPDX-License-Identifier: Apache-2.0 -package example_test - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = Describe("example ", Label("example"), func() { - - It("example", Label("example-1"), func() { - GinkgoWriter.Printf("cluster information: %+v \n", frame.Info) - - d, e := frame.GetDaemonSet("test", "default") - Expect(e).NotTo(HaveOccurred(), "failed to get daemonset ") - GinkgoWriter.Printf("daemonset: %+v \n", d) - }) -}) diff --git a/test/e2e/netreach/netreach_suite_test.go b/test/e2e/netreach/netreach_suite_test.go new file mode 100644 index 00000000..a40dbca5 --- /dev/null +++ b/test/e2e/netreach/netreach_suite_test.go @@ -0,0 +1,44 @@ +// Copyright 2023 Authors of kdoctor-io +// SPDX-License-Identifier: Apache-2.0 + +package netreach_test + +import ( + kdoctor_v1beta1 "github.com/kdoctor-io/kdoctor/pkg/k8s/apis/kdoctor.io/v1beta1" + "github.com/kdoctor-io/kdoctor/test/e2e/common" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + e2e "github.com/spidernet-io/e2eframework/framework" + v1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/runtime" + "testing" + // "k8s.io/apimachinery/pkg/runtime" +) + +func TestNetReach(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "NetReach Suite") +} + +var frame *e2e.Framework +var agentDS *v1.DaemonSet +var _ = BeforeSuite(func() { + defer GinkgoRecover() + var e error + frame, e = e2e.NewFramework(GinkgoT(), []func(*runtime.Scheme) error{kdoctor_v1beta1.AddToScheme}) + Expect(e).NotTo(HaveOccurred()) + agentDS, e = frame.GetDaemonSet(common.KDoctorAgentDSName, common.TestNameSpace) + Expect(e).NotTo(HaveOccurred(), "get kdoctor-agent daemonset") + + // add agent multus network + // TODO ii2day + //agentDS.Annotations[common.MultusDefaultAnnotationKey] = fmt.Sprintf("%s/%s", common.MultusNamespace, common.MultusCRName) + //agentDS.Annotations[common.MultusAddonAnnotation_Key] = fmt.Sprintf("%s/%s", common.MultusNamespace, common.MultusCRName) + // + //e = frame.UpdateResource(agentDS) + //Expect(e).NotTo(HaveOccurred()) + //ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) + //defer cancel() + //agentDS, e = frame.WaitDaemonSetReady(common.KDoctorAgentDSName, common.KDoctorAgentNS, ctx) + //Expect(e).NotTo(HaveOccurred()) +}) diff --git a/test/e2e/netreach/netreach_test.go b/test/e2e/netreach/netreach_test.go new file mode 100644 index 00000000..0c8ba98a --- /dev/null +++ b/test/e2e/netreach/netreach_test.go @@ -0,0 +1,85 @@ +// Copyright 2023 Authors of kdoctor-io +// SPDX-License-Identifier: Apache-2.0 + +package netreach_test + +import ( + "github.com/kdoctor-io/kdoctor/pkg/k8s/apis/kdoctor.io/v1beta1" + "github.com/kdoctor-io/kdoctor/pkg/pluginManager" + plugintypes "github.com/kdoctor-io/kdoctor/pkg/pluginManager/types" + "github.com/kdoctor-io/kdoctor/test/e2e/common" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/spidernet-io/e2eframework/tools" + "time" +) + +var _ = Describe("testing netReach ", Label("netReach"), func() { + + It("success testing netReach", Label("B00001"), func() { + var e error + successRate := float64(1) + successMean := int64(1500) + crontab := "0 1" + netReachName := "netreach-" + tools.RandomName() + + netReach := new(v1beta1.NetReach) + netReach.Name = netReachName + + // successCondition + successCondition := new(v1beta1.NetSuccessCondition) + successCondition.SuccessRate = &successRate + successCondition.MeanAccessDelayInMs = &successMean + netReach.Spec.SuccessCondition = successCondition + + // target + target := new(v1beta1.NetReachTarget) + target.Ingress = true + target.LoadBalancer = true + target.ClusterIP = true + target.Endpoint = true + target.NodePort = true + target.MultusInterface = false + target.IPv4 = &common.TestIPv4 + target.IPv6 = &common.TestIPv6 + netReach.Spec.Target = target + + // request + request := new(v1beta1.NetHttpRequest) + request.PerRequestTimeoutInMS = 1000 + request.QPS = 1 + request.DurationInSecond = 5 + netReach.Spec.Request = request + + // Schedule + Schedule := new(v1beta1.SchedulePlan) + Schedule.Schedule = &crontab + Schedule.RoundNumber = 1 + Schedule.RoundTimeoutMinute = 1 + netReach.Spec.Schedule = Schedule + + e = frame.CreateResource(netReach) + Expect(e).NotTo(HaveOccurred(), "create netReach resource") + + e = common.WaitKdoctorTaskDone(frame, netReach, pluginManager.KindNameNetReach, 120) + Expect(e).NotTo(HaveOccurred(), "wait netReach task finish") + + // wait report gen + time.Sleep(time.Second * 10) + r, e := common.GetPluginReportResult(frame, netReachName) + Expect(e).NotTo(HaveOccurred(), "get NetReach task result") + + failReason := common.GetTaskFailReason(r) + + if len(failReason) > 0 { + GinkgoWriter.Printf("fail reason: %v", failReason) + } + + t := common.TargetResult{ + Success: string(plugintypes.RoundResultSucceed), + RoundNumber: 1, + } + Expect(common.CompareTaskResult(r, t)).Should(BeTrue(), "task result need the same target") + + }) +}) diff --git a/test/scripts/debugCluster.sh b/test/scripts/debugCluster.sh index 1212294f..b6b00a76 100755 --- a/test/scripts/debugCluster.sh +++ b/test/scripts/debugCluster.sh @@ -18,7 +18,7 @@ COMPONENT_NAMESPACE="$4" echo "$CURRENT_FILENAME : E2E_KUBECONFIG $E2E_KUBECONFIG " # ====modify==== -COMPONENT_GOROUTINE_MAX=300 +COMPONENT_GOROUTINE_MAX=600 COMPONENT_PS_PROCESS_MAX=50 CONTROLLER_LABEL="app.kubernetes.io/component=kdoctor-controller" AGENT_LABEL="app.kubernetes.io/component=kdoctor-agent" diff --git a/test/yaml/kdoctortoken.yaml b/test/yaml/kdoctortoken.yaml new file mode 100644 index 00000000..43658665 --- /dev/null +++ b/test/yaml/kdoctortoken.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: kdoctor-test-token + namespace: <> + annotations: + kubernetes.io/service-account.name: kdoctor-controller +type: kubernetes.io/service-account-token \ No newline at end of file diff --git a/test/yaml/testpod.yaml b/test/yaml/testpod.yaml deleted file mode 100644 index 9a0e988f..00000000 --- a/test/yaml/testpod.yaml +++ /dev/null @@ -1,59 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: kdoctor-test - namespace: kube-system - labels: - app: kdoctor-test -spec: - selector: - matchLabels: - app: kdoctor-test - template: - metadata: - name: kdoctor-test - labels: - app: kdoctor-test - spec: - containers: - - name: kdoctor-test - image: <> - imagePullPolicy: IfNotPresent - command: ["/usr/bin/agent"] - args: - - "--app-mode=true" - - "--tls-ca-cert=/etc/tls/ca.crt" - - "--tls-ca-key=/etc/tls/ca.key" - volumeMounts: - - mountPath: /etc/tls - name: tls - volumes: - - name: tls - projected: - defaultMode: 0400 - sources: - - secret: - items: - - key: tls.key - path: ca.key - - key: tls.crt - path: ca.crt - name: kdoctor-ca - ---- -apiVersion: v1 -kind: Service -metadata: - name: kdoctor-test - namespace: kube-system -spec: - selector: - app: kdoctor-test - ports: - - name: http - port: 80 - targetPort: 80 - - name: https - port: 443 - targetPort: 443 - type: ClusterIP \ No newline at end of file