2020-01-02 02:12:45 +05:30
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"image"
|
|
|
|
"image/png"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2020-01-29 04:04:15 +05:30
|
|
|
testify "github.com/stretchr/testify/assert"
|
2020-01-02 02:12:45 +05:30
|
|
|
"github.com/stretchr/testify/mock"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
|
|
|
|
"github.com/elyby/chrly/api/mojang"
|
|
|
|
"github.com/elyby/chrly/model"
|
|
|
|
)
|
|
|
|
|
|
|
|
/***************
|
|
|
|
* Setup mocks *
|
|
|
|
***************/
|
|
|
|
|
|
|
|
type skinsRepositoryMock struct {
|
|
|
|
mock.Mock
|
|
|
|
}
|
|
|
|
|
2020-04-21 00:48:27 +05:30
|
|
|
func (m *skinsRepositoryMock) FindSkinByUsername(username string) (*model.Skin, error) {
|
2020-01-02 02:12:45 +05:30
|
|
|
args := m.Called(username)
|
|
|
|
var result *model.Skin
|
|
|
|
if casted, ok := args.Get(0).(*model.Skin); ok {
|
|
|
|
result = casted
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, args.Error(1)
|
|
|
|
}
|
|
|
|
|
2020-04-21 00:48:27 +05:30
|
|
|
func (m *skinsRepositoryMock) FindSkinByUserId(id int) (*model.Skin, error) {
|
2020-01-02 02:12:45 +05:30
|
|
|
args := m.Called(id)
|
|
|
|
var result *model.Skin
|
|
|
|
if casted, ok := args.Get(0).(*model.Skin); ok {
|
|
|
|
result = casted
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, args.Error(1)
|
|
|
|
}
|
|
|
|
|
2020-04-21 00:48:27 +05:30
|
|
|
func (m *skinsRepositoryMock) SaveSkin(skin *model.Skin) error {
|
2020-01-02 02:12:45 +05:30
|
|
|
args := m.Called(skin)
|
|
|
|
return args.Error(0)
|
|
|
|
}
|
|
|
|
|
2020-04-21 00:48:27 +05:30
|
|
|
func (m *skinsRepositoryMock) RemoveSkinByUserId(id int) error {
|
2020-01-02 02:12:45 +05:30
|
|
|
args := m.Called(id)
|
|
|
|
return args.Error(0)
|
|
|
|
}
|
|
|
|
|
2020-04-21 00:48:27 +05:30
|
|
|
func (m *skinsRepositoryMock) RemoveSkinByUsername(username string) error {
|
2020-01-02 02:12:45 +05:30
|
|
|
args := m.Called(username)
|
|
|
|
return args.Error(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
type capesRepositoryMock struct {
|
|
|
|
mock.Mock
|
|
|
|
}
|
|
|
|
|
2020-04-21 00:48:27 +05:30
|
|
|
func (m *capesRepositoryMock) FindCapeByUsername(username string) (*model.Cape, error) {
|
2020-01-02 02:12:45 +05:30
|
|
|
args := m.Called(username)
|
|
|
|
var result *model.Cape
|
|
|
|
if casted, ok := args.Get(0).(*model.Cape); ok {
|
|
|
|
result = casted
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, args.Error(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
type mojangTexturesProviderMock struct {
|
|
|
|
mock.Mock
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mojangTexturesProviderMock) GetForUsername(username string) (*mojang.SignedTexturesResponse, error) {
|
|
|
|
args := m.Called(username)
|
|
|
|
var result *mojang.SignedTexturesResponse
|
|
|
|
if casted, ok := args.Get(0).(*mojang.SignedTexturesResponse); ok {
|
|
|
|
result = casted
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, args.Error(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
type skinsystemTestSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
|
|
|
|
App *Skinsystem
|
|
|
|
|
|
|
|
SkinsRepository *skinsRepositoryMock
|
|
|
|
CapesRepository *capesRepositoryMock
|
|
|
|
MojangTexturesProvider *mojangTexturesProviderMock
|
2020-01-29 04:04:15 +05:30
|
|
|
Emitter *emitterMock
|
2020-01-02 02:12:45 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/********************
|
|
|
|
* Setup test suite *
|
|
|
|
********************/
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) SetupTest() {
|
|
|
|
suite.SkinsRepository = &skinsRepositoryMock{}
|
|
|
|
suite.CapesRepository = &capesRepositoryMock{}
|
|
|
|
suite.MojangTexturesProvider = &mojangTexturesProviderMock{}
|
2020-01-29 04:04:15 +05:30
|
|
|
suite.Emitter = &emitterMock{}
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
suite.App = &Skinsystem{
|
2020-04-20 19:52:04 +05:30
|
|
|
SkinsRepo: suite.SkinsRepository,
|
|
|
|
CapesRepo: suite.CapesRepository,
|
|
|
|
MojangTexturesProvider: suite.MojangTexturesProvider,
|
|
|
|
Emitter: suite.Emitter,
|
|
|
|
TexturesExtraParamName: "texturesParamName",
|
|
|
|
TexturesExtraParamValue: "texturesParamValue",
|
2020-01-02 02:12:45 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) TearDownTest() {
|
|
|
|
suite.SkinsRepository.AssertExpectations(suite.T())
|
|
|
|
suite.CapesRepository.AssertExpectations(suite.T())
|
|
|
|
suite.MojangTexturesProvider.AssertExpectations(suite.T())
|
2020-01-29 04:04:15 +05:30
|
|
|
suite.Emitter.AssertExpectations(suite.T())
|
2020-01-02 02:12:45 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) RunSubTest(name string, subTest func()) {
|
|
|
|
suite.SetupTest()
|
|
|
|
suite.Run(name, subTest)
|
|
|
|
suite.TearDownTest()
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************
|
|
|
|
* Run tests *
|
|
|
|
*************/
|
|
|
|
|
|
|
|
func TestSkinsystem(t *testing.T) {
|
|
|
|
suite.Run(t, new(skinsystemTestSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type skinsystemTestCase struct {
|
|
|
|
Name string
|
|
|
|
BeforeTest func(suite *skinsystemTestSuite)
|
|
|
|
AfterTest func(suite *skinsystemTestSuite, response *http.Response)
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************
|
|
|
|
* Get skin tests cases *
|
|
|
|
************************/
|
|
|
|
|
|
|
|
var skinsTestsCases = []*skinsystemTestCase{
|
|
|
|
{
|
|
|
|
Name: "Username exists in the local storage",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(301, response.StatusCode)
|
|
|
|
suite.Equal("http://chrly/skin.png", response.Header.Get("Location"))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username doesn't exists on the local storage, but exists on Mojang and has textures",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
2020-04-30 00:24:40 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(createMojangResponseWithTextures(true, false), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(301, response.StatusCode)
|
|
|
|
suite.Equal("http://mojang/skin.png", response.Header.Get("Location"))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2020-04-30 00:24:40 +05:30
|
|
|
Name: "Username doesn't exists on the local storage, but exists on Mojang and has no skin texture",
|
2020-01-02 02:12:45 +05:30
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
2020-04-30 00:24:40 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(createMojangResponseWithTextures(false, false), nil)
|
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(404, response.StatusCode)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username doesn't exists on the local storage, but exists on Mojang and has an empty properties",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(createEmptyMojangResponse(), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(404, response.StatusCode)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username doesn't exists on the local storage and doesn't exists on Mojang",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(nil, nil)
|
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(404, response.StatusCode)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) TestSkin() {
|
|
|
|
for _, testCase := range skinsTestsCases {
|
|
|
|
suite.RunSubTest(testCase.Name, func() {
|
|
|
|
testCase.BeforeTest(suite)
|
|
|
|
|
|
|
|
req := httptest.NewRequest("GET", "http://chrly/skins/mock_username", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
testCase.AfterTest(suite, w.Result())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
suite.RunSubTest("Pass username with png extension", func() {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
req := httptest.NewRequest("GET", "http://chrly/skins/mock_username.png", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
resp := w.Result()
|
|
|
|
suite.Equal(301, resp.StatusCode)
|
|
|
|
suite.Equal("http://chrly/skin.png", resp.Header.Get("Location"))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) TestSkinGET() {
|
|
|
|
for _, testCase := range skinsTestsCases {
|
|
|
|
suite.RunSubTest(testCase.Name, func() {
|
|
|
|
testCase.BeforeTest(suite)
|
|
|
|
|
|
|
|
req := httptest.NewRequest("GET", "http://chrly/skins?name=mock_username", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
testCase.AfterTest(suite, w.Result())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
suite.RunSubTest("Do not pass name param", func() {
|
2020-02-16 15:53:47 +05:30
|
|
|
|
2020-01-02 02:12:45 +05:30
|
|
|
req := httptest.NewRequest("GET", "http://chrly/skins", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
resp := w.Result()
|
|
|
|
suite.Equal(400, resp.StatusCode)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************
|
|
|
|
* Get cape tests cases *
|
|
|
|
************************/
|
|
|
|
|
|
|
|
var capesTestsCases = []*skinsystemTestCase{
|
|
|
|
{
|
|
|
|
Name: "Username exists in the local storage",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(createCapeModel(), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(200, response.StatusCode)
|
|
|
|
responseData, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.Equal(createCape(), responseData)
|
|
|
|
suite.Equal("image/png", response.Header.Get("Content-Type"))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username doesn't exists on the local storage, but exists on Mojang and has textures",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
2020-04-30 00:24:40 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(createMojangResponseWithTextures(true, true), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(301, response.StatusCode)
|
|
|
|
suite.Equal("http://mojang/cape.png", response.Header.Get("Location"))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2020-04-30 00:24:40 +05:30
|
|
|
Name: "Username doesn't exists on the local storage, but exists on Mojang and has no cape texture",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(createMojangResponseWithTextures(false, false), nil)
|
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(404, response.StatusCode)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username doesn't exists on the local storage, but exists on Mojang and has an empty properties",
|
2020-01-02 02:12:45 +05:30
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
2020-04-30 00:24:40 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(createEmptyMojangResponse(), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(404, response.StatusCode)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username doesn't exists on the local storage and doesn't exists on Mojang",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(nil, nil)
|
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(404, response.StatusCode)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) TestCape() {
|
|
|
|
for _, testCase := range capesTestsCases {
|
|
|
|
suite.RunSubTest(testCase.Name, func() {
|
|
|
|
testCase.BeforeTest(suite)
|
|
|
|
|
|
|
|
req := httptest.NewRequest("GET", "http://chrly/cloaks/mock_username", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
testCase.AfterTest(suite, w.Result())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
suite.RunSubTest("Pass username with png extension", func() {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(createCapeModel(), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
req := httptest.NewRequest("GET", "http://chrly/cloaks/mock_username.png", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
resp := w.Result()
|
|
|
|
suite.Equal(200, resp.StatusCode)
|
|
|
|
responseData, _ := ioutil.ReadAll(resp.Body)
|
|
|
|
suite.Equal(createCape(), responseData)
|
|
|
|
suite.Equal("image/png", resp.Header.Get("Content-Type"))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) TestCapeGET() {
|
|
|
|
for _, testCase := range capesTestsCases {
|
|
|
|
suite.RunSubTest(testCase.Name, func() {
|
|
|
|
testCase.BeforeTest(suite)
|
|
|
|
|
|
|
|
req := httptest.NewRequest("GET", "http://chrly/cloaks?name=mock_username", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
testCase.AfterTest(suite, w.Result())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
suite.RunSubTest("Do not pass name param", func() {
|
2020-02-16 15:53:47 +05:30
|
|
|
|
2020-01-02 02:12:45 +05:30
|
|
|
req := httptest.NewRequest("GET", "http://chrly/cloaks", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
resp := w.Result()
|
|
|
|
suite.Equal(400, resp.StatusCode)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************
|
|
|
|
* Get textures tests cases *
|
|
|
|
****************************/
|
|
|
|
|
|
|
|
var texturesTestsCases = []*skinsystemTestCase{
|
|
|
|
{
|
|
|
|
Name: "Username exists and has skin, no cape",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(200, response.StatusCode)
|
|
|
|
suite.Equal("application/json", response.Header.Get("Content-Type"))
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.JSONEq(`{
|
|
|
|
"SKIN": {
|
|
|
|
"url": "http://chrly/skin.png"
|
|
|
|
}
|
|
|
|
}`, string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username exists and has slim skin, no cape",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(createSkinModel("mock_username", true), nil)
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(200, response.StatusCode)
|
|
|
|
suite.Equal("application/json", response.Header.Get("Content-Type"))
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.JSONEq(`{
|
|
|
|
"SKIN": {
|
|
|
|
"url": "http://chrly/skin.png",
|
|
|
|
"metadata": {
|
|
|
|
"model": "slim"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`, string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username exists and has cape, no skin",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(createCapeModel(), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(200, response.StatusCode)
|
|
|
|
suite.Equal("application/json", response.Header.Get("Content-Type"))
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.JSONEq(`{
|
|
|
|
"CAPE": {
|
|
|
|
"url": "http://chrly/cloaks/mock_username"
|
|
|
|
}
|
|
|
|
}`, string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username exists and has both skin and cape",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(createSkinModel("mock_username", false), nil)
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(createCapeModel(), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(200, response.StatusCode)
|
|
|
|
suite.Equal("application/json", response.Header.Get("Content-Type"))
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.JSONEq(`{
|
|
|
|
"SKIN": {
|
|
|
|
"url": "http://chrly/skin.png"
|
|
|
|
},
|
|
|
|
"CAPE": {
|
|
|
|
"url": "http://chrly/cloaks/mock_username"
|
|
|
|
}
|
|
|
|
}`, string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username not exists, but Mojang profile available",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
2020-04-30 00:24:40 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Once().Return(createMojangResponseWithTextures(true, true), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(200, response.StatusCode)
|
|
|
|
suite.Equal("application/json", response.Header.Get("Content-Type"))
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.JSONEq(`{
|
|
|
|
"SKIN": {
|
|
|
|
"url": "http://mojang/skin.png"
|
|
|
|
},
|
|
|
|
"CAPE": {
|
|
|
|
"url": "http://mojang/cape.png"
|
|
|
|
}
|
|
|
|
}`, string(body))
|
|
|
|
},
|
|
|
|
},
|
2020-04-20 22:28:31 +05:30
|
|
|
{
|
2020-04-30 00:24:40 +05:30
|
|
|
Name: "Username not exists, but Mojang profile available, but there is an empty skin and cape textures",
|
2020-04-20 22:28:31 +05:30
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
2020-04-30 00:24:40 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Once().Return(createMojangResponseWithTextures(false, false), nil)
|
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(204, response.StatusCode)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username not exists, but Mojang profile available, but there is an empty properties",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Once().Return(createEmptyMojangResponse(), nil)
|
2020-04-20 22:28:31 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(204, response.StatusCode)
|
|
|
|
},
|
|
|
|
},
|
2020-01-02 02:12:45 +05:30
|
|
|
{
|
|
|
|
Name: "Username not exists and Mojang profile unavailable",
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
|
|
|
suite.CapesRepository.On("FindCapeByUsername", "mock_username").Return(nil, nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Once().Return(nil, nil)
|
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(204, response.StatusCode)
|
2020-04-20 22:28:31 +05:30
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.Equal("", string(body))
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) TestTextures() {
|
|
|
|
for _, testCase := range texturesTestsCases {
|
|
|
|
suite.RunSubTest(testCase.Name, func() {
|
|
|
|
testCase.BeforeTest(suite)
|
|
|
|
|
|
|
|
req := httptest.NewRequest("GET", "http://chrly/textures/mock_username", nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
testCase.AfterTest(suite, w.Result())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************
|
|
|
|
* Get signed textures tests cases *
|
|
|
|
***********************************/
|
|
|
|
|
|
|
|
type signedTexturesTestCase struct {
|
|
|
|
Name string
|
|
|
|
AllowProxy bool
|
|
|
|
BeforeTest func(suite *skinsystemTestSuite)
|
|
|
|
AfterTest func(suite *skinsystemTestSuite, response *http.Response)
|
|
|
|
}
|
|
|
|
|
|
|
|
var signedTexturesTestsCases = []*signedTexturesTestCase{
|
|
|
|
{
|
|
|
|
Name: "Username exists",
|
|
|
|
AllowProxy: false,
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(createSkinModel("mock_username", true), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(200, response.StatusCode)
|
|
|
|
suite.Equal("application/json", response.Header.Get("Content-Type"))
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.JSONEq(`{
|
|
|
|
"id": "0f657aa8bfbe415db7005750090d3af3",
|
|
|
|
"name": "mock_username",
|
|
|
|
"properties": [
|
|
|
|
{
|
|
|
|
"name": "textures",
|
|
|
|
"signature": "mocked signature",
|
|
|
|
"value": "mocked textures base64"
|
|
|
|
},
|
|
|
|
{
|
2020-04-20 19:52:04 +05:30
|
|
|
"name": "texturesParamName",
|
|
|
|
"value": "texturesParamValue"
|
2020-01-02 02:12:45 +05:30
|
|
|
}
|
|
|
|
]
|
|
|
|
}`, string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username not exists",
|
|
|
|
AllowProxy: false,
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(204, response.StatusCode)
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.Equal("", string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username exists, but has no signed textures",
|
|
|
|
AllowProxy: false,
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
|
|
|
skinModel := createSkinModel("mock_username", true)
|
|
|
|
skinModel.MojangTextures = ""
|
|
|
|
skinModel.MojangSignature = ""
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(skinModel, nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(204, response.StatusCode)
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.Equal("", string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username not exists, but Mojang profile is available and proxying is enabled",
|
|
|
|
AllowProxy: true,
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
2020-04-30 00:24:40 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(createMojangResponseWithTextures(true, false), nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(200, response.StatusCode)
|
|
|
|
suite.Equal("application/json", response.Header.Get("Content-Type"))
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.JSONEq(`{
|
|
|
|
"id": "00000000000000000000000000000000",
|
|
|
|
"name": "mock_username",
|
|
|
|
"properties": [
|
|
|
|
{
|
|
|
|
"name": "textures",
|
|
|
|
"value": "eyJ0aW1lc3RhbXAiOjE1NTYzOTg1NzIsInByb2ZpbGVJZCI6IjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIiwicHJvZmlsZU5hbWUiOiJtb2NrX3VzZXJuYW1lIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vbW9qYW5nL3NraW4ucG5nIn19fQ=="
|
|
|
|
},
|
|
|
|
{
|
2020-04-20 19:52:04 +05:30
|
|
|
"name": "texturesParamName",
|
|
|
|
"value": "texturesParamValue"
|
2020-01-02 02:12:45 +05:30
|
|
|
}
|
|
|
|
]
|
|
|
|
}`, string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Username not exists, Mojang profile is unavailable too and proxying is enabled",
|
|
|
|
AllowProxy: true,
|
|
|
|
BeforeTest: func(suite *skinsystemTestSuite) {
|
2020-04-21 00:48:27 +05:30
|
|
|
suite.SkinsRepository.On("FindSkinByUsername", "mock_username").Return(nil, nil)
|
2020-01-02 02:12:45 +05:30
|
|
|
suite.MojangTexturesProvider.On("GetForUsername", "mock_username").Return(nil, nil)
|
|
|
|
},
|
|
|
|
AfterTest: func(suite *skinsystemTestSuite, response *http.Response) {
|
|
|
|
suite.Equal(204, response.StatusCode)
|
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
|
suite.Equal("", string(body))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func (suite *skinsystemTestSuite) TestSignedTextures() {
|
|
|
|
for _, testCase := range signedTexturesTestsCases {
|
|
|
|
suite.RunSubTest(testCase.Name, func() {
|
|
|
|
testCase.BeforeTest(suite)
|
|
|
|
|
|
|
|
var target string
|
|
|
|
if testCase.AllowProxy {
|
|
|
|
target = "http://chrly/textures/signed/mock_username?proxy=true"
|
|
|
|
} else {
|
|
|
|
target = "http://chrly/textures/signed/mock_username"
|
|
|
|
}
|
|
|
|
|
|
|
|
req := httptest.NewRequest("GET", target, nil)
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2020-04-19 05:01:09 +05:30
|
|
|
suite.App.Handler().ServeHTTP(w, req)
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
testCase.AfterTest(suite, w.Result())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Custom tests *
|
|
|
|
****************/
|
|
|
|
|
|
|
|
func TestParseUsername(t *testing.T) {
|
|
|
|
assert := testify.New(t)
|
|
|
|
assert.Equal("test", parseUsername("test.png"), "Function should trim .png at end")
|
|
|
|
assert.Equal("test", parseUsername("test"), "Function should return string itself, if it not contains .png at end")
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************
|
|
|
|
* Utilities *
|
|
|
|
*************/
|
|
|
|
|
|
|
|
func createSkinModel(username string, isSlim bool) *model.Skin {
|
|
|
|
return &model.Skin{
|
|
|
|
UserId: 1,
|
|
|
|
Username: username,
|
|
|
|
Uuid: "0f657aa8-bfbe-415d-b700-5750090d3af3", // Use non nil UUID to pass validation in api tests
|
|
|
|
SkinId: 1,
|
|
|
|
Url: "http://chrly/skin.png",
|
|
|
|
MojangTextures: "mocked textures base64",
|
|
|
|
MojangSignature: "mocked signature",
|
|
|
|
IsSlim: isSlim,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func createCape() []byte {
|
|
|
|
img := image.NewAlpha(image.Rect(0, 0, 64, 32))
|
|
|
|
writer := &bytes.Buffer{}
|
|
|
|
_ = png.Encode(writer, img)
|
|
|
|
pngBytes, _ := ioutil.ReadAll(writer)
|
|
|
|
|
|
|
|
return pngBytes
|
|
|
|
}
|
|
|
|
|
|
|
|
func createCapeModel() *model.Cape {
|
|
|
|
return &model.Cape{File: bytes.NewReader(createCape())}
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:40 +05:30
|
|
|
func createEmptyMojangResponse() *mojang.SignedTexturesResponse {
|
|
|
|
return &mojang.SignedTexturesResponse{
|
|
|
|
Id: "00000000000000000000000000000000",
|
|
|
|
Name: "mock_username",
|
|
|
|
Props: []*mojang.Property{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func createMojangResponseWithTextures(includeSkin bool, includeCape bool) *mojang.SignedTexturesResponse {
|
2020-01-02 02:12:45 +05:30
|
|
|
timeZone, _ := time.LoadLocation("Europe/Minsk")
|
|
|
|
textures := &mojang.TexturesProp{
|
|
|
|
Timestamp: time.Date(2019, 4, 27, 23, 56, 12, 0, timeZone).Unix(),
|
|
|
|
ProfileID: "00000000000000000000000000000000",
|
|
|
|
ProfileName: "mock_username",
|
|
|
|
Textures: &mojang.TexturesResponse{},
|
|
|
|
}
|
|
|
|
|
|
|
|
if includeSkin {
|
|
|
|
textures.Textures.Skin = &mojang.SkinTexturesResponse{
|
|
|
|
Url: "http://mojang/skin.png",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if includeCape {
|
|
|
|
textures.Textures.Cape = &mojang.CapeTexturesResponse{
|
|
|
|
Url: "http://mojang/cape.png",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:40 +05:30
|
|
|
response := createEmptyMojangResponse()
|
|
|
|
response.Props = append(response.Props, &mojang.Property{
|
|
|
|
Name: "textures",
|
|
|
|
Value: mojang.EncodeTextures(textures),
|
|
|
|
})
|
2020-01-02 02:12:45 +05:30
|
|
|
|
|
|
|
return response
|
|
|
|
}
|