1 package measured_http
2
3 import (
4 "net/http"
5 "net/http/httptest"
6 "net/url"
7 "testing"
8 "time"
9
10 "github.com/jmhodges/clock"
11 "github.com/prometheus/client_golang/prometheus"
12 io_prometheus_client "github.com/prometheus/client_model/go"
13 )
14
15 type sleepyHandler struct {
16 clk clock.FakeClock
17 }
18
19 func (h sleepyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
20 h.clk.Sleep(999 * time.Second)
21 w.WriteHeader(302)
22 }
23
24 func collect(m prometheus.Collector) *io_prometheus_client.Metric {
25 ch := make(chan prometheus.Metric, 10)
26 m.Collect(ch)
27 result := <-ch
28 var iom = new(io_prometheus_client.Metric)
29 _ = result.Write(iom)
30 return iom
31 }
32
33 func TestMeasuring(t *testing.T) {
34 clk := clock.NewFake()
35
36
37
38 stat := prometheus.NewHistogramVec(
39 prometheus.HistogramOpts{
40 Name: "fake",
41 Help: "fake",
42 },
43 []string{"endpoint", "method", "code"})
44
45 mux := http.NewServeMux()
46 mux.Handle("/foo", sleepyHandler{clk})
47 mh := MeasuredHandler{
48 serveMux: mux,
49 clk: clk,
50 stat: stat,
51 }
52 mh.ServeHTTP(httptest.NewRecorder(), &http.Request{
53 URL: &url.URL{Path: "/foo"},
54 Method: "GET",
55 })
56 iom := collect(stat)
57
58 hist := iom.Histogram
59 if *hist.SampleCount != 1 {
60 t.Errorf("SampleCount = %d (expected 1)", *hist.SampleCount)
61 }
62 if *hist.SampleSum != 999 {
63 t.Errorf("SampleSum = %g (expected 999)", *hist.SampleSum)
64 }
65
66 expectedLabels := map[string]string{
67 "endpoint": "/foo",
68 "method": "GET",
69 "code": "302",
70 }
71 for _, labelPair := range iom.Label {
72 if expectedLabels[*labelPair.Name] == "" {
73 t.Errorf("Unexpected label %s", *labelPair.Name)
74 } else if expectedLabels[*labelPair.Name] != *labelPair.Value {
75 t.Errorf("labels[%q] = %q (expected %q)", *labelPair.Name, *labelPair.Value,
76 expectedLabels[*labelPair.Name])
77 }
78 delete(expectedLabels, *labelPair.Name)
79 }
80 if len(expectedLabels) != 0 {
81 t.Errorf("Some labels were expected, but not observed: %v", expectedLabels)
82 }
83 }
84
85
86
87 func TestUnknownMethod(t *testing.T) {
88 clk := clock.NewFake()
89
90
91
92 stat := prometheus.NewHistogramVec(
93 prometheus.HistogramOpts{
94 Name: "fake",
95 Help: "fake",
96 },
97 []string{"endpoint", "method", "code"})
98
99 mux := http.NewServeMux()
100 mux.Handle("/foo", sleepyHandler{clk})
101 mh := MeasuredHandler{
102 serveMux: mux,
103 clk: clk,
104 stat: stat,
105 }
106 mh.ServeHTTP(httptest.NewRecorder(), &http.Request{
107 URL: &url.URL{Path: "/foo"},
108 Method: "POKE",
109 })
110 iom := collect(stat)
111
112 expectedLabels := map[string]string{
113 "endpoint": "/foo",
114 "method": "unknown",
115 "code": "302",
116 }
117 for _, labelPair := range iom.Label {
118 if expectedLabels[*labelPair.Name] == "" {
119 t.Errorf("Unexpected label %s", *labelPair.Name)
120 } else if expectedLabels[*labelPair.Name] != *labelPair.Value {
121 t.Errorf("labels[%q] = %q (expected %q)", *labelPair.Name, *labelPair.Value,
122 expectedLabels[*labelPair.Name])
123 }
124 delete(expectedLabels, *labelPair.Name)
125 }
126 if len(expectedLabels) != 0 {
127 t.Errorf("Some labels were expected, but not observed: %v", expectedLabels)
128 }
129 }
130
131 func TestWrite(t *testing.T) {
132 clk := clock.NewFake()
133
134
135
136 stat := prometheus.NewHistogramVec(
137 prometheus.HistogramOpts{
138 Name: "fake",
139 Help: "fake",
140 },
141 []string{"endpoint", "method", "code"})
142
143 mux := http.NewServeMux()
144 mux.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
145 w.Write([]byte{})
146 })
147 mh := MeasuredHandler{
148 serveMux: mux,
149 clk: clk,
150 stat: stat,
151 }
152 mh.ServeHTTP(httptest.NewRecorder(), &http.Request{
153 URL: &url.URL{Path: "/foo"},
154 Method: "GET",
155 })
156 iom := collect(stat)
157
158 stat = prometheus.NewHistogramVec(
159 prometheus.HistogramOpts{
160 Name: "fake",
161 Help: "fake",
162 },
163 []string{"endpoint", "method", "code"})
164 mh.stat = stat
165 expectedLabels := map[string]string{
166 "endpoint": "/foo",
167 "method": "GET",
168 "code": "200",
169 }
170 for _, labelPair := range iom.Label {
171 if expectedLabels[*labelPair.Name] == "" {
172 t.Errorf("Unexpected label %s", *labelPair.Name)
173 } else if expectedLabels[*labelPair.Name] != *labelPair.Value {
174 t.Errorf("labels[%q] = %q (expected %q)", *labelPair.Name, *labelPair.Value,
175 expectedLabels[*labelPair.Name])
176 }
177 delete(expectedLabels, *labelPair.Name)
178 }
179 if len(expectedLabels) != 0 {
180 t.Errorf("Some labels were expected, but not observed: %v", expectedLabels)
181 }
182
183 mux.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
184 w.WriteHeader(202)
185 w.Write([]byte{})
186 })
187 mh.ServeHTTP(httptest.NewRecorder(), &http.Request{
188 URL: &url.URL{Path: "/bar"},
189 Method: "GET",
190 })
191 iom = collect(stat)
192
193 expectedLabels = map[string]string{
194 "endpoint": "/bar",
195 "method": "GET",
196 "code": "202",
197 }
198 for _, labelPair := range iom.Label {
199 if expectedLabels[*labelPair.Name] == "" {
200 t.Errorf("Unexpected label %s", *labelPair.Name)
201 } else if expectedLabels[*labelPair.Name] != *labelPair.Value {
202 t.Errorf("labels[%q] = %q (expected %q)", *labelPair.Name, *labelPair.Value,
203 expectedLabels[*labelPair.Name])
204 }
205 delete(expectedLabels, *labelPair.Name)
206 }
207 if len(expectedLabels) != 0 {
208 t.Errorf("Some labels were expected, but not observed: %v", expectedLabels)
209 }
210 }
211
View as plain text