Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 13 additions & 16 deletions conformance/tests/basic/inferencepool_invalid_epp_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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.
})
})
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions conformance/utils/config/timing.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
22 changes: 21 additions & 1 deletion conformance/utils/traffic/traffic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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.
Expand Down