test: add queue test suite with 8 cases (cooldown, join, leave, snapshot)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
21f9650585
commit
6144fa7910
@@ -0,0 +1,140 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
// Mock orchestrator
|
||||
vi.mock('./orchestrator.js', () => ({
|
||||
runFightAsync: vi.fn().mockResolvedValue('fight-123'),
|
||||
isInFight: vi.fn().mockReturnValue(false),
|
||||
getActiveFightId: vi.fn().mockReturnValue(null),
|
||||
}))
|
||||
|
||||
// Mock mock.ts
|
||||
vi.mock('./mock.js', () => ({
|
||||
seedMockBots: vi.fn().mockResolvedValue(undefined),
|
||||
}))
|
||||
|
||||
// Mock db
|
||||
const mockBotRows = vi.fn()
|
||||
vi.mock('../db/index.js', () => ({
|
||||
db: {
|
||||
select: () => ({
|
||||
from: () => ({
|
||||
where: () => ({
|
||||
limit: () => mockBotRows(),
|
||||
}),
|
||||
// For matchAgainstMock's full select (no where clause on this chain)
|
||||
}),
|
||||
}),
|
||||
},
|
||||
schema: {
|
||||
bots: {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
secretHash: 'secretHash',
|
||||
webhookUrl: 'webhookUrl',
|
||||
eloRating: 'eloRating',
|
||||
isActive: 'isActive',
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
const { joinQueue, leaveQueue, getQueueSize, getQueueSnapshot, setCooldown } = await import('./queue.js')
|
||||
const { isInFight } = await import('./orchestrator.js')
|
||||
|
||||
const mockBot = (id: string, name = 'TestBot', elo = 1200) => [{
|
||||
id,
|
||||
name,
|
||||
webhookUrl: 'https://example.com/webhook',
|
||||
eloRating: elo,
|
||||
isActive: true,
|
||||
secretHash: 'abc',
|
||||
ownerPubkey: 'pub123',
|
||||
wins: 0,
|
||||
losses: 0,
|
||||
draws: 0,
|
||||
winStreak: 0,
|
||||
createdAt: new Date().toISOString(),
|
||||
}]
|
||||
|
||||
describe('queue', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
// Drain queue
|
||||
while (getQueueSize() > 0) {
|
||||
const snap = getQueueSnapshot()
|
||||
if (snap[0]) leaveQueue(snap[0].botId)
|
||||
}
|
||||
})
|
||||
|
||||
it('getQueueSize returns 0 when empty', () => {
|
||||
expect(getQueueSize()).toBe(0)
|
||||
})
|
||||
|
||||
it('setCooldown prevents joining during cooldown', async () => {
|
||||
mockBotRows.mockResolvedValue(mockBot('bot-cool'))
|
||||
setCooldown('bot-cool')
|
||||
|
||||
await expect(joinQueue('bot-cool')).rejects.toThrow('Cooldown active')
|
||||
})
|
||||
|
||||
it('prevents bot already in fight from joining', async () => {
|
||||
mockBotRows.mockResolvedValue(mockBot('bot-fighting'))
|
||||
vi.mocked(isInFight).mockReturnValueOnce(true)
|
||||
|
||||
await expect(joinQueue('bot-fighting')).rejects.toThrow('already in a fight')
|
||||
})
|
||||
|
||||
it('throws for non-existent bot', async () => {
|
||||
mockBotRows.mockResolvedValue([])
|
||||
|
||||
await expect(joinQueue('nonexistent')).rejects.toThrow('Bot not found')
|
||||
})
|
||||
|
||||
it('throws for deactivated bot', async () => {
|
||||
const bot = mockBot('bot-inactive')
|
||||
bot[0].isActive = false
|
||||
mockBotRows.mockResolvedValue(bot)
|
||||
|
||||
await expect(joinQueue('bot-inactive')).rejects.toThrow('deactivated')
|
||||
})
|
||||
|
||||
it('leaveQueue returns false for unknown bot', () => {
|
||||
expect(leaveQueue('not-in-queue')).toBe(false)
|
||||
})
|
||||
|
||||
it('getQueueSnapshot returns queued bot info', async () => {
|
||||
mockBotRows.mockResolvedValue(mockBot('bot-snap', 'SnapBot', 1400))
|
||||
|
||||
// joinQueue will wait in queue since no opponent — don't await
|
||||
const promise = joinQueue('bot-snap')
|
||||
|
||||
// Flush microtasks so the async DB query resolves and bot enters queue
|
||||
await new Promise(r => setTimeout(r, 0))
|
||||
|
||||
const snap = getQueueSnapshot()
|
||||
expect(snap.length).toBe(1)
|
||||
expect(snap[0].botId).toBe('bot-snap')
|
||||
expect(snap[0].botName).toBe('SnapBot')
|
||||
expect(snap[0].eloRating).toBe(1400)
|
||||
|
||||
// Cleanup: leave queue
|
||||
leaveQueue('bot-snap')
|
||||
await promise.catch(() => {}) // swallow 'Left queue' rejection
|
||||
})
|
||||
|
||||
it('leaveQueue removes bot and returns true', async () => {
|
||||
mockBotRows.mockResolvedValue(mockBot('bot-leave'))
|
||||
|
||||
const promise = joinQueue('bot-leave')
|
||||
|
||||
// Flush microtasks so the async DB query resolves and bot enters queue
|
||||
await new Promise(r => setTimeout(r, 0))
|
||||
|
||||
expect(getQueueSize()).toBe(1)
|
||||
|
||||
const left = leaveQueue('bot-leave')
|
||||
expect(left).toBe(true)
|
||||
expect(getQueueSize()).toBe(0)
|
||||
|
||||
await promise.catch(() => {}) // swallow rejection
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user