From 993ca630f7a4edd7fdeb70b211690b2416e6893d Mon Sep 17 00:00:00 2001 From: Mickael Remond Date: Wed, 17 Jan 2018 18:47:34 +0100 Subject: [PATCH] Test and code refactor --- client.go | 1 + cmd/xmpp_component/xmpp_component.go | 31 +++++----- component.go | 14 ++++- iq.go | 20 ++++--- iq_test.go | 84 +++++++++++----------------- 5 files changed, 75 insertions(+), 75 deletions(-) diff --git a/client.go b/client.go index defa642..08ee804 100644 --- a/client.go +++ b/client.go @@ -127,6 +127,7 @@ func (c *Client) Recv() <-chan interface{} { } // Send sends message text. +// TODO Move to Go XML Marshaller func (c *Client) Send(packet string) error { fmt.Fprintf(c.Session.socketProxy, packet) // TODO handle errors return nil diff --git a/cmd/xmpp_component/xmpp_component.go b/cmd/xmpp_component/xmpp_component.go index e2126d1..01a222a 100644 --- a/cmd/xmpp_component/xmpp_component.go +++ b/cmd/xmpp_component/xmpp_component.go @@ -58,20 +58,21 @@ func (c MyComponent) processIQ(iqType, id, from string, inner *xmpp.Node) { switch inner.XMLName.Space + " " + iqType { case NSDiscoInfo + " get": fmt.Println("Send Disco Info") - result := fmt.Sprintf(` - - - - - -`, c.xmpp.Host, from, id, c.Category, c.Type, c.Name) - c.xmpp.Send(result) + + iq := xmpp.NewIQ("result", "admin@localhost", "test@localhost", "1", "en") + payload := xmpp.DiscoInfo{ + Identity: xmpp.Identity{ + Name: "Test Gateway", + Category: "gateway", + Type: "mqtt", + }, + Features: []xmpp.Feature{ + {Var: "http://jabber.org/protocol/disco#info"}, + {Var: "http://jabber.org/protocol/disco#item"}, + }, + } + iq.AddPayload(&payload) + c.xmpp.Send(iq) default: iqErr := fmt.Sprintf(` `, c.xmpp.Host, from, id) - c.xmpp.Send(iqErr) + c.xmpp.SendOld(iqErr) // FIXME Remove that method } } diff --git a/component.go b/component.go index aa5d8d0..750bfc9 100644 --- a/component.go +++ b/component.go @@ -94,7 +94,19 @@ func (c *Component) ReadPacket() (Packet, error) { return next(c.decoder) } -func (c *Component) Send(packet string) error { +func (c *Component) Send(packet Packet) error { + data, err := xml.Marshal(packet) + if err != nil { + return errors.New("cannot marshal packet " + err.Error()) + } + + if _, err := fmt.Fprintf(c.conn, string(data)); err != nil { + return errors.New("cannot send packet " + err.Error()) + } + return nil +} + +func (c *Component) SendOld(packet string) error { if _, err := fmt.Fprintf(c.conn, packet); err != nil { return errors.New("cannot send packet " + err.Error()) } diff --git a/iq.go b/iq.go index 695df48..69e04c4 100644 --- a/iq.go +++ b/iq.go @@ -152,7 +152,7 @@ func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { if err != nil { return err } - iq.Payload = append(iq.Payload, iqPl) // []IQPayload{iqPl} + iq.Payload = append(iq.Payload, iqPl) } } @@ -232,17 +232,23 @@ func (*Node) IsIQPayload() {} // Disco type DiscoInfo struct { - XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info query"` - Identity Identity + XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info query"` + Identity Identity `xml:"identity"` + Features []Feature `xml:"feature"` } func (*DiscoInfo) IsIQPayload() {} type Identity struct { - XMLName xml.Name `xml:"identity"` - Name string `xml:"name,attr"` - Category string `xml:"category,attr"` - Type string `xml:"type,attr"` + XMLName xml.Name `xml:"identity,omitempty"` + Name string `xml:"name,attr,omitempty"` + Category string `xml:"category,attr,omitempty"` + Type string `xml:"type,attr,omitempty"` +} + +type Feature struct { + XMLName xml.Name `xml:"feature"` + Var string `xml:"var,attr"` } // ============================================================================ diff --git a/iq_test.go b/iq_test.go index 1a88d72..2ee86b4 100644 --- a/iq_test.go +++ b/iq_test.go @@ -2,9 +2,10 @@ package xmpp // import "fluux.io/xmpp" import ( "encoding/xml" - "fmt" "reflect" "testing" + + "github.com/google/go-cmp/cmp" ) func TestUnmarshalIqs(t *testing.T) { @@ -30,63 +31,20 @@ func TestUnmarshalIqs(t *testing.T) { } func TestGenerateIq(t *testing.T) { - iq := NewIQ("get", "admin@localhost", "test@localhost", "1", "en") - payload := Node{ - XMLName: xml.Name{ - Space: "http://jabber.org/protocol/disco#info", - Local: "query", - }, - Nodes: []Node{ - {XMLName: xml.Name{ - Space: "http://jabber.org/protocol/disco#info", - Local: "identity", - }, - Attrs: []xml.Attr{ - {Name: xml.Name{Local: "category"}, Value: "gateway"}, - {Name: xml.Name{Local: "type"}, Value: "mqtt"}, - {Name: xml.Name{Local: "name"}, Value: "Test Gateway"}, - }, - Nodes: nil, - }}, - } - iq.AddPayload(&payload) - data, err := xml.Marshal(iq) - if err != nil { - t.Errorf("cannot marshal xml structure") - } - - fmt.Printf("XML Struct: %s\n", data) - - var parsedIQ = new(IQ) - if err = xml.Unmarshal(data, parsedIQ); err != nil { - t.Errorf("Unmarshal(%s) returned error", data) - } - - if !reflect.DeepEqual(parsedIQ.Payload[0], iq.Payload[0]) { - t.Errorf("expecting result %+v = %+v", parsedIQ.Payload[0], iq.Payload[0]) - } - - fmt.Println("ParsedIQ", parsedIQ) -} - -func TestGenerateIqNew(t *testing.T) { - iq := NewIQ("get", "admin@localhost", "test@localhost", "1", "en") + iq := NewIQ("result", "admin@localhost", "test@localhost", "1", "en") payload := DiscoInfo{ - XMLName: xml.Name{ - Space: "http://jabber.org/protocol/disco#info", - Local: "query", - }, Identity: Identity{ - XMLName: xml.Name{ - Space: "http://jabber.org/protocol/disco#info", - Local: "identity", - }, Name: "Test Gateway", Category: "gateway", Type: "mqtt", }, + Features: []Feature{ + {Var: "http://jabber.org/protocol/disco#info"}, + {Var: "http://jabber.org/protocol/disco#item"}, + }, } iq.AddPayload(&payload) + data, err := xml.Marshal(iq) if err != nil { t.Errorf("cannot marshal xml structure") @@ -97,7 +55,29 @@ func TestGenerateIqNew(t *testing.T) { t.Errorf("Unmarshal(%s) returned error", data) } - if !reflect.DeepEqual(parsedIQ.Payload[0], iq.Payload[0]) { - t.Errorf("expecting result %+v = %+v", parsedIQ.Payload[0], iq.Payload[0]) + if !xmlEqual(parsedIQ.Payload, iq.Payload) { + t.Errorf("non matching items\n%s", cmp.Diff(parsedIQ.Payload, iq.Payload)) } } + +// Compare iq structure but ignore empty namespace as they are set properly on +// marshal / unmarshal. There is no need to manage them on the manually +// crafted structure. +func xmlEqual(x, y interface{}) bool { + alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true }) + opts := cmp.Options{ + cmp.FilterValues(func(x, y interface{}) bool { + xx, xok := x.(xml.Name) + yy, yok := y.(xml.Name) + if xok && yok { + zero := xml.Name{} + if xx == zero || yy == zero { + return true + } + } + return false + }, alwaysEqual), + } + + return cmp.Equal(x, y, opts) +}