+42
Go/racer/racer.go
+42
Go/racer/racer.go
···
1
+
package racer
2
+
3
+
import (
4
+
"fmt"
5
+
"net/http"
6
+
"time"
7
+
)
8
+
9
+
var tenSecondTimeout = 10 * time.Second
10
+
11
+
func Racer(a, b string) (winner string, error error) {
12
+
return ConfigurableRacer(a, b, tenSecondTimeout)
13
+
}
14
+
15
+
func ConfigurableRacer(a, b string, timeout time.Duration) (winner string, error error) {
16
+
// allows to wait on multiple channels, the first to respond will be executed
17
+
select {
18
+
case <-ping(a):
19
+
return a, nil
20
+
case <-ping(b):
21
+
return b, nil
22
+
case <-time.After(timeout):
23
+
return "", fmt.Errorf("timed out waiting for %s and %s", a, b)
24
+
}
25
+
}
26
+
27
+
func measureResponseTime(url string) time.Duration {
28
+
start := time.Now()
29
+
http.Get(url)
30
+
return time.Since(start)
31
+
}
32
+
33
+
func ping(url string) chan struct{} {
34
+
ch := make(chan struct{})
35
+
36
+
go func() {
37
+
http.Get(url)
38
+
close(ch)
39
+
}()
40
+
41
+
return ch
42
+
}
+52
Go/racer/racer_test.go
+52
Go/racer/racer_test.go
···
1
+
package racer
2
+
3
+
import (
4
+
"net/http"
5
+
"net/http/httptest"
6
+
"testing"
7
+
"time"
8
+
)
9
+
10
+
func TestRacer(t *testing.T) {
11
+
t.Run("compares speed of servers, returning the url of the fastest one", func(t *testing.T) {
12
+
slowServer := makeDelayedServer(20 * time.Millisecond)
13
+
fastServer := makeDelayedServer(0 * time.Millisecond)
14
+
15
+
// Defer makes so that this instructions are executed at the end of the function
16
+
defer slowServer.Close()
17
+
defer fastServer.Close()
18
+
19
+
slowUrl := slowServer.URL
20
+
fastUrl := fastServer.URL
21
+
22
+
want := fastUrl
23
+
got, err := Racer(slowUrl, fastUrl)
24
+
25
+
if err != nil {
26
+
t.Fatalf("did not expect an error but got one %v", err)
27
+
}
28
+
29
+
if got != want {
30
+
t.Errorf("got %q, want %q", got, want)
31
+
}
32
+
})
33
+
34
+
t.Run("returns an error if a server doesn't respond within 10s", func(t *testing.T) {
35
+
server := makeDelayedServer(25 * time.Millisecond)
36
+
37
+
defer server.Close()
38
+
39
+
_, err := ConfigurableRacer(server.URL, server.URL, 20 * time.Millisecond)
40
+
41
+
if err == nil {
42
+
t.Errorf("expected an error but didn't get one")
43
+
}
44
+
})
45
+
}
46
+
47
+
func makeDelayedServer(delay time.Duration) *httptest.Server {
48
+
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
49
+
time.Sleep(delay)
50
+
w.WriteHeader(http.StatusOK)
51
+
}))
52
+
}