From ca6903f0ca0fc368586d9071d7d0aba340f2d439 Mon Sep 17 00:00:00 2001 From: ShyunnY <1147212064@qq.com> Date: Sun, 10 Mar 2024 22:58:33 +0800 Subject: [PATCH] e2e: add backend weighted Signed-off-by: ShyunnY <1147212064@qq.com> --- .../weight-backend-completing-rollout.yaml | 20 ++ .../testdata/weighted-backend-all-equal.yaml | 20 ++ .../testdata/weighted-backend-bluegreen.yaml | 20 ++ test/e2e/tests/weighted_backend.go | 225 ++++++++++++++++++ 4 files changed, 285 insertions(+) create mode 100644 test/e2e/testdata/weight-backend-completing-rollout.yaml create mode 100644 test/e2e/testdata/weighted-backend-all-equal.yaml create mode 100644 test/e2e/testdata/weighted-backend-bluegreen.yaml create mode 100644 test/e2e/tests/weighted_backend.go diff --git a/test/e2e/testdata/weight-backend-completing-rollout.yaml b/test/e2e/testdata/weight-backend-completing-rollout.yaml new file mode 100644 index 00000000000..2a36b557122 --- /dev/null +++ b/test/e2e/testdata/weight-backend-completing-rollout.yaml @@ -0,0 +1,20 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: weight-complete-rollout-http-route + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: infra-backend-v1 + port: 8080 + weight: 10 + - name: infra-backend-v2 + port: 8080 + weight: 0 diff --git a/test/e2e/testdata/weighted-backend-all-equal.yaml b/test/e2e/testdata/weighted-backend-all-equal.yaml new file mode 100644 index 00000000000..b81edeb4ae8 --- /dev/null +++ b/test/e2e/testdata/weighted-backend-all-equal.yaml @@ -0,0 +1,20 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: weight-equal-http-route + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: infra-backend-v1 + port: 8080 + weight: 1 + - name: infra-backend-v2 + port: 8080 + weight: 1 diff --git a/test/e2e/testdata/weighted-backend-bluegreen.yaml b/test/e2e/testdata/weighted-backend-bluegreen.yaml new file mode 100644 index 00000000000..13be4ab26a1 --- /dev/null +++ b/test/e2e/testdata/weighted-backend-bluegreen.yaml @@ -0,0 +1,20 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: weight-bluegreen-http-route + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: infra-backend-v1 + port: 8080 + weight: 9 + - name: infra-backend-v2 + port: 8080 + weight: 1 diff --git a/test/e2e/tests/weighted_backend.go b/test/e2e/tests/weighted_backend.go new file mode 100644 index 00000000000..ba208163587 --- /dev/null +++ b/test/e2e/tests/weighted_backend.go @@ -0,0 +1,225 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +//go:build e2e +// +build e2e + +package tests + +import ( + "fmt" + "regexp" + "testing" + + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" +) + +func init() { + ConformanceTests = append(ConformanceTests, WeightEqualTest, WeightBlueGreenTest, WeightCompleteRolloutTest) +} + +var WeightEqualTest = suite.ConformanceTest{ + ShortName: "WeightEqualBackend", + Description: "Resource with Weight Backend enabled, and use the all backend weight is equal", + Manifests: []string{"testdata/weighted-backend-all-equal.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("all backends receive the same weight of traffic", func(t *testing.T) { + ns := "gateway-conformance-infra" + weightEqualRoute := types.NamespacedName{Name: "weight-equal-http-route", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, + suite.ControllerName, + kubernetes.NewGatewayRef(gwNN), weightEqualRoute) + + expectedResponse := http.ExpectedResponse{ + Request: http.Request{ + Path: "/", + }, + Response: http.Response{ + StatusCode: 200, + }, + Namespace: ns, + } + req := http.MakeRequest(t, &expectedResponse, gwAddr, "HTTP", "http") + + weightMap := make(map[string]int) + for i := 0; i < 10; i++ { + cReq, cResp, err := suite.RoundTripper.CaptureRoundTrip(req) + if err != nil { + t.Errorf("failed to get expected response: %v", err) + } + + if err := http.CompareRequest(t, &req, cReq, cResp, expectedResponse); err != nil { + t.Errorf("failed to compare request and response: %v", err) + } + + podName := cReq.Pod + if len(podName) == 0 { + // it shouldn't be missing here + t.Errorf("failed to get pod header in response: %v", err) + + } else { + // all we need is the pod Name prefix + podNamePrefix := ExtractPodNamePrefix(podName) + weightMap[podNamePrefix]++ + } + } + + // Since we only route to pods with "infra-backend-v 1" and "infra-backend-v 2" prefixes + // So here we use fixed weight values + v1Weight := 1 + v2Weight := 1 + if !CalculateWeight(v1Weight, v2Weight, weightMap) { + t.Errorf("The actual traffic weights are not consistent with the expected routing weights") + } + }) + }, +} + +var WeightBlueGreenTest = suite.ConformanceTest{ + ShortName: "WeightBlueGreenBackend", + Description: "Resource with Weight Backend enabled, and use the blue-green policy weight setting", + Manifests: []string{"testdata/weighted-backend-bluegreen.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("all backends receive the blue green weight of traffic", func(t *testing.T) { + ns := "gateway-conformance-infra" + weightEqualRoute := types.NamespacedName{Name: "weight-bluegreen-http-route", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, + suite.ControllerName, + kubernetes.NewGatewayRef(gwNN), weightEqualRoute) + + expectedResponse := http.ExpectedResponse{ + Request: http.Request{ + Path: "/", + }, + Response: http.Response{ + StatusCode: 200, + }, + Namespace: ns, + } + req := http.MakeRequest(t, &expectedResponse, gwAddr, "HTTP", "http") + + weightMap := make(map[string]int) + for i := 0; i < 10; i++ { + cReq, cResp, err := suite.RoundTripper.CaptureRoundTrip(req) + if err != nil { + t.Errorf("failed to get expected response: %v", err) + } + + if err := http.CompareRequest(t, &req, cReq, cResp, expectedResponse); err != nil { + t.Errorf("failed to compare request and response: %v", err) + } + + podName := cReq.Pod + if len(podName) == 0 { + // it shouldn't be missing here + t.Errorf("failed to get pod header in response: %v", err) + + } else { + // all we need is the pod Name prefix + podNamePrefix := ExtractPodNamePrefix(podName) + weightMap[podNamePrefix]++ + } + } + + // Since we only route to pods with "infra-backend-v 1" and "infra-backend-v 2" prefixes + // So here we use fixed weight values + v1Weight := 9 + v2Weight := 1 + + if !CalculateWeight(v1Weight, v2Weight, weightMap) { + t.Errorf("The actual traffic weights are not consistent with the expected routing weights") + } + }) + }, +} + +var WeightCompleteRolloutTest = suite.ConformanceTest{ + ShortName: "WeightCompleteRollout", + Description: "Resource with Weight Backend enabled, and use the completing rollout policy weight setting", + Manifests: []string{"testdata/weight-backend-completing-rollout.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("all backends receive the complete rollout weight of traffic", func(t *testing.T) { + ns := "gateway-conformance-infra" + weightEqualRoute := types.NamespacedName{Name: "weight-complete-rollout-http-route", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, + suite.ControllerName, + kubernetes.NewGatewayRef(gwNN), weightEqualRoute) + + expectedResponse := http.ExpectedResponse{ + Request: http.Request{ + Path: "/", + }, + Response: http.Response{ + StatusCode: 200, + }, + Namespace: ns, + } + req := http.MakeRequest(t, &expectedResponse, gwAddr, "HTTP", "http") + + weightMap := make(map[string]int) + for i := 0; i < 10; i++ { + cReq, cResp, err := suite.RoundTripper.CaptureRoundTrip(req) + if err != nil { + t.Errorf("failed to get expected response: %v", err) + } + + if err := http.CompareRequest(t, &req, cReq, cResp, expectedResponse); err != nil { + t.Errorf("failed to compare request and response: %v", err) + } + + podName := cReq.Pod + if len(podName) == 0 { + // it shouldn't be missing here + t.Errorf("failed to get pod header in response: %v", err) + + } else { + // all we need is the pod Name prefix + podNamePrefix := ExtractPodNamePrefix(podName) + weightMap[podNamePrefix]++ + } + } + + // Since we only route to pods with "infra-backend-v 1" and "infra-backend-v 2" prefixes + // So here we use fixed weight values + v1Weight := 10 + v2Weight := 0 + if !CalculateWeight(v1Weight, v2Weight, weightMap) { + t.Errorf("The actual traffic weights are not consistent with the expected routing weights") + } + }) + }, +} + +// CalculateWeight Calculate whether the expected weight is equal to the weight of the expected traffic +func CalculateWeight(weight1, weight2 int, actualMap map[string]int) bool { + + var count int + for _, v := range actualMap { + count += v + } + expectedV1 := float64(weight1) / float64(weight1+weight2) * float64(count) + expectedV2 := float64(weight2) / float64(weight1+weight2) * float64(count) + + return int(expectedV1) == actualMap["infra-backend-v1"] && int(expectedV2) == actualMap["infra-backend-v2"] +} + +// ExtractPodNamePrefix Extract the Pod Name prefix +func ExtractPodNamePrefix(podName string) string { + + pattern := regexp.MustCompile(`infra-backend-(.+?)-`) + match := pattern.FindStringSubmatch(podName) + if len(match) > 1 { + version := match[1] + return fmt.Sprintf("infra-backend-%s", version) + } + + return podName +}