mirror of
https://github.com/black-ant/Ant-Browser.git
synced 2026-07-14 18:48:55 +08:00
201 lines
6.4 KiB
Go
201 lines
6.4 KiB
Go
package backend
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"ant-chrome/backend/internal/browser"
|
|
"ant-chrome/backend/internal/config"
|
|
)
|
|
|
|
func TestParseRemoteDebuggingPort(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got := parseRemoteDebuggingPort(`chrome.exe --user-data-dir="D:\data\p1" --remote-debugging-port=49152`)
|
|
if got != 49152 {
|
|
t.Fatalf("expected port 49152, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestBrowserInstanceStatusRecoversRunningProfileByUserDataDir(t *testing.T) {
|
|
server := newRecordedCDPServer(t)
|
|
defer server.Close()
|
|
|
|
app := newRuntimeRecoveryTestApp(t)
|
|
profile := &BrowserProfile{
|
|
ProfileId: "recover-status",
|
|
ProfileName: "Recover Status",
|
|
UserDataDir: "recover-status",
|
|
Running: false,
|
|
}
|
|
app.browserMgr.Profiles = map[string]*BrowserProfile{profile.ProfileId: profile}
|
|
userDataDir := app.browserMgr.ResolveUserDataDir(profile)
|
|
writeDevToolsActivePort(t, userDataDir, server.Port())
|
|
|
|
snapshot, err := app.BrowserInstanceStatus(profile.ProfileId)
|
|
if err != nil {
|
|
t.Fatalf("BrowserInstanceStatus returned error: %v", err)
|
|
}
|
|
if snapshot == nil || !snapshot.Running || !snapshot.DebugReady {
|
|
t.Fatalf("expected recovered running profile, got %+v", snapshot)
|
|
}
|
|
if snapshot.DebugPort != server.Port() {
|
|
t.Fatalf("expected debug port %d, got %d", server.Port(), snapshot.DebugPort)
|
|
}
|
|
}
|
|
|
|
func TestBrowserInstanceStartRecoversRunningProfileBeforeSessionCleanup(t *testing.T) {
|
|
server := newRecordedCDPServer(t)
|
|
defer server.Close()
|
|
|
|
app := newRuntimeRecoveryTestApp(t)
|
|
profile := &BrowserProfile{
|
|
ProfileId: "recover-start",
|
|
ProfileName: "Recover Start",
|
|
UserDataDir: "recover-start",
|
|
Running: false,
|
|
}
|
|
app.browserMgr.Profiles = map[string]*BrowserProfile{profile.ProfileId: profile}
|
|
userDataDir := app.browserMgr.ResolveUserDataDir(profile)
|
|
writeDevToolsActivePort(t, userDataDir, server.Port())
|
|
|
|
snapshot, err := app.BrowserInstanceStart(profile.ProfileId)
|
|
if err != nil {
|
|
t.Fatalf("BrowserInstanceStart returned error: %v", err)
|
|
}
|
|
if snapshot == nil || !snapshot.Running || !snapshot.DebugReady {
|
|
t.Fatalf("expected recovered running profile, got %+v", snapshot)
|
|
}
|
|
if snapshot.DebugPort != server.Port() {
|
|
t.Fatalf("expected debug port %d, got %d", server.Port(), snapshot.DebugPort)
|
|
}
|
|
}
|
|
|
|
func TestPrepareBrowserLaunchContextSkipsProcessScanWhenNoActivePort(t *testing.T) {
|
|
app := newRuntimeRecoveryTestApp(t)
|
|
profile := &BrowserProfile{
|
|
ProfileId: "cold-start",
|
|
ProfileName: "Cold Start",
|
|
UserDataDir: "cold-start",
|
|
}
|
|
app.browserMgr.Profiles = map[string]*BrowserProfile{profile.ProfileId: profile}
|
|
|
|
originalFind := findBrowserUserDataProcesses
|
|
defer func() { findBrowserUserDataProcesses = originalFind }()
|
|
|
|
findCalls := 0
|
|
findBrowserUserDataProcesses = func(string) ([]browserUserDataProcess, error) {
|
|
findCalls++
|
|
return nil, nil
|
|
}
|
|
|
|
_, _, _, _, err := app.prepareBrowserLaunchContext(newBrowserStartInput(profile.ProfileId, nil, nil, false, false, false, "", ""), profile, nil)
|
|
if err != nil {
|
|
t.Fatalf("prepareBrowserLaunchContext returned error: %v", err)
|
|
}
|
|
if findCalls != 0 {
|
|
t.Fatalf("cold start should not scan browser processes, got %d calls", findCalls)
|
|
}
|
|
}
|
|
func TestPrepareBrowserLaunchContextTerminatesProcessAndRetriesSessionCleanup(t *testing.T) {
|
|
app := newRuntimeRecoveryTestApp(t)
|
|
profile := &BrowserProfile{
|
|
ProfileId: "recover-lock",
|
|
ProfileName: "Recover Lock",
|
|
UserDataDir: "recover-lock",
|
|
}
|
|
app.browserMgr.Profiles = map[string]*BrowserProfile{profile.ProfileId: profile}
|
|
userDataDir := app.browserMgr.ResolveUserDataDir(profile)
|
|
sessionsDir := filepath.Join(userDataDir, "Default", "Sessions")
|
|
if err := os.MkdirAll(sessionsDir, 0o755); err != nil {
|
|
t.Fatalf("create sessions dir failed: %v", err)
|
|
}
|
|
|
|
originalFind := findBrowserUserDataProcesses
|
|
originalTerminate := terminateBrowserUserDataProcess
|
|
originalClear := clearBrowserSessionRestoreData
|
|
defer func() {
|
|
findBrowserUserDataProcesses = originalFind
|
|
terminateBrowserUserDataProcess = originalTerminate
|
|
clearBrowserSessionRestoreData = originalClear
|
|
}()
|
|
|
|
findBrowserUserDataProcesses = func(string) ([]browserUserDataProcess, error) {
|
|
return []browserUserDataProcess{{PID: 4321}}, nil
|
|
}
|
|
terminatedPID := 0
|
|
terminateBrowserUserDataProcess = func(pid int, timeout time.Duration) error {
|
|
terminatedPID = pid
|
|
return nil
|
|
}
|
|
clearCalls := 0
|
|
clearBrowserSessionRestoreData = func(string) error {
|
|
clearCalls++
|
|
if clearCalls == 1 {
|
|
return errors.New("remove sessions dir: locked")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
_, _, _, _, err := app.prepareBrowserLaunchContext(newBrowserStartInput(profile.ProfileId, nil, nil, false, false, false, "", ""), profile, nil)
|
|
if err != nil {
|
|
t.Fatalf("prepareBrowserLaunchContext returned error: %v", err)
|
|
}
|
|
if terminatedPID != 4321 {
|
|
t.Fatalf("expected terminating pid 4321, got %d", terminatedPID)
|
|
}
|
|
if clearCalls != 2 {
|
|
t.Fatalf("expected session cleanup to be retried once, got %d calls", clearCalls)
|
|
}
|
|
}
|
|
|
|
func newRuntimeRecoveryTestApp(t *testing.T) *App {
|
|
t.Helper()
|
|
|
|
appRoot := t.TempDir()
|
|
cfg := config.DefaultConfig()
|
|
cfg.Browser.UserDataRoot = "data"
|
|
cfg.Browser.RestoreLastSession = false
|
|
exePath := createRuntimeRecoveryFakeBrowserExecutable(t, appRoot)
|
|
cfg.Browser.Cores = []config.BrowserCore{
|
|
{CoreId: "runtime-recovery-core", CoreName: "Runtime Recovery Core", CorePath: exePath, IsDefault: true},
|
|
}
|
|
|
|
app := NewApp(appRoot)
|
|
app.config = cfg
|
|
app.browserMgr = browser.NewManager(cfg, appRoot)
|
|
app.browserMgr.Profiles = make(map[string]*BrowserProfile)
|
|
app.browserMgr.BrowserProcesses = make(map[string]*exec.Cmd)
|
|
return app
|
|
}
|
|
|
|
func createRuntimeRecoveryFakeBrowserExecutable(t *testing.T, appRoot string) string {
|
|
t.Helper()
|
|
|
|
path := filepath.Join(appRoot, "chrome", "chrome.exe")
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
t.Fatalf("create fake browser dir failed: %v", err)
|
|
}
|
|
if err := os.WriteFile(path, []byte("fake"), 0o644); err != nil {
|
|
t.Fatalf("write fake browser failed: %v", err)
|
|
}
|
|
return filepath.Dir(path)
|
|
}
|
|
|
|
func writeDevToolsActivePort(t *testing.T, userDataDir string, debugPort int) {
|
|
t.Helper()
|
|
|
|
if err := os.MkdirAll(userDataDir, 0o755); err != nil {
|
|
t.Fatalf("create user data dir failed: %v", err)
|
|
}
|
|
content := fmt.Sprintf("%d\n/devtools/browser/test\n", debugPort)
|
|
if err := os.WriteFile(filepath.Join(userDataDir, "DevToolsActivePort"), []byte(content), 0o644); err != nil {
|
|
t.Fatalf("write DevToolsActivePort failed: %v", err)
|
|
}
|
|
}
|