blob: fab26f87428500a8fedfbd3541bc4081fe0407da [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package middleware
import (
"encoding/json"
"hash/fnv"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
func TestStats(t *testing.T) {
data := []byte("this is the data we are going to serve")
const code = 218
ts := httptest.NewServer(Stats()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
w.WriteHeader(code)
SetStat(ctx, "a", 1)
w.Write(data[:10])
SetStat(ctx, "b", 2)
time.Sleep(500 * time.Millisecond)
SetStat(ctx, "a", 3)
w.Write(data[10:])
})))
defer ts.Close()
res, err := ts.Client().Get(ts.URL)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
t.Fatalf("failed with status %d", res.StatusCode)
}
gotData, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
var got PageStats
if err := json.Unmarshal(gotData, &got); err != nil {
t.Fatal(err)
}
h := fnv.New64a()
h.Write(data)
want := PageStats{
StatusCode: code,
Size: len(data),
Hash: h.Sum64(),
Other: map[string]interface{}{
// JSON unmarshals all numbers into float64s.
"a": []interface{}{float64(1), float64(3)},
"b": float64(2),
},
}
diff := cmp.Diff(want, got, cmpopts.IgnoreFields(PageStats{}, "MillisToFirstByte", "MillisToLastByte"))
if diff != "" {
t.Errorf("mismatch (-want, +got):\n%s", diff)
}
const tolerance = 50 // 50 ms of tolerance for time measurements
if g := got.MillisToFirstByte; !within(g, 0, tolerance) {
t.Errorf("MillisToFirstByte is %d, wanted 0 - %d", g, tolerance)
}
if g := got.MillisToLastByte; !within(g, 500, tolerance) {
t.Errorf("MillisToLastByte is %d, wanted 500 +/- %d", g, tolerance)
}
}
func within(got, want, tolerance int64) bool {
d := got - want
if d < 0 {
d = -d
}
return d <= tolerance
}