127 lines
5.2 KiB
Go
127 lines
5.2 KiB
Go
package tui
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
|
|
"proxyctl/internal/app"
|
|
"proxyctl/internal/target"
|
|
)
|
|
|
|
type progressiveDetectionModule struct {
|
|
snapshot app.Snapshot
|
|
streams []chan app.TargetDetectionUpdate
|
|
begins int
|
|
}
|
|
|
|
func (m *progressiveDetectionModule) Snapshot() app.Snapshot { return m.snapshot }
|
|
func (m *progressiveDetectionModule) Dispatch(app.Intent) app.Result {
|
|
return app.Result{Snapshot: m.snapshot}
|
|
}
|
|
func (m *progressiveDetectionModule) BeginTargetDetection() (app.Snapshot, <-chan app.TargetDetectionUpdate) {
|
|
m.begins++
|
|
for i := range m.snapshot.Targets {
|
|
m.snapshot.Targets[i].DetectionPhase = app.TargetChecking
|
|
m.snapshot.Targets[i].DetectionErr = nil
|
|
}
|
|
return m.snapshot, m.streams[m.begins-1]
|
|
}
|
|
|
|
func TestCompleteModelStreamsStartupAndRefreshByTargetWithoutMovingSelection(t *testing.T) {
|
|
startup := make(chan app.TargetDetectionUpdate, 4)
|
|
refresh := make(chan app.TargetDetectionUpdate, 4)
|
|
module := &progressiveDetectionModule{
|
|
snapshot: app.Snapshot{Targets: []app.TargetSnapshot{
|
|
{ID: "shell", Description: target.Description{Name: "Shell", Summary: "Shell description"}},
|
|
{ID: "apt", Description: target.Description{Name: "APT", Summary: "APT description"}},
|
|
{ID: "docker", Description: target.Description{Name: "Docker", Summary: "Docker description"}},
|
|
}},
|
|
streams: []chan app.TargetDetectionUpdate{startup, refresh},
|
|
}
|
|
model := resizedModel(t, module, themeModeNoColor, 120, 36)
|
|
assertUsableFrame(t, model.View(), 120, 36,
|
|
"> … Checking Shell", "… Checking APT", "… Checking Docker",
|
|
"Shell description", "Availability and configuration inspection are in progress.",
|
|
)
|
|
|
|
// Selection remains usable while checks run, and is retained by identity
|
|
// even when a later product row completes first.
|
|
model = updateKey(model, "down")
|
|
if model.selectedTargetID != "apt" {
|
|
t.Fatalf("selection during startup = %q, want apt", model.selectedTargetID)
|
|
}
|
|
command := model.Init()
|
|
if command == nil {
|
|
t.Fatal("startup did not wait for progressive detection")
|
|
}
|
|
|
|
startup <- detectionUpdate(module.snapshot, "docker", app.TargetReady, true, target.Enabled, "docker enabled", nil)
|
|
model, command = applyDetectionCommand(t, model, command)
|
|
view := model.View()
|
|
assertOrder(t, view, "Shell", "APT", "Docker")
|
|
assertUsableFrame(t, view, 120, 36, "… Checking Shell", "> … Checking APT", "● Enabled Docker")
|
|
if model.selectedTargetID != "apt" {
|
|
t.Fatalf("out-of-order completion moved selection to %q", model.selectedTargetID)
|
|
}
|
|
|
|
failure := errors.New("apt-config inspection failed")
|
|
startup <- detectionUpdate(module.snapshot, "shell", app.TargetDetectionFailed, false, "", "", failure)
|
|
model, command = applyDetectionCommand(t, model, command)
|
|
assertUsableFrame(t, model.View(), 120, 36, "! Check failed Shell", "> … Checking APT", "● Enabled Docker")
|
|
|
|
startup <- detectionUpdate(module.snapshot, "apt", app.TargetReady, true, target.External, "external APT proxy", nil)
|
|
model, command = applyDetectionCommand(t, model, command)
|
|
startup <- app.TargetDetectionUpdate{Complete: true}
|
|
model, command = applyDetectionCommand(t, model, command)
|
|
if command != nil || model.selectedTargetID != "apt" {
|
|
t.Fatalf("startup completion command=%v selection=%q", command != nil, model.selectedTargetID)
|
|
}
|
|
assertUsableFrame(t, model.View(), 120, 36, "! Check failed Shell", "> ◇ External APT", "● Enabled Docker")
|
|
model = updateKey(model, "up")
|
|
assertUsableFrame(t, model.View(), 120, 36, "> ! Check failed Shell", "Check error: apt-config inspection failed")
|
|
model = updateKey(model, "down")
|
|
|
|
updated, command := model.Update(keyMessage("r"))
|
|
model = updated.(Model)
|
|
if command == nil || module.begins != 2 {
|
|
t.Fatalf("refresh did not reuse progressive detection: command=%v begins=%d", command != nil, module.begins)
|
|
}
|
|
assertUsableFrame(t, model.View(), 120, 36, "… Checking Shell", "> … Checking APT", "… Checking Docker")
|
|
|
|
refresh <- detectionUpdate(module.snapshot, "apt", app.TargetReady, true, target.Enabled, "apt enabled", nil)
|
|
model, command = applyDetectionCommand(t, model, command)
|
|
assertUsableFrame(t, model.View(), 120, 36, "… Checking Shell", "> ● Enabled APT", "… Checking Docker")
|
|
if model.selectedTargetID != "apt" {
|
|
t.Fatalf("refresh completion moved selection to %q", model.selectedTargetID)
|
|
}
|
|
}
|
|
|
|
func detectionUpdate(snapshot app.Snapshot, id string, phase app.TargetDetectionPhase, available bool, state target.State, evidence string, err error) app.TargetDetectionUpdate {
|
|
return app.TargetDetectionUpdate{Result: app.TargetDetectionResult{
|
|
TargetID: id, Phase: phase,
|
|
Availability: target.Availability{Available: available, Evidence: evidence},
|
|
Inspection: target.Inspection{State: state, Evidence: evidence}, Err: err,
|
|
}}
|
|
}
|
|
|
|
func applyDetectionCommand(t *testing.T, model Model, command tea.Cmd) (Model, tea.Cmd) {
|
|
t.Helper()
|
|
updated, next := model.Update(command())
|
|
return updated.(Model), next
|
|
}
|
|
|
|
func assertOrder(t *testing.T, view string, values ...string) {
|
|
t.Helper()
|
|
last := -1
|
|
for _, value := range values {
|
|
index := strings.Index(view, value)
|
|
if index <= last {
|
|
t.Fatalf("%q did not follow prior Target in frame:\n%s", value, view)
|
|
}
|
|
last = index
|
|
}
|
|
}
|