mirror of
https://github.com/elyby/chrly.git
synced 2025-01-11 06:12:09 +05:30
Completely rework the HTTP app layer structure. Replace a logger with an event dispatcher. Adjust tests to the new app architecture.
This commit is contained in:
parent
fbfe9f4516
commit
b2ee10f72f
10
cmd/serve.go
10
cmd/serve.go
@ -74,20 +74,20 @@ var serveCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
logger.Info("Mojang's textures queue is successfully initialized")
|
logger.Info("Mojang's textures queue is successfully initialized")
|
||||||
|
|
||||||
cfg := &http.Skinsystem{
|
address := fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port"))
|
||||||
ListenSpec: fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port")),
|
handler := (&http.Skinsystem{
|
||||||
SkinsRepo: skinsRepo,
|
SkinsRepo: skinsRepo,
|
||||||
CapesRepo: capesRepo,
|
CapesRepo: capesRepo,
|
||||||
MojangTexturesProvider: mojangTexturesProvider,
|
MojangTexturesProvider: mojangTexturesProvider,
|
||||||
Logger: logger,
|
|
||||||
Auth: &auth.JwtAuth{Key: []byte(viper.GetString("chrly.secret"))},
|
Auth: &auth.JwtAuth{Key: []byte(viper.GetString("chrly.secret"))},
|
||||||
TexturesExtraParamName: viper.GetString("textures.extra_param_name"),
|
TexturesExtraParamName: viper.GetString("textures.extra_param_name"),
|
||||||
TexturesExtraParamValue: viper.GetString("textures.extra_param_value"),
|
TexturesExtraParamValue: viper.GetString("textures.extra_param_value"),
|
||||||
}
|
}).CreateHandler()
|
||||||
|
|
||||||
finishChan := make(chan bool)
|
finishChan := make(chan bool)
|
||||||
go func() {
|
go func() {
|
||||||
if err := cfg.Run(); err != nil {
|
logger.Info(fmt.Sprintf("Starting the app, HTTP on: %s", address))
|
||||||
|
if err := http.Serve(address, handler); err != nil {
|
||||||
logger.Error(fmt.Sprintf("Error in main(): %v", err))
|
logger.Error(fmt.Sprintf("Error in main(): %v", err))
|
||||||
finishChan <- true
|
finishChan <- true
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,16 @@ var workerCmd = &cobra.Command{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := &http.UUIDsWorker{
|
address := fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port"))
|
||||||
ListenSpec: fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port")),
|
handler := (&http.UUIDsWorker{
|
||||||
UUIDsProvider: uuidsProvider,
|
UUIDsProvider: uuidsProvider,
|
||||||
Logger: logger,
|
// TODO: create an emitter, restore logger
|
||||||
}
|
}).CreateHandler()
|
||||||
|
|
||||||
finishChan := make(chan bool)
|
finishChan := make(chan bool)
|
||||||
go func() {
|
go func() {
|
||||||
if err := cfg.Run(); err != nil {
|
logger.Info(fmt.Sprintf("Starting the worker, HTTP on: %s", address))
|
||||||
|
if err := http.Serve(address, handler); err != nil {
|
||||||
logger.Error(fmt.Sprintf("Error in main(): %v", err))
|
logger.Error(fmt.Sprintf("Error in main(): %v", err))
|
||||||
finishChan <- true
|
finishChan <- true
|
||||||
}
|
}
|
||||||
|
23
http/http.go
23
http/http.go
@ -2,9 +2,32 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Emitter interface {
|
||||||
|
Emit(name string, args ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Serve(address string, handler http.Handler) error {
|
||||||
|
listener, err := net.Listen("tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &http.Server{
|
||||||
|
ReadTimeout: 5 * time.Second,
|
||||||
|
WriteTimeout: 5 * time.Second,
|
||||||
|
IdleTimeout: 60 * time.Second,
|
||||||
|
MaxHeaderBytes: 1 << 16,
|
||||||
|
Handler: handler,
|
||||||
|
}
|
||||||
|
|
||||||
|
return server.Serve(listener)
|
||||||
|
}
|
||||||
|
|
||||||
func NotFound(response http.ResponseWriter, _ *http.Request) {
|
func NotFound(response http.ResponseWriter, _ *http.Request) {
|
||||||
data, _ := json.Marshal(map[string]string{
|
data, _ := json.Marshal(map[string]string{
|
||||||
"status": "404",
|
"status": "404",
|
||||||
|
@ -6,8 +6,17 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
testify "github.com/stretchr/testify/assert"
|
testify "github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type emitterMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emitterMock) Emit(name string, args ...interface{}) {
|
||||||
|
e.Called((append([]interface{}{name}, args...))...)
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfig_NotFound(t *testing.T) {
|
func TestConfig_NotFound(t *testing.T) {
|
||||||
assert := testify.New(t)
|
assert := testify.New(t)
|
||||||
|
|
||||||
|
@ -5,15 +5,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/mono83/slf/wd"
|
|
||||||
"github.com/thedevsaddam/govalidator"
|
"github.com/thedevsaddam/govalidator"
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
@ -21,7 +18,6 @@ import (
|
|||||||
"github.com/elyby/chrly/model"
|
"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}$"
|
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)
|
var regexUuidAny = regexp.MustCompile(UUID_ANY)
|
||||||
@ -67,7 +63,7 @@ type SkinNotFoundError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e SkinNotFoundError) Error() string {
|
func (e SkinNotFoundError) Error() string {
|
||||||
return "Skin data not found."
|
return "skin data not found"
|
||||||
}
|
}
|
||||||
|
|
||||||
type CapeNotFoundError struct {
|
type CapeNotFoundError struct {
|
||||||
@ -75,7 +71,7 @@ type CapeNotFoundError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e CapeNotFoundError) Error() string {
|
func (e CapeNotFoundError) Error() string {
|
||||||
return "Cape file not found."
|
return "cape file not found"
|
||||||
}
|
}
|
||||||
|
|
||||||
type MojangTexturesProvider interface {
|
type MojangTexturesProvider interface {
|
||||||
@ -87,33 +83,13 @@ type AuthChecker interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Skinsystem struct {
|
type Skinsystem struct {
|
||||||
ListenSpec string
|
Emitter
|
||||||
TexturesExtraParamName string
|
TexturesExtraParamName string
|
||||||
TexturesExtraParamValue string
|
TexturesExtraParamValue string
|
||||||
|
|
||||||
SkinsRepo SkinsRepository
|
SkinsRepo SkinsRepository
|
||||||
CapesRepo CapesRepository
|
CapesRepo CapesRepository
|
||||||
MojangTexturesProvider MojangTexturesProvider
|
MojangTexturesProvider MojangTexturesProvider
|
||||||
Auth AuthChecker
|
Auth AuthChecker
|
||||||
Logger wd.Watchdog
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *Skinsystem) Run() error {
|
|
||||||
ctx.Logger.Info(fmt.Sprintf("Starting the app, HTTP on: %s\n", ctx.ListenSpec))
|
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", ctx.ListenSpec)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
server := &http.Server{
|
|
||||||
ReadTimeout: 60 * time.Second,
|
|
||||||
WriteTimeout: 60 * time.Second,
|
|
||||||
MaxHeaderBytes: 1 << 16,
|
|
||||||
Handler: ctx.CreateHandler(),
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Serve(listener)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) CreateHandler() *mux.Router {
|
func (ctx *Skinsystem) CreateHandler() *mux.Router {
|
||||||
@ -129,9 +105,9 @@ func (ctx *Skinsystem) CreateHandler() *mux.Router {
|
|||||||
// API
|
// API
|
||||||
apiRouter := router.PathPrefix("/api").Subrouter()
|
apiRouter := router.PathPrefix("/api").Subrouter()
|
||||||
apiRouter.Use(ctx.AuthenticationMiddleware)
|
apiRouter.Use(ctx.AuthenticationMiddleware)
|
||||||
apiRouter.Handle("/skins", http.HandlerFunc(ctx.PostSkin)).Methods("POST")
|
apiRouter.HandleFunc("/skins", ctx.PostSkin).Methods("POST")
|
||||||
apiRouter.Handle("/skins/id:{id:[0-9]+}", http.HandlerFunc(ctx.DeleteSkinByUserId)).Methods("DELETE")
|
apiRouter.HandleFunc("/skins/id:{id:[0-9]+}", ctx.DeleteSkinByUserId).Methods("DELETE")
|
||||||
apiRouter.Handle("/skins/{username}", http.HandlerFunc(ctx.DeleteSkinByUsername)).Methods("DELETE")
|
apiRouter.HandleFunc("/skins/{username}", ctx.DeleteSkinByUsername).Methods("DELETE")
|
||||||
// 404
|
// 404
|
||||||
router.NotFoundHandler = http.HandlerFunc(NotFound)
|
router.NotFoundHandler = http.HandlerFunc(NotFound)
|
||||||
|
|
||||||
@ -139,10 +115,6 @@ func (ctx *Skinsystem) CreateHandler() *mux.Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) Skin(response http.ResponseWriter, request *http.Request) {
|
func (ctx *Skinsystem) Skin(response http.ResponseWriter, request *http.Request) {
|
||||||
if mux.Vars(request)["converted"] == "" {
|
|
||||||
ctx.Logger.IncCounter("skins.request", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
username := parseUsername(mux.Vars(request)["username"])
|
username := parseUsername(mux.Vars(request)["username"])
|
||||||
rec, err := ctx.SkinsRepo.FindByUsername(username)
|
rec, err := ctx.SkinsRepo.FindByUsername(username)
|
||||||
if err == nil && rec.SkinId != 0 {
|
if err == nil && rec.SkinId != 0 {
|
||||||
@ -173,7 +145,6 @@ func (ctx *Skinsystem) SkinGET(response http.ResponseWriter, request *http.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.IncCounter("skins.get_request", 1)
|
|
||||||
mux.Vars(request)["username"] = username
|
mux.Vars(request)["username"] = username
|
||||||
mux.Vars(request)["converted"] = "1"
|
mux.Vars(request)["converted"] = "1"
|
||||||
|
|
||||||
@ -181,10 +152,6 @@ func (ctx *Skinsystem) SkinGET(response http.ResponseWriter, request *http.Reque
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) Cape(response http.ResponseWriter, request *http.Request) {
|
func (ctx *Skinsystem) Cape(response http.ResponseWriter, request *http.Request) {
|
||||||
if mux.Vars(request)["converted"] == "" {
|
|
||||||
ctx.Logger.IncCounter("capes.request", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
username := parseUsername(mux.Vars(request)["username"])
|
username := parseUsername(mux.Vars(request)["username"])
|
||||||
rec, err := ctx.CapesRepo.FindByUsername(username)
|
rec, err := ctx.CapesRepo.FindByUsername(username)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -216,7 +183,6 @@ func (ctx *Skinsystem) CapeGET(response http.ResponseWriter, request *http.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.IncCounter("capes.get_request", 1)
|
|
||||||
mux.Vars(request)["username"] = username
|
mux.Vars(request)["username"] = username
|
||||||
mux.Vars(request)["converted"] = "1"
|
mux.Vars(request)["converted"] = "1"
|
||||||
|
|
||||||
@ -224,7 +190,6 @@ func (ctx *Skinsystem) CapeGET(response http.ResponseWriter, request *http.Reque
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) Textures(response http.ResponseWriter, request *http.Request) {
|
func (ctx *Skinsystem) Textures(response http.ResponseWriter, request *http.Request) {
|
||||||
ctx.Logger.IncCounter("textures.request", 1)
|
|
||||||
username := parseUsername(mux.Vars(request)["username"])
|
username := parseUsername(mux.Vars(request)["username"])
|
||||||
|
|
||||||
var textures *mojang.TexturesResponse
|
var textures *mojang.TexturesResponse
|
||||||
@ -261,8 +226,8 @@ func (ctx *Skinsystem) Textures(response http.ResponseWriter, request *http.Requ
|
|||||||
|
|
||||||
texturesProp := mojangTextures.DecodeTextures()
|
texturesProp := mojangTextures.DecodeTextures()
|
||||||
if texturesProp == nil {
|
if texturesProp == nil {
|
||||||
response.WriteHeader(http.StatusInternalServerError)
|
ctx.Emitter.Emit("skinsystem.error", errors.New("unable to find textures property"))
|
||||||
ctx.Logger.Error("Unable to find textures property")
|
apiServerError(response)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +240,6 @@ func (ctx *Skinsystem) Textures(response http.ResponseWriter, request *http.Requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) SignedTextures(response http.ResponseWriter, request *http.Request) {
|
func (ctx *Skinsystem) SignedTextures(response http.ResponseWriter, request *http.Request) {
|
||||||
ctx.Logger.IncCounter("signed_textures.request", 1)
|
|
||||||
username := parseUsername(mux.Vars(request)["username"])
|
username := parseUsername(mux.Vars(request)["username"])
|
||||||
|
|
||||||
var responseData *mojang.SignedTexturesResponse
|
var responseData *mojang.SignedTexturesResponse
|
||||||
@ -316,10 +280,8 @@ func (ctx *Skinsystem) SignedTextures(response http.ResponseWriter, request *htt
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) PostSkin(resp http.ResponseWriter, req *http.Request) {
|
func (ctx *Skinsystem) PostSkin(resp http.ResponseWriter, req *http.Request) {
|
||||||
ctx.Logger.IncCounter("api.skins.post.request", 1)
|
|
||||||
validationErrors := validatePostSkinRequest(req)
|
validationErrors := validatePostSkinRequest(req)
|
||||||
if validationErrors != nil {
|
if validationErrors != nil {
|
||||||
ctx.Logger.IncCounter("api.skins.post.validation_failed", 1)
|
|
||||||
apiBadRequest(resp, validationErrors)
|
apiBadRequest(resp, validationErrors)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -329,7 +291,7 @@ func (ctx *Skinsystem) PostSkin(resp http.ResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
record, err := findIdentity(ctx.SkinsRepo, identityId, username)
|
record, err := findIdentity(ctx.SkinsRepo, identityId, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Logger.Error("Error on requesting a skin from the repository: :err", wd.ErrParam(err))
|
ctx.Emitter.Emit("skinsystem:error", fmt.Errorf("error on requesting a skin from the repository: %w", err))
|
||||||
apiServerError(resp)
|
apiServerError(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -348,71 +310,67 @@ func (ctx *Skinsystem) PostSkin(resp http.ResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
err = ctx.SkinsRepo.Save(record)
|
err = ctx.SkinsRepo.Save(record)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Logger.Error("Unable to save record to the repository: :err", wd.ErrParam(err))
|
ctx.Emitter.Emit("skinsystem:error", fmt.Errorf("unable to save record to the repository: %w", err))
|
||||||
apiServerError(resp)
|
apiServerError(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.IncCounter("api.skins.post.success", 1)
|
|
||||||
resp.WriteHeader(http.StatusCreated)
|
resp.WriteHeader(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) DeleteSkinByUserId(resp http.ResponseWriter, req *http.Request) {
|
func (ctx *Skinsystem) DeleteSkinByUserId(resp http.ResponseWriter, req *http.Request) {
|
||||||
ctx.Logger.IncCounter("api.skins.delete.request", 1)
|
|
||||||
id, _ := strconv.Atoi(mux.Vars(req)["id"])
|
id, _ := strconv.Atoi(mux.Vars(req)["id"])
|
||||||
skin, err := ctx.SkinsRepo.FindByUserId(id)
|
skin, err := ctx.SkinsRepo.FindByUserId(id)
|
||||||
if err != nil {
|
ctx.deleteSkin(skin, err, resp)
|
||||||
ctx.Logger.IncCounter("api.skins.delete.not_found", 1)
|
|
||||||
apiNotFound(resp, "Cannot find record for requested user id")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.deleteSkin(skin, resp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) DeleteSkinByUsername(resp http.ResponseWriter, req *http.Request) {
|
func (ctx *Skinsystem) DeleteSkinByUsername(resp http.ResponseWriter, req *http.Request) {
|
||||||
ctx.Logger.IncCounter("api.skins.delete.request", 1)
|
|
||||||
username := mux.Vars(req)["username"]
|
username := mux.Vars(req)["username"]
|
||||||
skin, err := ctx.SkinsRepo.FindByUsername(username)
|
skin, err := ctx.SkinsRepo.FindByUsername(username)
|
||||||
if err != nil {
|
ctx.deleteSkin(skin, err, resp)
|
||||||
ctx.Logger.IncCounter("api.skins.delete.not_found", 1)
|
|
||||||
apiNotFound(resp, "Cannot find record for requested username")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.deleteSkin(skin, resp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) AuthenticationMiddleware(handler http.Handler) http.Handler {
|
func (ctx *Skinsystem) AuthenticationMiddleware(handler http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||||
ctx.Logger.IncCounter("authentication.challenge", 1)
|
// TODO: decide on how I would cover this with logging
|
||||||
|
// ctx.Logger.IncCounter("authentication.challenge", 1)
|
||||||
err := ctx.Auth.Check(req)
|
err := ctx.Auth.Check(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(*auth.Unauthorized); ok {
|
if _, ok := err.(*auth.Unauthorized); ok {
|
||||||
ctx.Logger.IncCounter("authentication.failed", 1)
|
// ctx.Logger.IncCounter("authentication.failed", 1)
|
||||||
apiForbidden(resp, err.Error())
|
apiForbidden(resp, err.Error())
|
||||||
} else {
|
} else {
|
||||||
ctx.Logger.Error("Unknown error on validating api request: :err", wd.ErrParam(err))
|
// ctx.Logger.Error("Unknown error on validating api request: :err", wd.ErrParam(err))
|
||||||
apiServerError(resp)
|
apiServerError(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.IncCounter("authentication.success", 1)
|
// ctx.Logger.IncCounter("authentication.success", 1)
|
||||||
handler.ServeHTTP(resp, req)
|
handler.ServeHTTP(resp, req)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Skinsystem) deleteSkin(skin *model.Skin, resp http.ResponseWriter) {
|
func (ctx *Skinsystem) deleteSkin(skin *model.Skin, err error, resp http.ResponseWriter) {
|
||||||
err := ctx.SkinsRepo.RemoveByUserId(skin.UserId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Logger.Error("Cannot delete skin by error: :err", wd.ErrParam(err))
|
if _, ok := err.(*SkinNotFoundError); ok {
|
||||||
|
apiNotFound(resp, "Cannot find record for the requested identifier")
|
||||||
|
} else {
|
||||||
|
ctx.Emitter.Emit("skinsystem:error", fmt.Errorf("unable to find skin info from the repository: %w", err))
|
||||||
|
apiServerError(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ctx.SkinsRepo.RemoveByUserId(skin.UserId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Emitter.Emit("skinsystem:error", fmt.Errorf("cannot delete skin by error: %w", err))
|
||||||
apiServerError(resp)
|
apiServerError(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.IncCounter("api.skins.delete.success", 1)
|
|
||||||
resp.WriteHeader(http.StatusNoContent)
|
resp.WriteHeader(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ package http
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"github.com/elyby/chrly/auth"
|
"errors"
|
||||||
testify "github.com/stretchr/testify/assert"
|
|
||||||
"image"
|
"image"
|
||||||
"image/png"
|
"image/png"
|
||||||
"io"
|
"io"
|
||||||
@ -16,12 +15,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
testify "github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
|
"github.com/elyby/chrly/auth"
|
||||||
"github.com/elyby/chrly/model"
|
"github.com/elyby/chrly/model"
|
||||||
"github.com/elyby/chrly/tests"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
@ -113,7 +113,7 @@ type skinsystemTestSuite struct {
|
|||||||
CapesRepository *capesRepositoryMock
|
CapesRepository *capesRepositoryMock
|
||||||
MojangTexturesProvider *mojangTexturesProviderMock
|
MojangTexturesProvider *mojangTexturesProviderMock
|
||||||
Auth *authCheckerMock
|
Auth *authCheckerMock
|
||||||
Logger *tests.WdMock
|
Emitter *emitterMock
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
@ -125,14 +125,14 @@ func (suite *skinsystemTestSuite) SetupTest() {
|
|||||||
suite.CapesRepository = &capesRepositoryMock{}
|
suite.CapesRepository = &capesRepositoryMock{}
|
||||||
suite.MojangTexturesProvider = &mojangTexturesProviderMock{}
|
suite.MojangTexturesProvider = &mojangTexturesProviderMock{}
|
||||||
suite.Auth = &authCheckerMock{}
|
suite.Auth = &authCheckerMock{}
|
||||||
suite.Logger = &tests.WdMock{}
|
suite.Emitter = &emitterMock{}
|
||||||
|
|
||||||
suite.App = &Skinsystem{
|
suite.App = &Skinsystem{
|
||||||
SkinsRepo: suite.SkinsRepository,
|
SkinsRepo: suite.SkinsRepository,
|
||||||
CapesRepo: suite.CapesRepository,
|
CapesRepo: suite.CapesRepository,
|
||||||
MojangTexturesProvider: suite.MojangTexturesProvider,
|
MojangTexturesProvider: suite.MojangTexturesProvider,
|
||||||
Auth: suite.Auth,
|
Auth: suite.Auth,
|
||||||
Logger: suite.Logger,
|
Emitter: suite.Emitter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ func (suite *skinsystemTestSuite) TearDownTest() {
|
|||||||
suite.CapesRepository.AssertExpectations(suite.T())
|
suite.CapesRepository.AssertExpectations(suite.T())
|
||||||
suite.MojangTexturesProvider.AssertExpectations(suite.T())
|
suite.MojangTexturesProvider.AssertExpectations(suite.T())
|
||||||
suite.Auth.AssertExpectations(suite.T())
|
suite.Auth.AssertExpectations(suite.T())
|
||||||
suite.Logger.AssertExpectations(suite.T())
|
suite.Emitter.AssertExpectations(suite.T())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *skinsystemTestSuite) RunSubTest(name string, subTest func()) {
|
func (suite *skinsystemTestSuite) RunSubTest(name string, subTest func()) {
|
||||||
@ -215,7 +215,6 @@ var skinsTestsCases = []*skinsystemTestCase{
|
|||||||
func (suite *skinsystemTestSuite) TestSkin() {
|
func (suite *skinsystemTestSuite) TestSkin() {
|
||||||
for _, testCase := range skinsTestsCases {
|
for _, testCase := range skinsTestsCases {
|
||||||
suite.RunSubTest(testCase.Name, func() {
|
suite.RunSubTest(testCase.Name, func() {
|
||||||
suite.Logger.On("IncCounter", "skins.request", int64(1)).Once()
|
|
||||||
testCase.BeforeTest(suite)
|
testCase.BeforeTest(suite)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://chrly/skins/mock_username", nil)
|
req := httptest.NewRequest("GET", "http://chrly/skins/mock_username", nil)
|
||||||
@ -228,7 +227,6 @@ func (suite *skinsystemTestSuite) TestSkin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suite.RunSubTest("Pass username with png extension", func() {
|
suite.RunSubTest("Pass username with png extension", func() {
|
||||||
suite.Logger.On("IncCounter", "skins.request", int64(1)).Once()
|
|
||||||
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://chrly/skins/mock_username.png", nil)
|
req := httptest.NewRequest("GET", "http://chrly/skins/mock_username.png", nil)
|
||||||
@ -245,7 +243,6 @@ func (suite *skinsystemTestSuite) TestSkin() {
|
|||||||
func (suite *skinsystemTestSuite) TestSkinGET() {
|
func (suite *skinsystemTestSuite) TestSkinGET() {
|
||||||
for _, testCase := range skinsTestsCases {
|
for _, testCase := range skinsTestsCases {
|
||||||
suite.RunSubTest(testCase.Name, func() {
|
suite.RunSubTest(testCase.Name, func() {
|
||||||
suite.Logger.On("IncCounter", "skins.get_request", int64(1)).Once()
|
|
||||||
testCase.BeforeTest(suite)
|
testCase.BeforeTest(suite)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://chrly/skins?name=mock_username", nil)
|
req := httptest.NewRequest("GET", "http://chrly/skins?name=mock_username", nil)
|
||||||
@ -321,7 +318,6 @@ var capesTestsCases = []*skinsystemTestCase{
|
|||||||
func (suite *skinsystemTestSuite) TestCape() {
|
func (suite *skinsystemTestSuite) TestCape() {
|
||||||
for _, testCase := range capesTestsCases {
|
for _, testCase := range capesTestsCases {
|
||||||
suite.RunSubTest(testCase.Name, func() {
|
suite.RunSubTest(testCase.Name, func() {
|
||||||
suite.Logger.On("IncCounter", "capes.request", int64(1)).Once()
|
|
||||||
testCase.BeforeTest(suite)
|
testCase.BeforeTest(suite)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://chrly/cloaks/mock_username", nil)
|
req := httptest.NewRequest("GET", "http://chrly/cloaks/mock_username", nil)
|
||||||
@ -334,7 +330,6 @@ func (suite *skinsystemTestSuite) TestCape() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suite.RunSubTest("Pass username with png extension", func() {
|
suite.RunSubTest("Pass username with png extension", func() {
|
||||||
suite.Logger.On("IncCounter", "capes.request", int64(1)).Once()
|
|
||||||
suite.CapesRepository.On("FindByUsername", "mock_username").Return(createCapeModel(), nil)
|
suite.CapesRepository.On("FindByUsername", "mock_username").Return(createCapeModel(), nil)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://chrly/cloaks/mock_username.png", nil)
|
req := httptest.NewRequest("GET", "http://chrly/cloaks/mock_username.png", nil)
|
||||||
@ -353,7 +348,6 @@ func (suite *skinsystemTestSuite) TestCape() {
|
|||||||
func (suite *skinsystemTestSuite) TestCapeGET() {
|
func (suite *skinsystemTestSuite) TestCapeGET() {
|
||||||
for _, testCase := range capesTestsCases {
|
for _, testCase := range capesTestsCases {
|
||||||
suite.RunSubTest(testCase.Name, func() {
|
suite.RunSubTest(testCase.Name, func() {
|
||||||
suite.Logger.On("IncCounter", "capes.get_request", int64(1)).Once()
|
|
||||||
testCase.BeforeTest(suite)
|
testCase.BeforeTest(suite)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://chrly/cloaks?name=mock_username", nil)
|
req := httptest.NewRequest("GET", "http://chrly/cloaks?name=mock_username", nil)
|
||||||
@ -492,7 +486,6 @@ var texturesTestsCases = []*skinsystemTestCase{
|
|||||||
func (suite *skinsystemTestSuite) TestTextures() {
|
func (suite *skinsystemTestSuite) TestTextures() {
|
||||||
for _, testCase := range texturesTestsCases {
|
for _, testCase := range texturesTestsCases {
|
||||||
suite.RunSubTest(testCase.Name, func() {
|
suite.RunSubTest(testCase.Name, func() {
|
||||||
suite.Logger.On("IncCounter", "textures.request", int64(1)).Once()
|
|
||||||
testCase.BeforeTest(suite)
|
testCase.BeforeTest(suite)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://chrly/textures/mock_username", nil)
|
req := httptest.NewRequest("GET", "http://chrly/textures/mock_username", nil)
|
||||||
@ -616,7 +609,6 @@ var signedTexturesTestsCases = []*signedTexturesTestCase{
|
|||||||
func (suite *skinsystemTestSuite) TestSignedTextures() {
|
func (suite *skinsystemTestSuite) TestSignedTextures() {
|
||||||
for _, testCase := range signedTexturesTestsCases {
|
for _, testCase := range signedTexturesTestsCases {
|
||||||
suite.RunSubTest(testCase.Name, func() {
|
suite.RunSubTest(testCase.Name, func() {
|
||||||
suite.Logger.On("IncCounter", "signed_textures.request", int64(1)).Once()
|
|
||||||
testCase.BeforeTest(suite)
|
testCase.BeforeTest(suite)
|
||||||
|
|
||||||
var target string
|
var target string
|
||||||
@ -769,15 +761,62 @@ var postSkinTestsCases = []*postSkinTestCase{
|
|||||||
suite.Empty(body)
|
suite.Empty(body)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "Handle an error when loading the data from the repository",
|
||||||
|
Form: bytes.NewBufferString(url.Values{
|
||||||
|
"identityId": {"1"},
|
||||||
|
"username": {"mock_username"},
|
||||||
|
"uuid": {"0f657aa8-bfbe-415d-b700-5750090d3af3"},
|
||||||
|
"skinId": {"5"},
|
||||||
|
"is1_8": {"1"},
|
||||||
|
"isSlim": {"1"},
|
||||||
|
"url": {"http://textures-server.com/skin.png"},
|
||||||
|
}.Encode()),
|
||||||
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
||||||
|
suite.SkinsRepository.On("FindByUserId", 1).Return(createSkinModel("mock_username", false), nil)
|
||||||
|
err := errors.New("mock error")
|
||||||
|
suite.SkinsRepository.On("Save", mock.Anything).Return(err)
|
||||||
|
suite.Emitter.On("Emit", "skinsystem:error", mock.MatchedBy(func(cErr error) bool {
|
||||||
|
return cErr.Error() == "unable to save record to the repository: mock error" &&
|
||||||
|
errors.Is(cErr, err)
|
||||||
|
})).Once()
|
||||||
|
},
|
||||||
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
||||||
|
suite.Equal(500, response.StatusCode)
|
||||||
|
body, _ := ioutil.ReadAll(response.Body)
|
||||||
|
suite.Empty(body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Handle an error when saving the data into the repository",
|
||||||
|
Form: bytes.NewBufferString(url.Values{
|
||||||
|
"identityId": {"1"},
|
||||||
|
"username": {"changed_username"},
|
||||||
|
"uuid": {"0f657aa8-bfbe-415d-b700-5750090d3af3"},
|
||||||
|
"skinId": {"5"},
|
||||||
|
"is1_8": {"0"},
|
||||||
|
"isSlim": {"0"},
|
||||||
|
"url": {"http://example.com/skin.png"},
|
||||||
|
}.Encode()),
|
||||||
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
||||||
|
err := errors.New("mock error")
|
||||||
|
suite.SkinsRepository.On("FindByUserId", 1).Return(nil, err)
|
||||||
|
suite.Emitter.On("Emit", "skinsystem:error", mock.MatchedBy(func(cErr error) bool {
|
||||||
|
return cErr.Error() == "error on requesting a skin from the repository: mock error" &&
|
||||||
|
errors.Is(cErr, err)
|
||||||
|
})).Once()
|
||||||
|
},
|
||||||
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
||||||
|
suite.Equal(500, response.StatusCode)
|
||||||
|
body, _ := ioutil.ReadAll(response.Body)
|
||||||
|
suite.Empty(body)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *skinsystemTestSuite) TestPostSkin() {
|
func (suite *skinsystemTestSuite) TestPostSkin() {
|
||||||
for _, testCase := range postSkinTestsCases {
|
for _, testCase := range postSkinTestsCases {
|
||||||
suite.RunSubTest(testCase.Name, func() {
|
suite.RunSubTest(testCase.Name, func() {
|
||||||
suite.Logger.On("IncCounter", "authentication.challenge", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "authentication.success", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.post.request", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.post.success", int64(1)).Once()
|
|
||||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||||
testCase.BeforeTest(suite)
|
testCase.BeforeTest(suite)
|
||||||
|
|
||||||
@ -792,10 +831,6 @@ func (suite *skinsystemTestSuite) TestPostSkin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suite.RunSubTest("Get errors about required fields", func() {
|
suite.RunSubTest("Get errors about required fields", func() {
|
||||||
suite.Logger.On("IncCounter", "authentication.challenge", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "authentication.success", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.post.request", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.post.validation_failed", int64(1)).Once()
|
|
||||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||||
|
|
||||||
req := httptest.NewRequest("POST", "http://chrly/api/skins", bytes.NewBufferString(url.Values{
|
req := httptest.NewRequest("POST", "http://chrly/api/skins", bytes.NewBufferString(url.Values{
|
||||||
@ -848,8 +883,6 @@ func (suite *skinsystemTestSuite) TestPostSkin() {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
suite.Auth.On("Check", mock.Anything).Return(&auth.Unauthorized{Reason: "Cannot parse passed JWT token"})
|
suite.Auth.On("Check", mock.Anything).Return(&auth.Unauthorized{Reason: "Cannot parse passed JWT token"})
|
||||||
suite.Logger.On("IncCounter", "authentication.challenge", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "authentication.failed", int64(1)).Once()
|
|
||||||
|
|
||||||
suite.App.CreateHandler().ServeHTTP(w, req)
|
suite.App.CreateHandler().ServeHTTP(w, req)
|
||||||
|
|
||||||
@ -863,10 +896,6 @@ func (suite *skinsystemTestSuite) TestPostSkin() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
suite.RunSubTest("Upload textures with skin as file", func() {
|
suite.RunSubTest("Upload textures with skin as file", func() {
|
||||||
suite.Logger.On("IncCounter", "authentication.challenge", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "authentication.success", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.post.request", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.post.validation_failed", int64(1)).Once()
|
|
||||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||||
|
|
||||||
inputBody := &bytes.Buffer{}
|
inputBody := &bytes.Buffer{}
|
||||||
@ -914,10 +943,6 @@ func (suite *skinsystemTestSuite) TestDeleteByUserId() {
|
|||||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||||
suite.SkinsRepository.On("FindByUserId", 1).Return(createSkinModel("mock_username", false), nil)
|
suite.SkinsRepository.On("FindByUserId", 1).Return(createSkinModel("mock_username", false), nil)
|
||||||
suite.SkinsRepository.On("RemoveByUserId", 1).Once().Return(nil)
|
suite.SkinsRepository.On("RemoveByUserId", 1).Once().Return(nil)
|
||||||
suite.Logger.On("IncCounter", "authentication.challenge", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "authentication.success", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.delete.request", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.delete.success", int64(1)).Once()
|
|
||||||
|
|
||||||
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/id:1", nil)
|
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/id:1", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -934,10 +959,6 @@ func (suite *skinsystemTestSuite) TestDeleteByUserId() {
|
|||||||
suite.RunSubTest("Try to remove not exists identity id", func() {
|
suite.RunSubTest("Try to remove not exists identity id", func() {
|
||||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||||
suite.SkinsRepository.On("FindByUserId", 1).Return(nil, &SkinNotFoundError{Who: "unknown"})
|
suite.SkinsRepository.On("FindByUserId", 1).Return(nil, &SkinNotFoundError{Who: "unknown"})
|
||||||
suite.Logger.On("IncCounter", "authentication.challenge", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "authentication.success", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.delete.request", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.delete.not_found", int64(1)).Once()
|
|
||||||
|
|
||||||
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/id:1", nil)
|
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/id:1", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -949,7 +970,7 @@ func (suite *skinsystemTestSuite) TestDeleteByUserId() {
|
|||||||
suite.Equal(404, resp.StatusCode)
|
suite.Equal(404, resp.StatusCode)
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
suite.JSONEq(`[
|
suite.JSONEq(`[
|
||||||
"Cannot find record for requested user id"
|
"Cannot find record for the requested identifier"
|
||||||
]`, string(body))
|
]`, string(body))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -963,10 +984,6 @@ func (suite *skinsystemTestSuite) TestDeleteByUsername() {
|
|||||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||||
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
||||||
suite.SkinsRepository.On("RemoveByUserId", 1).Once().Return(nil)
|
suite.SkinsRepository.On("RemoveByUserId", 1).Once().Return(nil)
|
||||||
suite.Logger.On("IncCounter", "authentication.challenge", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "authentication.success", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.delete.request", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.delete.success", int64(1)).Once()
|
|
||||||
|
|
||||||
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/mock_username", nil)
|
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/mock_username", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -983,10 +1000,6 @@ func (suite *skinsystemTestSuite) TestDeleteByUsername() {
|
|||||||
suite.RunSubTest("Try to remove not exists identity username", func() {
|
suite.RunSubTest("Try to remove not exists identity username", func() {
|
||||||
suite.Auth.On("Check", mock.Anything).Return(nil)
|
suite.Auth.On("Check", mock.Anything).Return(nil)
|
||||||
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(nil, &SkinNotFoundError{Who: "mock_username"})
|
suite.SkinsRepository.On("FindByUsername", "mock_username").Return(nil, &SkinNotFoundError{Who: "mock_username"})
|
||||||
suite.Logger.On("IncCounter", "authentication.challenge", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "authentication.success", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.delete.request", int64(1)).Once()
|
|
||||||
suite.Logger.On("IncCounter", "api.skins.delete.not_found", int64(1)).Once()
|
|
||||||
|
|
||||||
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/mock_username", nil)
|
req := httptest.NewRequest("DELETE", "http://chrly/api/skins/mock_username", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -998,7 +1011,7 @@ func (suite *skinsystemTestSuite) TestDeleteByUsername() {
|
|||||||
suite.Equal(404, resp.StatusCode)
|
suite.Equal(404, resp.StatusCode)
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
suite.JSONEq(`[
|
suite.JSONEq(`[
|
||||||
"Cannot find record for requested username"
|
"Cannot find record for the requested identifier"
|
||||||
]`, string(body))
|
]`, string(body))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,9 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/mono83/slf/wd"
|
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
"github.com/elyby/chrly/mojangtextures"
|
"github.com/elyby/chrly/mojangtextures"
|
||||||
@ -19,31 +15,11 @@ type UuidsProvider interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UUIDsWorker struct {
|
type UUIDsWorker struct {
|
||||||
ListenSpec string
|
Emitter
|
||||||
|
|
||||||
UUIDsProvider mojangtextures.UUIDsProvider
|
UUIDsProvider mojangtextures.UUIDsProvider
|
||||||
Logger wd.Watchdog
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *UUIDsWorker) Run() error {
|
func (ctx *UUIDsWorker) CreateHandler() *mux.Router {
|
||||||
ctx.Logger.Info(fmt.Sprintf("Starting the worker, HTTP on: %s\n", ctx.ListenSpec))
|
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", ctx.ListenSpec)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
server := &http.Server{
|
|
||||||
ReadTimeout: 60 * time.Second,
|
|
||||||
WriteTimeout: 60 * time.Second, // TODO: should I adjust this values?
|
|
||||||
MaxHeaderBytes: 1 << 16,
|
|
||||||
Handler: ctx.CreateHandler(),
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Serve(listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *UUIDsWorker) CreateHandler() http.Handler {
|
|
||||||
router := mux.NewRouter().StrictSlash(true)
|
router := mux.NewRouter().StrictSlash(true)
|
||||||
router.NotFoundHandler = http.HandlerFunc(NotFound)
|
router.NotFoundHandler = http.HandlerFunc(NotFound)
|
||||||
|
|
||||||
@ -56,13 +32,12 @@ func (ctx *UUIDsWorker) GetUUID(response http.ResponseWriter, request *http.Requ
|
|||||||
username := parseUsername(mux.Vars(request)["username"])
|
username := parseUsername(mux.Vars(request)["username"])
|
||||||
profile, err := ctx.UUIDsProvider.GetUuid(username)
|
profile, err := ctx.UUIDsProvider.GetUuid(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ctx.Emitter.Emit("uuids_provider:error", err) // TODO: do I need emitter here?
|
||||||
if _, ok := err.(*mojang.TooManyRequestsError); ok {
|
if _, ok := err.(*mojang.TooManyRequestsError); ok {
|
||||||
ctx.Logger.Warning("Got 429 Too Many Requests")
|
|
||||||
response.WriteHeader(http.StatusTooManyRequests)
|
response.WriteHeader(http.StatusTooManyRequests)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.Warning("Got non success response: :err", wd.ErrParam(err))
|
|
||||||
response.Header().Set("Content-Type", "application/json")
|
response.Header().Set("Content-Type", "application/json")
|
||||||
response.WriteHeader(http.StatusInternalServerError)
|
response.WriteHeader(http.StatusInternalServerError)
|
||||||
result, _ := json.Marshal(map[string]interface{}{
|
result, _ := json.Marshal(map[string]interface{}{
|
||||||
|
@ -2,14 +2,15 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/elyby/chrly/api/mojang"
|
|
||||||
"github.com/elyby/chrly/tests"
|
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"github.com/stretchr/testify/suite"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/elyby/chrly/api/mojang"
|
||||||
)
|
)
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
@ -36,7 +37,7 @@ type uuidsWorkerTestSuite struct {
|
|||||||
App *UUIDsWorker
|
App *UUIDsWorker
|
||||||
|
|
||||||
UuidsProvider *uuidsProviderMock
|
UuidsProvider *uuidsProviderMock
|
||||||
Logger *tests.WdMock
|
Emitter *emitterMock
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
@ -45,17 +46,17 @@ type uuidsWorkerTestSuite struct {
|
|||||||
|
|
||||||
func (suite *uuidsWorkerTestSuite) SetupTest() {
|
func (suite *uuidsWorkerTestSuite) SetupTest() {
|
||||||
suite.UuidsProvider = &uuidsProviderMock{}
|
suite.UuidsProvider = &uuidsProviderMock{}
|
||||||
suite.Logger = &tests.WdMock{}
|
suite.Emitter = &emitterMock{}
|
||||||
|
|
||||||
suite.App = &UUIDsWorker{
|
suite.App = &UUIDsWorker{
|
||||||
UUIDsProvider: suite.UuidsProvider,
|
UUIDsProvider: suite.UuidsProvider,
|
||||||
Logger: suite.Logger,
|
Emitter: suite.Emitter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *uuidsWorkerTestSuite) TearDownTest() {
|
func (suite *uuidsWorkerTestSuite) TearDownTest() {
|
||||||
suite.UuidsProvider.AssertExpectations(suite.T())
|
suite.UuidsProvider.AssertExpectations(suite.T())
|
||||||
suite.Logger.AssertExpectations(suite.T())
|
suite.Emitter.AssertExpectations(suite.T())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *uuidsWorkerTestSuite) RunSubTest(name string, subTest func()) {
|
func (suite *uuidsWorkerTestSuite) RunSubTest(name string, subTest func()) {
|
||||||
@ -115,8 +116,9 @@ var getUuidTestsCases = []*uuidsWorkerTestCase{
|
|||||||
{
|
{
|
||||||
Name: "Receive error from UUIDs provider",
|
Name: "Receive error from UUIDs provider",
|
||||||
BeforeTest: func(suite *uuidsWorkerTestSuite) {
|
BeforeTest: func(suite *uuidsWorkerTestSuite) {
|
||||||
suite.UuidsProvider.On("GetUuid", "mock_username").Return(nil, errors.New("this is an error"))
|
err := errors.New("this is an error")
|
||||||
suite.Logger.On("Warning", "Got non success response: :err", mock.Anything).Times(1)
|
suite.UuidsProvider.On("GetUuid", "mock_username").Return(nil, err)
|
||||||
|
suite.Emitter.On("Emit", "uuids_provider:error", err).Times(1)
|
||||||
},
|
},
|
||||||
AfterTest: func(suite *uuidsWorkerTestSuite, response *http.Response) {
|
AfterTest: func(suite *uuidsWorkerTestSuite, response *http.Response) {
|
||||||
suite.Equal(500, response.StatusCode)
|
suite.Equal(500, response.StatusCode)
|
||||||
@ -130,8 +132,9 @@ var getUuidTestsCases = []*uuidsWorkerTestCase{
|
|||||||
{
|
{
|
||||||
Name: "Receive Too Many Requests from UUIDs provider",
|
Name: "Receive Too Many Requests from UUIDs provider",
|
||||||
BeforeTest: func(suite *uuidsWorkerTestSuite) {
|
BeforeTest: func(suite *uuidsWorkerTestSuite) {
|
||||||
suite.UuidsProvider.On("GetUuid", "mock_username").Return(nil, &mojang.TooManyRequestsError{})
|
err := &mojang.TooManyRequestsError{}
|
||||||
suite.Logger.On("Warning", "Got 429 Too Many Requests").Times(1)
|
suite.UuidsProvider.On("GetUuid", "mock_username").Return(nil, err)
|
||||||
|
suite.Emitter.On("Emit", "uuids_provider:error", err).Times(1)
|
||||||
},
|
},
|
||||||
AfterTest: func(suite *uuidsWorkerTestSuite, response *http.Response) {
|
AfterTest: func(suite *uuidsWorkerTestSuite, response *http.Response) {
|
||||||
suite.Equal(429, response.StatusCode)
|
suite.Equal(429, response.StatusCode)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user