Skip to content

Commit d248065

Browse files
authored
[1.17] Fix route delegation flakes (#10705)
1 parent 04c9910 commit d248065

File tree

6 files changed

+115
-53
lines changed

6 files changed

+115
-53
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
changelog:
2+
- type: NON_USER_FACING
3+
issueLink: https://github.com/kgateway-dev/kgateway/issues/10114
4+
resolvesIssue: false
5+
description: Make the route delegation e2e tests more robust against flakes.

test/kubernetes/e2e/defaults/defaults.go

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ var (
2626

2727
CurlPodManifest = filepath.Join(util.MustGetThisDir(), "testdata", "curl_pod.yaml")
2828

29+
CurlPodLabelSelector = "app.kubernetes.io/name=curl"
30+
2931
HttpEchoPod = &corev1.Pod{
3032
ObjectMeta: metav1.ObjectMeta{
3133
Name: "http-echo",

test/kubernetes/e2e/features/route_delegation/suite.go

+62-16
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package route_delegation
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
"time"
78

89
. "github.com/onsi/gomega"
910
"github.com/stretchr/testify/assert"
1011
"github.com/stretchr/testify/suite"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1113
"k8s.io/apimachinery/pkg/types"
1214
"sigs.k8s.io/controller-runtime/pkg/client"
1315
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
@@ -16,7 +18,6 @@ import (
1618
testmatchers "github.com/solo-io/gloo/test/gomega/matchers"
1719
"github.com/solo-io/gloo/test/kubernetes/e2e"
1820
"github.com/solo-io/gloo/test/kubernetes/e2e/defaults"
19-
"github.com/solo-io/gloo/test/kubernetes/testutils/gloogateway"
2021
)
2122

2223
var _ e2e.NewSuiteFunc = NewTestingSuite
@@ -33,6 +34,9 @@ type tsuite struct {
3334
manifests map[string][]string
3435

3536
manifestObjects map[string][]client.Object
37+
38+
// resources from common manifest
39+
commonResources []client.Object
3640
}
3741

3842
func NewTestingSuite(ctx context.Context, testInst *e2e.TestInstallation) suite.TestingSuite {
@@ -44,21 +48,20 @@ func NewTestingSuite(ctx context.Context, testInst *e2e.TestInstallation) suite.
4448

4549
func (s *tsuite) SetupSuite() {
4650
s.manifests = map[string][]string{
47-
"TestBasic": {commonManifest, basicRoutesManifest},
48-
"TestRecursive": {commonManifest, recursiveRoutesManifest},
49-
"TestCyclic": {commonManifest, cyclicRoutesManifest},
50-
"TestInvalidChild": {commonManifest, invalidChildRoutesManifest},
51-
"TestHeaderQueryMatch": {commonManifest, headerQueryMatchRoutesManifest},
52-
"TestMultipleParents": {commonManifest, multipleParentsManifest},
53-
"TestInvalidChildValidStandalone": {commonManifest, invalidChildValidStandaloneManifest},
54-
"TestUnresolvedChild": {commonManifest, unresolvedChildManifest},
55-
"TestRouteOptions": {commonManifest, routeOptionsManifest},
56-
"TestMatcherInheritance": {commonManifest, matcherInheritanceManifest},
51+
"TestBasic": {basicRoutesManifest},
52+
"TestRecursive": {recursiveRoutesManifest},
53+
"TestCyclic": {cyclicRoutesManifest},
54+
"TestInvalidChild": {invalidChildRoutesManifest},
55+
"TestHeaderQueryMatch": {headerQueryMatchRoutesManifest},
56+
"TestMultipleParents": {multipleParentsManifest},
57+
"TestInvalidChildValidStandalone": {invalidChildValidStandaloneManifest},
58+
"TestUnresolvedChild": {unresolvedChildManifest},
59+
"TestRouteOptions": {routeOptionsManifest},
60+
"TestMatcherInheritance": {matcherInheritanceManifest},
5761
}
5862
// Not every resource that is applied needs to be verified. We are not testing `kubectl apply`,
5963
// but the below code demonstrates how it can be done if necessary
6064
s.manifestObjects = map[string][]client.Object{
61-
commonManifest: {proxyService, proxyDeployment, defaults.CurlPod, httpbinTeam1, httpbinTeam2, gateway},
6265
basicRoutesManifest: {routeRoot, routeTeam1, routeTeam2},
6366
cyclicRoutesManifest: {routeRoot, routeTeam1, routeTeam2},
6467
recursiveRoutesManifest: {routeRoot, routeTeam1, routeTeam2},
@@ -70,13 +73,56 @@ func (s *tsuite) SetupSuite() {
7073
routeOptionsManifest: {routeRoot, routeTeam1, routeTeam2},
7174
matcherInheritanceManifest: {routeParent1, routeParent2, routeTeam1},
7275
}
73-
clients, err := gloogateway.NewResourceClients(s.ctx, s.ti.ClusterContext)
74-
s.Require().NoError(err)
75-
s.ti.ResourceClients = clients
76+
77+
s.commonResources = []client.Object{
78+
// resources from manifest
79+
httpbinTeam1Service, httpbinTeam1Deployment, httpbinTeam2Service, httpbinTeam2Deployment, gateway,
80+
// deployer-generated resources
81+
proxyDeployment, proxyService,
82+
}
83+
84+
// set up common resources once
85+
err := s.ti.Actions.Kubectl().ApplyFile(s.ctx, commonManifest)
86+
s.Require().NoError(err, "can apply common manifest")
87+
s.ti.Assertions.EventuallyObjectsExist(s.ctx, s.commonResources...)
88+
// make sure pods are running
89+
s.ti.Assertions.EventuallyPodsRunning(s.ctx, httpbinTeam1Deployment.GetNamespace(), metav1.ListOptions{
90+
LabelSelector: "app=httpbin,version=v1",
91+
})
92+
s.ti.Assertions.EventuallyPodsRunning(s.ctx, httpbinTeam2Deployment.GetNamespace(), metav1.ListOptions{
93+
LabelSelector: "app=httpbin,version=v2",
94+
})
95+
s.ti.Assertions.EventuallyPodsRunning(s.ctx, proxyMeta.GetNamespace(), metav1.ListOptions{
96+
LabelSelector: fmt.Sprintf("app.kubernetes.io/name=%s", proxyMeta.GetName()),
97+
})
98+
99+
// set up curl once
100+
err = s.ti.Actions.Kubectl().ApplyFile(s.ctx, defaults.CurlPodManifest)
101+
s.Require().NoError(err, "can apply curl pod manifest")
102+
s.ti.Assertions.EventuallyPodsRunning(s.ctx, defaults.CurlPod.GetNamespace(), metav1.ListOptions{
103+
LabelSelector: defaults.CurlPodLabelSelector,
104+
})
76105
}
77106

78107
func (s *tsuite) TearDownSuite() {
79-
// nothing at the moment
108+
// clean up curl
109+
err := s.ti.Actions.Kubectl().DeleteFileSafe(s.ctx, defaults.CurlPodManifest)
110+
s.Require().NoError(err, "can delete curl pod manifest")
111+
s.ti.Assertions.EventuallyObjectsNotExist(s.ctx, defaults.CurlPod)
112+
113+
// clean up common resources
114+
err = s.ti.Actions.Kubectl().DeleteFileSafe(s.ctx, commonManifest)
115+
s.Require().NoError(err, "can delete common manifest")
116+
s.ti.Assertions.EventuallyObjectsNotExist(s.ctx, s.commonResources...)
117+
s.ti.Assertions.EventuallyPodsNotExist(s.ctx, httpbinTeam1Deployment.GetNamespace(), metav1.ListOptions{
118+
LabelSelector: "app=httpbin,version=v1",
119+
})
120+
s.ti.Assertions.EventuallyPodsNotExist(s.ctx, httpbinTeam2Deployment.GetNamespace(), metav1.ListOptions{
121+
LabelSelector: "app=httpbin,version=v2",
122+
})
123+
s.ti.Assertions.EventuallyPodsNotExist(s.ctx, proxyMeta.GetNamespace(), metav1.ListOptions{
124+
LabelSelector: fmt.Sprintf("app.kubernetes.io/name=%s", proxyMeta.GetName()),
125+
})
80126
}
81127

82128
func (s *tsuite) BeforeTest(suiteName, testName string) {

test/kubernetes/e2e/features/route_delegation/testdata/common.yaml

-24
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
# - team1/httpbin
55
# - team2/httpbin
66
#
7-
# Pods:
8-
# - curl/curl
9-
#
107
# Services:
118
# - team1/svc1
129
# - team2/svc2
@@ -126,27 +123,6 @@ spec:
126123
---
127124
apiVersion: v1
128125
kind: Namespace
129-
metadata:
130-
name: curl
131-
---
132-
apiVersion: v1
133-
kind: Pod
134-
metadata:
135-
name: curl
136-
namespace: curl
137-
labels:
138-
app: curl
139-
spec:
140-
containers:
141-
- name: curl
142-
image: curlimages/curl:7.83.1
143-
imagePullPolicy: IfNotPresent
144-
command:
145-
- "sleep"
146-
- "365d"
147-
---
148-
apiVersion: v1
149-
kind: Namespace
150126
metadata:
151127
name: infra
152128
---

test/kubernetes/e2e/features/route_delegation/types.go

+27-13
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,33 @@ import (
1212
)
1313

1414
const (
15-
// ref: test/kubernetes/e2e/features/delegation/testdata/common.yaml
1615
gatewayPort = 8080
1716
)
1817

19-
// ref: test/kubernetes/e2e/features/delegation/testdata/common.yaml
18+
// ref: common.yaml
2019
var (
2120
commonManifest = filepath.Join(util.MustGetThisDir(), "testdata", "common.yaml")
22-
proxyMeta = metav1.ObjectMeta{
23-
Name: "gloo-proxy-http-gateway",
24-
Namespace: "infra",
25-
}
26-
proxyDeployment = &appsv1.Deployment{ObjectMeta: proxyMeta}
27-
proxyService = &corev1.Service{ObjectMeta: proxyMeta}
28-
proxyHostPort = fmt.Sprintf("%s.%s.svc:%d", proxyService.Name, proxyService.Namespace, gatewayPort)
2921

30-
httpbinTeam1 = &appsv1.Deployment{
22+
// resources from common manifest
23+
httpbinTeam1Service = &corev1.Service{
24+
ObjectMeta: metav1.ObjectMeta{
25+
Name: "svc1",
26+
Namespace: "team1",
27+
},
28+
}
29+
httpbinTeam1Deployment = &appsv1.Deployment{
3130
ObjectMeta: metav1.ObjectMeta{
3231
Name: "httpbin",
3332
Namespace: "team1",
3433
},
3534
}
36-
httpbinTeam2 = &appsv1.Deployment{
35+
httpbinTeam2Service = &corev1.Service{
36+
ObjectMeta: metav1.ObjectMeta{
37+
Name: "svc2",
38+
Namespace: "team2",
39+
},
40+
}
41+
httpbinTeam2Deployment = &appsv1.Deployment{
3742
ObjectMeta: metav1.ObjectMeta{
3843
Name: "httpbin",
3944
Namespace: "team2",
@@ -45,9 +50,18 @@ var (
4550
Namespace: "infra",
4651
},
4752
}
53+
54+
// resources produced by deployer when Gateway is applied
55+
proxyMeta = metav1.ObjectMeta{
56+
Name: "gloo-proxy-http-gateway",
57+
Namespace: "infra",
58+
}
59+
proxyDeployment = &appsv1.Deployment{ObjectMeta: proxyMeta}
60+
proxyService = &corev1.Service{ObjectMeta: proxyMeta}
61+
proxyHostPort = fmt.Sprintf("%s.%s.svc:%d", proxyService.Name, proxyService.Namespace, gatewayPort)
4862
)
4963

50-
// ref: test/kubernetes/e2e/features/delegation/testdata/basic.yaml
64+
// ref: basic.yaml
5165
var (
5266
routeRoot = &gwv1.HTTPRoute{
5367
ObjectMeta: metav1.ObjectMeta{
@@ -85,7 +99,7 @@ var (
8599
pathTeam2 = "anything/team2/foo"
86100
)
87101

88-
// ref: test/kubernetes/e2e/features/route_delegation/inputs/invalid_child_valid_standalone.yaml
102+
// ref: invalid_child_valid_standalone.yaml
89103
var (
90104
gatewayTestPort = 8090
91105

test/kubernetes/testutils/assertions/pods.go

+19
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,22 @@ func (p *Provider) EventuallyPodsMatches(
4545
WithPolling(pollingInterval).
4646
Should(gomega.Succeed(), fmt.Sprintf("Failed to match pod in namespace %s", podNamespace))
4747
}
48+
49+
// EventuallyPodsNotExist asserts that the pod(s) are no longer present
50+
func (p *Provider) EventuallyPodsNotExist(
51+
ctx context.Context,
52+
podNamespace string,
53+
listOpt metav1.ListOptions,
54+
timeout ...time.Duration,
55+
) {
56+
currentTimeout, pollingInterval := helper.GetTimeouts(timeout...)
57+
58+
p.Gomega.Eventually(func(g gomega.Gomega) {
59+
pods, err := p.clusterContext.Clientset.CoreV1().Pods(podNamespace).List(ctx, listOpt)
60+
g.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to list pods")
61+
g.Expect(pods.Items).To(gomega.BeEmpty(), "Pods found")
62+
}).
63+
WithTimeout(currentTimeout).
64+
WithPolling(pollingInterval).
65+
Should(gomega.Succeed(), fmt.Sprintf("Failed to match pod in namespace %s", podNamespace))
66+
}

0 commit comments

Comments
 (0)