package processor import ( "context" "testing" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/models" "apskel-pos-be/internal/repository" ) // Plays against Postgres, so the game repositories really join the transaction: a // refused play leaves no game_plays row and no GAME_SPEND. func TestPlayGame_AgainstPostgres(t *testing.T) { db, _, player, _ := walletMoveDB(t) gameID, prizeID := uuid.New(), uuid.New() require.NoError(t, db.Exec(`INSERT INTO games (id, name, type, metadata) VALUES (?, 'Raffle', 'RAFFLE', '{"coin_cost": 2}')`, gameID).Error) require.NoError(t, db.Exec(`INSERT INTO game_prizes (id, game_id, name, weight, stock) VALUES (?, ?, 'Tumbler', 1, 1)`, prizeID, gameID).Error) t.Cleanup(func() { db.Exec(`DELETE FROM wallet_lot_allocations WHERE transaction_id IN (SELECT id FROM wallet_transactions WHERE customer_id = ?)`, player) db.Exec(`DELETE FROM game_plays WHERE game_id = ?`, gameID) db.Exec(`DELETE FROM game_prizes WHERE game_id = ?`, gameID) db.Exec(`DELETE FROM games WHERE id = ?`, gameID) }) wallet := NewWalletProcessor(repository.NewWalletRepository(db)) txm := repository.NewTxManager(db) require.NoError(t, txm.WithTransaction(context.Background(), func(ctx context.Context) error { in := earn(player, 3, nil) in.Currency = constants.WalletCurrencyCoin _, err := wallet.Credit(ctx, in) return err })) p := NewGamePlayProcessor(repository.NewGamePlayRepository(db), repository.NewGameRepository(db), repository.NewGamePrizeRepository(db), wallet, repository.NewWalletQueryRepository(db), txm) play := func() (*models.PlayGameResponse, error) { return p.PlayGame(context.Background(), &models.PlayGameRequest{GameID: gameID, CustomerID: player}) } res, err := play() require.NoError(t, err) assert.Equal(t, int64(1), res.CoinsRemaining) assert.Equal(t, 2, res.GamePlay.CoinsUsed) var spend struct { ReferenceID uuid.UUID Amount int64 } require.NoError(t, db.Raw(`SELECT reference_id, amount FROM wallet_transactions WHERE customer_id = ? AND type = 'GAME_SPEND'`, player).Scan(&spend).Error) assert.Equal(t, res.GamePlay.ID, spend.ReferenceID) assert.Equal(t, int64(-2), spend.Amount) // The only prize is gone, then the EnakCoin are too short: neither play leaves a row. _, err = play() assert.ErrorIs(t, err, ErrGamePlayRefused) require.NoError(t, db.Exec(`UPDATE game_prizes SET stock = 5 WHERE id = ?`, prizeID).Error) _, err = play() assert.ErrorIs(t, err, ErrGamePlayRefused) var plays, spends int64 require.NoError(t, db.Raw(`SELECT COUNT(*) FROM game_plays WHERE game_id = ? AND coins_used = 2`, gameID).Scan(&plays).Error) require.NoError(t, db.Raw(`SELECT COUNT(*) FROM wallet_transactions WHERE customer_id = ? AND type = 'GAME_SPEND'`, player).Scan(&spends).Error) assert.Equal(t, int64(1), plays) assert.Equal(t, int64(1), spends) }