mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-27 13:48:56 +08:00
Add SSE test coverage
Add a Stream type that handle the request to /events/:event and write tests for event stream Add a test for the events/:event endpoint that actually tests the endpoint response Using <-time.After in a 'select' creates one channel every time, let's use a time.Timer instead so that we reuse the same channel
This commit is contained in:
parent
bc8bb36f8f
commit
1f09fb021b
11
api/api.go
11
api/api.go
@ -224,15 +224,12 @@ func (a *API) robotDevice(res http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// robotDeviceEvent returns device event route handler.
|
|
||||||
// Creates an event stream connection
|
|
||||||
// and queries event data to be written when received
|
|
||||||
func (a *API) robotDeviceEvent(res http.ResponseWriter, req *http.Request) {
|
func (a *API) robotDeviceEvent(res http.ResponseWriter, req *http.Request) {
|
||||||
f, _ := res.(http.Flusher)
|
f, _ := res.(http.Flusher)
|
||||||
c, _ := res.(http.CloseNotifier)
|
c, _ := res.(http.CloseNotifier)
|
||||||
|
|
||||||
|
dataChan := make(chan string)
|
||||||
closer := c.CloseNotify()
|
closer := c.CloseNotify()
|
||||||
msg := make(chan string)
|
|
||||||
|
|
||||||
res.Header().Set("Content-Type", "text/event-stream")
|
res.Header().Set("Content-Type", "text/event-stream")
|
||||||
res.Header().Set("Cache-Control", "no-cache")
|
res.Header().Set("Cache-Control", "no-cache")
|
||||||
@ -243,12 +240,12 @@ func (a *API) robotDeviceEvent(res http.ResponseWriter, req *http.Request) {
|
|||||||
Event(req.URL.Query().Get(":event")); event != nil {
|
Event(req.URL.Query().Get(":event")); event != nil {
|
||||||
gobot.On(event, func(data interface{}) {
|
gobot.On(event, func(data interface{}) {
|
||||||
d, _ := json.Marshal(data)
|
d, _ := json.Marshal(data)
|
||||||
msg <- string(d)
|
dataChan <- string(d)
|
||||||
})
|
})
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case data := <-msg:
|
case data := <-dataChan:
|
||||||
fmt.Fprintf(res, "data: %v\n\n", data)
|
fmt.Fprintf(res, "data: %v\n\n", data)
|
||||||
f.Flush()
|
f.Flush()
|
||||||
case <-closer:
|
case <-closer:
|
||||||
@ -258,7 +255,7 @@ func (a *API) robotDeviceEvent(res http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
a.writeJSON(map[string]interface{}{
|
a.writeJSON(map[string]interface{}{
|
||||||
"error": errors.New("No Event found with the name " + req.URL.Query().Get(":event")),
|
"error": "No Event found with the name " + req.URL.Query().Get(":event"),
|
||||||
}, res)
|
}, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -8,6 +9,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hybridgroup/gobot"
|
"github.com/hybridgroup/gobot"
|
||||||
)
|
)
|
||||||
@ -363,6 +365,55 @@ func TestRobotConnection(t *testing.T) {
|
|||||||
gobot.Assert(t, body["error"], "No Connection found with the name UnknownConnection1")
|
gobot.Assert(t, body["error"], "No Connection found with the name UnknownConnection1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRobotDeviceEvent(t *testing.T) {
|
||||||
|
a := initTestAPI()
|
||||||
|
server := httptest.NewServer(a)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
eventsUrl := "/api/robots/Robot1/devices/Device1/events/"
|
||||||
|
|
||||||
|
// known event
|
||||||
|
respc := make(chan *http.Response, 1)
|
||||||
|
go func() {
|
||||||
|
resp, _ := http.Get(server.URL + eventsUrl + "TestEvent")
|
||||||
|
respc <- resp
|
||||||
|
}()
|
||||||
|
|
||||||
|
event := a.gobot.Robot("Robot1").
|
||||||
|
Device("Device1").(gobot.Eventer).
|
||||||
|
Event("TestEvent")
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Millisecond * 5)
|
||||||
|
gobot.Publish(event, "event-data")
|
||||||
|
}()
|
||||||
|
|
||||||
|
done := false
|
||||||
|
timer := time.NewTimer(time.Millisecond * 10)
|
||||||
|
|
||||||
|
for !done {
|
||||||
|
select {
|
||||||
|
case resp := <-respc:
|
||||||
|
reader := bufio.NewReader(resp.Body)
|
||||||
|
data, _ := reader.ReadString('\n')
|
||||||
|
gobot.Assert(t, data, "data: \"event-data\"\n")
|
||||||
|
done = true
|
||||||
|
case <-timer.C:
|
||||||
|
t.Error("Not receiving data")
|
||||||
|
done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server.CloseClientConnections()
|
||||||
|
|
||||||
|
// unknown event
|
||||||
|
response, _ := http.Get(server.URL + eventsUrl + "UnknownEvent")
|
||||||
|
|
||||||
|
var body map[string]interface{}
|
||||||
|
json.NewDecoder(response.Body).Decode(&body)
|
||||||
|
gobot.Assert(t, body["error"], "No Event found with the name UnknownEvent")
|
||||||
|
}
|
||||||
|
|
||||||
func TestAPIRouter(t *testing.T) {
|
func TestAPIRouter(t *testing.T) {
|
||||||
a := initTestAPI()
|
a := initTestAPI()
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ type testDriver struct {
|
|||||||
pin string
|
pin string
|
||||||
connection gobot.Connection
|
connection gobot.Connection
|
||||||
gobot.Commander
|
gobot.Commander
|
||||||
|
gobot.Eventer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testDriver) Start() (errs []error) { return }
|
func (t *testDriver) Start() (errs []error) { return }
|
||||||
@ -38,9 +39,12 @@ func newTestDriver(adaptor *testAdaptor, name string, pin string) *testDriver {
|
|||||||
name: name,
|
name: name,
|
||||||
connection: adaptor,
|
connection: adaptor,
|
||||||
pin: pin,
|
pin: pin,
|
||||||
|
Eventer: gobot.NewEventer(),
|
||||||
Commander: gobot.NewCommander(),
|
Commander: gobot.NewCommander(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.AddEvent("TestEvent")
|
||||||
|
|
||||||
t.AddCommand("TestDriverCommand", func(params map[string]interface{}) interface{} {
|
t.AddCommand("TestDriverCommand", func(params map[string]interface{}) interface{} {
|
||||||
name := params["name"].(string)
|
name := params["name"].(string)
|
||||||
return fmt.Sprintf("hello %v", name)
|
return fmt.Sprintf("hello %v", name)
|
||||||
|
@ -18,7 +18,6 @@ type testDriver struct {
|
|||||||
name string
|
name string
|
||||||
pin string
|
pin string
|
||||||
connection Connection
|
connection Connection
|
||||||
Eventer
|
|
||||||
Commander
|
Commander
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,24 +35,14 @@ func newTestDriver(adaptor *testAdaptor, name string, pin string) *testDriver {
|
|||||||
name: name,
|
name: name,
|
||||||
connection: adaptor,
|
connection: adaptor,
|
||||||
pin: pin,
|
pin: pin,
|
||||||
Eventer: NewEventer(),
|
|
||||||
Commander: NewCommander(),
|
Commander: NewCommander(),
|
||||||
}
|
}
|
||||||
|
|
||||||
t.AddEvent("DriverCommand")
|
t.AddCommand("DriverCommand", func(params map[string]interface{}) interface{} { return nil })
|
||||||
|
|
||||||
t.AddCommand("DriverCommand", func(params map[string]interface{}) interface{} {
|
|
||||||
return t.DriverCommand()
|
|
||||||
})
|
|
||||||
|
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testDriver) DriverCommand() string {
|
|
||||||
Publish(t.Event("DriverCommand"), "DriverCommand")
|
|
||||||
return "DriverCommand"
|
|
||||||
}
|
|
||||||
|
|
||||||
type testAdaptor struct {
|
type testAdaptor struct {
|
||||||
name string
|
name string
|
||||||
port string
|
port string
|
||||||
|
Loading…
x
Reference in New Issue
Block a user