gobot.io/x/gobot/v2@v2.1.0/platforms/particle/adaptor_test.go (about)

     1  package particle
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"net/url"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/donovanhide/eventsource"
    12  	"gobot.io/x/gobot/v2"
    13  	"gobot.io/x/gobot/v2/gobottest"
    14  )
    15  
    16  // HELPERS
    17  
    18  func createTestServer(handler func(w http.ResponseWriter, r *http.Request)) *httptest.Server {
    19  	return httptest.NewServer(http.HandlerFunc(handler))
    20  }
    21  
    22  func getDummyResponseForPath(path string, dummy_response string, t *testing.T) *httptest.Server {
    23  	dummy_data := []byte(dummy_response)
    24  
    25  	return createTestServer(func(w http.ResponseWriter, r *http.Request) {
    26  		actualPath := "/v1/devices" + path
    27  		if r.URL.Path != actualPath {
    28  			t.Errorf("Path doesn't match, expected %#v, got %#v", actualPath, r.URL.Path)
    29  		}
    30  		w.Write(dummy_data)
    31  	})
    32  }
    33  
    34  func getDummyResponseForPathWithParams(path string, params []string, dummy_response string, t *testing.T) *httptest.Server {
    35  	dummy_data := []byte(dummy_response)
    36  
    37  	return createTestServer(func(w http.ResponseWriter, r *http.Request) {
    38  		actualPath := "/v1/devices" + path
    39  		if r.URL.Path != actualPath {
    40  			t.Errorf("Path doesn't match, expected %#v, got %#v", actualPath, r.URL.Path)
    41  		}
    42  
    43  		r.ParseForm()
    44  
    45  		for key, value := range params {
    46  			if r.Form["params"][key] != value {
    47  				t.Error("Expected param to be " + r.Form["params"][key] + " but was " + value)
    48  			}
    49  		}
    50  		w.Write(dummy_data)
    51  	})
    52  }
    53  
    54  func initTestAdaptor() *Adaptor {
    55  	return NewAdaptor("myDevice", "token")
    56  }
    57  
    58  func initTestAdaptorWithServo() *Adaptor {
    59  	a := NewAdaptor("myDevice", "token")
    60  	a.servoPins["1"] = true
    61  	return a
    62  }
    63  
    64  // TESTS
    65  
    66  func TestAdaptor(t *testing.T) {
    67  	var a interface{} = initTestAdaptor()
    68  	_, ok := a.(gobot.Adaptor)
    69  	if !ok {
    70  		t.Errorf("Adaptor{} should be a gobot.Adaptor")
    71  	}
    72  }
    73  
    74  func TestNewAdaptor(t *testing.T) {
    75  	// does it return a pointer to an instance of Adaptor?
    76  	var a interface{} = initTestAdaptor()
    77  	core, ok := a.(*Adaptor)
    78  	if !ok {
    79  		t.Errorf("NewAdaptor() should have returned a *Adaptor")
    80  	}
    81  
    82  	gobottest.Assert(t, core.APIServer, "https://api.particle.io")
    83  	gobottest.Assert(t, strings.HasPrefix(core.Name(), "Particle"), true)
    84  
    85  	core.SetName("sparkie")
    86  	gobottest.Assert(t, core.Name(), "sparkie")
    87  }
    88  
    89  func TestAdaptorConnect(t *testing.T) {
    90  	a := initTestAdaptor()
    91  	gobottest.Assert(t, a.Connect(), nil)
    92  }
    93  
    94  func TestAdaptorFinalize(t *testing.T) {
    95  	a := initTestAdaptor()
    96  	a.Connect()
    97  	gobottest.Assert(t, a.Finalize(), nil)
    98  }
    99  
   100  func TestAdaptorAnalogRead(t *testing.T) {
   101  	// When no error
   102  	response := `{"return_value": 5.2}`
   103  	params := []string{"A1"}
   104  
   105  	a := initTestAdaptor()
   106  	testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/analogread", params, response, t)
   107  
   108  	a.setAPIServer(testServer.URL)
   109  	defer testServer.Close()
   110  
   111  	val, _ := a.AnalogRead("A1")
   112  	gobottest.Assert(t, val, 5)
   113  }
   114  
   115  func TestAdaptorAnalogReadError(t *testing.T) {
   116  	a := initTestAdaptor()
   117  	// When error
   118  	testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   119  		http.NotFound(w, r)
   120  	})
   121  	defer testServer.Close()
   122  	a.setAPIServer(testServer.URL)
   123  
   124  	val, _ := a.AnalogRead("A1")
   125  	gobottest.Assert(t, val, 0)
   126  }
   127  
   128  func TestAdaptorPwmWrite(t *testing.T) {
   129  	response := `{}`
   130  	params := []string{"A1,1"}
   131  
   132  	a := initTestAdaptor()
   133  	testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/analogwrite", params, response, t)
   134  	defer testServer.Close()
   135  
   136  	a.setAPIServer(testServer.URL)
   137  	a.PwmWrite("A1", 1)
   138  }
   139  
   140  func TestAdaptorAnalogWrite(t *testing.T) {
   141  	response := `{}`
   142  	params := []string{"A1,1"}
   143  
   144  	a := initTestAdaptor()
   145  	testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/analogwrite", params, response, t)
   146  	defer testServer.Close()
   147  
   148  	a.setAPIServer(testServer.URL)
   149  	a.AnalogWrite("A1", 1)
   150  }
   151  
   152  func TestAdaptorDigitalWrite(t *testing.T) {
   153  	// When HIGH
   154  	response := `{}`
   155  	params := []string{"D7,HIGH"}
   156  
   157  	a := initTestAdaptor()
   158  	testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/digitalwrite", params, response, t)
   159  
   160  	a.setAPIServer(testServer.URL)
   161  	a.DigitalWrite("D7", 1)
   162  
   163  	testServer.Close()
   164  	// When LOW
   165  	params = []string{"D7,LOW"}
   166  
   167  	testServer = getDummyResponseForPathWithParams("/"+a.DeviceID+"/digitalwrite", params, response, t)
   168  	defer testServer.Close()
   169  
   170  	a.setAPIServer(testServer.URL)
   171  	a.DigitalWrite("D7", 0)
   172  }
   173  
   174  func TestAdaptorServoOpen(t *testing.T) {
   175  	response := `{}`
   176  	params := []string{"1"}
   177  
   178  	a := initTestAdaptor()
   179  	testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/servoOpen", params, response, t)
   180  	defer testServer.Close()
   181  
   182  	a.setAPIServer(testServer.URL)
   183  	a.servoPinOpen("1")
   184  }
   185  
   186  func TestAdaptorServoWrite(t *testing.T) {
   187  	response := `{}`
   188  	params := []string{"1,128"}
   189  
   190  	a := initTestAdaptorWithServo()
   191  	testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/servoSet", params, response, t)
   192  	defer testServer.Close()
   193  
   194  	a.setAPIServer(testServer.URL)
   195  	a.ServoWrite("1", 128)
   196  }
   197  
   198  func TestAdaptorDigitalRead(t *testing.T) {
   199  	// When HIGH
   200  	response := `{"return_value": 1}`
   201  	params := []string{"D7"}
   202  
   203  	a := initTestAdaptor()
   204  	testServer := getDummyResponseForPathWithParams("/"+a.DeviceID+"/digitalread", params, response, t)
   205  
   206  	a.setAPIServer(testServer.URL)
   207  
   208  	val, _ := a.DigitalRead("D7")
   209  	gobottest.Assert(t, val, 1)
   210  	testServer.Close()
   211  
   212  	// When LOW
   213  	response = `{"return_value": 0}`
   214  
   215  	testServer = getDummyResponseForPathWithParams("/"+a.DeviceID+"/digitalread", params, response, t)
   216  
   217  	a.setAPIServer(testServer.URL)
   218  	defer testServer.Close()
   219  
   220  	val, _ = a.DigitalRead("D7")
   221  	gobottest.Assert(t, val, 0)
   222  }
   223  
   224  func TestAdaptorDigitalReadError(t *testing.T) {
   225  	a := initTestAdaptor()
   226  	// When error
   227  	testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   228  		http.NotFound(w, r)
   229  	})
   230  	defer testServer.Close()
   231  
   232  	a.setAPIServer(testServer.URL)
   233  
   234  	val, _ := a.DigitalRead("D7")
   235  	gobottest.Assert(t, val, -1)
   236  }
   237  
   238  func TestAdaptorFunction(t *testing.T) {
   239  	response := `{"return_value": 1}`
   240  
   241  	a := initTestAdaptor()
   242  	testServer := getDummyResponseForPath("/"+a.DeviceID+"/hello", response, t)
   243  
   244  	a.setAPIServer(testServer.URL)
   245  
   246  	val, _ := a.Function("hello", "100,200")
   247  	gobottest.Assert(t, val, 1)
   248  	testServer.Close()
   249  
   250  	// When not existent
   251  	response = `{"ok": false, "error": "timeout"}`
   252  	testServer = getDummyResponseForPath("/"+a.DeviceID+"/hello", response, t)
   253  
   254  	a.setAPIServer(testServer.URL)
   255  
   256  	_, err := a.Function("hello", "")
   257  	gobottest.Assert(t, err.Error(), "timeout")
   258  
   259  	testServer.Close()
   260  }
   261  
   262  func TestAdaptorVariable(t *testing.T) {
   263  	// When String
   264  	response := `{"result": "1"}`
   265  
   266  	a := initTestAdaptor()
   267  	testServer := getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)
   268  
   269  	a.setAPIServer(testServer.URL)
   270  
   271  	val, _ := a.Variable("variable_name")
   272  	gobottest.Assert(t, val, "1")
   273  	testServer.Close()
   274  
   275  	// When float
   276  	response = `{"result": 1.1}`
   277  	testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)
   278  
   279  	a.setAPIServer(testServer.URL)
   280  
   281  	val, _ = a.Variable("variable_name")
   282  	gobottest.Assert(t, val, "1.1")
   283  	testServer.Close()
   284  
   285  	// When int
   286  	response = `{"result": 1}`
   287  	testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)
   288  
   289  	a.setAPIServer(testServer.URL)
   290  
   291  	val, _ = a.Variable("variable_name")
   292  	gobottest.Assert(t, val, "1")
   293  	testServer.Close()
   294  
   295  	// When bool
   296  	response = `{"result": true}`
   297  	testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)
   298  
   299  	a.setAPIServer(testServer.URL)
   300  
   301  	val, _ = a.Variable("variable_name")
   302  	gobottest.Assert(t, val, "true")
   303  	testServer.Close()
   304  
   305  	// When not existent
   306  	response = `{"ok": false, "error": "Variable not found"}`
   307  	testServer = getDummyResponseForPath("/"+a.DeviceID+"/not_existent", response, t)
   308  
   309  	a.setAPIServer(testServer.URL)
   310  
   311  	_, err := a.Variable("not_existent")
   312  	gobottest.Assert(t, err.Error(), "Variable not found")
   313  
   314  	testServer.Close()
   315  }
   316  
   317  func TestAdaptorSetAPIServer(t *testing.T) {
   318  	a := initTestAdaptor()
   319  	apiServer := "new_api_server"
   320  	gobottest.Refute(t, a.APIServer, apiServer)
   321  
   322  	a.setAPIServer(apiServer)
   323  	gobottest.Assert(t, a.APIServer, apiServer)
   324  }
   325  
   326  func TestAdaptorDeviceURL(t *testing.T) {
   327  	// When APIServer is set
   328  	a := initTestAdaptor()
   329  	a.setAPIServer("http://server")
   330  	a.DeviceID = "devID"
   331  	gobottest.Assert(t, a.deviceURL(), "http://server/v1/devices/devID")
   332  
   333  	// When APIServer is not set
   334  	a = &Adaptor{name: "particleie", DeviceID: "myDevice", AccessToken: "token"}
   335  	gobottest.Assert(t, a.deviceURL(), "https://api.particle.io/v1/devices/myDevice")
   336  }
   337  
   338  func TestAdaptorPinLevel(t *testing.T) {
   339  	a := initTestAdaptor()
   340  
   341  	gobottest.Assert(t, a.pinLevel(1), "HIGH")
   342  	gobottest.Assert(t, a.pinLevel(0), "LOW")
   343  	gobottest.Assert(t, a.pinLevel(5), "LOW")
   344  }
   345  
   346  func TestAdaptorPostToparticle(t *testing.T) {
   347  	a := initTestAdaptor()
   348  
   349  	// When error on request
   350  	vals := url.Values{}
   351  	vals.Add("error", "error")
   352  	resp, err := a.request("POST", "http://invalid%20host.com", vals)
   353  	if err == nil {
   354  		t.Error("request() should return an error when request was unsuccessful but returned", resp)
   355  	}
   356  
   357  	// When error reading body
   358  	// Pending
   359  
   360  	// When response.Status is not 200
   361  	testServer := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   362  		http.NotFound(w, r)
   363  	})
   364  	defer testServer.Close()
   365  
   366  	resp, err = a.request("POST", testServer.URL+"/existent", vals)
   367  	if err == nil {
   368  		t.Error("request() should return an error when status is not 200 but returned", resp)
   369  	}
   370  }
   371  
   372  type testEventSource struct {
   373  	event string
   374  	data  string
   375  }
   376  
   377  func (testEventSource) Id() string      { return "" }
   378  func (t testEventSource) Event() string { return t.event }
   379  func (t testEventSource) Data() string  { return t.data }
   380  
   381  func TestAdaptorEventStream(t *testing.T) {
   382  	a := initTestAdaptor()
   383  	var url string
   384  	eventSource = func(u string) (chan eventsource.Event, chan error, error) {
   385  		url = u
   386  		return nil, nil, nil
   387  	}
   388  	a.EventStream("all", "ping")
   389  	gobottest.Assert(t, url, "https://api.particle.io/v1/events/ping?access_token=token")
   390  
   391  	a.EventStream("devices", "ping")
   392  	gobottest.Assert(t, url, "https://api.particle.io/v1/devices/events/ping?access_token=token")
   393  
   394  	a.EventStream("device", "ping")
   395  	gobottest.Assert(t, url, "https://api.particle.io/v1/devices/myDevice/events/ping?access_token=token")
   396  
   397  	_, err := a.EventStream("nothing", "ping")
   398  	gobottest.Assert(t, err.Error(), "source param should be: all, devices or device")
   399  
   400  	eventSource = func(u string) (chan eventsource.Event, chan error, error) {
   401  		return nil, nil, errors.New("error connecting sse")
   402  	}
   403  
   404  	_, err = a.EventStream("devices", "")
   405  	gobottest.Assert(t, err.Error(), "error connecting sse")
   406  
   407  	eventChan := make(chan eventsource.Event)
   408  	errorChan := make(chan error)
   409  
   410  	eventSource = func(u string) (chan eventsource.Event, chan error, error) {
   411  		return eventChan, errorChan, nil
   412  	}
   413  
   414  	_, err = a.EventStream("devices", "")
   415  	gobottest.Assert(t, err, nil)
   416  }