package api import ( "encoding/json" "net/http" "net/http/httptest" "testing" ) func TestParsePort(t *testing.T) { tests := []struct { in string want int }{ {"8989", 8989}, {"80", 80}, {"abc", 8989}, {"", 8989}, {"0", 8989}, } for _, tc := range tests { if got := parsePort(tc.in); got != tc.want { t.Fatalf("parsePort(%q) = %d, want %d", tc.in, got, tc.want) } } } func TestIsLoopbackHost(t *testing.T) { if !isLoopbackHost("localhost") { t.Fatal("localhost should be loopback") } if !isLoopbackHost("127.0.0.1") { t.Fatal("127.0.0.1 should be loopback") } if isLoopbackHost("192.168.1.1") { t.Fatal("192.168.1.1 should not be loopback") } } func TestItoa(t *testing.T) { if itoa(8989) != "8989" { t.Fatalf("itoa(8989) = %q", itoa(8989)) } if itoa(0) != "0" { t.Fatalf("itoa(0) = %q", itoa(0)) } } func TestGetServerInfoJSON(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/api/v1/server/info", nil) req.Host = "localhost:8989" rec := httptest.NewRecorder() GetServerInfo(rec, req, "", 8989, false) if rec.Code != http.StatusOK { t.Fatalf("status %d body %s", rec.Code, rec.Body.String()) } var info ServerInfo if err := json.Unmarshal(rec.Body.Bytes(), &info); err != nil { t.Fatal(err) } if info.Port != 8989 { t.Fatalf("port = %d, want 8989", info.Port) } if info.WebSocketURL == "" || info.SuggestedURL == "" { t.Fatalf("missing URLs: %+v", info) } } func TestGetServerInfoPublicURLOverride(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/api/v1/server/info", nil) req.Host = "localhost:8989" rec := httptest.NewRecorder() GetServerInfo(rec, req, "https://forge.example.com:443", 8989, false) var info ServerInfo if err := json.Unmarshal(rec.Body.Bytes(), &info); err != nil { t.Fatal(err) } if info.SuggestedURL != "https://forge.example.com" { t.Fatalf("override not applied: %q", info.SuggestedURL) } if info.WebSocketURL != "wss://forge.example.com/ws/agent" { t.Fatalf("ws url = %q", info.WebSocketURL) } } func TestGetServerInfoHTTPSBehindProxy(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/api/v1/server/info", nil) req.Host = "nothing.thetempleofdoom.com" req.Header.Set("X-Forwarded-Proto", "https") req.Header.Set("X-Forwarded-Host", "nothing.thetempleofdoom.com") rec := httptest.NewRecorder() GetServerInfo(rec, req, "", 8989, true) var info ServerInfo if err := json.Unmarshal(rec.Body.Bytes(), &info); err != nil { t.Fatal(err) } if info.SuggestedURL != "https://nothing.thetempleofdoom.com" { t.Fatalf("tunnel URL = %q, want https without :8989", info.SuggestedURL) } if info.TunnelURL != "https://nothing.thetempleofdoom.com" { t.Fatalf("tunnel_url = %q, want https public endpoint", info.TunnelURL) } if !info.CloudflaredConfigured { t.Fatal("expected cloudflared_configured=true") } } func TestGetServerInfoLANURLFromLocalhost(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/api/v1/server/info", nil) req.Host = "localhost:8989" rec := httptest.NewRecorder() GetServerInfo(rec, req, "", 8989, false) var info ServerInfo if err := json.Unmarshal(rec.Body.Bytes(), &info); err != nil { t.Fatal(err) } if info.TunnelURL != "" { t.Fatalf("tunnel_url should be empty on localhost, got %q", info.TunnelURL) } if len(info.LocalIPs) > 0 && info.LANURL == "" { t.Fatalf("expected lan_url when local IPs present: %+v", info) } if len(info.LocalIPs) > 0 && info.LANURL != formatBaseURL("http", info.LocalIPs[0], 8989) { t.Fatalf("lan_url = %q, want %s", info.LANURL, formatBaseURL("http", info.LocalIPs[0], 8989)) } }