mirror of
				https://github.com/elyby/chrly.git
				synced 2025-05-31 14:11:51 +05:30 
			
		
		
		
	
		
			
				
	
	
		
			211 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package mojang
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/stretchr/testify/mock"
 | |
| 	"github.com/stretchr/testify/suite"
 | |
| )
 | |
| 
 | |
| var awaitDelay = 20 * time.Millisecond
 | |
| 
 | |
| type mojangUsernamesToUuidsRequestMock struct {
 | |
| 	mock.Mock
 | |
| }
 | |
| 
 | |
| func (o *mojangUsernamesToUuidsRequestMock) UsernamesToUuids(ctx context.Context, usernames []string) ([]*ProfileInfo, error) {
 | |
| 	args := o.Called(ctx, usernames)
 | |
| 	var result []*ProfileInfo
 | |
| 	if casted, ok := args.Get(0).([]*ProfileInfo); ok {
 | |
| 		result = casted
 | |
| 	}
 | |
| 
 | |
| 	return result, args.Error(1)
 | |
| }
 | |
| 
 | |
| type batchUuidsProviderGetUuidResult struct {
 | |
| 	Result *ProfileInfo
 | |
| 	Error  error
 | |
| }
 | |
| 
 | |
| type batchUuidsProviderTestSuite struct {
 | |
| 	suite.Suite
 | |
| 
 | |
| 	Provider *BatchUuidsProvider
 | |
| 
 | |
| 	MojangApi *mojangUsernamesToUuidsRequestMock
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) SetupTest() {
 | |
| 	s.MojangApi = &mojangUsernamesToUuidsRequestMock{}
 | |
| 	s.Provider = NewBatchUuidsProvider(
 | |
| 		s.MojangApi.UsernamesToUuids,
 | |
| 		3,
 | |
| 		awaitDelay,
 | |
| 		false,
 | |
| 	)
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) TearDownTest() {
 | |
| 	s.MojangApi.AssertExpectations(s.T())
 | |
| 	s.Provider.StopQueue()
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) GetUuidAsync(username string) <-chan *batchUuidsProviderGetUuidResult {
 | |
| 	return s.GetUuidAsyncWithCtx(context.Background(), username)
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) GetUuidAsyncWithCtx(ctx context.Context, username string) <-chan *batchUuidsProviderGetUuidResult {
 | |
| 	startedChan := make(chan any)
 | |
| 	c := make(chan *batchUuidsProviderGetUuidResult, 1)
 | |
| 	go func() {
 | |
| 		close(startedChan)
 | |
| 		profile, err := s.Provider.GetUuid(ctx, username)
 | |
| 		c <- &batchUuidsProviderGetUuidResult{
 | |
| 			Result: profile,
 | |
| 			Error:  err,
 | |
| 		}
 | |
| 		close(c)
 | |
| 	}()
 | |
| 
 | |
| 	<-startedChan
 | |
| 
 | |
| 	return c
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) TestGetUuidForFewUsernamesSuccessfully() {
 | |
| 	expectedUsernames := []string{"username1", "username2"}
 | |
| 	expectedResult1 := &ProfileInfo{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username1"}
 | |
| 	expectedResult2 := &ProfileInfo{Id: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", Name: "username2"}
 | |
| 
 | |
| 	s.MojangApi.On("UsernamesToUuids", mock.Anything, expectedUsernames).Once().Return([]*ProfileInfo{
 | |
| 		expectedResult1,
 | |
| 		expectedResult2,
 | |
| 	}, nil)
 | |
| 
 | |
| 	chan1 := s.GetUuidAsync("username1")
 | |
| 	chan2 := s.GetUuidAsync("username2")
 | |
| 
 | |
| 	s.Require().Empty(chan1)
 | |
| 	s.Require().Empty(chan2)
 | |
| 
 | |
| 	time.Sleep(time.Duration(float64(awaitDelay) * 1.5))
 | |
| 
 | |
| 	result1 := <-chan1
 | |
| 	result2 := <-chan2
 | |
| 
 | |
| 	s.Require().NoError(result1.Error)
 | |
| 	s.Require().Equal(expectedResult1, result1.Result)
 | |
| 
 | |
| 	s.Require().NoError(result2.Error)
 | |
| 	s.Require().Equal(expectedResult2, result2.Result)
 | |
| 
 | |
| 	// Await a few more iterations to ensure, that no requests will be performed when there are no additional tasks
 | |
| 	time.Sleep(awaitDelay * 3)
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) TestGetUuidForManyUsernamesSplitByMultipleIterations() {
 | |
| 	var emptyResponse []string
 | |
| 
 | |
| 	s.MojangApi.On("UsernamesToUuids", mock.Anything, []string{"username1", "username2", "username3"}).Once().Return(emptyResponse, nil)
 | |
| 	s.MojangApi.On("UsernamesToUuids", mock.Anything, []string{"username4"}).Once().Return(emptyResponse, nil)
 | |
| 
 | |
| 	resultChan1 := s.GetUuidAsync("username1")
 | |
| 	resultChan2 := s.GetUuidAsync("username2")
 | |
| 	resultChan3 := s.GetUuidAsync("username3")
 | |
| 	resultChan4 := s.GetUuidAsync("username4")
 | |
| 
 | |
| 	time.Sleep(time.Duration(float64(awaitDelay) * 1.5))
 | |
| 
 | |
| 	s.Require().NotEmpty(resultChan1)
 | |
| 	s.Require().NotEmpty(resultChan2)
 | |
| 	s.Require().NotEmpty(resultChan3)
 | |
| 	s.Require().Empty(resultChan4)
 | |
| 
 | |
| 	time.Sleep(time.Duration(float64(awaitDelay) * 1.5))
 | |
| 
 | |
| 	s.Require().NotEmpty(resultChan4)
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) TestGetUuidForManyUsernamesWhenOneOfContextIsDeadlined() {
 | |
| 	var emptyResponse []string
 | |
| 
 | |
| 	s.MojangApi.On("UsernamesToUuids", mock.Anything, []string{"username1", "username2", "username4"}).Once().Return(emptyResponse, nil)
 | |
| 
 | |
| 	ctx, cancelCtx := context.WithCancel(context.Background())
 | |
| 
 | |
| 	resultChan1 := s.GetUuidAsync("username1")
 | |
| 	resultChan2 := s.GetUuidAsync("username2")
 | |
| 	resultChan3 := s.GetUuidAsyncWithCtx(ctx, "username3")
 | |
| 	resultChan4 := s.GetUuidAsync("username4")
 | |
| 
 | |
| 	cancelCtx()
 | |
| 
 | |
| 	time.Sleep(time.Duration(float64(awaitDelay) * 0.5))
 | |
| 
 | |
| 	s.Empty(resultChan1)
 | |
| 	s.Empty(resultChan2)
 | |
| 	s.NotEmpty(resultChan3, "canceled context must immediately release the job")
 | |
| 	s.Empty(resultChan4)
 | |
| 
 | |
| 	result3 := <-resultChan3
 | |
| 	s.Nil(result3.Result)
 | |
| 	s.ErrorIs(result3.Error, context.Canceled)
 | |
| 
 | |
| 	time.Sleep(awaitDelay)
 | |
| 
 | |
| 	s.Require().NotEmpty(resultChan1)
 | |
| 	s.Require().NotEmpty(resultChan2)
 | |
| 	s.Require().NotEmpty(resultChan4)
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) TestGetUuidForManyUsernamesFireOnFull() {
 | |
| 	s.Provider.fireOnFull = true
 | |
| 
 | |
| 	var emptyResponse []string
 | |
| 
 | |
| 	s.MojangApi.On("UsernamesToUuids", mock.Anything, []string{"username1", "username2", "username3"}).Once().Return(emptyResponse, nil)
 | |
| 	s.MojangApi.On("UsernamesToUuids", mock.Anything, []string{"username4"}).Once().Return(emptyResponse, nil)
 | |
| 
 | |
| 	resultChan1 := s.GetUuidAsync("username1")
 | |
| 	resultChan2 := s.GetUuidAsync("username2")
 | |
| 	resultChan3 := s.GetUuidAsync("username3")
 | |
| 	resultChan4 := s.GetUuidAsync("username4")
 | |
| 
 | |
| 	time.Sleep(time.Duration(float64(awaitDelay) * 0.5))
 | |
| 
 | |
| 	s.Require().NotEmpty(resultChan1)
 | |
| 	s.Require().NotEmpty(resultChan2)
 | |
| 	s.Require().NotEmpty(resultChan3)
 | |
| 	s.Require().Empty(resultChan4)
 | |
| 
 | |
| 	time.Sleep(time.Duration(float64(awaitDelay) * 1.5))
 | |
| 
 | |
| 	s.Require().NotEmpty(resultChan4)
 | |
| }
 | |
| 
 | |
| func (s *batchUuidsProviderTestSuite) TestGetUuidForFewUsernamesWithAnError() {
 | |
| 	expectedUsernames := []string{"username1", "username2"}
 | |
| 	expectedError := errors.New("mock error")
 | |
| 
 | |
| 	s.MojangApi.On("UsernamesToUuids", mock.Anything, expectedUsernames).Once().Return(nil, expectedError)
 | |
| 
 | |
| 	resultChan1 := s.GetUuidAsync("username1")
 | |
| 	resultChan2 := s.GetUuidAsync("username2")
 | |
| 
 | |
| 	result1 := <-resultChan1
 | |
| 	s.Assert().Nil(result1.Result)
 | |
| 	s.Assert().Equal(expectedError, result1.Error)
 | |
| 
 | |
| 	result2 := <-resultChan2
 | |
| 	s.Assert().Nil(result2.Result)
 | |
| 	s.Assert().Equal(expectedError, result2.Error)
 | |
| }
 | |
| 
 | |
| func TestBatchUuidsProvider(t *testing.T) {
 | |
| 	suite.Run(t, new(batchUuidsProviderTestSuite))
 | |
| }
 |