mirror of
https://github.com/elyby/chrly.git
synced 2025-05-31 14:11:51 +05:30
Add stats reporter events listener, restore all events for http layer, rework authentication middleware and authenticator interface
This commit is contained in:
50
http/http.go
50
http/http.go
@@ -4,7 +4,10 @@ import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type Emitter interface {
|
||||
@@ -28,6 +31,53 @@ func Serve(address string, handler http.Handler) error {
|
||||
return server.Serve(listener)
|
||||
}
|
||||
|
||||
type loggingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
statusCode int
|
||||
}
|
||||
|
||||
func (lrw *loggingResponseWriter) WriteHeader(code int) {
|
||||
lrw.statusCode = code
|
||||
lrw.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
func CreateRequestEventsMiddleware(emitter Emitter, prefix string) mux.MiddlewareFunc {
|
||||
beforeTopic := strings.Join([]string{prefix, "before_request"}, ":")
|
||||
afterTopic := strings.Join([]string{prefix, "after_request"}, ":")
|
||||
|
||||
return func(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
emitter.Emit(beforeTopic, req)
|
||||
|
||||
lrw := &loggingResponseWriter{
|
||||
ResponseWriter: resp,
|
||||
statusCode: http.StatusOK,
|
||||
}
|
||||
handler.ServeHTTP(lrw, req)
|
||||
|
||||
emitter.Emit(afterTopic, req, lrw.statusCode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type Authenticator interface {
|
||||
Authenticate(req *http.Request) error
|
||||
}
|
||||
|
||||
func CreateAuthenticationMiddleware(checker Authenticator) mux.MiddlewareFunc {
|
||||
return func(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
err := checker.Authenticate(req)
|
||||
if err != nil {
|
||||
apiForbidden(resp, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
handler.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func NotFound(response http.ResponseWriter, _ *http.Request) {
|
||||
data, _ := json.Marshal(map[string]string{
|
||||
"status": "404",
|
||||
|
@@ -1,7 +1,9 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
@@ -14,10 +16,84 @@ type emitterMock struct {
|
||||
}
|
||||
|
||||
func (e *emitterMock) Emit(name string, args ...interface{}) {
|
||||
e.Called((append([]interface{}{name}, args...))...)
|
||||
e.Called(append([]interface{}{name}, args...)...)
|
||||
}
|
||||
|
||||
func TestConfig_NotFound(t *testing.T) {
|
||||
func TestCreateRequestEventsMiddleware(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
emitter := &emitterMock{}
|
||||
emitter.On("Emit", "test_prefix:before_request", req)
|
||||
emitter.On("Emit", "test_prefix:after_request", req, 400)
|
||||
|
||||
isHandlerCalled := false
|
||||
middlewareFunc := CreateRequestEventsMiddleware(emitter, "test_prefix")
|
||||
middlewareFunc.Middleware(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.WriteHeader(400)
|
||||
isHandlerCalled = true
|
||||
})).ServeHTTP(resp, req)
|
||||
|
||||
if !isHandlerCalled {
|
||||
t.Fatal("Handler isn't called from the middleware")
|
||||
}
|
||||
|
||||
emitter.AssertExpectations(t)
|
||||
}
|
||||
|
||||
type authCheckerMock struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *authCheckerMock) Authenticate(req *http.Request) error {
|
||||
args := m.Called(req)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func TestCreateAuthenticationMiddleware(t *testing.T) {
|
||||
t.Run("pass", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
auth := &authCheckerMock{}
|
||||
auth.On("Authenticate", req).Once().Return(nil)
|
||||
|
||||
isHandlerCalled := false
|
||||
middlewareFunc := CreateAuthenticationMiddleware(auth)
|
||||
middlewareFunc.Middleware(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
isHandlerCalled = true
|
||||
})).ServeHTTP(resp, req)
|
||||
|
||||
testify.True(t, isHandlerCalled, "Handler isn't called from the middleware")
|
||||
|
||||
auth.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("fail", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
auth := &authCheckerMock{}
|
||||
auth.On("Authenticate", req).Once().Return(errors.New("error reason"))
|
||||
|
||||
isHandlerCalled := false
|
||||
middlewareFunc := CreateAuthenticationMiddleware(auth)
|
||||
middlewareFunc.Middleware(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
isHandlerCalled = true
|
||||
})).ServeHTTP(resp, req)
|
||||
|
||||
testify.False(t, isHandlerCalled, "Handler shouldn't be called")
|
||||
testify.Equal(t, 403, resp.Code)
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
testify.JSONEq(t, `{
|
||||
"error": "error reason"
|
||||
}`, string(body))
|
||||
|
||||
auth.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNotFound(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://example.com", nil)
|
||||
|
78
http/jwt.go
Normal file
78
http/jwt.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/SermoDigital/jose/crypto"
|
||||
"github.com/SermoDigital/jose/jws"
|
||||
)
|
||||
|
||||
var hashAlg = crypto.SigningMethodHS256
|
||||
|
||||
const scopesClaim = "scopes"
|
||||
|
||||
type Scope string
|
||||
|
||||
var (
|
||||
SkinScope = Scope("skin")
|
||||
)
|
||||
|
||||
type JwtAuth struct {
|
||||
Emitter
|
||||
Key []byte
|
||||
}
|
||||
|
||||
func (t *JwtAuth) NewToken(scopes ...Scope) ([]byte, error) {
|
||||
if len(t.Key) == 0 {
|
||||
return nil, errors.New("signing key not available")
|
||||
}
|
||||
|
||||
claims := jws.Claims{}
|
||||
claims.Set(scopesClaim, scopes)
|
||||
claims.SetIssuedAt(time.Now())
|
||||
encoder := jws.NewJWT(claims, hashAlg)
|
||||
token, err := encoder.Serialize(t.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (t *JwtAuth) Authenticate(req *http.Request) error {
|
||||
if len(t.Key) == 0 {
|
||||
return t.emitErr(errors.New("Signing key not set"))
|
||||
}
|
||||
|
||||
bearerToken := req.Header.Get("Authorization")
|
||||
if bearerToken == "" {
|
||||
return t.emitErr(errors.New("Authentication header not presented"))
|
||||
}
|
||||
|
||||
if !strings.EqualFold(bearerToken[0:7], "BEARER ") {
|
||||
return t.emitErr(errors.New("Cannot recognize JWT token in passed value"))
|
||||
}
|
||||
|
||||
tokenStr := bearerToken[7:]
|
||||
token, err := jws.ParseJWT([]byte(tokenStr))
|
||||
if err != nil {
|
||||
return t.emitErr(errors.New("Cannot parse passed JWT token"))
|
||||
}
|
||||
|
||||
err = token.Validate(t.Key, hashAlg)
|
||||
if err != nil {
|
||||
return t.emitErr(errors.New("JWT token have invalid signature. It may be corrupted or expired"))
|
||||
}
|
||||
|
||||
t.Emit("authentication:success")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *JwtAuth) emitErr(err error) error {
|
||||
t.Emit("authentication:error", err)
|
||||
return err
|
||||
}
|
127
http/jwt_test.go
Normal file
127
http/jwt_test.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxNTE2NjU4MTkzIiwic2NvcGVzIjoic2tpbiJ9.agbBS0qdyYMBaVfTZJAZcTTRgW1Y0kZty4H3N2JHBO8"
|
||||
|
||||
func TestJwtAuth_NewToken(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
jwt := &JwtAuth{Key: []byte("secret")}
|
||||
token, err := jwt.NewToken(SkinScope)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, token)
|
||||
})
|
||||
|
||||
t.Run("key not provided", func(t *testing.T) {
|
||||
jwt := &JwtAuth{}
|
||||
token, err := jwt.NewToken(SkinScope)
|
||||
assert.Error(t, err, "signing key not available")
|
||||
assert.Nil(t, token)
|
||||
})
|
||||
}
|
||||
|
||||
func TestJwtAuth_Authenticate(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
emitter := &emitterMock{}
|
||||
emitter.On("Emit", "authentication:success")
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
req.Header.Add("Authorization", "Bearer " + jwt)
|
||||
jwt := &JwtAuth{Key: []byte("secret"), Emitter: emitter}
|
||||
|
||||
err := jwt.Authenticate(req)
|
||||
assert.Nil(t, err)
|
||||
|
||||
emitter.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("request without auth header", func(t *testing.T) {
|
||||
emitter := &emitterMock{}
|
||||
emitter.On("Emit", "authentication:error", mock.MatchedBy(func(err error) bool {
|
||||
assert.Error(t, err, "Authentication header not presented")
|
||||
return true
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
jwt := &JwtAuth{Key: []byte("secret"), Emitter: emitter}
|
||||
|
||||
err := jwt.Authenticate(req)
|
||||
assert.Error(t, err, "Authentication header not presented")
|
||||
|
||||
emitter.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("no bearer token prefix", func(t *testing.T) {
|
||||
emitter := &emitterMock{}
|
||||
emitter.On("Emit", "authentication:error", mock.MatchedBy(func(err error) bool {
|
||||
assert.Error(t, err, "Cannot recognize JWT token in passed value")
|
||||
return true
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
req.Header.Add("Authorization", "this is not jwt")
|
||||
jwt := &JwtAuth{Key: []byte("secret"), Emitter: emitter}
|
||||
|
||||
err := jwt.Authenticate(req)
|
||||
assert.Error(t, err, "Cannot recognize JWT token in passed value")
|
||||
|
||||
emitter.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("bearer token but not jwt", func(t *testing.T) {
|
||||
emitter := &emitterMock{}
|
||||
emitter.On("Emit", "authentication:error", mock.MatchedBy(func(err error) bool {
|
||||
assert.Error(t, err, "Cannot parse passed JWT token")
|
||||
return true
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
req.Header.Add("Authorization", "Bearer thisIs.Not.Jwt")
|
||||
jwt := &JwtAuth{Key: []byte("secret"), Emitter: emitter}
|
||||
|
||||
err := jwt.Authenticate(req)
|
||||
assert.Error(t, err, "Cannot parse passed JWT token")
|
||||
|
||||
emitter.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("when secret is not set", func(t *testing.T) {
|
||||
emitter := &emitterMock{}
|
||||
emitter.On("Emit", "authentication:error", mock.MatchedBy(func(err error) bool {
|
||||
assert.Error(t, err, "Signing key not set")
|
||||
return true
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
req.Header.Add("Authorization", "Bearer " + jwt)
|
||||
jwt := &JwtAuth{Emitter: emitter}
|
||||
|
||||
err := jwt.Authenticate(req)
|
||||
assert.Error(t, err, "Signing key not set")
|
||||
|
||||
emitter.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("invalid signature", func(t *testing.T) {
|
||||
emitter := &emitterMock{}
|
||||
emitter.On("Emit", "authentication:error", mock.MatchedBy(func(err error) bool {
|
||||
assert.Error(t, err, "JWT token have invalid signature. It may be corrupted or expired")
|
||||
return true
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest("POST", "http://localhost", nil)
|
||||
req.Header.Add("Authorization", "Bearer " + jwt)
|
||||
jwt := &JwtAuth{Key: []byte("this is another secret"), Emitter: emitter}
|
||||
|
||||
err := jwt.Authenticate(req)
|
||||
assert.Error(t, err, "JWT token have invalid signature. It may be corrupted or expired")
|
||||
|
||||
emitter.AssertExpectations(t)
|
||||
})
|
||||
}
|
@@ -14,10 +14,10 @@ import (
|
||||
"github.com/thedevsaddam/govalidator"
|
||||
|
||||
"github.com/elyby/chrly/api/mojang"
|
||||
"github.com/elyby/chrly/auth"
|
||||
"github.com/elyby/chrly/model"
|
||||
)
|
||||
|
||||
//noinspection GoSnakeCaseUsage
|
||||
const UUID_ANY = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
||||
|
||||
var regexUuidAny = regexp.MustCompile(UUID_ANY)
|
||||
@@ -78,10 +78,6 @@ type MojangTexturesProvider interface {
|
||||
GetForUsername(username string) (*mojang.SignedTexturesResponse, error)
|
||||
}
|
||||
|
||||
type AuthChecker interface {
|
||||
Check(req *http.Request) error
|
||||
}
|
||||
|
||||
type Skinsystem struct {
|
||||
Emitter
|
||||
TexturesExtraParamName string
|
||||
@@ -89,25 +85,26 @@ type Skinsystem struct {
|
||||
SkinsRepo SkinsRepository
|
||||
CapesRepo CapesRepository
|
||||
MojangTexturesProvider MojangTexturesProvider
|
||||
Auth AuthChecker
|
||||
Authenticator Authenticator
|
||||
}
|
||||
|
||||
func (ctx *Skinsystem) CreateHandler() *mux.Router {
|
||||
router := mux.NewRouter().StrictSlash(true)
|
||||
router.Use(CreateRequestEventsMiddleware(ctx.Emitter, "skinsystem"))
|
||||
|
||||
router.HandleFunc("/skins/{username}", ctx.Skin).Methods("GET")
|
||||
router.HandleFunc("/cloaks/{username}", ctx.Cape).Methods("GET").Name("cloaks")
|
||||
router.HandleFunc("/textures/{username}", ctx.Textures).Methods("GET")
|
||||
router.HandleFunc("/textures/signed/{username}", ctx.SignedTextures).Methods("GET")
|
||||
router.HandleFunc("/skins/{username}", ctx.Skin).Methods(http.MethodGet)
|
||||
router.HandleFunc("/cloaks/{username}", ctx.Cape).Methods(http.MethodGet).Name("cloaks")
|
||||
router.HandleFunc("/textures/{username}", ctx.Textures).Methods(http.MethodGet)
|
||||
router.HandleFunc("/textures/signed/{username}", ctx.SignedTextures).Methods(http.MethodGet)
|
||||
// Legacy
|
||||
router.HandleFunc("/skins", ctx.SkinGET).Methods("GET")
|
||||
router.HandleFunc("/cloaks", ctx.CapeGET).Methods("GET")
|
||||
router.HandleFunc("/skins", ctx.SkinGET).Methods(http.MethodGet)
|
||||
router.HandleFunc("/cloaks", ctx.CapeGET).Methods(http.MethodGet)
|
||||
// API
|
||||
apiRouter := router.PathPrefix("/api").Subrouter()
|
||||
apiRouter.Use(ctx.AuthenticationMiddleware)
|
||||
apiRouter.HandleFunc("/skins", ctx.PostSkin).Methods("POST")
|
||||
apiRouter.HandleFunc("/skins/id:{id:[0-9]+}", ctx.DeleteSkinByUserId).Methods("DELETE")
|
||||
apiRouter.HandleFunc("/skins/{username}", ctx.DeleteSkinByUsername).Methods("DELETE")
|
||||
apiRouter.Use(CreateAuthenticationMiddleware(ctx.Authenticator))
|
||||
apiRouter.HandleFunc("/skins", ctx.PostSkin).Methods(http.MethodPost)
|
||||
apiRouter.HandleFunc("/skins/id:{id:[0-9]+}", ctx.DeleteSkinByUserId).Methods(http.MethodDelete)
|
||||
apiRouter.HandleFunc("/skins/{username}", ctx.DeleteSkinByUsername).Methods(http.MethodDelete)
|
||||
// 404
|
||||
router.NotFoundHandler = http.HandlerFunc(NotFound)
|
||||
|
||||
@@ -226,7 +223,7 @@ func (ctx *Skinsystem) Textures(response http.ResponseWriter, request *http.Requ
|
||||
|
||||
texturesProp := mojangTextures.DecodeTextures()
|
||||
if texturesProp == nil {
|
||||
ctx.Emit("skinsystem.error", errors.New("unable to find textures property"))
|
||||
ctx.Emit("skinsystem:error", errors.New("unable to find textures property"))
|
||||
apiServerError(response)
|
||||
return
|
||||
}
|
||||
@@ -330,28 +327,6 @@ func (ctx *Skinsystem) DeleteSkinByUsername(resp http.ResponseWriter, req *http.
|
||||
ctx.deleteSkin(skin, err, resp)
|
||||
}
|
||||
|
||||
func (ctx *Skinsystem) AuthenticationMiddleware(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
// TODO: decide on how I would cover this with logging
|
||||
// ctx.Logger.IncCounter("authentication.challenge", 1)
|
||||
err := ctx.Auth.Check(req)
|
||||
if err != nil {
|
||||
if _, ok := err.(*auth.Unauthorized); ok {
|
||||
// ctx.Logger.IncCounter("authentication.failed", 1)
|
||||
apiForbidden(resp, err.Error())
|
||||
} else {
|
||||
// ctx.Logger.Error("Unknown error on validating api request: :err", wd.ErrParam(err))
|
||||
apiServerError(resp)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ctx.Logger.IncCounter("authentication.success", 1)
|
||||
handler.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
|
||||
func (ctx *Skinsystem) deleteSkin(skin *model.Skin, err error, resp http.ResponseWriter) {
|
||||
if err != nil {
|
||||
if _, ok := err.(*SkinNotFoundError); ok {
|
||||
|
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/elyby/chrly/api/mojang"
|
||||
"github.com/elyby/chrly/auth"
|
||||
"github.com/elyby/chrly/model"
|
||||
)
|
||||
|
||||
@@ -95,15 +94,6 @@ func (m *mojangTexturesProviderMock) GetForUsername(username string) (*mojang.Si
|
||||
return result, args.Error(1)
|
||||
}
|
||||
|
||||
type authCheckerMock struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *authCheckerMock) Check(req *http.Request) error {
|
||||
args := m.Called(req)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
type skinsystemTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
@@ -131,7 +121,7 @@ func (suite *skinsystemTestSuite) SetupTest() {
|
||||
SkinsRepo: suite.SkinsRepository,
|
||||
CapesRepo: suite.CapesRepository,
|
||||
MojangTexturesProvider: suite.MojangTexturesProvider,
|
||||
Auth: suite.Auth,
|
||||
Authenticator: suite.Auth,
|
||||
Emitter: suite.Emitter,
|
||||
}
|
||||
}
|
||||
@@ -215,6 +205,8 @@ var skinsTestsCases = []*skinsystemTestCase{
|
||||
func (suite *skinsystemTestSuite) TestSkin() {
|
||||
for _, testCase := range skinsTestsCases {
|
||||
suite.RunSubTest(testCase.Name, func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
testCase.BeforeTest(suite)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/skins/mock_username", nil)
|
||||
@@ -227,6 +219,8 @@ func (suite *skinsystemTestSuite) TestSkin() {
|
||||
}
|
||||
|
||||
suite.RunSubTest("Pass username with png extension", func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/skins/mock_username.png", nil)
|
||||
@@ -243,6 +237,8 @@ func (suite *skinsystemTestSuite) TestSkin() {
|
||||
func (suite *skinsystemTestSuite) TestSkinGET() {
|
||||
for _, testCase := range skinsTestsCases {
|
||||
suite.RunSubTest(testCase.Name, func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
testCase.BeforeTest(suite)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/skins?name=mock_username", nil)
|
||||
@@ -255,6 +251,9 @@ func (suite *skinsystemTestSuite) TestSkinGET() {
|
||||
}
|
||||
|
||||
suite.RunSubTest("Do not pass name param", func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/skins", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
@@ -318,6 +317,8 @@ var capesTestsCases = []*skinsystemTestCase{
|
||||
func (suite *skinsystemTestSuite) TestCape() {
|
||||
for _, testCase := range capesTestsCases {
|
||||
suite.RunSubTest(testCase.Name, func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
testCase.BeforeTest(suite)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/cloaks/mock_username", nil)
|
||||
@@ -330,6 +331,8 @@ func (suite *skinsystemTestSuite) TestCape() {
|
||||
}
|
||||
|
||||
suite.RunSubTest("Pass username with png extension", func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.CapesRepository.On("FindByUsername", "mock_username").Return(createCapeModel(), nil)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/cloaks/mock_username.png", nil)
|
||||
@@ -348,6 +351,8 @@ func (suite *skinsystemTestSuite) TestCape() {
|
||||
func (suite *skinsystemTestSuite) TestCapeGET() {
|
||||
for _, testCase := range capesTestsCases {
|
||||
suite.RunSubTest(testCase.Name, func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
testCase.BeforeTest(suite)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/cloaks?name=mock_username", nil)
|
||||
@@ -360,6 +365,9 @@ func (suite *skinsystemTestSuite) TestCapeGET() {
|
||||
}
|
||||
|
||||
suite.RunSubTest("Do not pass name param", func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/cloaks", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
@@ -486,6 +494,8 @@ var texturesTestsCases = []*skinsystemTestCase{
|
||||
func (suite *skinsystemTestSuite) TestTextures() {
|
||||
for _, testCase := range texturesTestsCases {
|
||||
suite.RunSubTest(testCase.Name, func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
testCase.BeforeTest(suite)
|
||||
|
||||
req := httptest.NewRequest("GET", "http://chrly/textures/mock_username", nil)
|
||||
@@ -609,6 +619,8 @@ var signedTexturesTestsCases = []*signedTexturesTestCase{
|
||||
func (suite *skinsystemTestSuite) TestSignedTextures() {
|
||||
for _, testCase := range signedTexturesTestsCases {
|
||||
suite.RunSubTest(testCase.Name, func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
testCase.BeforeTest(suite)
|
||||
|
||||
var target string
|
||||
@@ -817,7 +829,9 @@ var postSkinTestsCases = []*postSkinTestCase{
|
||||
func (suite *skinsystemTestSuite) TestPostSkin() {
|
||||
for _, testCase := range postSkinTestsCases {
|
||||
suite.RunSubTest(testCase.Name, func() {
|
||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.Auth.On("Authenticate", mock.Anything).Return(nil)
|
||||
testCase.BeforeTest(suite)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://chrly/api/skins", testCase.Form)
|
||||
@@ -831,7 +845,9 @@ func (suite *skinsystemTestSuite) TestPostSkin() {
|
||||
}
|
||||
|
||||
suite.RunSubTest("Get errors about required fields", func() {
|
||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.Auth.On("Authenticate", mock.Anything).Return(nil)
|
||||
|
||||
req := httptest.NewRequest("POST", "http://chrly/api/skins", bytes.NewBufferString(url.Values{
|
||||
"mojangTextures": {"someBase64EncodedString"},
|
||||
@@ -878,11 +894,13 @@ func (suite *skinsystemTestSuite) TestPostSkin() {
|
||||
})
|
||||
|
||||
suite.RunSubTest("Send request without authorization", func() {
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
req := httptest.NewRequest("POST", "http://chrly/api/skins", nil)
|
||||
req.Header.Add("Authorization", "Bearer invalid.jwt.token")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
suite.Auth.On("Check", mock.Anything).Return(&auth.Unauthorized{Reason: "Cannot parse passed JWT token"})
|
||||
suite.Auth.On("Authenticate", mock.Anything).Return(errors.New("Cannot parse passed JWT token"))
|
||||
|
||||
suite.App.CreateHandler().ServeHTTP(w, req)
|
||||
|
||||
@@ -896,7 +914,9 @@ func (suite *skinsystemTestSuite) TestPostSkin() {
|
||||
})
|
||||
|
||||
suite.RunSubTest("Upload textures with skin as file", func() {
|
||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.Auth.On("Authenticate", mock.Anything).Return(nil)
|
||||
|
||||
inputBody := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(inputBody)
|
||||
@@ -940,7 +960,9 @@ func (suite *skinsystemTestSuite) TestPostSkin() {
|
||||
|
||||
func (suite *skinsystemTestSuite) TestDeleteByUserId() {
|
||||
suite.RunSubTest("Delete skin by its identity id", func() {
|
||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.Auth.On("Authenticate", mock.Anything).Return(nil)
|
||||
suite.SkinsRepository.On("FindByUserId", 1).Return(createSkinModel("mock_username", false), nil)
|
||||
suite.SkinsRepository.On("RemoveByUserId", 1).Once().Return(nil)
|
||||
|
||||
@@ -957,7 +979,9 @@ func (suite *skinsystemTestSuite) TestDeleteByUserId() {
|
||||
})
|
||||
|
||||
suite.RunSubTest("Try to remove not exists identity id", func() {
|
||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.Auth.On("Authenticate", mock.Anything).Return(nil)
|
||||
suite.SkinsRepository.On("FindByUserId", 1).Return(nil, &SkinNotFoundError{Who: "unknown"})
|
||||
|
||||
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/id:1", nil)
|
||||
@@ -981,7 +1005,9 @@ func (suite *skinsystemTestSuite) TestDeleteByUserId() {
|
||||
|
||||
func (suite *skinsystemTestSuite) TestDeleteByUsername() {
|
||||
suite.RunSubTest("Delete skin by its identity username", func() {
|
||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.Auth.On("Authenticate", mock.Anything).Return(nil)
|
||||
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
||||
suite.SkinsRepository.On("RemoveByUserId", 1).Once().Return(nil)
|
||||
|
||||
@@ -998,7 +1024,9 @@ func (suite *skinsystemTestSuite) TestDeleteByUsername() {
|
||||
})
|
||||
|
||||
suite.RunSubTest("Try to remove not exists identity username", func() {
|
||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||
suite.Emitter.On("Emit", "skinsystem:before_request", mock.Anything)
|
||||
suite.Emitter.On("Emit", "skinsystem:after_request", mock.Anything, mock.Anything)
|
||||
suite.Auth.On("Authenticate", mock.Anything).Return(nil)
|
||||
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(nil, &SkinNotFoundError{Who: "mock_username"})
|
||||
|
||||
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/mock_username", nil)
|
||||
|
Reference in New Issue
Block a user