Add unit tests for extractHostAndPort utility function
27 test cases covering URL/host:port parsing for node configuration: - Scheme stripping (http://, https://) - Path removal from URLs - IPv4 addresses with and without ports - IPv6 addresses (bracketed with port, unbracketed) - Edge cases (empty string, localhost, port-only) - Error cases (malformed brackets) Documents current behavior: bracketed IPv6 without port returns error (net.SplitHostPort limitation).
This commit is contained in:
parent
a21dd8c3d2
commit
5fcd4e9cb9
1 changed files with 201 additions and 0 deletions
|
|
@ -2,6 +2,207 @@ package api
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
|
func TestExtractHostAndPort(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
hostStr string
|
||||||
|
wantHost string
|
||||||
|
wantPort string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
// Basic host:port
|
||||||
|
{
|
||||||
|
name: "simple host with port",
|
||||||
|
hostStr: "example.com:8006",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "host without port",
|
||||||
|
hostStr: "example.com",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
// HTTP/HTTPS scheme stripping
|
||||||
|
{
|
||||||
|
name: "https scheme stripped",
|
||||||
|
hostStr: "https://example.com:8006",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "http scheme stripped",
|
||||||
|
hostStr: "http://example.com:8006",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "https scheme without port",
|
||||||
|
hostStr: "https://example.com",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "http scheme without port",
|
||||||
|
hostStr: "http://example.com",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Path stripping
|
||||||
|
{
|
||||||
|
name: "path stripped from host:port",
|
||||||
|
hostStr: "example.com:8006/api/v1",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "path stripped from host without port",
|
||||||
|
hostStr: "example.com/api/v1",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "full URL with scheme path and port",
|
||||||
|
hostStr: "https://example.com:8443/some/path",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "8443",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "trailing slash stripped",
|
||||||
|
hostStr: "example.com/",
|
||||||
|
wantHost: "example.com",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
// IPv4 addresses
|
||||||
|
{
|
||||||
|
name: "IPv4 with port",
|
||||||
|
hostStr: "192.168.1.100:8006",
|
||||||
|
wantHost: "192.168.1.100",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv4 without port",
|
||||||
|
hostStr: "192.168.1.100",
|
||||||
|
wantHost: "192.168.1.100",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv4 with scheme and port",
|
||||||
|
hostStr: "https://192.168.1.100:8006",
|
||||||
|
wantHost: "192.168.1.100",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
|
||||||
|
// IPv6 addresses with brackets
|
||||||
|
{
|
||||||
|
name: "IPv6 with brackets and port",
|
||||||
|
hostStr: "[2001:db8::1]:8006",
|
||||||
|
wantHost: "2001:db8::1",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 with brackets no port returns error",
|
||||||
|
hostStr: "[2001:db8::1]",
|
||||||
|
wantErr: true, // net.SplitHostPort fails on bracketed IPv6 without port
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 with scheme brackets and port",
|
||||||
|
hostStr: "https://[2001:db8::1]:8006",
|
||||||
|
wantHost: "2001:db8::1",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 loopback with brackets",
|
||||||
|
hostStr: "[::1]:8006",
|
||||||
|
wantHost: "::1",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
|
||||||
|
// IPv6 without brackets (no port case)
|
||||||
|
{
|
||||||
|
name: "IPv6 without brackets returns as-is",
|
||||||
|
hostStr: "2001:db8::1",
|
||||||
|
wantHost: "2001:db8::1",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 full address without brackets",
|
||||||
|
hostStr: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
||||||
|
wantHost: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 loopback without brackets",
|
||||||
|
hostStr: "::1",
|
||||||
|
wantHost: "::1",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Edge cases
|
||||||
|
{
|
||||||
|
name: "empty string",
|
||||||
|
hostStr: "",
|
||||||
|
wantHost: "",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "only port colon",
|
||||||
|
hostStr: ":8006",
|
||||||
|
wantHost: "",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "localhost with port",
|
||||||
|
hostStr: "localhost:8006",
|
||||||
|
wantHost: "localhost",
|
||||||
|
wantPort: "8006",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "localhost without port",
|
||||||
|
hostStr: "localhost",
|
||||||
|
wantHost: "localhost",
|
||||||
|
wantPort: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Error cases
|
||||||
|
{
|
||||||
|
name: "malformed brackets",
|
||||||
|
hostStr: "[2001:db8::1:8006",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "brackets without closing with port attempt",
|
||||||
|
hostStr: "[invalid:8006",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotHost, gotPort, err := extractHostAndPort(tt.hostStr)
|
||||||
|
if tt.wantErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("extractHostAndPort(%q) expected error, got host=%q port=%q", tt.hostStr, gotHost, gotPort)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("extractHostAndPort(%q) unexpected error: %v", tt.hostStr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gotHost != tt.wantHost {
|
||||||
|
t.Errorf("extractHostAndPort(%q) host = %q, want %q", tt.hostStr, gotHost, tt.wantHost)
|
||||||
|
}
|
||||||
|
if gotPort != tt.wantPort {
|
||||||
|
t.Errorf("extractHostAndPort(%q) port = %q, want %q", tt.hostStr, gotPort, tt.wantPort)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNormalizeNodeHost(t *testing.T) {
|
func TestNormalizeNodeHost(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue