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 5e8555444a
MF-1723 - Fix lack of logging for invalid query params (#1724)
* fix error package errors

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

* fix bootstap and bootstrap api

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

* fix certs

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

* fix consumers

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

* fix http

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

* fix provision

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

* fix readers

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

* fix twins

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

* fix things

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

* fix users

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

* fix sdk excpet channel policies users things

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

* tests passing, but logging not working for things and users

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

* fix sdk tests, and other failing tests

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

* fix comment

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

* fix errors acc to pr review

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

* fix errror wrapping in consumers api

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

* all tests running

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

* fix encodeError

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

* fix minor issues

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

* fix failing sdk policy tests

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

* fix errors in things test sdk

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

* update things service

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

* update usrs service

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

* fix things and users sdk

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

* fix sdk for channels groups policies things users

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

* fix remaining services and sdk

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

* fix bootstrap twins

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

* resolve conflicts

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

* Shift errmalformedentity to pkg/errors

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

* Fix bootstrap service

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

* Add errors.Unwrap and use in encodeError

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

* Fix type in print statement for policies_test

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

* Fix ordering of errvalidation wrapping and encodeError

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

* Fix failing tests

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

---------

Signed-off-by: aryan <aryangodara03@gmail.com>
2023-08-09 23:02:44 +02:00

1455 lines
44 KiB
Go

package sdk_test
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/internal/testsutil"
mflog "github.com/mainflux/mainflux/logger"
mfclients "github.com/mainflux/mainflux/pkg/clients"
"github.com/mainflux/mainflux/pkg/errors"
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
"github.com/mainflux/mainflux/things/clients"
"github.com/mainflux/mainflux/things/clients/api"
"github.com/mainflux/mainflux/things/clients/mocks"
gmocks "github.com/mainflux/mainflux/things/groups/mocks"
"github.com/mainflux/mainflux/things/policies"
papi "github.com/mainflux/mainflux/things/policies/api/http"
pmocks "github.com/mainflux/mainflux/things/policies/mocks"
cmocks "github.com/mainflux/mainflux/users/clients/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var (
adminToken = "token"
userToken = "userToken"
adminID = generateUUID(&testing.T{})
userID = generateUUID(&testing.T{})
users = map[string]string{adminToken: adminID, userToken: userID}
adminRelationKeys = []string{"c_update", "c_list", "c_delete", "c_share"}
uadminPolicy = cmocks.SubjectSet{Subject: adminID, Relation: adminRelationKeys}
)
func newThingsServer(svc clients.Service, psvc policies.Service) *httptest.Server {
logger := mflog.NewMock()
mux := bone.New()
api.MakeHandler(svc, mux, logger, instanceID)
papi.MakeHandler(svc, psvc, mux, logger)
return httptest.NewServer(mux)
}
func TestCreateThing(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
thing := sdk.Thing{
Name: "test",
Status: mfclients.EnabledStatus.String(),
}
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
cases := []struct {
desc string
client sdk.Thing
response sdk.Thing
token string
repoErr error
err errors.SDKError
}{
{
desc: "register new thing",
client: thing,
response: thing,
token: token,
repoErr: nil,
err: nil,
},
{
desc: "register existing thing",
client: thing,
response: sdk.Thing{},
token: token,
repoErr: sdk.ErrFailedCreation,
err: errors.NewSDKErrorWithStatus(sdk.ErrFailedCreation, http.StatusInternalServerError),
},
{
desc: "register empty thing",
client: sdk.Thing{},
response: sdk.Thing{},
token: token,
repoErr: errors.ErrMalformedEntity,
err: errors.NewSDKErrorWithStatus(errors.ErrMalformedEntity, http.StatusBadRequest),
},
{
desc: "register a thing that can't be marshalled",
client: sdk.Thing{
Name: "test",
Metadata: map[string]interface{}{
"test": make(chan int),
},
},
response: sdk.Thing{},
token: token,
err: errors.NewSDKError(fmt.Errorf("json: unsupported type: chan int")),
repoErr: errors.NewSDKError(fmt.Errorf("json: unsupported type: chan int")),
},
{
desc: "register thing with empty secret",
client: sdk.Thing{
Name: "emptysecret",
Credentials: sdk.Credentials{
Secret: "",
},
},
response: sdk.Thing{
Name: "emptysecret",
Credentials: sdk.Credentials{
Secret: "",
},
},
token: token,
err: nil,
repoErr: nil,
},
{
desc: "register thing with empty identity",
client: sdk.Thing{
Credentials: sdk.Credentials{
Identity: "",
Secret: secret,
},
},
response: sdk.Thing{
Credentials: sdk.Credentials{
Identity: "",
Secret: secret,
},
},
token: token,
repoErr: nil,
err: nil,
},
{
desc: "register thing with every field defined",
client: sdk.Thing{
ID: id,
Name: "name",
Tags: []string{"tag1", "tag2"},
Owner: id,
Credentials: user.Credentials,
Metadata: validMetadata,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Status: mfclients.EnabledStatus.String(),
},
response: sdk.Thing{
ID: id,
Name: "name",
Tags: []string{"tag1", "tag2"},
Owner: id,
Credentials: user.Credentials,
Metadata: validMetadata,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Status: mfclients.EnabledStatus.String(),
},
token: token,
repoErr: nil,
err: nil,
},
}
for _, tc := range cases {
repoCall := cRepo.On("Save", mock.Anything, mock.Anything).Return(tc.response, tc.repoErr)
rThing, err := mfsdk.CreateThing(tc.client, tc.token)
tc.response.ID = rThing.ID
tc.response.Owner = rThing.Owner
tc.response.CreatedAt = rThing.CreatedAt
tc.response.UpdatedAt = rThing.UpdatedAt
rThing.Credentials.Secret = tc.response.Credentials.Secret
rThing.Status = tc.response.Status
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.response, rThing, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, rThing))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "Save", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("Save was not called on %s", tc.desc))
}
repoCall.Unset()
}
}
func TestCreateThings(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
things := []sdk.Thing{
{
Name: "test",
Status: mfclients.EnabledStatus.String(),
},
{
Name: "test2",
Status: mfclients.EnabledStatus.String(),
},
}
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
cases := []struct {
desc string
things []sdk.Thing
response []sdk.Thing
token string
err errors.SDKError
}{
{
desc: "register new things",
things: things,
response: things,
token: token,
err: nil,
},
{
desc: "register existing things",
things: things,
response: []sdk.Thing{},
token: token,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, sdk.ErrFailedCreation), http.StatusInternalServerError),
},
{
desc: "register empty things",
things: []sdk.Thing{},
response: []sdk.Thing{},
token: token,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrEmptyList), http.StatusBadRequest),
},
{
desc: "register things that can't be marshalled",
things: []sdk.Thing{
{
Name: "test",
Metadata: map[string]interface{}{
"test": make(chan int),
},
},
},
response: []sdk.Thing{},
token: token,
err: errors.NewSDKError(fmt.Errorf("json: unsupported type: chan int")),
},
}
for _, tc := range cases {
repoCall := cRepo.On("Save", mock.Anything, mock.Anything).Return(tc.response, tc.err)
rThing, err := mfsdk.CreateThings(tc.things, tc.token)
for i, t := range rThing {
tc.response[i].ID = t.ID
tc.response[i].Owner = t.Owner
tc.response[i].CreatedAt = t.CreatedAt
tc.response[i].UpdatedAt = t.UpdatedAt
tc.response[i].Credentials.Secret = t.Credentials.Secret
t.Status = tc.response[i].Status
}
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.response, rThing, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, rThing))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "Save", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("Save was not called on %s", tc.desc))
}
repoCall.Unset()
}
}
func TestListThings(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
var ths []sdk.Thing
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
owner := generateUUID(t)
for i := 10; i < 100; i++ {
th := sdk.Thing{
ID: generateUUID(t),
Name: fmt.Sprintf("thing_%d", i),
Credentials: sdk.Credentials{
Identity: fmt.Sprintf("identity_%d", i),
Secret: generateUUID(t),
},
Metadata: sdk.Metadata{"name": fmt.Sprintf("thing_%d", i)},
Status: mfclients.EnabledStatus.String(),
}
if i == 50 {
th.Owner = owner
th.Status = mfclients.DisabledStatus.String()
th.Tags = []string{"tag1", "tag2"}
}
ths = append(ths, th)
}
cases := []struct {
desc string
token string
status string
total uint64
offset uint64
limit uint64
name string
identifier string
ownerID string
tag string
metadata sdk.Metadata
err errors.SDKError
response []sdk.Thing
}{
{
desc: "get a list of things",
token: token,
limit: limit,
offset: offset,
total: total,
err: nil,
response: ths[offset:limit],
},
{
desc: "get a list of things with invalid token",
token: invalidToken,
offset: offset,
limit: limit,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, sdk.ErrFailedList), http.StatusInternalServerError),
response: nil,
},
{
desc: "get a list of things with empty token",
token: "",
offset: offset,
limit: limit,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, sdk.ErrFailedList), http.StatusInternalServerError),
response: nil,
},
{
desc: "get a list of things with zero limit",
token: token,
offset: offset,
limit: 0,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrLimitSize), http.StatusInternalServerError),
response: nil,
},
{
desc: "get a list of things with limit greater than max",
token: token,
offset: offset,
limit: 110,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrLimitSize), http.StatusInternalServerError),
response: []sdk.Thing(nil),
},
{
desc: "get a list of things with same identity",
token: token,
offset: 0,
limit: 1,
err: nil,
identifier: Identity,
metadata: sdk.Metadata{},
response: []sdk.Thing{ths[89]},
},
{
desc: "get a list of things with same identity and metadata",
token: token,
offset: 0,
limit: 1,
err: nil,
identifier: Identity,
metadata: sdk.Metadata{
"name": "client99",
},
response: []sdk.Thing{ths[89]},
},
{
desc: "list things with given metadata",
token: adminToken,
offset: 0,
limit: 1,
metadata: sdk.Metadata{
"name": "client99",
},
response: []sdk.Thing{ths[89]},
err: nil,
},
{
desc: "list things with given name",
token: adminToken,
offset: 0,
limit: 1,
name: "client10",
response: []sdk.Thing{ths[0]},
err: nil,
},
{
desc: "list things with given owner",
token: adminToken,
offset: 0,
limit: 1,
ownerID: owner,
response: []sdk.Thing{ths[50]},
err: nil,
},
{
desc: "list things with given status",
token: adminToken,
offset: 0,
limit: 1,
status: mfclients.DisabledStatus.String(),
response: []sdk.Thing{ths[50]},
err: nil,
},
{
desc: "list things with given tag",
token: adminToken,
offset: 0,
limit: 1,
tag: "tag1",
response: []sdk.Thing{ths[50]},
err: nil,
},
}
for _, tc := range cases {
pm := sdk.PageMetadata{
Status: tc.status,
Total: total,
Offset: tc.offset,
Limit: tc.limit,
Name: tc.name,
OwnerID: tc.ownerID,
Metadata: tc.metadata,
Tag: tc.tag,
}
repoCall := cRepo.On("RetrieveAll", mock.Anything, mock.Anything).Return(mfclients.ClientsPage{Page: convertClientPage(pm), Clients: convertThings(tc.response)}, tc.err)
page, err := mfsdk.Things(pm, adminToken)
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 %v got %v\n", tc.desc, tc.response, page))
repoCall.Unset()
}
}
func TestListThingsByChannel(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
var nThing = uint64(10)
var aThings = []sdk.Thing{}
for i := uint64(1); i < nThing; i++ {
thing := sdk.Thing{
Name: fmt.Sprintf("member_%d@example.com", i),
Credentials: sdk.Credentials{
Secret: generateUUID(t),
},
Tags: []string{"tag1", "tag2"},
Metadata: sdk.Metadata{"role": "client"},
Status: mfclients.EnabledStatus.String(),
}
aThings = append(aThings, thing)
}
cases := []struct {
desc string
token string
channelID string
page sdk.PageMetadata
response []sdk.Thing
err errors.SDKError
}{
{
desc: "list things with authorized token",
token: adminToken,
channelID: testsutil.GenerateUUID(t, idProvider),
page: sdk.PageMetadata{},
response: aThings,
err: nil,
},
{
desc: "list things with offset and limit",
token: adminToken,
channelID: testsutil.GenerateUUID(t, idProvider),
page: sdk.PageMetadata{
Offset: 4,
Limit: nThing,
},
response: aThings[4:],
err: nil,
},
{
desc: "list things with given name",
token: adminToken,
channelID: testsutil.GenerateUUID(t, idProvider),
page: sdk.PageMetadata{
Name: Identity,
Offset: 6,
Limit: nThing,
},
response: aThings[6:],
err: nil,
},
{
desc: "list things with given ownerID",
token: adminToken,
channelID: testsutil.GenerateUUID(t, idProvider),
page: sdk.PageMetadata{
OwnerID: user.Owner,
Offset: 6,
Limit: nThing,
},
response: aThings[6:],
err: nil,
},
{
desc: "list things with given subject",
token: adminToken,
channelID: testsutil.GenerateUUID(t, idProvider),
page: sdk.PageMetadata{
Subject: subject,
Offset: 6,
Limit: nThing,
},
response: aThings[6:],
err: nil,
},
{
desc: "list things with given object",
token: adminToken,
channelID: testsutil.GenerateUUID(t, idProvider),
page: sdk.PageMetadata{
Object: object,
Offset: 6,
Limit: nThing,
},
response: aThings[6:],
err: nil,
},
{
desc: "list things with an invalid token",
token: invalidToken,
channelID: testsutil.GenerateUUID(t, idProvider),
page: sdk.PageMetadata{},
response: []sdk.Thing(nil),
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "list things with an invalid id",
token: adminToken,
channelID: mocks.WrongID,
page: sdk.PageMetadata{},
response: []sdk.Thing(nil),
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
}
for _, tc := range cases {
repoCall := cRepo.On("Members", mock.Anything, tc.channelID, mock.Anything).Return(mfclients.MembersPage{Members: convertThings(tc.response)}, tc.err)
membersPage, err := mfsdk.ThingsByChannel(tc.channelID, tc.page, 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, membersPage.Things, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, membersPage.Things))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "Members", mock.Anything, tc.channelID, mock.Anything)
assert.True(t, ok, fmt.Sprintf("Members was not called on %s", tc.desc))
}
repoCall.Unset()
}
}
func TestThing(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
thing := sdk.Thing{
Name: "thingname",
Tags: []string{"tag1", "tag2"},
Credentials: sdk.Credentials{Identity: "clientidentity", Secret: generateUUID(t)},
Metadata: validMetadata,
Status: mfclients.EnabledStatus.String(),
}
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
cases := []struct {
desc string
token string
thingID string
response sdk.Thing
err errors.SDKError
}{
{
desc: "view thing successfully",
response: thing,
token: adminToken,
thingID: generateUUID(t),
err: nil,
},
{
desc: "view thing with an invalid token",
response: sdk.Thing{},
token: invalidToken,
thingID: generateUUID(t),
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "view thing with valid token and invalid thing id",
response: sdk.Thing{},
token: adminToken,
thingID: mocks.WrongID,
err: errors.NewSDKErrorWithStatus(errors.ErrNotFound, http.StatusNotFound),
},
{
desc: "view thing with an invalid token and invalid thing id",
response: sdk.Thing{},
token: invalidToken,
thingID: mocks.WrongID,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
}
for _, tc := range cases {
repoCall := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
repoCall1 := cRepo.On("RetrieveByID", mock.Anything, tc.thingID).Return(convertThing(tc.response), tc.err)
rClient, err := mfsdk.Thing(tc.thingID, 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, rClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, rClient))
if tc.err == nil {
ok := repoCall1.Parent.AssertCalled(t, "RetrieveByID", mock.Anything, tc.thingID)
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
}
repoCall1.Unset()
repoCall.Unset()
}
}
func TestUpdateThing(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
thing := sdk.Thing{
ID: generateUUID(t),
Name: "clientname",
Credentials: sdk.Credentials{Secret: generateUUID(t)},
Metadata: validMetadata,
Status: mfclients.EnabledStatus.String(),
}
thing1 := thing
thing1.Name = "Updated client"
thing2 := thing
thing2.Metadata = sdk.Metadata{"role": "test"}
thing2.ID = invalidIdentity
cases := []struct {
desc string
thing sdk.Thing
response sdk.Thing
token string
err errors.SDKError
}{
{
desc: "update thing name with valid token",
thing: thing1,
response: thing1,
token: adminToken,
err: nil,
},
{
desc: "update thing name with invalid token",
thing: thing1,
response: sdk.Thing{},
token: invalidToken,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "update thing name with invalid id",
thing: thing2,
response: sdk.Thing{},
token: adminToken,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, sdk.ErrFailedUpdate), http.StatusInternalServerError),
},
{
desc: "update thing that can't be marshalled",
thing: sdk.Thing{
Name: "test",
Metadata: map[string]interface{}{
"test": make(chan int),
},
},
response: sdk.Thing{},
token: token,
err: errors.NewSDKError(fmt.Errorf("json: unsupported type: chan int")),
},
}
for _, tc := range cases {
repoCall := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
repoCall1 := cRepo.On("Update", mock.Anything, mock.Anything).Return(convertThing(tc.response), tc.err)
uClient, err := mfsdk.UpdateThing(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.response, uClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, uClient))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "EvaluateThingAccess", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("EvaluateThingAccess was not called on %s", tc.desc))
ok = repoCall1.Parent.AssertCalled(t, "Update", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("Update was not called on %s", tc.desc))
}
repoCall.Unset()
repoCall1.Unset()
}
}
func TestUpdateThingTags(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
thing := sdk.Thing{
ID: generateUUID(t),
Name: "clientname",
Tags: []string{"tag1", "tag2"},
Credentials: sdk.Credentials{Secret: generateUUID(t)},
Status: mfclients.EnabledStatus.String(),
}
thing1 := thing
thing1.Tags = []string{"updatedTag1", "updatedTag2"}
thing2 := thing
thing2.ID = invalidIdentity
cases := []struct {
desc string
thing sdk.Thing
response sdk.Thing
token string
err error
}{
{
desc: "update thing name with valid token",
thing: thing,
response: thing1,
token: adminToken,
err: nil,
},
{
desc: "update thing name with invalid token",
thing: thing1,
response: sdk.Thing{},
token: invalidToken,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "update thing name with invalid id",
thing: thing2,
response: sdk.Thing{},
token: adminToken,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, sdk.ErrFailedUpdate), http.StatusInternalServerError),
},
{
desc: "update thing that can't be marshalled",
thing: sdk.Thing{
Name: "test",
Metadata: map[string]interface{}{
"test": make(chan int),
},
},
response: sdk.Thing{},
token: token,
err: errors.NewSDKError(fmt.Errorf("json: unsupported type: chan int")),
},
}
for _, tc := range cases {
repoCall := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
repoCall1 := cRepo.On("UpdateTags", mock.Anything, mock.Anything).Return(convertThing(tc.response), tc.err)
uClient, err := mfsdk.UpdateThingTags(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.response, uClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, uClient))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "EvaluateThingAccess", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("EvaluateThingAccess was not called on %s", tc.desc))
ok = repoCall1.Parent.AssertCalled(t, "UpdateTags", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("UpdateTags was not called on %s", tc.desc))
}
repoCall.Unset()
repoCall1.Unset()
}
}
func TestUpdateThingSecret(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
user.ID = generateUUID(t)
rthing := thing
rthing.Credentials.Secret, _ = phasher.Hash(user.Credentials.Secret)
cases := []struct {
desc string
oldSecret string
newSecret string
token string
response sdk.Thing
repoErr error
err error
}{
{
desc: "update thing secret with valid token",
oldSecret: thing.Credentials.Secret,
newSecret: "newSecret",
token: adminToken,
response: rthing,
repoErr: nil,
err: nil,
},
{
desc: "update thing secret with invalid token",
oldSecret: thing.Credentials.Secret,
newSecret: "newPassword",
token: "non-existent",
response: sdk.Thing{},
repoErr: errors.ErrAuthorization,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "update thing secret with wrong old secret",
oldSecret: "oldSecret",
newSecret: "newSecret",
token: adminToken,
response: sdk.Thing{},
repoErr: apiutil.ErrInvalidSecret,
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidSecret, http.StatusBadRequest),
},
}
for _, tc := range cases {
repoCall := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
repoCall1 := cRepo.On("UpdateSecret", mock.Anything, mock.Anything).Return(convertThing(tc.response), tc.repoErr)
uClient, err := mfsdk.UpdateThingSecret(tc.oldSecret, tc.newSecret, 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, uClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, uClient))
if tc.err == nil {
ok := repoCall1.Parent.AssertCalled(t, "UpdateSecret", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("UpdateSecret was not called on %s", tc.desc))
}
repoCall.Unset()
repoCall1.Unset()
}
}
func TestUpdateThingOwner(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
thing = sdk.Thing{
ID: generateUUID(t),
Name: "clientname",
Tags: []string{"tag1", "tag2"},
Credentials: sdk.Credentials{Identity: "clientidentity", Secret: generateUUID(t)},
Metadata: validMetadata,
Status: mfclients.EnabledStatus.String(),
Owner: "owner",
}
thing2 := thing
thing2.ID = invalidIdentity
cases := []struct {
desc string
thing sdk.Thing
response sdk.Thing
token string
err errors.SDKError
}{
{
desc: "update thing name with valid token",
thing: thing,
response: thing,
token: adminToken,
err: nil,
},
{
desc: "update thing name with invalid token",
thing: thing2,
response: sdk.Thing{},
token: invalidToken,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
{
desc: "update thing name with invalid id",
thing: thing2,
response: sdk.Thing{},
token: adminToken,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, sdk.ErrFailedUpdate), http.StatusInternalServerError),
},
{
desc: "update thing that can't be marshalled",
thing: sdk.Thing{
Name: "test",
Metadata: map[string]interface{}{
"test": make(chan int),
},
},
response: sdk.Thing{},
token: token,
err: errors.NewSDKError(fmt.Errorf("json: unsupported type: chan int")),
},
}
for _, tc := range cases {
repoCall := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
repoCall1 := cRepo.On("UpdateOwner", mock.Anything, mock.Anything).Return(convertThing(tc.response), tc.err)
uClient, err := mfsdk.UpdateThingOwner(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.response, uClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, uClient))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "EvaluateThingAccess", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("EvaluateThingAccess was not called on %s", tc.desc))
ok = repoCall1.Parent.AssertCalled(t, "UpdateOwner", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("UpdateOwner was not called on %s", tc.desc))
}
repoCall.Unset()
repoCall1.Unset()
}
}
func TestEnableThing(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
enabledThing1 := sdk.Thing{ID: testsutil.GenerateUUID(t, idProvider), Credentials: sdk.Credentials{Identity: "client1@example.com", Secret: generateUUID(t)}, Status: mfclients.EnabledStatus.String()}
disabledThing1 := sdk.Thing{ID: testsutil.GenerateUUID(t, idProvider), Credentials: sdk.Credentials{Identity: "client3@example.com", Secret: generateUUID(t)}, Status: mfclients.DisabledStatus.String()}
endisabledThing1 := disabledThing1
endisabledThing1.Status = mfclients.EnabledStatus.String()
endisabledThing1.ID = testsutil.GenerateUUID(t, idProvider)
cases := []struct {
desc string
id string
token string
thing sdk.Thing
response sdk.Thing
repoErr error
err errors.SDKError
}{
{
desc: "enable disabled thing",
id: disabledThing1.ID,
token: adminToken,
thing: disabledThing1,
response: endisabledThing1,
repoErr: nil,
err: nil,
},
{
desc: "enable enabled thing",
id: enabledThing1.ID,
token: adminToken,
thing: enabledThing1,
response: sdk.Thing{},
repoErr: sdk.ErrFailedEnable,
err: errors.NewSDKErrorWithStatus(errors.Wrap(sdk.ErrFailedEnable, sdk.ErrFailedEnable), http.StatusInternalServerError),
},
{
desc: "enable non-existing thing",
id: mocks.WrongID,
token: adminToken,
thing: sdk.Thing{},
response: sdk.Thing{},
repoErr: sdk.ErrFailedEnable,
err: errors.NewSDKErrorWithStatus(errors.Wrap(sdk.ErrFailedEnable, errors.ErrNotFound), http.StatusNotFound),
},
}
for _, tc := range cases {
repoCall := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
repoCall1 := cRepo.On("RetrieveByID", mock.Anything, tc.id).Return(convertThing(tc.thing), tc.repoErr)
repoCall2 := cRepo.On("ChangeStatus", mock.Anything, mock.Anything).Return(convertThing(tc.response), tc.repoErr)
eClient, err := mfsdk.EnableThing(tc.id, 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, eClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, eClient))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "EvaluateThingAccess", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("EvaluateThingAccess was not called on %s", tc.desc))
ok = repoCall1.Parent.AssertCalled(t, "RetrieveByID", mock.Anything, tc.id)
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
ok = repoCall2.Parent.AssertCalled(t, "ChangeStatus", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("ChangeStatus was not called on %s", tc.desc))
}
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
}
cases2 := []struct {
desc string
token string
status string
metadata sdk.Metadata
response sdk.ThingsPage
size uint64
}{
{
desc: "list enabled clients",
status: mfclients.EnabledStatus.String(),
size: 2,
response: sdk.ThingsPage{
Things: []sdk.Thing{enabledThing1, endisabledThing1},
},
},
{
desc: "list disabled clients",
status: mfclients.DisabledStatus.String(),
size: 1,
response: sdk.ThingsPage{
Things: []sdk.Thing{disabledThing1},
},
},
{
desc: "list enabled and disabled clients",
status: mfclients.AllStatus.String(),
size: 3,
response: sdk.ThingsPage{
Things: []sdk.Thing{enabledThing1, disabledThing1, endisabledThing1},
},
},
}
for _, tc := range cases2 {
pm := sdk.PageMetadata{
Total: 100,
Offset: 0,
Limit: 100,
Status: tc.status,
}
repoCall := pRepo.On("CheckAdmin", mock.Anything, mock.Anything).Return(nil)
repoCall1 := cRepo.On("RetrieveAll", mock.Anything, mock.Anything).Return(convertThingsPage(tc.response), nil)
clientsPage, err := mfsdk.Things(pm, adminToken)
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
size := uint64(len(clientsPage.Things))
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestDisableThing(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
enabledThing1 := sdk.Thing{ID: testsutil.GenerateUUID(t, idProvider), Credentials: sdk.Credentials{Identity: "client1@example.com", Secret: generateUUID(t)}, Status: mfclients.EnabledStatus.String()}
disabledThing1 := sdk.Thing{ID: testsutil.GenerateUUID(t, idProvider), Credentials: sdk.Credentials{Identity: "client3@example.com", Secret: generateUUID(t)}, Status: mfclients.DisabledStatus.String()}
disenabledThing1 := enabledThing1
disenabledThing1.Status = mfclients.DisabledStatus.String()
disenabledThing1.ID = testsutil.GenerateUUID(t, idProvider)
cases := []struct {
desc string
id string
token string
thing sdk.Thing
response sdk.Thing
repoErr error
err errors.SDKError
}{
{
desc: "disable enabled thing",
id: enabledThing1.ID,
token: adminToken,
thing: enabledThing1,
response: disenabledThing1,
repoErr: nil,
err: nil,
},
{
desc: "disable disabled thing",
id: disabledThing1.ID,
token: adminToken,
thing: disabledThing1,
response: sdk.Thing{},
repoErr: sdk.ErrFailedDisable,
err: errors.NewSDKErrorWithStatus(errors.Wrap(sdk.ErrFailedDisable, sdk.ErrFailedDisable), http.StatusInternalServerError),
},
{
desc: "disable non-existing thing",
id: mocks.WrongID,
thing: sdk.Thing{},
token: adminToken,
response: sdk.Thing{},
repoErr: sdk.ErrFailedDisable,
err: errors.NewSDKErrorWithStatus(errors.Wrap(sdk.ErrFailedDisable, errors.ErrNotFound), http.StatusNotFound),
},
}
for _, tc := range cases {
repoCall := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
repoCall1 := cRepo.On("RetrieveByID", mock.Anything, tc.id).Return(convertThing(tc.thing), tc.repoErr)
repoCall2 := cRepo.On("ChangeStatus", mock.Anything, mock.Anything).Return(convertThing(tc.response), tc.repoErr)
dThing, err := mfsdk.DisableThing(tc.id, 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, dThing, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, dThing))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "EvaluateThingAccess", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("EvaluateThingAccess was not called on %s", tc.desc))
ok = repoCall1.Parent.AssertCalled(t, "RetrieveByID", mock.Anything, tc.id)
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
ok = repoCall2.Parent.AssertCalled(t, "ChangeStatus", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("ChangeStatus was not called on %s", tc.desc))
}
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
}
cases2 := []struct {
desc string
token string
status string
metadata sdk.Metadata
response sdk.ThingsPage
size uint64
}{
{
desc: "list enabled things",
status: mfclients.EnabledStatus.String(),
size: 2,
response: sdk.ThingsPage{
Things: []sdk.Thing{enabledThing1, disenabledThing1},
},
},
{
desc: "list disabled things",
status: mfclients.DisabledStatus.String(),
size: 1,
response: sdk.ThingsPage{
Things: []sdk.Thing{disabledThing1},
},
},
{
desc: "list enabled and disabled things",
status: mfclients.AllStatus.String(),
size: 3,
response: sdk.ThingsPage{
Things: []sdk.Thing{enabledThing1, disabledThing1, disenabledThing1},
},
},
}
for _, tc := range cases2 {
pm := sdk.PageMetadata{
Total: 100,
Offset: 0,
Limit: 100,
Status: tc.status,
}
repoCall := pRepo.On("CheckAdmin", mock.Anything, mock.Anything).Return(nil)
repoCall1 := cRepo.On("RetrieveAll", mock.Anything, mock.Anything).Return(convertThingsPage(tc.response), nil)
page, err := mfsdk.Things(pm, adminToken)
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
size := uint64(len(page.Things))
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestIdentify(t *testing.T) {
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {uadminPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
thing = sdk.Thing{
ID: generateUUID(t),
Name: "clientname",
Credentials: sdk.Credentials{Identity: "clientidentity", Secret: generateUUID(t)},
Status: mfclients.EnabledStatus.String(),
}
cases := []struct {
desc string
secret string
response string
repoErr error
err errors.SDKError
}{
{
desc: "identify thing successfully",
response: thing.ID,
secret: thing.Credentials.Secret,
repoErr: nil,
err: nil,
},
{
desc: "identify thing with an invalid token",
response: "",
secret: invalidToken,
repoErr: errors.ErrAuthentication,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthentication, http.StatusUnauthorized),
},
}
for _, tc := range cases {
repoCall := cRepo.On("RetrieveBySecret", mock.Anything, mock.Anything).Return(convertThing(thing), tc.repoErr)
id, err := mfsdk.IdentifyThing(tc.secret)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.response, id, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, id))
if tc.err == nil {
ok := repoCall.Parent.AssertCalled(t, "RetrieveBySecret", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("RetrieveBySecret was not called on %s", tc.desc))
}
repoCall.Unset()
}
}
func TestShareThing(t *testing.T) {
thingID := generateUUID(t)
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
aPolicy := cmocks.SubjectSet{Subject: "things", Relation: []string{"g_add", "c_share"}}
uPolicy := cmocks.SubjectSet{Subject: thingID, Relation: []string{"g_add"}}
uauth := cmocks.NewAuthService(users, map[string][]cmocks.SubjectSet{adminID: {aPolicy}, userID: {uPolicy}})
thingCache := mocks.NewCache()
policiesCache := pmocks.NewCache()
pRepo := new(pmocks.Repository)
psvc := policies.NewService(uauth, pRepo, policiesCache, idProvider)
svc := clients.NewService(uauth, psvc, cRepo, gRepo, thingCache, idProvider)
ts := newThingsServer(svc, psvc)
defer ts.Close()
conf := sdk.Config{
ThingsURL: ts.URL,
}
mfsdk := sdk.NewSDK(conf)
cases := []struct {
desc string
channelID string
thingID string
token string
err errors.SDKError
repoErr error
}{
{
desc: "share thing with valid token",
channelID: generateUUID(t),
thingID: thingID,
token: adminToken,
err: nil,
},
{
desc: "share thing with invalid token",
channelID: generateUUID(t),
thingID: thingID,
token: invalidToken,
err: errors.NewSDKErrorWithStatus(errors.Wrap(errors.ErrAuthorization, errors.ErrAuthentication), http.StatusUnauthorized),
},
{
desc: "share thing with valid token for unauthorized user",
channelID: generateUUID(t),
thingID: thingID,
token: userToken,
err: errors.NewSDKErrorWithStatus(errors.ErrAuthorization, http.StatusForbidden),
repoErr: errors.ErrAuthorization,
},
}
for _, tc := range cases {
repoCall := pRepo.On("EvaluateGroupAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, tc.repoErr)
repoCall1 := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, tc.repoErr)
repoCall2 := pRepo.On("Retrieve", mock.Anything, mock.Anything).Return(policies.PolicyPage{}, nil)
repoCall3 := pRepo.On("Save", mock.Anything, mock.Anything).Return(policies.Policy{}, nil)
err := mfsdk.ShareThing(tc.channelID, tc.thingID, []string{"c_list", "c_delete"}, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
if tc.err == nil {
ok := repoCall3.Parent.AssertCalled(t, "Save", mock.Anything, mock.Anything)
assert.True(t, ok, fmt.Sprintf("Save was not called on %s", tc.desc))
}
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
}
}