@@ -15,8 +15,10 @@ package promhttp
15
15
16
16
import (
17
17
"bytes"
18
+ "compress/gzip"
18
19
"errors"
19
20
"fmt"
21
+ "io"
20
22
"log"
21
23
"net/http"
22
24
"net/http/httptest"
@@ -31,6 +33,11 @@ import (
31
33
32
34
type errorCollector struct {}
33
35
36
+ const (
37
+ acceptHeader = "Accept"
38
+ acceptTextPlain = "text/plain"
39
+ )
40
+
34
41
func (e errorCollector ) Describe (ch chan <- * prometheus.Desc ) {
35
42
ch <- prometheus .NewDesc ("invalid_metric" , "not helpful" , nil , nil )
36
43
}
@@ -71,6 +78,16 @@ func (g *mockTransactionGatherer) Gather() (_ []*dto.MetricFamily, done func(),
71
78
return mfs , func () { g .doneInvoked ++ }, err
72
79
}
73
80
81
+ func readGzippedBody (r io.Reader ) (string , error ) {
82
+ reader , err := gzip .NewReader (r )
83
+ if err != nil {
84
+ return "" , err
85
+ }
86
+ defer reader .Close ()
87
+ got , err := io .ReadAll (reader )
88
+ return string (got ), err
89
+ }
90
+
74
91
func TestHandlerErrorHandling (t * testing.T ) {
75
92
// Create a registry that collects a MetricFamily with two elements,
76
93
// another with one, and reports an error. Further down, we'll use the
@@ -223,7 +240,7 @@ func TestInstrumentMetricHandler(t *testing.T) {
223
240
InstrumentMetricHandler (reg , HandlerForTransactional (mReg , HandlerOpts {}))
224
241
writer := httptest .NewRecorder ()
225
242
request , _ := http .NewRequest ("GET" , "/" , nil )
226
- request .Header .Add ("Accept" , "test/plain" )
243
+ request .Header .Add (acceptHeader , acceptTextPlain )
227
244
228
245
handler .ServeHTTP (writer , request )
229
246
if got := mReg .gatherInvoked ; got != 1 {
@@ -237,6 +254,10 @@ func TestInstrumentMetricHandler(t *testing.T) {
237
254
t .Errorf ("got HTTP status code %d, want %d" , got , want )
238
255
}
239
256
257
+ if got , want := writer .Header ().Get (contentEncodingHeader ), string (Identity ); got != want {
258
+ t .Errorf ("got HTTP content encoding header %s, want %s" , got , want )
259
+ }
260
+
240
261
want := "promhttp_metric_handler_requests_in_flight 1\n "
241
262
if got := writer .Body .String (); ! strings .Contains (got , want ) {
242
263
t .Errorf ("got body %q, does not contain %q" , got , want )
@@ -278,7 +299,7 @@ func TestHandlerMaxRequestsInFlight(t *testing.T) {
278
299
w2 := httptest .NewRecorder ()
279
300
w3 := httptest .NewRecorder ()
280
301
request , _ := http .NewRequest ("GET" , "/" , nil )
281
- request .Header .Add ("Accept" , "test/plain" )
302
+ request .Header .Add (acceptHeader , acceptTextPlain )
282
303
283
304
c := blockingCollector {Block : make (chan struct {}), CollectStarted : make (chan struct {}, 1 )}
284
305
reg .MustRegister (c )
@@ -332,6 +353,69 @@ func TestHandlerTimeout(t *testing.T) {
332
353
close (c .Block ) // To not leak a goroutine.
333
354
}
334
355
356
+ func TestInstrumentMetricHandlerWithCompression (t * testing.T ) {
357
+ reg := prometheus .NewRegistry ()
358
+ mReg := & mockTransactionGatherer {g : reg }
359
+ handler := InstrumentMetricHandler (reg , HandlerForTransactional (mReg , HandlerOpts {DisableCompression : false }))
360
+ writer := httptest .NewRecorder ()
361
+ request , _ := http .NewRequest ("GET" , "/" , nil )
362
+ request .Header .Add (acceptHeader , acceptTextPlain )
363
+ request .Header .Add (acceptEncodingHeader , string (Gzip ))
364
+
365
+ handler .ServeHTTP (writer , request )
366
+ if got := mReg .gatherInvoked ; got != 1 {
367
+ t .Fatalf ("unexpected number of gather invokes, want 1, got %d" , got )
368
+ }
369
+ if got := mReg .doneInvoked ; got != 1 {
370
+ t .Fatalf ("unexpected number of done invokes, want 1, got %d" , got )
371
+ }
372
+
373
+ if got , want := writer .Code , http .StatusOK ; got != want {
374
+ t .Errorf ("got HTTP status code %d, want %d" , got , want )
375
+ }
376
+
377
+ if got , want := writer .Header ().Get (contentEncodingHeader ), string (Gzip ); got != want {
378
+ t .Errorf ("got HTTP content encoding header %s, want %s" , got , want )
379
+ }
380
+
381
+ body , err := readGzippedBody (writer .Body )
382
+ want := "promhttp_metric_handler_requests_in_flight 1\n "
383
+ if got := body ; ! strings .Contains (got , want ) {
384
+ t .Errorf ("got body %q, does not contain %q, err: %v" , got , want , err )
385
+ }
386
+
387
+ want = "promhttp_metric_handler_requests_total{code=\" 200\" } 0\n "
388
+ if got := body ; ! strings .Contains (got , want ) {
389
+ t .Errorf ("got body %q, does not contain %q, err: %v" , got , want , err )
390
+ }
391
+
392
+ for i := 0 ; i < 100 ; i ++ {
393
+ writer .Body .Reset ()
394
+ handler .ServeHTTP (writer , request )
395
+
396
+ if got , want := mReg .gatherInvoked , i + 2 ; got != want {
397
+ t .Fatalf ("unexpected number of gather invokes, want %d, got %d" , want , got )
398
+ }
399
+ if got , want := mReg .doneInvoked , i + 2 ; got != want {
400
+ t .Fatalf ("unexpected number of done invokes, want %d, got %d" , want , got )
401
+ }
402
+ if got , want := writer .Code , http .StatusOK ; got != want {
403
+ t .Errorf ("got HTTP status code %d, want %d" , got , want )
404
+ }
405
+ body , err := readGzippedBody (writer .Body )
406
+
407
+ want := "promhttp_metric_handler_requests_in_flight 1\n "
408
+ if got := body ; ! strings .Contains (got , want ) {
409
+ t .Errorf ("got body %q, does not contain %q, err: %v" , got , want , err )
410
+ }
411
+
412
+ want = fmt .Sprintf ("promhttp_metric_handler_requests_total{code=\" 200\" } %d\n " , i + 1 )
413
+ if got := body ; ! strings .Contains (got , want ) {
414
+ t .Errorf ("got body %q, does not contain %q, err: %v" , got , want , err )
415
+ }
416
+ }
417
+ }
418
+
335
419
func TestNegotiateEncodingWriter (t * testing.T ) {
336
420
var defaultCompressions []string
337
421
@@ -393,7 +477,7 @@ func TestNegotiateEncodingWriter(t *testing.T) {
393
477
request , _ := http .NewRequest ("GET" , "/" , nil )
394
478
request .Header .Add (acceptEncodingHeader , test .acceptEncoding )
395
479
rr := httptest .NewRecorder ()
396
- _ , encodingHeader , err := NegotiateEncodingWriter (request , rr , test .disableCompression , test .offeredCompressions )
480
+ _ , encodingHeader , _ , err := NegotiateEncodingWriter (request , rr , test .disableCompression , test .offeredCompressions )
397
481
398
482
if ! errors .Is (err , test .err ) {
399
483
t .Errorf ("got error: %v, expected: %v" , err , test .err )
0 commit comments