mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
71 lines
3.0 KiB
Go
71 lines
3.0 KiB
Go
package core
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
// VNC 会话生命周期的**前向引用**判据(真实 bug 的守卫)。
|
||
//
|
||
// `sweepSessions` 里调用了 reapLoopback / browserStack / reapBrowser,而这三个
|
||
// 助手定义在**更后面**。Lua 的 `local` 只从定义处向后可见 ⇒ 未前向声明时它们是
|
||
// **全局 nil**:加载期不报错,只有真正走到"会话过期回收"那条分支才炸:
|
||
//
|
||
// attempt to call global 'reapLoopback' (a nil value)
|
||
//
|
||
// 症状极具迷惑性:**第一次登录完全正常**(没有过期会话可回收),第二次才 500,
|
||
// 且已经起来的浏览器栈**不会被回收**(reapBrowser 同样调不到)⇒ 进程与端口泄漏。
|
||
// 本文件此前已因同一个坑踩过 12 次,故这里钉住"三者都必须有前向声明"。
|
||
func TestSweepSessionsHelpersAreForwardDeclared(t *testing.T) {
|
||
b, err := readBundledChannels(t)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
// ① 必须存在对这三个助手的前向声明
|
||
if !strings.Contains(b, "local reapLoopback, browserStack, reapBrowser") {
|
||
t.Fatal("sweepSessions 用到的三个助手必须**前向声明** —— 否则 " +
|
||
"`local` 只从定义处向后可见,运行到该分支时是 nil 调用(第一次登录" +
|
||
"正常、第二次 500,且浏览器栈不会被回收)")
|
||
}
|
||
// ② 定义处必须是**赋值**形态(绑定到那个 local),不能又是 `local function`
|
||
// —— 那会遮蔽前向声明,效果与没声明完全相同。
|
||
for _, fn := range []string{"browserStack", "reapBrowser", "reapLoopback"} {
|
||
if strings.Contains(b, "local function "+fn+"(") {
|
||
t.Errorf("%s 的定必须是 `%s = function(...)` 形式(绑定前向声明);"+
|
||
"再用 `local function` 会另起一个 local,前向声明形同虚设", fn, fn)
|
||
}
|
||
if !strings.Contains(b, "\n"+fn+" = function(") {
|
||
t.Errorf("找不到 %s 的赋值式定义", fn)
|
||
}
|
||
}
|
||
// ③ 声明必须**先于**使用(行号比较):这是前向引用的核心
|
||
decl := strings.Index(b, "local reapLoopback, browserStack, reapBrowser")
|
||
use := strings.Index(b, "\n reapLoopback(id)\n")
|
||
if decl < 0 || use < 0 {
|
||
t.Fatalf("找不到声明(%d)或使用(%d)", decl, use)
|
||
}
|
||
if decl > use {
|
||
t.Error("前向声明必须在**使用之前** —— 否则 nil 调用")
|
||
}
|
||
}
|
||
|
||
// 浏览器栈的**启动后存活**必须有真实判据(谎报"就绪"比直接报错更坏)。
|
||
func TestBrowserStackVerifiesLivenessNotJustPort(t *testing.T) {
|
||
b, err := readBundledChannels(t)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
// CDP 真应答(端口在听 ≠ 服务可用)
|
||
if !strings.Contains(b, "browserUtil.cdpAlive") {
|
||
t.Error("必须用 CDP 真应答判活,不能只看端口")
|
||
}
|
||
// 进程真存活
|
||
if !strings.Contains(b, "/proc/") {
|
||
t.Error("必须检查 chromium 进程仍存活(/proc/<pid>)")
|
||
}
|
||
// 失败要把日志真因带出来(而不是一句"启动失败")
|
||
if !strings.Contains(b, "browserUtil.readTail") {
|
||
t.Error("启动失败必须带出日志真因")
|
||
}
|
||
}
|