mirror of
https://github.com/elyby/chrly.git
synced 2025-01-03 10:41:47 +05:30
#1: Add logging mechanic and remove awaiting of finishing of all textures requests in usernames queue
This commit is contained in:
parent
50a19202a5
commit
533afcc689
@ -8,6 +8,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mono83/slf/wd"
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,6 +25,7 @@ var allowedUsernamesRegex = regexp.MustCompile(`^[\w_]{3,16}$`)
|
|||||||
|
|
||||||
type JobsQueue struct {
|
type JobsQueue struct {
|
||||||
Storage Storage
|
Storage Storage
|
||||||
|
Logger wd.Watchdog
|
||||||
|
|
||||||
onFirstCall sync.Once
|
onFirstCall sync.Once
|
||||||
queue jobsQueue
|
queue jobsQueue
|
||||||
@ -38,6 +41,7 @@ func (ctx *JobsQueue) GetTexturesForUsername(username string) chan *mojang.Signe
|
|||||||
|
|
||||||
responseChan := make(chan *mojang.SignedTexturesResponse)
|
responseChan := make(chan *mojang.SignedTexturesResponse)
|
||||||
if !allowedUsernamesRegex.MatchString(username) {
|
if !allowedUsernamesRegex.MatchString(username) {
|
||||||
|
ctx.Logger.IncCounter("mojang_textures.invalid_username", 1)
|
||||||
go func() {
|
go func() {
|
||||||
responseChan <- nil
|
responseChan <- nil
|
||||||
close(responseChan)
|
close(responseChan)
|
||||||
@ -46,8 +50,12 @@ func (ctx *JobsQueue) GetTexturesForUsername(username string) chan *mojang.Signe
|
|||||||
return responseChan
|
return responseChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.Logger.IncCounter("mojang_textures.request", 1)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
responseChan <- nil
|
responseChan <- nil
|
||||||
close(responseChan)
|
close(responseChan)
|
||||||
@ -58,12 +66,15 @@ func (ctx *JobsQueue) GetTexturesForUsername(username string) chan *mojang.Signe
|
|||||||
|
|
||||||
isFirstListener := ctx.broadcast.AddListener(username, responseChan)
|
isFirstListener := ctx.broadcast.AddListener(username, responseChan)
|
||||||
if isFirstListener {
|
if isFirstListener {
|
||||||
|
start := time.Now()
|
||||||
// TODO: respond nil if processing takes more than 5 seconds
|
// TODO: respond nil if processing takes more than 5 seconds
|
||||||
|
|
||||||
resultChan := make(chan *mojang.SignedTexturesResponse)
|
resultChan := make(chan *mojang.SignedTexturesResponse)
|
||||||
if uuid == "" {
|
if uuid == "" {
|
||||||
|
ctx.Logger.IncCounter("mojang_textures.usernames.queued", 1)
|
||||||
ctx.queue.Enqueue(&jobItem{username, resultChan})
|
ctx.queue.Enqueue(&jobItem{username, resultChan})
|
||||||
} else {
|
} else {
|
||||||
|
ctx.Logger.IncCounter("mojang_textures.usernames.cache_hit", 1)
|
||||||
go func() {
|
go func() {
|
||||||
resultChan <- ctx.getTextures(uuid)
|
resultChan <- ctx.getTextures(uuid)
|
||||||
}()
|
}()
|
||||||
@ -73,7 +84,10 @@ func (ctx *JobsQueue) GetTexturesForUsername(username string) chan *mojang.Signe
|
|||||||
result := <-resultChan
|
result := <-resultChan
|
||||||
close(resultChan)
|
close(resultChan)
|
||||||
ctx.broadcast.BroadcastAndRemove(username, result)
|
ctx.broadcast.BroadcastAndRemove(username, result)
|
||||||
|
ctx.Logger.RecordTimer("mojang_textures.result_time", time.Since(start))
|
||||||
}()
|
}()
|
||||||
|
} else {
|
||||||
|
ctx.Logger.IncCounter("mojang_textures.already_in_queue", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return responseChan
|
return responseChan
|
||||||
@ -85,7 +99,9 @@ func (ctx *JobsQueue) startQueue() {
|
|||||||
for forever() {
|
for forever() {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
ctx.queueRound()
|
ctx.queueRound()
|
||||||
time.Sleep(uuidsQueuePeriod - time.Since(start))
|
elapsed := time.Since(start)
|
||||||
|
ctx.Logger.RecordTimer("mojang_textures.usernames.round_time", elapsed)
|
||||||
|
time.Sleep(uuidsQueuePeriod - elapsed)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@ -95,7 +111,10 @@ func (ctx *JobsQueue) queueRound() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queueSize := ctx.queue.Size()
|
||||||
jobs := ctx.queue.Dequeue(100)
|
jobs := ctx.queue.Dequeue(100)
|
||||||
|
ctx.Logger.UpdateGauge("mojang_textures.usernames.iteration_size", int64(len(jobs)))
|
||||||
|
ctx.Logger.UpdateGauge("mojang_textures.usernames.queue_size", int64(queueSize-len(jobs)))
|
||||||
var usernames []string
|
var usernames []string
|
||||||
for _, job := range jobs {
|
for _, job := range jobs {
|
||||||
usernames = append(usernames, job.Username)
|
usernames = append(usernames, job.Username)
|
||||||
@ -108,14 +127,12 @@ func (ctx *JobsQueue) queueRound() {
|
|||||||
job.RespondTo <- nil
|
job.RespondTo <- nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
maybeShouldPanic(err)
|
ctx.maybeShouldPanic(err)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for _, job := range jobs {
|
for _, job := range jobs {
|
||||||
wg.Add(1)
|
|
||||||
go func(job *jobItem) {
|
go func(job *jobItem) {
|
||||||
var uuid string
|
var uuid string
|
||||||
// Profiles in response not ordered, so we must search each username over full array
|
// Profiles in response not ordered, so we must search each username over full array
|
||||||
@ -129,27 +146,30 @@ func (ctx *JobsQueue) queueRound() {
|
|||||||
ctx.Storage.StoreUuid(job.Username, uuid)
|
ctx.Storage.StoreUuid(job.Username, uuid)
|
||||||
if uuid == "" {
|
if uuid == "" {
|
||||||
job.RespondTo <- nil
|
job.RespondTo <- nil
|
||||||
|
ctx.Logger.IncCounter("mojang_textures.usernames.uuid_miss", 1)
|
||||||
} else {
|
} else {
|
||||||
job.RespondTo <- ctx.getTextures(uuid)
|
job.RespondTo <- ctx.getTextures(uuid)
|
||||||
|
ctx.Logger.IncCounter("mojang_textures.usernames.uuid_hit", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Done()
|
|
||||||
}(job)
|
}(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *JobsQueue) getTextures(uuid string) *mojang.SignedTexturesResponse {
|
func (ctx *JobsQueue) getTextures(uuid string) *mojang.SignedTexturesResponse {
|
||||||
existsTextures, err := ctx.Storage.GetTextures(uuid)
|
existsTextures, err := ctx.Storage.GetTextures(uuid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
ctx.Logger.IncCounter("mojang_textures.textures.cache_hit", 1)
|
||||||
return existsTextures
|
return existsTextures
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldCache := true
|
ctx.Logger.IncCounter("mojang_textures.textures.request", 1)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
result, err := uuidToTextures(uuid, true)
|
result, err := uuidToTextures(uuid, true)
|
||||||
|
ctx.Logger.RecordTimer("mojang_textures.textures.request_time", time.Since(start))
|
||||||
|
shouldCache := true
|
||||||
if err != nil {
|
if err != nil {
|
||||||
maybeShouldPanic(err)
|
ctx.maybeShouldPanic(err)
|
||||||
shouldCache = false
|
shouldCache = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,9 +181,15 @@ func (ctx *JobsQueue) getTextures(uuid string) *mojang.SignedTexturesResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Starts to panic if there's an unexpected error
|
// Starts to panic if there's an unexpected error
|
||||||
func maybeShouldPanic(err error) {
|
func (ctx *JobsQueue) maybeShouldPanic(err error) {
|
||||||
|
ctx.Logger.Debug("Got response error :err", wd.ErrParam(err))
|
||||||
|
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case mojang.ResponseError:
|
case mojang.ResponseError:
|
||||||
|
if _, ok := err.(*mojang.TooManyRequestsError); ok {
|
||||||
|
ctx.Logger.Warning("Got 429 Too Many Requests :err", wd.ErrParam(err))
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
case net.Error:
|
case net.Error:
|
||||||
if err.(net.Error).Timeout() {
|
if err.(net.Error).Timeout() {
|
||||||
|
@ -3,14 +3,17 @@ package queue
|
|||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"github.com/elyby/chrly/api/mojang"
|
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"github.com/stretchr/testify/suite"
|
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/elyby/chrly/api/mojang"
|
||||||
|
|
||||||
|
mocks "github.com/elyby/chrly/tests"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mojangApiMocks struct {
|
type mojangApiMocks struct {
|
||||||
@ -69,6 +72,7 @@ type queueTestSuite struct {
|
|||||||
Queue *JobsQueue
|
Queue *JobsQueue
|
||||||
Storage *mockStorage
|
Storage *mockStorage
|
||||||
MojangApi *mojangApiMocks
|
MojangApi *mojangApiMocks
|
||||||
|
Logger *mocks.WdMock
|
||||||
Iterate func()
|
Iterate func()
|
||||||
|
|
||||||
iterateChan chan bool
|
iterateChan chan bool
|
||||||
@ -81,8 +85,9 @@ func (suite *queueTestSuite) SetupSuite() {
|
|||||||
|
|
||||||
func (suite *queueTestSuite) SetupTest() {
|
func (suite *queueTestSuite) SetupTest() {
|
||||||
suite.Storage = &mockStorage{}
|
suite.Storage = &mockStorage{}
|
||||||
|
suite.Logger = &mocks.WdMock{}
|
||||||
|
|
||||||
suite.Queue = &JobsQueue{Storage: suite.Storage}
|
suite.Queue = &JobsQueue{Storage: suite.Storage, Logger: suite.Logger}
|
||||||
|
|
||||||
suite.iterateChan = make(chan bool)
|
suite.iterateChan = make(chan bool)
|
||||||
forever = func() bool {
|
forever = func() bool {
|
||||||
@ -106,15 +111,27 @@ func (suite *queueTestSuite) TearDownTest() {
|
|||||||
suite.done()
|
suite.done()
|
||||||
suite.MojangApi.AssertExpectations(suite.T())
|
suite.MojangApi.AssertExpectations(suite.T())
|
||||||
suite.Storage.AssertExpectations(suite.T())
|
suite.Storage.AssertExpectations(suite.T())
|
||||||
|
suite.Logger.AssertExpectations(suite.T())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *queueTestSuite) TestReceiveTexturesForOneUsernameWithoutAnyCache() {
|
func (suite *queueTestSuite) TestReceiveTexturesForOneUsernameWithoutAnyCache() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
||||||
|
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.queued", int64(1)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(1)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything)
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.textures.request_time", mock.Anything).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_hit", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
||||||
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
||||||
suite.Storage.On("StoreTextures", expectedResult).Once()
|
suite.Storage.On("StoreTextures", expectedResult).Once()
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{
|
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{
|
||||||
{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"},
|
{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"},
|
||||||
}, nil)
|
}, nil)
|
||||||
@ -132,6 +149,16 @@ func (suite *queueTestSuite) TestReceiveTexturesForFewUsernamesWithoutAnyCache()
|
|||||||
expectedResult1 := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
expectedResult1 := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
||||||
expectedResult2 := &mojang.SignedTexturesResponse{Id: "4566e69fc90748ee8d71d7ba5aa00d20", Name: "Thinkofdeath"}
|
expectedResult2 := &mojang.SignedTexturesResponse{Id: "4566e69fc90748ee8d71d7ba5aa00d20", Name: "Thinkofdeath"}
|
||||||
|
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Twice()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.queued", int64(1)).Twice()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(2)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything)
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.textures.request", int64(1)).Twice()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.textures.request_time", mock.Anything).Twice()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_hit", int64(1)).Twice()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Twice()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("GetUuid", "Thinkofdeath").Once().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "Thinkofdeath").Once().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
||||||
@ -140,6 +167,7 @@ func (suite *queueTestSuite) TestReceiveTexturesForFewUsernamesWithoutAnyCache()
|
|||||||
suite.Storage.On("GetTextures", "4566e69fc90748ee8d71d7ba5aa00d20").Once().Return(nil, &ValueNotFound{})
|
suite.Storage.On("GetTextures", "4566e69fc90748ee8d71d7ba5aa00d20").Once().Return(nil, &ValueNotFound{})
|
||||||
suite.Storage.On("StoreTextures", expectedResult1).Once()
|
suite.Storage.On("StoreTextures", expectedResult1).Once()
|
||||||
suite.Storage.On("StoreTextures", expectedResult2).Once()
|
suite.Storage.On("StoreTextures", expectedResult2).Once()
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb", "Thinkofdeath"}).Once().Return([]*mojang.ProfileInfo{
|
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb", "Thinkofdeath"}).Once().Return([]*mojang.ProfileInfo{
|
||||||
{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"},
|
{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"},
|
||||||
{Id: "4566e69fc90748ee8d71d7ba5aa00d20", Name: "Thinkofdeath"},
|
{Id: "4566e69fc90748ee8d71d7ba5aa00d20", Name: "Thinkofdeath"},
|
||||||
@ -159,10 +187,17 @@ func (suite *queueTestSuite) TestReceiveTexturesForFewUsernamesWithoutAnyCache()
|
|||||||
func (suite *queueTestSuite) TestReceiveTexturesForUsernameWithCachedUuid() {
|
func (suite *queueTestSuite) TestReceiveTexturesForUsernameWithCachedUuid() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
||||||
|
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.cache_hit", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.textures.request_time", mock.Anything).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("0d252b7218b648bfb86c2ae476954d32", nil)
|
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("0d252b7218b648bfb86c2ae476954d32", nil)
|
||||||
// Storage.StoreUuid shouldn't be called
|
// Storage.StoreUuid shouldn't be called
|
||||||
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
||||||
suite.Storage.On("StoreTextures", expectedResult).Once()
|
suite.Storage.On("StoreTextures", expectedResult).Once()
|
||||||
|
|
||||||
// MojangApi.UsernamesToUuids shouldn't be called
|
// MojangApi.UsernamesToUuids shouldn't be called
|
||||||
suite.MojangApi.On("UuidToTextures", "0d252b7218b648bfb86c2ae476954d32", true).Once().Return(expectedResult, nil)
|
suite.MojangApi.On("UuidToTextures", "0d252b7218b648bfb86c2ae476954d32", true).Once().Return(expectedResult, nil)
|
||||||
|
|
||||||
@ -177,10 +212,16 @@ func (suite *queueTestSuite) TestReceiveTexturesForUsernameWithCachedUuid() {
|
|||||||
func (suite *queueTestSuite) TestReceiveTexturesForUsernameWithFullyCachedResult() {
|
func (suite *queueTestSuite) TestReceiveTexturesForUsernameWithFullyCachedResult() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
||||||
|
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.cache_hit", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.textures.cache_hit", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("0d252b7218b648bfb86c2ae476954d32", nil)
|
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("0d252b7218b648bfb86c2ae476954d32", nil)
|
||||||
// Storage.StoreUuid shouldn't be called
|
// Storage.StoreUuid shouldn't be called
|
||||||
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(expectedResult, nil)
|
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(expectedResult, nil)
|
||||||
// Storage.StoreTextures shouldn't be called
|
// Storage.StoreTextures shouldn't be called
|
||||||
|
|
||||||
// MojangApi.UsernamesToUuids shouldn't be called
|
// MojangApi.UsernamesToUuids shouldn't be called
|
||||||
// MojangApi.UuidToTextures shouldn't be called
|
// MojangApi.UuidToTextures shouldn't be called
|
||||||
|
|
||||||
@ -193,10 +234,14 @@ func (suite *queueTestSuite) TestReceiveTexturesForUsernameWithFullyCachedResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *queueTestSuite) TestReceiveTexturesForUsernameWithCachedUnknownUuid() {
|
func (suite *queueTestSuite) TestReceiveTexturesForUsernameWithCachedUnknownUuid() {
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.cache_hit_nil", int64(1)).Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", nil)
|
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", nil)
|
||||||
// Storage.StoreUuid shouldn't be called
|
// Storage.StoreUuid shouldn't be called
|
||||||
// Storage.GetTextures shouldn't be called
|
// Storage.GetTextures shouldn't be called
|
||||||
// Storage.StoreTextures shouldn't be called
|
// Storage.StoreTextures shouldn't be called
|
||||||
|
|
||||||
// MojangApi.UsernamesToUuids shouldn't be called
|
// MojangApi.UsernamesToUuids shouldn't be called
|
||||||
// MojangApi.UuidToTextures shouldn't be called
|
// MojangApi.UuidToTextures shouldn't be called
|
||||||
|
|
||||||
@ -213,23 +258,50 @@ func (suite *queueTestSuite) TestReceiveTexturesForMoreThan100Usernames() {
|
|||||||
usernames[i] = randStr(8)
|
usernames[i] = randStr(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Times(120)
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.queued", int64(1)).Times(120)
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(100)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(20)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(20)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything).Twice()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_miss", int64(1)).Times(120)
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Times(120)
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", mock.Anything).Times(120).Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", mock.Anything).Times(120).Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", mock.Anything, "").Times(120) // if username is not compared to uuid, then receive ""
|
suite.Storage.On("StoreUuid", mock.Anything, "").Times(120) // if username is not compared to uuid, then receive ""
|
||||||
// Storage.GetTextures and Storage.SetTextures shouldn't be called
|
// Storage.GetTextures and Storage.SetTextures shouldn't be called
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", usernames[0:100]).Once().Return([]*mojang.ProfileInfo{}, nil)
|
suite.MojangApi.On("UsernamesToUuids", usernames[0:100]).Once().Return([]*mojang.ProfileInfo{}, nil)
|
||||||
suite.MojangApi.On("UsernamesToUuids", usernames[100:120]).Once().Return([]*mojang.ProfileInfo{}, nil)
|
suite.MojangApi.On("UsernamesToUuids", usernames[100:120]).Once().Return([]*mojang.ProfileInfo{}, nil)
|
||||||
|
|
||||||
for _, username := range usernames {
|
channels := make([]chan *mojang.SignedTexturesResponse, 120)
|
||||||
suite.Queue.GetTexturesForUsername(username)
|
for i, username := range usernames {
|
||||||
|
channels[i] = suite.Queue.GetTexturesForUsername(username)
|
||||||
}
|
}
|
||||||
|
|
||||||
suite.Iterate()
|
suite.Iterate()
|
||||||
suite.Iterate()
|
suite.Iterate()
|
||||||
|
|
||||||
|
for _, channel := range channels {
|
||||||
|
<-channel
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *queueTestSuite) TestReceiveTexturesForTheSameUsernames() {
|
func (suite *queueTestSuite) TestReceiveTexturesForTheSameUsernames() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
||||||
|
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Twice()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.queued", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.already_in_queue", int64(1)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(1)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything)
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.textures.request_time", mock.Anything).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_hit", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Twice().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "maksimkurb").Twice().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
||||||
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
||||||
@ -251,10 +323,22 @@ func (suite *queueTestSuite) TestReceiveTexturesForTheSameUsernames() {
|
|||||||
func (suite *queueTestSuite) TestReceiveTexturesForUsernameThatAlreadyProcessing() {
|
func (suite *queueTestSuite) TestReceiveTexturesForUsernameThatAlreadyProcessing() {
|
||||||
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
expectedResult := &mojang.SignedTexturesResponse{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"}
|
||||||
|
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Twice()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.queued", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.already_in_queue", int64(1)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(1)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything)
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.textures.request_time", mock.Anything).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_hit", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Twice().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "maksimkurb").Twice().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
||||||
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
||||||
suite.Storage.On("StoreTextures", expectedResult).Once()
|
suite.Storage.On("StoreTextures", expectedResult).Once()
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{
|
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{
|
||||||
{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"},
|
{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"},
|
||||||
}, nil)
|
}, nil)
|
||||||
@ -278,9 +362,18 @@ func (suite *queueTestSuite) TestReceiveTexturesForUsernameThatAlreadyProcessing
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *queueTestSuite) TestDoNothingWhenNoTasks() {
|
func (suite *queueTestSuite) TestDoNothingWhenNoTasks() {
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.request", int64(1)).Once()
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.queued", int64(1)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.iteration_size", int64(1)).Once()
|
||||||
|
suite.Logger.On("UpdateGauge", "mojang_textures.usernames.queue_size", int64(0)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.usernames.round_time", mock.Anything)
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.usernames.uuid_miss", int64(1)).Once()
|
||||||
|
suite.Logger.On("RecordTimer", "mojang_textures.result_time", mock.Anything).Once()
|
||||||
|
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{})
|
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{})
|
||||||
suite.Storage.On("StoreUuid", "maksimkurb", "").Once()
|
suite.Storage.On("StoreUuid", "maksimkurb", "").Once()
|
||||||
// Storage.GetTextures and Storage.StoreTextures shouldn't be called
|
// Storage.GetTextures and Storage.StoreTextures shouldn't be called
|
||||||
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{}, nil)
|
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{}, nil)
|
||||||
|
|
||||||
// Perform first iteration and await it finish
|
// Perform first iteration and await it finish
|
||||||
@ -313,9 +406,17 @@ var expectedErrors = []error{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *queueTestSuite) TestShouldNotPanicWhenExpectedErrorReturnedFromUsernameToUuidRequest() {
|
func (suite *queueTestSuite) TestShouldNotPanicWhenExpectedErrorReturnedFromUsernameToUuidRequest() {
|
||||||
|
suite.Logger.On("IncCounter", mock.Anything, mock.Anything)
|
||||||
|
suite.Logger.On("UpdateGauge", mock.Anything, mock.Anything)
|
||||||
|
suite.Logger.On("RecordTimer", mock.Anything, mock.Anything)
|
||||||
|
suite.Logger.On("Debug", "Got response error :err", mock.Anything).Times(len(expectedErrors))
|
||||||
|
suite.Logger.On("Warning", "Got 429 Too Many Requests :err", mock.Anything).Once()
|
||||||
|
|
||||||
|
suite.Storage.On("GetUuid", "maksimkurb").Return("", &ValueNotFound{})
|
||||||
|
|
||||||
for _, err := range expectedErrors {
|
for _, err := range expectedErrors {
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{})
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return(nil, err)
|
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return(nil, err)
|
||||||
|
|
||||||
resultChan := suite.Queue.GetTexturesForUsername("maksimkurb")
|
resultChan := suite.Queue.GetTexturesForUsername("maksimkurb")
|
||||||
suite.Iterate()
|
suite.Iterate()
|
||||||
suite.Assert().Nil(<-resultChan)
|
suite.Assert().Nil(<-resultChan)
|
||||||
@ -325,15 +426,23 @@ func (suite *queueTestSuite) TestShouldNotPanicWhenExpectedErrorReturnedFromUser
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *queueTestSuite) TestShouldNotPanicWhenExpectedErrorReturnedFromUuidToTexturesRequest() {
|
func (suite *queueTestSuite) TestShouldNotPanicWhenExpectedErrorReturnedFromUuidToTexturesRequest() {
|
||||||
|
suite.Logger.On("IncCounter", mock.Anything, mock.Anything)
|
||||||
|
suite.Logger.On("UpdateGauge", mock.Anything, mock.Anything)
|
||||||
|
suite.Logger.On("RecordTimer", mock.Anything, mock.Anything)
|
||||||
|
suite.Logger.On("Debug", "Got response error :err", mock.Anything).Times(len(expectedErrors))
|
||||||
|
suite.Logger.On("Warning", "Got 429 Too Many Requests :err", mock.Anything).Once()
|
||||||
|
|
||||||
|
suite.Storage.On("GetUuid", "maksimkurb").Return("", &ValueNotFound{})
|
||||||
|
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32")
|
||||||
|
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Return(nil, &ValueNotFound{})
|
||||||
|
// Storage.StoreTextures shouldn't be called
|
||||||
|
|
||||||
for _, err := range expectedErrors {
|
for _, err := range expectedErrors {
|
||||||
suite.Storage.On("GetUuid", "maksimkurb").Once().Return("", &ValueNotFound{})
|
|
||||||
suite.Storage.On("StoreUuid", "maksimkurb", "0d252b7218b648bfb86c2ae476954d32").Once()
|
|
||||||
suite.Storage.On("GetTextures", "0d252b7218b648bfb86c2ae476954d32").Once().Return(nil, &ValueNotFound{})
|
|
||||||
// Storage.StoreTextures shouldn't be called
|
|
||||||
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{
|
suite.MojangApi.On("UsernamesToUuids", []string{"maksimkurb"}).Once().Return([]*mojang.ProfileInfo{
|
||||||
{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"},
|
{Id: "0d252b7218b648bfb86c2ae476954d32", Name: "maksimkurb"},
|
||||||
}, nil)
|
}, nil)
|
||||||
suite.MojangApi.On("UuidToTextures", "0d252b7218b648bfb86c2ae476954d32", true).Once().Return(nil, err)
|
suite.MojangApi.On("UuidToTextures", "0d252b7218b648bfb86c2ae476954d32", true).Once().Return(nil, err)
|
||||||
|
|
||||||
resultChan := suite.Queue.GetTexturesForUsername("maksimkurb")
|
resultChan := suite.Queue.GetTexturesForUsername("maksimkurb")
|
||||||
suite.Iterate()
|
suite.Iterate()
|
||||||
suite.Assert().Nil(<-resultChan)
|
suite.Assert().Nil(<-resultChan)
|
||||||
@ -343,6 +452,8 @@ func (suite *queueTestSuite) TestShouldNotPanicWhenExpectedErrorReturnedFromUuid
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *queueTestSuite) TestReceiveTexturesForNotAllowedMojangUsername() {
|
func (suite *queueTestSuite) TestReceiveTexturesForNotAllowedMojangUsername() {
|
||||||
|
suite.Logger.On("IncCounter", "mojang_textures.invalid_username", int64(1)).Once()
|
||||||
|
|
||||||
resultChan := suite.Queue.GetTexturesForUsername("Not allowed")
|
resultChan := suite.Queue.GetTexturesForUsername("Not allowed")
|
||||||
suite.Assert().Nil(<-resultChan)
|
suite.Assert().Nil(<-resultChan)
|
||||||
}
|
}
|
||||||
|
61
tests/wd_mock.go
Normal file
61
tests/wd_mock.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mono83/slf"
|
||||||
|
"github.com/mono83/slf/wd"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WdMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) Trace(message string, p ...slf.Param) {
|
||||||
|
m.Called(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) Debug(message string, p ...slf.Param) {
|
||||||
|
m.Called(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) Info(message string, p ...slf.Param) {
|
||||||
|
m.Called(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) Warning(message string, p ...slf.Param) {
|
||||||
|
m.Called(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) Error(message string, p ...slf.Param) {
|
||||||
|
m.Called(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) Alert(message string, p ...slf.Param) {
|
||||||
|
m.Called(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) Emergency(message string, p ...slf.Param) {
|
||||||
|
m.Called(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) IncCounter(name string, value int64, p ...slf.Param) {
|
||||||
|
m.Called(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) UpdateGauge(name string, value int64, p ...slf.Param) {
|
||||||
|
m.Called(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) RecordTimer(name string, d time.Duration, p ...slf.Param) {
|
||||||
|
m.Called(name, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) Timer(name string, p ...slf.Param) slf.Timer {
|
||||||
|
return slf.NewTimer(name, p, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WdMock) WithParams(p ...slf.Param) wd.Watchdog {
|
||||||
|
panic("this method shouldn't be used")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user