feat: add scoped browser stop and job control
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"chub/internal/domain"
|
||||
)
|
||||
@@ -42,6 +43,7 @@ func TestLauncherSeparatesProfilesBlocksDuplicatesAndReleasesAfterExit(t *testin
|
||||
if err == nil && !use.Occupied {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
if use.Occupied {
|
||||
t.Fatalf("profile remained occupied after exit: %+v", use)
|
||||
@@ -70,6 +72,24 @@ func TestProcessWaitCancellationDoesNotTerminateBrowser(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLauncherStopProfileTargetsOnlyRegisteredProfile(t *testing.T) {
|
||||
runner := &fakeRunner{}
|
||||
launcher := NewLauncher(runner)
|
||||
profile := filepath.Join(t.TempDir(), "profile")
|
||||
if _, err := launcher.Start(context.Background(), launchSpec(profile)); err != nil {
|
||||
t.Fatalf("Start() error = %v", err)
|
||||
}
|
||||
if err := launcher.StopProfile(context.Background(), profile, false); err != nil {
|
||||
t.Fatalf("StopProfile() error = %v", err)
|
||||
}
|
||||
if runner.processAt(0).stopCount != 1 || runner.processAt(0).stopForce {
|
||||
t.Fatalf("stop state = count %d force %v", runner.processAt(0).stopCount, runner.processAt(0).stopForce)
|
||||
}
|
||||
if err := launcher.StopProfile(context.Background(), filepath.Join(t.TempDir(), "other"), true); !errors.Is(err, domain.ErrInstanceNotFound) {
|
||||
t.Fatalf("unknown profile error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func launchSpec(profile string) domain.LaunchSpec {
|
||||
return domain.LaunchSpec{Kind: domain.BrowserChrome, Executable: `C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe`, UserDataDir: profile, TargetURL: "https://example.com"}
|
||||
}
|
||||
@@ -93,10 +113,12 @@ func (r *fakeRunner) processAt(index int) *fakeProcess {
|
||||
}
|
||||
|
||||
type fakeProcess struct {
|
||||
pid int
|
||||
done chan processResult
|
||||
mu sync.Mutex
|
||||
finished bool
|
||||
pid int
|
||||
done chan processResult
|
||||
mu sync.Mutex
|
||||
finished bool
|
||||
stopCount int
|
||||
stopForce bool
|
||||
}
|
||||
type processResult struct {
|
||||
code int
|
||||
@@ -108,6 +130,13 @@ func newFakeProcess(pid int) *fakeProcess {
|
||||
}
|
||||
func (p *fakeProcess) PID() int { return p.pid }
|
||||
func (p *fakeProcess) Wait() (int, error) { result := <-p.done; return result.code, result.err }
|
||||
func (p *fakeProcess) Stop(_ context.Context, force bool) error {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.stopCount++
|
||||
p.stopForce = force
|
||||
return nil
|
||||
}
|
||||
func (p *fakeProcess) finish(code int, err error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user