Skip to content

Testing

Strategy

Three layers, matching the proxy's architecture:

  1. Unit tests — Pure logic: key selection, auth hashing, rate limit math, circuit breaker state
  2. Integration tests — Worker running locally via wrangler dev, hitting real D1/KV (local miniflare)
  3. E2E smoke tests — Hit the deployed Worker with real team tokens, verify proxy works against upstream APIs

Running Tests

# Unit tests (fast, no network)
pnpm test

# Integration tests (starts local worker, needs wrangler)
pnpm test:integration

# E2E smoke (hits deployed worker)
KEYPOOL_URL=https://keypool.yourdomain.com TEAM_TOKEN=xxx pnpm test:e2e

Unit Tests

Use vitest (already compatible with Workers types). Test pure functions without Worker runtime:

// tests/unit/key-selector.test.ts
import { describe, it, expect } from 'vitest'

describe('key selection', () => {
  it('round-robin cycles through available keys', () => {
    // Test the selection logic with mock D1 results
  })

  it('skips keys with active circuit breakers', () => {
    // Verify circuit-broken keys are filtered
  })

  it('respects daily limits', () => {
    // Key at daily_limit should be skipped
  })
})

// tests/unit/auth.test.ts
describe('auth', () => {
  it('hashes tokens deterministically', async () => {
    // Verify SHA-256 hash matches expected output
  })

  it('extracts token from Bearer header', () => {
    // Test header parsing
  })

  it('extracts token from x-api-key header', () => {
    // Test header parsing
  })

  it('extracts token from xi-api-key header', () => {
    // Test header parsing
  })
})

Integration Tests

Use unstable_dev from wrangler to spin up a local Worker with real D1/KV bindings:

// tests/integration/proxy.test.ts
import { unstable_dev } from 'wrangler'
import { describe, it, expect, beforeAll, afterAll } from 'vitest'

describe('proxy integration', () => {
  let worker: Awaited<ReturnType<typeof unstable_dev>>

  beforeAll(async () => {
    worker = await unstable_dev('src/index.ts', {
      experimental: { disableExperimentalWarning: true },
    })
    // Seed local D1 with test data
  })

  afterAll(async () => {
    await worker.stop()
  })

  it('returns 401 without token', async () => {
    const res = await worker.fetch('/v1/exa/search', { method: 'POST' })
    expect(res.status).toBe(401)
  })

  it('returns 404 for unknown service', async () => {
    const res = await worker.fetch('/v1/nonexistent/test', {
      headers: { Authorization: 'Bearer test-token' },
    })
    expect(res.status).toBe(404) // or 503 if service not found
  })

  it('health endpoint works without auth', async () => {
    const res = await worker.fetch('/health')
    expect(res.status).toBe(200)
    const body = await res.json()
    expect(body.status).toBe('ok')
  })

  it('admin requires ADMIN_TOKEN', async () => {
    const res = await worker.fetch('/admin/status')
    expect(res.status).toBe(401)
  })
})

E2E Smoke Tests

Run against the deployed Worker with a real team token. These verify the full proxy path including upstream API calls:

// tests/e2e/smoke.test.ts
const KEYPOOL_URL = process.env.KEYPOOL_URL!
const TEAM_TOKEN = process.env.TEAM_TOKEN!

describe('e2e smoke', () => {
  it('proxies Exa search', async () => {
    const res = await fetch(`${KEYPOOL_URL}/v1/exa/search`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${TEAM_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        query: 'test query',
        num_results: 1,
      }),
    })

    expect(res.status).toBe(200)
    const body = await res.json()
    expect(body.results).toBeDefined()
    // Verify KeyPool headers are present
    expect(res.headers.get('X-KeyPool-Key-Id')).toBeTruthy()
  })

  it('proxies Firecrawl scrape', async () => {
    const res = await fetch(`${KEYPOOL_URL}/v1/firecrawl/v1/scrape`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${TEAM_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        url: 'https://example.com',
        formats: ['markdown'],
      }),
    })

    expect(res.status).toBe(200)
  })

  it('rate limits excessive requests', async () => {
    // Fire requests rapidly to trigger rate limit
    const promises = Array.from({ length: 100 }, () =>
      fetch(`${KEYPOOL_URL}/v1/exa/search`, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${TEAM_TOKEN}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ query: 'test', num_results: 1 }),
      })
    )

    const responses = await Promise.all(promises)
    const rateLimited = responses.filter((r) => r.status === 429)
    expect(rateLimited.length).toBeGreaterThan(0)
  })
})

Quick Manual Smoke Test

After deploy, run this to verify the proxy works:

# 1. Create a team token
curl -X POST https://keypool.yourdomain.com/admin/tokens \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"member_name": "test-user"}' | jq .

# 2. Save the returned token, then test proxy
curl -X POST https://keypool.yourdomain.com/v1/exa/search \
  -H "Authorization: Bearer TEAM_TOKEN_FROM_STEP_1" \
  -H "Content-Type: application/json" \
  -d '{"query": "cloudflare workers", "num_results": 1}' | jq .

# 3. Check admin status
curl https://keypool.yourdomain.com/admin/status \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN" | jq .

# 4. Check usage
curl "https://keypool.yourdomain.com/admin/usage?days=1" \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN" | jq .