add more tests

This commit is contained in:
41666 2024-10-28 19:53:57 -07:00
parent 74add408e6
commit 4a528fe85a
9 changed files with 266 additions and 55 deletions

View file

@ -17,17 +17,22 @@ func main() {
log.Fatalln(err)
}
playerStore := store.NewPlayerStore(db)
vehicleStore := store.NewVehicleStore(db)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
run(ctx, playerStore, vehicleStore)
}
func run(ctx context.Context, ps store.IPlayerStore, vs store.IVehicleStore) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
playerStore := store.NewPlayerStore(db)
i, err := playerStore.Prune(ctx)
i, err := ps.Prune(ctx)
if err != nil {
log.Println("pruner: playerStore.Prune failed")
}
@ -38,9 +43,7 @@ func main() {
wg.Add(1)
go func() {
defer wg.Done()
vehicleStore := store.NewVehicleStore(db)
i, err := vehicleStore.Prune(ctx)
i, err := vs.Prune(ctx)
if err != nil {
log.Println("pruner: vehicleStore.Prune failed")
}

22
cmd/pruner/pruner_test.go Normal file
View file

@ -0,0 +1,22 @@
package main
import (
"context"
"testing"
"time"
"github.com/genudine/saerro-go/store/storemock"
)
func TestRun(t *testing.T) {
ps := new(storemock.MockPlayerStore)
vs := new(storemock.MockVehicleStore)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
ps.On("Prune", ctx).Return(30, nil)
vs.On("Prune", ctx).Return(30, nil)
run(ctx, ps, vs)
}

View file

@ -0,0 +1,128 @@
package eventhandler_test
import (
"context"
"database/sql"
"math/rand"
"os"
"strconv"
"testing"
"github.com/genudine/saerro-go/cmd/ws/eventhandler"
"github.com/genudine/saerro-go/translators"
"github.com/genudine/saerro-go/types"
"github.com/genudine/saerro-go/util"
)
const PreloadedCharacterCount = 45
var (
characterStore = make([]string, PreloadedCharacterCount)
db *sql.DB
)
func BenchmarkESS(b *testing.B) {
events, eh := prebench(b)
for i := 0; i < b.N; i++ {
event := events[i]
eh.HandleEvent(context.Background(), event)
}
}
func prebench(b *testing.B) ([]types.ESSEvent, eventhandler.EventHandler) {
b.Helper()
b.StopTimer()
// Create our character pool
for i := 0; i < PreloadedCharacterCount; i++ {
characterStore[i] = mkRandomCharacterID()
}
// Create events
events := []types.ESSEvent{}
for i := 0; i < b.N; i++ {
events = append(events, mkRandomEvent())
}
if db == nil {
var err error
db, err = util.GetDBConnection(os.Getenv("DB_ADDR"))
if err != nil {
b.Fatal(err)
}
}
eh := eventhandler.NewEventHandler(db)
b.ResetTimer()
b.StartTimer()
return events, eh
}
func mkRandomEvent() types.ESSEvent {
w := rand.Intn(4)
z := rand.Intn(7)
switch rand.Intn(2) {
case 0:
return mkRandomDeathEvent(w, z)
default:
return mkRandomExpEvent(w, z)
}
}
func mkRandomDeathEvent(world, zone int) types.ESSEvent {
return types.ESSEvent{
EventName: "Death",
WorldID: uint16(world),
ZoneID: uint32(zone),
CharacterID: getRandomCharacterID(),
CharacterLoadoutID: mkRandomLoadout(),
TeamID: mkRandomFaction(),
AttackerCharacterID: getRandomCharacterID(),
AttackerLoadoutID: mkRandomLoadout(),
AttackerTeamID: mkRandomFaction(),
}
}
func mkRandomExpEvent(world, zone int) types.ESSEvent {
return types.ESSEvent{
EventName: "GainExperience",
WorldID: uint16(world),
ZoneID: uint32(zone),
CharacterID: getRandomCharacterID(),
LoadoutID: mkRandomLoadout(),
TeamID: mkRandomFaction(),
ExperienceID: rand.Uint32() % 256,
}
}
func getRandomCharacterID() string {
i := rand.Intn(PreloadedCharacterCount)
return characterStore[i]
}
func mkRandomCharacterID() string {
return strconv.Itoa(rand.Int())
}
func mkRandomFaction() types.Faction {
return types.Faction(rand.Intn(4))
}
func mkRandomLoadout() uint16 {
for {
i := rand.Intn(46)
_, ok := translators.LoadoutMap[uint16(i)]
if ok {
return uint16(i)
}
}
}

View file

@ -9,8 +9,15 @@ import (
"github.com/genudine/saerro-go/types"
)
type IEventHandler interface {
HandleEvent(ctx context.Context, event types.ESSEvent)
HandleDeath(ctx context.Context, event types.ESSEvent)
HandleExperience(ctx context.Context, event types.ESSEvent)
HandleAnalytics(ctx context.Context, event types.ESSEvent)
}
type EventHandler struct {
Ingest *ingest.Ingest
Ingest ingest.IIngest
}
func NewEventHandler(db *sql.DB) EventHandler {

View file

@ -5,32 +5,28 @@ import (
"testing"
"time"
"github.com/avast/retry-go"
"github.com/stretchr/testify/assert"
"github.com/genudine/saerro-go/cmd/ws/ingest"
"github.com/genudine/saerro-go/store"
"github.com/genudine/saerro-go/translators"
"github.com/genudine/saerro-go/store/storemock"
"github.com/genudine/saerro-go/types"
"github.com/genudine/saerro-go/util/testutil"
)
func getEventHandlerTestShim(t *testing.T) (EventHandler, context.Context) {
func getEventHandlerTestShim(t *testing.T) (EventHandler, context.Context, *storemock.MockPlayerStore) {
t.Helper()
db := testutil.GetTestDB(t)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
t.Cleanup(cancel)
ps := new(storemock.MockPlayerStore)
return EventHandler{
Ingest: &ingest.Ingest{
PlayerStore: store.NewPlayerStore(db),
PlayerStore: ps,
},
}, ctx
}, ctx, ps
}
func TestHandleDeath(t *testing.T) {
eh, ctx := getEventHandlerTestShim(t)
eh, ctx, ps := getEventHandlerTestShim(t)
event := types.ESSEvent{
EventName: "Death",
@ -46,21 +42,17 @@ func TestHandleDeath(t *testing.T) {
AttackerTeamID: types.TR,
}
p1 := types.PopEventFromESSEvent(event, false).ToPlayer()
p2 := types.PopEventFromESSEvent(event, true).ToPlayer()
ps.On("Insert", ctx, p1).Return(nil)
ps.On("Insert", ctx, p2).Return(nil)
eh.HandleDeath(ctx, event)
player1, err := eh.Ingest.PlayerStore.GetOne(ctx, event.CharacterID)
assert.NoError(t, err, "player1 fetch failed")
assert.Equal(t, event.CharacterID, player1.CharacterID)
assert.Equal(t, string(translators.ClassFromLoadout(event.LoadoutID)), player1.ClassName)
player2, err := eh.Ingest.PlayerStore.GetOne(ctx, event.AttackerCharacterID)
assert.NoError(t, err, "player2 fetch failed")
assert.Equal(t, event.AttackerCharacterID, player2.CharacterID)
assert.Equal(t, string(translators.ClassFromLoadout(event.AttackerLoadoutID)), player2.ClassName)
}
func TestHandleExperience(t *testing.T) {
eh, ctx := getEventHandlerTestShim(t)
eh, ctx, ps := getEventHandlerTestShim(t)
event := types.ESSEvent{
EventName: "GainExperience",
@ -74,15 +66,14 @@ func TestHandleExperience(t *testing.T) {
ExperienceID: 674,
}
p := types.PopEventFromESSEvent(event, false).ToPlayer()
ps.On("Insert", ctx, p).Return(nil)
eh.HandleExperience(ctx, event)
player, err := eh.Ingest.PlayerStore.GetOne(ctx, event.CharacterID)
assert.NoError(t, err, "player fetch check failed")
assert.Equal(t, event.CharacterID, player.CharacterID)
assert.Equal(t, string(translators.ClassFromLoadout(event.LoadoutID)), player.ClassName)
}
func TestHandleAnalytics(t *testing.T) {
eh, ctx := getEventHandlerTestShim(t)
eh, ctx, _ := getEventHandlerTestShim(t)
event := types.ESSEvent{
EventName: "GainExperience",
WorldID: 17,
@ -99,7 +90,7 @@ func TestHandleAnalytics(t *testing.T) {
}
func TestHandleEvent(t *testing.T) {
eh, ctx := getEventHandlerTestShim(t)
eh, ctx, ps := getEventHandlerTestShim(t)
events := []types.ESSEvent{
{
@ -107,9 +98,9 @@ func TestHandleEvent(t *testing.T) {
WorldID: 17,
ZoneID: 2,
CharacterID: "LyytisDoll",
LoadoutID: 3,
TeamID: types.NC,
CharacterID: "LyytisDoll",
CharacterLoadoutID: 3,
TeamID: types.NC,
AttackerCharacterID: "Lyyti",
AttackerLoadoutID: 3,
@ -126,19 +117,19 @@ func TestHandleEvent(t *testing.T) {
ExperienceID: 201,
},
{
EventName: "",
},
}
p1 := types.PopEventFromESSEvent(events[0], false).ToPlayer()
ps.On("Insert", ctx, p1).Return(nil).Once()
p2 := types.PopEventFromESSEvent(events[0], true).ToPlayer()
ps.On("Insert", ctx, p2).Return(nil).Once()
p3 := types.PopEventFromESSEvent(events[1], false).ToPlayer()
ps.On("Insert", ctx, p3).Return(nil).Once()
for _, event := range events {
eh.HandleEvent(ctx, event)
}
checkPlayers := []string{"LyytisDoll", "Lyyti", "DollNC"}
for _, id := range checkPlayers {
// eventual consistency <333
err := retry.Do(func() error {
_, err := eh.Ingest.PlayerStore.GetOne(ctx, id)
return err
})
assert.NoError(t, err)
}
}

View file

@ -9,8 +9,13 @@ import (
"github.com/genudine/saerro-go/types"
)
type IIngest interface {
TrackPop(context.Context, types.PopEvent)
}
type Ingest struct {
PlayerStore store.IPlayerStore
PlayerStore store.IPlayerStore
VehicleStore store.IVehicleStore
}
func (i *Ingest) TrackPop(ctx context.Context, event types.PopEvent) {

View file

@ -12,23 +12,25 @@ import (
"github.com/genudine/saerro-go/types"
)
func mkIngest(t *testing.T) (context.Context, *ingest.Ingest, *storemock.MockPlayerStore) {
func mkIngest(t *testing.T) (context.Context, *ingest.Ingest, *storemock.MockPlayerStore, *storemock.MockVehicleStore) {
t.Helper()
ps := new(storemock.MockPlayerStore)
vs := new(storemock.MockVehicleStore)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
t.Cleanup(cancel)
i := &ingest.Ingest{
PlayerStore: ps,
PlayerStore: ps,
VehicleStore: vs,
}
return ctx, i, ps
return ctx, i, ps, vs
}
func TestTrackPopHappyPath(t *testing.T) {
ctx, i, ps := mkIngest(t)
ctx, i, ps, _ := mkIngest(t)
// Combat Medic on Emerald
event := types.PopEvent{
@ -48,7 +50,7 @@ func TestTrackPopHappyPath(t *testing.T) {
}
func TestTrackPopFixup(t *testing.T) {
ctx, i, ps := mkIngest(t)
ctx, i, ps, _ := mkIngest(t)
event := types.PopEvent{
WorldID: 17,
@ -68,7 +70,7 @@ func TestTrackPopFixup(t *testing.T) {
}
func TestTrackPopFixupFailed(t *testing.T) {
ctx, i, ps := mkIngest(t)
ctx, i, ps, _ := mkIngest(t)
event := types.PopEvent{
WorldID: 17,

View file

@ -0,0 +1,45 @@
package storemock
import (
"context"
"database/sql"
"github.com/genudine/saerro-go/types"
"github.com/stretchr/testify/mock"
)
type MockVehicleStore struct {
mock.Mock
DB *sql.DB
RanMigration bool
}
func (m *MockVehicleStore) IsMigrated(ctx context.Context) bool {
args := m.Called(ctx)
return args.Bool(0)
}
func (m *MockVehicleStore) RunMigration(ctx context.Context, force bool) {
m.Called(ctx, force)
}
func (m *MockVehicleStore) Insert(ctx context.Context, vehicle *types.Vehicle) error {
args := m.Called(ctx, vehicle)
return args.Error(0)
}
func (m *MockVehicleStore) GetOne(ctx context.Context, id string) (*types.Vehicle, error) {
args := m.Called(ctx, id)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(*types.Vehicle), args.Error(1)
}
func (m *MockVehicleStore) Prune(ctx context.Context) (int64, error) {
args := m.Called(ctx)
return int64(args.Int(0)), args.Error(1)
}

View file

@ -11,6 +11,14 @@ import (
"github.com/avast/retry-go"
)
type IVehicleStore interface {
IsMigrated(context.Context) bool
RunMigration(context.Context, bool)
Insert(context.Context, *types.Vehicle) error
GetOne(context.Context, string) (*types.Vehicle, error)
Prune(context.Context) (int64, error)
}
type VehicleStore struct {
DB *sql.DB