@@ -16,6 +16,7 @@ package promhttp
1616import (
1717 "bytes"
1818 "errors"
19+ "fmt"
1920 "log"
2021 "net/http"
2122 "net/http/httptest"
@@ -24,6 +25,7 @@ import (
2425 "time"
2526
2627 "github.com/prometheus/client_golang/prometheus"
28+ dto "github.com/prometheus/client_model/go"
2729)
2830
2931type errorCollector struct {}
@@ -56,8 +58,19 @@ func (b blockingCollector) Collect(ch chan<- prometheus.Metric) {
5658 <- b .Block
5759}
5860
59- func TestHandlerErrorHandling (t * testing.T ) {
61+ type mockTransactionGatherer struct {
62+ g prometheus.Gatherer
63+ gatherInvoked int
64+ doneInvoked int
65+ }
6066
67+ func (g * mockTransactionGatherer ) Gather () (_ []* dto.MetricFamily , done func (), err error ) {
68+ g .gatherInvoked ++
69+ mfs , err := g .g .Gather ()
70+ return mfs , func () { g .doneInvoked ++ }, err
71+ }
72+
73+ func TestHandlerErrorHandling (t * testing.T ) {
6174 // Create a registry that collects a MetricFamily with two elements,
6275 // another with one, and reports an error. Further down, we'll use the
6376 // same registry in the HandlerOpts.
@@ -90,21 +103,30 @@ func TestHandlerErrorHandling(t *testing.T) {
90103 request , _ := http .NewRequest ("GET" , "/" , nil )
91104 request .Header .Add ("Accept" , "test/plain" )
92105
93- errorHandler := HandlerFor (reg , HandlerOpts {
106+ mReg := & mockTransactionGatherer {g : reg }
107+ errorHandler := HandlerForTransactional (mReg , HandlerOpts {
94108 ErrorLog : logger ,
95109 ErrorHandling : HTTPErrorOnError ,
96110 Registry : reg ,
97111 })
98- continueHandler := HandlerFor ( reg , HandlerOpts {
112+ continueHandler := HandlerForTransactional ( mReg , HandlerOpts {
99113 ErrorLog : logger ,
100114 ErrorHandling : ContinueOnError ,
101115 Registry : reg ,
102116 })
103- panicHandler := HandlerFor ( reg , HandlerOpts {
117+ panicHandler := HandlerForTransactional ( mReg , HandlerOpts {
104118 ErrorLog : logger ,
105119 ErrorHandling : PanicOnError ,
106120 Registry : reg ,
107121 })
122+ // Expect gatherer not touched.
123+ if got := mReg .gatherInvoked ; got != 0 {
124+ t .Fatalf ("unexpected number of gather invokes, want 0, got %d" , got )
125+ }
126+ if got := mReg .doneInvoked ; got != 0 {
127+ t .Fatalf ("unexpected number of done invokes, want 0, got %d" , got )
128+ }
129+
108130 wantMsg := `error gathering metrics: error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: []}: collect error
109131`
110132 wantErrorBody := `An error has occurred while serving metrics:
@@ -140,25 +162,39 @@ the_count 0
140162`
141163
142164 errorHandler .ServeHTTP (writer , request )
165+ if got := mReg .gatherInvoked ; got != 1 {
166+ t .Fatalf ("unexpected number of gather invokes, want 1, got %d" , got )
167+ }
168+ if got := mReg .doneInvoked ; got != 1 {
169+ t .Fatalf ("unexpected number of done invokes, want 1, got %d" , got )
170+ }
143171 if got , want := writer .Code , http .StatusInternalServerError ; got != want {
144172 t .Errorf ("got HTTP status code %d, want %d" , got , want )
145173 }
146- if got := logBuf .String (); got != wantMsg {
147- t .Errorf ("got log message: \n %s \n want log message: \n %s \n " , got , wantMsg )
174+ if got , want := logBuf .String (), wantMsg ; got != want {
175+ t .Errorf ("got log buf %q, want %q " , got , want )
148176 }
149- if got := writer .Body .String (); got != wantErrorBody {
150- t .Errorf ("got body: \n %s \n want body: \n %s \n " , got , wantErrorBody )
177+ if got , want := writer .Body .String (), wantErrorBody ; got != want {
178+ t .Errorf ("got body %q, want %q " , got , want )
151179 }
180+
152181 logBuf .Reset ()
153182 writer .Body .Reset ()
154183 writer .Code = http .StatusOK
155184
156185 continueHandler .ServeHTTP (writer , request )
186+
187+ if got := mReg .gatherInvoked ; got != 2 {
188+ t .Fatalf ("unexpected number of gather invokes, want 2, got %d" , got )
189+ }
190+ if got := mReg .doneInvoked ; got != 2 {
191+ t .Fatalf ("unexpected number of done invokes, want 2, got %d" , got )
192+ }
157193 if got , want := writer .Code , http .StatusOK ; got != want {
158194 t .Errorf ("got HTTP status code %d, want %d" , got , want )
159195 }
160- if got := logBuf .String (); got != wantMsg {
161- t .Errorf ("got log message %q, want %q" , got , wantMsg )
196+ if got , want := logBuf .String (), wantMsg ; got != want {
197+ t .Errorf ("got log buf %q, want %q" , got , want )
162198 }
163199 if got := writer .Body .String (); got != wantOKBody1 && got != wantOKBody2 {
164200 t .Errorf ("got body %q, want either %q or %q" , got , wantOKBody1 , wantOKBody2 )
@@ -168,20 +204,34 @@ the_count 0
168204 if err := recover (); err == nil {
169205 t .Error ("expected panic from panicHandler" )
170206 }
207+ if got := mReg .gatherInvoked ; got != 3 {
208+ t .Fatalf ("unexpected number of gather invokes, want 3, got %d" , got )
209+ }
210+ if got := mReg .doneInvoked ; got != 3 {
211+ t .Fatalf ("unexpected number of done invokes, want 3, got %d" , got )
212+ }
171213 }()
172214 panicHandler .ServeHTTP (writer , request )
173215}
174216
175217func TestInstrumentMetricHandler (t * testing.T ) {
176218 reg := prometheus .NewRegistry ()
177- handler := InstrumentMetricHandler (reg , HandlerFor (reg , HandlerOpts {}))
219+ mReg := & mockTransactionGatherer {g : reg }
220+ handler := InstrumentMetricHandler (reg , HandlerForTransactional (mReg , HandlerOpts {}))
178221 // Do it again to test idempotency.
179- InstrumentMetricHandler (reg , HandlerFor ( reg , HandlerOpts {}))
222+ InstrumentMetricHandler (reg , HandlerForTransactional ( mReg , HandlerOpts {}))
180223 writer := httptest .NewRecorder ()
181224 request , _ := http .NewRequest ("GET" , "/" , nil )
182225 request .Header .Add ("Accept" , "test/plain" )
183226
184227 handler .ServeHTTP (writer , request )
228+ if got := mReg .gatherInvoked ; got != 1 {
229+ t .Fatalf ("unexpected number of gather invokes, want 1, got %d" , got )
230+ }
231+ if got := mReg .doneInvoked ; got != 1 {
232+ t .Fatalf ("unexpected number of done invokes, want 1, got %d" , got )
233+ }
234+
185235 if got , want := writer .Code , http .StatusOK ; got != want {
186236 t .Errorf ("got HTTP status code %d, want %d" , got , want )
187237 }
@@ -195,19 +245,28 @@ func TestInstrumentMetricHandler(t *testing.T) {
195245 t .Errorf ("got body %q, does not contain %q" , got , want )
196246 }
197247
198- writer .Body .Reset ()
199- handler .ServeHTTP (writer , request )
200- if got , want := writer .Code , http .StatusOK ; got != want {
201- t .Errorf ("got HTTP status code %d, want %d" , got , want )
202- }
248+ for i := 0 ; i < 100 ; i ++ {
249+ writer .Body .Reset ()
250+ handler .ServeHTTP (writer , request )
203251
204- want = "promhttp_metric_handler_requests_in_flight 1\n "
205- if got := writer .Body .String (); ! strings .Contains (got , want ) {
206- t .Errorf ("got body %q, does not contain %q" , got , want )
207- }
208- want = "promhttp_metric_handler_requests_total{code=\" 200\" } 1\n "
209- if got := writer .Body .String (); ! strings .Contains (got , want ) {
210- t .Errorf ("got body %q, does not contain %q" , got , want )
252+ if got , want := mReg .gatherInvoked , i + 2 ; got != want {
253+ t .Fatalf ("unexpected number of gather invokes, want %d, got %d" , want , got )
254+ }
255+ if got , want := mReg .doneInvoked , i + 2 ; got != want {
256+ t .Fatalf ("unexpected number of done invokes, want %d, got %d" , want , got )
257+ }
258+ if got , want := writer .Code , http .StatusOK ; got != want {
259+ t .Errorf ("got HTTP status code %d, want %d" , got , want )
260+ }
261+
262+ want := "promhttp_metric_handler_requests_in_flight 1\n "
263+ if got := writer .Body .String (); ! strings .Contains (got , want ) {
264+ t .Errorf ("got body %q, does not contain %q" , got , want )
265+ }
266+ want = fmt .Sprintf ("promhttp_metric_handler_requests_total{code=\" 200\" } %d\n " , i + 1 )
267+ if got := writer .Body .String (); ! strings .Contains (got , want ) {
268+ t .Errorf ("got body %q, does not contain %q" , got , want )
269+ }
211270 }
212271}
213272
0 commit comments