Skip to content

Commit

Permalink
Merge 9326130 into 6de981b
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Tsiros committed Jan 12, 2019
2 parents 6de981b + 9326130 commit bfaac13
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 16 deletions.
17 changes: 17 additions & 0 deletions cameras_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,20 @@ func Test_GetCamera(t *testing.T) {

assert.Equal(t, "kphN5lNgHsDtoJkfKnDURMABSChmjsFcjoGuBimqasah81-lE93RiA", th.DeviceID, "deviceIDs should match")
}

func Test_StreamCameraDevice(t *testing.T) {
cl := newTestClient("event: 123\ndata: 456\n", http.StatusOK)
ts := NewCameraService(cl)
s, err := ts.Stream("12345")
if err != nil {
t.Fatal(err)
}

c, err := s.Open()
if err != nil {
t.Fatal(err)
}
event := <-c
assert.Equal(t, "123", event.name)
assert.Equal(t, "456", event.data)
}
3 changes: 3 additions & 0 deletions event.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ func readEvents(events chan<- Event, resp *http.Response) {
}

func extract(line []byte, pfx []byte) string {
if len(line) == 0 {
return ""
}
pfxIdx := len(pfx) + 1
endOfLineIdx := len(line) - 1
return string(line[pfxIdx:endOfLineIdx])
Expand Down
97 changes: 97 additions & 0 deletions event_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package nest

import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"

"github.com/jtsiros/nest/config"
"github.com/stretchr/testify/assert"
)

func Test_extract(t *testing.T) {

tt := []struct {
line []byte
prefix []byte
expected string
}{
{[]byte("data: this is my data\n"), []byte("data:"), "this is my data"},
{[]byte("event: update\n"), []byte("event:"), "update"},
{[]byte(""), []byte("event:"), ""},
}

for _, tc := range tt {
res := extract(tc.line, tc.prefix)
assert.Equal(t, tc.expected, res)
}
}

func Test_readEvents(t *testing.T) {

handlerSuccess := func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "event: this is an event\ndata: this is data\n")
}
handlerEmpty := func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "")
}
req := httptest.NewRequest("GET", "http://localhost/", nil)
tt := []struct {
req func(http.ResponseWriter, *http.Request)
rec *httptest.ResponseRecorder
expectedName, expectedData string
}{
{handlerSuccess, httptest.NewRecorder(), "this is an event", "this is data"},
{handlerEmpty, httptest.NewRecorder(), "", ""},
}

for _, tc := range tt {
tc.req(tc.rec, req)
resp := tc.rec.Result()

events := make(chan Event)
go readEvents(events, resp)
event := <-events

assert.Equal(t, tc.expectedName, event.name)
assert.Equal(t, tc.expectedData, event.data)
}
}

func Test_createConnection(t *testing.T) {
tsSuccess := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "name: event name\ndata: this is data")
}))
tsFailure := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintln(w, `{"message":"error msg"}`)
}))

tt := []struct {
expected string
s *httptest.Server
err error
}{
{"name: event name\ndata: this is data\n", tsSuccess, nil},
{"", tsFailure, errors.New("expected status code 200, got 400")},
}

for _, tc := range tt {
s, _ := NewStream(&config.Config{APIURL: tc.s.URL}, tc.s.Client())
resp, err := s.createConnection()
if tc.err != nil {
if tc.err.Error() != err.Error() {
t.Fatalf("expected err [%v] got [%v]\n", tc.err, err)
}
} else {
b, _ := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
assert.Equal(t, tc.expected, string(b))
}
}
}
19 changes: 19 additions & 0 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,31 @@ import (
"net/url"
)

type response struct {
Status int
Body string
}

func newTestServer(responseMap map[string]*response) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if res, ok := responseMap[r.URL.String()]; ok {
w.WriteHeader(res.Status)
fmt.Fprintln(w, res.Body)
return
}
w.WriteHeader(http.StatusBadRequest)
}))
}

func newTestClient(response string, code int) *Client {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(code)
fmt.Fprintln(w, response)
}))
return newTestClientWithServer(ts)
}

func newTestClientWithServer(ts *httptest.Server) *Client {
url, _ := url.Parse(ts.URL)
c := &Client{
baseURL: url,
Expand Down
92 changes: 83 additions & 9 deletions nest_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package nest

import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
Expand Down Expand Up @@ -309,21 +311,93 @@ const apiResponse = `{
`

func Test_ListOfDevices(t *testing.T) {
tsSuccess := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, apiResponse)
}))

tsErr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintln(w, `{"message": "error msg"}`)
}))

tt := []struct {
s *httptest.Server
err error
}{
{tsSuccess, nil},
{tsErr, errors.New("error msg")},
}

for _, tc := range tt {
api, err := NewClient(config.Config{APIURL: tc.s.URL}, tc.s.Client())
devices, err := api.Devices()
if tc.err != nil {
if err == nil {
t.Fatal("expected non nil Devices() response")
}
assert.Equal(t, tc.err.Error(), err.Error())
} else {
assert.True(t, len(devices.Thermostats) > 0, "should return at least one thermostat")
}
}
}

func Test_NewClientAPIUrl(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, apiResponse)
}))

api, err := NewClient(config.Config{APIURL: ts.URL}, ts.Client())
if err != nil {
assert.Fail(t, err.Error())
return
tt := []struct {
url string
err error
}{
{"http://localhost", nil},
{"()://", errors.New("Not a properly formed API URL: parse ()://: first path segment in URL cannot contain colon")},
}

devices, err := api.Devices()
if err != nil {
assert.Fail(t, err.Error())
return
for _, tc := range tt {
_, err := NewClient(config.Config{APIURL: tc.url}, ts.Client())
if tc.err != nil {
if tc.err.Error() != err.Error() {
t.Fatalf("expected client error [%v], got [%v]", tc.err, err)
}
}
}
}

func Test_NewRequest(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, apiResponse)
}))

tt := []struct {
method, path string
body interface{}
expectedBody string
err error
}{
{"GET", "/test", map[string]string{"key": "value"}, "{\"key\":\"value\"}\n", nil},
{"GET", "/test", map[string]string{}, "{}\n", nil},
{"GET", "/test", nil, "", nil},
{"POST", "/test", map[string]string{}, "{}\n", nil},
{"()", "/test", nil, "", errors.New("net/http: invalid method \"()\"")},
}

c, _ := NewClient(config.Config{APIURL: ts.URL}, ts.Client())

for _, tc := range tt {
req, err := c.newRequest(tc.method, tc.path, tc.body)
if tc.err != nil {
if tc.err.Error() != err.Error() {
t.Fatalf("expected client error [%v], got [%v]", tc.err, err)
}
} else {
if req.Body != nil {
b, _ := ioutil.ReadAll(req.Body)
assert.Equal(t, tc.expectedBody, string(b))
}
assert.Equal(t, tc.method, req.Method)
}
}
assert.True(t, len(devices.Thermostats) > 0, "should return at least one thermostat")
}
17 changes: 17 additions & 0 deletions smokecoalarms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,20 @@ func Test_GetSmokeCoAlarm(t *testing.T) {

assert.Equal(t, "2y2eUoaaXxBij4O1rxoiGfVfehTNCJA_", th.DeviceID, "deviceIDs should match")
}

func Test_StreamSmokeCoAlarmDevice(t *testing.T) {
cl := newTestClient("event: 123\ndata: 456\n", http.StatusOK)
ts := NewSmokeCoAlarmService(cl)
s, err := ts.Stream("12345")
if err != nil {
t.Fatal(err)
}

c, err := s.Open()
if err != nil {
t.Fatal(err)
}
event := <-c
assert.Equal(t, "123", event.name)
assert.Equal(t, "456", event.data)
}
66 changes: 59 additions & 7 deletions thermostats_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nest

import (
"errors"
"net/http"
"testing"

Expand Down Expand Up @@ -73,15 +74,20 @@ func Test_GetThermostat(t *testing.T) {

func Test_SetTargetTemp(t *testing.T) {

d := &device.Thermostat{
DeviceID: "12345abcd",
TemperatureScale: "F",
}

tt := []struct {
target float64
s *ThermostatService
d *device.Thermostat
err string
}{
{76.0, NewThermostatService(newTestClient("76", http.StatusOK)), &device.Thermostat{DeviceID: "12345abcd", TemperatureScale: "F"}, ""},
{91.0, NewThermostatService(newTestClient("{\"message\": \"Temperature F value is too high: 91\"}", http.StatusBadRequest)), &device.Thermostat{DeviceID: "12345abcd", TemperatureScale: "F"}, "Temperature F value is too high: 91"},
{10.0, NewThermostatService(newTestClient("{\"message\": \"Temperature F value is too low: 10\"}", http.StatusBadRequest)), &device.Thermostat{DeviceID: "12345abcd", TemperatureScale: "F"}, "Temperature F value is too low: 10"},
{76.0, NewThermostatService(newTestClient("76", http.StatusOK)), d, ""},
{91.0, NewThermostatService(newTestClient("{\"message\": \"Temperature F value is too high: 91\"}", http.StatusBadRequest)), d, "Temperature F value is too high: 91"},
{10.0, NewThermostatService(newTestClient("{\"message\": \"Temperature F value is too low: 10\"}", http.StatusBadRequest)), d, "Temperature F value is too low: 10"},
}

for _, tc := range tt {
Expand All @@ -94,17 +100,22 @@ func Test_SetTargetTemp(t *testing.T) {

func Test_SetTargetTempRange(t *testing.T) {

d := &device.Thermostat{
DeviceID: "12345abcd",
TemperatureScale: "F",
}

tt := []struct {
low float64
high float64
s *ThermostatService
d *device.Thermostat
err string
}{
{76.0, 80.0, NewThermostatService(newTestClient("76", http.StatusOK)), &device.Thermostat{DeviceID: "12345abcd", TemperatureScale: "F"}, ""},
{80.0, 80.0, NewThermostatService(newTestClient("", http.StatusOK)), &device.Thermostat{DeviceID: "12345abcd", TemperatureScale: "F"}, ""},
{80.0, 76.0, NewThermostatService(newTestClient("", http.StatusBadRequest)), &device.Thermostat{DeviceID: "12345abcd", TemperatureScale: "F"}, "low value must be less than or equal to high value"},
{0.0, 0.0, NewThermostatService(newTestClient("", http.StatusBadRequest)), &device.Thermostat{DeviceID: "12345abcd", TemperatureScale: "F"}, "either low or high target must be set above 0"},
{76.0, 80.0, NewThermostatService(newTestClient("76", http.StatusOK)), d, ""},
{80.0, 80.0, NewThermostatService(newTestClient("", http.StatusOK)), d, ""},
{80.0, 76.0, NewThermostatService(newTestClient("", http.StatusBadRequest)), d, "low value must be less than or equal to high value"},
{0.0, 0.0, NewThermostatService(newTestClient("", http.StatusBadRequest)), d, "either low or high target must be set above 0"},
}

for _, tc := range tt {
Expand Down Expand Up @@ -217,3 +228,44 @@ func Test_SetTempScale(t *testing.T) {
}
}
}

func Test_requestWithValues(t *testing.T) {

tt := []struct {
method string
path string
values map[string]interface{}
s *ThermostatService
err error
}{
{http.MethodGet, "/test", nil, NewThermostatService(newTestClient("", http.StatusOK)), nil},
{"()", "/test", nil, NewThermostatService(newTestClient("", http.StatusOK)), errors.New("net/http: invalid method \"()\"")},
}

for _, tc := range tt {
err := tc.s.requestWithValues(tc.method, tc.path, tc.values)
if tc.err != nil {
isNotNil := assert.NotNil(t, err)
if isNotNil {
assert.Equal(t, tc.err.Error(), err.Error())
}
}
}
}

func Test_StreamThermostatDevice(t *testing.T) {
cl := newTestClient("event: 123\ndata: 456\n", http.StatusOK)
ts := NewThermostatService(cl)
s, err := ts.Stream("12345")
if err != nil {
t.Fatal(err)
}

c, err := s.Open()
if err != nil {
t.Fatal(err)
}
event := <-c
assert.Equal(t, "123", event.name)
assert.Equal(t, "456", event.data)
}

0 comments on commit bfaac13

Please sign in to comment.