mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
60 lines
2.7 KiB
Go
60 lines
2.7 KiB
Go
package core
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// VNC 一直白屏的真因(2026-10-14 定位)。
|
||
//
|
||
// 生产 unit 加固过,其中 `SystemCallFilter=@system-service` 会挡住 chromium
|
||
// **独立 GPU 进程**启动所需的系统调用 ⇒ 它起不来 ⇒ chromium 放弃并退出:
|
||
//
|
||
// ERROR:gpu_process_host.cc] GPU process launch failed: error_code=1002
|
||
// FATAL:gpu_data_manager_impl_private.cc] GPU process isn't usable. Goodbye.
|
||
//
|
||
// 整个 chromium 几秒内退出 ⇒ **VNC 上永远白屏**,而插件因为只等 CDP 端口就报
|
||
// 「已就绪」,把白屏谎报成成功。
|
||
//
|
||
// 为什么长期没发现:手工在**沙箱外**跑同一条命令每次都成功。定位靠
|
||
// `systemd-run` 逐 directive 二分 —— 只有 SystemCallFilter 与 ProtectSystem
|
||
// 能复现,其余加固项无影响。
|
||
//
|
||
// 修法:`--in-process-gpu`(GPU 逻辑跑在浏览器进程内,不 fork)。
|
||
func TestBrowserStackUsesInProcessGPU(t *testing.T) {
|
||
b, err := readBundledChannels(t)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
// ① 必须带 --in-process-gpu,否则在加固环境下浏览器起不来
|
||
if !strings.Contains(b, "--in-process-gpu") {
|
||
t.Fatal("chromium 命令行必须带 --in-process-gpu —— 否则在 " +
|
||
"SystemCallFilter=@system-service 的加固环境下 GPU 进程起不来、" +
|
||
"浏览器自杀、VNC 永远白屏(真实事故,2026-10-14)")
|
||
}
|
||
// ② 必须给可写的 HOME/XDG:ProtectHome=yes 下 /root 只读,
|
||
// chromium 建 dconf/ibus 目录会持续刷 permission denied 噪声
|
||
for _, k := range []string{"XDG_CACHE_HOME=", "XDG_CONFIG_HOME="} {
|
||
if !strings.Contains(b, k) {
|
||
t.Errorf("chromium 命令行应设置 %s(加固环境下 /root 只读会产生噪声日志)", k)
|
||
}
|
||
}
|
||
// ③ **存活探针**必须存在:端口在听 ≠ 浏览器可用。
|
||
// 没有它时,"浏览器已死"会被谎报成"已就绪",运维打开 VNC 是白屏,
|
||
// 还会以为是自己操作的问题。谎报比直接报错更坏。
|
||
if !strings.Contains(b, "browserUtil.cdpAlive") {
|
||
t.Error("起栈后必须做 CDP 存活探针 —— 只等端口就报就绪会把白屏谎报成成功")
|
||
}
|
||
if !strings.Contains(b, "browserUtil.readTail") {
|
||
t.Error("启动失败必须把日志真因带给用户,而不是一句「启动失败」")
|
||
}
|
||
// ④ 失败必须回收整组进程(否则每次失败都留一套 Xvfb/x11vnc/websockify)
|
||
idx := strings.Index(b, "浏览器启动后即退出")
|
||
if idx < 0 {
|
||
t.Fatal("应有「浏览器启动后即退出」的失败分支")
|
||
}
|
||
if !strings.Contains(b[idx:idx+600], "reapBrowser()") {
|
||
t.Error("起栈失败必须先回收已起的进程(否则泄漏一套 Xvfb/x11vnc/websockify)")
|
||
}
|
||
}
|