blob: bdfe8b0b00e8beb4fc7835583905b224f6a1c6af [file] [log] [blame]
package ochttp
import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
)
func httpHandler(statusCode, respSize int) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(statusCode)
body := make([]byte, respSize)
w.Write(body)
})
}
func updateMean(mean float64, sample, count int) float64 {
if count == 1 {
return float64(sample)
}
return mean + (float64(sample)-mean)/float64(count)
}
func TestHandlerStatsCollection(t *testing.T) {
for _, v := range DefaultServerViews {
v.Subscribe()
}
views := []string{
"opencensus.io/http/server/request_count",
"opencensus.io/http/server/latency",
"opencensus.io/http/server/request_bytes",
"opencensus.io/http/server/response_bytes",
}
// TODO: test latency measurements?
tests := []struct {
name, method, target string
count, statusCode, reqSize, respSize int
}{
{"get 200", "GET", "http://opencensus.io/request/one", 10, 200, 512, 512},
{"post 503", "POST", "http://opencensus.io/request/two", 5, 503, 1024, 16384},
{"no body 302", "GET", "http://opencensus.io/request/three", 2, 302, 0, 0},
}
totalCount, meanReqSize, meanRespSize := 0, 0.0, 0.0
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
body := bytes.NewBuffer(make([]byte, test.reqSize))
r := httptest.NewRequest(test.method, test.target, body)
w := httptest.NewRecorder()
h := &Handler{
Handler: httpHandler(test.statusCode, test.respSize),
}
h.StartOptions.Sampler = trace.NeverSample()
for i := 0; i < test.count; i++ {
h.ServeHTTP(w, r)
totalCount++
// Distributions do not track sum directly, we must
// mimic their behaviour to avoid rounding failures.
meanReqSize = updateMean(meanReqSize, test.reqSize, totalCount)
meanRespSize = updateMean(meanRespSize, test.respSize, totalCount)
}
})
}
for _, viewName := range views {
v := view.Find(viewName)
if v == nil {
t.Errorf("view not found %q", viewName)
continue
}
rows, err := view.RetrieveData(viewName)
if err != nil {
t.Error(err)
continue
}
if got, want := len(rows), 1; got != want {
t.Errorf("len(%q) = %d; want %d", viewName, got, want)
continue
}
data := rows[0].Data
var count int
var sum float64
switch data := data.(type) {
case *view.CountData:
count = int(*data)
case *view.DistributionData:
count = int(data.Count)
sum = data.Sum()
default:
t.Errorf("Unkown data type: %v", data)
continue
}
if got, want := count, totalCount; got != want {
t.Fatalf("%s = %d; want %d", viewName, got, want)
}
// We can only check sum for distribution views.
switch viewName {
case "opencensus.io/http/server/request_bytes":
if got, want := sum, meanReqSize*float64(totalCount); got != want {
t.Fatalf("%s = %g; want %g", viewName, got, want)
}
case "opencensus.io/http/server/response_bytes":
if got, want := sum, meanRespSize*float64(totalCount); got != want {
t.Fatalf("%s = %g; want %g", viewName, got, want)
}
}
}
}