...
1 package handlers
2
3 import (
4 "io/ioutil"
5 "net"
6 "net/http"
7 "net/http/httptest"
8 "os"
9 "testing"
10 "time"
11
12 "github.com/docker/distribution/configuration"
13 "github.com/docker/distribution/context"
14 "github.com/docker/distribution/health"
15 )
16
17 func TestFileHealthCheck(t *testing.T) {
18 interval := time.Second
19
20 tmpfile, err := ioutil.TempFile(os.TempDir(), "healthcheck")
21 if err != nil {
22 t.Fatalf("could not create temporary file: %v", err)
23 }
24 defer tmpfile.Close()
25
26 config := &configuration.Configuration{
27 Storage: configuration.Storage{
28 "inmemory": configuration.Parameters{},
29 "maintenance": configuration.Parameters{"uploadpurging": map[interface{}]interface{}{
30 "enabled": false,
31 }},
32 },
33 Health: configuration.Health{
34 FileCheckers: []configuration.FileChecker{
35 {
36 Interval: interval,
37 File: tmpfile.Name(),
38 },
39 },
40 },
41 }
42
43 ctx := context.Background()
44
45 app := NewApp(ctx, config)
46 healthRegistry := health.NewRegistry()
47 app.RegisterHealthChecks(healthRegistry)
48
49
50 <-time.After(2 * interval)
51
52 status := healthRegistry.CheckStatus()
53 if len(status) != 1 {
54 t.Fatal("expected 1 item in health check results")
55 }
56 if status[tmpfile.Name()] != "file exists" {
57 t.Fatal(`did not get "file exists" result for health check`)
58 }
59
60 os.Remove(tmpfile.Name())
61
62 <-time.After(2 * interval)
63 if len(healthRegistry.CheckStatus()) != 0 {
64 t.Fatal("expected 0 items in health check results")
65 }
66 }
67
68 func TestTCPHealthCheck(t *testing.T) {
69 interval := time.Second
70
71 ln, err := net.Listen("tcp", "127.0.0.1:0")
72 if err != nil {
73 t.Fatalf("could not create listener: %v", err)
74 }
75 addrStr := ln.Addr().String()
76
77
78 go func() {
79 for {
80 conn, err := ln.Accept()
81 if err != nil {
82
83 return
84 }
85 defer conn.Close()
86 }
87 }()
88
89 config := &configuration.Configuration{
90 Storage: configuration.Storage{
91 "inmemory": configuration.Parameters{},
92 "maintenance": configuration.Parameters{"uploadpurging": map[interface{}]interface{}{
93 "enabled": false,
94 }},
95 },
96 Health: configuration.Health{
97 TCPCheckers: []configuration.TCPChecker{
98 {
99 Interval: interval,
100 Addr: addrStr,
101 Timeout: 500 * time.Millisecond,
102 },
103 },
104 },
105 }
106
107 ctx := context.Background()
108
109 app := NewApp(ctx, config)
110 healthRegistry := health.NewRegistry()
111 app.RegisterHealthChecks(healthRegistry)
112
113
114 <-time.After(2 * interval)
115
116 if len(healthRegistry.CheckStatus()) != 0 {
117 t.Fatal("expected 0 items in health check results")
118 }
119
120 ln.Close()
121 <-time.After(2 * interval)
122
123
124 status := healthRegistry.CheckStatus()
125 if len(status) != 1 {
126 t.Fatal("expected 1 item in health check results")
127 }
128 if status[addrStr] != "connection to "+addrStr+" failed" {
129 t.Fatal(`did not get "connection failed" result for health check`)
130 }
131 }
132
133 func TestHTTPHealthCheck(t *testing.T) {
134 interval := time.Second
135 threshold := 3
136
137 stopFailing := make(chan struct{})
138
139 checkedServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
140 if r.Method != "HEAD" {
141 t.Fatalf("expected HEAD request, got %s", r.Method)
142 }
143 select {
144 case <-stopFailing:
145 w.WriteHeader(http.StatusOK)
146 default:
147 w.WriteHeader(http.StatusInternalServerError)
148 }
149 }))
150
151 config := &configuration.Configuration{
152 Storage: configuration.Storage{
153 "inmemory": configuration.Parameters{},
154 "maintenance": configuration.Parameters{"uploadpurging": map[interface{}]interface{}{
155 "enabled": false,
156 }},
157 },
158 Health: configuration.Health{
159 HTTPCheckers: []configuration.HTTPChecker{
160 {
161 Interval: interval,
162 URI: checkedServer.URL,
163 Threshold: threshold,
164 },
165 },
166 },
167 }
168
169 ctx := context.Background()
170
171 app := NewApp(ctx, config)
172 healthRegistry := health.NewRegistry()
173 app.RegisterHealthChecks(healthRegistry)
174
175 for i := 0; ; i++ {
176 <-time.After(interval)
177
178 status := healthRegistry.CheckStatus()
179
180 if i < threshold-1 {
181
182 if len(status) != 0 {
183 t.Fatal("expected 1 item in health check results")
184 }
185 continue
186 }
187 if i < threshold+1 {
188
189 continue
190 }
191
192 if len(status) != 1 {
193 t.Fatal("expected 1 item in health check results")
194 }
195 if status[checkedServer.URL] != "downstream service returned unexpected status: 500" {
196 t.Fatal("did not get expected result for health check")
197 }
198
199 break
200 }
201
202
203 close(stopFailing)
204
205 <-time.After(2 * interval)
206
207 if len(healthRegistry.CheckStatus()) != 0 {
208 t.Fatal("expected 0 items in health check results")
209 }
210 }
211
View as plain text