This repository has been archived on 2024-04-06. You can view files and clone it, but cannot push or open issues or pull requests.
core-old/internal/service/player_test.go
2023-01-04 05:21:02 +00:00

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)
})
}