Files
CyberStrikeAI/internal/termout/startup_test.go
T
苏尼克andsycpro c563567502 fix: startup banner hardcodes 127.0.0.1 regardless of server.host (#307)
The Web UI startup banner always printed 127.0.0.1, even when
server.host was bound to 0.0.0.0 or a specific interface. This made
users believe the host setting was ignored (the actual listen binding
was correct). Pass the configured host into the banner and expand
wildcard binds to the machine's real addresses so LAN URLs are shown.

Fixes #301

Co-authored-by: sycpro <sycpro@sycprodeMacBook-Pro.local>
2026-09-13 15:27:38 +08:00

171 lines
4.4 KiB
Go

package termout
import (
"bytes"
"net"
"strings"
"testing"
)
func TestStartupHostsExplicitHost(t *testing.T) {
for _, host := range []string{"192.168.1.5", "127.0.0.1", "10.0.0.8"} {
got := startupHosts(host)
if len(got) != 1 || got[0] != host {
t.Fatalf("startupHosts(%q) = %v, want [%q]", host, got, host)
}
}
}
func TestStartupHostsWildcardExpandsToLocalAddresses(t *testing.T) {
for _, host := range []string{"", "0.0.0.0", "::", "[::]"} {
got := startupHosts(host)
if len(got) == 0 || got[0] != "127.0.0.1" {
t.Fatalf("startupHosts(%q) = %v, want first entry 127.0.0.1", host, got)
}
seen := map[string]bool{}
for _, h := range got {
if seen[h] {
t.Fatalf("startupHosts(%q) contains duplicate %q", host, h)
}
seen[h] = true
ip := net.ParseIP(h)
if ip == nil {
t.Fatalf("startupHosts(%q) returned non-IP %q", host, h)
}
if ip.IsLoopback() && h != "127.0.0.1" {
t.Fatalf("startupHosts(%q) returned unexpected loopback %q", host, h)
}
}
}
}
func TestPrintStartupWebUIReflectsConfiguredHost(t *testing.T) {
var buf bytes.Buffer
printStartupWebUI(&buf, StartupWebUIOptions{
Scheme: "http",
Host: "192.168.1.5",
Port: 8080,
})
out := buf.String()
if !strings.Contains(out, "http://192.168.1.5:8080/") {
t.Fatalf("banner should show configured host, got:\n%s", out)
}
if strings.Contains(out, "127.0.0.1") {
t.Fatalf("banner should not fall back to 127.0.0.1 for explicit host, got:\n%s", out)
}
}
func TestPrintStartupWebUIWildcardShowsLoopbackFirst(t *testing.T) {
var buf bytes.Buffer
printStartupWebUI(&buf, StartupWebUIOptions{
Scheme: "https",
Host: "0.0.0.0",
Port: 8443,
})
out := buf.String()
if !strings.Contains(out, "https://127.0.0.1:8443/") {
t.Fatalf("wildcard banner should include loopback URL, got:\n%s", out)
}
for _, h := range startupHosts("0.0.0.0")[1:] {
if !strings.Contains(out, "https://"+h+":8443/") {
t.Fatalf("wildcard banner should include network URL for %s, got:\n%s", h, out)
}
}
}
func TestPrintStartupWebUIIPv6HostBracketed(t *testing.T) {
var buf bytes.Buffer
printStartupWebUI(&buf, StartupWebUIOptions{
Scheme: "http",
Host: "::1",
Port: 8080,
})
if !strings.Contains(buf.String(), "http://[::1]:8080/") {
t.Fatalf("IPv6 host should be bracketed in URL, got:\n%s", buf.String())
}
}
func TestPrintStartupWebUIRedirectUsesConfiguredHost(t *testing.T) {
var buf bytes.Buffer
printStartupWebUI(&buf, StartupWebUIOptions{
Scheme: "https",
Host: "10.1.2.3",
Port: 8080,
HTTPRedirect: true,
})
out := buf.String()
if !strings.Contains(out, "http://10.1.2.3:8080/") || !strings.Contains(out, "https://10.1.2.3:8080/") {
t.Fatalf("redirect line should use configured host, got:\n%s", out)
}
}
func TestDisplayWidthEmoji(t *testing.T) {
if got := displayWidth("🚀"); got != 2 {
t.Fatalf("displayWidth(emoji) = %d, want 2", got)
}
if got := displayWidth("ab"); got != 2 {
t.Fatalf("displayWidth(ab) = %d, want 2", got)
}
}
func TestDisplayWidthIgnoresANSI(t *testing.T) {
s := New(nil)
colored := s.Bold("admin")
if got := displayWidth(colored); got != 5 {
t.Fatalf("displayWidth colored = %d, want 5", got)
}
}
func TestPadRightDisplay(t *testing.T) {
got := padRightDisplay("pwd", 10)
if displayWidth(got) != 10 {
t.Fatalf("padded width = %d, want 10", displayWidth(got))
}
}
func TestColorDisabledWithoutTTY(t *testing.T) {
s := New(nil)
if s.enabled {
t.Fatal("expected colors disabled for nil writer")
}
if got := s.Cyan("x"); got != "x" {
t.Fatalf("Cyan without TTY = %q, want plain text", got)
}
}
func TestPrintBootstrapAdminCredentialsEmpty(t *testing.T) {
PrintBootstrapAdminCredentials(" ")
}
func TestPrintStartupWebUIOptions(t *testing.T) {
PrintStartupWebUI(StartupWebUIOptions{
Scheme: "https",
Port: 8080,
SelfSigned: true,
HTTPRedirect: true,
})
}
func TestBoxRowAlignedWidth(t *testing.T) {
s := New(nil)
rows := []string{
s.Bold("CyberStrikeAI") + s.White(" is ready"),
s.Dim("Web UI ") + s.Bold("https://127.0.0.1:8080/"),
}
inner := maxDisplayWidth(rows...)
for _, row := range rows {
line := s.boxRow(inner, row)
if !strings.Contains(line, "│") {
t.Fatalf("box row missing border: %q", line)
}
}
}
func TestMaxDisplayWidth(t *testing.T) {
short := "abc"
long := "https://127.0.0.1:8080/"
if got := maxDisplayWidth(short, long); got != displayWidth(long) {
t.Fatalf("maxDisplayWidth = %d, want %d", got, displayWidth(long))
}
}