diff --git a/conformance/tests/basic/inferencepool_invalid_epp_service.go b/conformance/tests/basic/inferencepool_invalid_epp_service.go index 73e6dc0c5..7e3bfaedf 100644 --- a/conformance/tests/basic/inferencepool_invalid_epp_service.go +++ b/conformance/tests/basic/inferencepool_invalid_epp_service.go @@ -17,18 +17,18 @@ limitations under the License. package basic import ( - "net/http" "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + inferenceapi "sigs.k8s.io/gateway-api-inference-extension/api/v1alpha2" "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" "sigs.k8s.io/gateway-api/conformance/utils/suite" "sigs.k8s.io/gateway-api/pkg/features" "sigs.k8s.io/gateway-api-inference-extension/conformance/tests" - gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" - conformancehttp "sigs.k8s.io/gateway-api/conformance/utils/http" + k8sutils "sigs.k8s.io/gateway-api-inference-extension/conformance/utils/kubernetes" + trafficutils "sigs.k8s.io/gateway-api-inference-extension/conformance/utils/traffic" ) func init() { @@ -49,30 +49,27 @@ var InferencePoolInvalidEPPService = suite.ConformanceTest{ routePath = "/invalid-epp-test" infraNamespace = "gateway-conformance-infra" appNamespace = "gateway-conformance-app-backend" + poolName = "pool-with-invalid-epp" ) routeNN := types.NamespacedName{Name: "httproute-for-invalid-epp-pool", Namespace: appNamespace} gwNN := types.NamespacedName{Name: "conformance-primary-gateway", Namespace: infraNamespace} + poolNN := types.NamespacedName{Name: poolName, Namespace: appNamespace} gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, s.Client, s.TimeoutConfig, s.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) - - t.Run("HTTPRoute has a ResolvedRefs Condition with status False and Reason BackendNotFound", func(t *testing.T) { - resolvedRefsCond := metav1.Condition{ - Type: string(gatewayv1.RouteConditionResolvedRefs), + t.Run("InferecePool has a ResolvedRefs Condition with status False", func(t *testing.T) { + acceptedCondition := metav1.Condition{ + Type: string(inferenceapi.InferencePoolConditionResolvedRefs), // Standard condition type Status: metav1.ConditionFalse, - Reason: string(gatewayv1.RouteReasonBackendNotFound), + Reason: "", // "" means we don't strictly check the Reason for this basic test. } - kubernetes.HTTPRouteMustHaveCondition(t, s.Client, s.TimeoutConfig, routeNN, gwNN, resolvedRefsCond) + k8sutils.InferencePoolMustHaveCondition(t, s.Client, poolNN, acceptedCondition) }) t.Run("Request to a route with an invalid backend reference receives a 500 response", func(t *testing.T) { - conformancehttp.MakeRequestAndExpectEventuallyConsistentResponse(t, s.RoundTripper, s.TimeoutConfig, gwAddr, conformancehttp.ExpectedResponse{ - Request: conformancehttp.Request{ - Path: routePath, - }, - Response: conformancehttp.Response{ - StatusCode: http.StatusInternalServerError, - }, + trafficutils.MakeRequestAndExpectEventuallyConsistentResponse(t, s.RoundTripper, s.TimeoutConfig, gwAddr, trafficutils.Request{ + Path: routePath, + ExpectedStatusCode: 5, // Expecting response status code 5XX. }) }) }, diff --git a/conformance/tests/basic/inferencepool_invalid_epp_service.yaml b/conformance/tests/basic/inferencepool_invalid_epp_service.yaml index 3a190369d..7d9295fe2 100644 --- a/conformance/tests/basic/inferencepool_invalid_epp_service.yaml +++ b/conformance/tests/basic/inferencepool_invalid_epp_service.yaml @@ -5,7 +5,7 @@ metadata: namespace: gateway-conformance-app-backend spec: selector: - app: "inference-model-1" + app: primary-inference-model-server targetPortNumber: 3000 extensionRef: name: non-existent-epp-svc diff --git a/conformance/utils/config/timing.go b/conformance/utils/config/timing.go index 861eb0f90..00aefdaa5 100644 --- a/conformance/utils/config/timing.go +++ b/conformance/utils/config/timing.go @@ -47,6 +47,7 @@ type InferenceExtensionTimeoutConfig struct { func DefaultInferenceExtensionTimeoutConfig() InferenceExtensionTimeoutConfig { config := gatewayconfig.DefaultTimeoutConfig() config.HTTPRouteMustHaveCondition = 300 * time.Second + config.RouteMustHaveParents = 200 * time.Second config.MaxTimeToConsistency = 200 * time.Second config.DefaultTestTimeout = 600 * time.Second return InferenceExtensionTimeoutConfig{ diff --git a/conformance/utils/traffic/traffic.go b/conformance/utils/traffic/traffic.go index b65863988..f53cc3236 100644 --- a/conformance/utils/traffic/traffic.go +++ b/conformance/utils/traffic/traffic.go @@ -159,7 +159,7 @@ func waitForConvergeToExpected( return false } - if err := gwhttp.CompareRequest(t, &request.Request, cReq, cRes, expectedResponse); err != nil { + if err := CompareRequestWithWildcardStatus(t, &request.Request, cReq, cRes, expectedResponse); err != nil { tlog.Logf(t, "Response expectation failed for request: %+v not ready yet: %v (after %v)", request.Request, err, elapsed) return false } @@ -169,6 +169,26 @@ func waitForConvergeToExpected( tlog.Logf(t, "Request passed") } +// CompareRequestWithWildcardStatus compares requests with wildcard status code support. +// It treats a single-digit expected code (e.g., 4) as a class wildcard (4xx), +// while standard 3-digit codes are matched exactly. +func CompareRequestWithWildcardStatus(t *testing.T, req *roundtripper.Request, cReq *roundtripper.CapturedRequest, cRes *roundtripper.CapturedResponse, expected gwhttp.ExpectedResponse) error { + if expected.Response.StatusCode < 1 || expected.Response.StatusCode >= 100 { + return gwhttp.CompareRequest(t, req, cReq, cRes, expected) + } + + expectedClass := expected.Response.StatusCode + actualClass := cRes.StatusCode / 100 + if expectedClass != actualClass { + return fmt.Errorf("expected status code class %dxx, but got %d", expectedClass, cRes.StatusCode) + } + + // StatusCode Class matches; update status code on a copy to allow the standard comparator to pass. + modifiedExpected := expected + modifiedExpected.Response.StatusCode = cRes.StatusCode + return gwhttp.CompareRequest(t, req, cReq, cRes, modifiedExpected) +} + // TODO: https://github.com/kubernetes-sigs/gateway-api-inference-extension/issues/1031 // remove this when sigs.k8s.io/gateway-api/conformance/utils/roundtripper is able to send request with body. // RequestWithBody extends roundtripper.Request to include a request body.