1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2024-12-01 11:01:04 +02:00
pocketbase/apis/base_test.go

317 lines
8.2 KiB
Go
Raw Normal View History

2022-07-06 23:19:05 +02:00
package apis_test
import (
"errors"
2023-04-15 13:44:07 +02:00
"fmt"
2022-07-06 23:19:05 +02:00
"net/http"
2023-04-15 13:44:07 +02:00
"strings"
2022-07-06 23:19:05 +02:00
"testing"
"github.com/labstack/echo/v5"
2022-10-30 10:28:14 +02:00
"github.com/pocketbase/pocketbase/apis"
2022-07-06 23:19:05 +02:00
"github.com/pocketbase/pocketbase/tests"
2023-04-15 13:44:07 +02:00
"github.com/spf13/cast"
2022-07-06 23:19:05 +02:00
)
func Test404(t *testing.T) {
scenarios := []tests.ApiScenario{
{
Method: http.MethodGet,
Url: "/api/missing",
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
},
{
Method: http.MethodPost,
Url: "/api/missing",
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
},
{
Method: http.MethodPatch,
Url: "/api/missing",
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
},
{
Method: http.MethodDelete,
Url: "/api/missing",
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
},
{
Method: http.MethodHead,
Url: "/api/missing",
ExpectedStatus: 404,
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
func TestCustomRoutesAndErrorsHandling(t *testing.T) {
scenarios := []tests.ApiScenario{
{
Name: "custom route",
Method: http.MethodGet,
Url: "/custom",
2022-09-07 19:31:05 +02:00
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
2022-07-06 23:19:05 +02:00
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/custom",
Handler: func(c echo.Context) error {
return c.String(200, "test123")
},
})
},
ExpectedStatus: 200,
ExpectedContent: []string{"test123"},
},
{
Name: "custom route with url encoded parameter",
Method: http.MethodGet,
Url: "/a%2Bb%2Bc",
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/:param",
Handler: func(c echo.Context) error {
return c.String(200, c.PathParam("param"))
},
})
},
ExpectedStatus: 200,
ExpectedContent: []string{"a+b+c"},
},
2022-07-06 23:19:05 +02:00
{
Name: "route with HTTPError",
Method: http.MethodGet,
Url: "/http-error",
2022-09-07 19:31:05 +02:00
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
2022-07-06 23:19:05 +02:00
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/http-error",
Handler: func(c echo.Context) error {
return echo.ErrBadRequest
},
})
},
ExpectedStatus: 400,
ExpectedContent: []string{`{"code":400,"message":"Bad Request.","data":{}}`},
},
{
Name: "route with api error",
Method: http.MethodGet,
Url: "/api-error",
2022-09-07 19:31:05 +02:00
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
2022-07-06 23:19:05 +02:00
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/api-error",
Handler: func(c echo.Context) error {
2022-10-30 10:28:14 +02:00
return apis.NewApiError(500, "test message", errors.New("internal_test"))
2022-07-06 23:19:05 +02:00
},
})
},
ExpectedStatus: 500,
ExpectedContent: []string{`{"code":500,"message":"Test message.","data":{}}`},
},
{
Name: "route with plain error",
Method: http.MethodGet,
Url: "/plain-error",
2022-09-07 19:31:05 +02:00
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
2022-07-06 23:19:05 +02:00
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/plain-error",
Handler: func(c echo.Context) error {
return errors.New("Test error")
},
})
},
ExpectedStatus: 400,
ExpectedContent: []string{`{"code":400,"message":"Something went wrong while processing your request.","data":{}}`},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
func TestRemoveTrailingSlashMiddleware(t *testing.T) {
scenarios := []tests.ApiScenario{
{
Name: "non /api/* route (exact match)",
Method: http.MethodGet,
Url: "/custom",
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/custom",
Handler: func(c echo.Context) error {
return c.String(200, "test123")
},
})
},
ExpectedStatus: 200,
ExpectedContent: []string{"test123"},
},
{
Name: "non /api/* route (with trailing slash)",
Method: http.MethodGet,
Url: "/custom/",
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/custom",
Handler: func(c echo.Context) error {
return c.String(200, "test123")
},
})
},
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
},
{
Name: "/api/* route (exact match)",
Method: http.MethodGet,
Url: "/api/custom",
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/api/custom",
Handler: func(c echo.Context) error {
return c.String(200, "test123")
},
})
},
ExpectedStatus: 200,
ExpectedContent: []string{"test123"},
},
{
Name: "/api/* route (with trailing slash)",
Method: http.MethodGet,
Url: "/api/custom/",
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
e.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/api/custom",
Handler: func(c echo.Context) error {
return c.String(200, "test123")
},
})
},
ExpectedStatus: 200,
ExpectedContent: []string{"test123"},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
2023-04-15 13:44:07 +02:00
func TestEagerRequestInfoCache(t *testing.T) {
2023-04-15 13:44:07 +02:00
scenarios := []tests.ApiScenario{
{
Name: "custom non-api group route",
Method: "POST",
2023-04-15 13:44:07 +02:00
Url: "/custom",
Body: strings.NewReader(`{"name":"test123"}`),
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
e.AddRoute(echo.Route{
Method: "POST",
2023-04-15 13:44:07 +02:00
Path: "/custom",
Handler: func(c echo.Context) error {
data := &struct {
Name string `json:"name"`
}{}
if err := c.Bind(data); err != nil {
return err
}
// since the unknown method is not eager cache support
// it should fail reading the json body twice
r := apis.RequestInfo(c)
2023-04-15 13:44:07 +02:00
if v := cast.ToString(r.Data["name"]); v != "" {
t.Fatalf("Expected empty request data body, got, %v", r.Data)
}
return c.NoContent(200)
2023-04-15 13:44:07 +02:00
},
})
},
ExpectedStatus: 200,
2023-04-15 13:44:07 +02:00
},
{
Name: "api group route with unsupported eager cache request method",
Method: "GET",
Url: "/api/admins",
Body: strings.NewReader(`{"name":"test123"}`),
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// it is not important whether the route handler return an error since
// we just need to ensure that the eagerRequestInfoCache was registered
next(c)
2023-04-15 13:44:07 +02:00
// ensure that the body was read at least once
data := &struct {
Name string `json:"name"`
}{}
c.Bind(data)
2023-04-15 13:44:07 +02:00
// since the unknown method is not eager cache support
// it should fail reading the json body twice
r := apis.RequestInfo(c)
if v := cast.ToString(r.Data["name"]); v != "" {
t.Fatalf("Expected empty request data body, got, %v", r.Data)
}
2023-04-15 13:44:07 +02:00
return nil
}
})
},
ExpectedStatus: 200,
},
{
Name: "api group route with supported eager cache request method",
Method: "POST",
Url: "/api/admins",
Body: strings.NewReader(`{"name":"test123"}`),
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// it is not important whether the route handler return an error since
// we just need to ensure that the eagerRequestInfoCache was registered
next(c)
2023-04-15 13:44:07 +02:00
// ensure that the body was read at least once
data := &struct {
Name string `json:"name"`
}{}
c.Bind(data)
// try to read the body again
r := apis.RequestInfo(c)
fmt.Println(r)
if v := cast.ToString(r.Data["name"]); v != "test123" {
t.Fatalf("Expected request data with name %q, got, %q", "test123", v)
}
return nil
}
})
2023-04-15 13:44:07 +02:00
},
ExpectedStatus: 200,
},
2023-04-15 13:44:07 +02:00
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}