Completely rework mojang textures queue implementation, split it across separate data providers

This commit is contained in:
ErickSkrauch
2019-11-21 01:33:13 +03:00
parent 6fd88e077e
commit 0644dfe021
34 changed files with 1405 additions and 1180 deletions

View File

@@ -20,8 +20,8 @@ func (cfg *Config) Cape(response http.ResponseWriter, request *http.Request) {
return
}
mojangTextures := <-cfg.MojangTexturesQueue.GetTexturesForUsername(username)
if mojangTextures == nil {
mojangTextures, err := cfg.MojangTexturesProvider.GetForUsername(username)
if err != nil || mojangTextures == nil {
response.WriteHeader(http.StatusNotFound)
return
}

View File

@@ -28,7 +28,7 @@ type capesTestCase struct {
var capesTestCases = []*capesTestCase{
{
Name: "Obtain cape for known username",
Name: "Obtain cape for known username",
ExistsInLocalStorage: true,
AssertResponse: func(assert *testify.Assertions, resp *http.Response) {
assert.Equal(200, resp.StatusCode)
@@ -38,28 +38,28 @@ var capesTestCases = []*capesTestCase{
},
},
{
Name: "Obtain cape for unknown username that exists in Mojang and has a cape",
Name: "Obtain cape for unknown username that exists in Mojang and has a cape",
ExistsInLocalStorage: false,
ExistsInMojang: true,
HasCapeInMojangResp: true,
ExistsInMojang: true,
HasCapeInMojangResp: true,
AssertResponse: func(assert *testify.Assertions, resp *http.Response) {
assert.Equal(301, resp.StatusCode)
assert.Equal("http://mojang/cape.png", resp.Header.Get("Location"))
},
},
{
Name: "Obtain cape for unknown username that exists in Mojang, but don't has a cape",
Name: "Obtain cape for unknown username that exists in Mojang, but don't has a cape",
ExistsInLocalStorage: false,
ExistsInMojang: true,
HasCapeInMojangResp: false,
ExistsInMojang: true,
HasCapeInMojangResp: false,
AssertResponse: func(assert *testify.Assertions, resp *http.Response) {
assert.Equal(404, resp.StatusCode)
},
},
{
Name: "Obtain cape for unknown username that doesn't exists in Mojang",
Name: "Obtain cape for unknown username that doesn't exists in Mojang",
ExistsInLocalStorage: false,
ExistsInMojang: false,
ExistsInMojang: false,
AssertResponse: func(assert *testify.Assertions, resp *http.Response) {
assert.Equal(404, resp.StatusCode)
},
@@ -86,9 +86,9 @@ func TestConfig_Cape(t *testing.T) {
if testCase.ExistsInMojang {
textures := createTexturesResponse(false, testCase.HasCapeInMojangResp)
mocks.Queue.On("GetTexturesForUsername", "mock_username").Return(textures)
mocks.MojangProvider.On("GetForUsername", "mock_username").Return(textures, nil)
} else {
mocks.Queue.On("GetTexturesForUsername", "mock_username").Return(nil)
mocks.MojangProvider.On("GetForUsername", "mock_username").Return(nil, nil)
}
req := httptest.NewRequest("GET", testCase.RequestUrl, nil)

View File

@@ -19,11 +19,11 @@ import (
type Config struct {
ListenSpec string
SkinsRepo interfaces.SkinsRepository
CapesRepo interfaces.CapesRepository
MojangTexturesQueue interfaces.MojangTexturesQueue
Logger wd.Watchdog
Auth interfaces.AuthChecker
SkinsRepo interfaces.SkinsRepository
CapesRepo interfaces.CapesRepository
MojangTexturesProvider interfaces.MojangTexturesProvider
Logger wd.Watchdog
Auth interfaces.AuthChecker
}
func (cfg *Config) Run() error {

View File

@@ -4,9 +4,10 @@ import (
"testing"
"time"
"github.com/stretchr/testify/mock"
"github.com/elyby/chrly/api/mojang"
"github.com/elyby/chrly/tests"
"github.com/golang/mock/gomock"
testify "github.com/stretchr/testify/assert"
@@ -20,46 +21,57 @@ func TestParseUsername(t *testing.T) {
assert.Equal("test", parseUsername("test"), "Function should return string itself, if it not contains .png at end")
}
type mocks struct {
Skins *mock_interfaces.MockSkinsRepository
Capes *mock_interfaces.MockCapesRepository
Queue *tests.MojangTexturesQueueMock
Auth *mock_interfaces.MockAuthChecker
Log *mock_wd.MockWatchdog
type mojangTexturesProviderMock struct {
mock.Mock
}
func setupMocks(ctrl *gomock.Controller) (
*Config,
*mocks,
) {
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 mocks struct {
Skins *mock_interfaces.MockSkinsRepository
Capes *mock_interfaces.MockCapesRepository
MojangProvider *mojangTexturesProviderMock
Auth *mock_interfaces.MockAuthChecker
Log *mock_wd.MockWatchdog
}
func setupMocks(ctrl *gomock.Controller) (*Config, *mocks) {
skinsRepo := mock_interfaces.NewMockSkinsRepository(ctrl)
capesRepo := mock_interfaces.NewMockCapesRepository(ctrl)
authChecker := mock_interfaces.NewMockAuthChecker(ctrl)
wd := mock_wd.NewMockWatchdog(ctrl)
texturesQueue := &tests.MojangTexturesQueueMock{}
texturesProvider := &mojangTexturesProviderMock{}
return &Config{
SkinsRepo: skinsRepo,
CapesRepo: capesRepo,
Auth: authChecker,
MojangTexturesQueue: texturesQueue,
Logger: wd,
}, &mocks{
Skins: skinsRepo,
Capes: capesRepo,
Auth: authChecker,
Queue: texturesQueue,
Log: wd,
}
SkinsRepo: skinsRepo,
CapesRepo: capesRepo,
Auth: authChecker,
MojangTexturesProvider: texturesProvider,
Logger: wd,
}, &mocks{
Skins: skinsRepo,
Capes: capesRepo,
Auth: authChecker,
MojangProvider: texturesProvider,
Log: wd,
}
}
func createTexturesResponse(includeSkin bool, includeCape bool) *mojang.SignedTexturesResponse {
timeZone, _ := time.LoadLocation("Europe/Minsk")
textures := &mojang.TexturesProp{
Timestamp: time.Date(2019, 4, 27, 23, 56, 12, 0, timeZone).Unix(),
ProfileID: "00000000000000000000000000000000",
Timestamp: time.Date(2019, 4, 27, 23, 56, 12, 0, timeZone).Unix(),
ProfileID: "00000000000000000000000000000000",
ProfileName: "mock_user",
Textures: &mojang.TexturesResponse{},
Textures: &mojang.TexturesResponse{},
}
if includeSkin {
@@ -75,11 +87,11 @@ func createTexturesResponse(includeSkin bool, includeCape bool) *mojang.SignedTe
}
response := &mojang.SignedTexturesResponse{
Id: "00000000000000000000000000000000",
Id: "00000000000000000000000000000000",
Name: "mock_user",
Props: []*mojang.Property{
{
Name: "textures",
Name: "textures",
Value: mojang.EncodeTextures(textures),
},
},

View File

@@ -30,7 +30,10 @@ func (cfg *Config) SignedTextures(response http.ResponseWriter, request *http.Re
},
}
} else if request.URL.Query().Get("proxy") != "" {
responseData = <-cfg.MojangTexturesQueue.GetTexturesForUsername(username)
mojangTextures, err := cfg.MojangTexturesProvider.GetForUsername(username)
if err == nil && mojangTextures != nil {
responseData = mojangTextures
}
}
if responseData == nil {

View File

@@ -112,7 +112,7 @@ func TestConfig_SignedTextures(t *testing.T) {
mocks.Log.EXPECT().IncCounter("signed_textures.request", int64(1))
mocks.Skins.EXPECT().FindByUsername("mock_user").Return(skinModel, nil)
mocks.Queue.On("GetTexturesForUsername", "mock_user").Once().Return(createTexturesResponse(true, false))
mocks.MojangProvider.On("GetForUsername", "mock_user").Once().Return(createTexturesResponse(true, false), nil)
req := httptest.NewRequest("GET", "http://chrly/textures/signed/mock_user?proxy=true", nil)
w := httptest.NewRecorder()

View File

@@ -18,8 +18,8 @@ func (cfg *Config) Skin(response http.ResponseWriter, request *http.Request) {
return
}
mojangTextures := <-cfg.MojangTexturesQueue.GetTexturesForUsername(username)
if mojangTextures == nil {
mojangTextures, err := cfg.MojangTexturesProvider.GetForUsername(username)
if err != nil || mojangTextures == nil {
response.WriteHeader(http.StatusNotFound)
return
}

View File

@@ -78,9 +78,9 @@ func TestConfig_Skin(t *testing.T) {
if testCase.ExistsInMojang {
textures := createTexturesResponse(testCase.HasSkinInMojangResp, true)
mocks.Queue.On("GetTexturesForUsername", "mock_username").Return(textures)
mocks.MojangProvider.On("GetForUsername", "mock_username").Return(textures, nil)
} else {
mocks.Queue.On("GetTexturesForUsername", "mock_username").Return(nil)
mocks.MojangProvider.On("GetForUsername", "mock_username").Return(nil, nil)
}
req := httptest.NewRequest("GET", testCase.RequestUrl, nil)

View File

@@ -39,8 +39,8 @@ func (cfg *Config) Textures(response http.ResponseWriter, request *http.Request)
}
}
} else {
mojangTextures := <-cfg.MojangTexturesQueue.GetTexturesForUsername(username)
if mojangTextures == nil {
mojangTextures, err := cfg.MojangTexturesProvider.GetForUsername(username)
if err != nil || mojangTextures == nil {
response.WriteHeader(http.StatusNoContent)
return
}

View File

@@ -148,7 +148,7 @@ func TestConfig_Textures(t *testing.T) {
mocks.Skins.EXPECT().FindByUsername("mock_username").Return(nil, &db.SkinNotFoundError{})
mocks.Capes.EXPECT().FindByUsername("mock_username").Return(nil, &db.CapeNotFoundError{})
mocks.Queue.On("GetTexturesForUsername", "mock_username").Once().Return(createTexturesResponse(true, true))
mocks.MojangProvider.On("GetForUsername", "mock_username").Once().Return(createTexturesResponse(true, true), nil)
req := httptest.NewRequest("GET", "http://chrly/textures/mock_username", nil)
w := httptest.NewRecorder()
@@ -181,7 +181,7 @@ func TestConfig_Textures(t *testing.T) {
mocks.Skins.EXPECT().FindByUsername("mock_username").Return(nil, &db.SkinNotFoundError{})
mocks.Capes.EXPECT().FindByUsername("mock_username").Return(nil, &db.CapeNotFoundError{})
mocks.Queue.On("GetTexturesForUsername", "mock_username").Once().Return(nil)
mocks.MojangProvider.On("GetForUsername", "mock_username").Once().Return(nil, nil)
req := httptest.NewRequest("GET", "http://chrly/textures/mock_username", nil)
w := httptest.NewRecorder()