Skip to content

Commit

Permalink
Add tests and travis tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tcnksm committed Oct 25, 2016
1 parent 9109ec1 commit 6f90f00
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 0 deletions.
16 changes: 16 additions & 0 deletions .travis.yml
@@ -0,0 +1,16 @@
language: go
go:
- 1.7.3
- tip

os:
- linux
- osx

sudo: false

install:
- echo "skipping travis' default"

script:
- go test -v
19 changes: 19 additions & 0 deletions httpstat.go
Expand Up @@ -11,11 +11,13 @@ import (

// Result stores httpstat info.
type Result struct {
// The following are duration for each phase
DNSLookup time.Duration
TCPConnection time.Duration
TLSHandshake time.Duration
ServerProcessing time.Duration

// The followings are timeline of reuqest
NameLookup time.Duration
Connect time.Duration
Pretransfer time.Duration
Expand All @@ -30,6 +32,22 @@ type Result struct {
isTLS bool
}

func (r *Result) durations(t time.Time) map[string]time.Duration {
return map[string]time.Duration{
"DNSLookup": r.DNSLookup,
"TCPConnection": r.TCPConnection,
"TLSHandshake": r.TLSHandshake,
"ServerProcessing": r.ServerProcessing,
"ContentTransfer": r.ContentTransfer(t),

"NameLookup": r.NameLookup,
"Connect": r.Connect,
"Pretransfer": r.Connect,
"StartTransfer": r.StartTransfer,
"Total": r.Total(t),
}
}

// ContentTransfer returns the duration of content transfer time.
// It is from first response byte to the given time. The time must
// be time after read body (go-httpstat can not detect that time).
Expand Down Expand Up @@ -105,6 +123,7 @@ func WithHTTPStat(ctx context.Context, r *Result) context.Context {
r.t0 = time.Now()
r.t1 = r.t0
r.t2 = r.t0
r.t3 = r.t0
}

if r.isTLS {
Expand Down
143 changes: 143 additions & 0 deletions httpstat_test.go
@@ -0,0 +1,143 @@
package httpstat

import (
"io"
"io/ioutil"
"net"
"net/http"
"testing"
"time"
)

const (
TestDomainHTTP = "http://example.com"
TestDomainHTTPS = "https://example.com"
)

func DefaultTransport() *http.Transport {
// It comes from std transport.go
return &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
}

// To avoid shared transport
func DefaultClient() *http.Client {
return &http.Client{
Transport: DefaultTransport(),
}
}

func NewRequest(t *testing.T, urlStr string, result *Result) *http.Request {
req, err := http.NewRequest("GET", urlStr, nil)
if err != nil {
t.Fatal("NewRequest failed:", err)
}

ctx := WithHTTPStat(req.Context(), result)
return req.WithContext(ctx)
}

func TestHTTPStat_HTTPS(t *testing.T) {
var result Result
req := NewRequest(t, TestDomainHTTPS, &result)

client := DefaultClient()
res, err := client.Do(req)
if err != nil {
t.Fatal("client.Do failed:", err)
}

if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
t.Fatal("io.Copy failed:", err)
}
res.Body.Close()
end := time.Now()

for k, d := range result.durations(end) {
if d <= 0*time.Millisecond {
t.Fatalf("expect %s to be non-zero", k)
}
}
}

func TestHTTPStat_HTTP(t *testing.T) {
var result Result
req := NewRequest(t, TestDomainHTTP, &result)

client := DefaultClient()
res, err := client.Do(req)
if err != nil {
t.Fatal("client.Do failed:", err)
}

if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
t.Fatal("io.Copy failed:", err)
}
res.Body.Close()
end := time.Now()

if got, want := result.TLSHandshake, 0*time.Millisecond; got != want {
t.Fatalf("TLSHandshake time of HTTP = %d, want %d", got, want)
}

// Except TLS should be non zero
durations := result.durations(end)
delete(durations, "TLSHandshake")

for k, d := range durations {
if d <= 0*time.Millisecond {
t.Fatalf("expect %s to be non-zero", k)
}
}
}

func TestHTTPStat_beforeGO17(t *testing.T) {
var result Result
req := NewRequest(t, TestDomainHTTPS, &result)

// Before go1.7, it uses non context based Dial function.
// It doesn't support httptrace.
oldTransport := &http.Transport{
Dial: (&net.Dialer{
Timeout: 5 * time.Second,
}).Dial,
TLSHandshakeTimeout: 5 * time.Second,
}

client := &http.Client{
Timeout: time.Second * 10,
Transport: oldTransport,
}

res, err := client.Do(req)
if err != nil {
t.Fatal("client.Do failed:", err)
}

if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
t.Fatal("io.Copy failed:", err)
}
res.Body.Close()

// The following values are not mesured.
durations := []time.Duration{
result.DNSLookup,
result.TCPConnection,
result.TLSHandshake,
}

for i, d := range durations {
if got, want := d, 0*time.Millisecond; got != want {
t.Fatalf("#%d expect %d to be eq %d", i, got, want)
}
}
}

0 comments on commit 6f90f00

Please sign in to comment.