Files
code-utils/launchpad_test.go

93 lines
2.8 KiB
Go
Raw Normal View History

2026-08-14 07:52:01 +08:00
package main
import (
"path/filepath"
"testing"
)
func TestInferLaunchKind(t *testing.T) {
cases := []struct {
name, exe, cmdline, want string
}{
{"node.exe", `C:\nodejs\node.exe`, "node vite dev", "node"},
{"mysqld.exe", `C:\mysql\bin\mysqld.exe`, "mysqld --console", "mysql"},
{"redis-server", "/usr/bin/redis-server", "redis-server *:6379", "redis"},
{"nginx.exe", `C:\nginx\nginx.exe`, "nginx", "nginx"},
{"java.exe", `C:\jdk\bin\java.exe`, "java -jar app.jar", "java"},
{"python.exe", `C:\py\python.exe`, "uvicorn main:app", "python"},
{"php-cgi.exe", `C:\php\php-cgi.exe`, "", "php"},
{"dotnet.exe", `C:\dotnet\dotnet.exe`, "dotnet run", "dotnet"},
{"main.exe", `C:\Temp\go-build\__debug_bin.exe`, "", "go"},
{"svchost.exe", `C:\Windows\svchost.exe`, "-k netsvcs", "other"},
}
for _, c := range cases {
if got := inferLaunchKind(c.name, c.exe, c.cmdline); got != c.want {
t.Errorf("inferLaunchKind(%q)=%q want %q", c.name, got, c.want)
}
}
}
func TestLaunchCmdSuggest(t *testing.T) {
a := &App{}
if s := a.LaunchCmdSuggest("node"); len(s.Start) == 0 {
t.Fatal("node suggestions empty")
}
if s := a.LaunchCmdSuggest("mysql"); len(s.Stop) == 0 {
t.Fatal("mysql stop suggestions empty")
}
if s := a.LaunchCmdSuggest("unknown-kind"); len(s.Start) != 0 || len(s.Stop) != 0 {
t.Fatal("unknown kind should be empty")
}
}
func TestLaunchAppCRUD(t *testing.T) {
s, e := OpenStore(filepath.Join(t.TempDir(), "lp.db"))
if e != nil {
t.Fatal(e)
}
defer s.db.Close()
if _, e := s.SaveLaunchApp(LaunchApp{Name: " "}); e == nil {
t.Fatal("blank name accepted")
}
app, e := s.SaveLaunchApp(LaunchApp{Name: "demo-api", Port: 8080, Dir: t.TempDir(), StartCmd: "npm run dev"})
if e != nil || app.ID == 0 || app.Kind != "other" {
t.Fatalf("create: %#v %v", app, e)
}
app.Kind, app.StopCmd = "node", "npx kill-port 8080"
app2, e := s.SaveLaunchApp(app)
if e != nil || app2.Kind != "node" || app2.StopCmd != "npx kill-port 8080" {
t.Fatalf("update: %#v %v", app2, e)
}
if e := s.setLaunchPID(app.ID, 4321); e != nil {
t.Fatal(e)
}
got, e := s.GetLaunchApp(app.ID)
if e != nil || got.LastPID != 4321 {
t.Fatalf("get: %#v %v", got, e)
}
lst, e := s.ListLaunchApps()
if e != nil || len(lst) != 1 {
t.Fatalf("list: %d %v", len(lst), e)
}
if e := s.DeleteLaunchApp(app.ID); e != nil {
t.Fatal(e)
}
if lst, _ = s.ListLaunchApps(); len(lst) != 0 {
t.Fatalf("after delete: %d", len(lst))
}
}
// TestScanListenPorts 冒烟:真机上应能扫出至少 0 个监听进程且不报错。
func TestScanListenPorts(t *testing.T) {
m, e := scanListenPorts()
if e != nil {
t.Fatalf("scan failed: %v", e)
}
for pid, ports := range m {
if pid <= 0 || len(ports) == 0 {
t.Fatalf("bad entry pid=%d ports=%v", pid, ports)
}
}
t.Logf("scanned %d listening processes", len(m))
}