Skip to content

Commit

Permalink
#1: Tests for http layer are restored
Browse files Browse the repository at this point in the history
  • Loading branch information
erickskrauch committed Apr 27, 2019
1 parent f7cdab2 commit 2c7a162
Show file tree
Hide file tree
Showing 9 changed files with 1,028 additions and 785 deletions.
816 changes: 412 additions & 404 deletions http/api_test.go

Large diffs are not rendered by default.

239 changes: 132 additions & 107 deletions http/cape_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"image"
"image/png"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"

Expand All @@ -15,123 +16,147 @@ import (
"github.com/elyby/chrly/model"
)

func TestConfig_Cape(t *testing.T) {
assert := testify.New(t)

ctrl := gomock.NewController(t)
defer ctrl.Finish()

config, mocks := setupMocks(ctrl)

cape := createCape()

mocks.Capes.EXPECT().FindByUsername("mocked_username").Return(&model.Cape{
File: bytes.NewReader(cape),
}, nil)
mocks.Log.EXPECT().IncCounter("capes.request", int64(1))

req := httptest.NewRequest("GET", "http://skinsystem.ely.by/cloaks/mocked_username", nil)
w := httptest.NewRecorder()

config.CreateHandler().ServeHTTP(w, req)

resp := w.Result()
assert.Equal(200, resp.StatusCode)
responseData, _ := ioutil.ReadAll(resp.Body)
assert.Equal(cape, responseData)
assert.Equal("image/png", resp.Header.Get("Content-Type"))
}

func TestConfig_Cape2(t *testing.T) {
assert := testify.New(t)

ctrl := gomock.NewController(t)
defer ctrl.Finish()

config, mocks := setupMocks(ctrl)

mocks.Capes.EXPECT().FindByUsername("notch").Return(nil, &db.CapeNotFoundError{"notch"})
mocks.Log.EXPECT().IncCounter("capes.request", int64(1))

req := httptest.NewRequest("GET", "http://skinsystem.ely.by/cloaks/notch", nil)
w := httptest.NewRecorder()

config.CreateHandler().ServeHTTP(w, req)

resp := w.Result()
assert.Equal(301, resp.StatusCode)
assert.Equal("http://skins.minecraft.net/MinecraftCloaks/notch.png", resp.Header.Get("Location"))
}

func TestConfig_CapeGET(t *testing.T) {
assert := testify.New(t)

ctrl := gomock.NewController(t)
defer ctrl.Finish()

config, mocks := setupMocks(ctrl)

cape := createCape()

mocks.Capes.EXPECT().FindByUsername("mocked_username").Return(&model.Cape{
File: bytes.NewReader(cape),
}, nil)
mocks.Log.EXPECT().IncCounter("capes.request", int64(1)).Times(0)
mocks.Log.EXPECT().IncCounter("capes.get_request", int64(1))

req := httptest.NewRequest("GET", "http://skinsystem.ely.by/cloaks?name=mocked_username", nil)
w := httptest.NewRecorder()

config.CreateHandler().ServeHTTP(w, req)

resp := w.Result()
assert.Equal(200, resp.StatusCode)
responseData, _ := ioutil.ReadAll(resp.Body)
assert.Equal(cape, responseData)
assert.Equal("image/png", resp.Header.Get("Content-Type"))
type capesTestCase struct {
Name string
RequestUrl string
ExpectedLogKey string
ExistsInLocalStorage bool
ExistsInMojang bool
HasCapeInMojangResp bool
AssertResponse func(assert *testify.Assertions, resp *http.Response)
}

func TestConfig_CapeGET2(t *testing.T) {
assert := testify.New(t)

ctrl := gomock.NewController(t)
defer ctrl.Finish()

config, mocks := setupMocks(ctrl)

mocks.Capes.EXPECT().FindByUsername("notch").Return(nil, &db.CapeNotFoundError{"notch"})
mocks.Log.EXPECT().IncCounter("capes.request", int64(1)).Times(0)
mocks.Log.EXPECT().IncCounter("capes.get_request", int64(1))

req := httptest.NewRequest("GET", "http://skinsystem.ely.by/cloaks?name=notch", nil)
w := httptest.NewRecorder()

config.CreateHandler().ServeHTTP(w, req)

resp := w.Result()
assert.Equal(301, resp.StatusCode)
assert.Equal("http://skins.minecraft.net/MinecraftCloaks/notch.png", resp.Header.Get("Location"))
var capesTestCases = []*capesTestCase{
{
Name: "Obtain cape for known username",
ExistsInLocalStorage: true,
AssertResponse: func(assert *testify.Assertions, resp *http.Response) {
assert.Equal(200, resp.StatusCode)
responseData, _ := ioutil.ReadAll(resp.Body)
assert.Equal(createCape(), responseData)
assert.Equal("image/png", resp.Header.Get("Content-Type"))
},
},
{
Name: "Obtain cape for unknown username that exists in Mojang and has a cape",
ExistsInLocalStorage: false,
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",
ExistsInLocalStorage: 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",
ExistsInLocalStorage: false,
ExistsInMojang: false,
AssertResponse: func(assert *testify.Assertions, resp *http.Response) {
assert.Equal(404, resp.StatusCode)
},
},
}

func TestConfig_CapeGET3(t *testing.T) {
assert := testify.New(t)

req := httptest.NewRequest("GET", "http://skinsystem.ely.by/cloaks/?name=notch", nil)
w := httptest.NewRecorder()

(&Config{}).CreateHandler().ServeHTTP(w, req)

resp := w.Result()
assert.Equal(301, resp.StatusCode)
assert.Equal("http://skinsystem.ely.by/cloaks?name=notch", resp.Header.Get("Location"))
func TestConfig_Cape(t *testing.T) {
performTest := func(t *testing.T, testCase *capesTestCase) {
assert := testify.New(t)

ctrl := gomock.NewController(t)
defer ctrl.Finish()

config, mocks := setupMocks(ctrl)

mocks.Log.EXPECT().IncCounter(testCase.ExpectedLogKey, int64(1))
if testCase.ExistsInLocalStorage {
mocks.Capes.EXPECT().FindByUsername("mock_username").Return(&model.Cape{
File: bytes.NewReader(createCape()),
}, nil)
} else {
mocks.Capes.EXPECT().FindByUsername("mock_username").Return(nil, &db.CapeNotFoundError{Who: "mock_username"})
}

if testCase.ExistsInMojang {
textures := createTexturesResponse(false, testCase.HasCapeInMojangResp)
mocks.Queue.On("GetTexturesForUsername", "mock_username").Return(textures)
} else {
mocks.Queue.On("GetTexturesForUsername", "mock_username").Return(nil)
}

req := httptest.NewRequest("GET", testCase.RequestUrl, nil)
w := httptest.NewRecorder()

config.CreateHandler().ServeHTTP(w, req)

resp := w.Result()
testCase.AssertResponse(assert, resp)
}

t.Run("Normal API", func(t *testing.T) {
for _, testCase := range capesTestCases {
testCase.RequestUrl = "http://chrly/cloaks/mock_username"
testCase.ExpectedLogKey = "capes.request"
t.Run(testCase.Name, func(t *testing.T) {
performTest(t, testCase)
})
}
})

t.Run("GET fallback API", func(t *testing.T) {
for _, testCase := range capesTestCases {
testCase.RequestUrl = "http://chrly/cloaks?name=mock_username"
testCase.ExpectedLogKey = "capes.get_request"
t.Run(testCase.Name, func(t *testing.T) {
performTest(t, testCase)
})
}

t.Run("Should trim trailing slash", func(t *testing.T) {
assert := testify.New(t)

req := httptest.NewRequest("GET", "http://chrly/cloaks/?name=notch", nil)
w := httptest.NewRecorder()

(&Config{}).CreateHandler().ServeHTTP(w, req)

resp := w.Result()
assert.Equal(301, resp.StatusCode)
assert.Equal("http://chrly/cloaks?name=notch", resp.Header.Get("Location"))
})

t.Run("Return error when name is not provided", func(t *testing.T) {
assert := testify.New(t)

ctrl := gomock.NewController(t)
defer ctrl.Finish()

config, mocks := setupMocks(ctrl)
mocks.Log.EXPECT().IncCounter("capes.get_request", int64(1))

req := httptest.NewRequest("GET", "http://chrly/cloaks", nil)
w := httptest.NewRecorder()

config.CreateHandler().ServeHTTP(w, req)

resp := w.Result()
assert.Equal(400, resp.StatusCode)
})
})
}

// Cape md5: 424ff79dce9940af89c28ad80de8aaad
func createCape() []byte {
img := image.NewAlpha(image.Rect(0, 0, 64, 32))
writer := &bytes.Buffer{}
png.Encode(writer, img)

_ = png.Encode(writer, img)
pngBytes, _ := ioutil.ReadAll(writer)

return pngBytes
Expand Down
51 changes: 47 additions & 4 deletions http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package http

import (
"testing"
"time"

"github.com/elyby/chrly/api/mojang"

"github.com/elyby/chrly/tests"
"github.com/golang/mock/gomock"
testify "github.com/stretchr/testify/assert"

Expand All @@ -19,6 +23,7 @@ func TestParseUsername(t *testing.T) {
type mocks struct {
Skins *mock_interfaces.MockSkinsRepository
Capes *mock_interfaces.MockCapesRepository
Queue *tests.MojangTexturesQueueMock
Auth *mock_interfaces.MockAuthChecker
Log *mock_wd.MockWatchdog
}
Expand All @@ -31,16 +36,54 @@ func setupMocks(ctrl *gomock.Controller) (
capesRepo := mock_interfaces.NewMockCapesRepository(ctrl)
authChecker := mock_interfaces.NewMockAuthChecker(ctrl)
wd := mock_wd.NewMockWatchdog(ctrl)
texturesQueue := &tests.MojangTexturesQueueMock{}

return &Config{
SkinsRepo: skinsRepo,
CapesRepo: capesRepo,
Auth: authChecker,
Logger: wd,
SkinsRepo: skinsRepo,
CapesRepo: capesRepo,
Auth: authChecker,
MojangTexturesQueue: texturesQueue,
Logger: wd,
}, &mocks{
Skins: skinsRepo,
Capes: capesRepo,
Auth: authChecker,
Queue: texturesQueue,
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",
ProfileName: "mock_user",
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",
}
}

response := &mojang.SignedTexturesResponse{
Id: "00000000000000000000000000000000",
Name: "mock_user",
Props: []*mojang.Property{
{
Name: "textures",
Value: mojang.EncodeTextures(textures),
},
},
}

return response
}
9 changes: 5 additions & 4 deletions http/signed_textures.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ func (cfg *Config) SignedTextures(response http.ResponseWriter, request *http.Re
Signature: rec.MojangSignature,
Value: rec.MojangTextures,
},
{
Name: "chrly",
Value: "how do you tame a horse in Minecraft?",
},
},
}
} else if request.URL.Query().Get("proxy") != "" {
Expand All @@ -42,6 +38,11 @@ func (cfg *Config) SignedTextures(response http.ResponseWriter, request *http.Re
return
}

responseData.Props = append(responseData.Props, &mojang.Property{
Name: "chrly",
Value: "how do you tame a horse in Minecraft?",
})

responseJson, _ := json.Marshal(responseData)
response.Header().Set("Content-Type", "application/json")
response.Write(responseJson)
Expand Down
Loading

0 comments on commit 2c7a162

Please sign in to comment.