feat: toggle managed instance start and stop
This commit is contained in:
@@ -2,6 +2,7 @@ package ui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@@ -191,6 +192,103 @@ func TestShellDoesNotStartTheSameInstanceTwiceWhilePending(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellStopsManagedInstanceAsynchronouslyAndRestoresStartAction(t *testing.T) {
|
||||
shell := NewShell(material.NewTheme())
|
||||
target := shell.rows[0]
|
||||
stopped := make(chan InstanceRow, 1)
|
||||
shell.OnStopInstance(func(_ context.Context, row InstanceRow) error {
|
||||
stopped <- row
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
shell.requestInstanceAction(target.ID)
|
||||
if row, ok := shell.instanceRow(target.ID); !ok || row.Status != "停止中" {
|
||||
t.Fatalf("stop status = %#v, want 停止中", row)
|
||||
}
|
||||
select {
|
||||
case got := <-stopped:
|
||||
if got.ID != target.ID || got.Status != "运行中" {
|
||||
t.Fatalf("stopped row = %#v", got)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("stop callback was not invoked")
|
||||
}
|
||||
var result instanceStopResult
|
||||
select {
|
||||
case result = <-shell.stopResults:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("stop result was not produced")
|
||||
}
|
||||
shell.stopResults <- result
|
||||
shell.consumeStopResults()
|
||||
row, ok := shell.instanceRow(target.ID)
|
||||
if !ok || row.Status != "已退出" || row.PID != 0 || row.RemoteDebugPort != 0 || instanceActionFor(row).stop {
|
||||
t.Fatalf("completed stop row = %#v", row)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellDoesNotStopTheSameInstanceTwiceOrExternalInstance(t *testing.T) {
|
||||
shell := NewShell(material.NewTheme())
|
||||
target := shell.rows[0]
|
||||
entered := make(chan struct{}, 1)
|
||||
release := make(chan struct{})
|
||||
var calls atomic.Int32
|
||||
shell.OnStopInstance(func(context.Context, InstanceRow) error {
|
||||
calls.Add(1)
|
||||
entered <- struct{}{}
|
||||
<-release
|
||||
return nil
|
||||
}, nil)
|
||||
shell.requestInstanceAction(target.ID)
|
||||
shell.requestInstanceAction(target.ID)
|
||||
select {
|
||||
case <-entered:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("stop callback was not invoked")
|
||||
}
|
||||
if calls.Load() != 1 {
|
||||
t.Fatalf("stop calls = %d, want 1", calls.Load())
|
||||
}
|
||||
close(release)
|
||||
select {
|
||||
case result := <-shell.stopResults:
|
||||
shell.stopResults <- result
|
||||
shell.consumeStopResults()
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("stop result was not produced")
|
||||
}
|
||||
|
||||
external := shell.rows[2]
|
||||
var externalStops atomic.Int32
|
||||
shell.OnStopInstance(func(context.Context, InstanceRow) error { externalStops.Add(1); return nil }, nil)
|
||||
shell.OnStartInstance(func(context.Context, InstanceRow, SettingsState) (InstanceStartOutcome, error) {
|
||||
return InstanceStartOutcome{External: true, Source: "browser_message_window"}, nil
|
||||
}, nil)
|
||||
shell.requestInstanceAction(external.ID)
|
||||
if externalStops.Load() != 0 {
|
||||
t.Fatal("external association used stop callback")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellRestoresManagedStatusAfterStopFailure(t *testing.T) {
|
||||
shell := NewShell(material.NewTheme())
|
||||
target := shell.rows[0]
|
||||
shell.OnStopInstance(func(context.Context, InstanceRow) error { return errors.New("permission denied") }, nil)
|
||||
shell.requestInstanceAction(target.ID)
|
||||
var result instanceStopResult
|
||||
select {
|
||||
case result = <-shell.stopResults:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("stop result was not produced")
|
||||
}
|
||||
shell.stopResults <- result
|
||||
shell.consumeStopResults()
|
||||
row, ok := shell.instanceRow(target.ID)
|
||||
if !ok || row.Status != "运行中" || !strings.Contains(shell.instanceFeedback, "失败") {
|
||||
t.Fatalf("failed stop row = %#v, feedback=%q", row, shell.instanceFeedback)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellCancelsOnlyTheActivePathSearch(t *testing.T) {
|
||||
shell := NewShell(material.NewTheme())
|
||||
started := make(chan struct{}, 1)
|
||||
|
||||
Reference in New Issue
Block a user