mirror of
https://github.com/elyby/chrly.git
synced 2024-08-25 14:20:00 +05:30
Integrate event dispatcher into mojangtextures package
This commit is contained in:
parent
b2ee10f72f
commit
2abe2db469
@ -1,6 +1,7 @@
|
|||||||
package bootstrap
|
package bootstrap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/elyby/chrly/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
@ -69,7 +70,7 @@ func init() {
|
|||||||
viper.SetDefault("queue.batch_size", 10)
|
viper.SetDefault("queue.batch_size", 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateMojangUUIDsProvider(logger wd.Watchdog) (mojangtextures.UUIDsProvider, error) {
|
func CreateMojangUUIDsProvider(emitter http.Emitter) (mojangtextures.UUIDsProvider, error) {
|
||||||
var uuidsProvider mojangtextures.UUIDsProvider
|
var uuidsProvider mojangtextures.UUIDsProvider
|
||||||
preferredUuidsProvider := viper.GetString("mojang_textures.uuids_provider.driver")
|
preferredUuidsProvider := viper.GetString("mojang_textures.uuids_provider.driver")
|
||||||
if preferredUuidsProvider == "remote" {
|
if preferredUuidsProvider == "remote" {
|
||||||
@ -79,14 +80,14 @@ func CreateMojangUUIDsProvider(logger wd.Watchdog) (mojangtextures.UUIDsProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
uuidsProvider = &mojangtextures.RemoteApiUuidsProvider{
|
uuidsProvider = &mojangtextures.RemoteApiUuidsProvider{
|
||||||
Url: *remoteUrl,
|
Emitter: emitter,
|
||||||
Logger: logger,
|
Url: *remoteUrl,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uuidsProvider = &mojangtextures.BatchUuidsProvider{
|
uuidsProvider = &mojangtextures.BatchUuidsProvider{
|
||||||
|
Emitter: emitter,
|
||||||
IterationDelay: viper.GetDuration("queue.loop_delay"),
|
IterationDelay: viper.GetDuration("queue.loop_delay"),
|
||||||
IterationSize: viper.GetInt("queue.batch_size"),
|
IterationSize: viper.GetInt("queue.batch_size"),
|
||||||
Logger: logger,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ var serveCmd = &cobra.Command{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uuidsProvider, err := bootstrap.CreateMojangUUIDsProvider(logger)
|
uuidsProvider, err := bootstrap.CreateMojangUUIDsProvider(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Emergency("Unable to parse remote url :err", wd.ErrParam(err))
|
logger.Emergency("Unable to parse remote url :err", wd.ErrParam(err))
|
||||||
return
|
return
|
||||||
@ -62,10 +62,10 @@ var serveCmd = &cobra.Command{
|
|||||||
texturesStorage := mojangtextures.NewInMemoryTexturesStorage()
|
texturesStorage := mojangtextures.NewInMemoryTexturesStorage()
|
||||||
texturesStorage.Start()
|
texturesStorage.Start()
|
||||||
mojangTexturesProvider := &mojangtextures.Provider{
|
mojangTexturesProvider := &mojangtextures.Provider{
|
||||||
Logger: logger,
|
// TODO: configure emitter
|
||||||
UUIDsProvider: uuidsProvider,
|
UUIDsProvider: uuidsProvider,
|
||||||
TexturesProvider: &mojangtextures.MojangApiTexturesProvider{
|
TexturesProvider: &mojangtextures.MojangApiTexturesProvider{
|
||||||
Logger: logger,
|
// TODO: configure emitter
|
||||||
},
|
},
|
||||||
Storage: &mojangtextures.SeparatedStorage{
|
Storage: &mojangtextures.SeparatedStorage{
|
||||||
UuidsStorage: mojangUuidsRepository,
|
UuidsStorage: mojangUuidsRepository,
|
||||||
|
@ -31,7 +31,7 @@ var workerCmd = &cobra.Command{
|
|||||||
address := fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port"))
|
address := fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port"))
|
||||||
handler := (&http.UUIDsWorker{
|
handler := (&http.UUIDsWorker{
|
||||||
UUIDsProvider: uuidsProvider,
|
UUIDsProvider: uuidsProvider,
|
||||||
// TODO: create an emitter, restore logger
|
// TODO: configure emitter
|
||||||
}).CreateHandler()
|
}).CreateHandler()
|
||||||
|
|
||||||
finishChan := make(chan bool)
|
finishChan := make(chan bool)
|
||||||
|
@ -226,7 +226,7 @@ func (ctx *Skinsystem) Textures(response http.ResponseWriter, request *http.Requ
|
|||||||
|
|
||||||
texturesProp := mojangTextures.DecodeTextures()
|
texturesProp := mojangTextures.DecodeTextures()
|
||||||
if texturesProp == nil {
|
if texturesProp == nil {
|
||||||
ctx.Emitter.Emit("skinsystem.error", errors.New("unable to find textures property"))
|
ctx.Emit("skinsystem.error", errors.New("unable to find textures property"))
|
||||||
apiServerError(response)
|
apiServerError(response)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -291,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.Emitter.Emit("skinsystem:error", fmt.Errorf("error on requesting a skin from the repository: %w", err))
|
ctx.Emit("skinsystem:error", fmt.Errorf("error on requesting a skin from the repository: %w", err))
|
||||||
apiServerError(resp)
|
apiServerError(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ 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.Emitter.Emit("skinsystem:error", fmt.Errorf("unable to save record to the repository: %w", err))
|
ctx.Emit("skinsystem:error", fmt.Errorf("unable to save record to the repository: %w", err))
|
||||||
apiServerError(resp)
|
apiServerError(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -357,7 +357,7 @@ func (ctx *Skinsystem) deleteSkin(skin *model.Skin, err error, resp http.Respons
|
|||||||
if _, ok := err.(*SkinNotFoundError); ok {
|
if _, ok := err.(*SkinNotFoundError); ok {
|
||||||
apiNotFound(resp, "Cannot find record for the requested identifier")
|
apiNotFound(resp, "Cannot find record for the requested identifier")
|
||||||
} else {
|
} else {
|
||||||
ctx.Emitter.Emit("skinsystem:error", fmt.Errorf("unable to find skin info from the repository: %w", err))
|
ctx.Emit("skinsystem:error", fmt.Errorf("unable to find skin info from the repository: %w", err))
|
||||||
apiServerError(resp)
|
apiServerError(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ func (ctx *Skinsystem) deleteSkin(skin *model.Skin, err error, resp http.Respons
|
|||||||
|
|
||||||
err = ctx.SkinsRepo.RemoveByUserId(skin.UserId)
|
err = ctx.SkinsRepo.RemoveByUserId(skin.UserId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Emitter.Emit("skinsystem:error", fmt.Errorf("cannot delete skin by error: %w", err))
|
ctx.Emit("skinsystem:error", fmt.Errorf("cannot delete skin by error: %w", err))
|
||||||
apiServerError(resp)
|
apiServerError(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ 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?
|
ctx.Emit("uuids_provider:error", err) // TODO: do I need emitter here?
|
||||||
if _, ok := err.(*mojang.TooManyRequestsError); ok {
|
if _, ok := err.(*mojang.TooManyRequestsError); ok {
|
||||||
response.WriteHeader(http.StatusTooManyRequests)
|
response.WriteHeader(http.StatusTooManyRequests)
|
||||||
return
|
return
|
||||||
|
@ -5,8 +5,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mono83/slf/wd"
|
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,9 +66,10 @@ var forever = func() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BatchUuidsProvider struct {
|
type BatchUuidsProvider struct {
|
||||||
|
Emitter
|
||||||
|
|
||||||
IterationDelay time.Duration
|
IterationDelay time.Duration
|
||||||
IterationSize int
|
IterationSize int
|
||||||
Logger wd.Watchdog
|
|
||||||
|
|
||||||
onFirstCall sync.Once
|
onFirstCall sync.Once
|
||||||
queue jobsQueue
|
queue jobsQueue
|
||||||
@ -84,7 +83,7 @@ func (ctx *BatchUuidsProvider) GetUuid(username string) (*mojang.ProfileInfo, er
|
|||||||
|
|
||||||
resultChan := make(chan *jobResult)
|
resultChan := make(chan *jobResult)
|
||||||
ctx.queue.Enqueue(&jobItem{username, resultChan})
|
ctx.queue.Enqueue(&jobItem{username, resultChan})
|
||||||
ctx.Logger.IncCounter("mojang_textures.usernames.queued", 1)
|
ctx.Emit("mojang_textures:batch_uuids_provider:queued", username)
|
||||||
|
|
||||||
result := <-resultChan
|
result := <-resultChan
|
||||||
|
|
||||||
@ -95,10 +94,9 @@ func (ctx *BatchUuidsProvider) startQueue() {
|
|||||||
go func() {
|
go func() {
|
||||||
time.Sleep(ctx.IterationDelay)
|
time.Sleep(ctx.IterationDelay)
|
||||||
for forever() {
|
for forever() {
|
||||||
start := time.Now()
|
ctx.Emit("mojang_textures:batch_uuids_provider:before_round")
|
||||||
ctx.queueRound()
|
ctx.queueRound()
|
||||||
elapsed := time.Since(start)
|
ctx.Emit("mojang_textures:batch_uuids_provider:after_round")
|
||||||
ctx.Logger.RecordTimer("mojang_textures.usernames.round_time", elapsed)
|
|
||||||
time.Sleep(ctx.IterationDelay)
|
time.Sleep(ctx.IterationDelay)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -107,17 +105,17 @@ func (ctx *BatchUuidsProvider) startQueue() {
|
|||||||
func (ctx *BatchUuidsProvider) queueRound() {
|
func (ctx *BatchUuidsProvider) queueRound() {
|
||||||
queueSize := ctx.queue.Size()
|
queueSize := ctx.queue.Size()
|
||||||
jobs := ctx.queue.Dequeue(ctx.IterationSize)
|
jobs := ctx.queue.Dequeue(ctx.IterationSize)
|
||||||
ctx.Logger.UpdateGauge("mojang_textures.usernames.queue_size", int64(queueSize-len(jobs)))
|
|
||||||
ctx.Logger.UpdateGauge("mojang_textures.usernames.iteration_size", int64(len(jobs)))
|
|
||||||
if len(jobs) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var usernames []string
|
var usernames []string
|
||||||
for _, job := range jobs {
|
for _, job := range jobs {
|
||||||
usernames = append(usernames, job.username)
|
usernames = append(usernames, job.username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.Emit("mojang_textures:batch_uuids_provider:round", usernames, queueSize - len(jobs))
|
||||||
|
if len(usernames) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
profiles, err := usernamesToUuids(usernames)
|
profiles, err := usernamesToUuids(usernames)
|
||||||
for _, job := range jobs {
|
for _, job := range jobs {
|
||||||
go func(job *jobItem) {
|
go func(job *jobItem) {
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
mocks "github.com/elyby/chrly/tests"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestJobsQueue(t *testing.T) {
|
func TestJobsQueue(t *testing.T) {
|
||||||
@ -85,7 +84,7 @@ type batchUuidsProviderTestSuite struct {
|
|||||||
Provider *BatchUuidsProvider
|
Provider *BatchUuidsProvider
|
||||||
GetUuidAsync func(username string) chan *batchUuidsProviderGetUuidResult
|
GetUuidAsync func(username string) chan *batchUuidsProviderGetUuidResult
|
||||||
|
|
||||||
Logger *mocks.WdMock
|
Emitter *mockEmitter
|
||||||
MojangApi *mojangUsernamesToUuidsRequestMock
|
MojangApi *mojangUsernamesToUuidsRequestMock
|
||||||
|
|
||||||
Iterate func()
|
Iterate func()
|
||||||
@ -94,10 +93,10 @@ type batchUuidsProviderTestSuite struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *batchUuidsProviderTestSuite) SetupTest() {
|
func (suite *batchUuidsProviderTestSuite) SetupTest() {
|
||||||
suite.Logger = &mocks.WdMock{}
|
suite.Emitter = &mockEmitter{}
|
||||||
|
|
||||||
suite.Provider = &BatchUuidsProvider{
|
suite.Provider = &BatchUuidsProvider{
|
||||||
Logger: suite.Logger,
|
Emitter: suite.Emitter,
|
||||||
IterationDelay: 0,
|
IterationDelay: 0,
|
||||||
IterationSize: 10,
|
IterationSize: 10,
|
||||||
}
|
}
|
||||||
@ -120,7 +119,10 @@ func (suite *batchUuidsProviderTestSuite) SetupTest() {
|
|||||||
// This dirty hack ensures, that the username will be queued before we return control to the caller.
|
// This dirty hack ensures, that the username will be queued before we return control to the caller.
|
||||||
// It's needed to keep expected calls order and prevent cases when iteration happens before all usernames
|
// It's needed to keep expected calls order and prevent cases when iteration happens before all usernames
|
||||||
// will be queued.
|
// will be queued.
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.queued", int64(1)).Once().Run(func(args mock.Arguments) {
|
suite.Emitter.On("Emit",
|
||||||
|
"mojang_textures:batch_uuids_provider:queued",
|
||||||
|
username,
|
||||||
|
).Once().Run(func(args mock.Arguments) {
|
||||||
s <- true
|
s <- true
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -144,8 +146,8 @@ func (suite *batchUuidsProviderTestSuite) SetupTest() {
|
|||||||
|
|
||||||
func (suite *batchUuidsProviderTestSuite) TearDownTest() {
|
func (suite *batchUuidsProviderTestSuite) TearDownTest() {
|
||||||
suite.done()
|
suite.done()
|
||||||
|
suite.Emitter.AssertExpectations(suite.T())
|
||||||
suite.MojangApi.AssertExpectations(suite.T())
|
suite.MojangApi.AssertExpectations(suite.T())
|
||||||
suite.Logger.AssertExpectations(suite.T())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBatchUuidsProvider(t *testing.T) {
|
func TestBatchUuidsProvider(t *testing.T) {
|
||||||
@ -155,9 +157,9 @@ func TestBatchUuidsProvider(t *testing.T) {
|
|||||||
func (suite *batchUuidsProviderTestSuite) TestGetUuidForOneUsername() {
|
func (suite *batchUuidsProviderTestSuite) TestGetUuidForOneUsername() {
|
||||||
expectedResult := &mojang.ProfileInfo{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
expectedResult := &mojang.ProfileInfo{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
||||||
|
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Once()
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", []string{"username"}, 0).Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Once()
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"username"}).Once().Return([]*mojang.ProfileInfo{expectedResult}, nil)
|
suite.MojangApi.On("UsernamesToUuids", []string{"username"}).Once().Return([]*mojang.ProfileInfo{expectedResult}, nil)
|
||||||
|
|
||||||
@ -174,9 +176,9 @@ func (suite *batchUuidsProviderTestSuite) TestGetUuidForTwoUsernames() {
|
|||||||
expectedResult1 := &mojang.ProfileInfo{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username1"}
|
expectedResult1 := &mojang.ProfileInfo{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username1"}
|
||||||
expectedResult2 := &mojang.ProfileInfo{Id: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", Name: "username2"}
|
expectedResult2 := &mojang.ProfileInfo{Id: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", Name: "username2"}
|
||||||
|
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(2)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Once()
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", []string{"username1", "username2"}, 0).Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Once()
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"username1", "username2"}).Once().Return([]*mojang.ProfileInfo{
|
suite.MojangApi.On("UsernamesToUuids", []string{"username1", "username2"}).Once().Return([]*mojang.ProfileInfo{
|
||||||
expectedResult1,
|
expectedResult1,
|
||||||
@ -203,18 +205,13 @@ func (suite *batchUuidsProviderTestSuite) TestGetUuidForMoreThan10Usernames() {
|
|||||||
usernames[i] = randStr(8)
|
usernames[i] = randStr(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(10)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Twice()
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(2)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", usernames[0:10], 2).Once()
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(2)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", usernames[10:12], 0).Once()
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Twice()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything).Twice()
|
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", mock.MatchedBy(func(usernames []string) bool {
|
suite.MojangApi.On("UsernamesToUuids", usernames[0:10]).Once().Return([]*mojang.ProfileInfo{}, nil)
|
||||||
return len(usernames) == 10
|
suite.MojangApi.On("UsernamesToUuids", usernames[10:12]).Once().Return([]*mojang.ProfileInfo{}, nil)
|
||||||
})).Once().Return([]*mojang.ProfileInfo{}, nil)
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", mock.MatchedBy(func(usernames []string) bool {
|
|
||||||
return len(usernames) == 2
|
|
||||||
})).Once().Return([]*mojang.ProfileInfo{}, nil)
|
|
||||||
|
|
||||||
channels := make([]chan *batchUuidsProviderGetUuidResult, len(usernames))
|
channels := make([]chan *batchUuidsProviderGetUuidResult, len(usernames))
|
||||||
for i, username := range usernames {
|
for i, username := range usernames {
|
||||||
@ -230,10 +227,11 @@ func (suite *batchUuidsProviderTestSuite) TestGetUuidForMoreThan10Usernames() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *batchUuidsProviderTestSuite) TestDoNothingWhenNoTasks() {
|
func (suite *batchUuidsProviderTestSuite) TestDoNothingWhenNoTasks() {
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Times(3)
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(0)).Twice()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", []string{"username"}, 0).Once()
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Times(3)
|
var nilStringSlice []string
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything)
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", nilStringSlice, 0).Twice()
|
||||||
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Times(3)
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"username"}).Once().Return([]*mojang.ProfileInfo{}, nil)
|
suite.MojangApi.On("UsernamesToUuids", []string{"username"}).Once().Return([]*mojang.ProfileInfo{}, nil)
|
||||||
|
|
||||||
@ -254,9 +252,9 @@ func (suite *batchUuidsProviderTestSuite) TestDoNothingWhenNoTasks() {
|
|||||||
func (suite *batchUuidsProviderTestSuite) TestGetUuidForTwoUsernamesWithAnError() {
|
func (suite *batchUuidsProviderTestSuite) TestGetUuidForTwoUsernamesWithAnError() {
|
||||||
expectedError := &mojang.TooManyRequestsError{}
|
expectedError := &mojang.TooManyRequestsError{}
|
||||||
|
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(2)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Once()
|
||||||
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", []string{"username1", "username2"}, 0).Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Once()
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"username1", "username2"}).Once().Return(nil, expectedError)
|
suite.MojangApi.On("UsernamesToUuids", []string{"username1", "username2"}).Once().Return(nil, expectedError)
|
||||||
|
|
||||||
|
@ -1,25 +1,19 @@
|
|||||||
package mojangtextures
|
package mojangtextures
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/mono83/slf/wd"
|
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
)
|
)
|
||||||
|
|
||||||
var uuidToTextures = mojang.UuidToTextures
|
var uuidToTextures = mojang.UuidToTextures
|
||||||
|
|
||||||
type MojangApiTexturesProvider struct {
|
type MojangApiTexturesProvider struct {
|
||||||
Logger wd.Watchdog
|
Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *MojangApiTexturesProvider) GetTextures(uuid string) (*mojang.SignedTexturesResponse, error) {
|
func (ctx *MojangApiTexturesProvider) GetTextures(uuid string) (*mojang.SignedTexturesResponse, error) {
|
||||||
ctx.Logger.IncCounter("mojang_textures.textures.request", 1)
|
ctx.Emit("mojang_textures:mojang_api_textures_provider:before_request", uuid)
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
result, err := uuidToTextures(uuid, true)
|
result, err := uuidToTextures(uuid, true)
|
||||||
ctx.Logger.RecordTimer("mojang_textures.textures.request_time", time.Since(start))
|
ctx.Emit("mojang_textures:mojang_api_textures_provider:after_request", result, err)
|
||||||
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
mocks "github.com/elyby/chrly/tests"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type mojangUuidToTexturesRequestMock struct {
|
type mojangUuidToTexturesRequestMock struct {
|
||||||
@ -28,16 +27,16 @@ type mojangApiTexturesProviderTestSuite struct {
|
|||||||
suite.Suite
|
suite.Suite
|
||||||
|
|
||||||
Provider *MojangApiTexturesProvider
|
Provider *MojangApiTexturesProvider
|
||||||
Logger *mocks.WdMock
|
Emitter *mockEmitter
|
||||||
MojangApi *mojangUuidToTexturesRequestMock
|
MojangApi *mojangUuidToTexturesRequestMock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *mojangApiTexturesProviderTestSuite) SetupTest() {
|
func (suite *mojangApiTexturesProviderTestSuite) SetupTest() {
|
||||||
suite.Logger = &mocks.WdMock{}
|
suite.Emitter = &mockEmitter{}
|
||||||
suite.MojangApi = &mojangUuidToTexturesRequestMock{}
|
suite.MojangApi = &mojangUuidToTexturesRequestMock{}
|
||||||
|
|
||||||
suite.Provider = &MojangApiTexturesProvider{
|
suite.Provider = &MojangApiTexturesProvider{
|
||||||
Logger: suite.Logger,
|
Emitter: suite.Emitter,
|
||||||
}
|
}
|
||||||
|
|
||||||
uuidToTextures = suite.MojangApi.UuidToTextures
|
uuidToTextures = suite.MojangApi.UuidToTextures
|
||||||
@ -45,7 +44,7 @@ func (suite *mojangApiTexturesProviderTestSuite) SetupTest() {
|
|||||||
|
|
||||||
func (suite *mojangApiTexturesProviderTestSuite) TearDownTest() {
|
func (suite *mojangApiTexturesProviderTestSuite) TearDownTest() {
|
||||||
suite.MojangApi.AssertExpectations(suite.T())
|
suite.MojangApi.AssertExpectations(suite.T())
|
||||||
suite.Logger.AssertExpectations(suite.T())
|
suite.Emitter.AssertExpectations(suite.T())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMojangApiTexturesProvider(t *testing.T) {
|
func TestMojangApiTexturesProvider(t *testing.T) {
|
||||||
@ -59,8 +58,15 @@ func (suite *mojangApiTexturesProviderTestSuite) TestGetTextures() {
|
|||||||
}
|
}
|
||||||
suite.MojangApi.On("UuidToTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true).Once().Return(expectedResult, nil)
|
suite.MojangApi.On("UuidToTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true).Once().Return(expectedResult, nil)
|
||||||
|
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.textures.request", int64(1)).Once()
|
suite.Emitter.On("Emit",
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.textures.request_time", mock.Anything).Once()
|
"mojang_textures:mojang_api_textures_provider:before_request",
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
|
).Once()
|
||||||
|
suite.Emitter.On("Emit",
|
||||||
|
"mojang_textures:mojang_api_textures_provider:after_request",
|
||||||
|
expectedResult,
|
||||||
|
nil,
|
||||||
|
).Once()
|
||||||
|
|
||||||
result, err := suite.Provider.GetTextures("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
result, err := suite.Provider.GetTextures("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||||
|
|
||||||
@ -69,11 +75,19 @@ func (suite *mojangApiTexturesProviderTestSuite) TestGetTextures() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *mojangApiTexturesProviderTestSuite) TestGetTexturesWithError() {
|
func (suite *mojangApiTexturesProviderTestSuite) TestGetTexturesWithError() {
|
||||||
|
var expectedResponse *mojang.SignedTexturesResponse
|
||||||
expectedError := &mojang.TooManyRequestsError{}
|
expectedError := &mojang.TooManyRequestsError{}
|
||||||
suite.MojangApi.On("UuidToTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true).Once().Return(nil, expectedError)
|
suite.MojangApi.On("UuidToTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true).Once().Return(nil, expectedError)
|
||||||
|
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.textures.request", int64(1)).Once()
|
suite.Emitter.On("Emit",
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.textures.request_time", mock.Anything).Once()
|
"mojang_textures:mojang_api_textures_provider:before_request",
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
|
).Once()
|
||||||
|
suite.Emitter.On("Emit",
|
||||||
|
"mojang_textures:mojang_api_textures_provider:after_request",
|
||||||
|
expectedResponse,
|
||||||
|
expectedError,
|
||||||
|
).Once()
|
||||||
|
|
||||||
result, err := suite.Provider.GetTextures("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
result, err := suite.Provider.GetTextures("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||||
|
|
||||||
|
@ -2,15 +2,9 @@ package mojangtextures
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/mono83/slf/wd"
|
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
)
|
)
|
||||||
@ -77,40 +71,45 @@ type TexturesProvider interface {
|
|||||||
GetTextures(uuid string) (*mojang.SignedTexturesResponse, error)
|
GetTextures(uuid string) (*mojang.SignedTexturesResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Emitter interface {
|
||||||
|
Emit(name string, args ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
|
Emitter
|
||||||
UUIDsProvider
|
UUIDsProvider
|
||||||
TexturesProvider
|
TexturesProvider
|
||||||
Storage
|
Storage
|
||||||
Logger wd.Watchdog
|
|
||||||
|
|
||||||
onFirstCall sync.Once
|
onFirstCall sync.Once
|
||||||
*broadcaster
|
*broadcaster
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move cache events on the corresponding level
|
||||||
|
|
||||||
func (ctx *Provider) GetForUsername(username string) (*mojang.SignedTexturesResponse, error) {
|
func (ctx *Provider) GetForUsername(username string) (*mojang.SignedTexturesResponse, error) {
|
||||||
ctx.onFirstCall.Do(func() {
|
ctx.onFirstCall.Do(func() {
|
||||||
ctx.broadcaster = createBroadcaster()
|
ctx.broadcaster = createBroadcaster()
|
||||||
})
|
})
|
||||||
|
|
||||||
if !allowedUsernamesRegex.MatchString(username) {
|
if !allowedUsernamesRegex.MatchString(username) {
|
||||||
ctx.Logger.IncCounter("mojang_textures.invalid_username", 1)
|
|
||||||
return nil, errors.New("invalid username")
|
return nil, errors.New("invalid username")
|
||||||
}
|
}
|
||||||
|
|
||||||
username = strings.ToLower(username)
|
username = strings.ToLower(username)
|
||||||
ctx.Logger.IncCounter("mojang_textures.request", 1)
|
ctx.Emit("mojang_textures:call")
|
||||||
|
|
||||||
uuid, err := ctx.Storage.GetUuid(username)
|
uuid, err := ctx.Storage.GetUuid(username)
|
||||||
if err == nil && uuid == "" {
|
if err == nil && uuid == "" {
|
||||||
ctx.Logger.IncCounter("mojang_textures.usernames.cache_hit_nil", 1)
|
ctx.Emit("mojang_textures:usernames:cache_hit_nil")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if uuid != "" {
|
if uuid != "" {
|
||||||
ctx.Logger.IncCounter("mojang_textures.usernames.cache_hit", 1)
|
ctx.Emit("mojang_textures:usernames:cache_hit")
|
||||||
textures, err := ctx.Storage.GetTextures(uuid)
|
textures, err := ctx.Storage.GetTextures(uuid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ctx.Logger.IncCounter("mojang_textures.textures.cache_hit", 1)
|
ctx.Emit("mojang_textures:textures:cache_hit")
|
||||||
return textures, nil
|
return textures, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +119,7 @@ func (ctx *Provider) GetForUsername(username string) (*mojang.SignedTexturesResp
|
|||||||
if isFirstListener {
|
if isFirstListener {
|
||||||
go ctx.getResultAndBroadcast(username, uuid)
|
go ctx.getResultAndBroadcast(username, uuid)
|
||||||
} else {
|
} else {
|
||||||
ctx.Logger.IncCounter("mojang_textures.already_scheduled", 1)
|
ctx.Emit("mojang_textures:already_processing")
|
||||||
}
|
}
|
||||||
|
|
||||||
result := <-resultChan
|
result := <-resultChan
|
||||||
@ -129,19 +128,19 @@ func (ctx *Provider) GetForUsername(username string) (*mojang.SignedTexturesResp
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Provider) getResultAndBroadcast(username string, uuid string) {
|
func (ctx *Provider) getResultAndBroadcast(username string, uuid string) {
|
||||||
start := time.Now()
|
ctx.Emit("mojang_textures:before_get_result")
|
||||||
|
|
||||||
result := ctx.getResult(username, uuid)
|
result := ctx.getResult(username, uuid)
|
||||||
ctx.broadcaster.BroadcastAndRemove(username, result)
|
ctx.broadcaster.BroadcastAndRemove(username, result)
|
||||||
|
|
||||||
ctx.Logger.RecordTimer("mojang_textures.result_time", time.Since(start))
|
ctx.Emit("mojang_textures:after_get_result")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Provider) getResult(username string, uuid string) *broadcastResult {
|
func (ctx *Provider) getResult(username string, uuid string) *broadcastResult {
|
||||||
if uuid == "" {
|
if uuid == "" {
|
||||||
profile, err := ctx.UUIDsProvider.GetUuid(username)
|
profile, err := ctx.UUIDsProvider.GetUuid(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.handleMojangApiResponseError(err, "usernames")
|
ctx.Emit("mojang_textures:usernames:error", err)
|
||||||
return &broadcastResult{nil, err}
|
return &broadcastResult{nil, err}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,16 +152,16 @@ func (ctx *Provider) getResult(username string, uuid string) *broadcastResult {
|
|||||||
_ = ctx.Storage.StoreUuid(username, uuid)
|
_ = ctx.Storage.StoreUuid(username, uuid)
|
||||||
|
|
||||||
if uuid == "" {
|
if uuid == "" {
|
||||||
ctx.Logger.IncCounter("mojang_textures.usernames.uuid_miss", 1)
|
ctx.Emit("mojang_textures:usernames:uuid_miss")
|
||||||
return &broadcastResult{nil, nil}
|
return &broadcastResult{nil, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.IncCounter("mojang_textures.usernames.uuid_hit", 1)
|
ctx.Emit("mojang_textures:usernames:uuid_hit")
|
||||||
}
|
}
|
||||||
|
|
||||||
textures, err := ctx.TexturesProvider.GetTextures(uuid)
|
textures, err := ctx.TexturesProvider.GetTextures(uuid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.handleMojangApiResponseError(err, "textures")
|
ctx.Emit("mojang_textures:textures:error", err)
|
||||||
return &broadcastResult{nil, err}
|
return &broadcastResult{nil, err}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,55 +170,10 @@ func (ctx *Provider) getResult(username string, uuid string) *broadcastResult {
|
|||||||
ctx.Storage.StoreTextures(uuid, textures)
|
ctx.Storage.StoreTextures(uuid, textures)
|
||||||
|
|
||||||
if textures != nil {
|
if textures != nil {
|
||||||
ctx.Logger.IncCounter("mojang_textures.usernames.textures_hit", 1)
|
ctx.Emit("mojang_textures:textures:hit")
|
||||||
} else {
|
} else {
|
||||||
ctx.Logger.IncCounter("mojang_textures.usernames.textures_miss", 1)
|
ctx.Emit("mojang_textures:textures:miss")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &broadcastResult{textures, nil}
|
return &broadcastResult{textures, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Provider) handleMojangApiResponseError(err error, threadName string) {
|
|
||||||
errParam := wd.ErrParam(err)
|
|
||||||
threadParam := wd.NameParam(threadName)
|
|
||||||
|
|
||||||
ctx.Logger.Debug(":name: Got response error :err", threadParam, errParam)
|
|
||||||
|
|
||||||
switch err.(type) {
|
|
||||||
case mojang.ResponseError:
|
|
||||||
if _, ok := err.(*mojang.BadRequestError); ok {
|
|
||||||
ctx.Logger.Warning(":name: Got 400 Bad Request :err", threadParam, errParam)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := err.(*mojang.ForbiddenError); ok {
|
|
||||||
ctx.Logger.Warning(":name: Got 403 Forbidden :err", threadParam, errParam)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := err.(*mojang.TooManyRequestsError); ok {
|
|
||||||
ctx.Logger.Warning(":name: Got 429 Too Many Requests :err", threadParam, errParam)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
case net.Error:
|
|
||||||
if err.(net.Error).Timeout() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := err.(*url.Error); ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if opErr, ok := err.(*net.OpError); ok && (opErr.Op == "dial" || opErr.Op == "read") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == syscall.ECONNREFUSED {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Logger.Emergency(":name: Unknown Mojang response error: :err", threadParam, errParam)
|
|
||||||
}
|
|
||||||
|
@ -2,10 +2,7 @@ package mojangtextures
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,7 +11,6 @@ import (
|
|||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
mocks "github.com/elyby/chrly/tests"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBroadcaster(t *testing.T) {
|
func TestBroadcaster(t *testing.T) {
|
||||||
@ -86,6 +82,14 @@ func TestBroadcaster(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockEmitter struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *mockEmitter) Emit(name string, args ...interface{}) {
|
||||||
|
e.Called(append([]interface{}{name}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
type mockUuidsProvider struct {
|
type mockUuidsProvider struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
@ -145,32 +149,31 @@ func (m *mockStorage) StoreTextures(uuid string, textures *mojang.SignedTextures
|
|||||||
type providerTestSuite struct {
|
type providerTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
Provider *Provider
|
Provider *Provider
|
||||||
|
Emitter *mockEmitter
|
||||||
UuidsProvider *mockUuidsProvider
|
UuidsProvider *mockUuidsProvider
|
||||||
TexturesProvider *mockTexturesProvider
|
TexturesProvider *mockTexturesProvider
|
||||||
Storage *mockStorage
|
Storage *mockStorage
|
||||||
Logger *mocks.WdMock
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *providerTestSuite) SetupTest() {
|
func (suite *providerTestSuite) SetupTest() {
|
||||||
|
suite.Emitter = &mockEmitter{}
|
||||||
suite.UuidsProvider = &mockUuidsProvider{}
|
suite.UuidsProvider = &mockUuidsProvider{}
|
||||||
suite.TexturesProvider = &mockTexturesProvider{}
|
suite.TexturesProvider = &mockTexturesProvider{}
|
||||||
suite.Storage = &mockStorage{}
|
suite.Storage = &mockStorage{}
|
||||||
suite.Logger = &mocks.WdMock{}
|
|
||||||
|
|
||||||
suite.Provider = &Provider{
|
suite.Provider = &Provider{
|
||||||
|
Emitter: suite.Emitter,
|
||||||
UUIDsProvider: suite.UuidsProvider,
|
UUIDsProvider: suite.UuidsProvider,
|
||||||
TexturesProvider: suite.TexturesProvider,
|
TexturesProvider: suite.TexturesProvider,
|
||||||
Storage: suite.Storage,
|
Storage: suite.Storage,
|
||||||
Logger: suite.Logger,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *providerTestSuite) TearDownTest() {
|
func (suite *providerTestSuite) TearDownTest() {
|
||||||
// time.Sleep(10 * time.Millisecond) // Add delay to let finish all goroutines before assert mocks calls
|
suite.Emitter.AssertExpectations(suite.T())
|
||||||
suite.UuidsProvider.AssertExpectations(suite.T())
|
suite.UuidsProvider.AssertExpectations(suite.T())
|
||||||
suite.TexturesProvider.AssertExpectations(suite.T())
|
suite.TexturesProvider.AssertExpectations(suite.T())
|
||||||
suite.Storage.AssertExpectations(suite.T())
|
suite.Storage.AssertExpectations(suite.T())
|
||||||
suite.Logger.AssertExpectations(suite.T())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProvider(t *testing.T) {
|
func TestProvider(t *testing.T) {
|
||||||
@ -180,10 +183,11 @@ func TestProvider(t *testing.T) {
|
|||||||
func (suite *providerTestSuite) TestGetForUsernameWithoutAnyCache() {
|
func (suite *providerTestSuite) TestGetForUsernameWithoutAnyCache() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
||||||
|
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:call").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:before_get_result").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.textures_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:usernames:uuid_hit").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:textures:hit").Once()
|
||||||
|
suite.Emitter.On("Emit", "mojang_textures:after_get_result").Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
|
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
|
||||||
@ -204,10 +208,11 @@ func (suite *providerTestSuite) TestGetForUsernameWithoutAnyCache() {
|
|||||||
func (suite *providerTestSuite) TestGetForUsernameWithCachedUuid() {
|
func (suite *providerTestSuite) TestGetForUsernameWithCachedUuid() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
||||||
|
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:call").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.cache_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:usernames:cache_hit").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.textures_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:before_get_result").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:textures:hit").Once()
|
||||||
|
suite.Emitter.On("Emit", "mojang_textures:after_get_result").Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Once().Return("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil)
|
suite.Storage.On("GetUuid", "username").Once().Return("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil)
|
||||||
suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, &ValueNotFound{})
|
suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, &ValueNotFound{})
|
||||||
@ -224,9 +229,9 @@ func (suite *providerTestSuite) TestGetForUsernameWithCachedUuid() {
|
|||||||
func (suite *providerTestSuite) TestGetForUsernameWithFullyCachedResult() {
|
func (suite *providerTestSuite) TestGetForUsernameWithFullyCachedResult() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
||||||
|
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:call").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.cache_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:usernames:cache_hit").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.textures.cache_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:textures:cache_hit").Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Once().Return("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil)
|
suite.Storage.On("GetUuid", "username").Once().Return("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil)
|
||||||
suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(expectedResult, nil)
|
suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(expectedResult, nil)
|
||||||
@ -238,8 +243,8 @@ func (suite *providerTestSuite) TestGetForUsernameWithFullyCachedResult() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *providerTestSuite) TestGetForUsernameWithCachedUnknownUuid() {
|
func (suite *providerTestSuite) TestGetForUsernameWithCachedUnknownUuid() {
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:call").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.cache_hit_nil", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:usernames:cache_hit_nil").Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Once().Return("", nil)
|
suite.Storage.On("GetUuid", "username").Once().Return("", nil)
|
||||||
|
|
||||||
@ -250,9 +255,10 @@ func (suite *providerTestSuite) TestGetForUsernameWithCachedUnknownUuid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *providerTestSuite) TestGetForUsernameWhichHasNoMojangAccount() {
|
func (suite *providerTestSuite) TestGetForUsernameWhichHasNoMojangAccount() {
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:call").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_miss", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:before_get_result").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:usernames:uuid_miss").Once()
|
||||||
|
suite.Emitter.On("Emit", "mojang_textures:after_get_result").Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "username", "").Once().Return(nil)
|
suite.Storage.On("StoreUuid", "username", "").Once().Return(nil)
|
||||||
@ -268,10 +274,11 @@ func (suite *providerTestSuite) TestGetForUsernameWhichHasNoMojangAccount() {
|
|||||||
func (suite *providerTestSuite) TestGetForUsernameWhichHasMojangAccountButHasNoMojangSkin() {
|
func (suite *providerTestSuite) TestGetForUsernameWhichHasMojangAccountButHasNoMojangSkin() {
|
||||||
var expectedResult *mojang.SignedTexturesResponse
|
var expectedResult *mojang.SignedTexturesResponse
|
||||||
|
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:call").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:before_get_result").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.textures_miss", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:usernames:uuid_hit").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:textures:miss").Once()
|
||||||
|
suite.Emitter.On("Emit", "mojang_textures:after_get_result").Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
|
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
|
||||||
@ -292,11 +299,12 @@ func (suite *providerTestSuite) TestGetForUsernameWhichHasMojangAccountButHasNoM
|
|||||||
func (suite *providerTestSuite) TestGetForTheSameUsernames() {
|
func (suite *providerTestSuite) TestGetForTheSameUsernames() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
||||||
|
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Twice()
|
suite.Emitter.On("Emit", "mojang_textures:call").Twice()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.already_scheduled", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:already_processing").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:before_get_result").Once()
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.textures_hit", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:usernames:uuid_hit").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:textures:hit").Once()
|
||||||
|
suite.Emitter.On("Emit", "mojang_textures:after_get_result").Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Twice().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "username").Twice().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
|
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
|
||||||
@ -326,114 +334,45 @@ func (suite *providerTestSuite) TestGetForTheSameUsernames() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *providerTestSuite) TestGetForNotAllowedMojangUsername() {
|
func (suite *providerTestSuite) TestGetForNotAllowedMojangUsername() {
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.invalid_username", int64(1)).Once()
|
|
||||||
|
|
||||||
result, err := suite.Provider.GetForUsername("Not allowed")
|
result, err := suite.Provider.GetForUsername("Not allowed")
|
||||||
suite.Assert().Error(err, "invalid username")
|
suite.Assert().Error(err, "invalid username")
|
||||||
suite.Assert().Nil(result)
|
suite.Assert().Nil(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeoutError struct {
|
func (suite *providerTestSuite) TestGetErrorFromUuidsProvider() {
|
||||||
}
|
err := errors.New("mock error")
|
||||||
|
|
||||||
func (*timeoutError) Error() string { return "timeout error" }
|
suite.Emitter.On("Emit", "mojang_textures:call").Once()
|
||||||
func (*timeoutError) Timeout() bool { return true }
|
suite.Emitter.On("Emit", "mojang_textures:before_get_result").Once()
|
||||||
func (*timeoutError) Temporary() bool { return false }
|
suite.Emitter.On("Emit", "mojang_textures:usernames:error", err).Once()
|
||||||
|
suite.Emitter.On("Emit", "mojang_textures:after_get_result").Once()
|
||||||
|
|
||||||
var expectedErrors = []error{
|
suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
|
||||||
&mojang.BadRequestError{},
|
suite.UuidsProvider.On("GetUuid", "username").Once().Return(nil, err)
|
||||||
&mojang.ForbiddenError{},
|
|
||||||
&mojang.TooManyRequestsError{},
|
|
||||||
&mojang.ServerError{},
|
|
||||||
&timeoutError{},
|
|
||||||
&url.Error{Op: "GET", URL: "http://localhost"},
|
|
||||||
&net.OpError{Op: "read"},
|
|
||||||
&net.OpError{Op: "dial"},
|
|
||||||
syscall.ECONNREFUSED,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *providerTestSuite) TestShouldNotLogErrorWhenExpectedErrorReturnedFromUsernameToUuidRequest() {
|
result, resErr := suite.Provider.GetForUsername("username")
|
||||||
suite.Logger.On("IncCounter", mock.Anything, mock.Anything)
|
|
||||||
suite.Logger.On("RecordTimer", mock.Anything, mock.Anything)
|
|
||||||
suite.Logger.On("Debug", ":name: Got response error :err", mock.Anything, mock.Anything).Times(len(expectedErrors))
|
|
||||||
suite.Logger.On("Warning", ":name: Got 400 Bad Request :err", mock.Anything, mock.Anything).Once()
|
|
||||||
suite.Logger.On("Warning", ":name: Got 403 Forbidden :err", mock.Anything, mock.Anything).Once()
|
|
||||||
suite.Logger.On("Warning", ":name: Got 429 Too Many Requests :err", mock.Anything, mock.Anything).Once()
|
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Return("", &ValueNotFound{})
|
|
||||||
|
|
||||||
for _, err := range expectedErrors {
|
|
||||||
suite.UuidsProvider.On("GetUuid", "username").Once().Return(nil, err)
|
|
||||||
|
|
||||||
result, err := suite.Provider.GetForUsername("username")
|
|
||||||
suite.Assert().Nil(result)
|
|
||||||
suite.Assert().NotNil(err)
|
|
||||||
suite.UuidsProvider.AssertExpectations(suite.T())
|
|
||||||
suite.UuidsProvider.ExpectedCalls = nil // https://github.com/stretchr/testify/issues/558#issuecomment-372112364
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *providerTestSuite) TestShouldLogEmergencyOnUnexpectedErrorReturnedFromUsernameToUuidRequest() {
|
|
||||||
suite.Logger.On("IncCounter", mock.Anything, mock.Anything)
|
|
||||||
suite.Logger.On("RecordTimer", mock.Anything, mock.Anything)
|
|
||||||
suite.Logger.On("Debug", ":name: Got response error :err", mock.Anything, mock.Anything).Once()
|
|
||||||
suite.Logger.On("Emergency", ":name: Unknown Mojang response error: :err", mock.Anything, mock.Anything).Once()
|
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Return("", &ValueNotFound{})
|
|
||||||
|
|
||||||
suite.UuidsProvider.On("GetUuid", "username").Once().Return(nil, errors.New("unexpected error"))
|
|
||||||
|
|
||||||
result, err := suite.Provider.GetForUsername("username")
|
|
||||||
suite.Assert().Nil(result)
|
suite.Assert().Nil(result)
|
||||||
suite.Assert().NotNil(err)
|
suite.Assert().Equal(err, resErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *providerTestSuite) TestShouldNotLogErrorWhenExpectedErrorReturnedFromUuidToTexturesRequest() {
|
func (suite *providerTestSuite) TestGetErrorFromTexturesProvider() {
|
||||||
suite.Logger.On("IncCounter", mock.Anything, mock.Anything)
|
err := errors.New("mock error")
|
||||||
suite.Logger.On("RecordTimer", mock.Anything, mock.Anything)
|
|
||||||
suite.Logger.On("Debug", ":name: Got response error :err", mock.Anything, mock.Anything).Times(len(expectedErrors))
|
suite.Emitter.On("Emit", "mojang_textures:call").Once()
|
||||||
suite.Logger.On("Warning", ":name: Got 400 Bad Request :err", mock.Anything, mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:before_get_result").Once()
|
||||||
suite.Logger.On("Warning", ":name: Got 403 Forbidden :err", mock.Anything, mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:usernames:uuid_hit").Once()
|
||||||
suite.Logger.On("Warning", ":name: Got 429 Too Many Requests :err", mock.Anything, mock.Anything).Once()
|
suite.Emitter.On("Emit", "mojang_textures:textures:error", err).Once()
|
||||||
|
suite.Emitter.On("Emit", "mojang_textures:after_get_result").Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "username").Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Return(nil)
|
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Return(nil)
|
||||||
// suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Return(nil, &ValueNotFound{})
|
|
||||||
// suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", (*mojang.SignedTexturesResponse)(nil))
|
|
||||||
|
|
||||||
for _, err := range expectedErrors {
|
|
||||||
suite.UuidsProvider.On("GetUuid", "username").Once().Return(&mojang.ProfileInfo{
|
|
||||||
Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
||||||
Name: "username",
|
|
||||||
}, nil)
|
|
||||||
suite.TexturesProvider.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, err)
|
|
||||||
|
|
||||||
result, err := suite.Provider.GetForUsername("username")
|
|
||||||
suite.Assert().Nil(result)
|
|
||||||
suite.Assert().NotNil(err)
|
|
||||||
suite.UuidsProvider.AssertExpectations(suite.T())
|
|
||||||
suite.TexturesProvider.AssertExpectations(suite.T())
|
|
||||||
suite.UuidsProvider.ExpectedCalls = nil // https://github.com/stretchr/testify/issues/558#issuecomment-372112364
|
|
||||||
suite.TexturesProvider.ExpectedCalls = nil // https://github.com/stretchr/testify/issues/558#issuecomment-372112364
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *providerTestSuite) TestShouldLogEmergencyOnUnexpectedErrorReturnedFromUuidToTexturesRequest() {
|
|
||||||
suite.Logger.On("IncCounter", mock.Anything, mock.Anything)
|
|
||||||
suite.Logger.On("RecordTimer", mock.Anything, mock.Anything)
|
|
||||||
suite.Logger.On("Debug", ":name: Got response error :err", mock.Anything, mock.Anything).Once()
|
|
||||||
suite.Logger.On("Emergency", ":name: Unknown Mojang response error: :err", mock.Anything, mock.Anything).Once()
|
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "username").Return("", &ValueNotFound{})
|
|
||||||
suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Return(nil)
|
|
||||||
|
|
||||||
suite.UuidsProvider.On("GetUuid", "username").Once().Return(&mojang.ProfileInfo{
|
suite.UuidsProvider.On("GetUuid", "username").Once().Return(&mojang.ProfileInfo{
|
||||||
Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
Name: "username",
|
Name: "username",
|
||||||
}, nil)
|
}, nil)
|
||||||
suite.TexturesProvider.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, errors.New("unexpected error"))
|
suite.TexturesProvider.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, err)
|
||||||
|
|
||||||
result, err := suite.Provider.GetForUsername("username")
|
result, resErr := suite.Provider.GetForUsername("username")
|
||||||
suite.Assert().Nil(result)
|
suite.Assert().Nil(result)
|
||||||
suite.Assert().NotNil(err)
|
suite.Assert().Equal(err, resErr)
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,13 @@ package mojangtextures
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/elyby/chrly/version"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
. "net/url"
|
. "net/url"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/mono83/slf/wd"
|
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
|
"github.com/elyby/chrly/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
var HttpClient = &http.Client{
|
var HttpClient = &http.Client{
|
||||||
@ -21,24 +18,23 @@ var HttpClient = &http.Client{
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoteApiUuidsProvider struct {
|
type RemoteApiUuidsProvider struct {
|
||||||
|
Emitter
|
||||||
Url URL
|
Url URL
|
||||||
Logger wd.Watchdog
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *RemoteApiUuidsProvider) GetUuid(username string) (*mojang.ProfileInfo, error) {
|
func (ctx *RemoteApiUuidsProvider) GetUuid(username string) (*mojang.ProfileInfo, error) {
|
||||||
ctx.Logger.IncCounter("mojang_textures.usernames.request", 1)
|
|
||||||
|
|
||||||
url := ctx.Url
|
url := ctx.Url
|
||||||
url.Path = path.Join(url.Path, username)
|
url.Path = path.Join(url.Path, username)
|
||||||
|
urlStr := url.String()
|
||||||
|
|
||||||
request, _ := http.NewRequest("GET", url.String(), nil)
|
request, _ := http.NewRequest("GET", urlStr, nil)
|
||||||
request.Header.Add("Accept", "application/json")
|
request.Header.Add("Accept", "application/json")
|
||||||
// Change default User-Agent to allow specify "Username -> UUID at time" Mojang's api endpoint
|
// Change default User-Agent to allow specify "Username -> UUID at time" Mojang's api endpoint
|
||||||
request.Header.Add("User-Agent", "Chrly/"+version.Version())
|
request.Header.Add("User-Agent", "Chrly/"+version.Version())
|
||||||
|
|
||||||
start := time.Now()
|
ctx.Emit("mojang_textures:remote_api_uuids_provider:before_request", urlStr)
|
||||||
response, err := HttpClient.Do(request)
|
response, err := HttpClient.Do(request)
|
||||||
ctx.Logger.RecordTimer("mojang_textures.usernames.request_time", time.Since(start))
|
ctx.Emit("mojang_textures:remote_api_uuids_provider:after_request", response, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,19 @@ package mojangtextures
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
. "net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/h2non/gock"
|
"github.com/h2non/gock"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
mocks "github.com/elyby/chrly/tests"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type remoteApiUuidsProviderTestSuite struct {
|
type remoteApiUuidsProviderTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
|
|
||||||
Provider *RemoteApiUuidsProvider
|
Provider *RemoteApiUuidsProvider
|
||||||
Logger *mocks.WdMock
|
Emitter *mockEmitter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *remoteApiUuidsProviderTestSuite) SetupSuite() {
|
func (suite *remoteApiUuidsProviderTestSuite) SetupSuite() {
|
||||||
@ -28,14 +26,14 @@ func (suite *remoteApiUuidsProviderTestSuite) SetupSuite() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *remoteApiUuidsProviderTestSuite) SetupTest() {
|
func (suite *remoteApiUuidsProviderTestSuite) SetupTest() {
|
||||||
suite.Logger = &mocks.WdMock{}
|
suite.Emitter = &mockEmitter{}
|
||||||
suite.Provider = &RemoteApiUuidsProvider{
|
suite.Provider = &RemoteApiUuidsProvider{
|
||||||
Logger: suite.Logger,
|
Emitter: suite.Emitter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *remoteApiUuidsProviderTestSuite) TearDownTest() {
|
func (suite *remoteApiUuidsProviderTestSuite) TearDownTest() {
|
||||||
suite.Logger.AssertExpectations(suite.T())
|
suite.Emitter.AssertExpectations(suite.T())
|
||||||
gock.Off()
|
gock.Off()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +42,12 @@ func TestRemoteApiUuidsProvider(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForValidUsername() {
|
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForValidUsername() {
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:remote_api_uuids_provider:before_request", "http://example.com/subpath/username").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.request_time", mock.Anything).Once()
|
suite.Emitter.On("Emit",
|
||||||
|
"mojang_textures:remote_api_uuids_provider:after_request",
|
||||||
|
mock.AnythingOfType("*http.Response"),
|
||||||
|
nil,
|
||||||
|
).Once()
|
||||||
|
|
||||||
gock.New("http://example.com").
|
gock.New("http://example.com").
|
||||||
Get("/subpath/username").
|
Get("/subpath/username").
|
||||||
@ -68,8 +70,12 @@ func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForValidUsername() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNotExistsUsername() {
|
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNotExistsUsername() {
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:remote_api_uuids_provider:before_request", "http://example.com/subpath/username").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.request_time", mock.Anything).Once()
|
suite.Emitter.On("Emit",
|
||||||
|
"mojang_textures:remote_api_uuids_provider:after_request",
|
||||||
|
mock.AnythingOfType("*http.Response"),
|
||||||
|
nil,
|
||||||
|
).Once()
|
||||||
|
|
||||||
gock.New("http://example.com").
|
gock.New("http://example.com").
|
||||||
Get("/subpath/username").
|
Get("/subpath/username").
|
||||||
@ -84,8 +90,12 @@ func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNotExistsUsername()
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNon20xResponse() {
|
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNon20xResponse() {
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:remote_api_uuids_provider:before_request", "http://example.com/subpath/username").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.request_time", mock.Anything).Once()
|
suite.Emitter.On("Emit",
|
||||||
|
"mojang_textures:remote_api_uuids_provider:after_request",
|
||||||
|
mock.AnythingOfType("*http.Response"),
|
||||||
|
nil,
|
||||||
|
).Once()
|
||||||
|
|
||||||
gock.New("http://example.com").
|
gock.New("http://example.com").
|
||||||
Get("/subpath/username").
|
Get("/subpath/username").
|
||||||
@ -101,8 +111,12 @@ func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNon20xResponse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNotSuccessRequest() {
|
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNotSuccessRequest() {
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:remote_api_uuids_provider:before_request", "http://example.com/subpath/username").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.request_time", mock.Anything).Once()
|
suite.Emitter.On("Emit",
|
||||||
|
"mojang_textures:remote_api_uuids_provider:after_request",
|
||||||
|
mock.AnythingOfType("*http.Response"),
|
||||||
|
mock.AnythingOfType("*url.Error"),
|
||||||
|
).Once()
|
||||||
|
|
||||||
expectedError := &net.OpError{Op: "dial"}
|
expectedError := &net.OpError{Op: "dial"}
|
||||||
|
|
||||||
@ -116,15 +130,19 @@ func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForNotSuccessRequest()
|
|||||||
assert := suite.Assert()
|
assert := suite.Assert()
|
||||||
assert.Nil(result)
|
assert.Nil(result)
|
||||||
if assert.Error(err) {
|
if assert.Error(err) {
|
||||||
assert.IsType(&url.Error{}, err)
|
assert.IsType(&Error{}, err)
|
||||||
casterErr, _ := err.(*url.Error)
|
casterErr, _ := err.(*Error)
|
||||||
assert.Equal(expectedError, casterErr.Err)
|
assert.Equal(expectedError, casterErr.Err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForInvalidSuccessResponse() {
|
func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForInvalidSuccessResponse() {
|
||||||
suite.Logger.On("IncCounter", "mojang_textures.usernames.request", int64(1)).Once()
|
suite.Emitter.On("Emit", "mojang_textures:remote_api_uuids_provider:before_request", "http://example.com/subpath/username").Once()
|
||||||
suite.Logger.On("RecordTimer", "mojang_textures.usernames.request_time", mock.Anything).Once()
|
suite.Emitter.On("Emit",
|
||||||
|
"mojang_textures:remote_api_uuids_provider:after_request",
|
||||||
|
mock.AnythingOfType("*http.Response"),
|
||||||
|
nil,
|
||||||
|
).Once()
|
||||||
|
|
||||||
gock.New("http://example.com").
|
gock.New("http://example.com").
|
||||||
Get("/subpath/username").
|
Get("/subpath/username").
|
||||||
@ -139,8 +157,8 @@ func (suite *remoteApiUuidsProviderTestSuite) TestGetUuidForInvalidSuccessRespon
|
|||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldParseUrl(rawUrl string) url.URL {
|
func shouldParseUrl(rawUrl string) URL {
|
||||||
url, err := url.Parse(rawUrl)
|
url, err := Parse(rawUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user