Files
new-api-key-usage/apps/server/src/sync/policy.test.ts
T
skycurtain e1c6d2153e feat(server): 同步引擎与 seed(阶段 4)
- 引擎:tick(5 分钟 + 防重入 + 启动即跑)· 单轮串行遍历 active key · 日志整批单事务入库(ON CONFLICT DO NOTHING + log_synced_at 取请求发起时刻)· 额度采集(上游字段全组,独立 try)· QPU 采样(基线 / 值变化才追加)· 每轮摘要与超期 warning
- 401 状态机:N=3 摘除(disabled_source=auto_401);403/500/网络不计数;解密失败跳过不计数
- 纯逻辑抽层:policy(计数 / 合并判定)· dedupe(去重键与内容指纹)· log-row(日志映射,与 seed 共用)
- seed 脚本(幂等):假 key + 984 条日志 + QPU 基线 + 示例购买
- 实测:401 端到端 1→2→3 摘除且摘除后不再轮询;幂等重跑新增 0 条
- 实证发现:错误行 request_id 不唯一(8 组 ×3)——记入实施计划「待定问题 #5」与 upstream 文档,待作者裁决
- AGENTS.md / 根 package.json 增 seed 命令
2026-09-15 00:46:46 +08:00

80 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 401 状态机与轮次结果合并的单测(同步引擎设计 §3.4 + 实施计划「实现假设」#15)。
*/
import { describe, expect, test } from 'bun:test'
import {
combineRoundResult,
MAX_CONSECUTIVE_401S,
nextKeyCounter,
type KeyCounterNext,
} from './policy'
const active = (consecutive401s = 0): KeyCounterNext => ({
consecutive401s,
status: 'active',
disabledSource: null,
removed: false,
})
describe('combineRoundResult(两个调用合并为「本轮结果」)', () => {
test('任一 401 → unauthorized(401 优先于成功)', () => {
expect(combineRoundResult(['ok', 'unauthorized'])).toBe('unauthorized')
expect(combineRoundResult(['unauthorized', 'failed'])).toBe('unauthorized')
})
test('无 401 且任一成功 → ok', () => {
expect(combineRoundResult(['ok', 'failed'])).toBe('ok')
expect(combineRoundResult(['ok', 'ok'])).toBe('ok')
})
test('全失败 → failed(不动计数)', () => {
expect(combineRoundResult(['failed', 'failed'])).toBe('failed')
})
})
describe('nextKeyCounter(401 计数 / 摘除 / 清零)', () => {
test('成功 → 计数清零(不摘除)', () => {
const next = nextKeyCounter(active(2), 'ok')
expect(next.consecutive401s).toBe(0)
expect(next.status).toBe('active')
expect(next.removed).toBe(false)
})
test('其他失败(403/500/网络)→ 计数不动', () => {
const next = nextKeyCounter(active(1), 'failed')
expect(next.consecutive401s).toBe(1)
expect(next.removed).toBe(false)
})
test('连续 401 累加;未达阈值不摘除', () => {
let state = active(0)
for (let i = 1; i < MAX_CONSECUTIVE_401S; i++) {
const next = nextKeyCounter(state, 'unauthorized')
expect(next.consecutive401s).toBe(i)
expect(next.removed).toBe(false)
expect(next.status).toBe('active')
state = next
}
})
test('第 N 次(N=3)连续 401 → 摘除且 disabled_source = auto_401', () => {
let state: KeyCounterNext = active(0)
for (let i = 1; i <= MAX_CONSECUTIVE_401S; i++) {
state = nextKeyCounter(state, 'unauthorized')
}
expect(state.consecutive401s).toBe(MAX_CONSECUTIVE_401S)
expect(state.status).toBe('disabled')
expect(state.disabledSource).toBe('auto_401')
expect(state.removed).toBe(true)
})
test('中途成功会打断连续性(计数回零)', () => {
let state: KeyCounterNext = active(2)
state = nextKeyCounter(state, 'ok')
state = nextKeyCounter(state, 'unauthorized')
expect(state.consecutive401s).toBe(1)
expect(state.removed).toBe(false)
})
})