214 lines
5.7 KiB
Go
214 lines
5.7 KiB
Go
package rest_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dwysokinski.me/twhelp/sessions/internal/router/rest"
|
|
"gitea.dwysokinski.me/twhelp/sessions/internal/router/rest/internal/model"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestRouteNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
resp := doRequest(rest.NewRouter(rest.RouterConfig{}), http.MethodGet, "/v1/"+uuid.NewString(), "", nil)
|
|
defer resp.Body.Close()
|
|
assertJSONResponse(t, resp, http.StatusNotFound, &model.ErrorResp{
|
|
Error: model.APIError{
|
|
Code: "route-not-found",
|
|
Message: "route not found",
|
|
},
|
|
}, &model.ErrorResp{})
|
|
}
|
|
|
|
func TestMethodNotAllowed(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
resp := doRequest(rest.NewRouter(rest.RouterConfig{
|
|
Swagger: rest.SwaggerConfig{
|
|
Enabled: true,
|
|
},
|
|
}), http.MethodPost, "/v1/swagger/index.html", "", nil)
|
|
defer resp.Body.Close()
|
|
assertJSONResponse(t, resp, http.StatusMethodNotAllowed, &model.ErrorResp{
|
|
Error: model.APIError{
|
|
Code: "method-not-allowed",
|
|
Message: "method not allowed",
|
|
},
|
|
}, &model.ErrorResp{})
|
|
}
|
|
|
|
func TestCORS(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
cfg rest.CORSConfig
|
|
reqHeaders map[string]string
|
|
resHeaders map[string]string
|
|
expectedStatus int
|
|
}{
|
|
{
|
|
name: "Disabled",
|
|
cfg: rest.CORSConfig{
|
|
Enabled: false,
|
|
AllowedOrigins: []string{"*"},
|
|
AllowedMethods: []string{"GET", "POST"},
|
|
AllowCredentials: false,
|
|
MaxAge: 600,
|
|
},
|
|
reqHeaders: map[string]string{
|
|
"Origin": "https://sessions.tribalwarshelp.com",
|
|
"Access-Control-Request-Method": http.MethodGet,
|
|
},
|
|
resHeaders: map[string]string{
|
|
"Content-Type": "application/json",
|
|
},
|
|
expectedStatus: http.StatusNotFound,
|
|
},
|
|
{
|
|
name: "*",
|
|
cfg: rest.CORSConfig{
|
|
Enabled: true,
|
|
AllowedOrigins: []string{"*"},
|
|
AllowedMethods: []string{"GET", "POST"},
|
|
AllowCredentials: false,
|
|
MaxAge: 600,
|
|
},
|
|
reqHeaders: map[string]string{
|
|
"Origin": "https://sessions.tribalwarshelp.com",
|
|
"Access-Control-Request-Method": http.MethodGet,
|
|
},
|
|
resHeaders: map[string]string{
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Methods": http.MethodGet,
|
|
"Access-Control-Max-Age": "600",
|
|
"Vary": "Origin Access-Control-Request-Method Access-Control-Request-Headers",
|
|
},
|
|
expectedStatus: http.StatusOK,
|
|
},
|
|
{
|
|
name: "https://sessions.tribalwarshelp.com",
|
|
cfg: rest.CORSConfig{
|
|
Enabled: true,
|
|
AllowedOrigins: []string{"https://sessions.tribalwarshelp.com"},
|
|
AllowedMethods: []string{"GET", "POST"},
|
|
AllowCredentials: true,
|
|
MaxAge: 300,
|
|
},
|
|
reqHeaders: map[string]string{
|
|
"Origin": "https://sessions.tribalwarshelp.com",
|
|
"Access-Control-Request-Method": http.MethodGet,
|
|
},
|
|
resHeaders: map[string]string{
|
|
"Access-Control-Allow-Origin": "https://sessions.tribalwarshelp.com",
|
|
"Access-Control-Allow-Credentials": "true",
|
|
"Access-Control-Allow-Methods": http.MethodGet,
|
|
"Access-Control-Max-Age": "300",
|
|
"Vary": "Origin Access-Control-Request-Method Access-Control-Request-Headers",
|
|
},
|
|
expectedStatus: http.StatusOK,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := rest.NewRouter(rest.RouterConfig{
|
|
CORS: tt.cfg,
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodOptions, "/url", nil)
|
|
for k, v := range tt.reqHeaders {
|
|
req.Header.Set(k, v)
|
|
}
|
|
|
|
resp := doCustomRequest(r, req)
|
|
defer resp.Body.Close()
|
|
assert.Equal(t, tt.expectedStatus, resp.StatusCode)
|
|
assert.Len(t, resp.Header, len(tt.resHeaders))
|
|
for k, expected := range tt.resHeaders {
|
|
assert.Equal(t, expected, strings.Join(resp.Header.Values(k), " "))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSwagger(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
target string
|
|
expectedContentType string
|
|
}{
|
|
{
|
|
name: "/v1/swagger/index.html",
|
|
target: "/v1/swagger/index.html",
|
|
expectedContentType: "text/html; charset=utf-8",
|
|
},
|
|
{
|
|
name: "/v1/swagger/doc.json",
|
|
target: "/v1/swagger/doc.json",
|
|
expectedContentType: "application/json; charset=utf-8",
|
|
},
|
|
}
|
|
router := rest.NewRouter(rest.RouterConfig{
|
|
Swagger: rest.SwaggerConfig{
|
|
Enabled: true,
|
|
},
|
|
})
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
resp := doRequest(router, http.MethodGet, tt.target, "", nil)
|
|
defer resp.Body.Close()
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
assert.Equal(t, tt.expectedContentType, resp.Header.Get("Content-Type"))
|
|
})
|
|
}
|
|
}
|
|
|
|
func doRequest(mux chi.Router, method, target, apiKey string, body io.Reader) *http.Response {
|
|
req := httptest.NewRequest(method, target, body)
|
|
if apiKey != "" {
|
|
req.Header.Set("X-Api-Key", apiKey)
|
|
}
|
|
return doCustomRequest(mux, req)
|
|
}
|
|
|
|
func doCustomRequest(mux chi.Router, r *http.Request) *http.Response {
|
|
rr := httptest.NewRecorder()
|
|
mux.ServeHTTP(rr, r)
|
|
return rr.Result()
|
|
}
|
|
|
|
func assertJSONResponse(tb testing.TB, resp *http.Response, expectedStatus int, expected any, target any) {
|
|
tb.Helper()
|
|
|
|
assert.Equal(tb, "application/json", resp.Header.Get("Content-Type"))
|
|
assert.Equal(tb, expectedStatus, resp.StatusCode)
|
|
assert.NoError(tb, json.NewDecoder(resp.Body).Decode(target))
|
|
opts := cmp.Options{
|
|
cmpopts.IgnoreUnexported(time.Time{}),
|
|
}
|
|
assert.Empty(tb, cmp.Diff(expected, target, opts...))
|
|
}
|