parent
22ba8d1f4e
commit
e59a86c380
@ -0,0 +1,32 @@
|
|||||||
|
package stanza
|
||||||
|
|
||||||
|
// FIFO queue for string contents
|
||||||
|
// Implementations have no guarantee regarding thread safety !
|
||||||
|
type FifoQueue interface {
|
||||||
|
// Pop returns the first inserted element still in queue and delete it from queue
|
||||||
|
// No guarantee regarding thread safety !
|
||||||
|
Pop() Queueable
|
||||||
|
|
||||||
|
// PopN returns the N first inserted elements still in queue and delete them from queue
|
||||||
|
// No guarantee regarding thread safety !
|
||||||
|
PopN(i int) []Queueable
|
||||||
|
|
||||||
|
// Peek returns a copy of the first inserted element in queue without deleting it
|
||||||
|
// No guarantee regarding thread safety !
|
||||||
|
Peek() Queueable
|
||||||
|
|
||||||
|
// Peek returns a copy of the first inserted element in queue without deleting it
|
||||||
|
// No guarantee regarding thread safety !
|
||||||
|
PeekN() []Queueable
|
||||||
|
// Push adds an element to the queue
|
||||||
|
// No guarantee regarding thread safety !
|
||||||
|
Push(s Queueable) error
|
||||||
|
|
||||||
|
// Empty returns true if queue is empty
|
||||||
|
// No guarantee regarding thread safety !
|
||||||
|
Empty() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Queueable interface {
|
||||||
|
QueueableName() string
|
||||||
|
}
|
@ -0,0 +1,171 @@
|
|||||||
|
package stanza
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StanzaErrorGroup interface {
|
||||||
|
GroupErrorName() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BadFormat struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas bad-format"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *BadFormat) GroupErrorName() string { return "bad-format" }
|
||||||
|
|
||||||
|
type BadNamespacePrefix struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas bad-namespace-prefix"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *BadNamespacePrefix) GroupErrorName() string { return "bad-namespace-prefix" }
|
||||||
|
|
||||||
|
type Conflict struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas conflict"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Conflict) GroupErrorName() string { return "conflict" }
|
||||||
|
|
||||||
|
type ConnectionTimeout struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas connection-timeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ConnectionTimeout) GroupErrorName() string { return "connection-timeout" }
|
||||||
|
|
||||||
|
type HostGone struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas host-gone"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *HostGone) GroupErrorName() string { return "host-gone" }
|
||||||
|
|
||||||
|
type HostUnknown struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas host-unknown"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *HostUnknown) GroupErrorName() string { return "host-unknown" }
|
||||||
|
|
||||||
|
type ImproperAddressing struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas improper-addressing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ImproperAddressing) GroupErrorName() string { return "improper-addressing" }
|
||||||
|
|
||||||
|
type InternalServerError struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas internal-server-error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InternalServerError) GroupErrorName() string { return "internal-server-error" }
|
||||||
|
|
||||||
|
type InvalidForm struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas invalid-from"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidForm) GroupErrorName() string { return "invalid-from" }
|
||||||
|
|
||||||
|
type InvalidId struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas invalid-id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidId) GroupErrorName() string { return "invalid-id" }
|
||||||
|
|
||||||
|
type InvalidNamespace struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas invalid-namespace"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidNamespace) GroupErrorName() string { return "invalid-namespace" }
|
||||||
|
|
||||||
|
type InvalidXML struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas invalid-xml"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidXML) GroupErrorName() string { return "invalid-xml" }
|
||||||
|
|
||||||
|
type NotAuthorized struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas not-authorized"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NotAuthorized) GroupErrorName() string { return "not-authorized" }
|
||||||
|
|
||||||
|
type NotWellFormed struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas not-well-formed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NotWellFormed) GroupErrorName() string { return "not-well-formed" }
|
||||||
|
|
||||||
|
type PolicyViolation struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas policy-violation"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PolicyViolation) GroupErrorName() string { return "policy-violation" }
|
||||||
|
|
||||||
|
type RemoteConnectionFailed struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas remote-connection-failed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RemoteConnectionFailed) GroupErrorName() string { return "remote-connection-failed" }
|
||||||
|
|
||||||
|
type Reset struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas reset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Reset) GroupErrorName() string { return "reset" }
|
||||||
|
|
||||||
|
type ResourceConstraint struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas resource-constraint"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ResourceConstraint) GroupErrorName() string { return "resource-constraint" }
|
||||||
|
|
||||||
|
type RestrictedXML struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas restricted-xml"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RestrictedXML) GroupErrorName() string { return "restricted-xml" }
|
||||||
|
|
||||||
|
type SeeOtherHost struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas see-other-host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SeeOtherHost) GroupErrorName() string { return "see-other-host" }
|
||||||
|
|
||||||
|
type SystemShutdown struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas system-shutdown"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SystemShutdown) GroupErrorName() string { return "system-shutdown" }
|
||||||
|
|
||||||
|
type UndefinedCondition struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas undefined-condition"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UndefinedCondition) GroupErrorName() string { return "undefined-condition" }
|
||||||
|
|
||||||
|
type UnsupportedEncoding struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas unsupported-encoding"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnexpectedRequest struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas unexpected-request"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnexpectedRequest) GroupErrorName() string { return "unexpected-request" }
|
||||||
|
|
||||||
|
func (e *UnsupportedEncoding) GroupErrorName() string { return "unsupported-encoding" }
|
||||||
|
|
||||||
|
type UnsupportedStanzaType struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas unsupported-stanza-type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnsupportedStanzaType) GroupErrorName() string { return "unsupported-stanza-type" }
|
||||||
|
|
||||||
|
type UnsupportedVersion struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas unsupported-version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnsupportedVersion) GroupErrorName() string { return "unsupported-version" }
|
||||||
|
|
||||||
|
type XMLNotWellFormed struct {
|
||||||
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-stanzas xml-not-well-formed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *XMLNotWellFormed) GroupErrorName() string { return "xml-not-well-formed" }
|
@ -0,0 +1,187 @@
|
|||||||
|
package stanza_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gosrc.io/xmpp/stanza"
|
||||||
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO : tests to add
|
||||||
|
// - Pop on nil or empty slice
|
||||||
|
// - PeekN (normal and too long)
|
||||||
|
|
||||||
|
func TestPushUnack(t *testing.T) {
|
||||||
|
uaq := initUnAckQueue()
|
||||||
|
toPush := stanza.UnAckedStz{
|
||||||
|
Id: 3,
|
||||||
|
Stz: `<iq type='submit'
|
||||||
|
from='confucius@scholars.lit/home'
|
||||||
|
to='registrar.scholars.lit'
|
||||||
|
id='kj3b157n'
|
||||||
|
xml:lang='en'>
|
||||||
|
<query xmlns='jabber:iq:register'>
|
||||||
|
<username>confucius</username>
|
||||||
|
<first>Qui</first>
|
||||||
|
<last>Kong</last>
|
||||||
|
</query>
|
||||||
|
</iq>`,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := uaq.Push(&toPush)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not push element to the queue : %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uaq.Uslice) != 4 {
|
||||||
|
t.Fatalf("push to the non-acked queue failed")
|
||||||
|
}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
if uaq.Uslice[i].Id != i+1 {
|
||||||
|
t.Fatalf("indexes were not updated correctly. Expected %d got %d", i, uaq.Uslice[i].Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the queue is a fifo : popped element should not be the one we just pushed.
|
||||||
|
popped := uaq.Pop()
|
||||||
|
poppedElt, ok := popped.(*stanza.UnAckedStz)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("popped element is not a *stanza.UnAckedStz")
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.DeepEqual(*poppedElt, toPush) {
|
||||||
|
t.Fatalf("pushed element is at the top of the fifo queue when it should be at the bottom")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPeekUnack(t *testing.T) {
|
||||||
|
uaq := initUnAckQueue()
|
||||||
|
|
||||||
|
expectedPeek := stanza.UnAckedStz{
|
||||||
|
Id: 1,
|
||||||
|
Stz: `<iq type='set'
|
||||||
|
from='romeo@montague.net/home'
|
||||||
|
to='characters.shakespeare.lit'
|
||||||
|
id='search2'
|
||||||
|
xml:lang='en'>
|
||||||
|
<query xmlns='jabber:iq:search'>
|
||||||
|
<last>Capulet</last>
|
||||||
|
</query>
|
||||||
|
</iq>`,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expectedPeek, *uaq.Uslice[0]) {
|
||||||
|
t.Fatalf("peek failed to return the correct stanza")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPopNUnack(t *testing.T) {
|
||||||
|
uaq := initUnAckQueue()
|
||||||
|
initLen := len(uaq.Uslice)
|
||||||
|
randPop := rand.Int31n(int32(initLen))
|
||||||
|
|
||||||
|
popped := uaq.PopN(int(randPop))
|
||||||
|
|
||||||
|
if len(uaq.Uslice)+len(popped) != initLen {
|
||||||
|
t.Fatalf("total length changed whith pop n operation : had %d found %d after pop", initLen, len(uaq.Uslice)+len(popped))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, elt := range popped {
|
||||||
|
for _, oldElt := range uaq.Uslice {
|
||||||
|
if reflect.DeepEqual(elt, oldElt) {
|
||||||
|
t.Fatalf("pop n operation duplicated some elements")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPopNUnackTooLong(t *testing.T) {
|
||||||
|
uaq := initUnAckQueue()
|
||||||
|
initLen := len(uaq.Uslice)
|
||||||
|
|
||||||
|
// Have a random number of elements to pop that's greater than the queue size
|
||||||
|
randPop := rand.Int31n(int32(initLen)) + 1 + int32(initLen)
|
||||||
|
|
||||||
|
popped := uaq.PopN(int(randPop))
|
||||||
|
|
||||||
|
if len(uaq.Uslice)+len(popped) != initLen {
|
||||||
|
t.Fatalf("total length changed whith pop n operation : had %d found %d after pop", initLen, len(uaq.Uslice)+len(popped))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, elt := range popped {
|
||||||
|
for _, oldElt := range uaq.Uslice {
|
||||||
|
if reflect.DeepEqual(elt, oldElt) {
|
||||||
|
t.Fatalf("pop n operation duplicated some elements")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPopUnack(t *testing.T) {
|
||||||
|
uaq := initUnAckQueue()
|
||||||
|
initLen := len(uaq.Uslice)
|
||||||
|
|
||||||
|
popped := uaq.Pop()
|
||||||
|
|
||||||
|
if len(uaq.Uslice)+1 != initLen {
|
||||||
|
t.Fatalf("total length changed whith pop operation : had %d found %d after pop", initLen, len(uaq.Uslice)+1)
|
||||||
|
}
|
||||||
|
for _, oldElt := range uaq.Uslice {
|
||||||
|
if reflect.DeepEqual(popped, oldElt) {
|
||||||
|
t.Fatalf("pop n operation duplicated some elements")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func initUnAckQueue() stanza.UnAckQueue {
|
||||||
|
q := []*stanza.UnAckedStz{
|
||||||
|
{
|
||||||
|
Id: 1,
|
||||||
|
Stz: `<iq type='set'
|
||||||
|
from='romeo@montague.net/home'
|
||||||
|
to='characters.shakespeare.lit'
|
||||||
|
id='search2'
|
||||||
|
xml:lang='en'>
|
||||||
|
<query xmlns='jabber:iq:search'>
|
||||||
|
<last>Capulet</last>
|
||||||
|
</query>
|
||||||
|
</iq>`,
|
||||||
|
},
|
||||||
|
{Id: 2,
|
||||||
|
Stz: `<iq type='get'
|
||||||
|
from='juliet@capulet.com/balcony'
|
||||||
|
to='characters.shakespeare.lit'
|
||||||
|
id='search3'
|
||||||
|
xml:lang='en'>
|
||||||
|
<query xmlns='jabber:iq:search'/>
|
||||||
|
</iq>`},
|
||||||
|
{Id: 3,
|
||||||
|
Stz: `<iq type='set'
|
||||||
|
from='juliet@capulet.com/balcony'
|
||||||
|
to='characters.shakespeare.lit'
|
||||||
|
id='search4'
|
||||||
|
xml:lang='en'>
|
||||||
|
<query xmlns='jabber:iq:search'>
|
||||||
|
<x xmlns='jabber:x:data' type='submit'>
|
||||||
|
<field type='hidden' var='FORM_TYPE'>
|
||||||
|
<value>jabber:iq:search</value>
|
||||||
|
</field>
|
||||||
|
<field var='x-gender'>
|
||||||
|
<value>male</value>
|
||||||
|
</field>
|
||||||
|
</x>
|
||||||
|
</query>
|
||||||
|
</iq>`},
|
||||||
|
}
|
||||||
|
|
||||||
|
return stanza.UnAckQueue{Uslice: q}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().UTC().UnixNano())
|
||||||
|
}
|
Loading…
Reference in new issue