memory-store.test.js 1.96 KB
import { describe, it, expect } from 'vitest'
import { createMemoryStore } from '../src/memory-store.js'

const rule = { endpoint: 'llm', by: 'ip', capacity: 2, refillPerSec: 1 }

describe('memory-store', () => {
  it('take 在 capacity 内连续放行、超限拒绝', async () => {
    const store = createMemoryStore()
    const a = await store.take('k', 1, rule, 0)
    const b = await store.take('k', 1, rule, 0)
    const c = await store.take('k', 1, rule, 0)
    expect(a.allowed).toBe(true)
    expect(b.allowed).toBe(true)
    expect(c.allowed).toBe(false)
    expect(c.retryAfterMs).toBeGreaterThan(0)
  })

  it('时间推进后恢复放行', async () => {
    const store = createMemoryStore()
    await store.take('k', 1, rule, 0)
    await store.take('k', 1, rule, 0)
    expect((await store.take('k', 1, rule, 0)).allowed).toBe(false)
    // 1s 后补 1 个
    expect((await store.take('k', 1, rule, 1000)).allowed).toBe(true)
  })

  it('peek 不消耗令牌', async () => {
    const store = createMemoryStore()
    await store.take('k', 1, rule, 0) // 剩 1
    const p1 = await store.peek('k', rule, 0)
    const p2 = await store.peek('k', rule, 0)
    expect(p1.remaining).toBe(1)
    expect(p2.remaining).toBe(1)
    // peek 后仍能再 take 1 次成功
    expect((await store.take('k', 1, rule, 0)).allowed).toBe(true)
  })

  it('并发顺序调用不超发(同步原子,不超过 capacity)', async () => {
    const store = createMemoryStore()
    const results = await Promise.all(
      Array.from({ length: 5 }, () => store.take('k', 1, rule, 0)),
    )
    const allowed = results.filter((r) => r.allowed).length
    expect(allowed).toBe(2) // 恰好 capacity 个
  })

  it('不同 key 互不串桶', async () => {
    const store = createMemoryStore()
    await store.take('a', 1, rule, 0)
    await store.take('a', 1, rule, 0)
    expect((await store.take('a', 1, rule, 0)).allowed).toBe(false)
    expect((await store.take('b', 1, rule, 0)).allowed).toBe(true)
  })
})