diff options
| -rw-r--r-- | xgb_test.go | 108 |
1 files changed, 98 insertions, 10 deletions
diff --git a/xgb_test.go b/xgb_test.go index 55c70d4..e937e62 100644 --- a/xgb_test.go +++ b/xgb_test.go @@ -1,7 +1,10 @@ package xgb import ( + "errors" + "io" "net" + "runtime" "testing" "time" ) @@ -11,20 +14,105 @@ type addr struct{} func (_ addr) Network() string { return "" } func (_ addr) String() string { return "" } -type server struct{} +type server struct { + control chan interface{} + done chan struct{} +} + +func newServer() net.Conn { + s := &server{ + make(chan interface{}), + make(chan struct{}), + } + go func() { + defer close(s.done) + for { + select { + case ci := <-s.control: + if ci == nil { + return + } + } + } + }() + return s +} -func (s *server) Write(b []byte) (int, error) { return len(b), nil } -func (s *server) Read(b []byte) (int, error) { return len(b), nil } -func (s *server) Close() error { return nil } -func (s *server) LocalAddr() Addr { return addr{} } -func (s *server) RemoteAddr() Addr { return addr{} } +func (_ *server) errClosed() error { + return errors.New("closed") +} +func (_ *server) errEOF() error { + return io.EOF +} + +func (s *server) Write(b []byte) (int, error) { + select { + case <-s.done: + } + return 0, s.errClosed() +} + +func (s *server) Read(b []byte) (int, error) { + select { + case <-s.done: + } + return 0, s.errEOF() +} +func (s *server) Close() error { + select { + case s.control <- nil: + <-s.done + return nil + case <-s.done: + return s.errClosed() + } +} +func (s *server) LocalAddr() net.Addr { return addr{} } +func (s *server) RemoteAddr() net.Addr { return addr{} } func (s *server) SetDeadline(t time.Time) error { return nil } func (s *server) SetReadDeadline(t time.Time) error { return nil } func (s *server) SetWriteDeadline(t time.Time) error { return nil } -func dummyServer() net.Conn { - return &server -} - func TestConnOpenClose(t *testing.T) { + ngrs := runtime.NumGoroutine() + + t.Logf("creating new dummy blocking server") + s := newServer() + defer func() { + if err := s.Close(); err != nil { + t.Errorf("server closing error: %v", err) + } + }() + t.Logf("new server created: %v", s) + + leakTimeout := time.Second + defer func() { + if ngre := runtime.NumGoroutine(); ngrs != ngre { + t.Logf("possible goroutine leakage, waiting %v", leakTimeout) + time.Sleep(time.Second) + if ngre := runtime.NumGoroutine(); ngrs != ngre { + t.Errorf("goroutine leaks: start(%d) != end(%d)", ngrs, ngre) + } + } + }() + + c, err := postNewConn(&Conn{conn: s}) + if err != nil { + t.Fatalf("connect error: %v", err) + } + t.Logf("connection to server created: %v", c) + + closeErr := make(chan error, 1) + closeTimeout := time.Second + select { + case closeErr <- func() error { + t.Logf("closing connection to server") + c.Close() + t.Logf("connection to server closed") + return nil + }(): + case <-time.After(closeTimeout): + t.Errorf("*Conn.Close() not responded for %v", closeTimeout) + } + } |
