...

Source file src/github.com/letsencrypt/boulder/metrics/measured_http/http_test.go

Documentation: github.com/letsencrypt/boulder/metrics/measured_http

     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  	// Create a local histogram stat with the same labels as the real one, but
    37  	// don't register it; we will collect its data here in the test to verify it.
    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  // Make an HTTP request with an unknown method and ensure we use the appropriate
    86  // label value.
    87  func TestUnknownMethod(t *testing.T) {
    88  	clk := clock.NewFake()
    89  
    90  	// Create a local histogram stat with the same labels as the real one, but
    91  	// don't register it; we will collect its data here in the test to verify it.
    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  	// Create a local histogram stat with the same labels as the real one, but
   135  	// don't register it; we will collect its data here in the test to verify it.
   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