diff --git a/api/mojang/mojang.go b/api/mojang/mojang.go index 323cd95..db2a7f0 100644 --- a/api/mojang/mojang.go +++ b/api/mojang/mojang.go @@ -89,11 +89,13 @@ func UuidToTextures(uuid string, signed bool) (*SignedTexturesResponse, error) { } func validateResponse(response *http.Response) error { - switch response.StatusCode { - case 204: + switch { + case response.StatusCode == 204: return &EmptyResponse{} - case 429: + case response.StatusCode == 429: return &TooManyRequestsError{} + case response.StatusCode >= 500: + return &ServerError{response.StatusCode} } return nil @@ -115,3 +117,12 @@ type TooManyRequestsError struct { func (*TooManyRequestsError) Error() string { return "Too Many Requests" } + +// ServerError happens when Mojang's API returns any response with 50* status +type ServerError struct { + Status int +} + +func (e *ServerError) Error() string { + return "Server error" +} diff --git a/api/mojang/mojang_test.go b/api/mojang/mojang_test.go index 8bd809d..633e6f7 100644 --- a/api/mojang/mojang_test.go +++ b/api/mojang/mojang_test.go @@ -51,7 +51,7 @@ func TestUsernamesToUuids(t *testing.T) { } }) - t.Run("handle too many requests error", func(t *testing.T) { + t.Run("handle too many requests response", func(t *testing.T) { assert := testify.New(t) defer gock.Off() @@ -73,6 +73,27 @@ func TestUsernamesToUuids(t *testing.T) { assert.IsType(&TooManyRequestsError{}, err) assert.EqualError(err, "Too Many Requests") }) + + t.Run("handle server error", func(t *testing.T) { + assert := testify.New(t) + + defer gock.Off() + gock.New("https://api.mojang.com"). + Post("/profiles/minecraft"). + Reply(500). + BodyString("500 Internal Server Error") + + client := &http.Client{} + gock.InterceptClient(client) + + HttpClient = client + + result, err := UsernamesToUuids([]string{"Thinkofdeath", "maksimkurb"}) + assert.Nil(result) + assert.IsType(&ServerError{}, err) + assert.EqualError(err, "Server error") + assert.Equal(500, err.(*ServerError).Status) + }) } func TestUuidToTextures(t *testing.T) { @@ -188,4 +209,25 @@ func TestUuidToTextures(t *testing.T) { assert.IsType(&TooManyRequestsError{}, err) assert.EqualError(err, "Too Many Requests") }) + + t.Run("handle server error", func(t *testing.T) { + assert := testify.New(t) + + defer gock.Off() + gock.New("https://sessionserver.mojang.com"). + Get("/session/minecraft/profile/4566e69fc90748ee8d71d7ba5aa00d20"). + Reply(500). + BodyString("500 Internal Server Error") + + client := &http.Client{} + gock.InterceptClient(client) + + HttpClient = client + + result, err := UuidToTextures("4566e69fc90748ee8d71d7ba5aa00d20", false) + assert.Nil(result) + assert.IsType(&ServerError{}, err) + assert.EqualError(err, "Server error") + assert.Equal(500, err.(*ServerError).Status) + }) } diff --git a/api/mojang/queue/queue.go b/api/mojang/queue/queue.go index 1511718..566b41f 100644 --- a/api/mojang/queue/queue.go +++ b/api/mojang/queue/queue.go @@ -101,7 +101,7 @@ func (ctx *JobsQueue) queueRound() { profiles, err := usernamesToUuids(usernames) switch err.(type) { - case *mojang.TooManyRequestsError: + case *mojang.TooManyRequestsError, *mojang.ServerError: for _, job := range jobs { job.RespondTo <- nil } @@ -147,8 +147,7 @@ func (ctx *JobsQueue) getTextures(uuid string) *mojang.SignedTexturesResponse { shouldCache := true result, err := uuidToTextures(uuid, true) switch err.(type) { - case *mojang.EmptyResponse: - case *mojang.TooManyRequestsError: + case *mojang.EmptyResponse, *mojang.TooManyRequestsError, *mojang.ServerError: shouldCache = false case error: panic(err) diff --git a/api/mojang/queue/queue_test.go b/api/mojang/queue/queue_test.go index 627c3c5..be7af0e 100644 --- a/api/mojang/queue/queue_test.go +++ b/api/mojang/queue/queue_test.go @@ -305,6 +305,18 @@ func (suite *QueueTestSuite) TestHandleTooManyRequestsResponseWhenExchangingUser suite.Assert().Nil(<-resultChan) } +func (suite *QueueTestSuite) TestHandleServerErrorWhenExchangingUsernamesToUuids() { + suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{}) + // Storage.StoreUuid, Storage.GetTextures and Storage.StoreTextures shouldn't be called + suite.MojangApi.On("UsernameToUuids", []string{"maksimkurb"}).Once().Return(nil, &mojang.ServerError{Status: 500}) + + resultChan := suite.Queue.GetTexturesForUsername("maksimkurb") + + suite.Iterate() + + suite.Assert().Nil(<-resultChan) +} + func (suite *QueueTestSuite) TestHandleEmptyResponseWhenRequestingUsersTextures() { suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{}) suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once() @@ -345,6 +357,26 @@ func (suite *QueueTestSuite) TestHandleTooManyRequestsResponseWhenRequestingUser suite.Assert().Nil(<-resultChan) } +func (suite *QueueTestSuite) TestHandleServerErrorWhenRequestingUsersTextures() { + suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{}) + suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once() + suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{}) + // Storage.StoreTextures shouldn't be called + suite.MojangApi.On("UsernameToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{ + {Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}, + }, nil) + suite.MojangApi.On("UuidToTextures", "0d252b7218b648bfb86c2ae476954d32", true).Once().Return( + nil, + &mojang.ServerError{Status: 500}, + ) + + resultChan := suite.Queue.GetTexturesForUsername("maksimkurb") + + suite.Iterate() + + suite.Assert().Nil(<-resultChan) +} + func (suite *QueueTestSuite) TestReceiveTexturesForNotAllowedMojangUsername() { resultChan := suite.Queue.GetTexturesForUsername("Not allowed") suite.Assert().Nil(<-resultChan)