You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
6.1 KiB
294 lines
6.1 KiB
5 months ago
|
package servertiming
|
||
|
|
||
|
import (
|
||
|
"net/http"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// Example taken from the W3C spec
|
||
|
// see: https://w3c.github.io/server-timing/#examples
|
||
|
//
|
||
|
// ```
|
||
|
// > GET /resource HTTP/1.1
|
||
|
// > Host: example.com
|
||
|
//
|
||
|
//
|
||
|
// < HTTP/1.1 200 OK
|
||
|
// < Server-Timing: miss, db;dur=53, app;dur=47.2
|
||
|
// < Server-Timing: customView, dc;desc=atl
|
||
|
// < Server-Timing: cache;desc="Cache Read";dur=23.2
|
||
|
// < Trailer: Server-Timing
|
||
|
// < (... snip response body ...)
|
||
|
// < Server-Timing: total;dur=123.4
|
||
|
// ```
|
||
|
//
|
||
|
// | Name | Duration | Description |
|
||
|
// | ---------- | -------- | ----------- |
|
||
|
// | miss | | |
|
||
|
// | db | 53 | |
|
||
|
// | app | 47.2 | |
|
||
|
// | customView | | |
|
||
|
// | dc | | atl |
|
||
|
// | cache | 23.2 | Cache Read |
|
||
|
// | total | 123.4 | |
|
||
|
|
||
|
func TestServerTiming_String(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
st ServerTiming
|
||
|
want string
|
||
|
}{
|
||
|
{
|
||
|
name: "just name",
|
||
|
st: ServerTiming{Name: "miss"},
|
||
|
want: "miss",
|
||
|
},
|
||
|
{
|
||
|
name: "name and dur",
|
||
|
st: ServerTiming{
|
||
|
Name: "db",
|
||
|
Dur: 53 * time.Millisecond,
|
||
|
},
|
||
|
want: "db;dur=53",
|
||
|
},
|
||
|
{
|
||
|
name: "name and decimal dur",
|
||
|
st: ServerTiming{
|
||
|
Name: "app",
|
||
|
Dur: 47_200 * time.Microsecond,
|
||
|
DecimalPrecision: 1,
|
||
|
},
|
||
|
want: "app;dur=47.2",
|
||
|
},
|
||
|
{
|
||
|
name: "name and nanosecond dur",
|
||
|
st: ServerTiming{
|
||
|
Name: "app",
|
||
|
Dur: 47_200 * time.Microsecond,
|
||
|
DecimalPrecision: 6,
|
||
|
},
|
||
|
want: "app;dur=47.200000",
|
||
|
},
|
||
|
{
|
||
|
name: "name and dur, negative precision",
|
||
|
st: ServerTiming{
|
||
|
Name: "app",
|
||
|
Dur: 47_200 * time.Microsecond,
|
||
|
DecimalPrecision: -1,
|
||
|
},
|
||
|
want: "app;dur=47",
|
||
|
},
|
||
|
{
|
||
|
name: "name and dur, out-of-bound precision",
|
||
|
st: ServerTiming{
|
||
|
Name: "app",
|
||
|
Dur: 47_200 * time.Microsecond,
|
||
|
DecimalPrecision: 7,
|
||
|
},
|
||
|
want: "app;dur=47.200000",
|
||
|
},
|
||
|
{
|
||
|
name: "name and desc",
|
||
|
st: ServerTiming{
|
||
|
Name: "dc",
|
||
|
Desc: "atl",
|
||
|
},
|
||
|
want: "dc;desc=atl",
|
||
|
},
|
||
|
{
|
||
|
name: "name, desc, and dur",
|
||
|
st: ServerTiming{
|
||
|
Name: "cache",
|
||
|
Dur: 23 * time.Millisecond,
|
||
|
Desc: "Cache Read",
|
||
|
},
|
||
|
want: "cache;dur=23;desc=Cache Read",
|
||
|
},
|
||
|
{
|
||
|
name: "name, desc, and decimal dur",
|
||
|
st: ServerTiming{
|
||
|
Name: "cache",
|
||
|
Dur: 23_200 * time.Microsecond,
|
||
|
Desc: "Cache Read",
|
||
|
DecimalPrecision: 1,
|
||
|
},
|
||
|
want: "cache;dur=23.2;desc=Cache Read",
|
||
|
},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
if got := tt.st.String(); got != tt.want {
|
||
|
t.Errorf("ServerTiming.String() = %v, want %v", got, tt.want)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestFromString(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
s string
|
||
|
want ServerTiming
|
||
|
}{
|
||
|
{
|
||
|
name: "empty",
|
||
|
s: "",
|
||
|
want: ServerTiming{},
|
||
|
},
|
||
|
{
|
||
|
name: "name only",
|
||
|
s: "miss",
|
||
|
want: ServerTiming{Name: "miss"},
|
||
|
},
|
||
|
{
|
||
|
name: "name and dur",
|
||
|
s: "db;dur=53",
|
||
|
want: ServerTiming{
|
||
|
Name: "db",
|
||
|
Dur: 53 * time.Millisecond,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "name, dur and desc",
|
||
|
s: "cache;dur=23;desc=Cache Read",
|
||
|
want: ServerTiming{
|
||
|
Name: "cache",
|
||
|
Dur: 23 * time.Millisecond,
|
||
|
Desc: "Cache Read",
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "name, desc",
|
||
|
s: "cache;desc=Cache Read;dur=23",
|
||
|
want: ServerTiming{
|
||
|
Name: "cache",
|
||
|
Dur: 23 * time.Millisecond,
|
||
|
Desc: "Cache Read",
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "name, dur and desc with padding",
|
||
|
s: "cache ; dur=23 ; desc=Cache Read ",
|
||
|
want: ServerTiming{
|
||
|
Name: "cache",
|
||
|
Dur: 23 * time.Millisecond,
|
||
|
Desc: "Cache Read",
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "name and decimal dur",
|
||
|
s: "cache;dur=23.2",
|
||
|
want: ServerTiming{
|
||
|
Name: "cache",
|
||
|
Dur: 23_200 * time.Microsecond,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
if got := FromString(tt.s); !reflect.DeepEqual(got, tt.want) {
|
||
|
t.Errorf("FromString() = %v, want %v", got, tt.want)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestAppend(t *testing.T) {
|
||
|
resp := &http.Response{
|
||
|
Header: http.Header{},
|
||
|
}
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
st ServerTiming
|
||
|
}{
|
||
|
{
|
||
|
name: "name only",
|
||
|
st: ServerTiming{Name: "miss"},
|
||
|
},
|
||
|
{
|
||
|
name: "name and dur",
|
||
|
st: ServerTiming{
|
||
|
Name: "db",
|
||
|
Dur: 53 * time.Millisecond,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "name, dur and desc",
|
||
|
st: ServerTiming{
|
||
|
Name: "cache",
|
||
|
Dur: 23 * time.Millisecond,
|
||
|
Desc: "Cache Read",
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
Append(resp, tt.st)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
vals := resp.Header.Values("Server-Timing")
|
||
|
if len(vals) != len(tests) {
|
||
|
t.Errorf("Expected %d values in the headers, got %d", len(tests), len(vals))
|
||
|
}
|
||
|
|
||
|
for i, v := range vals {
|
||
|
if v != tests[i].st.String() {
|
||
|
t.Errorf("Expected '%s', got %s", tests[i].st.String(), v)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestTrailer(t *testing.T) {
|
||
|
type args struct {
|
||
|
r *http.Response
|
||
|
t ServerTiming
|
||
|
}
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
args args
|
||
|
}{
|
||
|
// TODO: Add test cases.
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
Trailer(tt.args.r, tt.args.t)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestParse(t *testing.T) {
|
||
|
resp := &http.Response{
|
||
|
Header: http.Header{},
|
||
|
Trailer: http.Header{},
|
||
|
}
|
||
|
resp.Header.Add("Server-Timing", "miss, db;dur=53, app;dur=47")
|
||
|
resp.Header.Add("Server-Timing", "customView, dc;desc=atl")
|
||
|
resp.Header.Add("Server-Timing", `cache;desc="Cache Read";dur=23`)
|
||
|
resp.Trailer.Add("Server-Timing", "total;dur=123")
|
||
|
|
||
|
timings := Parse(resp)
|
||
|
if len(timings) != 7 {
|
||
|
t.Errorf("Expected 7 timings, got %d", len(timings))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestParseWithDecimal(t *testing.T) {
|
||
|
resp := &http.Response{
|
||
|
Header: http.Header{},
|
||
|
Trailer: http.Header{},
|
||
|
}
|
||
|
resp.Header.Add("Server-Timing", "miss, db;dur=53, app;dur=47.2")
|
||
|
resp.Header.Add("Server-Timing", "customView, dc;desc=atl")
|
||
|
resp.Header.Add("Server-Timing", `cache;desc="Cache Read";dur=23.2`)
|
||
|
resp.Trailer.Add("Server-Timing", "total;dur=123.4")
|
||
|
|
||
|
timings := Parse(resp)
|
||
|
if len(timings) != 7 {
|
||
|
t.Errorf("Expected 7 timings, got %d", len(timings))
|
||
|
}
|
||
|
}
|