author | Alberto Bertogli
<albertito@blitiri.com.ar> 2017-08-26 01:03:02 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2017-08-26 01:16:24 UTC |
parent | e08b0495890b4bd9057e78fb7ed9941b9952c88d |
proxy/proxy_test.go | +102 | -37 |
diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index a5eb438..74035ce 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -3,20 +3,60 @@ package proxy import ( "fmt" "io/ioutil" - "log" "net" "net/http" "net/http/httptest" + "os" "strings" "testing" "time" "blitiri.com.ar/go/gofer/config" + "blitiri.com.ar/go/log" ) +// WaitForHTTPServer waits 5 seconds for an HTTP server to start, and returns +// an error if it fails to do so. +// It does this by repeatedly querying the server until it either replies or +// times out. +func waitForHTTPServer(addr string) error { + c := http.Client{ + Timeout: 100 * time.Millisecond, + } + + deadline := time.Now().Add(5 * time.Second) + tick := time.Tick(100 * time.Millisecond) + + for (<-tick).Before(deadline) { + _, err := c.Get("http://" + addr + "/testpoke") + if err == nil { + return nil + } + } + + return fmt.Errorf("timed out") +} + +// Get a free (TCP) port. This is hacky and not race-free, but it works well +// enough for testing purposes. +func getFreePort() string { + l, _ := net.Listen("tcp", "localhost:0") + defer l.Close() + return l.Addr().String() +} + const backendResponse = "backend response\n" -func TestSimple(t *testing.T) { +// Addresses of the proxy under test (created by TestMain). +var ( + httpAddr string + rawAddr string +) + +// startServer for testing. Returns raw addr, http addr, and the backend test +// server (which should be closed afterwards). +// Note it leaks goroutines, we're ok with this for testing. +func TestMain(m *testing.M) { backend := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, backendResponse) @@ -24,8 +64,10 @@ func TestSimple(t *testing.T) { defer backend.Close() // We have two frontends: one raw and one http. - rawAddr := getFreePort() - httpAddr := getFreePort() + rawAddr = getFreePort() + httpAddr = getFreePort() + + log.Default.Level = log.Error const configTemplate = ` [[raw]] @@ -48,10 +90,8 @@ addr = "$HTTP_ADDR" conf, err := config.LoadString(configStr) if err != nil { - log.Fatal(err) + log.Fatalf("error loading test config: %v", err) } - t.Logf("conf.Raw[0]: %#v", conf.Raw[0]) - t.Logf("conf.HTTP[0]: %#v", *conf.HTTP[0]) go Raw(conf.Raw[0]) go HTTP(*conf.HTTP[0]) @@ -59,6 +99,10 @@ addr = "$HTTP_ADDR" waitForHTTPServer(httpAddr) waitForHTTPServer(rawAddr) + os.Exit(m.Run()) +} + +func TestSimple(t *testing.T) { // Test the raw proxy. testGet(t, "http://"+rawAddr+"/be", 200) @@ -78,6 +122,7 @@ addr = "$HTTP_ADDR" } func testGet(t *testing.T, url string, expectedStatus int) { + //t.Helper() -- Uncomment once Go 1.9 is commonplace. t.Logf("URL: %s", url) resp, err := http.Get(url) if err != nil { @@ -106,36 +151,6 @@ func testGet(t *testing.T, url string, expectedStatus int) { t.Logf("response body: %q", b) } -// WaitForHTTPServer waits 5 seconds for an HTTP server to start, and returns -// an error if it fails to do so. -// It does this by repeatedly querying the server until it either replies or -// times out. -func waitForHTTPServer(addr string) error { - c := http.Client{ - Timeout: 100 * time.Millisecond, - } - - deadline := time.Now().Add(5 * time.Second) - tick := time.Tick(100 * time.Millisecond) - - for (<-tick).Before(deadline) { - _, err := c.Get("http://" + addr + "/testpoke") - if err == nil { - return nil - } - } - - return fmt.Errorf("timed out") -} - -// Get a free (TCP) port. This is hacky and not race-free, but it works well -// enough for testing purposes. -func getFreePort() string { - l, _ := net.Listen("tcp", "localhost:0") - defer l.Close() - return l.Addr().String() -} - func TestJoinPath(t *testing.T) { cases := []struct{ a, b, expected string }{ {"/a/", "", "/a/"}, @@ -155,3 +170,53 @@ func TestJoinPath(t *testing.T) { } } } + +func Benchmark(b *testing.B) { + makeBench := func(url string) func(b *testing.B) { + return func(b *testing.B) { + var resp *http.Response + var err error + for i := 0; i < b.N; i++ { + resp, err = http.Get(url) + if err != nil { + b.Fatal(err) + } + resp.Body.Close() + if resp.StatusCode != 200 { + b.Errorf("expected status 200, got %v", resp.Status) + b.Fatalf("response: %#v", resp) + } + } + } + } + + b.Run("HTTP", makeBench("http://"+httpAddr+"/be")) + b.Run("Raw", makeBench("http://"+rawAddr+"/be")) +} + +func BenchmarkParallel(b *testing.B) { + makeP := func(url string) func(pb *testing.PB) { + return func(pb *testing.PB) { + var resp *http.Response + var err error + for pb.Next() { + resp, err = http.Get(url) + if err != nil { + b.Fatal(err) + } + resp.Body.Close() + if resp.StatusCode != 200 { + b.Errorf("expected status 200, got %v", resp.Status) + b.Fatalf("response: %#v", resp) + } + } + } + } + + b.Run("HTTP", func(b *testing.B) { + b.RunParallel(makeP("http://" + httpAddr + "/be")) + }) + b.Run("Raw", func(b *testing.B) { + b.RunParallel(makeP("http://" + rawAddr + "/be")) + }) +}