-
Notifications
You must be signed in to change notification settings - Fork 26
/
tcplisten_test.go
132 lines (117 loc) · 2.92 KB
/
tcplisten_test.go
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package tcplisten
import (
"fmt"
"io/ioutil"
"net"
"testing"
"time"
)
func TestConfigDeferAccept(t *testing.T) {
testConfig(t, Config{DeferAccept: true})
}
func TestConfigReusePort(t *testing.T) {
testConfig(t, Config{ReusePort: true})
}
func TestConfigFastOpen(t *testing.T) {
testConfig(t, Config{FastOpen: true})
}
func TestConfigAll(t *testing.T) {
cfg := Config{
ReusePort: true,
DeferAccept: true,
FastOpen: true,
}
testConfig(t, cfg)
}
func TestConfigBacklog(t *testing.T) {
cfg := Config{
Backlog: 32,
}
testConfig(t, cfg)
}
func testConfig(t *testing.T, cfg Config) {
testConfigV(t, cfg, "tcp4", "localhost:10081")
testConfigV(t, cfg, "tcp6", "ip6-localhost:10081")
}
func testConfigV(t *testing.T, cfg Config, network, addr string) {
const requestsCount = 1000
var serversCount = 1
if cfg.ReusePort {
serversCount = 10
}
doneCh := make(chan struct{}, serversCount)
var lns []net.Listener
for i := 0; i < serversCount; i++ {
ln, err := cfg.NewListener(network, addr)
if err != nil {
t.Fatalf("cannot create listener %d using Config %#v: %s", i, &cfg, err)
}
go func() {
serveEcho(t, ln)
doneCh <- struct{}{}
}()
lns = append(lns, ln)
}
for i := 0; i < requestsCount; i++ {
c, err := net.Dial(network, addr)
if err != nil {
t.Fatalf("%d. unexpected error when dialing: %s", i, err)
}
req := fmt.Sprintf("request number %d", i)
if _, err = c.Write([]byte(req)); err != nil {
t.Fatalf("%d. unexpected error when writing request: %s", i, err)
}
if err = c.(*net.TCPConn).CloseWrite(); err != nil {
t.Fatalf("%d. unexpected error when closing write end of the connection: %s", i, err)
}
var resp []byte
ch := make(chan struct{})
go func() {
if resp, err = ioutil.ReadAll(c); err != nil {
t.Fatalf("%d. unexpected error when reading response: %s", i, err)
}
close(ch)
}()
select {
case <-ch:
case <-time.After(200 * time.Millisecond):
t.Fatalf("%d. timeout when waiting for response: %s", i, err)
}
if string(resp) != req {
t.Fatalf("%d. unexpected response %q. Expecting %q", i, resp, req)
}
if err = c.Close(); err != nil {
t.Fatalf("%d. unexpected error when closing connection: %s", i, err)
}
}
for _, ln := range lns {
if err := ln.Close(); err != nil {
t.Fatalf("unexpected error when closing listener: %s", err)
}
}
for i := 0; i < serversCount; i++ {
select {
case <-doneCh:
case <-time.After(time.Second):
t.Fatalf("timeout when waiting for servers to be closed")
}
}
}
func serveEcho(t *testing.T, ln net.Listener) {
for {
c, err := ln.Accept()
if err != nil {
break
}
req, err := ioutil.ReadAll(c)
if err != nil {
t.Fatalf("unepxected error when reading request: %s", err)
}
if _, err = c.Write(req); err != nil {
t.Fatalf("unexpected error when writing response: %s", err)
}
if err = c.Close(); err != nil {
t.Fatalf("unexpected error when closing connection: %s", err)
}
}
}