168 lines
8.6 KiB
Go
168 lines
8.6 KiB
Go
package service
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"browser.local/platform/domain"
|
|
)
|
|
|
|
func TestSCUMFactIngestMaintainsPlatformTablesAndWelcomeQueue(t *testing.T) {
|
|
svc, session, runSession, instance := newSourceRCONFixture(t)
|
|
squadID := int64(42)
|
|
bank := int64(1200)
|
|
gold := int64(3)
|
|
exists := true
|
|
locked := true
|
|
functional := true
|
|
observedAt := fixedTime.Add(-1 * time.Minute)
|
|
|
|
result, err := svc.IngestSCUMFacts(domain.SCUMFactIngest{
|
|
RunEndpointID: instance.RunEndpointID,
|
|
SessionToken: runSession,
|
|
ServerInstanceID: instance.ID,
|
|
Users: []domain.SCUMUserFact{{
|
|
SteamID: "76561198000000001", DisplayName: "Mira", SquadID: &squadID, LoginIP: "203.0.113.7", Online: true, Login: true,
|
|
ObservedAt: observedAt, LoginObservedAt: observedAt, Position: &domain.SCUMPosition{X: 10, Y: 20, Z: 3}, BankBalance: &bank, GoldBars: &gold, RiddenGameVehicleID: "game-veh-1",
|
|
}},
|
|
Vehicles: []domain.SCUMVehicleFact{{
|
|
GameVehicleID: "game-veh-1", VehicleClass: "BPC_Laika_C", DisplayName: "Laika", Exists: &exists, Locked: &locked, Functional: &functional, LockedBySteamID: "76561198000000001", LockedAt: observedAt, ObservedAt: observedAt, Position: &domain.SCUMPosition{X: 400, Y: 200, Z: 0},
|
|
}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ingest SCUM facts: %v", err)
|
|
}
|
|
if !result.Accepted || result.AcceptedUserCount != 1 || result.AcceptedVehicleCount != 1 || result.WelcomeQueuedCount != 1 {
|
|
t.Fatalf("unexpected ingest result: %+v", result)
|
|
}
|
|
|
|
users, err := svc.ListSCUMUsersForSession(session, domain.SCUMUserFilter{ServerInstanceID: instance.ID})
|
|
if err != nil || len(users) != 1 {
|
|
t.Fatalf("list SCUM users: users=%+v err=%v", users, err)
|
|
}
|
|
user := users[0]
|
|
if user.SteamID != "76561198000000001" || user.SquadID != squadID || user.LastLoginIP != "203.0.113.7" || !user.Online || user.BankBalance == nil || *user.BankBalance != bank || user.GoldBars == nil || *user.GoldBars != gold || user.RiddenVehicleID == "" || user.GameVehicleID != "game-veh-1" {
|
|
t.Fatalf("unexpected SCUM user: %+v", user)
|
|
}
|
|
if user.LastLoginAge != time.Minute {
|
|
t.Fatalf("expected one-minute login age, got %s", user.LastLoginAge)
|
|
}
|
|
|
|
jobs, err := svc.store.Jobs().List(domain.JobFilter{ServerInstanceID: instance.ID})
|
|
if err != nil || len(jobs) != 1 {
|
|
t.Fatalf("expected one queued welcome job, jobs=%+v err=%v", jobs, err)
|
|
}
|
|
if jobs[0].Capability != domain.JobCapabilityRemoteRunRCONCommand || !jobs[0].QueueEligibleAt.Equal(fixedTime.Add(domain.SCUMWelcomeMessageDelay)) {
|
|
t.Fatalf("unexpected welcome job: %+v", jobs[0])
|
|
}
|
|
|
|
userTracks, err := svc.ListSCUMUserTrajectoriesForSession(session, domain.SCUMUserTrajectoryFilter{ServerInstanceID: instance.ID})
|
|
if err != nil || len(userTracks) != 1 || userTracks[0].RiddenVehicleID != user.RiddenVehicleID {
|
|
t.Fatalf("unexpected user trajectory rows: rows=%+v err=%v", userTracks, err)
|
|
}
|
|
vehicles, err := svc.ListSCUMVehiclesForSession(session, domain.SCUMVehicleFilter{ServerInstanceID: instance.ID})
|
|
if err != nil || len(vehicles) != 1 || vehicles[0].GameVehicleID != "game-veh-1" || !vehicles[0].Exists || !vehicles[0].Locked || vehicles[0].Functional == nil || !*vehicles[0].Functional {
|
|
t.Fatalf("unexpected SCUM vehicles: vehicles=%+v err=%v", vehicles, err)
|
|
}
|
|
vehicleTracks, err := svc.ListSCUMVehicleTrajectoriesForSession(session, domain.SCUMVehicleTrajectoryFilter{ServerInstanceID: instance.ID})
|
|
if err != nil || len(vehicleTracks) != 1 || vehicleTracks[0].SCUMVehicleID != vehicles[0].ID {
|
|
t.Fatalf("unexpected vehicle trajectory rows: rows=%+v err=%v", vehicleTracks, err)
|
|
}
|
|
locks, err := svc.ListSCUMVehicleLocksForSession(session, domain.SCUMVehicleLockFilter{ServerInstanceID: instance.ID})
|
|
if err != nil || len(locks) != 1 || locks[0].SCUMUserID != user.ID || locks[0].SCUMVehicleID != vehicles[0].ID {
|
|
t.Fatalf("unexpected vehicle lock history: locks=%+v err=%v", locks, err)
|
|
}
|
|
|
|
_, err = svc.IngestSCUMFacts(domain.SCUMFactIngest{
|
|
RunEndpointID: instance.RunEndpointID, SessionToken: runSession, ServerInstanceID: instance.ID,
|
|
Users: []domain.SCUMUserFact{{SteamID: "76561198000000001", Online: true, ObservedAt: observedAt, Position: &domain.SCUMPosition{X: 10, Y: 20, Z: 3}}},
|
|
Vehicles: []domain.SCUMVehicleFact{{GameVehicleID: "game-veh-1", ObservedAt: observedAt, Position: &domain.SCUMPosition{X: 400, Y: 200, Z: 0}}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("re-ingest unchanged SCUM facts: %v", err)
|
|
}
|
|
userTracks, _ = svc.ListSCUMUserTrajectoriesForSession(session, domain.SCUMUserTrajectoryFilter{ServerInstanceID: instance.ID})
|
|
vehicleTracks, _ = svc.ListSCUMVehicleTrajectoriesForSession(session, domain.SCUMVehicleTrajectoryFilter{ServerInstanceID: instance.ID})
|
|
if len(userTracks) != 1 || len(vehicleTracks) != 1 {
|
|
t.Fatalf("unchanged positions must not create trajectory rows, users=%+v vehicles=%+v", userTracks, vehicleTracks)
|
|
}
|
|
|
|
_, err = svc.IngestSCUMFacts(domain.SCUMFactIngest{
|
|
RunEndpointID: instance.RunEndpointID, SessionToken: runSession, ServerInstanceID: instance.ID,
|
|
Users: []domain.SCUMUserFact{{SteamID: "76561198000000001", Online: false, ObservedAt: fixedTime, Position: &domain.SCUMPosition{X: 11, Y: 21, Z: 4}}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ingest offline SCUM user fact: %v", err)
|
|
}
|
|
userTracks, _ = svc.ListSCUMUserTrajectoriesForSession(session, domain.SCUMUserTrajectoryFilter{ServerInstanceID: instance.ID})
|
|
if len(userTracks) != 1 {
|
|
t.Fatalf("offline users must not create trajectory rows, rows=%+v", userTracks)
|
|
}
|
|
}
|
|
|
|
func TestSCUMFactIngestQueuesFreshWelcomeAfterActivityGap(t *testing.T) {
|
|
svc, session, runSession, instance := newSourceRCONFixture(t)
|
|
firstLogin := fixedTime.Add(-20 * time.Minute)
|
|
secondLogin := fixedTime.Add(-4 * time.Minute)
|
|
|
|
for _, loginAt := range []time.Time{firstLogin, secondLogin} {
|
|
result, err := svc.IngestSCUMFacts(domain.SCUMFactIngest{RunEndpointID: instance.RunEndpointID, SessionToken: runSession, ServerInstanceID: instance.ID, Users: []domain.SCUMUserFact{{SteamID: "76561198000000002", DisplayName: "Noah", Online: true, Login: true, ObservedAt: loginAt, LoginObservedAt: loginAt}}})
|
|
if err != nil {
|
|
t.Fatalf("ingest login at %s: %v", loginAt, err)
|
|
}
|
|
if result.WelcomeQueuedCount != 1 {
|
|
t.Fatalf("expected fresh welcome for login at %s, got %+v", loginAt, result)
|
|
}
|
|
}
|
|
|
|
users, err := svc.ListSCUMUsersForSession(session, domain.SCUMUserFilter{ServerInstanceID: instance.ID, SteamID: "76561198000000002"})
|
|
if err != nil || len(users) != 1 {
|
|
t.Fatalf("list gap user: users=%+v err=%v", users, err)
|
|
}
|
|
if users[0].LastLoginAge != 4*time.Minute {
|
|
t.Fatalf("expected last login age to show the second login, got %s", users[0].LastLoginAge)
|
|
}
|
|
jobs, err := svc.store.Jobs().List(domain.JobFilter{ServerInstanceID: instance.ID})
|
|
if err != nil || len(jobs) != 2 {
|
|
t.Fatalf("expected two welcome jobs after activity gap, jobs=%+v err=%v", jobs, err)
|
|
}
|
|
}
|
|
|
|
func TestSCUMStaleOnlineUserConvergesToOffline(t *testing.T) {
|
|
svc, session, runSession, instance := newSourceRCONFixture(t)
|
|
staleAt := fixedTime.Add(-16 * time.Minute)
|
|
if _, err := svc.IngestSCUMFacts(domain.SCUMFactIngest{
|
|
RunEndpointID: instance.RunEndpointID, SessionToken: runSession, ServerInstanceID: instance.ID,
|
|
Users: []domain.SCUMUserFact{{SteamID: "76561198000000003", DisplayName: "Stale", Online: true, Login: true, ObservedAt: staleAt, LoginObservedAt: staleAt}},
|
|
}); err != nil {
|
|
t.Fatalf("ingest stale SCUM user fact: %v", err)
|
|
}
|
|
|
|
users, err := svc.ListSCUMUsersForSession(session, domain.SCUMUserFilter{ServerInstanceID: instance.ID})
|
|
if err != nil || len(users) != 1 {
|
|
t.Fatalf("list stale SCUM users: users=%+v err=%v", users, err)
|
|
}
|
|
if users[0].Online {
|
|
t.Fatalf("expected a user without activity for %s to converge offline: %+v", domain.SCUMUserOfflineAfter, users[0])
|
|
}
|
|
}
|
|
|
|
func TestSCUMFactsRejectedForNonSCUMServerInstance(t *testing.T) {
|
|
svc, _, runSession, instance := newSourceRCONFixture(t)
|
|
if err := svc.store.GamePlugins().Create(domain.GamePlugin{ID: "server.other", Name: "Other", Version: "1.0.0", ServerType: "other"}); err != nil {
|
|
t.Fatalf("create non-SCUM plugin: %v", err)
|
|
}
|
|
if err := svc.store.ServerInstances().Create(domain.ServerInstance{ID: "server-other", PluginID: "server.other", RunEndpointID: instance.RunEndpointID, Name: "Other Server", State: domain.ServerInstanceStateRunning, ConfigVersion: 1}); err != nil {
|
|
t.Fatalf("create non-SCUM server: %v", err)
|
|
}
|
|
|
|
_, err := svc.IngestSCUMFacts(domain.SCUMFactIngest{
|
|
RunEndpointID: instance.RunEndpointID, SessionToken: runSession, ServerInstanceID: "server-other",
|
|
Users: []domain.SCUMUserFact{{SteamID: "76561198000000004", Online: true}},
|
|
})
|
|
if !errors.Is(err, ErrForbidden) {
|
|
t.Fatalf("expected SCUM facts for a non-SCUM server to be rejected, got %v", err)
|
|
}
|
|
}
|