라이브 티커 · 갤럭시 검색 색인 · 주간 랭킹 스냅샷 · 연속 ZAP 상한 · 가입 행성 Zap · 성운 목표 · 랭킹 갱신 안내 · 행성 터치 반응
This commit is contained in:
@@ -160,7 +160,7 @@ it('fn-pop-spend 는 Zap 만 받고 횟수를 서버가 세며 Zap 한 가입
|
||||
const { fnPopSpend } = await import('../src/ledger/pop.js');
|
||||
const run = (data: Record<string, unknown>) => fnPopSpend.run(
|
||||
{ data, auth: { uid, token: {} } } as Parameters<typeof fnPopSpend.run>[0]);
|
||||
await db.doc('config/policy').set({ zapPop: 10 }, { merge: true });
|
||||
await db.doc('config/policy').set({ zapPop: 10, zapMinIntervalMs: 0 }, { merge: true });
|
||||
await grantPop({ uid, popType: 'activity', amount: 100, reasonCode: 'ADMIN_GRANT', idempotencyKey: 'zap:seed' });
|
||||
|
||||
await expect(run({ popType: 'activity', amount: 10, reasonCode: 'CAMPAIGN_FUND', idempotencyKey: 'zap:h1' }))
|
||||
@@ -192,3 +192,22 @@ it('fn-pop-spend 는 Zap 만 받고 횟수를 서버가 세며 Zap 한 가입
|
||||
await db.recursiveDelete(db.collection(`fandoms/${a}/fpiEvents`));
|
||||
await db.recursiveDelete(db.collection(`fandoms/${b}/fpiEvents`));
|
||||
});
|
||||
|
||||
it('연속 ZAP Rate Limit — 한 호출 상한 · 호출 간격(운영값, FX §3)', async () => {
|
||||
const db = getFirestore();
|
||||
const { fnPopSpend } = await import('../src/ledger/pop.js');
|
||||
const run = (data: Record<string, unknown>) => fnPopSpend.run(
|
||||
{ data, auth: { uid, token: {} } } as Parameters<typeof fnPopSpend.run>[0]);
|
||||
await db.doc('config/policy').set({ zapPop: 10, zapMaxPerCall: 3, zapMinIntervalMs: 60_000 }, { merge: true });
|
||||
await grantPop({ uid, popType: 'activity', amount: 100, reasonCode: 'ADMIN_GRANT', idempotencyKey: 'rl:seed' });
|
||||
await expect(run({ popType: 'activity', amount: 40, reasonCode: 'ZAP_CONTRIBUTION', idempotencyKey: 'rl:4' }))
|
||||
.rejects.toMatchObject({ details: { code: 'E-QST-02' } });
|
||||
await run({ popType: 'activity', amount: 30, reasonCode: 'ZAP_CONTRIBUTION', idempotencyKey: 'rl:1' });
|
||||
// 같은 요청의 재시도는 간격에 걸리지 않는다(멱등).
|
||||
await run({ popType: 'activity', amount: 30, reasonCode: 'ZAP_CONTRIBUTION', idempotencyKey: 'rl:1' });
|
||||
await expect(run({ popType: 'activity', amount: 10, reasonCode: 'ZAP_CONTRIBUTION', idempotencyKey: 'rl:2' }))
|
||||
.rejects.toMatchObject({ details: { code: 'E-QST-02' } });
|
||||
expect((await db.doc(`users/${uid}/wallet/main`).get()).get('activityBalance')).toBe(70);
|
||||
await db.doc('config/policy').set({ zapMaxPerCall: 50, zapMinIntervalMs: 400 }, { merge: true });
|
||||
await db.recursiveDelete(db.collection(`fandoms/${a}/fpiEvents`));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user