端到端驗證:全新安裝真的跑得起同步引擎(自己驗,不推給 leo)
自走警察點破:我把「在 Windows 全新裝一次確認」推給 leo,但這件事我自己驗得了。
新增 `TestFreshInstallCollectorStarts`:
全新 HOME → App 的 saveCfg 存 config → **編出真正的執行檔、用 `--collector direct
--once --dry-run` 把它自己跑起來** → 斷言不是 exit 2、輸出沒有「缺必填欄位」。
為什麼要再加這支(已經有 LoadDirectConfig 那支了):
**「函式回傳 nil」與「行程活得下去」是兩件事**——事故正是死在後者。
反向驗證(拿掉修正)重現 leo 截圖上那句一字不差的訊息:
collector direct: config 缺必填欄位:manifest
⇒ 這支不是假測試。修正放回後全套綠。
順帶修測試自身的坑:先 `go build` 再改 HOME——先改 HOME 會讓 Go 把**唯讀的**
模組快取寫進暫存目錄,測試結束清不掉(TempDir RemoveAll permission denied)。
剩下真正只有 Windows 能驗的:實機安裝後的行為(托盤/畫面),已列 CP 待辦。
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestFreshInstallCollectorStarts 端到端釘住 leo 2026-08-06 Windows 事故的完整鏈條:
|
||||
//
|
||||
// 全新安裝 → App 存 config → supervisor 用「同一支執行檔 + --collector」拉起同步引擎。
|
||||
//
|
||||
// 事故當時這條鏈在最後一步斷掉:config 少了 `manifest` ⇒ `exit status 2` ⇒ 無限重拉。
|
||||
// 上一支測試只驗到「LoadDirectConfig 讀得下去」;這支**真的把執行檔跑起來**,
|
||||
// 因為「函式回傳 nil」與「行程活得下去」是兩件事——事故就是死在後者。
|
||||
//
|
||||
// 用 --once --dry-run:只走到解析設定就收工,不 POST、不寫 manifest,不動到真資料。
|
||||
func TestFreshInstallCollectorStarts(t *testing.T) {
|
||||
// 🔴 先編再改 HOME:把 HOME 指到暫存目錄後才 `go build`,Go 會把**唯讀的**模組快取
|
||||
// 寫進那個目錄,測試結束清不掉(實撞:TempDir RemoveAll permission denied)。
|
||||
bin := filepath.Join(t.TempDir(), "arcrun-app-test")
|
||||
if out, err := exec.Command("go", "build", "-o", bin, ".").CombinedOutput(); err != nil {
|
||||
t.Fatalf("編不出執行檔:%v\n%s", err, out)
|
||||
}
|
||||
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
|
||||
cfg := &directConfig{
|
||||
Accounts: []accountCfg{{
|
||||
CypherURL: "https://example.workers.dev",
|
||||
Namespace: "abc123",
|
||||
APIKey: "abc123",
|
||||
}},
|
||||
Extractor: "workers-ai",
|
||||
}
|
||||
if err := saveCfg(cfg); err != nil {
|
||||
t.Fatalf("存檔失敗:%v", err)
|
||||
}
|
||||
|
||||
// 用剛才編好的執行檔自己當 collector 跑(=supervisor 在真機上做的事)
|
||||
cmd := exec.Command(bin, collectorModeFlag, "direct", "--once", "--dry-run", "--config", configPath())
|
||||
cmd.Env = append(os.Environ(), "HOME="+home, "USERPROFILE="+home)
|
||||
out, err := cmd.CombinedOutput()
|
||||
|
||||
code := 0
|
||||
if ee, ok := err.(*exec.ExitError); ok {
|
||||
code = ee.ExitCode()
|
||||
} else if err != nil {
|
||||
t.Fatalf("跑不起來:%v", err)
|
||||
}
|
||||
|
||||
if code == 2 {
|
||||
t.Fatalf("同步引擎以 exit status 2 結束=設定被拒,就是 leo 撞到的無限重試。\n輸出:%s", out)
|
||||
}
|
||||
if strings.Contains(string(out), "缺必填欄位") {
|
||||
t.Fatalf("設定仍缺必填欄位:%s", out)
|
||||
}
|
||||
t.Logf("✅ 全新安裝的設定,同步引擎吃得下去(exit=%d)", code)
|
||||
}
|
||||
Reference in New Issue
Block a user