openmeter / api /v3 /oasmiddleware /validator_test.go
Leon4gr45's picture
Upload folder using huggingface_hub (part 4)
1f10f31 verified
Raw
History Blame Contribute Delete
4.52 kB
package oasmiddleware_test
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/getkin/kin-openapi/routers"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
api "github.com/openmeterio/openmeter/api/v3"
"github.com/openmeterio/openmeter/api/v3/oasmiddleware"
)
// TestValidateResponse_Violation proves that the ValidateResponse middleware fires its
// error hook when a handler returns a response body that violates the OpenAPI spec.
//
// GET /openmeter/addons requires a 200 body with both "data" and "meta" fields.
// Returning {} omits both required fields and must trigger a violation.
func TestValidateResponse_Violation(t *testing.T) {
swagger, err := api.GetSwagger()
require.NoError(t, err)
swagger.Servers = nil
router, err := oasmiddleware.NewValidationRouter(t.Context(), swagger, &oasmiddleware.ValidationRouterOpts{
DeleteServers: true,
})
require.NoError(t, err)
var gotErr error
mw := oasmiddleware.ValidateResponse(router, oasmiddleware.ValidateResponseOption{
ResponseValidationErrorHook: func(err error, r *http.Request) {
gotErr = err
},
})
badHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{}`))
})
req := httptest.NewRequest(http.MethodGet, "/openmeter/addons", nil)
rec := httptest.NewRecorder()
mw(badHandler).ServeHTTP(rec, req)
assert.Error(t, gotErr, "expected a validation error for missing required fields")
t.Logf("validation error (expected): %v", gotErr)
}
// TestValidateResponse_Clean proves that a well-formed response does not trigger the error hook.
func TestValidateResponse_Clean(t *testing.T) {
swagger, err := api.GetSwagger()
require.NoError(t, err)
swagger.Servers = nil
router, err := oasmiddleware.NewValidationRouter(t.Context(), swagger, &oasmiddleware.ValidationRouterOpts{
DeleteServers: true,
})
require.NoError(t, err)
var gotErr error
mw := oasmiddleware.ValidateResponse(router, oasmiddleware.ValidateResponseOption{
ResponseValidationErrorHook: func(err error, r *http.Request) {
gotErr = err
},
})
goodHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"data":[],"meta":{"page":{"number":0,"size":100,"total":0}}}`))
})
req := httptest.NewRequest(http.MethodGet, "/openmeter/addons", nil)
rec := httptest.NewRecorder()
mw(goodHandler).ServeHTTP(rec, req)
assert.NoError(t, gotErr, "expected no validation error for a well-formed response")
}
// TestValidateResponse_RouteFilterSkipsValidation proves that when RouteFilterHook returns false,
// the response body is neither buffered nor validated — even if it would otherwise violate the spec.
// The filter is the per-route gate that lets callers (e.g. unstable-only mode) avoid the
// buffering overhead on routes they don't care about.
func TestValidateResponse_RouteFilterSkipsValidation(t *testing.T) {
swagger, err := api.GetSwagger()
require.NoError(t, err)
swagger.Servers = nil
router, err := oasmiddleware.NewValidationRouter(t.Context(), swagger, &oasmiddleware.ValidationRouterOpts{
DeleteServers: true,
})
require.NoError(t, err)
var (
gotErr error
filteredRoute *routers.Route
)
mw := oasmiddleware.ValidateResponse(router, oasmiddleware.ValidateResponseOption{
RouteFilterHook: func(route *routers.Route) bool {
filteredRoute = route
return false
},
ResponseValidationErrorHook: func(err error, r *http.Request) {
gotErr = err
},
})
// Body that would fail validation if the filter let it through.
badHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{}`))
})
req := httptest.NewRequest(http.MethodGet, "/openmeter/addons", nil)
rec := httptest.NewRecorder()
mw(badHandler).ServeHTTP(rec, req)
require.NotNil(t, filteredRoute, "RouteFilterHook should have been invoked with the matched route")
assert.Equal(t, "/openmeter/addons", filteredRoute.Path)
assert.NoError(t, gotErr, "validation error hook must not fire when the filter returns false")
assert.Equal(t, http.StatusOK, rec.Code, "client response should still be served")
assert.Equal(t, `{}`, rec.Body.String(), "client response body should still be served")
}