Skip to content

Latest commit

 

History

History
151 lines (116 loc) · 5.38 KB

README.md

File metadata and controls

151 lines (116 loc) · 5.38 KB

relay relay

GoDoc Build Status Coverage Status Donate

Powered up Go HTTP Server for comprehensive end-to-end HTTP tests.

Relay consists of two components, Proxy and Switcher. They are both HTTP middlewares which wrap around the target server's handler to simulate latent connections, proxy servers, or load balancers.

Usage

To use relay in your test, install with

$ go get github.com/jochasinga/relay

Or better, use a package manager like Godep or Glide.

HTTPTestServer

Every instance, including the standard httptest.Server, implements HTTPTestServer interface, which means that they can be used interchangeably as a general "server".

Proxy

A Proxy is used to place in front of any HTTPTestServer (httptest.Server, Proxy, or Switcher) to simulate a proxy server or a connection with some network latency. It takes a latency unit in time.Duration and a backend HTTPTestServer as arguments.

Switcher

Switcher works similarly to Proxy, except with each request it "switches" between several backend HTTPTestServer in a round-robin fashion.

Examples

Let's begin setting up a basic httptest.Server to send a request to.

var handler = func(w http.ResponseWriter, r *http.Request) {
	    fmt.Fprint(w, "Hello world!")
}

func TestGet(t *testing.T) {
	    ts := httptest.NewServer(http.HandlerFunc(handler))
		resp, _ := http.Get(ts.URL)
		b, _ := ioutil.ReadAll(resp.Body)
		if string(b) != "Hello world!" {
			    t.Error("Response is not as expected.")
		}
}

Now let's use Proxy to simulate a slow connection through which an HTTP request can be sent to test server.

// Connection takes 4s to and from the test server.
delay := time.Duration(2) * time.Second
// Client takes 3s before timing out.
timeout := time.Duration(3) * time.Second
// Create a new proxy with the delay and test server backend.
conn := relay.NewProxy(delay, ts)
client := &Client{ Timeout: timeout }
start := time.Now()
_, _ := client.Get(conn.URL)
elapsed := time.Since(start)
deviation := time.Duration(50) * time.Millisecond

if elapsed >= timeout + deviation {
	    t.Error("Client took too long to time out.")
}

Note that the latency will double because of the round trip to and from the server.

Proxy can be placed in front of another proxy, and vice versa. So you can create a chain of test proxies this way:

delay := time.Duration(1) * time.Second
ts := httptest.NewServer(http.HandlerFunc(handler))
p3 := relay.NewProxy(delay, ts)
p2 := relay.NewProxy(delay, p3)
p1 := relay.NewProxy(delay, p2)
start := time.Now()
_, _ := client.Get(p1.URL)
elapsed := time.Since(start)
deviation := time.Duration(50) * time.Millisecond
if elapsed >= (time.Duration * 6) + deviation {
	    t.Error("Client took longer than expected.")
}

In the above code, Each hop to and from the target server ts will be delayed for one second, total to six seconds of latency.

Switcher can be used instead of Proxy to simulate a round-robin load-balancing proxy or just to switch between several test servers' handlers for convenience.

ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	    fmt.Fprint(w, "Hello world!")
}))
ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	    fmt.Fprint(w, "Hello mars!")
}))
ts3 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	    fmt.Fprint(w, "Hello pluto!")
}))

// a proxy sitting in front of ts3
p := relay.NewProxy(delay, ts3)
sw := relay.NewSwitcher(delay, []HTTPTestServer{ts1, ts2, p})

resp1, _ := http.Get(sw.URL) // hits ts1
resp2, _ := http.Get(sw.URL) // hits ts2
resp3, _ := http.Get(sw.URL) // hits p, which eventually hits ts3
resp4, _ := http.Get(sw.URL) // hits ts1 again, and so on.

Also please check out this introduction to writing test with goconvey and relay on Medium.

TODO

  • Make Proxy a standalone httptest.Server with optional backend=nil.
  • Add other common middlewares to each proxy and switcher.
  • Add options to inject middleware into each proxy and switcher.
  • Add more "load-balancing" capabilities to Switcher.

CONTRIBUTE

Feel free to open an issue or send a pull request. Please see goconvey on how to write BDD tests for relay. Contact me on twitter @jochasinga. Fuel me with high-quality caffeine to continue working on cool code -> Donate