Skip to content
This repository was archived by the owner on Sep 4, 2018. It is now read-only.

Commit 8616219

Browse files
committed
refactored the eventsource endpoint to make it testable. Added some basic smoke test.
1 parent d9fc294 commit 8616219

2 files changed

Lines changed: 122 additions & 24 deletions

File tree

main.go

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,35 @@ func (h *Hub) run() {
110110
}
111111
}
112112

113-
// NewHub a pointer to an initialized Hub
113+
// EventSourceHandler implements the Handler interface
114+
func (h *Hub) EventSourceHandler(w http.ResponseWriter, req *http.Request) {
115+
token := req.URL.Path[len(ssePath):]
116+
117+
if h.userExists(token) {
118+
log.Println("[Info] Forbiden, user already connected")
119+
http.Error(w, "Forbiden", http.StatusForbidden)
120+
} else {
121+
log.Println("[Info] Exchange token against the channel list", token)
122+
val, err := h.client.Getset(token, []byte{})
123+
if err != nil {
124+
log.Println("[Error] occured while exchanging the your security token.", token, ":", err)
125+
http.Error(w, "Error occured while exchanging the your security token", http.StatusUnauthorized)
126+
} else if chanName := string(val); chanName != "" {
127+
log.Println("[Info] Connecting", token, "to the channel", chanName)
128+
h.register <- Connection{token, chanName}
129+
defer func(u string) {
130+
h.unregister <- u
131+
}(token)
132+
h.srv.Handler(token)(w, req)
133+
}
134+
_, err = h.client.Del(token)
135+
if err != nil {
136+
log.Println("[Error] An error occured while trying to delete the token from redis", err)
137+
}
138+
}
139+
}
140+
141+
// NewHub returns a pointer to a initialized and running Hub
114142
func NewHub() *Hub {
115143
redisURLString := os.Getenv("REDIS_SSEQUEUE_URL")
116144
if redisURLString == "" {
@@ -140,6 +168,7 @@ func NewHub() *Hub {
140168
srv: server,
141169
client: goredis.Client{Addr: redisURL.Host, Db: redisDb},
142170
}
171+
go h.run()
143172
return &h
144173
}
145174

@@ -152,31 +181,9 @@ func main() {
152181

153182
log.Println("[Info] Starting the eventsource Hub")
154183
h := NewHub()
155-
go h.run()
156184

157185
// eventsource endpoints
158-
http.HandleFunc(ssePath, func(w http.ResponseWriter, req *http.Request) {
159-
token := req.URL.Path[len(ssePath):]
160-
161-
if h.userExists(token) {
162-
log.Println("[Info] Forbiden, user already connected")
163-
http.Error(w, "Forbiden", http.StatusForbidden)
164-
} else {
165-
log.Println("[Info] Exchange token against the channel list")
166-
val, err := h.client.Getset(token, []byte{})
167-
if err != nil {
168-
log.Println("[Error] occured while exchanging the your security token.")
169-
http.Error(w, "Error occured while exchanging the your security token", http.StatusUnauthorized)
170-
} else if chanName := string(val); chanName != "" {
171-
log.Println("[Info] Connecting", token, "to the channel", chanName)
172-
h.register <- Connection{token, chanName}
173-
defer func(u string) {
174-
h.unregister <- u
175-
}(token)
176-
h.srv.Handler(token)(w, req)
177-
}
178-
}
179-
})
186+
http.HandleFunc(ssePath, h.EventSourceHandler)
180187

181188
log.Fatalln(http.ListenAndServe(sseString, nil))
182189
}

main_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"net/http/httptest"
7+
"net/url"
8+
"testing"
9+
"time"
10+
)
11+
12+
type closeNotifyingRecorder struct {
13+
*httptest.ResponseRecorder
14+
closed chan bool
15+
}
16+
17+
func newCloseNotifyingRecorder() *closeNotifyingRecorder {
18+
return &closeNotifyingRecorder{
19+
httptest.NewRecorder(),
20+
make(chan bool, 1),
21+
}
22+
}
23+
24+
func (c *closeNotifyingRecorder) close() {
25+
c.closed <- true
26+
}
27+
28+
func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
29+
return c.closed
30+
}
31+
32+
func TestEventSourceHandler(t *testing.T) {
33+
h := NewHub()
34+
setup := func() {
35+
err := h.client.Set("existing-token", []byte("channelName"))
36+
if err != nil {
37+
t.Error("[Error] An error occured while setting up the test", err)
38+
}
39+
}
40+
tearDown := func() {
41+
_, err := h.client.Del("existing-token")
42+
if err != nil {
43+
t.Error("[Error] An error occured while tearing down the test", err)
44+
}
45+
_, err = h.client.Del("bad-token")
46+
if err != nil {
47+
t.Error("[Error] An error occured while tearing down the test", err)
48+
}
49+
50+
}
51+
52+
tests := []struct {
53+
Desc string
54+
Handler func(http.ResponseWriter, *http.Request)
55+
Path string
56+
Status int
57+
}{
58+
{
59+
Desc: "Access the EventSourceHandler with a bad-token",
60+
Handler: h.EventSourceHandler,
61+
Path: ssePath + "bad-token",
62+
Status: http.StatusUnauthorized,
63+
},
64+
{
65+
Desc: "Access the EventSourceHandler with an existing-token",
66+
Handler: h.EventSourceHandler,
67+
Path: ssePath + "existing-token",
68+
Status: http.StatusOK,
69+
},
70+
}
71+
for _, test := range tests {
72+
fmt.Println("[Testing]", test.Desc)
73+
setup()
74+
defer tearDown()
75+
record := newCloseNotifyingRecorder()
76+
req := &http.Request{
77+
Method: "GET",
78+
URL: &url.URL{Path: test.Path},
79+
}
80+
go test.Handler(record, req)
81+
// walk around a timing issue
82+
// When we connect to the eventsrouce endpoint the connection is hold open
83+
// so we need to start the handler in a goroutine else the test is blocking
84+
time.Sleep(time.Second * 1)
85+
record.CloseNotify()
86+
87+
if got, want := record.Code, test.Status; got != want {
88+
t.Errorf("%s: response code = %d, want %d", test.Desc, got, want)
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)