1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-27 13:48:49 +08:00
Mainflux.mainflux/pkg/sdk/go/things_test.go
Aryan Godara e6e9d22133
MF-1670 - Improve error handling in SDK (#1674)
* initial commit

Signed-off-by: aryan <aryangodara03@gmail.com>

* remove unused variables.

Signed-off-by: aryan <aryangodara03@gmail.com>

* removed temporarily created file.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Fix failing CI

Signed-off-by: aryan <aryangodara03@gmail.com>

* Fix thing_test failing cases.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Remove dead code, debug statements, and add comments.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Extract errors to separate file.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Updated things/api/http tests

Signed-off-by: aryan <aryangodara03@gmail.com>

* Created custom SDK error.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Changed to using CheckError. All tests passing.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Replace error interface with errors.SDKError interface.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Fix failing CI.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Remove unused sdk errors.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Change SDKError to error in internal function of sdk package.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Remove unused error.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Remove encodeError. All tests working.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Rename sdkerr vars, convert common strings to constants.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Change checkerror to take error instead of string.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Remove unused errors, and removed errfailedwhitelist wrap.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Removed unused errors, and remove errors.go since it only had a repeated error from errors package

Signed-off-by: aryan <aryangodara03@gmail.com>

* Remove unused errors.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Update sdk_error.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Used function to reduce code for sending and receiving requests.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Added function sendrequestandgetheadersorerror.

Signed-off-by: aryan <aryangodara03@gmail.com>

* sdk_error updated.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Updated function names to processRequest.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Made errors internal, fixed typo in http.

Signed-off-by: aryan <aryangodara03@gmail.com>

* Remove empty line.

Signed-off-by: aryan <aryangodara03@gmail.com>

* merged proceessBody and processHeaders functions in sdk.

Signed-off-by: aryan <aryangodara03@gmail.com>

* remove sendThingRequest function.

Signed-off-by: aryan <aryangodara03@gmail.com>

* changed processRequest signature

Signed-off-by: aryan <aryangodara03@gmail.com>

* changed processRequest signature, changed error names.

Signed-off-by: aryan <aryangodara03@gmail.com>

Signed-off-by: aryan <aryangodara03@gmail.com>
Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2022-12-15 16:24:19 +01:00

911 lines
24 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package sdk_test
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/things"
authapi "github.com/mainflux/mainflux/things/api/auth/http"
httpapi "github.com/mainflux/mainflux/things/api/things/http"
"github.com/mainflux/mainflux/things/mocks"
"github.com/opentracing/opentracing-go/mocktracer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const (
contentType = "application/senml+json"
email = "user@example.com"
adminEmail = "admin@example.com"
otherEmail = "other_user@example.com"
token = "token"
otherToken = "other_token"
wrongValue = "wrong_value"
badKey = "999"
)
var (
metadata = map[string]interface{}{"meta": "data"}
metadata2 = map[string]interface{}{"meta": "data2"}
th1 = sdk.Thing{ID: "fe6b4e92-cc98-425e-b0aa-000000000001", Name: "test1", Metadata: metadata}
th2 = sdk.Thing{ID: "fe6b4e92-cc98-425e-b0aa-000000000002", Name: "test2", Metadata: metadata}
emptyThing = sdk.Thing{}
)
func newThingsService(tokens map[string]string) things.Service {
userPolicy := mocks.MockSubjectSet{Object: "users", Relation: "member"}
adminPolicy := mocks.MockSubjectSet{Object: "authorities", Relation: "member"}
auth := mocks.NewAuthService(tokens, map[string][]mocks.MockSubjectSet{
adminEmail: {userPolicy, adminPolicy}, email: {userPolicy}})
conns := make(chan mocks.Connection)
thingsRepo := mocks.NewThingRepository(conns)
channelsRepo := mocks.NewChannelRepository(thingsRepo, conns)
chanCache := mocks.NewChannelCache()
thingCache := mocks.NewThingCache()
idProvider := uuid.NewMock()
return things.New(auth, thingsRepo, channelsRepo, chanCache, thingCache, idProvider)
}
func newThingsServer(svc things.Service) *httptest.Server {
logger := logger.NewMock()
mux := httpapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
func newAuthServer(svc things.Service) *httptest.Server {
logger := logger.NewMock()
mux := authapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
func TestCreateThing(t *testing.T) {
svc := newThingsService(map[string]string{token: email})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
cases := []struct {
desc string
thing sdk.Thing
token string
err error
location string
}{
{
desc: "create new thing",
thing: th1,
token: token,
err: nil,
location: th1.ID,
},
{
desc: "create new empty thing",
thing: emptyThing,
token: token,
err: nil,
location: fmt.Sprintf("%s%012d", uuid.Prefix, 2),
},
{
desc: "create new thing with empty token",
thing: th1,
token: "",
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
location: "",
},
{
desc: "create new thing with invalid token",
thing: th1,
token: wrongValue,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
location: "",
},
}
for _, tc := range cases {
loc, err := mainfluxSDK.CreateThing(tc.thing, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.location, loc, fmt.Sprintf("%s: expected location %s got %s", tc.desc, tc.location, loc))
}
}
func TestCreateThings(t *testing.T) {
svc := newThingsService(map[string]string{token: email})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
things := []sdk.Thing{
th1,
th2,
}
thsExtID := []sdk.Thing{
{ID: th1.ID, Name: "1", Key: "1", Metadata: metadata},
{ID: th2.ID, Name: "2", Key: "2", Metadata: metadata},
}
thsWrongExtID := []sdk.Thing{
{ID: "b0aa-000000000001", Name: "1", Key: "1", Metadata: metadata},
{ID: "b0aa-000000000002", Name: "2", Key: "2", Metadata: metadata2},
}
cases := []struct {
desc string
things []sdk.Thing
token string
err error
res []sdk.Thing
}{
{
desc: "create new things",
things: things,
token: token,
err: nil,
res: things,
},
{
desc: "create new things with empty things",
things: []sdk.Thing{},
token: token,
err: errors.NewSDKErrorWithStatus(apiutil.ErrEmptyList, http.StatusBadRequest),
res: []sdk.Thing{},
},
{
desc: "create new thing with empty token",
things: things,
token: "",
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
res: []sdk.Thing{},
},
{
desc: "create new thing with invalid token",
things: things,
token: wrongValue,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
res: []sdk.Thing{},
},
{
desc: "create new things with external UUID",
things: thsExtID,
token: token,
err: nil,
res: things,
},
{
desc: "create new things with wrong external UUID",
things: thsWrongExtID,
token: token,
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidIDFormat, http.StatusBadRequest),
res: []sdk.Thing{},
},
}
for _, tc := range cases {
res, err := mainfluxSDK.CreateThings(tc.things, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
for idx := range tc.res {
assert.Equal(t, tc.res[idx].ID, res[idx].ID, fmt.Sprintf("%s: expected response ID %s got %s", tc.desc, tc.res[idx].ID, res[idx].ID))
}
}
}
func TestThing(t *testing.T) {
svc := newThingsService(map[string]string{token: email})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th1.Key = fmt.Sprintf("%s%012d", uuid.Prefix, 1)
cases := []struct {
desc string
thID string
token string
err error
response sdk.Thing
}{
{
desc: "get existing thing",
thID: id,
token: token,
err: nil,
response: th1,
},
{
desc: "get non-existent thing",
thID: "43",
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
response: sdk.Thing{},
},
{
desc: "get thing with invalid token",
thID: id,
token: wrongValue,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
response: sdk.Thing{},
},
}
for _, tc := range cases {
respTh, err := mainfluxSDK.Thing(tc.thID, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.response, respTh, fmt.Sprintf("%s: expected response thing %s, got %s", tc.desc, tc.response, respTh))
}
}
func TestThings(t *testing.T) {
svc := newThingsService(map[string]string{token: email})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
var things []sdk.Thing
mainfluxSDK := sdk.NewSDK(sdkConf)
for i := 1; i < 101; i++ {
id := fmt.Sprintf("%s%012d", chPrefix, i)
name := fmt.Sprintf("test-%d", i)
th := sdk.Thing{ID: id, Name: name, Metadata: metadata}
_, err := mainfluxSDK.CreateThing(th, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th.Key = fmt.Sprintf("%s%012d", uuid.Prefix, i)
things = append(things, th)
}
cases := []struct {
desc string
token string
offset uint64
limit uint64
err error
response []sdk.Thing
name string
metadata map[string]interface{}
}{
{
desc: "get a list of things",
token: token,
offset: offset,
limit: limit,
err: nil,
response: things[0:limit],
metadata: make(map[string]interface{}),
},
{
desc: "get a list of things with invalid token",
token: wrongValue,
offset: offset,
limit: limit,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
response: nil,
metadata: make(map[string]interface{}),
},
{
desc: "get a list of things with empty token",
token: "",
offset: offset,
limit: limit,
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
response: nil,
metadata: make(map[string]interface{}),
},
{
desc: "get a list of things with zero limit",
token: token,
offset: 0,
limit: 0,
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
response: nil,
metadata: make(map[string]interface{}),
},
{
desc: "get a list of things with limit greater than max",
token: token,
offset: offset,
limit: 110,
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
response: nil,
metadata: make(map[string]interface{}),
},
{
desc: "get a list of things with offset greater than max",
token: token,
offset: 110,
limit: limit,
err: nil,
response: []sdk.Thing{},
metadata: make(map[string]interface{}),
},
}
for _, tc := range cases {
filter := sdk.PageMetadata{
Name: tc.name,
Total: total,
Offset: uint64(tc.offset),
Limit: uint64(tc.limit),
Metadata: tc.metadata,
}
page, err := mainfluxSDK.Things(tc.token, filter)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.response, page.Things, fmt.Sprintf("%s: expected response channel %s, got %s", tc.desc, tc.response, page.Things))
}
}
func TestThingsByChannel(t *testing.T) {
svc := newThingsService(map[string]string{token: email})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
ch := sdk.Channel{Name: "test_channel"}
cid, err := mainfluxSDK.CreateChannel(ch, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
var n = 10
var thsDiscoNum = 1
var things []sdk.Thing
for i := 1; i < n+1; i++ {
id := fmt.Sprintf("%s%012d", chPrefix, i)
name := fmt.Sprintf("test-%d", i)
th := sdk.Thing{
ID: id,
Name: name,
Metadata: metadata,
Key: fmt.Sprintf("%s%012d", uuid.Prefix, 2*i+1),
}
tid, err := mainfluxSDK.CreateThing(th, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
things = append(things, th)
// Don't connect last Thing
if i == n+1-thsDiscoNum {
break
}
// Don't connect last 2 Channels
conIDs := sdk.ConnectionIDs{
ChannelIDs: []string{cid},
ThingIDs: []string{tid},
}
err = mainfluxSDK.Connect(conIDs, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
}
cases := []struct {
desc string
channel string
token string
offset uint64
limit uint64
disconnected bool
err error
response []sdk.Thing
}{
{
desc: "get a list of things by channel",
channel: cid,
token: token,
offset: offset,
limit: limit,
err: nil,
response: things[0:limit],
},
{
desc: "get a list of things by channel with invalid token",
channel: cid,
token: wrongValue,
offset: offset,
limit: limit,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
response: nil,
},
{
desc: "get a list of things by channel with empty token",
channel: cid,
token: "",
offset: offset,
limit: limit,
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
response: nil,
},
{
desc: "get a list of things by channel with zero limit",
channel: cid,
token: token,
offset: offset,
limit: 0,
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
response: nil,
},
{
desc: "get a list of things by channel with limit greater than max",
channel: cid,
token: token,
offset: offset,
limit: 110,
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
response: nil,
},
{
desc: "get a list of things by channel with offset greater than max",
channel: cid,
token: token,
offset: 110,
limit: limit,
err: nil,
response: []sdk.Thing{},
},
{
desc: "get a list of things by channel with invalid args (zero limit) and invalid token",
channel: cid,
token: wrongValue,
offset: offset,
limit: 0,
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
response: nil,
},
{
desc: "get a list of not connected things by channel",
channel: cid,
token: token,
offset: offset,
limit: 100,
disconnected: true,
err: nil,
response: []sdk.Thing{things[n-thsDiscoNum]},
},
}
for _, tc := range cases {
page, err := mainfluxSDK.ThingsByChannel(tc.token, tc.channel, tc.offset, tc.limit, tc.disconnected)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.response, page.Things, fmt.Sprintf("%s: expected response channel %s, got %s", tc.desc, tc.response, page.Things))
}
}
func TestUpdateThing(t *testing.T) {
svc := newThingsService(map[string]string{token: email})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th1.Name = "test2"
cases := []struct {
desc string
thing sdk.Thing
token string
err error
}{
{
desc: "update existing thing",
thing: sdk.Thing{
ID: id,
Name: "test_app",
Metadata: metadata2,
},
token: token,
err: nil,
},
{
desc: "update non-existing thing",
thing: sdk.Thing{
ID: "0",
Name: "test_device",
Metadata: metadata,
},
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthorization, http.StatusForbidden),
},
{
desc: "update channel with an empty id",
thing: sdk.Thing{
ID: "",
Name: "test_device",
Metadata: metadata,
},
token: token,
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
},
{
desc: "update channel with invalid token",
thing: sdk.Thing{
ID: id,
Name: "test_app",
Metadata: metadata2,
},
token: wrongValue,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "update channel with empty token",
thing: sdk.Thing{
ID: id,
Name: "test_app",
Metadata: metadata2,
},
token: "",
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
},
}
for _, tc := range cases {
err := mainfluxSDK.UpdateThing(tc.thing, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
}
}
func TestDeleteThing(t *testing.T) {
svc := newThingsService(map[string]string{token: email})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
desc string
thingID string
token string
err error
}{
{
desc: "delete thing with invalid token",
thingID: id,
token: wrongValue,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "delete non-existing thing",
thingID: "2",
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
{
desc: "delete thing with invalid id",
thingID: "",
token: token,
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
},
{
desc: "delete thing with empty token",
thingID: id,
token: "",
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
},
{
desc: "delete existing thing",
thingID: id,
token: token,
err: nil,
},
{
desc: "delete deleted thing",
thingID: id,
token: token,
err: nil,
},
}
for _, tc := range cases {
err := mainfluxSDK.DeleteThing(tc.thingID, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
}
}
func TestIdentifyThing(t *testing.T) {
svc := newThingsService(map[string]string{token: email})
ts := newThingsServer(svc)
as := newAuthServer(svc)
defer ts.Close()
defer as.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
authSdkConf := sdk.Config{
ThingsURL: as.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
mainfluxAuthSDK := sdk.NewSDK(authSdkConf)
th := sdk.Thing{ID: "fe6b4e92-cc98-425e-b0aa-000000007891", Name: "identify"}
id, err := mainfluxSDK.CreateThing(th, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
thing, err := mainfluxSDK.Thing(th.ID, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
desc string
thingKey string
err error
response string
}{
{
desc: "identify thing with a valid key",
thingKey: thing.Key,
err: nil,
response: id,
},
{
desc: "identify thing with an invalid key",
thingKey: badKey,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
response: "",
},
{
desc: "identify thing with an empty key",
thingKey: "",
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerKey, http.StatusUnauthorized),
response: "",
},
}
for _, tc := range cases {
thingID, err := mainfluxAuthSDK.IdentifyThing(tc.thingKey)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.response, thingID, fmt.Sprintf("%s: expected response id %s, got %s", tc.desc, tc.response, thingID))
}
}
func TestConnectThing(t *testing.T) {
svc := newThingsService(map[string]string{
token: email,
otherToken: otherEmail,
})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
thingID, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID1, err := mainfluxSDK.CreateChannel(ch2, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID2, err := mainfluxSDK.CreateChannel(ch3, otherToken)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
desc string
thingID string
chanID string
token string
err error
}{
{
desc: "connect existing thing to existing channel",
thingID: thingID,
chanID: chanID1,
token: token,
err: nil,
},
{
desc: "connect existing thing to non-existing channel",
thingID: thingID,
chanID: "9",
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
{
desc: "connect non-existing thing to existing channel",
thingID: "9",
chanID: chanID1,
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
{
desc: "connect existing thing to channel with invalid ID",
thingID: thingID,
chanID: "",
token: token,
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
},
{
desc: "connect thing with missing ID to existing channel",
thingID: "",
chanID: chanID1,
token: token,
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
},
{
desc: "connect existing thing to existing channel with invalid token",
thingID: thingID,
chanID: chanID1,
token: wrongValue,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "connect existing thing to existing channel with empty token",
thingID: thingID,
chanID: chanID1,
token: "",
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
},
{
desc: "connect thing from owner to channel of other user",
thingID: thingID,
chanID: chanID2,
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
}
for _, tc := range cases {
conIDs := sdk.ConnectionIDs{
ChannelIDs: []string{tc.chanID},
ThingIDs: []string{tc.thingID},
}
err := mainfluxSDK.Connect(conIDs, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
}
}
func TestDisconnectThing(t *testing.T) {
svc := newThingsService(map[string]string{
token: email,
otherToken: otherEmail,
})
ts := newThingsServer(svc)
defer ts.Close()
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
TLSVerification: false,
}
mainfluxSDK := sdk.NewSDK(sdkConf)
thingID, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID1, err := mainfluxSDK.CreateChannel(ch2, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
conIDs := sdk.ConnectionIDs{
ChannelIDs: []string{chanID1},
ThingIDs: []string{thingID},
}
err = mainfluxSDK.Connect(conIDs, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID2, err := mainfluxSDK.CreateChannel(ch2, otherToken)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
desc string
thingID string
chanID string
token string
err error
}{
{
desc: "disconnect connected thing from channel",
thingID: thingID,
chanID: chanID1,
token: token,
err: nil,
},
{
desc: "disconnect existing thing from non-existing channel",
thingID: thingID,
chanID: "9",
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
{
desc: "disconnect non-existing thing from existing channel",
thingID: "9",
chanID: chanID1,
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
{
desc: "disconnect existing thing from channel with invalid ID",
thingID: thingID,
chanID: "",
token: token,
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
},
{
desc: "disconnect thing with invalid ID from existing channel",
thingID: "",
chanID: chanID1,
token: token,
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
},
{
desc: "disconnect existing thing from existing channel with invalid token",
thingID: thingID,
chanID: chanID1,
token: wrongValue,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "disconnect existing thing from existing channel with empty token",
thingID: thingID,
chanID: chanID1,
token: "",
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
},
{
desc: "disconnect owner's thing from someone elses channel",
thingID: thingID,
chanID: chanID2,
token: token,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
}
for _, tc := range cases {
err := mainfluxSDK.DisconnectThing(tc.thingID, tc.chanID, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
}
}