|
|
@ -7,7 +7,6 @@ import (
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"gosrc.io/xmpp/stanza"
|
|
|
|
"gosrc.io/xmpp/stanza"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
@ -36,7 +35,7 @@ func TestHandshake(t *testing.T) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Tests connection process with a handshake exchange
|
|
|
|
// Tests connection process with a handshake exchange
|
|
|
|
// Tests multiple session IDs. All connections should generate a unique stream ID
|
|
|
|
// Tests multiple session IDs. All serverConnections should generate a unique stream ID
|
|
|
|
func TestGenerateHandshakeId(t *testing.T) {
|
|
|
|
func TestGenerateHandshakeId(t *testing.T) {
|
|
|
|
// Using this array with a channel to make a queue of values to test
|
|
|
|
// Using this array with a channel to make a queue of values to test
|
|
|
|
// These are stream IDs that will be used to test the connection process, mixing them with the "secret" to generate
|
|
|
|
// These are stream IDs that will be used to test the connection process, mixing them with the "secret" to generate
|
|
|
@ -56,11 +55,11 @@ func TestGenerateHandshakeId(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
|
|
// Performs a Component connection with a handshake. It expects to have an ID sent its way through the "uchan"
|
|
|
|
// Performs a Component connection with a handshake. It expects to have an ID sent its way through the "uchan"
|
|
|
|
// channel of this file. Otherwise it will hang for ever.
|
|
|
|
// channel of this file. Otherwise it will hang for ever.
|
|
|
|
h := func(t *testing.T, c net.Conn) {
|
|
|
|
h := func(t *testing.T, sc *ServerConn) {
|
|
|
|
decoder := xml.NewDecoder(c)
|
|
|
|
|
|
|
|
checkOpenStreamHandshakeID(t, c, decoder, <-uchan)
|
|
|
|
checkOpenStreamHandshakeID(t, sc, <-uchan)
|
|
|
|
readHandshakeComponent(t, decoder)
|
|
|
|
readHandshakeComponent(t, sc.decoder)
|
|
|
|
fmt.Fprintln(c, "<handshake/>") // That's all the server needs to return (see xep-0114)
|
|
|
|
fmt.Fprintln(sc.connection, "<handshake/>") // That's all the server needs to return (see xep-0114)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -122,8 +121,8 @@ func TestDecoder(t *testing.T) {
|
|
|
|
// Tests sending an IQ to the server, and getting the response
|
|
|
|
// Tests sending an IQ to the server, and getting the response
|
|
|
|
func TestSendIq(t *testing.T) {
|
|
|
|
func TestSendIq(t *testing.T) {
|
|
|
|
done := make(chan struct{})
|
|
|
|
done := make(chan struct{})
|
|
|
|
h := func(t *testing.T, c net.Conn) {
|
|
|
|
h := func(t *testing.T, sc *ServerConn) {
|
|
|
|
handlerForComponentIQSend(t, c)
|
|
|
|
handlerForComponentIQSend(t, sc)
|
|
|
|
done <- struct{}{}
|
|
|
|
done <- struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -164,8 +163,8 @@ func TestSendIq(t *testing.T) {
|
|
|
|
// Checking that error handling is done properly client side when an invalid IQ is sent and the server responds in kind.
|
|
|
|
// Checking that error handling is done properly client side when an invalid IQ is sent and the server responds in kind.
|
|
|
|
func TestSendIqFail(t *testing.T) {
|
|
|
|
func TestSendIqFail(t *testing.T) {
|
|
|
|
done := make(chan struct{})
|
|
|
|
done := make(chan struct{})
|
|
|
|
h := func(t *testing.T, c net.Conn) {
|
|
|
|
h := func(t *testing.T, sc *ServerConn) {
|
|
|
|
handlerForComponentIQSend(t, c)
|
|
|
|
handlerForComponentIQSend(t, sc)
|
|
|
|
done <- struct{}{}
|
|
|
|
done <- struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//Connecting to a mock server, initialized with given port and handler function
|
|
|
|
//Connecting to a mock server, initialized with given port and handler function
|
|
|
@ -213,27 +212,30 @@ func TestSendIqFail(t *testing.T) {
|
|
|
|
func TestSendRaw(t *testing.T) {
|
|
|
|
func TestSendRaw(t *testing.T) {
|
|
|
|
done := make(chan struct{})
|
|
|
|
done := make(chan struct{})
|
|
|
|
// Handler for the mock server
|
|
|
|
// Handler for the mock server
|
|
|
|
h := func(t *testing.T, c net.Conn) {
|
|
|
|
h := func(t *testing.T, sc *ServerConn) {
|
|
|
|
// Completes the connection by exchanging handshakes
|
|
|
|
// Completes the connection by exchanging handshakes
|
|
|
|
handlerForComponentHandshakeDefaultID(t, c)
|
|
|
|
handlerForComponentHandshakeDefaultID(t, sc)
|
|
|
|
receiveIq(c, xml.NewDecoder(c))
|
|
|
|
respondToIQ(t, sc)
|
|
|
|
done <- struct{}{}
|
|
|
|
done <- struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type testCase struct {
|
|
|
|
type testCase struct {
|
|
|
|
req string
|
|
|
|
req string
|
|
|
|
shouldErr bool
|
|
|
|
shouldErr bool
|
|
|
|
|
|
|
|
port int
|
|
|
|
}
|
|
|
|
}
|
|
|
|
testRequests := make(map[string]testCase)
|
|
|
|
testRequests := make(map[string]testCase)
|
|
|
|
// Sending a correct IQ of type get. Not supposed to err
|
|
|
|
// Sending a correct IQ of type get. Not supposed to err
|
|
|
|
testRequests["Correct IQ"] = testCase{
|
|
|
|
testRequests["Correct IQ"] = testCase{
|
|
|
|
req: `<iq type="get" id="91bd0bba-012f-4d92-bb17-5fc41e6fe545" from="test1@localhost/mremond-mbp" to="testServer" lang="en"><query xmlns="http://jabber.org/protocol/disco#info"></query></iq>`,
|
|
|
|
req: `<iq type="get" id="91bd0bba-012f-4d92-bb17-5fc41e6fe545" from="test1@localhost/mremond-mbp" to="testServer" lang="en"><query xmlns="http://jabber.org/protocol/disco#info"></query></iq>`,
|
|
|
|
shouldErr: false,
|
|
|
|
shouldErr: false,
|
|
|
|
|
|
|
|
port: testSendRawPort + 100,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Sending an IQ with a missing ID. Should err
|
|
|
|
// Sending an IQ with a missing ID. Should err
|
|
|
|
testRequests["IQ with missing ID"] = testCase{
|
|
|
|
testRequests["IQ with missing ID"] = testCase{
|
|
|
|
req: `<iq type="get" from="test1@localhost/mremond-mbp" to="testServer" lang="en"><query xmlns="http://jabber.org/protocol/disco#info"></query></iq>`,
|
|
|
|
req: `<iq type="get" from="test1@localhost/mremond-mbp" to="testServer" lang="en"><query xmlns="http://jabber.org/protocol/disco#info"></query></iq>`,
|
|
|
|
shouldErr: true,
|
|
|
|
shouldErr: true,
|
|
|
|
|
|
|
|
port: testSendRawPort + 200,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// A handler for the component.
|
|
|
|
// A handler for the component.
|
|
|
@ -247,7 +249,7 @@ func TestSendRaw(t *testing.T) {
|
|
|
|
for name, tcase := range testRequests {
|
|
|
|
for name, tcase := range testRequests {
|
|
|
|
t.Run(name, func(st *testing.T) {
|
|
|
|
t.Run(name, func(st *testing.T) {
|
|
|
|
//Connecting to a mock server, initialized with given port and handler function
|
|
|
|
//Connecting to a mock server, initialized with given port and handler function
|
|
|
|
c, m := mockComponentConnection(t, testSendRawPort, h)
|
|
|
|
c, m := mockComponentConnection(t, tcase.port, h)
|
|
|
|
c.ErrorHandler = errHandler
|
|
|
|
c.ErrorHandler = errHandler
|
|
|
|
// Sending raw xml from test case
|
|
|
|
// Sending raw xml from test case
|
|
|
|
err := c.SendRaw(tcase.req)
|
|
|
|
err := c.SendRaw(tcase.req)
|
|
|
@ -328,10 +330,10 @@ func TestStreamManagerDisconnect(t *testing.T) {
|
|
|
|
// Init mock server and connection
|
|
|
|
// Init mock server and connection
|
|
|
|
// Creating a mock server and connecting a Component to it. Initialized with given port and handler function
|
|
|
|
// Creating a mock server and connecting a Component to it. Initialized with given port and handler function
|
|
|
|
// The Component and mock are both returned
|
|
|
|
// The Component and mock are both returned
|
|
|
|
func mockComponentConnection(t *testing.T, port int, handler func(t *testing.T, c net.Conn)) (*Component, *ServerMock) {
|
|
|
|
func mockComponentConnection(t *testing.T, port int, handler func(t *testing.T, sc *ServerConn)) (*Component, *ServerMock) {
|
|
|
|
// Init mock server
|
|
|
|
// Init mock server
|
|
|
|
testComponentAddress := fmt.Sprintf("%s:%d", testComponentDomain, port)
|
|
|
|
testComponentAddress := fmt.Sprintf("%s:%d", testComponentDomain, port)
|
|
|
|
mock := ServerMock{}
|
|
|
|
mock := &ServerMock{}
|
|
|
|
mock.Start(t, testComponentAddress, handler)
|
|
|
|
mock.Start(t, testComponentAddress, handler)
|
|
|
|
|
|
|
|
|
|
|
|
//==================================
|
|
|
|
//==================================
|
|
|
@ -345,7 +347,9 @@ func mockComponentConnection(t *testing.T, port int, handler func(t *testing.T,
|
|
|
|
t.Errorf("%+v", err)
|
|
|
|
t.Errorf("%+v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return c, &mock
|
|
|
|
// Now that the Component is connected, let's set the xml.Decoder for the server
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return c, mock
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func makeBasicComponent(name string, mockServerAddr string, t *testing.T) *Component {
|
|
|
|
func makeBasicComponent(name string, mockServerAddr string, t *testing.T) *Component {
|
|
|
@ -380,19 +384,19 @@ func componentDefaultErrorHandler(err error) {
|
|
|
|
|
|
|
|
|
|
|
|
// Sends IQ response to Component request.
|
|
|
|
// Sends IQ response to Component request.
|
|
|
|
// No parsing of the request here. We just check that it's valid, and send the default response.
|
|
|
|
// No parsing of the request here. We just check that it's valid, and send the default response.
|
|
|
|
func handlerForComponentIQSend(t *testing.T, c net.Conn) {
|
|
|
|
func handlerForComponentIQSend(t *testing.T, sc *ServerConn) {
|
|
|
|
// Completes the connection by exchanging handshakes
|
|
|
|
// Completes the connection by exchanging handshakes
|
|
|
|
handlerForComponentHandshakeDefaultID(t, c)
|
|
|
|
handlerForComponentHandshakeDefaultID(t, sc)
|
|
|
|
respondToIQ(t, c)
|
|
|
|
respondToIQ(t, sc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Used for ID and handshake related tests
|
|
|
|
// Used for ID and handshake related tests
|
|
|
|
func checkOpenStreamHandshakeID(t *testing.T, c net.Conn, decoder *xml.Decoder, streamID string) {
|
|
|
|
func checkOpenStreamHandshakeID(t *testing.T, sc *ServerConn, streamID string) {
|
|
|
|
c.SetDeadline(time.Now().Add(defaultTimeout))
|
|
|
|
sc.connection.SetDeadline(time.Now().Add(defaultTimeout))
|
|
|
|
defer c.SetDeadline(time.Time{})
|
|
|
|
defer sc.connection.SetDeadline(time.Time{})
|
|
|
|
|
|
|
|
|
|
|
|
for { // TODO clean up. That for loop is not elegant and I prefer bounded recursion.
|
|
|
|
for { // TODO clean up. That for loop is not elegant and I prefer bounded recursion.
|
|
|
|
token, err := decoder.Token()
|
|
|
|
token, err := sc.decoder.Token()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("cannot read next token: %s", err)
|
|
|
|
t.Errorf("cannot read next token: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -404,7 +408,7 @@ func checkOpenStreamHandshakeID(t *testing.T, c net.Conn, decoder *xml.Decoder,
|
|
|
|
err = errors.New("xmpp: expected <stream> but got <" + elem.Name.Local + "> in " + elem.Name.Space)
|
|
|
|
err = errors.New("xmpp: expected <stream> but got <" + elem.Name.Local + "> in " + elem.Name.Space)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if _, err := fmt.Fprintf(c, serverStreamOpen, "localhost", streamID, stanza.NSComponent, stanza.NSStream); err != nil {
|
|
|
|
if _, err := fmt.Fprintf(sc.connection, serverStreamOpen, "localhost", streamID, stanza.NSComponent, stanza.NSStream); err != nil {
|
|
|
|
t.Errorf("cannot write server stream open: %s", err)
|
|
|
|
t.Errorf("cannot write server stream open: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -412,16 +416,15 @@ func checkOpenStreamHandshakeID(t *testing.T, c net.Conn, decoder *xml.Decoder,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func checkOpenStreamHandshakeDefaultID(t *testing.T, c net.Conn, decoder *xml.Decoder) {
|
|
|
|
func checkOpenStreamHandshakeDefaultID(t *testing.T, sc *ServerConn) {
|
|
|
|
checkOpenStreamHandshakeID(t, c, decoder, defaultStreamID)
|
|
|
|
checkOpenStreamHandshakeID(t, sc, defaultStreamID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Performs a Component connection with a handshake. It uses a default ID defined in this file as a constant.
|
|
|
|
// Performs a Component connection with a handshake. It uses a default ID defined in this file as a constant.
|
|
|
|
// This handler is supposed to fail by sending a "message" stanza instead of a <handshake/> stanza to finalize the handshake.
|
|
|
|
// This handler is supposed to fail by sending a "message" stanza instead of a <handshake/> stanza to finalize the handshake.
|
|
|
|
func handlerComponentFailedHandshakeDefaultID(t *testing.T, c net.Conn) {
|
|
|
|
func handlerComponentFailedHandshakeDefaultID(t *testing.T, sc *ServerConn) {
|
|
|
|
decoder := xml.NewDecoder(c)
|
|
|
|
checkOpenStreamHandshakeDefaultID(t, sc)
|
|
|
|
checkOpenStreamHandshakeDefaultID(t, c, decoder)
|
|
|
|
readHandshakeComponent(t, sc.decoder)
|
|
|
|
readHandshakeComponent(t, decoder)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send a message, instead of a "<handshake/>" tag, to fail the handshake process dans disconnect the client.
|
|
|
|
// Send a message, instead of a "<handshake/>" tag, to fail the handshake process dans disconnect the client.
|
|
|
|
me := stanza.Message{
|
|
|
|
me := stanza.Message{
|
|
|
@ -429,7 +432,7 @@ func handlerComponentFailedHandshakeDefaultID(t *testing.T, c net.Conn) {
|
|
|
|
Body: "Fail my handshake.",
|
|
|
|
Body: "Fail my handshake.",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s, _ := xml.Marshal(me)
|
|
|
|
s, _ := xml.Marshal(me)
|
|
|
|
fmt.Fprintln(c, string(s))
|
|
|
|
fmt.Fprintln(sc.connection, string(s))
|
|
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -454,10 +457,9 @@ func readHandshakeComponent(t *testing.T, decoder *xml.Decoder) {
|
|
|
|
|
|
|
|
|
|
|
|
// Performs a Component connection with a handshake. It uses a default ID defined in this file as a constant.
|
|
|
|
// Performs a Component connection with a handshake. It uses a default ID defined in this file as a constant.
|
|
|
|
// Used in the mock server as a Handler
|
|
|
|
// Used in the mock server as a Handler
|
|
|
|
func handlerForComponentHandshakeDefaultID(t *testing.T, c net.Conn) {
|
|
|
|
func handlerForComponentHandshakeDefaultID(t *testing.T, sc *ServerConn) {
|
|
|
|
decoder := xml.NewDecoder(c)
|
|
|
|
checkOpenStreamHandshakeDefaultID(t, sc)
|
|
|
|
checkOpenStreamHandshakeDefaultID(t, c, decoder)
|
|
|
|
readHandshakeComponent(t, sc.decoder)
|
|
|
|
readHandshakeComponent(t, decoder)
|
|
|
|
fmt.Fprintln(sc.connection, "<handshake/>") // That's all the server needs to return (see xep-0114)
|
|
|
|
fmt.Fprintln(c, "<handshake/>") // That's all the server needs to return (see xep-0114)
|
|
|
|
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|