package processor import ( "fmt" "testing" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "apskel-pos-be/internal/models" ) // The weekly leaderboard against Postgres. Needs TEST_DATABASE_URL; see // internal/repository/wallet_repository_test.go. func TestGameSession_Leaderboard(t *testing.T) { e := newEnakGameEnv(t) ctx := e.ctx() dave := uuid.New() require.NoError(t, e.db.Exec(`INSERT INTO customers (id, organization_id, name) VALUES (?, ?, 'Dave Lee')`, dave, e.orgA).Error) runner := e.playableGame(e.orgA, "runner", 1) other := e.playableGame(e.orgA, "other", 1) theirs := e.playableGame(e.orgB, "theirs", 1) for _, c := range []uuid.UUID{e.alice, e.bob, e.carol, dave} { e.coins(c, 100, nil) } n := 0 // play completes a session of game for customer and returns its id; every // playableGame pays 10. play := func(customer, game uuid.UUID) uuid.UUID { t.Helper() n++ s, err := e.sessions.Start(ctx, customer, game, fmt.Sprintf("k%d", n)) require.NoError(t, err) _, err = e.sessions.Complete(ctx, customer, s.SessionID, models.GameSessionCompleteInput{}) require.NoError(t, err) return s.SessionID } play(e.alice, runner.ID) play(e.alice, other.ID) bobs := play(e.bob, runner.ID) play(dave, runner.ID) play(e.carol, theirs.ID) // Bob reached 10 before Dave did. require.NoError(t, e.db.Exec(`UPDATE game_sessions SET ended_at = ended_at - INTERVAL '1 minute' WHERE id = ?`, bobs).Error) flagged := play(e.bob, runner.ID) require.NoError(t, e.db.Exec(`UPDATE game_sessions SET flagged = TRUE WHERE id = ?`, flagged).Error) lastWeek := play(dave, runner.ID) require.NoError(t, e.db.Exec(`UPDATE game_sessions SET started_at = started_at - INTERVAL '7 days' WHERE id = ?`, lastWeek).Error) _, err := e.sessions.Start(ctx, e.alice, runner.ID, "open") require.NoError(t, err, "a STARTED session counts for nothing") board, err := e.sessions.Leaderboard(ctx, e.bob, models.EnakGameLeaderboardQuery{}) require.NoError(t, err) week := leaderboardWeekStart(e.now) assert.Equal(t, week.Format("2006-01-02"), board.WeekStart) assert.Equal(t, week.AddDate(0, 0, 6).Format("2006-01-02"), board.WeekEnd) assert.Equal(t, []models.EnakGameLeaderboardEntry{ {Rank: 1, Name: "Alice", Coins: 20}, {Rank: 2, Name: "Bob", Coins: 10, IsMe: true}, {Rank: 3, Name: "Dave L**", Coins: 10}, }, board.Entries, "the flagged play, last week's play and another organization's do not count") require.NotNil(t, board.Me) assert.Equal(t, 2, board.Me.Rank) board, err = e.sessions.Leaderboard(ctx, dave, models.EnakGameLeaderboardQuery{Limit: 1}) require.NoError(t, err) require.Len(t, board.Entries, 1) assert.Equal(t, "Alice", board.Entries[0].Name) require.NotNil(t, board.Me, "the customer asking is returned below the limit") assert.Equal(t, models.EnakGameLeaderboardEntry{Rank: 3, Name: "Dave L**", Coins: 10, IsMe: true}, *board.Me) board, err = e.sessions.Leaderboard(ctx, e.alice, models.EnakGameLeaderboardQuery{GameID: other.ID.String()}) require.NoError(t, err) assert.Equal(t, []models.EnakGameLeaderboardEntry{{Rank: 1, Name: "Alice", Coins: 10, IsMe: true}}, board.Entries) assert.Equal(t, &other.ID, board.GameID) board, err = e.sessions.Leaderboard(ctx, dave, models.EnakGameLeaderboardQuery{Date: week.AddDate(0, 0, -3).Format("2006-01-02")}) require.NoError(t, err) assert.Equal(t, []models.EnakGameLeaderboardEntry{{Rank: 1, Name: "Dave L**", Coins: 10, IsMe: true}}, board.Entries, "last week") board, err = e.sessions.Leaderboard(ctx, e.carol, models.EnakGameLeaderboardQuery{}) require.NoError(t, err) assert.Equal(t, []models.EnakGameLeaderboardEntry{{Rank: 1, Name: "Carol", Coins: 10, IsMe: true}}, board.Entries, "only the customer's organization") board, err = e.sessions.Leaderboard(ctx, e.bob, models.EnakGameLeaderboardQuery{GameID: uuid.NewString(), Date: "2020-01-01"}) require.NoError(t, err) assert.Empty(t, board.Entries) assert.Nil(t, board.Me) _, err = e.sessions.Leaderboard(ctx, e.bob, models.EnakGameLeaderboardQuery{Date: "12-10-2026"}) assert.ErrorIs(t, err, ErrGameSessionRejected) _, err = e.sessions.Leaderboard(ctx, e.bob, models.EnakGameLeaderboardQuery{GameID: "runner"}) assert.ErrorIs(t, err, ErrGameSessionRejected) }