package deploy
import (
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestXMLEscape(t *testing.T) {
got := xmlEscape(`a&bd`)
want := "a&b<c>d"
if got != want {
t.Fatalf("got %q want %q", got, want)
}
}
func TestIntSliceStr(t *testing.T) {
got := intSliceStr([]int{22, 445, 5985})
want := []string{"22", "445", "5985"}
if len(got) != len(want) {
t.Fatalf("len %d != %d", len(got), len(want))
}
for i := range want {
if got[i] != want[i] {
t.Fatalf("[%d] got %q want %q", i, got[i], want[i])
}
}
}
func TestGetSubnet(t *testing.T) {
if got := getSubnet("192.168.1.42"); got != "192.168.1" {
t.Fatalf("got %q", got)
}
if getSubnet("bad") != "" {
t.Fatal("invalid ip should return empty")
}
if getSubnet("10.0.0.1") != "10.0.0" {
t.Fatalf("got %q", getSubnet("10.0.0.1"))
}
}
func TestCloseUPnPInvalidPort(t *testing.T) {
_, err := CloseUPnP(0)
if err == nil || !strings.Contains(err.Error(), "external port required") {
t.Fatalf("expected port error, got %v", err)
}
}
func TestResolveWANControlURL(t *testing.T) {
const igdXML = `
urn:schemas-upnp-org:service:WANIPConnection:1
/ctl/IPConn
`
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, igdXML)
}))
defer srv.Close()
got, err := resolveWANControlURL(srv.URL + "/igd.xml")
if err != nil {
t.Fatal(err)
}
want := srv.URL + "/ctl/IPConn"
if got != want {
t.Fatalf("got %q want %q", got, want)
}
}
func TestResolveWANControlURLAbsolute(t *testing.T) {
const igdXML = `
urn:schemas-upnp-org:service:WANPPPConnection:1
http://192.168.0.1:49152/ctl/IPConn
`
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, igdXML)
}))
defer srv.Close()
got, err := resolveWANControlURL(srv.URL + "/desc.xml")
if err != nil {
t.Fatal(err)
}
if got != "http://192.168.0.1:49152/ctl/IPConn" {
t.Fatalf("got %q", got)
}
}
func TestResolveWANControlURLMissingService(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `/x`)
}))
defer srv.Close()
_, err := resolveWANControlURL(srv.URL)
if err == nil || !strings.Contains(err.Error(), "WANIPConnection service not found") {
t.Fatalf("expected service error, got %v", err)
}
}
func TestResolveWANControlURLMissingControlURL(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `urn:schemas-upnp-org:service:WANIPConnection:1`)
}))
defer srv.Close()
_, err := resolveWANControlURL(srv.URL)
if err == nil || !strings.Contains(err.Error(), "controlURL not found") {
t.Fatalf("expected controlURL error, got %v", err)
}
}
func TestUpnpGetExternalIP(t *testing.T) {
const soapResp = `
203.0.113.10
`
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method", http.StatusMethodNotAllowed)
return
}
fmt.Fprint(w, soapResp)
}))
defer srv.Close()
ip, err := upnpGetExternalIP(srv.URL)
if err != nil {
t.Fatal(err)
}
if ip != "203.0.113.10" {
t.Fatalf("got %q", ip)
}
}
func TestUpnpSOAPErrorResponse(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `718`)
}))
defer srv.Close()
_, err := upnpSOAP(srv.URL, "AddPortMapping", "")
if err == nil || !strings.Contains(err.Error(), "AddPortMapping failed") {
t.Fatalf("expected SOAP error, got %v", err)
}
}
func TestReLocationParsesSSDPResponse(t *testing.T) {
cases := []struct {
body string
want string
}{
{
"HTTP/1.1 200 OK\r\nLOCATION: http://192.168.0.1:49152/desc.xml\r\n\r\n",
"http://192.168.0.1:49152/desc.xml",
},
{
"location: http://10.0.0.1/igd.xml",
"http://10.0.0.1/igd.xml",
},
}
for _, tc := range cases {
m := reLocation.FindStringSubmatch(tc.body)
if len(m) != 2 {
t.Fatalf("no LOCATION match in %q", tc.body)
}
if got := strings.TrimSpace(m[1]); got != tc.want {
t.Fatalf("got %q want %q", got, tc.want)
}
}
}
func TestResolveWANControlURLRelativeWithoutLeadingSlash(t *testing.T) {
const igdXML = `
urn:schemas-upnp-org:service:WANIPConnection:1
ctl/IPConn
`
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, igdXML)
}))
defer srv.Close()
got, err := resolveWANControlURL(srv.URL + "/igd.xml")
if err != nil {
t.Fatal(err)
}
want := srv.URL + "/ctl/IPConn"
if got != want {
t.Fatalf("got %q want %q", got, want)
}
}
func TestUpnpSOAPRequestHeaders(t *testing.T) {
var contentType, soapAction string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
contentType = r.Header.Get("Content-Type")
soapAction = r.Header.Get("SOAPAction")
fmt.Fprint(w, ``)
}))
defer srv.Close()
if _, err := upnpSOAP(srv.URL, "GetExternalIPAddress", "