forked from wangziqi/gongxue-base
test: strengthen launch smoke and capacity guardrails
This commit is contained in:
112
scripts/auto-badge-concurrency-test.js
Normal file
112
scripts/auto-badge-concurrency-test.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import pg from 'pg';
|
||||
import { autoGrantBadges } from '../apps/api/src/features/profile/badges.ts';
|
||||
|
||||
const DATABASE_URL = process.env.DATABASE_URL || 'postgresql://postgres:postgres@127.0.0.1:54322/postgres';
|
||||
const TENANT_ID = process.env.TENANT_ID || '00000000-0000-0000-0000-000000000001';
|
||||
const USER_ID = process.env.USER_ID || '00000000-0000-0000-0000-000000000101';
|
||||
const BADGE_ID = '00000000-0000-0000-0000-00000000b881';
|
||||
|
||||
const pool = new pg.Pool({ connectionString: DATABASE_URL, max: 8 });
|
||||
|
||||
async function resetFixture() {
|
||||
await pool.query(
|
||||
`
|
||||
delete from public.user_notifications
|
||||
where tenant_id = $1
|
||||
and dedupe_key = $2
|
||||
`,
|
||||
[TENANT_ID, `badge:${BADGE_ID}:user:${USER_ID}`],
|
||||
);
|
||||
await pool.query(
|
||||
`
|
||||
delete from public.user_badges
|
||||
where tenant_id = $1
|
||||
and (badge_id = $2::uuid or legacy_id = $3)
|
||||
`,
|
||||
[TENANT_ID, BADGE_ID, `auto:${BADGE_ID}:user:${USER_ID}`],
|
||||
);
|
||||
await pool.query(
|
||||
`
|
||||
delete from public.badges
|
||||
where tenant_id = $1 and id = $2::uuid
|
||||
`,
|
||||
[TENANT_ID, BADGE_ID],
|
||||
);
|
||||
await pool.query(
|
||||
`
|
||||
insert into public.badges (
|
||||
id, tenant_id, legacy_id, name, description, category, level,
|
||||
unlock_type, condition_field, condition_operator, condition_value,
|
||||
condition_extra, metadata, sort_order, is_active
|
||||
)
|
||||
values (
|
||||
$1::uuid, $2, 'integration-badge-auto-concurrency',
|
||||
'并发自动勋章烟测', '并发触发时只能发放一次', 'practice', 1,
|
||||
'practice_count', 'concurrencyGrantCount', 'gte', 1,
|
||||
'{}'::jsonb, '{"source":"auto-badge-concurrency-test"}'::jsonb, 99, true
|
||||
)
|
||||
`,
|
||||
[BADGE_ID, TENANT_ID],
|
||||
);
|
||||
}
|
||||
|
||||
async function grantOnce(index) {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('begin');
|
||||
const grants = await autoGrantBadges(client, {
|
||||
tenantId: TENANT_ID,
|
||||
userId: USER_ID,
|
||||
trigger: 'practice_count',
|
||||
evidence: {
|
||||
concurrencyGrantCount: 1,
|
||||
workerIndex: index,
|
||||
},
|
||||
});
|
||||
await client.query('commit');
|
||||
return grants;
|
||||
} catch (error) {
|
||||
await client.query('rollback').catch(() => undefined);
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await resetFixture();
|
||||
const results = await Promise.all(Array.from({ length: 20 }, (_, index) => grantOnce(index)));
|
||||
const grantedRows = results.flat().filter(item => item.badgeId === BADGE_ID);
|
||||
const count = await pool.query(
|
||||
`
|
||||
select count(*)::int as count
|
||||
from public.user_badges
|
||||
where tenant_id = $1 and user_id = $2 and badge_id = $3::uuid
|
||||
`,
|
||||
[TENANT_ID, USER_ID, BADGE_ID],
|
||||
);
|
||||
const legacyCount = await pool.query(
|
||||
`
|
||||
select count(*)::int as count
|
||||
from public.user_badges
|
||||
where tenant_id = $1 and legacy_id = $2
|
||||
`,
|
||||
[TENANT_ID, `auto:${BADGE_ID}:user:${USER_ID}`],
|
||||
);
|
||||
|
||||
assert.equal(Number(count.rows[0]?.count || 0), 1, 'concurrent auto badge grants should create one user_badges row');
|
||||
assert.equal(Number(legacyCount.rows[0]?.count || 0), 0, 'auto badge grants should not write legacy_id idempotency keys');
|
||||
assert.equal(grantedRows.length, 1, 'only one concurrent caller should receive a new grant payload');
|
||||
|
||||
console.log('Auto badge concurrency test complete.');
|
||||
} finally {
|
||||
await pool.end();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
Reference in New Issue
Block a user