// 已读取AGENTS.md import * as fs from 'fs'; import * as path from 'path'; /** * 性能回归闸门: * - 不允许无界内存缓存; * - 收益走势不得按天/周/月逐条查询; * - 活动列表参与者不得全表扫描; * - 外部地理编码不得串行阻塞; * - 索引定义必须与真实字段一致。 */ describe('性能与内存回归闸门', () => { const root = path.resolve(__dirname, '../../'); const read = (rel: string) => fs.readFileSync(path.join(root, rel), 'utf-8'); const repo = read('server/src/db/repository.ts'); const mysql = read('server/src/db/mysql.ts'); const indexCode = read('server/src/index.ts'); it('不得保留只写不读的无界 verifyCodeCache', () => { expect(repo).not.toContain('verifyCodeCache'); }); it('大神收益走势必须使用 GROUP BY 聚合,而不是按天/周/月逐条查询', () => { const start = repo.indexOf('async getExpertRevenueTrends('); const block = repo.slice(start, start + 6000); expect(block).toContain('GROUP BY d'); expect(block).toContain('GROUP BY bucket'); expect(block).toContain('GROUP BY ym'); }); it('活动列表参与者必须按当前页活动 id 查询', () => { expect(repo).toContain('WHERE p.activity_id IN (?)'); }); it('派单池地理编码必须并行,避免串行等待外部接口', () => { expect(indexCode).toContain('Promise.allSettled(missing.map'); }); it('提现索引必须使用真实存在的 apply_time,而不是不存在的 created_at', () => { expect(mysql).toContain("['withdrawals', 'idx_wd_status_apply', 'status, apply_time']"); expect(mysql).toContain("['withdrawals', 'idx_wd_companion_apply', 'companion_id, apply_time']"); expect(mysql).not.toContain("['withdrawals', 'idx_wd_status_created', 'status, created_at']"); }); it('关键列表查询必须有组合索引', () => { for (const v of [ "['orders', 'idx_orders_buyer_created', 'buyer_id, created_at']", "['orders', 'idx_orders_claimed_created', 'claimed_by, created_at']", "['activities', 'idx_act_pay_created', 'pay_type, created_at']", "['participants', 'idx_activity_created', 'activity_id, created_at']", "['user_notifications', 'idx_notif_user_created', 'user_id, created_at, id']", "['posts', 'idx_posts_top_created', 'is_top, created_at']", ]) { expect(mysql).toContain(v); } }); it('数据库连接池必须可通过环境变量调优,并有排队上限', () => { expect(mysql).toContain('MYSQL_CONNECTION_LIMIT'); expect(mysql).toContain('MYSQL_QUEUE_LIMIT'); }); });