mirror of
https://github.com/davidebianchi/gswagger.git
synced 2025-12-23 23:38:43 -05:00
444 lines
13 KiB
Go
444 lines
13 KiB
Go
package swagger
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/davidebianchi/gswagger/support/gorilla"
|
|
"github.com/getkin/kin-openapi/openapi3"
|
|
"github.com/gorilla/mux"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewRouter(t *testing.T) {
|
|
muxRouter := mux.NewRouter()
|
|
mAPIRouter := gorilla.NewRouter(muxRouter)
|
|
|
|
info := &openapi3.Info{
|
|
Title: "my title",
|
|
Version: "my version",
|
|
}
|
|
openapi := &openapi3.T{
|
|
Info: info,
|
|
Paths: openapi3.Paths{},
|
|
}
|
|
|
|
t.Run("not ok - invalid Openapi option", func(t *testing.T) {
|
|
r, err := NewRouter(mAPIRouter, Options{})
|
|
|
|
require.Nil(t, r)
|
|
require.EqualError(t, err, fmt.Sprintf("%s: swagger is required", ErrValidatingSwagger))
|
|
})
|
|
|
|
t.Run("ok - with default context", func(t *testing.T) {
|
|
r, err := NewRouter(mAPIRouter, Options{
|
|
Openapi: openapi,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, &Router[gorilla.HandlerFunc, gorilla.Route]{
|
|
context: context.Background(),
|
|
router: mAPIRouter,
|
|
swaggerSchema: openapi,
|
|
jsonDocumentationPath: DefaultJSONDocumentationPath,
|
|
yamlDocumentationPath: DefaultYAMLDocumentationPath,
|
|
}, r)
|
|
})
|
|
|
|
t.Run("ok - with custom context", func(t *testing.T) {
|
|
type key struct{}
|
|
ctx := context.WithValue(context.Background(), key{}, "value")
|
|
r, err := NewRouter(mAPIRouter, Options{
|
|
Openapi: openapi,
|
|
Context: ctx,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, &Router[gorilla.HandlerFunc, gorilla.Route]{
|
|
context: ctx,
|
|
router: mAPIRouter,
|
|
swaggerSchema: openapi,
|
|
jsonDocumentationPath: DefaultJSONDocumentationPath,
|
|
yamlDocumentationPath: DefaultYAMLDocumentationPath,
|
|
}, r)
|
|
})
|
|
|
|
t.Run("ok - with custom docs paths", func(t *testing.T) {
|
|
type key struct{}
|
|
ctx := context.WithValue(context.Background(), key{}, "value")
|
|
r, err := NewRouter(mAPIRouter, Options{
|
|
Openapi: openapi,
|
|
Context: ctx,
|
|
JSONDocumentationPath: "/json/path",
|
|
YAMLDocumentationPath: "/yaml/path",
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, &Router[gorilla.HandlerFunc, gorilla.Route]{
|
|
context: ctx,
|
|
router: mAPIRouter,
|
|
swaggerSchema: openapi,
|
|
jsonDocumentationPath: "/json/path",
|
|
yamlDocumentationPath: "/yaml/path",
|
|
}, r)
|
|
})
|
|
|
|
t.Run("ko - json documentation path does not start with /", func(t *testing.T) {
|
|
type key struct{}
|
|
ctx := context.WithValue(context.Background(), key{}, "value")
|
|
r, err := NewRouter(mAPIRouter, Options{
|
|
Openapi: openapi,
|
|
Context: ctx,
|
|
JSONDocumentationPath: "json/path",
|
|
YAMLDocumentationPath: "/yaml/path",
|
|
})
|
|
|
|
require.EqualError(t, err, "invalid path json/path. Path should start with '/'")
|
|
require.Nil(t, r)
|
|
})
|
|
|
|
t.Run("ko - yaml documentation path does not start with /", func(t *testing.T) {
|
|
type key struct{}
|
|
ctx := context.WithValue(context.Background(), key{}, "value")
|
|
r, err := NewRouter(mAPIRouter, Options{
|
|
Openapi: openapi,
|
|
Context: ctx,
|
|
JSONDocumentationPath: "/json/path",
|
|
YAMLDocumentationPath: "yaml/path",
|
|
})
|
|
|
|
require.EqualError(t, err, "invalid path yaml/path. Path should start with '/'")
|
|
require.Nil(t, r)
|
|
})
|
|
}
|
|
|
|
func TestGenerateValidSwagger(t *testing.T) {
|
|
t.Run("not ok - empty swagger info", func(t *testing.T) {
|
|
swagger := &openapi3.T{}
|
|
|
|
swagger, err := generateNewValidOpenapi(swagger)
|
|
require.Nil(t, swagger)
|
|
require.EqualError(t, err, "swagger info is required")
|
|
})
|
|
|
|
t.Run("not ok - empty info title", func(t *testing.T) {
|
|
swagger := &openapi3.T{
|
|
Info: &openapi3.Info{},
|
|
}
|
|
|
|
swagger, err := generateNewValidOpenapi(swagger)
|
|
require.Nil(t, swagger)
|
|
require.EqualError(t, err, "swagger info title is required")
|
|
})
|
|
|
|
t.Run("not ok - empty info version", func(t *testing.T) {
|
|
swagger := &openapi3.T{
|
|
Info: &openapi3.Info{
|
|
Title: "title",
|
|
},
|
|
}
|
|
|
|
swagger, err := generateNewValidOpenapi(swagger)
|
|
require.Nil(t, swagger)
|
|
require.EqualError(t, err, "swagger info version is required")
|
|
})
|
|
|
|
t.Run("ok - custom swagger", func(t *testing.T) {
|
|
swagger := &openapi3.T{
|
|
Info: &openapi3.Info{},
|
|
}
|
|
|
|
swagger, err := generateNewValidOpenapi(swagger)
|
|
require.Nil(t, swagger)
|
|
require.EqualError(t, err, "swagger info title is required")
|
|
})
|
|
|
|
t.Run("not ok - swagger is required", func(t *testing.T) {
|
|
swagger, err := generateNewValidOpenapi(nil)
|
|
require.Nil(t, swagger)
|
|
require.EqualError(t, err, "swagger is required")
|
|
})
|
|
|
|
t.Run("ok", func(t *testing.T) {
|
|
info := &openapi3.Info{
|
|
Title: "my title",
|
|
Version: "my version",
|
|
}
|
|
swagger := &openapi3.T{
|
|
Info: info,
|
|
}
|
|
|
|
swagger, err := generateNewValidOpenapi(swagger)
|
|
require.NoError(t, err)
|
|
require.Equal(t, &openapi3.T{
|
|
OpenAPI: defaultOpenapiVersion,
|
|
Info: info,
|
|
Paths: openapi3.Paths{},
|
|
}, swagger)
|
|
})
|
|
}
|
|
|
|
func TestGenerateAndExposeSwagger(t *testing.T) {
|
|
t.Run("fails swagger validation", func(t *testing.T) {
|
|
mRouter := mux.NewRouter()
|
|
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
|
|
Openapi: &openapi3.T{
|
|
Info: &openapi3.Info{
|
|
Title: "title",
|
|
Version: "version",
|
|
},
|
|
Components: &openapi3.Components{
|
|
Schemas: map[string]*openapi3.SchemaRef{
|
|
"&%": {},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = router.GenerateAndExposeOpenapi()
|
|
require.Error(t, err)
|
|
require.True(t, strings.HasPrefix(err.Error(), fmt.Sprintf("%s:", ErrValidatingSwagger)))
|
|
})
|
|
|
|
t.Run("correctly expose json documentation from loaded swagger file", func(t *testing.T) {
|
|
mRouter := mux.NewRouter()
|
|
|
|
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
|
|
require.NoError(t, err)
|
|
|
|
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
|
|
Openapi: swagger,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = router.GenerateAndExposeOpenapi()
|
|
require.NoError(t, err)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, DefaultJSONDocumentationPath, nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
|
|
|
|
body := readBody(t, w.Result().Body)
|
|
actual, err := os.ReadFile("testdata/users_employees.json")
|
|
require.NoError(t, err)
|
|
require.JSONEq(t, string(actual), body)
|
|
})
|
|
|
|
t.Run("correctly expose json documentation from loaded swagger file - custom path", func(t *testing.T) {
|
|
mRouter := mux.NewRouter()
|
|
|
|
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
|
|
require.NoError(t, err)
|
|
|
|
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
|
|
Openapi: swagger,
|
|
JSONDocumentationPath: "/custom/path",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = router.GenerateAndExposeOpenapi()
|
|
require.NoError(t, err)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/custom/path", nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
|
|
|
|
body := readBody(t, w.Result().Body)
|
|
actual, err := os.ReadFile("testdata/users_employees.json")
|
|
require.NoError(t, err)
|
|
require.JSONEq(t, string(actual), body)
|
|
})
|
|
|
|
t.Run("correctly expose yaml documentation from loaded swagger file", func(t *testing.T) {
|
|
mRouter := mux.NewRouter()
|
|
|
|
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
|
|
require.NoError(t, err)
|
|
|
|
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
|
|
Openapi: swagger,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = router.GenerateAndExposeOpenapi()
|
|
require.NoError(t, err)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, DefaultYAMLDocumentationPath, nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "text/plain"))
|
|
|
|
body := readBody(t, w.Result().Body)
|
|
expected, err := os.ReadFile("testdata/users_employees.yaml")
|
|
require.NoError(t, err)
|
|
require.YAMLEq(t, string(expected), body, string(body))
|
|
})
|
|
|
|
t.Run("correctly expose yaml documentation from loaded swagger file - custom path", func(t *testing.T) {
|
|
mRouter := mux.NewRouter()
|
|
|
|
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
|
|
require.NoError(t, err)
|
|
|
|
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
|
|
Openapi: swagger,
|
|
YAMLDocumentationPath: "/custom/path",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = router.GenerateAndExposeOpenapi()
|
|
require.NoError(t, err)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/custom/path", nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "text/plain"))
|
|
|
|
body := readBody(t, w.Result().Body)
|
|
expected, err := os.ReadFile("testdata/users_employees.yaml")
|
|
require.NoError(t, err)
|
|
require.YAMLEq(t, string(expected), body, string(body))
|
|
})
|
|
|
|
t.Run("ok - subrouter", func(t *testing.T) {
|
|
mRouter := mux.NewRouter()
|
|
|
|
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
|
|
Openapi: &openapi3.T{
|
|
Info: &openapi3.Info{
|
|
Title: "test swagger title",
|
|
Version: "test swagger version",
|
|
},
|
|
},
|
|
JSONDocumentationPath: "/custom/path",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
router.AddRoute(http.MethodGet, "/foo", func(w http.ResponseWriter, req *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("ok"))
|
|
}, Definitions{})
|
|
|
|
mSubRouter := mRouter.NewRoute().Subrouter()
|
|
subrouter, err := router.SubRouter(gorilla.NewRouter(mSubRouter), SubRouterOptions{
|
|
PathPrefix: "/prefix",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
_, err = subrouter.AddRoute(http.MethodGet, "/taz", func(w http.ResponseWriter, req *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("ok"))
|
|
}, Definitions{})
|
|
require.NoError(t, err)
|
|
|
|
t.Run("add route with path equal to prefix path", func(t *testing.T) {
|
|
_, err = subrouter.AddRoute(http.MethodGet, "", func(w http.ResponseWriter, req *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("ok"))
|
|
}, Definitions{})
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
err = router.GenerateAndExposeOpenapi()
|
|
require.NoError(t, err)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/custom/path", nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
|
|
|
|
body := readBody(t, w.Result().Body)
|
|
actual, err := os.ReadFile("testdata/subrouter.json")
|
|
require.NoError(t, err)
|
|
require.JSONEq(t, string(actual), body)
|
|
|
|
t.Run("test request /prefix", func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/prefix", nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
})
|
|
|
|
t.Run("test request /prefix/taz", func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/prefix/taz", nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
})
|
|
|
|
t.Run("test request /foo", func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/foo", nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
})
|
|
})
|
|
|
|
t.Run("ok - new router with path prefix", func(t *testing.T) {
|
|
mRouter := mux.NewRouter()
|
|
|
|
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
|
|
Openapi: &openapi3.T{
|
|
Info: &openapi3.Info{
|
|
Title: "test swagger title",
|
|
Version: "test swagger version",
|
|
},
|
|
},
|
|
JSONDocumentationPath: "/custom/path",
|
|
PathPrefix: "/prefix",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
router.AddRoute(http.MethodGet, "/foo", func(w http.ResponseWriter, req *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("ok"))
|
|
}, Definitions{})
|
|
|
|
err = router.GenerateAndExposeOpenapi()
|
|
require.NoError(t, err)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/custom/path", nil)
|
|
mRouter.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
|
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
|
|
|
|
body := readBody(t, w.Result().Body)
|
|
actual, err := os.ReadFile("testdata/router_with_prefix.json")
|
|
require.NoError(t, err)
|
|
require.JSONEq(t, string(actual), body, body)
|
|
})
|
|
}
|
|
|
|
func readBody(t *testing.T, requestBody io.ReadCloser) string {
|
|
t.Helper()
|
|
|
|
body, err := io.ReadAll(requestBody)
|
|
require.NoError(t, err)
|
|
|
|
return string(body)
|
|
}
|