Skip to content

Commit f142921

Browse files
SinaChavoshiirar2
authored andcommitted
feat(conformance): Update InferencePoolResolvedRefsCondition test for E2E request validation (kubernetes-sigs#866)
* WIP tests for inferencepool_resolvedrefs_condition * update condition check * Add helper method for inf pool parrent status check * update manifests * update the test to match manifest * fix yaml files. * add SupportInferencePool * Add a helper function for HTTPRouteMustBeAcceptedAndResolved * Add a helper method InferencePoolMustBeAcceptedByParent * add todo for ensure http requests are routed correctly kubernetes-sigs#865 * Add http tests * update to use echo server instead * fix echo server port. * Add env var to include namespace and pod name for echo server resposne. * factor out the common HTTPResponse builder * shorten wait time * remove extra space * fix yaml formatting * clean up yaml file remove white space and optional fields. * change naming convention to primary secondary consistently. * add helper method for "MakeRequestAndExpectNotFound/Success * use config instead of inferenceconfig
1 parent 84dcfe0 commit f142921

File tree

6 files changed

+231
-87
lines changed

6 files changed

+231
-87
lines changed

conformance/resources/manifests/manifests.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ metadata:
1111
name: gateway-conformance-infra
1212
labels:
1313
gateway-conformance: infra
14-
1514
---
1615
# Namespace for application backends (potentially simulating model servers
1716
# or where InferencePools might reside in some tests).
@@ -21,7 +20,6 @@ metadata:
2120
name: gateway-conformance-app-backend
2221
labels:
2322
gateway-conformance: backend
24-
2523
---
2624
# Namespace for simple web server backends. This is expected by
2725
# the upstream conformance suite's Setup method.
@@ -31,7 +29,6 @@ metadata:
3129
name: gateway-conformance-web-backend
3230
labels:
3331
gateway-conformance: web-backend
34-
3532
---
3633
# A basic Gateway resource that allows HTTPRoutes from the same namespace.
3734
# Tests can use this as a parent reference for routes that target InferencePools.
@@ -55,7 +52,6 @@ spec:
5552
# Allows HTTPRoutes to attach, which can then reference InferencePools.
5653
- group: gateway.networking.k8s.io
5754
kind: HTTPRoute
58-
5955
---
6056
# --- Conformance Secondary Gateway Definition ---
6157
# A second generic Gateway resource for tests requiring multiple Gateways.

conformance/tests/basic/inferencepool_resolvedrefs_condition.go

Lines changed: 91 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ import (
2929
"sigs.k8s.io/gateway-api/pkg/features"
3030

3131
"sigs.k8s.io/gateway-api-inference-extension/conformance/tests"
32+
"sigs.k8s.io/gateway-api-inference-extension/conformance/utils/config"
3233
k8sutils "sigs.k8s.io/gateway-api-inference-extension/conformance/utils/kubernetes"
34+
trafficutils "sigs.k8s.io/gateway-api-inference-extension/conformance/utils/traffic"
3335
)
3436

3537
func init() {
@@ -46,59 +48,115 @@ var InferencePoolParentStatus = suite.ConformanceTest{
4648
},
4749
Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
4850
const (
49-
appBackendNamespace = "gateway-conformance-app-backend"
50-
infraNamespace = "gateway-conformance-infra"
51-
poolName = "multi-gateway-pool"
52-
sharedGateway1Name = "conformance-gateway"
53-
sharedGateway2Name = "conformance-secondary-gateway"
54-
httpRoute1Name = "httproute-for-gw1"
55-
httpRoute2Name = "httproute-for-gw2"
51+
appBackendNamespace = "gateway-conformance-app-backend"
52+
infraNamespace = "gateway-conformance-infra"
53+
poolName = "multi-gateway-pool"
54+
sharedPrimaryGatewayName = "conformance-gateway"
55+
sharedSecondaryGatewayName = "conformance-secondary-gateway"
56+
httpRoutePrimaryName = "httproute-for-primary-gw"
57+
httpRouteSecondaryName = "httproute-for-secondary-gw"
58+
hostnamePrimaryGw = "primary.example.com"
59+
pathPrimaryGw = "/primary-gateway-test"
60+
hostnameSecondaryGw = "secondary.example.com"
61+
pathSecondaryGw = "/secondary-gateway-test"
62+
backendServicePodName = "infra-backend-deployment"
5663
)
5764

5865
poolNN := types.NamespacedName{Name: poolName, Namespace: appBackendNamespace}
59-
httpRoute1NN := types.NamespacedName{Name: httpRoute1Name, Namespace: appBackendNamespace}
60-
httpRoute2NN := types.NamespacedName{Name: httpRoute2Name, Namespace: appBackendNamespace}
61-
gateway1NN := types.NamespacedName{Name: sharedGateway1Name, Namespace: infraNamespace}
62-
gateway2NN := types.NamespacedName{Name: sharedGateway2Name, Namespace: infraNamespace}
66+
httpRoutePrimaryNN := types.NamespacedName{Name: httpRoutePrimaryName, Namespace: appBackendNamespace}
67+
httpRouteSecondaryNN := types.NamespacedName{Name: httpRouteSecondaryName, Namespace: appBackendNamespace}
68+
gatewayPrimaryNN := types.NamespacedName{Name: sharedPrimaryGatewayName, Namespace: infraNamespace}
69+
gatewaySecondaryNN := types.NamespacedName{Name: sharedSecondaryGatewayName, Namespace: infraNamespace}
6370

64-
k8sutils.HTTPRouteMustBeAcceptedAndResolved(t, s.Client, s.TimeoutConfig, httpRoute1NN, gateway1NN)
65-
k8sutils.HTTPRouteMustBeAcceptedAndResolved(t, s.Client, s.TimeoutConfig, httpRoute2NN, gateway2NN)
71+
inferenceTimeoutConfig := config.DefaultInferenceExtensionTimeoutConfig()
6672

67-
t.Run("InferencePool should show Accepted:True by parents when referenced by multiple HTTPRoutes", func(t *testing.T) {
73+
k8sutils.HTTPRouteMustBeAcceptedAndResolved(t, s.Client, s.TimeoutConfig, httpRoutePrimaryNN, gatewayPrimaryNN)
74+
k8sutils.HTTPRouteMustBeAcceptedAndResolved(t, s.Client, s.TimeoutConfig, httpRouteSecondaryNN, gatewaySecondaryNN)
75+
76+
gwPrimaryAddr := k8sutils.GetGatewayEndpoint(t, s.Client, s.TimeoutConfig, gatewayPrimaryNN)
77+
gwSecondaryAddr := k8sutils.GetGatewayEndpoint(t, s.Client, s.TimeoutConfig, gatewaySecondaryNN)
78+
79+
t.Run("InferencePool should show Accepted:True by parents and be routable via multiple HTTPRoutes", func(t *testing.T) {
6880
k8sutils.InferencePoolMustBeAcceptedByParent(t, s.Client, poolNN)
69-
// TODO(#865) ensure requests are correctly routed to this InferencePool.
7081
t.Logf("InferencePool %s has parent status Accepted:True as expected with two references.", poolNN.String())
82+
83+
trafficutils.MakeRequestAndExpectSuccess(
84+
t,
85+
s.RoundTripper,
86+
s.TimeoutConfig,
87+
gwPrimaryAddr,
88+
hostnamePrimaryGw,
89+
pathPrimaryGw,
90+
backendServicePodName,
91+
appBackendNamespace,
92+
)
93+
94+
trafficutils.MakeRequestAndExpectSuccess(
95+
t,
96+
s.RoundTripper,
97+
s.TimeoutConfig,
98+
gwSecondaryAddr,
99+
hostnameSecondaryGw,
100+
pathSecondaryGw,
101+
backendServicePodName,
102+
appBackendNamespace,
103+
)
71104
})
72105

73-
t.Run("Delete httproute-for-gw1", func(t *testing.T) {
74-
httproute1 := &gatewayv1.HTTPRoute{
75-
ObjectMeta: metav1.ObjectMeta{Name: httpRoute1NN.Name, Namespace: httpRoute1NN.Namespace},
106+
t.Run("Delete httproute-for-primary-gw and verify InferencePool status and routing via secondary gw", func(t *testing.T) {
107+
httpRoutePrimary := &gatewayv1.HTTPRoute{
108+
ObjectMeta: metav1.ObjectMeta{Name: httpRoutePrimaryNN.Name, Namespace: httpRoutePrimaryNN.Namespace},
76109
}
77-
t.Logf("Deleting HTTPRoute %s", httpRoute1NN.String())
78-
require.NoError(t, s.Client.Delete(context.TODO(), httproute1), "failed to delete httproute-for-gw1")
79-
time.Sleep(s.TimeoutConfig.GatewayMustHaveCondition)
80-
})
110+
t.Logf("Deleting HTTPRoute %s", httpRoutePrimaryNN.String())
111+
require.NoError(t, s.Client.Delete(context.TODO(), httpRoutePrimary), "failed to delete httproute-for-primary-gw")
112+
113+
t.Logf("Waiting for %v for Gateway conditions to update after deleting HTTPRoute %s", inferenceTimeoutConfig.HTTPRouteDeletionReconciliationTimeout, httpRoutePrimaryNN.String()) //
114+
time.Sleep(inferenceTimeoutConfig.HTTPRouteDeletionReconciliationTimeout) //
81115

82-
t.Run("InferencePool should still show Accepted:True by parent after one HTTPRoute is deleted", func(t *testing.T) {
83116
k8sutils.InferencePoolMustBeAcceptedByParent(t, s.Client, poolNN)
84-
// TODO(#865) ensure requests are correctly routed to this InferencePool.
85117
t.Logf("InferencePool %s still has parent status Accepted:True as expected with one reference remaining.", poolNN.String())
118+
119+
trafficutils.MakeRequestAndExpectSuccess(
120+
t,
121+
s.RoundTripper,
122+
s.TimeoutConfig,
123+
gwSecondaryAddr,
124+
hostnameSecondaryGw,
125+
pathSecondaryGw,
126+
backendServicePodName,
127+
appBackendNamespace,
128+
)
129+
130+
trafficutils.MakeRequestAndExpectNotFound(
131+
t,
132+
s.RoundTripper,
133+
s.TimeoutConfig,
134+
gwPrimaryAddr,
135+
hostnamePrimaryGw,
136+
pathPrimaryGw,
137+
)
86138
})
87139

88-
t.Run("Delete httproute-for-gw2", func(t *testing.T) {
89-
httproute2 := &gatewayv1.HTTPRoute{
90-
ObjectMeta: metav1.ObjectMeta{Name: httpRoute2NN.Name, Namespace: httpRoute2NN.Namespace},
140+
t.Run("Delete httproute-for-secondary-gw and verify InferencePool has no parent statuses and is not routable", func(t *testing.T) {
141+
httpRouteSecondary := &gatewayv1.HTTPRoute{
142+
ObjectMeta: metav1.ObjectMeta{Name: httpRouteSecondaryNN.Name, Namespace: httpRouteSecondaryNN.Namespace},
91143
}
92-
t.Logf("Deleting HTTPRoute %s", httpRoute2NN.String())
93-
require.NoError(t, s.Client.Delete(context.TODO(), httproute2), "failed to delete httproute-for-gw2")
94-
})
144+
t.Logf("Deleting HTTPRoute %s", httpRouteSecondaryNN.String())
145+
require.NoError(t, s.Client.Delete(context.TODO(), httpRouteSecondary), "failed to delete httproute-for-secondary-gw")
95146

96-
t.Run("InferencePool should have no parent statuses after all HTTPRoutes are deleted", func(t *testing.T) {
97-
t.Logf("Waiting for InferencePool %s to have no parent statuses.", poolNN.String())
98147
k8sutils.InferencePoolMustHaveNoParents(t, s.Client, poolNN)
99148
t.Logf("InferencePool %s correctly shows no parent statuses, indicating it's no longer referenced.", poolNN.String())
149+
150+
trafficutils.MakeRequestAndExpectNotFound(
151+
t,
152+
s.RoundTripper,
153+
s.TimeoutConfig,
154+
gwSecondaryAddr,
155+
hostnameSecondaryGw,
156+
pathSecondaryGw,
157+
)
100158
})
101159

102-
t.Logf("InferencePoolResolvedRefsCondition completed.")
160+
t.Logf("InferencePoolResolvedRefsCondition test completed.")
103161
},
104162
}

conformance/tests/basic/inferencepool_resolvedrefs_condition.yaml

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# This manifest defines the initial resources for the
44
# inferencepool_resolvedrefs_condition.go conformance test.
55

6-
# --- Backend Deployment (using agnhost echo server) ---
6+
# --- Backend Deployment (using standard Gateway API echoserver) ---
77
# This Deployment provides Pods for the InferencePool to select.
88
apiVersion: apps/v1
99
kind: Deployment
@@ -13,7 +13,6 @@ metadata:
1313
labels:
1414
app: infra-backend
1515
spec:
16-
replicas: 1
1716
selector:
1817
matchLabels:
1918
app: infra-backend
@@ -23,22 +22,30 @@ spec:
2322
app: infra-backend
2423
spec:
2524
containers:
26-
- name: agnhost-echo
27-
image: k8s.gcr.io/e2e-test-images/agnhost:2.39
28-
args:
29-
- serve-hostname
30-
- --port=8080
25+
- name: echoserver
26+
image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd
3127
ports:
32-
- name: http
33-
containerPort: 8080
28+
- containerPort: 3000
3429
readinessProbe:
3530
httpGet:
3631
path: /
37-
port: 8080
32+
port: 3000
3833
initialDelaySeconds: 3
3934
periodSeconds: 5
4035
failureThreshold: 2
41-
36+
env:
37+
- name: POD_NAME
38+
valueFrom:
39+
fieldRef:
40+
fieldPath: metadata.name
41+
- name: NAMESPACE
42+
valueFrom:
43+
fieldRef:
44+
fieldPath: metadata.namespace
45+
- name: POD_IP
46+
valueFrom:
47+
fieldRef:
48+
fieldPath: status.podIP
4249
---
4350
# --- Backend Service ---
4451
# Service for the infra-backend-deployment.
@@ -52,36 +59,30 @@ spec:
5259
app: infra-backend
5360
ports:
5461
- name: http
55-
protocol: TCP
56-
port: 8080
57-
targetPort: 8080
62+
port: 3000
63+
targetPort: 3000
5864
- name: epp
5965
port: 9002
6066
targetPort: 9002
61-
6267
---
6368
# --- InferencePool Definition ---
6469
apiVersion: inference.networking.x-k8s.io/v1alpha2
6570
kind: InferencePool
6671
metadata:
67-
name: multi-gateway-pool # Name used in the Go test
68-
namespace: gateway-conformance-app-backend # Defined in base manifests.yaml
72+
name: multi-gateway-pool
73+
namespace: gateway-conformance-app-backend
6974
spec:
70-
# --- Selector (Required) ---
71-
# Selects the Pods belonging to this pool.
7275
selector:
7376
app: "infra-backend"
74-
# --- Target Port (Required) ---
75-
targetPortNumber: 8080
77+
targetPortNumber: 3000
7678
extensionRef:
7779
name: infra-backend-svc
78-
7980
---
80-
# --- HTTPRoute for Gateway 1 (conformance-gateway) ---
81+
# --- HTTPRoute for Primary Gateway (conformance-gateway) ---
8182
apiVersion: gateway.networking.k8s.io/v1
8283
kind: HTTPRoute
8384
metadata:
84-
name: httproute-for-gw1
85+
name: httproute-for-primary-gw
8586
namespace: gateway-conformance-app-backend
8687
spec:
8788
parentRefs:
@@ -91,24 +92,23 @@ spec:
9192
namespace: gateway-conformance-infra
9293
sectionName: http
9394
hostnames:
94-
- "gw1.example.com"
95+
- "primary.example.com"
9596
rules:
9697
- backendRefs:
9798
- group: inference.networking.x-k8s.io
9899
kind: InferencePool
99100
name: multi-gateway-pool
100-
port: 8080
101+
port: 3000
101102
matches:
102103
- path:
103104
type: PathPrefix
104-
value: /conformance-gateway-test
105-
105+
value: /primary-gateway-test
106106
---
107-
# --- HTTPRoute for Gateway 2 (conformance-secondary-gateway) ---
107+
# --- HTTPRoute for Secondary Gateway (conformance-secondary-gateway) ---
108108
apiVersion: gateway.networking.k8s.io/v1
109109
kind: HTTPRoute
110110
metadata:
111-
name: httproute-for-gw2
111+
name: httproute-for-secondary-gw
112112
namespace: gateway-conformance-app-backend
113113
spec:
114114
parentRefs:
@@ -124,8 +124,8 @@ spec:
124124
- group: inference.networking.x-k8s.io
125125
kind: InferencePool
126126
name: multi-gateway-pool
127-
port: 8080
127+
port: 3000
128128
matches:
129129
- path:
130130
type: PathPrefix
131-
value: /gateway-2-test
131+
value: /secondary-gateway-test

conformance/utils/config/timing.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,19 @@ type InferenceExtensionTimeoutConfig struct {
3737

3838
// GatewayObjectPollInterval is the polling interval used when waiting for a Gateway object to appear.
3939
GatewayObjectPollInterval time.Duration
40+
41+
// HTTPRouteDeletionReconciliationTimeout is the time to wait for controllers to reconcile
42+
// state after an HTTPRoute is deleted, before checking dependent resources or traffic.
43+
HTTPRouteDeletionReconciliationTimeout time.Duration
4044
}
4145

46+
// DefaultInferenceExtensionTimeoutConfig returns a new InferenceExtensionTimeoutConfig with default values.
4247
func DefaultInferenceExtensionTimeoutConfig() InferenceExtensionTimeoutConfig {
4348
return InferenceExtensionTimeoutConfig{
44-
TimeoutConfig: gatewayconfig.DefaultTimeoutConfig(),
49+
TimeoutConfig: gatewayconfig.DefaultTimeoutConfig(), // Initialize embedded struct
4550
InferencePoolMustHaveConditionTimeout: 300 * time.Second,
4651
InferencePoolMustHaveConditionInterval: 10 * time.Second,
4752
GatewayObjectPollInterval: 5 * time.Second,
53+
HTTPRouteDeletionReconciliationTimeout: 5 * time.Second,
4854
}
4955
}

conformance/utils/kubernetes/helpers.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,18 @@ func InferencePoolMustBeAcceptedByParent(t *testing.T, c client.Client, poolNN t
256256
InferencePoolMustHaveCondition(t, c, poolNN, acceptedByParentCondition)
257257
t.Logf("InferencePool %s is Accepted by a parent Gateway (Reason: %s)", poolNN.String(), gatewayv1.GatewayReasonAccepted)
258258
}
259+
260+
// GetGatewayEndpoint waits for the specified Gateway to have at least one address
261+
// and returns the address in "host:port" format.
262+
// It leverages the upstream Gateway API's WaitForGatewayAddress.
263+
func GetGatewayEndpoint(t *testing.T, k8sClient client.Client, timeoutConfig gatewayapiconfig.TimeoutConfig, gatewayNN types.NamespacedName) string {
264+
t.Helper()
265+
266+
t.Logf("Waiting for Gateway %s/%s to get an address...", gatewayNN.Namespace, gatewayNN.Name)
267+
gwAddr, err := gatewayk8sutils.WaitForGatewayAddress(t, k8sClient, timeoutConfig, gatewayk8sutils.NewGatewayRef(gatewayNN))
268+
require.NoError(t, err, "failed to get Gateway address for %s", gatewayNN.String())
269+
require.NotEmpty(t, gwAddr, "Gateway %s has no address", gatewayNN.String())
270+
271+
t.Logf("Gateway %s/%s has address: %s", gatewayNN.Namespace, gatewayNN.Name, gwAddr)
272+
return gwAddr
273+
}

0 commit comments

Comments
 (0)