self-chat-callbacks.test.js
3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* 自唤醒回调(`selfChat`)的两条不变式。
*
* 背景:`/task/dispatch`、`/task/report`、`task/transition` 等六处都要「服务端自己给某个
* agent 发一条 chat」。它们原来各自写死 `hostname:'localhost', port: systemConfig.port`
* (3010)—— 单测把路由挂到 `app.listen(0)` 的临时端口上,回调却照样打进**线上 3010**:
* 每跑一次汇报用例就给真 CEO 发一条 chat、起一个常驻 claude CLI 子进程、留一个
* `callback-T-*` 会话目录。症状完全静默(测试全绿),只有进程数和内存在涨。
*
* 抽成 `selfChat` 之后要盯两件事:
* 1. **不许再有第二处自己拼 http.request 打 systemConfig.port** —— 那就是分叉的开始;
* 2. **不许留下 `chatReq.write(postData)` 这类孤儿调用** —— 改造时删了声明却留下调用,
* `node --check` 一样通过(是运行时 ReferenceError 不是语法错),而它在
* `setImmediate` 里抛就是未捕获异常、直接杀进程。实测这次改造就留下了两处。
*/
import { describe, it, expect } from 'vitest';
import fs from 'fs';
import path from 'path';
const FILE = path.resolve(__dirname, '../../routes/agent-chat.js');
const src = fs.readFileSync(FILE, 'utf-8');
const lines = src.split('\n');
describe('自唤醒回调', () => {
it('样本非空 —— 路径写错时不许退化成永远通过', () => {
expect(src.length).toBeGreaterThan(1000);
expect(src).toContain('function selfChat(');
});
it('chatReq / postData 只出现在 selfChat 内部,没有孤儿调用', () => {
// selfChat 的函数体范围
const start = lines.findIndex((l) => l.includes('function selfChat('));
expect(start).toBeGreaterThan(-1);
let end = start;
for (let i = start + 1; i < lines.length; i++) {
if (lines[i] === '}') { end = i; break; }
}
const offenders = [];
lines.forEach((l, i) => {
if (i >= start && i <= end) return; // 函数体内是正当用法
if (/\bchatReq\b|\bpostData\b/.test(l)) offenders.push(`${i + 1}: ${l.trim()}`);
});
expect(offenders).toEqual([]);
});
it('没有第二处自己拼 http.request 打 systemConfig.port', () => {
const start = lines.findIndex((l) => l.includes('function selfChat('));
let end = start;
for (let i = start + 1; i < lines.length; i++) {
if (lines[i] === '}') { end = i; break; }
}
const offenders = [];
lines.forEach((l, i) => {
if (i >= start && i <= end) return;
// 「自己拼端口去打自己」的形状:port: systemConfig.port
// 跳过注释行 —— selfChat 上方那段说明**引用**了这个写法来解释它为什么被换掉,
// 那是文档不是代码。第一版没跳,把注释当成漏改报了红。
if (/^\s*(\/\/|\*|\/\*)/.test(l)) return;
if (/port:\s*systemConfig\.port/.test(l)) offenders.push(`${i + 1}: ${l.trim()}`);
});
expect(offenders).toEqual([]);
});
it('测试环境必须短路 —— 否则单测会打进线上端口', () => {
expect(src).toMatch(/process\.env\.VITEST|NODE_ENV === 'test'/);
});
});