Files
Genarrative/scripts/spacetime-editor-idempotency-smoke.test.ts
T
suzmii bf63766d88 给 SpacetimeDB 冒烟用例的杀进程断言加局部有界超时:只改这一条,不动全局预算
- spacetime-editor-idempotency-smoke.test.ts:terminates a live standalone-shaped child process 补第三参 20_000,并加注释写明这是负载敏感的局部超时。
- 性质说明:这是局部有界超时,不是放宽判据。断言 child.exitCode !== null || child.signalCode !== null 一字未动,全局 testTimeout 与 maxThreads 也未动。
- 为什么不加注入桩:该用例的存在意义就是验真实杀进程路径(spawn 真实常驻 node → stopStandalone → Windows 上 spawn taskkill /PID /T /F 杀进程树并等退出)。加桩等于把被测对象换掉,比放宽断言更隐蔽,因此明确不采用注入桩。
- 为什么需要:这两个真实进程的启动与回收在全并行负载下会明显超过默认 5000ms;单独跑实测 167ms,全仓并行时曾撞满 5000ms 上限。
- 上限仍具约束力:stopStandalone 自身对 SIGTERM → SIGKILL 只有 5s 有界等待,而 runTaskKill 与 SIGKILL 之后的 once(child, 'exit') 都没有内部超时,20s 外层上限仍能抓住真实挂死。
- 已实测第三参在当前 vitest 0.34.6 生效:临时把该值改成 1 时复现 Test timed out in 1ms,改回 20_000 后该文件 4 passed。
2026-09-10 20:00:58 +08:00

89 lines
2.7 KiB
TypeScript

import { spawn } from 'node:child_process';
import { describe, expect, it } from 'vitest';
import {
parseProcedureOutput,
parseSqlRows,
sanitizeDiagnostic,
stopStandalone,
} from './spacetime-editor-idempotency-smoke.mjs';
describe('SpacetimeDB editor idempotency smoke parsers', () => {
it('parses successful and failed procedure SATS results', () => {
expect(
parseProcedureOutput(
'[true,[0,["project-a","owner-a"]],[1,[]]]',
'create_editor_project_and_return',
),
).toEqual({
ok: true,
record: ['project-a', 'owner-a'],
errorMessage: null,
});
expect(
parseProcedureOutput(
'[false,[1,[]],[0,"幂等创建冲突"]]',
'create_editor_project_and_return',
),
).toEqual({
ok: false,
record: null,
errorMessage: '幂等创建冲突',
});
expect(
parseProcedureOutput(
'[true,[1,[]],[0,["receipt-owner",[],[]]],[1,[]]]',
'delete_editor_asset_folder_and_return',
),
).toEqual({
ok: true,
record: ['receipt-owner', [], []],
errorMessage: null,
});
});
it('parses only the rows from one JSON SQL statement', () => {
const stdout = JSON.stringify([
{
schema: { elements: [{ name: 'project_id' }] },
rows: [['project-a'], ['project-b']],
total_duration_micros: 12,
},
]);
expect(parseSqlRows(stdout, 'projects')).toEqual([
['project-a'],
['project-b'],
]);
expect(() => parseSqlRows('[]', 'projects')).toThrow(
'invalid result shape',
);
});
it('redacts an isolated CLI token from diagnostics', () => {
expect(sanitizeDiagnostic('failed token-private', ['token-private'])).toBe(
'failed [redacted]',
);
});
});
describe('SpacetimeDB editor idempotency smoke cleanup', () => {
// 本用例真会拉起真实子进程:spawn 一个常驻 node,再由 stopStandalone 在 Windows 上
// spawn taskkill /PID /T /F 杀进程树并等退出。全并行负载下这两个真实进程的启动与回收
// 会明显超过 vitest 默认的 5000ms,因此只给这一条设局部有界超时,不动全局 testTimeout
// 与 maxThreads。这里不加注入桩:本用例的意义就是验真实杀进程路径,加桩等于换掉被测对象。
// stopStandalone 自身对 SIGTERM → SIGKILL 只有 5s 有界等待,20s 外层上限仍能抓住真实挂死。
it('terminates a live standalone-shaped child process', async () => {
const child = spawn(
process.execPath,
['-e', 'setInterval(() => {}, 1000)'],
{ stdio: 'ignore' },
);
await stopStandalone(child);
expect(child.exitCode !== null || child.signalCode !== null).toBe(true);
}, 20_000);
});