summaryrefslogtreecommitdiff
path: root/xgb_test.go
blob: e937e62969baead5d10f5b370b48d5e567ec12c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package xgb

import (
	"errors"
	"io"
	"net"
	"runtime"
	"testing"
	"time"
)

type addr struct{}

func (_ addr) Network() string { return "" }
func (_ addr) String() string  { return "" }

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 (_ *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 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)
	}

}