Dawid Wysokiński
04e3f1d6bd
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: twhelp/core#151
584 lines
16 KiB
Go
584 lines
16 KiB
Go
package service_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dwysokinski.me/twhelp/core/internal/tw"
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
|
"gitea.dwysokinski.me/twhelp/core/internal/service"
|
|
"gitea.dwysokinski.me/twhelp/core/internal/service/internal/mock"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestPlayer_Refresh(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
serverKey, serverUrl := "pl169", "https://pl169.plemiona.pl"
|
|
|
|
players := []tw.Player{
|
|
{
|
|
OpponentsDefeated: tw.OpponentsDefeated{ // update
|
|
RankAtt: 8,
|
|
ScoreAtt: 7,
|
|
RankDef: 6,
|
|
ScoreDef: 5,
|
|
RankSup: 4,
|
|
ScoreSup: 3,
|
|
RankTotal: 2,
|
|
ScoreTotal: 1,
|
|
},
|
|
ID: 998,
|
|
Name: "name 998",
|
|
NumVillages: 5,
|
|
Points: 4,
|
|
Rank: 2,
|
|
ProfileURL: "profile-998",
|
|
},
|
|
{
|
|
OpponentsDefeated: tw.OpponentsDefeated{ // create, tribe change
|
|
RankAtt: 1,
|
|
ScoreAtt: 2,
|
|
RankDef: 3,
|
|
ScoreDef: 4,
|
|
RankSup: 5,
|
|
ScoreSup: 6,
|
|
RankTotal: 7,
|
|
ScoreTotal: 8,
|
|
},
|
|
ID: 999,
|
|
Name: "name 999",
|
|
NumVillages: 3,
|
|
Points: 4,
|
|
Rank: 6,
|
|
TribeID: 1234,
|
|
ProfileURL: "profile-999",
|
|
},
|
|
{
|
|
OpponentsDefeated: tw.OpponentsDefeated{ // update, tribe change
|
|
RankAtt: 111,
|
|
ScoreAtt: 222,
|
|
RankDef: 333,
|
|
ScoreDef: 444,
|
|
RankSup: 555,
|
|
ScoreSup: 666,
|
|
RankTotal: 777,
|
|
ScoreTotal: 888,
|
|
},
|
|
ID: 1000,
|
|
Name: "name 1000",
|
|
NumVillages: 333,
|
|
Points: 444,
|
|
Rank: 666,
|
|
TribeID: 1110,
|
|
ProfileURL: "profile-1000",
|
|
},
|
|
}
|
|
client := &mock.FakePlayerGetter{}
|
|
client.GetPlayersReturns(players, nil)
|
|
|
|
existingPlayers := []domain.Player{
|
|
{
|
|
OpponentsDefeated: domain.OpponentsDefeated{
|
|
RankAtt: 888,
|
|
ScoreAtt: 777,
|
|
RankDef: 666,
|
|
ScoreDef: 555,
|
|
RankSup: 444,
|
|
ScoreSup: 333,
|
|
RankTotal: 222,
|
|
ScoreTotal: 111,
|
|
},
|
|
ID: 111,
|
|
Name: "name 111",
|
|
NumVillages: 555,
|
|
Points: 444,
|
|
Rank: 222,
|
|
ProfileURL: "profile-111",
|
|
BestRank: 222,
|
|
BestRankAt: time.Now(),
|
|
MostPoints: 444,
|
|
MostPointsAt: time.Now(),
|
|
MostVillages: 555,
|
|
MostVillagesAt: time.Now(),
|
|
LastActivityAt: time.Now(),
|
|
ServerKey: serverKey,
|
|
CreatedAt: time.Now(),
|
|
},
|
|
{
|
|
OpponentsDefeated: domain.OpponentsDefeated{
|
|
RankAtt: 8,
|
|
ScoreAtt: 7,
|
|
RankDef: 6,
|
|
ScoreDef: 5,
|
|
RankSup: 4,
|
|
ScoreSup: 3,
|
|
RankTotal: 2,
|
|
ScoreTotal: 1,
|
|
},
|
|
ID: 997,
|
|
Name: "name 997",
|
|
NumVillages: 5,
|
|
Points: 4,
|
|
Rank: 2,
|
|
TribeID: 12331,
|
|
ProfileURL: "profile-997",
|
|
BestRank: 2,
|
|
BestRankAt: time.Now(),
|
|
MostPoints: 4,
|
|
MostPointsAt: time.Now(),
|
|
MostVillages: 5,
|
|
MostVillagesAt: time.Now(),
|
|
LastActivityAt: time.Now(),
|
|
ServerKey: serverKey,
|
|
CreatedAt: time.Now(),
|
|
},
|
|
{
|
|
OpponentsDefeated: domain.OpponentsDefeated(players[0].OpponentsDefeated), // update
|
|
ID: players[0].ID,
|
|
Name: players[0].Name,
|
|
NumVillages: players[0].NumVillages,
|
|
Points: players[0].Points,
|
|
Rank: players[0].Rank,
|
|
TribeID: players[0].TribeID,
|
|
ProfileURL: players[0].ProfileURL,
|
|
BestRank: players[0].Rank,
|
|
BestRankAt: time.Now().Add(-5 * time.Minute),
|
|
MostPoints: players[0].Points,
|
|
MostPointsAt: time.Now().Add(-5 * time.Minute),
|
|
MostVillages: players[0].NumVillages,
|
|
MostVillagesAt: time.Now().Add(-5 * time.Minute),
|
|
LastActivityAt: time.Now().Add(-5 * time.Minute),
|
|
ServerKey: serverKey,
|
|
CreatedAt: time.Now().Add(-5 * time.Minute),
|
|
},
|
|
{
|
|
OpponentsDefeated: domain.OpponentsDefeated(players[2].OpponentsDefeated), // update, tribe change
|
|
ID: players[2].ID,
|
|
Name: players[2].Name,
|
|
NumVillages: players[2].NumVillages - 1,
|
|
Points: players[2].Points - 1,
|
|
Rank: players[2].Rank + 1,
|
|
TribeID: 1234,
|
|
ProfileURL: players[2].ProfileURL,
|
|
BestRank: players[2].Rank + 1,
|
|
BestRankAt: time.Now().Add(-15 * time.Minute),
|
|
MostPoints: players[2].Points - 1,
|
|
MostPointsAt: time.Now().Add(-20 * time.Minute),
|
|
MostVillages: players[2].NumVillages - 1,
|
|
MostVillagesAt: time.Now().Add(-13 * time.Minute),
|
|
LastActivityAt: time.Now().Add(-25 * time.Minute),
|
|
ServerKey: serverKey,
|
|
CreatedAt: time.Now(),
|
|
},
|
|
}
|
|
repo := &mock.FakePlayerRepository{}
|
|
repo.ListReturns(existingPlayers, nil)
|
|
repo.CreateOrUpdateReturns(nil)
|
|
repo.DeleteReturns(nil)
|
|
|
|
tribeChangeSvc := &mock.FakeTribeChangeCreator{}
|
|
tribeChangeSvc.CreateReturns(nil)
|
|
|
|
numPlayers, err := service.NewPlayer(repo, tribeChangeSvc, client).Refresh(context.Background(), serverKey, serverUrl)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, len(players), numPlayers)
|
|
|
|
require.Equal(t, 1, client.GetPlayersCallCount())
|
|
_, passedServerUrl := client.GetPlayersArgsForCall(0)
|
|
assert.Equal(t, passedServerUrl, serverUrl)
|
|
|
|
require.Equal(t, 1, repo.CreateOrUpdateCallCount())
|
|
_, params := repo.CreateOrUpdateArgsForCall(0)
|
|
expectedParams := []domain.CreatePlayerParams{
|
|
{
|
|
OpponentsDefeated: domain.OpponentsDefeated(players[0].OpponentsDefeated),
|
|
ID: players[0].ID,
|
|
Name: players[0].Name,
|
|
NumVillages: players[0].NumVillages,
|
|
Points: players[0].Points,
|
|
Rank: players[0].Rank,
|
|
TribeID: players[0].TribeID,
|
|
ProfileURL: players[0].ProfileURL,
|
|
BestRank: existingPlayers[2].BestRank,
|
|
BestRankAt: existingPlayers[2].BestRankAt,
|
|
MostPoints: existingPlayers[2].MostPoints,
|
|
MostPointsAt: existingPlayers[2].MostPointsAt,
|
|
MostVillages: existingPlayers[2].MostVillages,
|
|
MostVillagesAt: existingPlayers[2].MostVillagesAt,
|
|
LastActivityAt: existingPlayers[2].LastActivityAt,
|
|
ServerKey: serverKey,
|
|
},
|
|
{
|
|
OpponentsDefeated: domain.OpponentsDefeated(players[1].OpponentsDefeated),
|
|
ID: players[1].ID,
|
|
Name: players[1].Name,
|
|
NumVillages: players[1].NumVillages,
|
|
Points: players[1].Points,
|
|
Rank: players[1].Rank,
|
|
TribeID: players[1].TribeID,
|
|
ProfileURL: players[1].ProfileURL,
|
|
BestRank: players[1].Rank,
|
|
BestRankAt: time.Now(),
|
|
MostPoints: players[1].Points,
|
|
MostPointsAt: time.Now(),
|
|
MostVillages: players[1].NumVillages,
|
|
MostVillagesAt: time.Now(),
|
|
LastActivityAt: time.Now(),
|
|
ServerKey: serverKey,
|
|
},
|
|
{
|
|
OpponentsDefeated: domain.OpponentsDefeated(players[2].OpponentsDefeated),
|
|
ID: players[2].ID,
|
|
Name: players[2].Name,
|
|
NumVillages: players[2].NumVillages,
|
|
Points: players[2].Points,
|
|
Rank: players[2].Rank,
|
|
TribeID: players[2].TribeID,
|
|
ProfileURL: players[2].ProfileURL,
|
|
BestRank: players[2].Rank,
|
|
BestRankAt: time.Now(),
|
|
MostPoints: players[2].Points,
|
|
MostPointsAt: time.Now(),
|
|
MostVillages: players[2].NumVillages,
|
|
MostVillagesAt: time.Now(),
|
|
LastActivityAt: time.Now(),
|
|
ServerKey: serverKey,
|
|
},
|
|
}
|
|
assert.Empty(t, cmp.Diff(
|
|
params,
|
|
expectedParams,
|
|
cmp.Comparer(func(x time.Time, y time.Time) bool {
|
|
dt := x.Sub(y)
|
|
return dt > -time.Second || dt < time.Second
|
|
}),
|
|
))
|
|
|
|
require.Equal(t, 1, repo.DeleteCallCount())
|
|
_, serverKeyDelete, playersToDelete := repo.DeleteArgsForCall(0)
|
|
assert.Equal(t, serverKey, serverKeyDelete)
|
|
assert.Len(t, playersToDelete, 2)
|
|
for _, id := range []int64{existingPlayers[0].ID, existingPlayers[1].ID} {
|
|
assert.Contains(t, playersToDelete, id)
|
|
}
|
|
|
|
require.Equal(t, 2, repo.ListCallCount())
|
|
|
|
require.Equal(t, 2, tribeChangeSvc.CreateCallCount()) // one from createOrUpdate + one from delete
|
|
|
|
_, tribeChanges := tribeChangeSvc.CreateArgsForCall(0) // call from createOrUpdate
|
|
assert.Len(t, tribeChanges, 2)
|
|
assert.Contains(t, tribeChanges, domain.CreateTribeChangeParams{
|
|
PlayerID: players[1].ID,
|
|
NewTribeID: players[1].TribeID,
|
|
OldTribeID: 0,
|
|
ServerKey: serverKey,
|
|
})
|
|
assert.Contains(t, tribeChanges, domain.CreateTribeChangeParams{
|
|
PlayerID: existingPlayers[3].ID,
|
|
NewTribeID: players[2].TribeID,
|
|
OldTribeID: existingPlayers[3].TribeID,
|
|
ServerKey: serverKey,
|
|
})
|
|
|
|
_, tribeChanges = tribeChangeSvc.CreateArgsForCall(1) // call from delete
|
|
assert.Len(t, tribeChanges, 1)
|
|
assert.Contains(t, tribeChanges, domain.CreateTribeChangeParams{
|
|
PlayerID: existingPlayers[1].ID,
|
|
NewTribeID: 0,
|
|
OldTribeID: existingPlayers[1].TribeID,
|
|
ServerKey: serverKey,
|
|
})
|
|
}
|
|
|
|
func TestPlayer_List_ListCountWithRelations(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("OK", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
limit int32
|
|
sort []domain.PlayerSort
|
|
}{
|
|
{
|
|
name: "default limit, default sort",
|
|
limit: 0,
|
|
sort: nil,
|
|
},
|
|
{
|
|
name: "custom limit",
|
|
limit: 199,
|
|
},
|
|
{
|
|
name: "custom sort",
|
|
limit: 0,
|
|
sort: []domain.PlayerSort{
|
|
{By: domain.PlayerSortByPoints, Direction: domain.SortDirectionDESC},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
limit := tt.limit
|
|
if limit == 0 {
|
|
limit = 200
|
|
}
|
|
|
|
repo := &mock.FakePlayerRepository{}
|
|
repo.ListCountWithRelationsCalls(func(
|
|
_ context.Context,
|
|
params domain.ListPlayersParams,
|
|
) ([]domain.PlayerWithRelations, int64, error) {
|
|
expectedParams := domain.ListPlayersParams{
|
|
Pagination: domain.Pagination{
|
|
Limit: limit,
|
|
},
|
|
Sort: func(sort []domain.PlayerSort) []domain.PlayerSort {
|
|
if len(sort) == 0 {
|
|
return []domain.PlayerSort{
|
|
{
|
|
By: domain.PlayerSortByID,
|
|
Direction: domain.SortDirectionASC,
|
|
},
|
|
}
|
|
}
|
|
return sort
|
|
}(tt.sort),
|
|
}
|
|
|
|
if diff := cmp.Diff(params, expectedParams); diff != "" {
|
|
return nil, 0, fmt.Errorf("validation failed: %s", diff)
|
|
}
|
|
|
|
return make([]domain.PlayerWithRelations, params.Pagination.Limit), int64(params.Pagination.Limit), nil
|
|
})
|
|
repo.ListCalls(func(
|
|
ctx context.Context,
|
|
params domain.ListPlayersParams,
|
|
) ([]domain.Player, error) {
|
|
playersWithRelations, _, err := repo.ListCountWithRelations(ctx, params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
players := make([]domain.Player, 0, len(playersWithRelations))
|
|
for _, p := range playersWithRelations {
|
|
players = append(players, p.Player)
|
|
}
|
|
|
|
return players, nil
|
|
})
|
|
client := &mock.FakePlayerGetter{}
|
|
|
|
svc := service.NewPlayer(repo, &mock.FakeTribeChangeCreator{}, client)
|
|
|
|
params := domain.ListPlayersParams{
|
|
Pagination: domain.Pagination{
|
|
Limit: tt.limit,
|
|
},
|
|
Sort: tt.sort,
|
|
}
|
|
|
|
playersListCountWithRelations, count, err := svc.ListCountWithRelations(context.Background(), params)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, limit, count)
|
|
assert.Len(t, playersListCountWithRelations, int(limit))
|
|
|
|
playersList, err := svc.List(context.Background(), params)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, playersList, len(playersListCountWithRelations))
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("ERR: validation failed", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
params domain.ListPlayersParams
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "params.Pagination.Limit < 0",
|
|
params: domain.ListPlayersParams{
|
|
Pagination: domain.Pagination{
|
|
Limit: -1,
|
|
},
|
|
},
|
|
expectedErr: domain.ValidationError{
|
|
Field: "limit",
|
|
Err: domain.MinError{
|
|
Min: 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "params.Pagination.Limit > 200",
|
|
params: domain.ListPlayersParams{
|
|
Pagination: domain.Pagination{
|
|
Limit: 201,
|
|
},
|
|
},
|
|
expectedErr: domain.ValidationError{
|
|
Field: "limit",
|
|
Err: domain.MaxError{
|
|
Max: 200,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "params.Pagination.Offset < 0",
|
|
params: domain.ListPlayersParams{
|
|
Pagination: domain.Pagination{
|
|
Offset: -1,
|
|
},
|
|
},
|
|
expectedErr: domain.ValidationError{
|
|
Field: "offset",
|
|
Err: domain.MinError{
|
|
Min: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "len(params.Sort) > 3",
|
|
params: domain.ListPlayersParams{
|
|
Sort: []domain.PlayerSort{
|
|
{
|
|
By: domain.PlayerSortByID,
|
|
Direction: domain.SortDirectionASC,
|
|
},
|
|
{
|
|
By: domain.PlayerSortByScoreDef,
|
|
Direction: domain.SortDirectionDESC,
|
|
},
|
|
{
|
|
By: domain.PlayerSortByScoreTotal,
|
|
Direction: domain.SortDirectionASC,
|
|
},
|
|
{
|
|
By: domain.PlayerSortByScoreAtt,
|
|
Direction: domain.SortDirectionASC,
|
|
},
|
|
},
|
|
},
|
|
expectedErr: domain.ValidationError{
|
|
Field: "sort",
|
|
Err: domain.MaxLengthError{
|
|
Max: 3,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
repo := &mock.FakePlayerRepository{}
|
|
client := &mock.FakePlayerGetter{}
|
|
|
|
svc := service.NewPlayer(repo, &mock.FakeTribeChangeCreator{}, client)
|
|
|
|
playersListCountWithRelations, count, err := svc.ListCountWithRelations(context.Background(), tt.params)
|
|
assert.ErrorIs(t, err, tt.expectedErr)
|
|
assert.Zero(t, playersListCountWithRelations)
|
|
assert.Zero(t, count)
|
|
assert.Equal(t, 0, repo.ListCountWithRelationsCallCount())
|
|
|
|
playersList, err := svc.List(context.Background(), tt.params)
|
|
assert.ErrorIs(t, err, tt.expectedErr)
|
|
assert.Zero(t, playersList)
|
|
assert.Equal(t, 0, repo.ListCallCount())
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPlayer_GetByServerKeyAndID_GetByServerKeyAndIDWithRelations(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("OK", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := domain.PlayerWithRelations{
|
|
Player: domain.Player{
|
|
ID: 123,
|
|
TribeID: 123,
|
|
ServerKey: "pl151",
|
|
},
|
|
Tribe: domain.NullTribeMeta{
|
|
Valid: true,
|
|
Tribe: domain.TribeMeta{
|
|
ID: 123,
|
|
},
|
|
},
|
|
}
|
|
repo := &mock.FakePlayerRepository{}
|
|
repo.ListCountWithRelationsReturns([]domain.PlayerWithRelations{p}, 1, nil)
|
|
repo.ListReturns([]domain.Player{p.Player}, nil)
|
|
client := &mock.FakePlayerGetter{}
|
|
tribeChangeSvc := &mock.FakeTribeChangeCreator{}
|
|
|
|
player, err := service.NewPlayer(repo, tribeChangeSvc, client).
|
|
GetByServerKeyAndID(context.Background(), p.ServerKey, p.ID)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, p.Player, player)
|
|
|
|
playerWithRelations, err := service.NewPlayer(repo, tribeChangeSvc, client).
|
|
GetByServerKeyAndIDWithRelations(context.Background(), player.ServerKey, player.ID)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, p, playerWithRelations)
|
|
|
|
require.Equal(t, 1, repo.ListCallCount())
|
|
_, argParams := repo.ListArgsForCall(0)
|
|
assert.Equal(t, domain.ListPlayersParams{
|
|
IDs: []int64{player.ID},
|
|
ServerKeys: []string{player.ServerKey},
|
|
Pagination: domain.Pagination{
|
|
Limit: 1,
|
|
},
|
|
}, argParams)
|
|
require.Equal(t, 1, repo.ListCountWithRelationsCallCount())
|
|
_, argsParamsWithRelations := repo.ListCountWithRelationsArgsForCall(0)
|
|
assert.Equal(t, argParams, argsParamsWithRelations)
|
|
|
|
})
|
|
|
|
t.Run("ERR: player not found", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
repo := &mock.FakePlayerRepository{}
|
|
client := &mock.FakePlayerGetter{}
|
|
tribeChangeSvc := &mock.FakeTribeChangeCreator{}
|
|
|
|
var id int64 = 123
|
|
|
|
player, err := service.NewPlayer(repo, tribeChangeSvc, client).
|
|
GetByServerKeyAndID(context.Background(), "pl151", id)
|
|
assert.ErrorIs(t, err, domain.PlayerNotFoundError{ID: id})
|
|
assert.Zero(t, player)
|
|
|
|
playerWithRelations, err := service.NewPlayer(repo, tribeChangeSvc, client).
|
|
GetByServerKeyAndIDWithRelations(context.Background(), "pl151", id)
|
|
assert.ErrorIs(t, err, domain.PlayerNotFoundError{ID: id})
|
|
assert.Zero(t, playerWithRelations)
|
|
})
|
|
}
|