mirror of
				https://github.com/elyby/chrly.git
				synced 2025-05-31 14:11:51 +05:30 
			
		
		
		
	Resolves #26. Rework UUIDs storage interface to simplify results handling
This commit is contained in:
		@@ -14,7 +14,6 @@ import (
 | 
				
			|||||||
	"github.com/mediocregopher/radix.v2/util"
 | 
						"github.com/mediocregopher/radix.v2/util"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/elyby/chrly/model"
 | 
						"github.com/elyby/chrly/model"
 | 
				
			||||||
	"github.com/elyby/chrly/mojangtextures"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var now = time.Now
 | 
					var now = time.Now
 | 
				
			||||||
@@ -186,20 +185,21 @@ func removeByUsername(username string, conn util.Cmder) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (db *Redis) GetUuid(username string) (string, error) {
 | 
					func (db *Redis) GetUuid(username string) (string, bool, error) {
 | 
				
			||||||
	conn, err := db.pool.Get()
 | 
						conn, err := db.pool.Get()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", false, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer db.pool.Put(conn)
 | 
						defer db.pool.Put(conn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return findMojangUuidByUsername(username, conn)
 | 
						return findMojangUuidByUsername(username, conn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func findMojangUuidByUsername(username string, conn util.Cmder) (string, error) {
 | 
					func findMojangUuidByUsername(username string, conn util.Cmder) (string, bool, error) {
 | 
				
			||||||
	response := conn.Cmd("HGET", mojangUsernameToUuidKey, strings.ToLower(username))
 | 
						key := strings.ToLower(username)
 | 
				
			||||||
 | 
						response := conn.Cmd("HGET", mojangUsernameToUuidKey, key)
 | 
				
			||||||
	if response.IsType(redis.Nil) {
 | 
						if response.IsType(redis.Nil) {
 | 
				
			||||||
		return "", &mojangtextures.ValueNotFound{}
 | 
							return "", false, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data, _ := response.Str()
 | 
						data, _ := response.Str()
 | 
				
			||||||
@@ -207,10 +207,11 @@ func findMojangUuidByUsername(username string, conn util.Cmder) (string, error)
 | 
				
			|||||||
	timestamp, _ := strconv.ParseInt(parts[1], 10, 64)
 | 
						timestamp, _ := strconv.ParseInt(parts[1], 10, 64)
 | 
				
			||||||
	storedAt := time.Unix(timestamp, 0)
 | 
						storedAt := time.Unix(timestamp, 0)
 | 
				
			||||||
	if storedAt.Add(time.Hour * 24 * 30).Before(now()) {
 | 
						if storedAt.Add(time.Hour * 24 * 30).Before(now()) {
 | 
				
			||||||
		return "", &mojangtextures.ValueNotFound{}
 | 
							conn.Cmd("HDEL", mojangUsernameToUuidKey, key)
 | 
				
			||||||
 | 
							return "", false, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return parts[0], nil
 | 
						return parts[0], true, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (db *Redis) StoreUuid(username string, uuid string) error {
 | 
					func (db *Redis) StoreUuid(username string, uuid string) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,6 @@ import (
 | 
				
			|||||||
	"github.com/stretchr/testify/suite"
 | 
						"github.com/stretchr/testify/suite"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/elyby/chrly/model"
 | 
						"github.com/elyby/chrly/model"
 | 
				
			||||||
	"github.com/elyby/chrly/mojangtextures"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const redisAddr = "localhost:6379"
 | 
					const redisAddr = "localhost:6379"
 | 
				
			||||||
@@ -317,15 +316,30 @@ func (suite *redisTestSuite) TestGetUuid() {
 | 
				
			|||||||
			fmt.Sprintf("%s:%d", "d3ca513eb3e14946b58047f2bd3530fd", time.Now().Unix()),
 | 
								fmt.Sprintf("%s:%d", "d3ca513eb3e14946b58047f2bd3530fd", time.Now().Unix()),
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uuid, err := suite.Redis.GetUuid("Mock")
 | 
							uuid, found, err := suite.Redis.GetUuid("Mock")
 | 
				
			||||||
		suite.Require().Nil(err)
 | 
							suite.Require().Nil(err)
 | 
				
			||||||
 | 
							suite.Require().True(found)
 | 
				
			||||||
		suite.Require().Equal("d3ca513eb3e14946b58047f2bd3530fd", uuid)
 | 
							suite.Require().Equal("d3ca513eb3e14946b58047f2bd3530fd", uuid)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.RunSubTest("exists record with empty uuid value", func() {
 | 
				
			||||||
 | 
							suite.cmd("HSET",
 | 
				
			||||||
 | 
								"hash:mojang-username-to-uuid",
 | 
				
			||||||
 | 
								"mock",
 | 
				
			||||||
 | 
								fmt.Sprintf(":%d", time.Now().Unix()),
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uuid, found, err := suite.Redis.GetUuid("Mock")
 | 
				
			||||||
 | 
							suite.Require().Nil(err)
 | 
				
			||||||
 | 
							suite.Require().True(found)
 | 
				
			||||||
 | 
							suite.Require().Empty("", uuid)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.RunSubTest("not exists record", func() {
 | 
						suite.RunSubTest("not exists record", func() {
 | 
				
			||||||
		uuid, err := suite.Redis.GetUuid("Mock")
 | 
							uuid, found, err := suite.Redis.GetUuid("Mock")
 | 
				
			||||||
 | 
							suite.Require().Nil(err)
 | 
				
			||||||
 | 
							suite.Require().False(found)
 | 
				
			||||||
		suite.Require().Empty(uuid)
 | 
							suite.Require().Empty(uuid)
 | 
				
			||||||
		suite.Require().IsType(new(mojangtextures.ValueNotFound), err)
 | 
					 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.RunSubTest("exists, but expired record", func() {
 | 
						suite.RunSubTest("exists, but expired record", func() {
 | 
				
			||||||
@@ -335,9 +349,10 @@ func (suite *redisTestSuite) TestGetUuid() {
 | 
				
			|||||||
			fmt.Sprintf("%s:%d", "d3ca513eb3e14946b58047f2bd3530fd", time.Now().Add(-1*time.Hour*24*31).Unix()),
 | 
								fmt.Sprintf("%s:%d", "d3ca513eb3e14946b58047f2bd3530fd", time.Now().Add(-1*time.Hour*24*31).Unix()),
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uuid, err := suite.Redis.GetUuid("Mock")
 | 
							uuid, found, err := suite.Redis.GetUuid("Mock")
 | 
				
			||||||
		suite.Require().Empty(uuid)
 | 
							suite.Require().Empty(uuid)
 | 
				
			||||||
		suite.Require().IsType(new(mojangtextures.ValueNotFound), err)
 | 
							suite.Require().False(found)
 | 
				
			||||||
 | 
							suite.Require().Nil(err)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								di/db.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								di/db.go
									
									
									
									
									
								
							@@ -22,7 +22,7 @@ import (
 | 
				
			|||||||
var db = di.Options(
 | 
					var db = di.Options(
 | 
				
			||||||
	di.Provide(newRedis,
 | 
						di.Provide(newRedis,
 | 
				
			||||||
		di.As(new(http.SkinsRepository)),
 | 
							di.As(new(http.SkinsRepository)),
 | 
				
			||||||
		di.As(new(mojangtextures.UuidsStorage)),
 | 
							di.As(new(mojangtextures.UUIDsStorage)),
 | 
				
			||||||
	),
 | 
						),
 | 
				
			||||||
	di.Provide(newFSFactory,
 | 
						di.Provide(newFSFactory,
 | 
				
			||||||
		di.As(new(http.CapesRepository)),
 | 
							di.As(new(http.CapesRepository)),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -210,11 +210,11 @@ func newMojangSignedTexturesProvider(emitter mojangtextures.Emitter) mojangtextu
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newMojangTexturesStorageFactory(
 | 
					func newMojangTexturesStorageFactory(
 | 
				
			||||||
	uuidsStorage mojangtextures.UuidsStorage,
 | 
						uuidsStorage mojangtextures.UUIDsStorage,
 | 
				
			||||||
	texturesStorage mojangtextures.TexturesStorage,
 | 
						texturesStorage mojangtextures.TexturesStorage,
 | 
				
			||||||
) mojangtextures.Storage {
 | 
					) mojangtextures.Storage {
 | 
				
			||||||
	return &mojangtextures.SeparatedStorage{
 | 
						return &mojangtextures.SeparatedStorage{
 | 
				
			||||||
		UuidsStorage:    uuidsStorage,
 | 
							UUIDsStorage:    uuidsStorage,
 | 
				
			||||||
		TexturesStorage: texturesStorage,
 | 
							TexturesStorage: texturesStorage,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,8 +34,8 @@ func (s *StatsReporter) ConfigureWithDispatcher(d Subscriber) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Mojang signed textures source events
 | 
						// Mojang signed textures source events
 | 
				
			||||||
	d.Subscribe("mojang_textures:call", s.incCounterHandler("mojang_textures.request"))
 | 
						d.Subscribe("mojang_textures:call", s.incCounterHandler("mojang_textures.request"))
 | 
				
			||||||
	d.Subscribe("mojang_textures:usernames:after_cache", func(username string, uuid string, err error) {
 | 
						d.Subscribe("mojang_textures:usernames:after_cache", func(username string, uuid string, found bool, err error) {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil || !found {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -213,13 +213,19 @@ var statsReporterTestCases = []*StatsReporterTestCase{
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Events: [][]interface{}{
 | 
							Events: [][]interface{}{
 | 
				
			||||||
			{"mojang_textures:usernames:after_cache", "username", "", errors.New("error")},
 | 
								{"mojang_textures:usernames:after_cache", "username", "", false, errors.New("error")},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		ExpectedCalls: [][]interface{}{},
 | 
							ExpectedCalls: [][]interface{}{},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Events: [][]interface{}{
 | 
							Events: [][]interface{}{
 | 
				
			||||||
			{"mojang_textures:usernames:after_cache", "username", "", nil},
 | 
								{"mojang_textures:usernames:after_cache", "username", "", false, nil},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							ExpectedCalls: [][]interface{}{},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Events: [][]interface{}{
 | 
				
			||||||
 | 
								{"mojang_textures:usernames:after_cache", "username", "", true, nil},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		ExpectedCalls: [][]interface{}{
 | 
							ExpectedCalls: [][]interface{}{
 | 
				
			||||||
			{"IncCounter", "mojang_textures:usernames:cache_hit_nil", int64(1)},
 | 
								{"IncCounter", "mojang_textures:usernames:cache_hit_nil", int64(1)},
 | 
				
			||||||
@@ -227,7 +233,7 @@ var statsReporterTestCases = []*StatsReporterTestCase{
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Events: [][]interface{}{
 | 
							Events: [][]interface{}{
 | 
				
			||||||
			{"mojang_textures:usernames:after_cache", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil},
 | 
								{"mojang_textures:usernames:after_cache", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true, nil},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		ExpectedCalls: [][]interface{}{
 | 
							ExpectedCalls: [][]interface{}{
 | 
				
			||||||
			{"IncCounter", "mojang_textures:usernames:cache_hit", int64(1)},
 | 
								{"IncCounter", "mojang_textures:usernames:cache_hit", int64(1)},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,7 +66,7 @@ func (s *InMemoryTexturesStorage) GetTextures(uuid string) (*mojang.SignedTextur
 | 
				
			|||||||
	item, exists := s.data[uuid]
 | 
						item, exists := s.data[uuid]
 | 
				
			||||||
	validRange := s.getMinimalNotExpiredTimestamp()
 | 
						validRange := s.getMinimalNotExpiredTimestamp()
 | 
				
			||||||
	if !exists || validRange > item.timestamp {
 | 
						if !exists || validRange > item.timestamp {
 | 
				
			||||||
		return nil, &ValueNotFound{}
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return item.textures, nil
 | 
						return item.textures, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
package mojangtextures
 | 
					package mojangtextures
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/elyby/chrly/api/mojang"
 | 
						assert "github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testify "github.com/stretchr/testify/assert"
 | 
						"github.com/elyby/chrly/api/mojang"
 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var texturesWithSkin = &mojang.SignedTexturesResponse{
 | 
					var texturesWithSkin = &mojang.SignedTexturesResponse{
 | 
				
			||||||
@@ -45,30 +45,24 @@ var texturesWithoutSkin = &mojang.SignedTexturesResponse{
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestInMemoryTexturesStorage_GetTextures(t *testing.T) {
 | 
					func TestInMemoryTexturesStorage_GetTextures(t *testing.T) {
 | 
				
			||||||
	t.Run("get error when uuid is not exists", func(t *testing.T) {
 | 
						t.Run("should return nil, nil when textures are unavailable", func(t *testing.T) {
 | 
				
			||||||
		assert := testify.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		storage := NewInMemoryTexturesStorage()
 | 
							storage := NewInMemoryTexturesStorage()
 | 
				
			||||||
		result, err := storage.GetTextures("b5d58475007d4f9e9ddd1403e2497579")
 | 
							result, err := storage.GetTextures("b5d58475007d4f9e9ddd1403e2497579")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Nil(result)
 | 
							assert.Nil(t, result)
 | 
				
			||||||
		assert.Error(err, "value not found in the storage")
 | 
							assert.Nil(t, err)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("get textures object, when uuid is stored in the storage", func(t *testing.T) {
 | 
						t.Run("get textures object, when uuid is stored in the storage", func(t *testing.T) {
 | 
				
			||||||
		assert := testify.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		storage := NewInMemoryTexturesStorage()
 | 
							storage := NewInMemoryTexturesStorage()
 | 
				
			||||||
		storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithSkin)
 | 
							storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithSkin)
 | 
				
			||||||
		result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
							result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Equal(texturesWithSkin, result)
 | 
							assert.Equal(t, texturesWithSkin, result)
 | 
				
			||||||
		assert.Nil(err)
 | 
							assert.Nil(t, err)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("get error when uuid is exists, but textures are expired", func(t *testing.T) {
 | 
						t.Run("should return nil, nil when textures are exists, but cache duration is expired", func(t *testing.T) {
 | 
				
			||||||
		assert := testify.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		storage := NewInMemoryTexturesStorage()
 | 
							storage := NewInMemoryTexturesStorage()
 | 
				
			||||||
		storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithSkin)
 | 
							storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithSkin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,8 +72,8 @@ func TestInMemoryTexturesStorage_GetTextures(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
							result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Nil(result)
 | 
							assert.Nil(t, result)
 | 
				
			||||||
		assert.Error(err, "value not found in the storage")
 | 
							assert.Nil(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		now = time.Now
 | 
							now = time.Now
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -87,50 +81,42 @@ func TestInMemoryTexturesStorage_GetTextures(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestInMemoryTexturesStorage_StoreTextures(t *testing.T) {
 | 
					func TestInMemoryTexturesStorage_StoreTextures(t *testing.T) {
 | 
				
			||||||
	t.Run("store textures for previously not existed uuid", func(t *testing.T) {
 | 
						t.Run("store textures for previously not existed uuid", func(t *testing.T) {
 | 
				
			||||||
		assert := testify.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		storage := NewInMemoryTexturesStorage()
 | 
							storage := NewInMemoryTexturesStorage()
 | 
				
			||||||
		storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithSkin)
 | 
							storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithSkin)
 | 
				
			||||||
		result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
							result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Equal(texturesWithSkin, result)
 | 
							assert.Equal(t, texturesWithSkin, result)
 | 
				
			||||||
		assert.Nil(err)
 | 
							assert.Nil(t, err)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("override already existed textures for uuid", func(t *testing.T) {
 | 
						t.Run("override already existed textures for uuid", func(t *testing.T) {
 | 
				
			||||||
		assert := testify.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		storage := NewInMemoryTexturesStorage()
 | 
							storage := NewInMemoryTexturesStorage()
 | 
				
			||||||
		storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithoutSkin)
 | 
							storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithoutSkin)
 | 
				
			||||||
		storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithSkin)
 | 
							storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", texturesWithSkin)
 | 
				
			||||||
		result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
							result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.NotEqual(texturesWithoutSkin, result)
 | 
							assert.NotEqual(t, texturesWithoutSkin, result)
 | 
				
			||||||
		assert.Equal(texturesWithSkin, result)
 | 
							assert.Equal(t, texturesWithSkin, result)
 | 
				
			||||||
		assert.Nil(err)
 | 
							assert.Nil(t, err)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("store nil textures", func(t *testing.T) {
 | 
						t.Run("store nil textures", func(t *testing.T) {
 | 
				
			||||||
		assert := testify.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		storage := NewInMemoryTexturesStorage()
 | 
							storage := NewInMemoryTexturesStorage()
 | 
				
			||||||
		storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", nil)
 | 
							storage.StoreTextures("dead24f9a4fa4877b7b04c8c6c72bb46", nil)
 | 
				
			||||||
		result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
							result, err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Nil(result)
 | 
							assert.Nil(t, result)
 | 
				
			||||||
		assert.Nil(err)
 | 
							assert.Nil(t, err)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("should panic if textures prop is not decoded", func(t *testing.T) {
 | 
						t.Run("should panic if textures prop is not decoded", func(t *testing.T) {
 | 
				
			||||||
		assert := testify.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		toStore := &mojang.SignedTexturesResponse{
 | 
							toStore := &mojang.SignedTexturesResponse{
 | 
				
			||||||
			Id:    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
 | 
								Id:    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
 | 
				
			||||||
			Name:  "mock",
 | 
								Name:  "mock",
 | 
				
			||||||
			Props: []*mojang.Property{},
 | 
								Props: []*mojang.Property{},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.PanicsWithValue("unable to decode textures", func() {
 | 
							assert.PanicsWithValue(t, "unable to decode textures", func() {
 | 
				
			||||||
			storage := NewInMemoryTexturesStorage()
 | 
								storage := NewInMemoryTexturesStorage()
 | 
				
			||||||
			storage.StoreTextures("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", toStore)
 | 
								storage.StoreTextures("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", toStore)
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
@@ -138,8 +124,6 @@ func TestInMemoryTexturesStorage_StoreTextures(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestInMemoryTexturesStorage_GarbageCollection(t *testing.T) {
 | 
					func TestInMemoryTexturesStorage_GarbageCollection(t *testing.T) {
 | 
				
			||||||
	assert := testify.New(t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	storage := NewInMemoryTexturesStorage()
 | 
						storage := NewInMemoryTexturesStorage()
 | 
				
			||||||
	storage.GCPeriod = 10 * time.Millisecond
 | 
						storage.GCPeriod = 10 * time.Millisecond
 | 
				
			||||||
	storage.Duration = 10 * time.Millisecond
 | 
						storage.Duration = 10 * time.Millisecond
 | 
				
			||||||
@@ -179,22 +163,25 @@ func TestInMemoryTexturesStorage_GarbageCollection(t *testing.T) {
 | 
				
			|||||||
	storage.StoreTextures("b5d58475007d4f9e9ddd1403e2497579", textures2)
 | 
						storage.StoreTextures("b5d58475007d4f9e9ddd1403e2497579", textures2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	storage.Start()
 | 
						storage.Start()
 | 
				
			||||||
 | 
						defer storage.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	time.Sleep(storage.GCPeriod + time.Millisecond) // Let it start first iteration
 | 
						time.Sleep(storage.GCPeriod + time.Millisecond) // Let it start first iteration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, textures1Err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
						texturesFromStorage1, textures1Err := storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
				
			||||||
	_, textures2Err := storage.GetTextures("b5d58475007d4f9e9ddd1403e2497579")
 | 
						texturesFromStorage2, textures2Err := storage.GetTextures("b5d58475007d4f9e9ddd1403e2497579")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Nil(textures1Err)
 | 
						assert.NotNil(t, texturesFromStorage1)
 | 
				
			||||||
	assert.Error(textures2Err)
 | 
						assert.Nil(t, textures1Err)
 | 
				
			||||||
 | 
						assert.Nil(t, texturesFromStorage2)
 | 
				
			||||||
 | 
						assert.Nil(t, textures2Err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	time.Sleep(storage.GCPeriod + time.Millisecond) // Let another iteration happen
 | 
						time.Sleep(storage.GCPeriod + time.Millisecond) // Let another iteration happen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, textures1Err = storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
						texturesFromStorage1, textures1Err = storage.GetTextures("dead24f9a4fa4877b7b04c8c6c72bb46")
 | 
				
			||||||
	_, textures2Err = storage.GetTextures("b5d58475007d4f9e9ddd1403e2497579")
 | 
						texturesFromStorage2, textures2Err = storage.GetTextures("b5d58475007d4f9e9ddd1403e2497579")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Error(textures1Err)
 | 
						assert.Nil(t, texturesFromStorage1)
 | 
				
			||||||
	assert.Error(textures2Err)
 | 
						assert.Nil(t, textures1Err)
 | 
				
			||||||
 | 
						assert.Nil(t, texturesFromStorage2)
 | 
				
			||||||
	storage.Stop()
 | 
						assert.Nil(t, textures2Err)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,14 +98,18 @@ func (ctx *Provider) GetForUsername(username string) (*mojang.SignedTexturesResp
 | 
				
			|||||||
	username = strings.ToLower(username)
 | 
						username = strings.ToLower(username)
 | 
				
			||||||
	ctx.Emit("mojang_textures:call", username)
 | 
						ctx.Emit("mojang_textures:call", username)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uuid, err := ctx.getUuidFromCache(username)
 | 
						uuid, found, err := ctx.getUuidFromCache(username)
 | 
				
			||||||
	if err == nil && uuid == "" {
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if found && uuid == "" {
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if uuid != "" {
 | 
						if uuid != "" {
 | 
				
			||||||
		textures, err := ctx.getTexturesFromCache(uuid)
 | 
							textures, err := ctx.getTexturesFromCache(uuid)
 | 
				
			||||||
		if err == nil {
 | 
							if err == nil && textures != nil {
 | 
				
			||||||
			return textures, nil
 | 
								return textures, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -162,12 +166,12 @@ func (ctx *Provider) getResult(username string, uuid string) *broadcastResult {
 | 
				
			|||||||
	return &broadcastResult{textures, nil}
 | 
						return &broadcastResult{textures, nil}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ctx *Provider) getUuidFromCache(username string) (string, error) {
 | 
					func (ctx *Provider) getUuidFromCache(username string) (string, bool, error) {
 | 
				
			||||||
	ctx.Emit("mojang_textures:usernames:before_cache", username)
 | 
						ctx.Emit("mojang_textures:usernames:before_cache", username)
 | 
				
			||||||
	uuid, err := ctx.Storage.GetUuid(username)
 | 
						uuid, found, err := ctx.Storage.GetUuid(username)
 | 
				
			||||||
	ctx.Emit("mojang_textures:usernames:after_cache", username, uuid, err)
 | 
						ctx.Emit("mojang_textures:usernames:after_cache", username, uuid, found, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return uuid, err
 | 
						return uuid, found, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ctx *Provider) getTexturesFromCache(uuid string) (*mojang.SignedTexturesResponse, error) {
 | 
					func (ctx *Provider) getTexturesFromCache(uuid string) (*mojang.SignedTexturesResponse, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -122,9 +122,9 @@ type mockStorage struct {
 | 
				
			|||||||
	mock.Mock
 | 
						mock.Mock
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *mockStorage) GetUuid(username string) (string, error) {
 | 
					func (m *mockStorage) GetUuid(username string) (string, bool, error) {
 | 
				
			||||||
	args := m.Called(username)
 | 
						args := m.Called(username)
 | 
				
			||||||
	return args.String(0), args.Error(1)
 | 
						return args.String(0), args.Bool(1), args.Error(2)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *mockStorage) StoreUuid(username string, uuid string) error {
 | 
					func (m *mockStorage) StoreUuid(username string, uuid string) error {
 | 
				
			||||||
@@ -186,7 +186,7 @@ func (suite *providerTestSuite) TestGetForUsernameWithoutAnyCache() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", &ValueNotFound{}).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", false, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, nil).Once()
 | 
				
			||||||
@@ -194,7 +194,7 @@ func (suite *providerTestSuite) TestGetForUsernameWithoutAnyCache() {
 | 
				
			|||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
 | 
						suite.Storage.On("GetUuid", "username").Once().Return("", false, nil)
 | 
				
			||||||
	suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
 | 
						suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
 | 
				
			||||||
	suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult).Once()
 | 
						suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -213,16 +213,16 @@ func (suite *providerTestSuite) TestGetForUsernameWithCachedUuid() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:before_cache", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:before_cache", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:after_cache", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedCachedTextures, &ValueNotFound{}).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:after_cache", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedCachedTextures, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:before_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:before_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Once().Return("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil)
 | 
						suite.Storage.On("GetUuid", "username").Once().Return("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true, nil)
 | 
				
			||||||
	suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, &ValueNotFound{})
 | 
						suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, nil)
 | 
				
			||||||
	suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult).Once()
 | 
						suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.TexturesProvider.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Return(expectedResult, nil)
 | 
						suite.TexturesProvider.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Return(expectedResult, nil)
 | 
				
			||||||
@@ -238,11 +238,11 @@ func (suite *providerTestSuite) TestGetForUsernameWithFullyCachedResult() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:before_cache", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:before_cache", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:after_cache", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:after_cache", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Once().Return("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nil)
 | 
						suite.Storage.On("GetUuid", "username").Once().Return("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true, nil)
 | 
				
			||||||
	suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(expectedResult, nil)
 | 
						suite.Storage.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(expectedResult, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result, err := suite.Provider.GetForUsername("username")
 | 
						result, err := suite.Provider.GetForUsername("username")
 | 
				
			||||||
@@ -254,9 +254,9 @@ func (suite *providerTestSuite) TestGetForUsernameWithFullyCachedResult() {
 | 
				
			|||||||
func (suite *providerTestSuite) TestGetForUsernameWithCachedUnknownUuid() {
 | 
					func (suite *providerTestSuite) TestGetForUsernameWithCachedUnknownUuid() {
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", true, nil).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Once().Return("", nil)
 | 
						suite.Storage.On("GetUuid", "username").Once().Return("", true, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result, err := suite.Provider.GetForUsername("username")
 | 
						result, err := suite.Provider.GetForUsername("username")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -270,13 +270,13 @@ func (suite *providerTestSuite) TestGetForUsernameWhichHasNoMojangAccount() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", &ValueNotFound{}).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", false, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
 | 
						suite.Storage.On("GetUuid", "username").Once().Return("", false, nil)
 | 
				
			||||||
	suite.Storage.On("StoreUuid", "username", "").Once().Return(nil)
 | 
						suite.Storage.On("StoreUuid", "username", "").Once().Return(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.UuidsProvider.On("GetUuid", "username").Once().Return(nil, nil)
 | 
						suite.UuidsProvider.On("GetUuid", "username").Once().Return(nil, nil)
 | 
				
			||||||
@@ -293,7 +293,7 @@ func (suite *providerTestSuite) TestGetForUsernameWhichHasMojangAccountButHasNoM
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", &ValueNotFound{}).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", false, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, nil).Once()
 | 
				
			||||||
@@ -301,7 +301,7 @@ func (suite *providerTestSuite) TestGetForUsernameWhichHasMojangAccountButHasNoM
 | 
				
			|||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
 | 
						suite.Storage.On("GetUuid", "username").Once().Return("", false, nil)
 | 
				
			||||||
	suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
 | 
						suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
 | 
				
			||||||
	suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult).Once()
 | 
						suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -320,7 +320,7 @@ func (suite *providerTestSuite) TestGetForTheSameUsernames() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Twice()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Twice()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Twice()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Twice()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", &ValueNotFound{}).Twice()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", false, nil).Twice()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:already_processing", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:already_processing", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
				
			||||||
@@ -329,7 +329,7 @@ func (suite *providerTestSuite) TestGetForTheSameUsernames() {
 | 
				
			|||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, nil).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Twice().Return("", &ValueNotFound{})
 | 
						suite.Storage.On("GetUuid", "username").Twice().Return("", false, nil)
 | 
				
			||||||
	suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
 | 
						suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil)
 | 
				
			||||||
	suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult).Once()
 | 
						suite.Storage.On("StoreTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -359,6 +359,21 @@ func (suite *providerTestSuite) TestGetForNotAllowedMojangUsername() {
 | 
				
			|||||||
	suite.Assert().Nil(result)
 | 
						suite.Assert().Nil(result)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *providerTestSuite) TestGetErrorFromUUIDsStorage() {
 | 
				
			||||||
 | 
						expectedErr := errors.New("mock error")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", false, expectedErr).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Storage.On("GetUuid", "username").Once().Return("", false, expectedErr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result, err := suite.Provider.GetForUsername("username")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Assert().Nil(result)
 | 
				
			||||||
 | 
						suite.Assert().Equal(expectedErr, err)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (suite *providerTestSuite) TestGetErrorFromUuidsProvider() {
 | 
					func (suite *providerTestSuite) TestGetErrorFromUuidsProvider() {
 | 
				
			||||||
	var expectedProfile *mojang.ProfileInfo
 | 
						var expectedProfile *mojang.ProfileInfo
 | 
				
			||||||
	var expectedResult *mojang.SignedTexturesResponse
 | 
						var expectedResult *mojang.SignedTexturesResponse
 | 
				
			||||||
@@ -366,13 +381,13 @@ func (suite *providerTestSuite) TestGetErrorFromUuidsProvider() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", &ValueNotFound{}).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", false, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, err).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, err).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, err).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, err).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Once().Return("", &ValueNotFound{})
 | 
						suite.Storage.On("GetUuid", "username").Once().Return("", false, nil)
 | 
				
			||||||
	suite.UuidsProvider.On("GetUuid", "username").Once().Return(nil, err)
 | 
						suite.UuidsProvider.On("GetUuid", "username").Once().Return(nil, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result, resErr := suite.Provider.GetForUsername("username")
 | 
						result, resErr := suite.Provider.GetForUsername("username")
 | 
				
			||||||
@@ -387,7 +402,7 @@ func (suite *providerTestSuite) TestGetErrorFromTexturesProvider() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_cache", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", &ValueNotFound{}).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_cache", "username", "", false, nil).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:before_result", "username", "").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:before_call", "username").Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, nil).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:usernames:after_call", "username", expectedProfile, nil).Once()
 | 
				
			||||||
@@ -395,7 +410,7 @@ func (suite *providerTestSuite) TestGetErrorFromTexturesProvider() {
 | 
				
			|||||||
	suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, err).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:textures:after_call", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", expectedResult, err).Once()
 | 
				
			||||||
	suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, err).Once()
 | 
						suite.Emitter.On("Emit", "mojang_textures:after_result", "username", expectedResult, err).Once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	suite.Storage.On("GetUuid", "username").Return("", &ValueNotFound{})
 | 
						suite.Storage.On("GetUuid", "username").Return("", false, nil)
 | 
				
			||||||
	suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Return(nil)
 | 
						suite.Storage.On("StoreUuid", "username", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Return(nil)
 | 
				
			||||||
	suite.UuidsProvider.On("GetUuid", "username").Once().Return(expectedProfile, nil)
 | 
						suite.UuidsProvider.On("GetUuid", "username").Once().Return(expectedProfile, nil)
 | 
				
			||||||
	suite.TexturesProvider.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, err)
 | 
						suite.TexturesProvider.On("GetTextures", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").Once().Return(nil, err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,12 +4,13 @@ import (
 | 
				
			|||||||
	"github.com/elyby/chrly/api/mojang"
 | 
						"github.com/elyby/chrly/api/mojang"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UuidsStorage is a key-value storage of Mojang usernames pairs to its UUIDs,
 | 
					// UUIDsStorage is a key-value storage of Mojang usernames pairs to its UUIDs,
 | 
				
			||||||
// used to reduce the load on the account information queue
 | 
					// used to reduce the load on the account information queue
 | 
				
			||||||
type UuidsStorage interface {
 | 
					type UUIDsStorage interface {
 | 
				
			||||||
	// Since only primitive types are used in this method, you should return a special error ValueNotFound
 | 
						// The second argument indicates whether a record was found in the storage,
 | 
				
			||||||
	// to return the information that no error has occurred and username does not have uuid
 | 
						// since depending on it, the empty value must be interpreted as "no cached record"
 | 
				
			||||||
	GetUuid(username string) (string, error)
 | 
						// or "value cached and has an empty value"
 | 
				
			||||||
 | 
						GetUuid(username string) (uuid string, found bool, err error)
 | 
				
			||||||
	// An empty uuid value can be passed if the corresponding account has not been found
 | 
						// An empty uuid value can be passed if the corresponding account has not been found
 | 
				
			||||||
	StoreUuid(username string, uuid string) error
 | 
						StoreUuid(username string, uuid string) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -24,23 +25,23 @@ type TexturesStorage interface {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Storage interface {
 | 
					type Storage interface {
 | 
				
			||||||
	UuidsStorage
 | 
						UUIDsStorage
 | 
				
			||||||
	TexturesStorage
 | 
						TexturesStorage
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SeparatedStorage allows you to use separate storage engines to satisfy
 | 
					// SeparatedStorage allows you to use separate storage engines to satisfy
 | 
				
			||||||
// the Storage interface
 | 
					// the Storage interface
 | 
				
			||||||
type SeparatedStorage struct {
 | 
					type SeparatedStorage struct {
 | 
				
			||||||
	UuidsStorage
 | 
						UUIDsStorage
 | 
				
			||||||
	TexturesStorage
 | 
						TexturesStorage
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SeparatedStorage) GetUuid(username string) (string, error) {
 | 
					func (s *SeparatedStorage) GetUuid(username string) (string, bool, error) {
 | 
				
			||||||
	return s.UuidsStorage.GetUuid(username)
 | 
						return s.UUIDsStorage.GetUuid(username)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SeparatedStorage) StoreUuid(username string, uuid string) error {
 | 
					func (s *SeparatedStorage) StoreUuid(username string, uuid string) error {
 | 
				
			||||||
	return s.UuidsStorage.StoreUuid(username, uuid)
 | 
						return s.UUIDsStorage.StoreUuid(username, uuid)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SeparatedStorage) GetTextures(uuid string) (*mojang.SignedTexturesResponse, error) {
 | 
					func (s *SeparatedStorage) GetTextures(uuid string) (*mojang.SignedTexturesResponse, error) {
 | 
				
			||||||
@@ -50,12 +51,3 @@ func (s *SeparatedStorage) GetTextures(uuid string) (*mojang.SignedTexturesRespo
 | 
				
			|||||||
func (s *SeparatedStorage) StoreTextures(uuid string, textures *mojang.SignedTexturesResponse) {
 | 
					func (s *SeparatedStorage) StoreTextures(uuid string, textures *mojang.SignedTexturesResponse) {
 | 
				
			||||||
	s.TexturesStorage.StoreTextures(uuid, textures)
 | 
						s.TexturesStorage.StoreTextures(uuid, textures)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// This error can be used to indicate, that requested
 | 
					 | 
				
			||||||
// value doesn't exists in the storage
 | 
					 | 
				
			||||||
type ValueNotFound struct {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (*ValueNotFound) Error() string {
 | 
					 | 
				
			||||||
	return "value not found in the storage"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,9 +12,9 @@ type uuidsStorageMock struct {
 | 
				
			|||||||
	mock.Mock
 | 
						mock.Mock
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *uuidsStorageMock) GetUuid(username string) (string, error) {
 | 
					func (m *uuidsStorageMock) GetUuid(username string) (string, bool, error) {
 | 
				
			||||||
	args := m.Called(username)
 | 
						args := m.Called(username)
 | 
				
			||||||
	return args.String(0), args.Error(1)
 | 
						return args.String(0), args.Bool(1), args.Error(2)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *uuidsStorageMock) StoreUuid(username string, uuid string) error {
 | 
					func (m *uuidsStorageMock) StoreUuid(username string, uuid string) error {
 | 
				
			||||||
@@ -50,9 +50,10 @@ func TestSplittedStorage(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	t.Run("GetUuid", func(t *testing.T) {
 | 
						t.Run("GetUuid", func(t *testing.T) {
 | 
				
			||||||
		storage, uuidsMock, _ := createMockedStorage()
 | 
							storage, uuidsMock, _ := createMockedStorage()
 | 
				
			||||||
		uuidsMock.On("GetUuid", "username").Once().Return("find me", nil)
 | 
							uuidsMock.On("GetUuid", "username").Once().Return("find me", true, nil)
 | 
				
			||||||
		result, err := storage.GetUuid("username")
 | 
							result, found, err := storage.GetUuid("username")
 | 
				
			||||||
		assert.Nil(t, err)
 | 
							assert.Nil(t, err)
 | 
				
			||||||
 | 
							assert.True(t, found)
 | 
				
			||||||
		assert.Equal(t, "find me", result)
 | 
							assert.Equal(t, "find me", result)
 | 
				
			||||||
		uuidsMock.AssertExpectations(t)
 | 
							uuidsMock.AssertExpectations(t)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -82,8 +83,3 @@ func TestSplittedStorage(t *testing.T) {
 | 
				
			|||||||
		texturesMock.AssertExpectations(t)
 | 
							texturesMock.AssertExpectations(t)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestValueNotFound_Error(t *testing.T) {
 | 
					 | 
				
			||||||
	err := &ValueNotFound{}
 | 
					 | 
				
			||||||
	assert.Equal(t, "value not found in the storage", err.Error())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user