Skip to content

Commit e7a278e

Browse files
committed
feat(conformance): add conformance test for endpoint served.
1 parent c7487f2 commit e7a278e

File tree

3 files changed

+135
-2
lines changed

3 files changed

+135
-2
lines changed

conformance/resources/base.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ spec:
200200
terminationGracePeriodSeconds: 130
201201
containers:
202202
- name: epp
203-
image: us-central1-docker.pkg.dev/k8s-staging-images/gateway-api-inference-extension/epp:v20251105-cbb8928
203+
image: us-central1-docker.pkg.dev/bobzetian-gke-dev/gateway-api-inference-extension/epp:latest
204204
imagePullPolicy: Always
205205
args:
206206
- --pool-name
@@ -298,7 +298,7 @@ spec:
298298
terminationGracePeriodSeconds: 130
299299
containers:
300300
- name: epp
301-
image: us-central1-docker.pkg.dev/k8s-staging-images/gateway-api-inference-extension/epp:v20251105-cbb8928
301+
image: us-central1-docker.pkg.dev/bobzetian-gke-dev/gateway-api-inference-extension/epp:latest
302302
imagePullPolicy: Always
303303
args:
304304
- --pool-name
@@ -560,6 +560,7 @@ data:
560560
kind: EndpointPickerConfig
561561
plugins:
562562
- type: header-based-testing-filter
563+
- type: destination-endpoint-served-verifier
563564
schedulingProfiles:
564565
- name: conformance-profile
565566
plugins:
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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 tests
18+
19+
import (
20+
"net/http"
21+
"testing"
22+
23+
"github.com/stretchr/testify/require"
24+
"k8s.io/apimachinery/pkg/types"
25+
gwhttp "sigs.k8s.io/gateway-api/conformance/utils/http"
26+
"sigs.k8s.io/gateway-api/conformance/utils/suite"
27+
"sigs.k8s.io/gateway-api/pkg/features"
28+
29+
"sigs.k8s.io/gateway-api-inference-extension/conformance/resources"
30+
k8sutils "sigs.k8s.io/gateway-api-inference-extension/conformance/utils/kubernetes"
31+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/requestcontrol/plugins/test"
32+
testscheduling "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework/plugins/test"
33+
)
34+
35+
func init() {
36+
ConformanceTests = append(ConformanceTests, GatewayDestinationEndpointServed)
37+
}
38+
39+
var GatewayDestinationEndpointServed = suite.ConformanceTest{
40+
ShortName: "GatewayDestinationEndpointServed",
41+
Description: "A conformance test to verify that the gateway correctly reports the endpoint that served the request.",
42+
Manifests: []string{"tests/gateway_destination_endpoint_served.yaml"},
43+
Features: []features.FeatureName{
44+
features.FeatureName("SupportInferencePool"),
45+
features.SupportGateway,
46+
},
47+
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
48+
const (
49+
hostname = "primary.example.com"
50+
path = "/destination-endpoint-served-test"
51+
)
52+
53+
httpRouteNN := types.NamespacedName{Name: "httproute-for-destination-endpoint-served", Namespace: resources.AppBackendNamespace}
54+
gatewayNN := resources.PrimaryGatewayNN
55+
poolNN := resources.PrimaryInferencePoolNN
56+
backendPodLabels := map[string]string{"app": resources.PrimaryModelServerAppLabel}
57+
58+
t.Log("Verifying HTTPRoute and InferencePool are accepted and the Gateway has an address.")
59+
k8sutils.HTTPRouteMustBeAcceptedAndResolved(t, s.Client, s.TimeoutConfig, httpRouteNN, gatewayNN)
60+
k8sutils.InferencePoolMustBeAcceptedByParent(t, s.Client, poolNN, gatewayNN)
61+
gwAddr := k8sutils.GetGatewayEndpoint(t, s.Client, s.TimeoutConfig, gatewayNN)
62+
63+
t.Logf("Fetching backend pods with labels: %v", backendPodLabels)
64+
pods, err := k8sutils.GetPodsWithLabel(t, s.Client, resources.AppBackendNamespace, backendPodLabels, s.TimeoutConfig)
65+
require.NoError(t, err, "Failed to get backend pods")
66+
require.Len(t, pods, resources.ModelServerPodReplicas, "Expected to find %d backend pods, but found %d.", resources.ModelServerPodReplicas, len(pods))
67+
68+
podIPs := make([]string, len(pods))
69+
podNames := make([]string, len(pods))
70+
for i, pod := range pods {
71+
podIPs[i] = pod.Status.PodIP
72+
podNames[i] = pod.Name
73+
}
74+
75+
requestBody := `{
76+
"model": "conformance-fake-model",
77+
"prompt": "Write as if you were a critic: San Francisco"
78+
}`
79+
t.Run("Request is served by the selected backend pod", func(t *testing.T) {
80+
for i := 0; i < len(pods); i++ {
81+
gwhttp.MakeRequestAndExpectEventuallyConsistentResponse(
82+
t,
83+
s.RoundTripper,
84+
s.TimeoutConfig,
85+
gwAddr,
86+
gwhttp.ExpectedResponse{
87+
Request: gwhttp.Request{
88+
Host: hostname,
89+
Path: path,
90+
Method: http.MethodPost,
91+
Body: requestBody,
92+
Headers: map[string]string{
93+
testscheduling.HeaderTestEppEndPointSelectionKey: podIPs[i],
94+
},
95+
},
96+
Response: gwhttp.Response{
97+
StatusCodes: []int{http.StatusOK},
98+
Headers: map[string]string{
99+
test.ConformanceTestResultHeader: podIPs[i] + ":3000", // The echo server's port is 3000.
100+
},
101+
},
102+
Backend: podNames[i],
103+
Namespace: resources.AppBackendNamespace,
104+
},
105+
)
106+
}
107+
})
108+
},
109+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
apiVersion: gateway.networking.k8s.io/v1
2+
kind: HTTPRoute
3+
metadata:
4+
name: httproute-for-destination-endpoint-served
5+
namespace: inference-conformance-app-backend
6+
spec:
7+
parentRefs:
8+
- group: gateway.networking.k8s.io
9+
kind: Gateway
10+
name: conformance-primary
11+
namespace: inference-conformance-infra
12+
sectionName: http
13+
hostnames:
14+
- "primary.example.com"
15+
rules:
16+
- backendRefs:
17+
- group: inference.networking.k8s.io
18+
kind: InferencePool
19+
name: primary-inference-pool
20+
matches:
21+
- path:
22+
type: PathPrefix
23+
value: /destination-endpoint-served-test

0 commit comments

Comments
 (0)