Test refactoring
This commit is contained in:
parent
2579c84481
commit
228cb14491
|
@ -16,8 +16,8 @@ const (
|
||||||
|
|
||||||
func TestClient_Connect(t *testing.T) {
|
func TestClient_Connect(t *testing.T) {
|
||||||
// Setup Mock server
|
// Setup Mock server
|
||||||
mock := XMPPServerMock{}
|
mock := ServerMock{}
|
||||||
mock.Start(t, handlerConnackSuccess)
|
mock.Start(t, testXMPPAddress, handlerConnectSuccess)
|
||||||
|
|
||||||
// Test / Check result
|
// Test / Check result
|
||||||
options := Options{Address: testXMPPAddress, Jid: "test@localhost", Password: "test"}
|
options := Options{Address: testXMPPAddress, Jid: "test@localhost", Password: "test"}
|
||||||
|
@ -28,13 +28,10 @@ func TestClient_Connect(t *testing.T) {
|
||||||
t.Errorf("connect create XMPP client: %s", err)
|
t.Errorf("connect create XMPP client: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var session *Session
|
if _, err = client.Connect(); err != nil {
|
||||||
if session, err = client.Connect(); err != nil {
|
|
||||||
t.Errorf("XMPP connection failed: %s", err)
|
t.Errorf("XMPP connection failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Stream opened, we have streamID = ", session.StreamId)
|
|
||||||
|
|
||||||
mock.Stop()
|
mock.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,30 +40,20 @@ func TestClient_Connect(t *testing.T) {
|
||||||
|
|
||||||
const serverStreamOpen = "<?xml version='1.0'?><stream:stream to='%s' id='%s' xmlns='%s' xmlns:stream='%s' version='1.0'>"
|
const serverStreamOpen = "<?xml version='1.0'?><stream:stream to='%s' id='%s' xmlns='%s' xmlns:stream='%s' version='1.0'>"
|
||||||
|
|
||||||
func handlerConnackSuccess(t *testing.T, c net.Conn) {
|
func handlerConnectSuccess(t *testing.T, c net.Conn) {
|
||||||
decoder := xml.NewDecoder(c)
|
decoder := xml.NewDecoder(c)
|
||||||
checkOpenStream(t, decoder)
|
checkOpenStream(t, c, decoder)
|
||||||
|
|
||||||
if _, err := fmt.Fprintf(c, serverStreamOpen, "localhost", "streamid1", NSClient, NSStream); err != nil {
|
|
||||||
t.Errorf("cannot write server stream open: %s", err)
|
|
||||||
}
|
|
||||||
fmt.Println("Sent stream Open")
|
|
||||||
sendStreamFeatures(t, c, decoder)
|
sendStreamFeatures(t, c, decoder)
|
||||||
fmt.Println("Sent stream feature")
|
|
||||||
readAuth(t, decoder)
|
readAuth(t, decoder)
|
||||||
fmt.Fprintln(c, "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>")
|
fmt.Fprintln(c, "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>")
|
||||||
|
|
||||||
checkOpenStream(t, decoder)
|
checkOpenStream(t, c, decoder)
|
||||||
if _, err := fmt.Fprintf(c, serverStreamOpen, "localhost", "streamid1", NSClient, NSStream); err != nil {
|
|
||||||
t.Errorf("cannot write server stream open: %s", err)
|
|
||||||
}
|
|
||||||
sendBindFeature(t, c, decoder)
|
sendBindFeature(t, c, decoder)
|
||||||
|
|
||||||
bind(t, c, decoder)
|
bind(t, c, decoder)
|
||||||
session(t, c, decoder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkOpenStream(t *testing.T, decoder *xml.Decoder) {
|
func checkOpenStream(t *testing.T, c net.Conn, decoder *xml.Decoder) {
|
||||||
for {
|
for {
|
||||||
var token xml.Token
|
var token xml.Token
|
||||||
token, err := decoder.Token()
|
token, err := decoder.Token()
|
||||||
|
@ -79,11 +66,12 @@ func checkOpenStream(t *testing.T, decoder *xml.Decoder) {
|
||||||
case xml.StartElement:
|
case xml.StartElement:
|
||||||
if elem.Name.Space != NSStream || elem.Name.Local != "stream" {
|
if elem.Name.Space != NSStream || elem.Name.Local != "stream" {
|
||||||
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
|
||||||
|
}
|
||||||
|
if _, err := fmt.Fprintf(c, serverStreamOpen, "localhost", "streamid1", NSClient, NSStream); err != nil {
|
||||||
|
t.Errorf("cannot write server stream open: %s", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Received: %v\n", elem.Name.Local)
|
|
||||||
return
|
return
|
||||||
case xml.ProcInst:
|
|
||||||
fmt.Printf("Received: %v\n", elem.Inst)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +100,6 @@ func readAuth(t *testing.T, decoder *xml.Decoder) string {
|
||||||
nv = &auth{}
|
nv = &auth{}
|
||||||
// Decode element into pointer storage
|
// Decode element into pointer storage
|
||||||
if err = decoder.DecodeElement(nv, &se); err != nil {
|
if err = decoder.DecodeElement(nv, &se); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
t.Errorf("cannot decode auth: %s", err)
|
t.Errorf("cannot decode auth: %s", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -144,7 +131,6 @@ func bind(t *testing.T, c net.Conn, decoder *xml.Decoder) {
|
||||||
iq := &ClientIQ{}
|
iq := &ClientIQ{}
|
||||||
// Decode element into pointer storage
|
// Decode element into pointer storage
|
||||||
if err = decoder.DecodeElement(&iq, &se); err != nil {
|
if err = decoder.DecodeElement(&iq, &se); err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
t.Errorf("cannot decode bind iq: %s", err)
|
t.Errorf("cannot decode bind iq: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -160,68 +146,3 @@ func bind(t *testing.T, c net.Conn, decoder *xml.Decoder) {
|
||||||
</iq>`
|
</iq>`
|
||||||
fmt.Fprintf(c, result, iq.Id, "test@localhost/test") // TODO use real JID
|
fmt.Fprintf(c, result, iq.Id, "test@localhost/test") // TODO use real JID
|
||||||
}
|
}
|
||||||
|
|
||||||
func session(t *testing.T, c net.Conn, decoder *xml.Decoder) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type testHandler func(t *testing.T, conn net.Conn)
|
|
||||||
|
|
||||||
type XMPPServerMock struct {
|
|
||||||
t *testing.T
|
|
||||||
handler testHandler
|
|
||||||
listener net.Listener
|
|
||||||
connections []net.Conn
|
|
||||||
done chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mock *XMPPServerMock) Start(t *testing.T, handler testHandler) {
|
|
||||||
mock.t = t
|
|
||||||
mock.handler = handler
|
|
||||||
if err := mock.init(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go mock.loop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mock *XMPPServerMock) Stop() {
|
|
||||||
close(mock.done)
|
|
||||||
if mock.listener != nil {
|
|
||||||
mock.listener.Close()
|
|
||||||
}
|
|
||||||
// Close all existing connections
|
|
||||||
for _, c := range mock.connections {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mock *XMPPServerMock) init() error {
|
|
||||||
mock.done = make(chan struct{})
|
|
||||||
|
|
||||||
l, err := net.Listen("tcp", testXMPPAddress)
|
|
||||||
if err != nil {
|
|
||||||
mock.t.Errorf("TCPServerMock cannot listen on address: %q", testXMPPAddress)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mock.listener = l
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mock *XMPPServerMock) loop() {
|
|
||||||
listener := mock.listener
|
|
||||||
for {
|
|
||||||
conn, err := listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
select {
|
|
||||||
case <-mock.done:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
mock.t.Error("TCPServerMock accept error:", err.Error())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mock.connections = append(mock.connections, conn)
|
|
||||||
// TODO Create and pass a context to cancel the handler if they are still around = avoid possible leak on complex handlers
|
|
||||||
go mock.handler(mock.t, conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
83
xmpp/tcp_server_mock.go
Normal file
83
xmpp/tcp_server_mock.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package xmpp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// TCP Server Mock
|
||||||
|
|
||||||
|
// ClientHandler is passed by the test client to provide custom behaviour to
|
||||||
|
// the TCP server mock. This allows customizing the server behaviour to allow
|
||||||
|
// testing clients under various scenarii.
|
||||||
|
type ClientHandler func(t *testing.T, conn net.Conn)
|
||||||
|
|
||||||
|
// ServerMock is a simple TCP server that can be use to mock basic server
|
||||||
|
// behaviour to test clients.
|
||||||
|
type ServerMock struct {
|
||||||
|
t *testing.T
|
||||||
|
handler ClientHandler
|
||||||
|
listener net.Listener
|
||||||
|
connections []net.Conn
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start launches the mock TCP server, listening to an actual address / port.
|
||||||
|
func (mock *ServerMock) Start(t *testing.T, addr string, handler ClientHandler) {
|
||||||
|
mock.t = t
|
||||||
|
mock.handler = handler
|
||||||
|
if err := mock.init(addr); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go mock.loop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mock *ServerMock) Stop() {
|
||||||
|
close(mock.done)
|
||||||
|
if mock.listener != nil {
|
||||||
|
mock.listener.Close()
|
||||||
|
}
|
||||||
|
// Close all existing connections
|
||||||
|
for _, c := range mock.connections {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Mock Server internals
|
||||||
|
|
||||||
|
// init starts listener on the provided address.
|
||||||
|
func (mock *ServerMock) init(addr string) error {
|
||||||
|
mock.done = make(chan struct{})
|
||||||
|
|
||||||
|
l, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
mock.t.Errorf("TCPServerMock cannot listen on address: %q", addr)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mock.listener = l
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop accepts connections and creates a go routine per connection.
|
||||||
|
// The go routine is running the client handler, that is used to provide the
|
||||||
|
// real TCP server behaviour.
|
||||||
|
func (mock *ServerMock) loop() {
|
||||||
|
listener := mock.listener
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case <-mock.done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
mock.t.Error("TCPServerMock accept error:", err.Error())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mock.connections = append(mock.connections, conn)
|
||||||
|
// TODO Create and pass a context to cancel the handler if they are still around = avoid possible leak on complex handlers
|
||||||
|
go mock.handler(mock.t, conn)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue