feat: wire gui instance start and delete confirmation
This commit is contained in:
@@ -2,6 +2,7 @@ package ui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -90,6 +91,98 @@ func TestShellDeletesOnlyTheRequestedInstance(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellDeletesOnlyAfterConfirmation(t *testing.T) {
|
||||
shell := NewShell(material.NewTheme())
|
||||
target := shell.rows[1]
|
||||
changes := 0
|
||||
shell.OnInstancesChanged(func([]InstanceRow) { changes++ })
|
||||
|
||||
shell.requestDelete(target.ID)
|
||||
if shell.pendingDeleteID != target.ID {
|
||||
t.Fatalf("pending delete = %q, want %q", shell.pendingDeleteID, target.ID)
|
||||
}
|
||||
if len(shell.rows) != 4 {
|
||||
t.Fatalf("instance count changed before confirmation: %d", len(shell.rows))
|
||||
}
|
||||
shell.cancelDelete()
|
||||
if shell.pendingDeleteID != "" || len(shell.rows) != 4 || changes != 0 {
|
||||
t.Fatalf("cancel delete state = pending %q, rows %d, changes %d", shell.pendingDeleteID, len(shell.rows), changes)
|
||||
}
|
||||
|
||||
shell.requestDelete(target.ID)
|
||||
shell.confirmDelete()
|
||||
if shell.pendingDeleteID != "" || len(shell.rows) != 3 || changes != 1 {
|
||||
t.Fatalf("confirm delete state = pending %q, rows %d, changes %d", shell.pendingDeleteID, len(shell.rows), changes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellStartsInstanceAsynchronouslyAndAppliesResult(t *testing.T) {
|
||||
shell := NewShell(material.NewTheme())
|
||||
target := shell.rows[0]
|
||||
started := make(chan InstanceRow, 1)
|
||||
shell.OnStartInstance(func(_ context.Context, row InstanceRow, _ SettingsState) (int, error) {
|
||||
started <- row
|
||||
return 4242, nil
|
||||
}, nil)
|
||||
|
||||
shell.requestStart(target.ID)
|
||||
if row, ok := shell.instanceRow(target.ID); !ok || row.Status != "启动中" {
|
||||
t.Fatalf("start status = %#v, want 启动中", row)
|
||||
}
|
||||
select {
|
||||
case got := <-started:
|
||||
if got.ID != target.ID {
|
||||
t.Fatalf("started instance = %q, want %q", got.ID, target.ID)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("start callback was not invoked")
|
||||
}
|
||||
var result instanceStartResult
|
||||
select {
|
||||
case result = <-shell.startResults:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("start result was not produced")
|
||||
}
|
||||
shell.startResults <- result
|
||||
shell.consumeStartResults()
|
||||
if row, ok := shell.instanceRow(target.ID); !ok || row.Status != "运行中" {
|
||||
t.Fatalf("completed start status = %#v, want 运行中", row)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellDoesNotStartTheSameInstanceTwiceWhilePending(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.OnStartInstance(func(_ context.Context, _ InstanceRow, _ SettingsState) (int, error) {
|
||||
calls.Add(1)
|
||||
entered <- struct{}{}
|
||||
<-release
|
||||
return 4242, nil
|
||||
}, nil)
|
||||
|
||||
shell.requestStart(target.ID)
|
||||
shell.requestStart(target.ID)
|
||||
select {
|
||||
case <-entered:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("start callback was not invoked")
|
||||
}
|
||||
if calls.Load() != 1 {
|
||||
t.Fatalf("start calls = %d, want 1", calls.Load())
|
||||
}
|
||||
close(release)
|
||||
select {
|
||||
case result := <-shell.startResults:
|
||||
shell.startResults <- result
|
||||
shell.consumeStartResults()
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("start result was not produced")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellCancelsOnlyTheActivePathSearch(t *testing.T) {
|
||||
shell := NewShell(material.NewTheme())
|
||||
started := make(chan struct{}, 1)
|
||||
|
||||
Reference in New Issue
Block a user