From 8a50eb548b6645d024f9c113df82fabb84ef7913 Mon Sep 17 00:00:00 2001 From: AlinsRan Date: Wed, 10 Dec 2025 10:32:42 +0800 Subject: [PATCH 1/2] fix: wss related tests are unstable (#2675) (cherry picked from commit b70e22ebac75a4e790d770cd49fbfba9730c1664) --- internal/controller/gateway_controller.go | 4 + internal/controller/indexer/ssl_host.go | 6 +- test/e2e/crds/v2/route.go | 9 ++ test/e2e/framework/manifests/apisix.yaml | 3 + test/e2e/framework/manifests/nginx.yaml | 10 +- test/e2e/gatewayapi/httproute.go | 16 ++- test/e2e/ingress/ingress.go | 21 ++-- test/e2e/scaffold/apisix_deployer.go | 13 ++ test/e2e/scaffold/scaffold.go | 139 ++++++++++++++++++++++ 9 files changed, 200 insertions(+), 21 deletions(-) diff --git a/internal/controller/gateway_controller.go b/internal/controller/gateway_controller.go index 76648a4a..3a3f4a3a 100644 --- a/internal/controller/gateway_controller.go +++ b/internal/controller/gateway_controller.go @@ -120,6 +120,10 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct } return ctrl.Result{}, err } + if !r.checkGatewayClass(gateway) { + return ctrl.Result{}, nil + } + conditionProgrammedStatus, conditionProgrammedMsg := true, "Programmed" r.Log.Info("gateway has been accepted", "gateway", gateway.GetName()) diff --git a/internal/controller/indexer/ssl_host.go b/internal/controller/indexer/ssl_host.go index 9838d43f..6762aa30 100644 --- a/internal/controller/indexer/ssl_host.go +++ b/internal/controller/indexer/ssl_host.go @@ -69,9 +69,11 @@ func GatewayTLSHostIndexFunc(rawObj client.Object) []string { } } - tlsHostIndexLogger.Info("GatewayTLSHostIndexFunc", "hosts", hostSetToSlice(hosts), "len", len(hostSetToSlice(hosts))) + hostsSlice := hostSetToSlice(hosts) - return hostSetToSlice(hosts) + tlsHostIndexLogger.V(1).Info("GatewayTLSHostIndexFunc", "hosts", hostsSlice) + + return hostsSlice } // IngressTLSHostIndexFunc indexes Ingresses by their TLS SNI hosts. diff --git a/test/e2e/crds/v2/route.go b/test/e2e/crds/v2/route.go index bc1af407..81adb9b0 100644 --- a/test/e2e/crds/v2/route.go +++ b/test/e2e/crds/v2/route.go @@ -2323,6 +2323,7 @@ spec: applier.MustApplyAPIv2(types.NamespacedName{Namespace: s.Namespace(), Name: "default"}, new(apiv2.ApisixRoute), fmt.Sprintf(apisixRouteWithBackendWSS, s.Namespace())) +<<<<<<< HEAD By("verify wss connection with retry") u := url.URL{ Scheme: "wss", @@ -2345,6 +2346,14 @@ spec: return dialErr }).WithTimeout(30*time.Second).WithPolling(2*time.Second).Should(Succeed(), "WebSocket handshake should succeed") Expect(resp.StatusCode).Should(Equal(http.StatusSwitchingProtocols)) +======= + By("verify wss connection") + hostname := "api6.com" + conn := s.NewWebsocketClient(&tls.Config{ + InsecureSkipVerify: true, + ServerName: hostname, + }, "/ws", http.Header{"Host": []string{hostname}}) +>>>>>>> b70e22eb (fix: wss related tests are unstable (#2675)) defer func() { _ = conn.Close() diff --git a/test/e2e/framework/manifests/apisix.yaml b/test/e2e/framework/manifests/apisix.yaml index 31581bcc..30289194 100644 --- a/test/e2e/framework/manifests/apisix.yaml +++ b/test/e2e/framework/manifests/apisix.yaml @@ -63,15 +63,18 @@ metadata: name: apisix labels: app.kubernetes.io/name: apisix + app: apisix spec: replicas: {{ default 1 .Replicas }} selector: matchLabels: app.kubernetes.io/name: apisix + app: apisix template: metadata: labels: app.kubernetes.io/name: apisix + app: apisix spec: initContainers: - name: config-setup diff --git a/test/e2e/framework/manifests/nginx.yaml b/test/e2e/framework/manifests/nginx.yaml index a795e812..82b08e96 100644 --- a/test/e2e/framework/manifests/nginx.yaml +++ b/test/e2e/framework/manifests/nginx.yaml @@ -124,13 +124,19 @@ spec: containers: - livenessProbe: failureThreshold: 3 - initialDelaySeconds: 1 - periodSeconds: 5 + initialDelaySeconds: 10 + periodSeconds: 15 successThreshold: 1 httpGet: path: /healthz port: 80 timeoutSeconds: 2 + readinessProbe: + httpGet: + path: /healthz + port: 80 + initialDelaySeconds: 5 + periodSeconds: 5 image: "openresty/openresty:1.27.1.2-4-bullseye-fat" imagePullPolicy: IfNotPresent name: nginx diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index c6017ae7..2bf9176d 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -22,7 +22,6 @@ import ( "crypto/tls" "fmt" "net/http" - "net/url" "strings" "time" @@ -2507,17 +2506,10 @@ spec: It("WSS backend", func() { s.ResourceApplied("HTTPRoute", "nginx-wss", fmt.Sprintf(httprouteWithWSS, s.Namespace()), 1) - time.Sleep(6 * time.Second) By("verify wss connection") - u := url.URL{ - Scheme: "wss", - Host: s.GetAPISIXHTTPSEndpoint(), - Path: "/ws", - } - headers := http.Header{"Host": []string{"api6.com"}} - hostname := "api6.com" +<<<<<<< HEAD dialer := websocket.Dialer{ TLSClientConfig: &tls.Config{ @@ -2534,6 +2526,12 @@ spec: return dialErr }).WithTimeout(30*time.Second).WithPolling(2*time.Second).Should(Succeed(), "WebSocket handshake should succeed") Expect(resp.StatusCode).Should(Equal(http.StatusSwitchingProtocols)) +======= + conn := s.NewWebsocketClient(&tls.Config{ + InsecureSkipVerify: true, + ServerName: hostname, + }, "/ws", http.Header{"Host": []string{hostname}}) +>>>>>>> b70e22eb (fix: wss related tests are unstable (#2675)) defer func() { _ = conn.Close() diff --git a/test/e2e/ingress/ingress.go b/test/e2e/ingress/ingress.go index af00f16d..afdb03d3 100644 --- a/test/e2e/ingress/ingress.go +++ b/test/e2e/ingress/ingress.go @@ -23,7 +23,6 @@ import ( "encoding/base64" "fmt" "net/http" - "net/url" "strings" "time" @@ -992,14 +991,13 @@ spec: By("create Ingress") err := s.CreateResourceFromStringWithNamespace(fmt.Sprintf(ingress, s.Namespace()), s.Namespace()) Expect(err).NotTo(HaveOccurred(), "creating Ingress") - time.Sleep(5 * time.Second) By("verify Ingress works") - s.NewAPISIXClient(). - GET("/get"). - WithHost("ingress.example.com"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Host: "ingress.example.com", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("create additional gateway group to get new admin key") additionalGatewayGroupID, _, err = s.Deployer.CreateAdditionalGateway("gateway-proxy-update") @@ -1121,9 +1119,9 @@ spec: createSecret(s, _secretName) By("create Ingress") Expect(s.CreateResourceFromString(fmt.Sprintf(ingressWithWSS, s.Namespace()))).ShouldNot(HaveOccurred(), "creating Ingress") - time.Sleep(6 * time.Second) By("verify wss connection") +<<<<<<< HEAD u := url.URL{ Scheme: "wss", Host: s.GetAPISIXHTTPSEndpoint(), @@ -1145,6 +1143,13 @@ spec: return dialErr }).WithTimeout(30*time.Second).WithPolling(2*time.Second).Should(Succeed(), "WebSocket handshake should succeed") Expect(resp.StatusCode).Should(Equal(http.StatusSwitchingProtocols)) +======= + hostname := "api6.com" + conn := s.NewWebsocketClient(&tls.Config{ + InsecureSkipVerify: true, + ServerName: hostname, + }, "/ws", http.Header{"Host": []string{hostname}}) +>>>>>>> b70e22eb (fix: wss related tests are unstable (#2675)) defer func() { _ = conn.Close() diff --git a/test/e2e/scaffold/apisix_deployer.go b/test/e2e/scaffold/apisix_deployer.go index 62221879..5be98524 100644 --- a/test/e2e/scaffold/apisix_deployer.go +++ b/test/e2e/scaffold/apisix_deployer.go @@ -111,6 +111,19 @@ func (s *APISIXDeployer) AfterEach() { if output != "" { _, _ = fmt.Fprintln(GinkgoWriter, output) } + + _, _ = fmt.Fprintln(GinkgoWriter, "Dumping APISIX logs:") + output = s.GetDeploymentLogs("apisix") + if output != "" { + _, _ = fmt.Fprintln(GinkgoWriter, output) + } + if framework.ProviderType == framework.ProviderTypeAPISIXStandalone && s.adminTunnel != nil { + client := NewClient("http", s.adminTunnel.Endpoint()) + reporter := &ErrorReporter{} + body := client.GET("/apisix/admin/configs").WithHeader("X-API-KEY", s.AdminKey()).WithReporter(reporter).Expect().Body().Raw() + _, _ = fmt.Fprintln(GinkgoWriter, "Dumping APISIX configs:") + _, _ = fmt.Fprintln(GinkgoWriter, body) + } } // Delete all additional gateways diff --git a/test/e2e/scaffold/scaffold.go b/test/e2e/scaffold/scaffold.go index 9256a97d..1bd18fce 100644 --- a/test/e2e/scaffold/scaffold.go +++ b/test/e2e/scaffold/scaffold.go @@ -29,6 +29,7 @@ import ( "github.com/api7/gopkg/pkg/log" "github.com/gavv/httpexpect/v2" + "github.com/gorilla/websocket" "github.com/gruntwork-io/terratest/modules/k8s" "github.com/gruntwork-io/terratest/modules/testing" . "github.com/onsi/ginkgo/v2" //nolint:staticcheck @@ -579,3 +580,141 @@ func (s *Scaffold) GetMetricsEndpoint() string { s.addFinalizers(tunnel.Close) return fmt.Sprintf("http://%s/metrics", tunnel.Endpoint()) } +<<<<<<< HEAD +======= + +func (s *Scaffold) NewWebsocketClient(tls *tls.Config, path string, headers http.Header) *websocket.Conn { + var host = s.ApisixHTTPEndpoint() + var scheme = "ws" + if tls != nil { + scheme = "wss" + host = s.GetAPISIXHTTPSEndpoint() + } + + dialer := websocket.Dialer{ + TLSClientConfig: tls, + } + + u := url.URL{ + Scheme: scheme, + Host: host, + Path: path, + } + var conn *websocket.Conn + + s.RetryAssertion(func() error { + c, resp, err := dialer.Dial(u.String(), headers) + if err != nil { + return err + } + if resp == nil || resp.StatusCode != http.StatusSwitchingProtocols { + _ = c.Close() + return fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + conn = c + return nil + }).ShouldNot(HaveOccurred(), "establishing websocket connection") + return conn +} + +func (s *Scaffold) ControlAPIClient() (ControlAPIClient, error) { + tunnel := k8s.NewTunnel(s.kubectlOptions, k8s.ResourceTypeService, "apisix-control-api", 9090, 9090) + if err := tunnel.ForwardPortE(s.t); err != nil { + return nil, err + } + s.addFinalizers(tunnel.Close) + + return &controlAPI{ + client: NewClient("http", tunnel.Endpoint()), + }, nil +} + +func (s *Scaffold) EnsureNumService(controlAPIClient ControlAPIClient, matcher func(result int) bool) error { + times := 0 + return wait.PollUntilContextTimeout(context.Background(), 100*time.Millisecond, 10*time.Minute, true, func(ctx context.Context) (done bool, err error) { + times++ + results, _, err := controlAPIClient.ListServices() + if err != nil { + log.Errorw("failed to ListServices", zap.Error(err)) + return false, nil + } + if !matcher(len(results)) { + log.Debugw("number of effective services", zap.Int("number", len(results)), zap.Int("times", times)) + return false, nil + } + return true, nil + }) +} + +func (s *Scaffold) ExpectUpstream(controlAPIClient ControlAPIClient, name string, matcher func(upstream adctypes.Upstream) bool) error { + times := 0 + return wait.PollUntilContextTimeout(context.Background(), 1*time.Second, 10*time.Minute, true, func(ctx context.Context) (done bool, err error) { + times++ + upstreams, _, err := controlAPIClient.ListUpstreams() + if err != nil { + log.Errorw("failed to ListServices", zap.Error(err)) + return false, nil + } + for _, upstream := range upstreams { + upsValue := upstream.(map[string]any) + data, err := json.Marshal(upsValue["value"]) + if err != nil { + return false, fmt.Errorf("failed to marshal upstream: %v", err) + } + + var ups adctypes.Upstream + if err := json.Unmarshal(data, &ups); err != nil { + return false, fmt.Errorf("failed to unmarshal upstream: %v", err) + } + if name != "" && ups.Name != name { + continue + } + if ok := matcher(ups); !ok { + return false, nil + } + } + return true, nil + }) +} + +func (s *Scaffold) EnsureNumUpstreamNodes(controlAPIClient ControlAPIClient, name string, number int) error { + return s.ExpectUpstream(controlAPIClient, name, func(upstream adctypes.Upstream) bool { + if len(upstream.Nodes) != number { + log.Warnf("expect upstream: [%s] nodes num to be %d, but got %d", upstream.Name, number, len(upstream.Nodes)) + return false + } + return true + }) +} + +type ControlAPIClient interface { + ListServices() ([]any, int64, error) + ListUpstreams() ([]any, int64, error) +} + +type controlAPI struct { + client *httpexpect.Expect +} + +func (c *controlAPI) ListUpstreams() (result []any, total int64, err error) { + resp := c.client.Request(http.MethodGet, "/v1/upstreams").Expect() + if resp.Raw().StatusCode != http.StatusOK { + return nil, 0, fmt.Errorf("unexpected status code: %v, message: %s", resp.Raw().StatusCode, resp.Body().Raw()) + } + if err = json.Unmarshal([]byte(resp.Body().Raw()), &result); err != nil { + return nil, 0, fmt.Errorf("failed to unmarshal response body: %w", err) + } + return result, int64(len(result)), err +} + +func (c *controlAPI) ListServices() (result []any, total int64, err error) { + resp := c.client.Request(http.MethodGet, "/v1/services").Expect() + if resp.Raw().StatusCode != http.StatusOK { + return nil, 0, fmt.Errorf("unexpected status code: %v, message: %s", resp.Raw().StatusCode, resp.Body().Raw()) + } + if err = json.Unmarshal([]byte(resp.Body().Raw()), &result); err != nil { + return nil, 0, fmt.Errorf("failed to unmarshal response body: %w", err) + } + return result, int64(len(result)), err +} +>>>>>>> b70e22eb (fix: wss related tests are unstable (#2675)) From 2cd409eb3b09cf56f1db9ac8704319820c192b2b Mon Sep 17 00:00:00 2001 From: rongxin Date: Fri, 19 Dec 2025 12:22:48 +0800 Subject: [PATCH 2/2] resolve conflict --- test/e2e/crds/v2/route.go | 25 -------- test/e2e/gatewayapi/httproute.go | 19 ------ test/e2e/ingress/ingress.go | 24 ------- test/e2e/scaffold/scaffold.go | 104 ------------------------------- 4 files changed, 172 deletions(-) diff --git a/test/e2e/crds/v2/route.go b/test/e2e/crds/v2/route.go index 81adb9b0..c2347a94 100644 --- a/test/e2e/crds/v2/route.go +++ b/test/e2e/crds/v2/route.go @@ -2323,37 +2323,12 @@ spec: applier.MustApplyAPIv2(types.NamespacedName{Namespace: s.Namespace(), Name: "default"}, new(apiv2.ApisixRoute), fmt.Sprintf(apisixRouteWithBackendWSS, s.Namespace())) -<<<<<<< HEAD - By("verify wss connection with retry") - u := url.URL{ - Scheme: "wss", - Host: s.GetAPISIXHTTPSEndpoint(), - Path: "/ws", - } - headers := http.Header{"Host": []string{"api6.com"}} - dialer := websocket.Dialer{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - ServerName: "api6.com", - }, - } - - var conn *websocket.Conn - var resp *http.Response - Eventually(func() error { - var dialErr error - conn, resp, dialErr = dialer.Dial(u.String(), headers) - return dialErr - }).WithTimeout(30*time.Second).WithPolling(2*time.Second).Should(Succeed(), "WebSocket handshake should succeed") - Expect(resp.StatusCode).Should(Equal(http.StatusSwitchingProtocols)) -======= By("verify wss connection") hostname := "api6.com" conn := s.NewWebsocketClient(&tls.Config{ InsecureSkipVerify: true, ServerName: hostname, }, "/ws", http.Header{"Host": []string{hostname}}) ->>>>>>> b70e22eb (fix: wss related tests are unstable (#2675)) defer func() { _ = conn.Close() diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index 2bf9176d..75197a29 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -2509,29 +2509,10 @@ spec: By("verify wss connection") hostname := "api6.com" -<<<<<<< HEAD - - dialer := websocket.Dialer{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - ServerName: hostname, - }, - } - - var conn *websocket.Conn - var resp *http.Response - Eventually(func() error { - var dialErr error - conn, resp, dialErr = dialer.Dial(u.String(), headers) - return dialErr - }).WithTimeout(30*time.Second).WithPolling(2*time.Second).Should(Succeed(), "WebSocket handshake should succeed") - Expect(resp.StatusCode).Should(Equal(http.StatusSwitchingProtocols)) -======= conn := s.NewWebsocketClient(&tls.Config{ InsecureSkipVerify: true, ServerName: hostname, }, "/ws", http.Header{"Host": []string{hostname}}) ->>>>>>> b70e22eb (fix: wss related tests are unstable (#2675)) defer func() { _ = conn.Close() diff --git a/test/e2e/ingress/ingress.go b/test/e2e/ingress/ingress.go index afdb03d3..93cb486a 100644 --- a/test/e2e/ingress/ingress.go +++ b/test/e2e/ingress/ingress.go @@ -1121,35 +1121,11 @@ spec: Expect(s.CreateResourceFromString(fmt.Sprintf(ingressWithWSS, s.Namespace()))).ShouldNot(HaveOccurred(), "creating Ingress") By("verify wss connection") -<<<<<<< HEAD - u := url.URL{ - Scheme: "wss", - Host: s.GetAPISIXHTTPSEndpoint(), - Path: "/ws", - } - headers := http.Header{"Host": []string{"api6.com"}} - dialer := websocket.Dialer{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - ServerName: "api6.com", - }, - } - - var conn *websocket.Conn - var resp *http.Response - Eventually(func() error { - var dialErr error - conn, resp, dialErr = dialer.Dial(u.String(), headers) - return dialErr - }).WithTimeout(30*time.Second).WithPolling(2*time.Second).Should(Succeed(), "WebSocket handshake should succeed") - Expect(resp.StatusCode).Should(Equal(http.StatusSwitchingProtocols)) -======= hostname := "api6.com" conn := s.NewWebsocketClient(&tls.Config{ InsecureSkipVerify: true, ServerName: hostname, }, "/ws", http.Header{"Host": []string{hostname}}) ->>>>>>> b70e22eb (fix: wss related tests are unstable (#2675)) defer func() { _ = conn.Close() diff --git a/test/e2e/scaffold/scaffold.go b/test/e2e/scaffold/scaffold.go index 1bd18fce..fc2ee56b 100644 --- a/test/e2e/scaffold/scaffold.go +++ b/test/e2e/scaffold/scaffold.go @@ -580,8 +580,6 @@ func (s *Scaffold) GetMetricsEndpoint() string { s.addFinalizers(tunnel.Close) return fmt.Sprintf("http://%s/metrics", tunnel.Endpoint()) } -<<<<<<< HEAD -======= func (s *Scaffold) NewWebsocketClient(tls *tls.Config, path string, headers http.Header) *websocket.Conn { var host = s.ApisixHTTPEndpoint() @@ -616,105 +614,3 @@ func (s *Scaffold) NewWebsocketClient(tls *tls.Config, path string, headers http }).ShouldNot(HaveOccurred(), "establishing websocket connection") return conn } - -func (s *Scaffold) ControlAPIClient() (ControlAPIClient, error) { - tunnel := k8s.NewTunnel(s.kubectlOptions, k8s.ResourceTypeService, "apisix-control-api", 9090, 9090) - if err := tunnel.ForwardPortE(s.t); err != nil { - return nil, err - } - s.addFinalizers(tunnel.Close) - - return &controlAPI{ - client: NewClient("http", tunnel.Endpoint()), - }, nil -} - -func (s *Scaffold) EnsureNumService(controlAPIClient ControlAPIClient, matcher func(result int) bool) error { - times := 0 - return wait.PollUntilContextTimeout(context.Background(), 100*time.Millisecond, 10*time.Minute, true, func(ctx context.Context) (done bool, err error) { - times++ - results, _, err := controlAPIClient.ListServices() - if err != nil { - log.Errorw("failed to ListServices", zap.Error(err)) - return false, nil - } - if !matcher(len(results)) { - log.Debugw("number of effective services", zap.Int("number", len(results)), zap.Int("times", times)) - return false, nil - } - return true, nil - }) -} - -func (s *Scaffold) ExpectUpstream(controlAPIClient ControlAPIClient, name string, matcher func(upstream adctypes.Upstream) bool) error { - times := 0 - return wait.PollUntilContextTimeout(context.Background(), 1*time.Second, 10*time.Minute, true, func(ctx context.Context) (done bool, err error) { - times++ - upstreams, _, err := controlAPIClient.ListUpstreams() - if err != nil { - log.Errorw("failed to ListServices", zap.Error(err)) - return false, nil - } - for _, upstream := range upstreams { - upsValue := upstream.(map[string]any) - data, err := json.Marshal(upsValue["value"]) - if err != nil { - return false, fmt.Errorf("failed to marshal upstream: %v", err) - } - - var ups adctypes.Upstream - if err := json.Unmarshal(data, &ups); err != nil { - return false, fmt.Errorf("failed to unmarshal upstream: %v", err) - } - if name != "" && ups.Name != name { - continue - } - if ok := matcher(ups); !ok { - return false, nil - } - } - return true, nil - }) -} - -func (s *Scaffold) EnsureNumUpstreamNodes(controlAPIClient ControlAPIClient, name string, number int) error { - return s.ExpectUpstream(controlAPIClient, name, func(upstream adctypes.Upstream) bool { - if len(upstream.Nodes) != number { - log.Warnf("expect upstream: [%s] nodes num to be %d, but got %d", upstream.Name, number, len(upstream.Nodes)) - return false - } - return true - }) -} - -type ControlAPIClient interface { - ListServices() ([]any, int64, error) - ListUpstreams() ([]any, int64, error) -} - -type controlAPI struct { - client *httpexpect.Expect -} - -func (c *controlAPI) ListUpstreams() (result []any, total int64, err error) { - resp := c.client.Request(http.MethodGet, "/v1/upstreams").Expect() - if resp.Raw().StatusCode != http.StatusOK { - return nil, 0, fmt.Errorf("unexpected status code: %v, message: %s", resp.Raw().StatusCode, resp.Body().Raw()) - } - if err = json.Unmarshal([]byte(resp.Body().Raw()), &result); err != nil { - return nil, 0, fmt.Errorf("failed to unmarshal response body: %w", err) - } - return result, int64(len(result)), err -} - -func (c *controlAPI) ListServices() (result []any, total int64, err error) { - resp := c.client.Request(http.MethodGet, "/v1/services").Expect() - if resp.Raw().StatusCode != http.StatusOK { - return nil, 0, fmt.Errorf("unexpected status code: %v, message: %s", resp.Raw().StatusCode, resp.Body().Raw()) - } - if err = json.Unmarshal([]byte(resp.Body().Raw()), &result); err != nil { - return nil, 0, fmt.Errorf("failed to unmarshal response body: %w", err) - } - return result, int64(len(result)), err -} ->>>>>>> b70e22eb (fix: wss related tests are unstable (#2675))