Skip to content

Commit 45aedfe

Browse files
authored
Merge pull request #911 from zetxqx/conformance
feat(conformance): Add HTTPRoute port validation tests for InferencePool backends
2 parents 7d054af + 0eb6a29 commit 45aedfe

File tree

2 files changed

+363
-0
lines changed

2 files changed

+363
-0
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package basic
18+
19+
import (
20+
"testing"
21+
22+
"k8s.io/apimachinery/pkg/types"
23+
"sigs.k8s.io/gateway-api/conformance/utils/suite"
24+
"sigs.k8s.io/gateway-api/pkg/features"
25+
26+
// Local project imports
27+
"sigs.k8s.io/gateway-api-inference-extension/conformance/tests"
28+
k8sutils "sigs.k8s.io/gateway-api-inference-extension/conformance/utils/kubernetes"
29+
trafficutils "sigs.k8s.io/gateway-api-inference-extension/conformance/utils/traffic"
30+
)
31+
32+
func init() {
33+
tests.ConformanceTests = append(tests.ConformanceTests, InferencePoolHTTPRoutePortValidation)
34+
}
35+
36+
var InferencePoolHTTPRoutePortValidation = suite.ConformanceTest{
37+
ShortName: "InferencePoolHTTPRoutePortValidation",
38+
Description: "Validates HTTPRoute backendRef port configurations (unspecified, matching, non-matching) when referencing an InferencePool, and checks resulting status conditions.",
39+
Manifests: []string{"tests/basic/inferencepool_httproute_port_validation.yaml"},
40+
Features: []features.FeatureName{
41+
features.FeatureName("SupportInferencePool"),
42+
features.SupportGateway,
43+
},
44+
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
45+
const (
46+
appBackendNamespace = "gateway-conformance-app-backend"
47+
infraNamespace = "gateway-conformance-infra"
48+
gatewayName = "conformance-gateway"
49+
poolName = "target-pool-port-validation"
50+
backendDeploymentName = "infra-backend-deployment-port-test"
51+
)
52+
53+
gatewayNN := types.NamespacedName{Name: gatewayName, Namespace: infraNamespace}
54+
poolNN := types.NamespacedName{Name: poolName, Namespace: appBackendNamespace}
55+
56+
gatewayAddr := k8sutils.GetGatewayEndpoint(t, s.Client, s.TimeoutConfig, gatewayNN)
57+
58+
t.Run("Scenario 1: HTTPRoute backendRef to InferencePool with Port Unspecified", func(t *testing.T) {
59+
routeNN := types.NamespacedName{Name: "httproute-pool-port-unspecified", Namespace: appBackendNamespace}
60+
hostname := "port-unspecified.example.com"
61+
path := "/test-port-unspecified"
62+
63+
k8sutils.HTTPRouteMustBeAcceptedAndResolved(t, s.Client, s.TimeoutConfig, routeNN, gatewayNN)
64+
k8sutils.InferencePoolMustBeAcceptedByParent(t, s.Client, poolNN)
65+
66+
trafficutils.MakeRequestAndExpectSuccess(
67+
t,
68+
s.RoundTripper,
69+
s.TimeoutConfig,
70+
gatewayAddr,
71+
hostname,
72+
path,
73+
backendDeploymentName,
74+
appBackendNamespace,
75+
)
76+
})
77+
78+
t.Run("Scenario 2: HTTPRoute backendRef to InferencePool with Port Specified and Matching", func(t *testing.T) {
79+
routeNN := types.NamespacedName{Name: "httproute-pool-port-matching", Namespace: appBackendNamespace}
80+
hostname := "port-matching.example.com"
81+
path := "/test-port-matching"
82+
83+
k8sutils.HTTPRouteMustBeAcceptedAndResolved(t, s.Client, s.TimeoutConfig, routeNN, gatewayNN)
84+
k8sutils.InferencePoolMustBeAcceptedByParent(t, s.Client, poolNN)
85+
86+
trafficutils.MakeRequestAndExpectSuccess(
87+
t,
88+
s.RoundTripper,
89+
s.TimeoutConfig,
90+
gatewayAddr,
91+
hostname,
92+
path,
93+
backendDeploymentName,
94+
appBackendNamespace,
95+
)
96+
})
97+
98+
// TODO: Add a warning check after the required change is made per discussion in github.com/kubernetes-sigs/gateway-api-inference-extension/discussions/918
99+
t.Run("Scenario 3: HTTPRoute backendRef to InferencePool with Port Specified and Non-Matching. Request still passing because HTTP Port is ignored when inferencePool is backendRef", func(t *testing.T) {
100+
routeNN := types.NamespacedName{Name: "httproute-pool-port-non-matching", Namespace: appBackendNamespace}
101+
hostname := "port-non-matching.example.com"
102+
path := "/test-port-non-matching"
103+
104+
k8sutils.HTTPRouteMustBeAcceptedAndResolved(t, s.Client, s.TimeoutConfig, routeNN, gatewayNN)
105+
k8sutils.InferencePoolMustBeAcceptedByParent(t, s.Client, poolNN)
106+
107+
trafficutils.MakeRequestAndExpectSuccess(
108+
t,
109+
s.RoundTripper,
110+
s.TimeoutConfig,
111+
gatewayAddr,
112+
hostname,
113+
path,
114+
backendDeploymentName,
115+
appBackendNamespace,
116+
)
117+
})
118+
},
119+
}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# conformance/tests/basic/inferencepool_httproute_port_validation.yaml
2+
3+
# --- Backend Deployment (reusing standard echoserver) ---
4+
5+
apiVersion: apps/v1
6+
kind: Deployment
7+
metadata:
8+
name: infra-backend-deployment-port-test
9+
namespace: gateway-conformance-app-backend
10+
labels:
11+
app: infra-backend-port-test
12+
spec:
13+
replicas: 1
14+
selector:
15+
matchLabels:
16+
app: infra-backend-port-test
17+
template:
18+
metadata:
19+
labels:
20+
app: infra-backend-port-test
21+
spec:
22+
containers:
23+
- name: echoserver
24+
image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd
25+
ports:
26+
- containerPort: 3000
27+
readinessProbe:
28+
httpGet:
29+
path: /
30+
port: 3000
31+
initialDelaySeconds: 3
32+
periodSeconds: 5
33+
failureThreshold: 2
34+
env:
35+
- name: POD_NAME
36+
valueFrom:
37+
fieldRef:
38+
fieldPath: metadata.name
39+
- name: NAMESPACE
40+
valueFrom:
41+
fieldRef:
42+
fieldPath: metadata.namespace
43+
---
44+
# --- Backend Service ---
45+
# Service for the infra-backend-deployment-port-test.
46+
apiVersion: v1
47+
kind: Service
48+
metadata:
49+
name: infra-backend-svc-port-test
50+
namespace: gateway-conformance-app-backend
51+
spec:
52+
selector:
53+
app: infra-backend-port-test
54+
ports:
55+
- name: http
56+
port: 3000
57+
targetPort: 3000
58+
---
59+
# --- InferencePool Definition ---
60+
apiVersion: inference.networking.x-k8s.io/v1alpha2
61+
kind: InferencePool
62+
metadata:
63+
name: target-pool-port-validation
64+
namespace: gateway-conformance-app-backend
65+
spec:
66+
selector:
67+
app: "infra-backend-port-test"
68+
targetPortNumber: 3000
69+
extensionRef:
70+
name: target-pool-port-validation-epp
71+
---
72+
apiVersion: v1
73+
kind: Service
74+
metadata:
75+
name: target-pool-port-validation-epp
76+
namespace: gateway-conformance-app-backend
77+
spec:
78+
selector:
79+
app: target-pool-port-validation-epp
80+
ports:
81+
- protocol: TCP
82+
port: 9002
83+
targetPort: 9002
84+
appProtocol: http2
85+
type: ClusterIP
86+
---
87+
apiVersion: apps/v1
88+
kind: Deployment
89+
metadata:
90+
name: target-pool-port-validation-epp
91+
namespace: gateway-conformance-app-backend
92+
labels:
93+
app: target-pool-port-validation-epp
94+
spec:
95+
replicas: 1
96+
selector:
97+
matchLabels:
98+
app: target-pool-port-validation-epp
99+
template:
100+
metadata:
101+
labels:
102+
app: target-pool-port-validation-epp
103+
spec:
104+
terminationGracePeriodSeconds: 130
105+
containers:
106+
- name: epp
107+
image: us-central1-docker.pkg.dev/k8s-staging-images/gateway-api-inference-extension/epp:main
108+
imagePullPolicy: Always
109+
args:
110+
- -poolName
111+
- "target-pool-port-validation"
112+
- "-poolNamespace"
113+
- "gateway-conformance-app-backend"
114+
- -v
115+
- "4"
116+
- --zap-encoder
117+
- "json"
118+
- -grpcPort
119+
- "9002"
120+
- -grpcHealthPort
121+
- "9003"
122+
ports:
123+
- containerPort: 9002
124+
- containerPort: 9003
125+
- name: metrics
126+
containerPort: 9090
127+
livenessProbe:
128+
grpc:
129+
port: 9003
130+
service: inference-extension
131+
initialDelaySeconds: 5
132+
periodSeconds: 10
133+
readinessProbe:
134+
grpc:
135+
port: 9003
136+
service: inference-extension
137+
initialDelaySeconds: 5
138+
periodSeconds: 10
139+
---
140+
# --- HTTPRoute Scenario 1: Port Unspecified ---
141+
apiVersion: gateway.networking.k8s.io/v1
142+
kind: HTTPRoute
143+
metadata:
144+
name: httproute-pool-port-unspecified
145+
namespace: gateway-conformance-app-backend
146+
spec:
147+
parentRefs:
148+
- group: gateway.networking.k8s.io
149+
kind: Gateway
150+
name: conformance-gateway
151+
namespace: gateway-conformance-infra
152+
sectionName: http
153+
hostnames:
154+
- "port-unspecified.example.com"
155+
rules:
156+
- backendRefs:
157+
- group: inference.networking.x-k8s.io
158+
kind: InferencePool
159+
name: target-pool-port-validation
160+
# Port is intentionally unspecified here
161+
matches:
162+
- path:
163+
type: PathPrefix
164+
value: /test-port-unspecified
165+
---
166+
# --- HTTPRoute Scenario 2: Port Matching ---
167+
apiVersion: gateway.networking.k8s.io/v1
168+
kind: HTTPRoute
169+
metadata:
170+
name: httproute-pool-port-matching
171+
namespace: gateway-conformance-app-backend
172+
spec:
173+
parentRefs:
174+
- group: gateway.networking.k8s.io
175+
kind: Gateway
176+
name: conformance-gateway
177+
namespace: gateway-conformance-infra
178+
sectionName: http
179+
hostnames:
180+
- "port-matching.example.com"
181+
rules:
182+
- backendRefs:
183+
- group: inference.networking.x-k8s.io
184+
kind: InferencePool
185+
name: target-pool-port-validation
186+
port: 3000 # Port matches InferencePool's targetPortNumber
187+
matches:
188+
- path:
189+
type: PathPrefix
190+
value: /test-port-matching
191+
---
192+
# --- HTTPRoute Scenario 3: Port Non-Matching ---
193+
apiVersion: gateway.networking.k8s.io/v1
194+
kind: HTTPRoute
195+
metadata:
196+
name: httproute-pool-port-non-matching
197+
namespace: gateway-conformance-app-backend
198+
spec:
199+
parentRefs:
200+
- group: gateway.networking.k8s.io
201+
kind: Gateway
202+
name: conformance-gateway
203+
namespace: gateway-conformance-infra
204+
sectionName: http
205+
hostnames:
206+
- "port-non-matching.example.com"
207+
rules:
208+
- backendRefs:
209+
- group: inference.networking.x-k8s.io
210+
kind: InferencePool
211+
name: target-pool-port-validation
212+
port: 8888 # Port does NOT match InferencePool's targetPortNumber
213+
matches:
214+
- path:
215+
type: PathPrefix
216+
value: /test-port-non-matching
217+
---
218+
# --- Conformance EPP Requried Role and RoleBindings ---
219+
apiVersion: rbac.authorization.k8s.io/v1
220+
kind: Role
221+
metadata:
222+
name: inference-model-reader
223+
namespace: gateway-conformance-app-backend
224+
rules:
225+
- apiGroups: ["inference.networking.x-k8s.io"]
226+
resources: ["inferencemodels", "inferencepools"]
227+
verbs: ["get", "list", "watch"]
228+
- apiGroups: [""]
229+
resources: ["pods"]
230+
verbs: ["get", "list", "watch"]
231+
---
232+
apiVersion: rbac.authorization.k8s.io/v1
233+
kind: RoleBinding
234+
metadata:
235+
name: epp-to-inference-model-reader
236+
namespace: gateway-conformance-app-backend
237+
subjects:
238+
- kind: ServiceAccount
239+
name: default
240+
namespace: gateway-conformance-app-backend
241+
roleRef:
242+
kind: Role
243+
name: inference-model-reader
244+
apiGroup: rbac.authorization.k8s.io

0 commit comments

Comments
 (0)