Skip to Content
BackendBDD Test Results

BDD Test Results

Last Updated: April 2026

110 scenarios, all passing. Run with go test -v ./test/bdd/standalone/ in the service/ directory.


Feature: Full game simulation

Scenario: Two players compete, long wins when market rises Given a game template with entry_fee 10 and reward 18 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match Then the match should be in "open" status And player A wallet should have 40 USDT And player B wallet should have 40 USDT When BTCUSDT price is set to 95.0 And player A opens a "buy" position with margin 10.0 and leverage 2 at price 95.0 And player B opens a "sell" position with margin 10.0 and leverage 2 at price 95.0 Then player A should have an "open" position And player B should have an "open" position When BTCUSDT price changes to 110.0 And player A closes their position And player B closes their position Then player A position should be "closed" with positive profit And player B position should be "closed" with negative profit When the match is closed and rewards are calculated Then player A should be the winner And player A wallet should have 58 USDT And player A should have gained XP and cups Scenario: Match auto-starts when room is full Given a game template with entry_fee 0 and reward 0 and duration "1m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT When player A joins the match Then the match should be in "waiting" status When player B joins the match Then the match should be in "open" status Scenario: Player cannot join a full match Given a game template with entry_fee 0 and reward 0 and duration "1m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player C has a wallet with 50 USDT And player A joins the match And player B joins the match Then player C should fail to join the match with error "not in waiting status" Scenario: Player with insufficient balance cannot join Given a game template with entry_fee 100 and reward 180 and duration "1m" And admin creates a match room from the game And player A has a wallet with 50 USDT Then player A should fail to join the match with error "insufficient balance"

Feature: Risk management

Scenario: Player is disqualified when total drawdown limit exceeded Given a game template with entry_fee 0 and reward 0 and duration "5m" And the game has max_total_drawdown_pct of 30.0 And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 And player A opens a "buy" position with margin 50.0 and leverage 2 at price 100.0 And BTCUSDT price changes to 70.0 Then player A should be disqualified Scenario: Disqualified player cannot open new positions Given a game template with entry_fee 0 and reward 0 and duration "5m" And the game has max_total_drawdown_pct of 10.0 And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 And player A opens a "buy" position with margin 50.0 and leverage 2 at price 100.0 And BTCUSDT price changes to 85.0 Then player A should be disqualified And player A should fail to open a position with error "disqualified" Scenario: Trading is locked on a match Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When admin locks trading on the match And BTCUSDT price is set to 100.0 Then player A should fail to open a position with error "trading is locked" Scenario: Max loss per trade prevents oversized positions Given a game template with entry_fee 0 and reward 0 and duration "5m" And the game has max_loss_per_trade_pct of 10.0 And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 Then player A should fail to open a position with margin 20.0 and error "max loss per trade"

Feature: Challenge rule engine

Scenario: Symbol not in allowed list is rejected Given a game template with entry_fee 0 and reward 0 and duration "5m" And the game allows only symbols "BTCUSDT,ETHUSDT" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 Then player A should fail to open a "SOLUSDT" position with error "symbol not allowed" Scenario: Leverage exceeds challenge max is rejected Given a game template with entry_fee 0 and reward 0 and duration "5m" And the game has max_leverage of 5 And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 Then player A should fail to open a position with leverage 10 and error "leverage exceeds" Scenario: Short position rejected in long-only challenge Given a game template with entry_fee 0 and reward 0 and duration "5m" And the game allows only "long_only" direction And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 Then player A should fail to open a "sell" direction position with error "direction not allowed" And player A opens a "buy" position with margin 10.0 and leverage 1 at price 100.0 And player A should have an "open" position

Feature: Match lifecycle and refunds

Scenario: Admin cancels a waiting match and players get refunded Given a game template with entry_fee 10 and reward 18 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player A joins the match Then player A wallet should have 40 USDT When admin cancels the match Then the match should be in "canceled" status And player A wallet should have 50 USDT Scenario: Admin cancels match with two players, both refunded Given a game template with entry_fee 20 and reward 36 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match Then player A wallet should have 30 USDT And player B wallet should have 30 USDT When admin cancels the match Then the match should be in "canceled" status And player A wallet should have 50 USDT And player B wallet should have 50 USDT Scenario: Cannot cancel a closed match Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 And the match is closed and rewards are calculated Then admin should fail to cancel match with error "cannot be canceled"

Feature: Anti-cheat and account suspension

Scenario: Suspended user cannot join a match Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player A is suspended with reason "cheating detected" Then player A should fail to join the match with error "suspended" Scenario: User can join after suspension is lifted Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A is suspended with reason "under review" And player A suspension is lifted And player A joins the match And player B joins the match Then the match should be in "open" status

Feature: Friend system

Scenario: Send and accept friend request Given player A exists And player B exists When player A sends a friend request to player B Then player B should have 1 pending friend request When player B accepts the friend request Then player A should have 1 friend And player B should have 1 friend Scenario: Reject friend request Given player A exists And player B exists When player A sends a friend request to player B And player B rejects the friend request Then player B should have 0 pending friend requests And player A should have 0 friends Scenario: Cannot send friend request to yourself Given player A exists Then player A should fail to send friend request to self with error "cannot send friend request to yourself" Scenario: Cannot send duplicate friend request Given player A exists And player B exists When player A sends a friend request to player B Then player A should fail to send another request to player B with error "already friends" Scenario: Remove friend Given player A exists And player B exists When player A sends a friend request to player B And player B accepts the friend request Then player A should have 1 friend When player A removes the friendship Then player A should have 0 friends

Feature: Analytics and leaderboard

Scenario: Dashboard shows correct stats after a completed match Given a game template with entry_fee 10 and reward 18 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 And player A opens a "buy" position with margin 10.0 and leverage 1 at price 100.0 And BTCUSDT price changes to 110.0 And player A closes their position And the match is closed and rewards are calculated Then the dashboard should show 2 total users And the dashboard should show 1 total matches Scenario: Leaderboard ranks users by cup points Given player A exists with 100 cup points And player B exists with 200 cup points And player C exists with 50 cup points Then the leaderboard first place should be player B And the leaderboard second place should be player A And the leaderboard third place should be player C Scenario: Match summary reports trade stats after match Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 And player A opens a "buy" position with margin 10.0 and leverage 1 at price 100.0 And BTCUSDT price changes to 110.0 And player A closes their position And the match is closed and rewards are calculated Then the match summary should show 2 total trades And the match summary should show 2 total participants Scenario: Emergency stop locks all active matches Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match Then the match should be in "open" status When admin triggers emergency stop Then player A should fail to open a position with error "trading is locked"

Feature: Admin match management

Scenario: Admin manually starts a waiting match with enough players Given a game template with entry_fee 0 and reward 0 and duration "5m" and max_players 3 And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match Then the match should be in "waiting" status When admin manually starts the match Then the match should be in "open" status Scenario: Cannot start a match without enough players Given a game template with entry_fee 0 and reward 0 and duration "5m" and max_players 3 And admin creates a match room from the game And player A has a wallet with 50 USDT And player A joins the match Then admin should fail to start match with error "min players not met" Scenario: Cannot start an already open match Given a game template with entry_fee 0 and reward 0 and duration "1m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match Then the match should be in "open" status And admin should fail to start match with error "not in waiting status" Scenario: Admin force-closes an open match Given a game template with entry_fee 0 and reward 0 and duration "1m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match Then the match should be in "open" status When admin force-closes the match Then the match should be in "closed" status

Feature: Position management

Scenario: Update stop loss and take profit on open position Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 And player A opens a "buy" position with margin 10.0 and leverage 1 at price 100.0 Then player A should have an "open" position When player A updates position with SL 90.0 and TP 120.0 Then player A position should have SL 90.0 and TP 120.0

Feature: Automatic match closure

Scenario: Expired match gets auto-closed with rewards Given a game template with entry_fee 0 and reward 10 and duration "1s" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match Then the match should be in "open" status When we wait for the match to expire And ProcessCloseMatches runs Then the match should be in "closed" status

Feature: Rule enforcement

Scenario: Trading frequency limit blocks rapid trades Given a game template with entry_fee 0 and reward 0 and duration "5m" And the game has max_trades_per_minute of 2 And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 And player A opens a "buy" position with margin 5.0 and leverage 1 at price 100.0 And player A opens a "buy" position with margin 5.0 and leverage 1 at price 100.0 Then player A should fail to open a position with error "trading frequency" Scenario: Min trades excludes inactive player from winning Given a game template with entry_fee 0 and reward 10 and duration "5m" And the game has min_trades of 1 And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match When BTCUSDT price is set to 100.0 And player B opens a "buy" position with margin 5.0 and leverage 1 at price 100.0 And BTCUSDT price changes to 110.0 And player B closes their position And the match is closed and rewards are calculated Then player B should be the winner

Feature: Authentication

Scenario: New user requests OTP and auto-registers Given a fresh auth service When user "alice@test.com" requests an OTP Then the OTP request should succeed with expiry 120 And user "alice@test.com" should exist in the database Scenario: User logs in with correct OTP Given a fresh auth service And user "bob@test.com" requests an OTP When user "bob@test.com" logs in with the correct OTP Then the login should return valid tokens Scenario: User login fails with wrong OTP Given a fresh auth service And user "charlie@test.com" requests an OTP When user "charlie@test.com" logs in with OTP "99999" Then the login should fail with error "invalid verification code" Scenario: Token refresh returns new access token Given a fresh auth service And user "dave@test.com" requests an OTP And user "dave@test.com" logs in with the correct OTP When the user refreshes their token Then the refresh should return a new access token Scenario: Inactive user cannot request OTP Given a fresh auth service And an inactive user "banned@test.com" exists When user "banned@test.com" requests an OTP expecting error Then the OTP request should fail with error "inactive user"

Feature: User management

Scenario: Create and retrieve a user Given a fresh user service When a user is created with email "alice@test.com" Then the user should exist with email "alice@test.com" Scenario: Update user nickname Given a fresh user service And a user is created with email "bob@test.com" When the user nickname is updated to "BobTrader" Then the user nickname should be "BobTrader" Scenario: Suspend and unsuspend a user Given a fresh user service And a user is created with email "charlie@test.com" When the user is suspended with reason "cheating" Then the user should be suspended When the user suspension is lifted Then the user should not be suspended Scenario: Delete a user Given a fresh user service And a user is created with email "dave@test.com" When the user is deleted Then the user should not exist Scenario: List users with pagination Given a fresh user service And a user is created with email "user1@test.com" And a user is created with email "user2@test.com" And a user is created with email "user3@test.com" Then the users page should have 3 total users

Feature: Wallet management

Scenario: Create a wallet for a user Given a fresh wallet service And a registered user exists When a USDT wallet is created for the user Then the wallet should exist with 0 balance Scenario: Deposit to a wallet Given a fresh wallet service And a registered user with a USDT wallet exists When 100 USDT is deposited via the wallet mock Then the wallet balance should be 100 Scenario: Withdraw from a wallet Given a fresh wallet service And a registered user with a USDT wallet exists And 100 USDT is deposited via the wallet mock When 30 USDT is withdrawn via the wallet mock Then the wallet balance should be 70 Scenario: Withdraw more than balance fails Given a fresh wallet service And a registered user with a USDT wallet exists When 100 USDT withdrawal is attempted via the wallet mock Then the withdrawal should fail with error "insufficient balance"

Feature: Transaction management

Scenario: Create a deposit transaction Given a fresh transaction service And a user with a wallet exists When a deposit transaction of 100 is created Then the transaction should exist with type "deposit" and amount 100 Scenario: Create a withdrawal transaction Given a fresh transaction service And a user with a wallet exists When a withdrawal transaction of 50 is created Then the transaction should exist with type "withdraw" and amount 50 Scenario: List transactions for a wallet Given a fresh transaction service And a user with a wallet exists And a deposit transaction of 100 is created And a withdrawal transaction of 30 is created Then the transactions page should have 2 total transactions

Feature: Achievement management

Scenario: Create an achievement Given a fresh achievement service When an achievement is created with title "First Win" Then the achievement should exist with title "First Win" Scenario: Update an achievement Given a fresh achievement service And an achievement is created with title "First Win" When the achievement title is updated to "Champion" Then the achievement should have title "Champion" Scenario: Delete an achievement Given a fresh achievement service And an achievement is created with title "To Delete" When the achievement is deleted Then the achievement should not exist Scenario: List achievements Given a fresh achievement service And an achievement is created with title "Win 1" And an achievement is created with title "Win 5" Then the achievements page should have 2 total achievements

Feature: Consumable management

Scenario: Create a consumable Given a fresh consumable service When a consumable is created with title "XP Boost" and type "exp" and value 100 Then the consumable should exist with title "XP Boost" Scenario: Apply EXP consumable to user Given a fresh consumable service And a registered user exists And a consumable is created with title "XP Boost" and type "exp" and value 50 When the consumable is applied to the user Then the user should have 50 exp Scenario: Apply VBalance consumable to user Given a fresh consumable service And a registered user exists And a consumable is created with title "Balance Boost" and type "v_balance" and value 25 When the consumable is applied to the user Then the user v_balance should have increased Scenario: Delete a consumable Given a fresh consumable service And a consumable is created with title "To Remove" and type "exp" and value 10 When the consumable is deleted Then the consumable should not exist

Feature: Market data

Scenario: Get asset price after setting it Given BTCUSDT price is set to 95000.0 Then the market should return BTCUSDT price of 95000.0 Scenario: Price changes propagate Given BTCUSDT price is set to 50000.0 When BTCUSDT price changes to 55000.0 Then the market should return BTCUSDT price of 55000.0 Scenario: Multiple assets tracked independently Given BTCUSDT price is set to 95000.0 And ETHUSDT price is set to 3500.0 Then the market should return BTCUSDT price of 95000.0 And the market should return ETHUSDT price of 3500.0

Feature: Notification system

Scenario: OTP email is captured on auth request Given a fresh auth service When user "test@test.com" requests an OTP Then an OTP email should have been sent to "test@test.com" Scenario: In-app notifications are recorded Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT When player A joins the match Then notifications should have been sent Scenario: Notification count tracks correctly Given a game template with entry_fee 0 and reward 0 and duration "5m" And admin creates a match room from the game And player A has a wallet with 50 USDT And player B has a wallet with 50 USDT And player A joins the match And player B joins the match Then the notification count should be greater than 0

Test Harness

The BDD tests use a standalone harness (test/bdd/standalone/) with:

  • In-memory SQLite (cache=shared) for database
  • MockMarket — channel-based price feed simulation
  • NotificationRecorder — captures notifications + OTP emails for assertions
  • redismock — in-memory Redis mock for auth OTP flow
  • gomock — mocks for Solana HD wallet, sequence counter, webshare, etc.
  • No external services — no NATS, Redis, Postgres, Binance, Temporal required

Each scenario gets a fresh database and isolated state via context.WithValue.

Last updated on