forked from mailgun/manners
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_helper.go
More file actions
155 lines (135 loc) · 3.44 KB
/
test_helper.go
File metadata and controls
155 lines (135 loc) · 3.44 KB
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package manners
import (
"bufio"
"crypto/tls"
"io/ioutil"
"net"
"net/http"
"os"
"testing"
)
func newServer() *GracefulServer {
return NewWithServer(new(http.Server))
}
// a simple step-controllable http client
type client struct {
tls bool
addr net.Addr
connected chan error
sendrequest chan bool
response chan *rawResponse
closed chan bool
}
type rawResponse struct {
body []string
err error
}
func (c *client) Run() {
go func() {
var err error
conn, err := net.Dial(c.addr.Network(), c.addr.String())
if err != nil {
c.connected <- err
return
}
if c.tls {
conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
}
c.connected <- nil
for <-c.sendrequest {
_, err = conn.Write([]byte("GET / HTTP/1.1\nHost: localhost:8000\n\n"))
if err != nil {
c.response <- &rawResponse{err: err}
}
// Read response; no content
scanner := bufio.NewScanner(conn)
var lines []string
for scanner.Scan() {
// our null handler doesn't send a body, so we know the request is
// done when we reach the blank line after the headers
line := scanner.Text()
if line == "" {
break
}
lines = append(lines, line)
}
c.response <- &rawResponse{lines, scanner.Err()}
}
conn.Close()
ioutil.ReadAll(conn)
c.closed <- true
}()
}
func newClient(addr net.Addr, tls bool) *client {
return &client{
addr: addr,
tls: tls,
connected: make(chan error),
sendrequest: make(chan bool),
response: make(chan *rawResponse),
closed: make(chan bool),
}
}
// a handler that returns 200 ok with no body
var nullHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
func startGenericServer(t *testing.T, server *GracefulServer, statechanged chan http.ConnState, runner func() error) (l net.Listener, errc chan error) {
server.Addr = "localhost:0"
server.Handler = nullHandler
if statechanged != nil {
// Wrap the ConnState handler with something that will notify
// the statechanged channel when a state change happens
server.ConnState = func(conn net.Conn, newState http.ConnState) {
s := conn.LocalAddr().(*gracefulAddr).gconn.lastHTTPState
statechanged <- s
}
}
//server.up = make(chan chan bool))
server.up = make(chan net.Listener)
exitchan := make(chan error)
go func() {
err := runner()
if err != nil {
exitchan <- err
} else {
exitchan <- nil
}
}()
// wait for server socket to be bound
select {
case l = <-server.up:
// all good
case err := <-exitchan:
// all bad
t.Fatal("Server failed to start", err)
}
return l, exitchan
}
func startServer(t *testing.T, server *GracefulServer, statechanged chan http.ConnState) (l net.Listener, errc chan error) {
runner := func() error {
return server.ListenAndServe()
}
return startGenericServer(t, server, statechanged, runner)
}
func startTLSServer(t *testing.T, server *GracefulServer, certFile, keyFile string, statechanged chan http.ConnState) (l net.Listener, errc chan error) {
runner := func() error {
return server.ListenAndServeTLS(certFile, keyFile)
}
return startGenericServer(t, server, statechanged, runner)
}
type tempFile struct {
*os.File
}
func newTempFile(content []byte) (*tempFile, error) {
f, err := ioutil.TempFile("", "graceful-test")
if err != nil {
return nil, err
}
f.Write(content)
return &tempFile{f}, nil
}
func (tf *tempFile) Unlink() {
if tf.File != nil {
os.Remove(tf.Name())
tf.File = nil
}
}