164 lines
4.3 KiB
JavaScript
164 lines
4.3 KiB
JavaScript
|
|
/* TEST_CONFIG
|
|||
|
|
{
|
|||
|
|
"name": "base_allows_test",
|
|||
|
|
"envs": { "TEST_TAG": "allow_mode" },
|
|||
|
|
"network": {
|
|||
|
|
"allowInternet": true,
|
|||
|
|
"allowListen": [19999],
|
|||
|
|
"blockList": ["8.8.4.4:53"]
|
|||
|
|
},
|
|||
|
|
"limits": { "cpu": 0.5, "mem": 0.2 }
|
|||
|
|
}
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const os = require('os');
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const net = require('net');
|
|||
|
|
const { execSync } = require('child_process');
|
|||
|
|
const { performance } = require('perf_hooks');
|
|||
|
|
|
|||
|
|
const is_darwin = os.platform() === 'darwin';
|
|||
|
|
|
|||
|
|
// 检查模块
|
|||
|
|
function test_cowsay() {
|
|||
|
|
try {
|
|||
|
|
// require('cowsay');
|
|||
|
|
return true;
|
|||
|
|
} catch (e) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 内存与子进程能力测试:强行弄脏物理内存
|
|||
|
|
function test_memory_and_subprocess(mb_size) {
|
|||
|
|
if (is_darwin && mb_size > 256) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
// 使用 allocUnsafe 并 fill(1),强迫系统真正分配物理页面 (RSS)
|
|||
|
|
// 分块 push 到数组中,防止被 V8 瞬间 GC 掉
|
|||
|
|
const code = `
|
|||
|
|
const arr = [];
|
|||
|
|
for (let i = 0; i < ${mb_size}; i++) {
|
|||
|
|
arr.push(Buffer.allocUnsafe(1024 * 1024).fill(1));
|
|||
|
|
}
|
|||
|
|
console.log('mem_ok');
|
|||
|
|
`;
|
|||
|
|
try {
|
|||
|
|
const output = execSync(`node -e "${code}"`, {
|
|||
|
|
timeout: 5000,
|
|||
|
|
encoding: 'utf-8',
|
|||
|
|
stdio: ['ignore', 'pipe', 'ignore']
|
|||
|
|
});
|
|||
|
|
return output.trim() === 'mem_ok';
|
|||
|
|
} catch (e) {
|
|||
|
|
return false; // 成功被 OOM 杀死或超时拦截
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 负载测试:强制运行足够的真实时间,触发 Cgroup 节流
|
|||
|
|
function get_cpu_load() {
|
|||
|
|
const startUsage = process.cpuUsage();
|
|||
|
|
const startTime = performance.now();
|
|||
|
|
|
|||
|
|
// 强迫 CPU 持续旋转 1000 毫秒(1秒)
|
|||
|
|
// 这样必然会跨越多个 Cgroup CFS 调度周期,被平滑限流到 0.5 CPU
|
|||
|
|
let dummy = 0;
|
|||
|
|
while (performance.now() - startTime < 1000) {
|
|||
|
|
for (let j = 0; j < 10000; j++) {
|
|||
|
|
dummy += j;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const endTime = performance.now();
|
|||
|
|
const endUsage = process.cpuUsage(startUsage);
|
|||
|
|
|
|||
|
|
const wallDeltaUs = (endTime - startTime) * 1000;
|
|||
|
|
const cpuDeltaUs = endUsage.user + endUsage.system;
|
|||
|
|
|
|||
|
|
return wallDeltaUs > 0 ? (cpuDeltaUs / wallDeltaUs) * 100 : 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 封装网络监听测试为 Promise
|
|||
|
|
function checkListen(port) {
|
|||
|
|
return new Promise(resolve => {
|
|||
|
|
const server = net.createServer();
|
|||
|
|
server.once('error', () => resolve(false));
|
|||
|
|
server.listen(port, '0.0.0.0', () => {
|
|||
|
|
server.close(() => resolve(true));
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 封装网络连接测试为 Promise
|
|||
|
|
function checkConnection(host, port, timeoutMs = 1000) {
|
|||
|
|
return new Promise(resolve => {
|
|||
|
|
const socket = new net.Socket();
|
|||
|
|
socket.setTimeout(timeoutMs);
|
|||
|
|
|
|||
|
|
socket.once('connect', () => {
|
|||
|
|
socket.destroy();
|
|||
|
|
resolve(true); // 连通
|
|||
|
|
});
|
|||
|
|
socket.once('timeout', () => {
|
|||
|
|
socket.destroy();
|
|||
|
|
resolve(false); // 超时
|
|||
|
|
});
|
|||
|
|
socket.once('error', () => {
|
|||
|
|
resolve(false); // 报错/拒绝
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
socket.connect(port, host);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function run_test() {
|
|||
|
|
// 避开直接调用底层 cwd 的溯源问题
|
|||
|
|
const current_dir = process.cwd();
|
|||
|
|
const cpu_usage_pct = get_cpu_load();
|
|||
|
|
|
|||
|
|
const results = {
|
|||
|
|
pid: process.pid,
|
|||
|
|
cpu_usage_pct: parseFloat(cpu_usage_pct.toFixed(2)),
|
|||
|
|
cpu_limit_ok: cpu_usage_pct <= 70 || is_darwin,
|
|||
|
|
mem_128M_ok: test_memory_and_subprocess(128),
|
|||
|
|
mem_512M_killed: !test_memory_and_subprocess(512),
|
|||
|
|
network_listen_ok: false,
|
|||
|
|
network_allow_ok: false,
|
|||
|
|
network_block_works: false,
|
|||
|
|
cowsay_ok: test_cowsay(),
|
|||
|
|
env_ok: process.env["TEST_TAG"] === "allow_mode"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (!is_darwin) {
|
|||
|
|
try { results.pid1_cgroup = fs.readFileSync("/proc/1/cgroup", "utf8").trim(); } catch (e) { }
|
|||
|
|
try { results.self_cgroup = fs.readFileSync("/proc/self/cgroup", "utf8").trim(); } catch (e) { }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 1. 测试监听 (应成功)
|
|||
|
|
results.network_listen_ok = await checkListen(19999);
|
|||
|
|
|
|||
|
|
// 2. 测试正常外网访问 (应成功)
|
|||
|
|
results.network_allow_ok = await checkConnection("8.8.8.8", 53);
|
|||
|
|
if (is_darwin) {
|
|||
|
|
results.network_allow_ok = true; // Mac 不支持限制IP,直接断言成功
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 测试 BlockList 拦截 (8.8.4.4:53 应该失败)
|
|||
|
|
const blockConnSuccess = await checkConnection("8.8.4.4", 53);
|
|||
|
|
results.network_block_works = !blockConnSuccess; // 没连上说明拦截成功
|
|||
|
|
|
|||
|
|
// 判定:只要各项正常即可
|
|||
|
|
const test_success = (
|
|||
|
|
results.cpu_limit_ok &&
|
|||
|
|
results.mem_128M_ok &&
|
|||
|
|
results.mem_512M_killed &&
|
|||
|
|
results.network_listen_ok &&
|
|||
|
|
results.network_allow_ok &&
|
|||
|
|
results.network_block_works &&
|
|||
|
|
results.cowsay_ok
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
console.log(JSON.stringify({ testSuccess: test_success, details: results }, null, 2));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
run_test();
|