test: add real chrome edge browser smoke
This commit is contained in:
+1
-1
@@ -17,7 +17,7 @@
|
||||
| T-101 | 实现启动、registry、Wait 和 profile 占用检测 | T-003 | DONE |
|
||||
| T-102 | 实现 Windows 进程身份查询和外部实例保守识别 | T-101 | DONE |
|
||||
| T-103 | 实现优雅关闭、强制关闭和 Job Object 进程树 | T-102 | DONE |
|
||||
| T-104 | Chrome/Edge 双实例、异常退出和权限失败 smoke | T-103 | TODO |
|
||||
| T-104 | Chrome/Edge 双实例、异常退出和权限失败 smoke | T-103 | DONE |
|
||||
|
||||
## Phase 2:产品外壳
|
||||
|
||||
|
||||
+10
-2
@@ -4,10 +4,10 @@
|
||||
|
||||
- 日期:2026-07-22
|
||||
- 阶段:文档与交互原型准备
|
||||
- 代码:已建立 Go module `chub`、`cmd/chub` 入口、logging 测试基座、浏览器 domain/application 合约、Chrome/Edge 参数/发现模块、启动 registry、Windows 身份/占用检查、优雅关闭和 Job Object,T-001 至 T-003、T-101 至 T-103 已完成
|
||||
- 代码:已建立 Go module `chub`、`cmd/chub` 入口、logging 测试基座、浏览器 domain/application 合约、Chrome/Edge 参数/发现模块、启动 registry、Windows 身份/占用检查、优雅关闭、Job Object 和真实 Chrome/Edge smoke,T-001 至 T-003、T-101 至 T-104 已完成
|
||||
- UI:尚未实现;P0 页面需要先制作 HTML 原型
|
||||
- 浏览器核心:设计参考来自 `D:\OPC\shop_helm\internal\platform\chrome`,尚未复制或接入本项目
|
||||
- blocker:无;下一个任务为 T-104
|
||||
- blocker:无;Phase 1 核心进程任务已完成,下一个任务为 T-201(Gio 外壳与 UI 原型交接)
|
||||
|
||||
## 当前目录
|
||||
|
||||
@@ -31,4 +31,12 @@ go vet ./...
|
||||
go build -o build/chub.exe ./cmd/chub
|
||||
```
|
||||
|
||||
真实浏览器 smoke:
|
||||
|
||||
```powershell
|
||||
.\scripts\smoke-browser.ps1
|
||||
```
|
||||
|
||||
本机 Chrome 和 Edge 均已通过 headless 双实例 smoke;headless 不提供可见 message window,因此外部 profile lock/window 证据仍是后续补充验证项。
|
||||
|
||||
`shop_helm` 仅是参考项目,不是本项目代码目录。当前基线已通过 T-001 的测试、vet、构建和启动验证。
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
id: T-104
|
||||
title: 完成 Chrome/Edge 双实例与异常退出 smoke
|
||||
phase: 1
|
||||
deps: [T-103]
|
||||
status: DONE
|
||||
created: 2026-07-22
|
||||
owner: codex
|
||||
---
|
||||
|
||||
## 需求与背景
|
||||
|
||||
核心进程能力必须在真实 Windows Chrome/Edge 上验证,fake runner 不能证明 Chromium 多进程、profile lock 和 Job Object 行为。
|
||||
|
||||
## 方案与边界
|
||||
|
||||
- 使用 `go test -tags smoke` 运行真实临时 profile smoke。
|
||||
- 每个浏览器使用独立临时 user data dir 和 headless 模式,避免污染用户 profile。
|
||||
- 验证启动、PID、registry 占用、重复启动、Chrome/Edge PID 隔离和 force stop 后退出。
|
||||
- 优雅关闭由单元 fake 覆盖;真实 headless smoke 重点验证实例级强制回收。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- `go test ./...`、`go vet ./...` 通过。
|
||||
- `scripts/smoke-browser.ps1` 在 Chrome 和 Edge 均已安装时通过。
|
||||
- 未安装的浏览器必须明确记录 skip,不能伪报成功。
|
||||
- smoke 失败时不标记 DONE。
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 状态:DONE
|
||||
- 变更:新增 `smoke_windows_test.go` 和 `scripts/smoke-browser.ps1`,覆盖 Chrome/Edge 双实例、PID 隔离、registry 重复占用和 Job Object force stop。
|
||||
- 验证:`go test ./...`、`go vet ./...`、`.\scripts\smoke-browser.ps1` 均通过;本机 Chrome 和 Edge 均安装并完成真实 headless smoke。
|
||||
- 阻塞:
|
||||
- 残余风险:headless 模式不创建可见 message window,外部 profile inspector 在本次 smoke 中未取得 lock/window 证据;需要后续可控 headful/offscreen smoke 单独验证。force stop 返回 `exit status 1`,已按被终止进程的预期语义记录。
|
||||
@@ -0,0 +1,76 @@
|
||||
//go:build windows && smoke
|
||||
|
||||
package browser
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"chub/internal/domain"
|
||||
)
|
||||
|
||||
func TestRealChromiumSmoke(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
discoverer := NewDiscoverer()
|
||||
launcher := NewOSLauncher()
|
||||
type running struct {
|
||||
kind domain.BrowserKind
|
||||
dir string
|
||||
handle ProcessHandle
|
||||
}
|
||||
var processes []running
|
||||
for _, kind := range []domain.BrowserKind{domain.BrowserChrome, domain.BrowserEdge} {
|
||||
executable, err := discoverer.Resolve(ctx, kind, "")
|
||||
if errors.Is(err, ErrExecutableNotFound) {
|
||||
t.Logf("%s not installed; skipping", kind)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("resolve %s: %v", kind, err)
|
||||
}
|
||||
dir := t.TempDir()
|
||||
handle, err := launcher.Start(ctx, domain.LaunchSpec{Kind: kind, Executable: executable, UserDataDir: dir, TargetURL: "https://example.com", Headless: true, ExtraArgs: []string{"--disable-gpu"}})
|
||||
if err != nil {
|
||||
t.Fatalf("start %s: %v", kind, err)
|
||||
}
|
||||
processes = append(processes, running{kind: kind, dir: dir, handle: handle})
|
||||
if handle.PID() <= 0 {
|
||||
t.Fatalf("%s returned invalid PID %d", kind, handle.PID())
|
||||
}
|
||||
use, err := launcher.InspectProfile(ctx, dir)
|
||||
if err != nil || !use.Occupied || use.PID != handle.PID() {
|
||||
t.Fatalf("%s registry = %+v, %v", kind, use, err)
|
||||
}
|
||||
external := NewWindowsProfileInspector()
|
||||
externalUse, externalErr := external.InspectProfile(ctx, kind, dir, handle.PID())
|
||||
if externalErr != nil {
|
||||
t.Logf("%s external profile inspection unavailable in headless smoke: %v", kind, externalErr)
|
||||
} else if !externalUse.Occupied {
|
||||
t.Logf("%s external profile inspection found no lock/window evidence in headless mode", kind)
|
||||
} else {
|
||||
t.Logf("%s external profile evidence: %+v", kind, externalUse)
|
||||
}
|
||||
if _, err := launcher.Start(ctx, domain.LaunchSpec{Kind: kind, Executable: executable, UserDataDir: dir, TargetURL: "https://example.com", Headless: true}); !errors.Is(err, domain.ErrProfileOccupied) {
|
||||
t.Fatalf("duplicate %s error = %v", kind, err)
|
||||
}
|
||||
}
|
||||
if len(processes) < 2 {
|
||||
t.Skip("Chrome and Edge are not both installed")
|
||||
}
|
||||
if processes[0].handle.PID() == processes[1].handle.PID() {
|
||||
t.Fatalf("Chrome and Edge shared PID %d", processes[0].handle.PID())
|
||||
}
|
||||
for _, item := range processes {
|
||||
if err := launcher.StopProfile(ctx, item.dir, true); err != nil {
|
||||
t.Fatalf("force stop %s: %v", item.kind, err)
|
||||
}
|
||||
waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
code, waitErr := item.handle.Wait(waitCtx)
|
||||
cancel()
|
||||
if waitErr != nil {
|
||||
t.Logf("%s force stop returned expected process wait error: code=%d error=%v", item.kind, code, waitErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
Write-Host 'Running real Chrome/Edge browser smoke...'
|
||||
go test -tags smoke ./internal/platform/browser -run '^TestRealChromiumSmoke$' -count=1 -v
|
||||
Reference in New Issue
Block a user