hybridgroup.gobot/platforms/particle/adaptor_test.go

394 lines
10 KiB
Go

package particle
import (
"errors"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/donovanhide/eventsource"
"gobot.io/x/gobot"
"gobot.io/x/gobot/drivers/aio"
"gobot.io/x/gobot/drivers/gpio"
"gobot.io/x/gobot/gobottest"
)
var _ gobot.Adaptor = (*Adaptor)(nil)
var _ gpio.DigitalReader = (*Adaptor)(nil)
var _ gpio.DigitalWriter = (*Adaptor)(nil)
var _ aio.AnalogReader = (*Adaptor)(nil)
var _ gpio.PwmWriter = (*Adaptor)(nil)
// HELPERS
func createTestServer(handler func(w http.ResponseWriter, r *http.Request)) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(handler))
}
func getDummyResponseForPath(path string, dummy_response string, t *testing.T) *httptest.Server {
dummy_data := []byte(dummy_response)
return createTestServer(func(w http.ResponseWriter, r *http.Request) {
actualPath := "/v1/devices" + path
if r.URL.Path != actualPath {
t.Errorf("Path doesn't match, expected %#v, got %#v", actualPath, r.URL.Path)
}
w.Write(dummy_data)
})
}
func getDummyResponseForPathWithParams(path string, params []string, dummy_response string, t *testing.T) *httptest.Server {
dummy_data := []byte(dummy_response)
return createTestServer(func(w http.ResponseWriter, r *http.Request) {
actualPath := "/v1/devices" + path
if r.URL.Path != actualPath {
t.Errorf("Path doesn't match, expected %#v, got %#v", actualPath, r.URL.Path)
}
r.ParseForm()
for key, value := range params {
if r.Form["params"][key] != value {
t.Error("Expected param to be " + r.Form["params"][key] + " but was " + value)
}
}
w.Write(dummy_data)
})
}
func initTestAdaptor() *Adaptor {
return NewAdaptor("myDevice", "token")
}
// TESTS
func TestAdaptor(t *testing.T) {
var _ gobot.Adaptor = (*Adaptor)(nil)
var a interface{} = initTestAdaptor()
_, ok := a.(gobot.Adaptor)
if !ok {
t.Errorf("Adaptor{} should be a gobot.Adaptor")
}
}
func TestNewAdaptor(t *testing.T) {
// does it return a pointer to an instance of Adaptor?
var a interface{} = initTestAdaptor()
core, ok := a.(*Adaptor)
if !ok {
t.Errorf("NewAdaptor() should have returned a *Adaptor")
}
gobottest.Assert(t, core.APIServer, "https://api.particle.io")
gobottest.Assert(t, core.Name(), "Particle")
}
func TestAdaptorConnect(t *testing.T) {
a := initTestAdaptor()
gobottest.Assert(t, a.Connect(), nil)
}
func TestAdaptorFinalize(t *testing.T) {
a := initTestAdaptor()
a.Connect()
gobottest.Assert(t, a.Finalize(), nil)
}
func TestAdaptorAnalogRead(t *testing.T) {
// When no error
response := `{"return_value": 5.2}`
params := []string{"A1"}
a := initTestAdaptor()
testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/analogread", params, response, t)
a.setAPIServer(testServer.URL)
defer testServer.Close()
val, _ := a.AnalogRead("A1")
gobottest.Assert(t, val, 5)
}
func TestAdaptorAnalogReadError(t *testing.T) {
a := initTestAdaptor()
// When error
testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
})
defer testServer.Close()
a.setAPIServer(testServer.URL)
val, _ := a.AnalogRead("A1")
gobottest.Assert(t, val, 0)
}
func TestAdaptorPwmWrite(t *testing.T) {
response := `{}`
params := []string{"A1,1"}
a := initTestAdaptor()
testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/analogwrite", params, response, t)
defer testServer.Close()
a.setAPIServer(testServer.URL)
a.PwmWrite("A1", 1)
}
func TestAdaptorAnalogWrite(t *testing.T) {
response := `{}`
params := []string{"A1,1"}
a := initTestAdaptor()
testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/analogwrite", params, response, t)
defer testServer.Close()
a.setAPIServer(testServer.URL)
a.AnalogWrite("A1", 1)
}
func TestAdaptorDigitalWrite(t *testing.T) {
// When HIGH
response := `{}`
params := []string{"D7,HIGH"}
a := initTestAdaptor()
testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/digitalwrite", params, response, t)
a.setAPIServer(testServer.URL)
a.DigitalWrite("D7", 1)
testServer.Close()
// When LOW
params = []string{"D7,LOW"}
testServer = getDummyResponseForPathWithParams("/"+a.DeviceID+"/digitalwrite", params, response, t)
defer testServer.Close()
a.setAPIServer(testServer.URL)
a.DigitalWrite("D7", 0)
}
func TestAdaptorDigitalRead(t *testing.T) {
// When HIGH
response := `{"return_value": 1}`
params := []string{"D7"}
a := initTestAdaptor()
testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/digitalread", params, response, t)
a.setAPIServer(testServer.URL)
val, _ := a.DigitalRead("D7")
gobottest.Assert(t, val, 1)
testServer.Close()
// When LOW
response = `{"return_value": 0}`
testServer = getDummyResponseForPathWithParams("/"+a.DeviceID+"/digitalread", params, response, t)
a.setAPIServer(testServer.URL)
defer testServer.Close()
val, _ = a.DigitalRead("D7")
gobottest.Assert(t, val, 0)
}
func TestAdaptorDigitalReadError(t *testing.T) {
a := initTestAdaptor()
// When error
testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
})
defer testServer.Close()
a.setAPIServer(testServer.URL)
val, _ := a.DigitalRead("D7")
gobottest.Assert(t, val, -1)
}
func TestAdaptorFunction(t *testing.T) {
response := `{"return_value": 1}`
a := initTestAdaptor()
testServer := getDummyResponseForPath("/"+a.DeviceID+"/hello", response, t)
a.setAPIServer(testServer.URL)
val, _ := a.Function("hello", "100,200")
gobottest.Assert(t, val, 1)
testServer.Close()
// When not existent
response = `{"ok": false, "error": "timeout"}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/hello", response, t)
a.setAPIServer(testServer.URL)
_, err := a.Function("hello", "")
gobottest.Assert(t, err.Error(), "timeout")
testServer.Close()
}
func TestAdaptorVariable(t *testing.T) {
// When String
response := `{"result": "1"}`
a := initTestAdaptor()
testServer := getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)
a.setAPIServer(testServer.URL)
val, _ := a.Variable("variable_name")
gobottest.Assert(t, val, "1")
testServer.Close()
// When float
response = `{"result": 1.1}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)
a.setAPIServer(testServer.URL)
val, _ = a.Variable("variable_name")
gobottest.Assert(t, val, "1.1")
testServer.Close()
// When int
response = `{"result": 1}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)
a.setAPIServer(testServer.URL)
val, _ = a.Variable("variable_name")
gobottest.Assert(t, val, "1")
testServer.Close()
// When bool
response = `{"result": true}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)
a.setAPIServer(testServer.URL)
val, _ = a.Variable("variable_name")
gobottest.Assert(t, val, "true")
testServer.Close()
// When not existent
response = `{"ok": false, "error": "Variable not found"}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/not_existent", response, t)
a.setAPIServer(testServer.URL)
_, err := a.Variable("not_existent")
gobottest.Assert(t, err.Error(), "Variable not found")
testServer.Close()
}
func TestAdaptorSetAPIServer(t *testing.T) {
a := initTestAdaptor()
apiServer := "new_api_server"
gobottest.Refute(t, a.APIServer, apiServer)
a.setAPIServer(apiServer)
gobottest.Assert(t, a.APIServer, apiServer)
}
func TestAdaptorDeviceURL(t *testing.T) {
// When APIServer is set
a := initTestAdaptor()
a.setAPIServer("http://server")
a.DeviceID = "devID"
gobottest.Assert(t, a.deviceURL(), "http://server/v1/devices/devID")
// When APIServer is not set
a = &Adaptor{name: "particleie", DeviceID: "myDevice", AccessToken: "token"}
gobottest.Assert(t, a.deviceURL(), "https://api.particle.io/v1/devices/myDevice")
}
func TestAdaptorPinLevel(t *testing.T) {
a := initTestAdaptor()
gobottest.Assert(t, a.pinLevel(1), "HIGH")
gobottest.Assert(t, a.pinLevel(0), "LOW")
gobottest.Assert(t, a.pinLevel(5), "LOW")
}
func TestAdaptorPostToparticle(t *testing.T) {
a := initTestAdaptor()
// When error on request
vals := url.Values{}
vals.Add("error", "error")
resp, err := a.request("POST", "http://invalid%20host.com", vals)
if err == nil {
t.Error("request() should return an error when request was unsuccessful but returned", resp)
}
// When error reading body
// Pending
// When response.Status is not 200
testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
})
defer testServer.Close()
resp, err = a.request("POST", testServer.URL+"/existent", vals)
if err == nil {
t.Error("request() should return an error when status is not 200 but returned", resp)
}
}
type testEventSource struct {
event string
data string
}
func (testEventSource) Id() string { return "" }
func (t testEventSource) Event() string { return t.event }
func (t testEventSource) Data() string { return t.data }
func TestAdaptorEventStream(t *testing.T) {
a := initTestAdaptor()
var url string
eventSource = func(u string) (chan eventsource.Event, chan error, error) {
url = u
return nil, nil, nil
}
a.EventStream("all", "ping")
gobottest.Assert(t, url, "https://api.particle.io/v1/events/ping?access_token=token")
a.EventStream("devices", "ping")
gobottest.Assert(t, url, "https://api.particle.io/v1/devices/events/ping?access_token=token")
a.EventStream("device", "ping")
gobottest.Assert(t, url, "https://api.particle.io/v1/devices/myDevice/events/ping?access_token=token")
_, err := a.EventStream("nothing", "ping")
gobottest.Assert(t, err.Error(), "source param should be: all, devices or device")
eventSource = func(u string) (chan eventsource.Event, chan error, error) {
return nil, nil, errors.New("error connecting sse")
}
_, err = a.EventStream("devices", "")
gobottest.Assert(t, err.Error(), "error connecting sse")
eventChan := make(chan eventsource.Event, 0)
errorChan := make(chan error, 0)
eventSource = func(u string) (chan eventsource.Event, chan error, error) {
return eventChan, errorChan, nil
}
_, err = a.EventStream("devices", "")
gobottest.Assert(t, err, nil)
}