relay

package module
v0.0.0-...-6a08827 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 25, 2016 License: BSD-2-Clause Imports: 5 Imported by: 1

README

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

Documentation

Overview

Package relay is a standard `httptest.Server` on steroid for end-to-end HTTP testing. It implements the test server with a delay middleware to simulate latency before the target test server's handler.

Relay consists of two components, a Proxy and Switcher. They are HTTP middlewares which wrap the target httptest.Server's handler, thus behaving like a proxy server. It is used with httptest.Server to simulate latent proxy servers or load balancers for use in end-to-end HTTP tests.

Proxy can be placed before a HTTPTestServer (httptest.Server, Proxy, or Switcher) to simulate a proxy server or a connection with some latency. It takes a latency unit and a backend HTTPTestServer as arguments.

Switcher behaves similarly to a proxy, but with each request it switches between several test servers in a round-robin fashion. Switcher takes a latency unit and a []HTTPTestServer to which it will circulate requests.

Let's begin setting up a basic `httptest.Server` to send 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 a HTTP request can be sent to the test server.

delay := time.Duration(2) * time.Second
timeout = time.Duration(3) * time.Second
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 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()
_, _ := http.Get(p1.URL)
elapsed := time.Since(start)
if elapsed >= time.Duration(6) * time.Second + time.Duration(10) * time.Millisecond {
        t.Error("Client took longer than expected.")
}

Each hop to and from the target server will be delayed for one second.

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!")
}))
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

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type HTTPTestServer

type HTTPTestServer interface {
	Close()
	CloseClientConnections()
	Start()
	StartTLS()
}

HTTPTestServer is an interface which all instances including httptest.Server implement.

type Proxy

type Proxy struct {
	*httptest.Server
	Latency time.Duration
	Backend HTTPTestServer
}

A Proxy is an HTTPTestServer placed in front of another HTTPTestServer to simulate a real proxy server or a connection with latency.

func NewProxy

func NewProxy(latency time.Duration, backend HTTPTestServer) *Proxy

NewProxy starts and run a proxy instance.

func NewUnstartedProxy

func NewUnstartedProxy(latency time.Duration, backend HTTPTestServer) *Proxy

NewUnstartedProxy Start an unstarted proxy instance.

func (*Proxy) Close

func (p *Proxy) Close()

Close shuts down the proxy and blocks until all outstanding requests on this proxy have completed.

func (*Proxy) Start

func (p *Proxy) Start()

Start starts a proxy from NewUnstartedProxy.

type Switcher

type Switcher struct {
	*httptest.Server
	Latency  time.Duration
	Backends []HTTPTestServer
}

A Switcher is an HTTPTestServer placed in front of another HTTPTestServer's to simulate a round-robin load-balancer.

func NewSwitcher

func NewSwitcher(latency time.Duration, backends []HTTPTestServer) *Switcher

NewProxy starts and run a proxy instance.

func NewUnstartedSwitcher

func NewUnstartedSwitcher(latency time.Duration, backends []HTTPTestServer) *Switcher

NewUnstartedProxy Start an unstarted proxy instance.

func (*Switcher) Close

func (sw *Switcher) Close()

Close shuts down the switcher and blocks until all outstanding requests on this switcher have completed.

func (*Switcher) Start

func (sw *Switcher) Start()

Start starts a switcher from NewUnstartedSwitcher.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL