goupnp/soap/soap_test.go
2023-05-10 17:07:24 +01:00

182 lines
4.1 KiB
Go

package soap
import (
"bytes"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"strings"
"testing"
)
type capturingRoundTripper struct {
err error
resp *http.Response
capturedReq *http.Request
}
func (rt *capturingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
rt.capturedReq = req
return rt.resp, rt.err
}
func TestActionInputs(t *testing.T) {
t.Parallel()
url, err := url.Parse("http://example.com/soap")
if err != nil {
t.Fatal(err)
}
rt := &capturingRoundTripper{
err: nil,
resp: &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString(`
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:myactionResponse xmlns:u="mynamespace">
<A>valueA</A>
<B>valueB</B>
</u:myactionResponse>
</s:Body>
</s:Envelope>
`)),
},
}
client := SOAPClient{
EndpointURL: *url,
HTTPClient: http.Client{
Transport: rt,
},
}
type In struct {
Foo string
Bar string `soap:"bar"`
Baz string
}
type Out struct {
A string
B string
}
in := In{"foo", "bar", "quoted=\"baz\""}
gotOut := Out{}
err = client.PerformAction("mynamespace", "myaction", &in, &gotOut)
if err != nil {
t.Fatal(err)
}
wantBody := (soapPrefix +
`<u:myaction xmlns:u="mynamespace">` +
`<Foo>foo</Foo>` +
`<bar>bar</bar>` +
`<Baz>quoted="baz"</Baz>` +
`</u:myaction>` +
soapSuffix)
body, err := ioutil.ReadAll(rt.capturedReq.Body)
if err != nil {
t.Fatal(err)
}
gotBody := string(body)
if wantBody != gotBody {
t.Errorf("Bad request body\nwant: %q\n got: %q", wantBody, gotBody)
}
wantOut := Out{"valueA", "valueB"}
if !reflect.DeepEqual(wantOut, gotOut) {
t.Errorf("Bad output\nwant: %+v\n got: %+v", wantOut, gotOut)
}
}
func TestUPnPError(t *testing.T) {
t.Parallel()
url, err := url.Parse("http://example.com/soap")
if err != nil {
t.Fatal(err)
}
body := `
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring>UPnPError</faultstring>
<detail>
<UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
<errorCode>725</errorCode>
<errorDescription>OnlyPermanentLeasesSupported</errorDescription>
</UPnPError>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>`
rt := &capturingRoundTripper{
resp: &http.Response{
StatusCode: 500,
ContentLength: int64(len(body)),
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
},
}
client := SOAPClient{
EndpointURL: *url,
HTTPClient: http.Client{
Transport: rt,
},
}
err = client.PerformAction("mynamespace", "myaction", nil, nil)
if err == nil {
t.Fatal("expected error, got nil")
}
if testing.Verbose() {
t.Logf("%+v\n", err)
}
soapErr, ok := err.(*SOAPFaultError)
if !ok {
t.Fatal("expected *SOAPFaultError")
}
if soapErr.FaultCode != "s:Client" {
t.Fatalf("unexpected FaultCode: %s", soapErr.FaultCode)
}
if soapErr.FaultString != "UPnPError" {
t.Fatalf("unexpected FaultString: %s", soapErr.FaultString)
}
if soapErr.Detail.UPnPError.Errorcode != 725 {
t.Fatalf("unexpected UPnPError Errorcode: %d", soapErr.Detail.UPnPError.Errorcode)
}
if soapErr.Detail.UPnPError.ErrorDescription != "OnlyPermanentLeasesSupported" {
t.Fatalf("unexpected UPnPError ErrorDescription: %s",
soapErr.Detail.UPnPError.ErrorDescription)
}
if !strings.EqualFold(string(soapErr.Detail.Raw), `
<UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
<errorCode>725</errorCode>
<errorDescription>OnlyPermanentLeasesSupported</errorDescription>
</UPnPError>
`) {
t.Fatalf("unexpected Detail.Raw, got:\n%s", string(soapErr.Detail.Raw))
}
}
func TestEscapeXMLText(t *testing.T) {
t.Parallel()
tests := []struct {
input string
want string
}{
{"", ""},
{"abc123", "abc123"},
{"<foo>&", "&lt;foo&gt;&amp;"},
{"\"foo'", "\"foo'"},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
got := escapeXMLText(test.input)
if got != test.want {
t.Errorf("want %q, got %q", test.want, got)
}
})
}
}