summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xgb_test.go108
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)
+ }
+
}