Add tests for explicit and implicit (via EOF) shutdown; fix bug ;-)

This commit is contained in:
Alex Bramley 2011-08-23 10:53:52 +01:00
parent 770c5eb5ac
commit 7d9b8c3099
2 changed files with 85 additions and 1 deletions

View File

@ -265,11 +265,11 @@ func (conn *Conn) shutdown() {
// Guard against double-call of shutdown() if we get an error in send() // Guard against double-call of shutdown() if we get an error in send()
// as calling sock.Close() will cause recv() to recieve EOF in readstring() // as calling sock.Close() will cause recv() to recieve EOF in readstring()
if conn.Connected { if conn.Connected {
conn.Dispatcher.Dispatch("disconnected", conn, &Line{})
conn.Connected = false conn.Connected = false
conn.sock.Close() conn.sock.Close()
conn.cSend <- true conn.cSend <- true
conn.cLoop <- true conn.cLoop <- true
conn.Dispatcher.Dispatch("disconnected", conn, &Line{})
// reinit datastructures ready for next connection // reinit datastructures ready for next connection
// do this here rather than after runLoop()'s for due to race // do this here rather than after runLoop()'s for due to race
conn.initialise() conn.initialise()

View File

@ -3,6 +3,7 @@ package client
import ( import (
"strings" "strings"
"testing" "testing"
"time"
) )
func setUp(t *testing.T) (*mockNetConn, *Conn) { func setUp(t *testing.T) (*mockNetConn, *Conn) {
@ -14,6 +15,89 @@ func setUp(t *testing.T) (*mockNetConn, *Conn) {
return m, c return m, c
} }
func tearDown(m *mockNetConn, c *Conn) {
// This is enough to cause all the associated goroutines in m and c stop
// (tested below in TestShutdown to make sure this is the case)
m.Close()
}
func TestShutdown(t *testing.T) {
_, c := setUp(t)
// Shutdown won't clean things up unless we're "connected" already
c.Connected = true
// Setup a mock event dispatcher to test correct triggering of "disconnected"
flag := false
c.Dispatcher = WasEventDispatched("disconnected", &flag)
// Call shutdown manually
c.shutdown()
// Check that we get an EOF from Read()
timer := time.NewTimer(5e6)
select {
case <-timer.C:
t.Errorf("No error received for shutdown.")
case err := <-c.Err:
timer.Stop()
if err.String() != "irc.recv(): EOF" {
t.Errorf("Expected EOF, got: %s", err)
}
}
// Verify that the connection no longer thinks it's connected
if c.Connected {
t.Errorf("Conn still thinks it's connected to the server.")
}
// Verify that the "disconnected" event fired correctly
if !flag {
t.Errorf("Calling Close() didn't result in dispatch of disconnected event.")
}
// TODO(fluffle): Try to work out a way of testing that the background
// goroutines were *actually* stopped? Test m a bit more?
}
// Practically the same as the above test, but shutdown is called implicitly
// by recv() getting an EOF from the mock connection.
func TestEOF(t *testing.T) {
m, c := setUp(t)
// Shutdown won't clean things up unless we're "connected" already
c.Connected = true
// Setup a mock event dispatcher to test correct triggering of "disconnected"
flag := false
c.Dispatcher = WasEventDispatched("disconnected", &flag)
// Simulate EOF from server
m.Close()
// Check that we get an EOF from Read()
timer := time.NewTimer(5e6)
select {
case <-timer.C:
t.Errorf("No error received for shutdown.")
case err := <-c.Err:
timer.Stop()
if err.String() != "irc.recv(): EOF" {
t.Errorf("Expected EOF, got: %s", err)
}
}
// Verify that the connection no longer thinks it's connected
if c.Connected {
t.Errorf("Conn still thinks it's connected to the server.")
}
// Verify that the "disconnected" event fired correctly
if !flag {
t.Errorf("Calling Close() didn't result in dispatch of disconnected event.")
}
}
// Mock dispatcher to verify that events are triggered successfully // Mock dispatcher to verify that events are triggered successfully
type mockDispatcher func(string, ...interface{}) type mockDispatcher func(string, ...interface{})