mirror of
				https://github.com/elyby/chrly.git
				synced 2025-05-31 14:11:51 +05:30 
			
		
		
		
	Integrate event dispatcher into mojangtextures package
This commit is contained in:
		@@ -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{
 | 
				
			||||||
 | 
								Emitter: emitter,
 | 
				
			||||||
			Url:     *remoteUrl,
 | 
								Url:     *remoteUrl,
 | 
				
			||||||
			Logger: logger,
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} 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{},
 | 
					 | 
				
			||||||
	&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() {
 | 
					 | 
				
			||||||
	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)
 | 
						suite.UuidsProvider.On("GetUuid", "username").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)
 | 
				
			||||||
		suite.UuidsProvider.AssertExpectations(suite.T())
 | 
					 | 
				
			||||||
		suite.UuidsProvider.ExpectedCalls = nil // https://github.com/stretchr/testify/issues/558#issuecomment-372112364
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (suite *providerTestSuite) TestShouldLogEmergencyOnUnexpectedErrorReturnedFromUsernameToUuidRequest() {
 | 
					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).Once()
 | 
					 | 
				
			||||||
	suite.Logger.On("Emergency", ":name: Unknown Mojang response error: :err", mock.Anything, mock.Anything).Once()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Return("", &ValueNotFound{})
 | 
						suite.Emitter.On("Emit", "mojang_textures:call").Once()
 | 
				
			||||||
 | 
						suite.Emitter.On("Emit", "mojang_textures:before_get_result").Once()
 | 
				
			||||||
	suite.UuidsProvider.On("GetUuid", "username").Once().Return(nil, errors.New("unexpected error"))
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:uuid_hit").Once()
 | 
				
			||||||
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:error", err).Once()
 | 
				
			||||||
	result, err := suite.Provider.GetForUsername("username")
 | 
						suite.Emitter.On("Emit", "mojang_textures:after_get_result").Once()
 | 
				
			||||||
	suite.Assert().Nil(result)
 | 
					 | 
				
			||||||
	suite.Assert().NotNil(err)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (suite *providerTestSuite) TestShouldNotLogErrorWhenExpectedErrorReturnedFromUuidToTexturesRequest() {
 | 
					 | 
				
			||||||
	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{})
 | 
						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{
 | 
						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, err)
 | 
						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)
 | 
				
			||||||
		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{
 | 
					 | 
				
			||||||
		Id:   "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
 | 
					 | 
				
			||||||
		Name: "username",
 | 
					 | 
				
			||||||
	}, nil)
 | 
					 | 
				
			||||||
	suite.TexturesProvider.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, errors.New("unexpected error"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result, err := suite.Provider.GetForUsername("username")
 | 
					 | 
				
			||||||
	suite.Assert().Nil(result)
 | 
					 | 
				
			||||||
	suite.Assert().NotNil(err)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user