mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-27 13:48:49 +08:00

* MF-1425 - Rebase mainflux master to resolve conflicts MF-1425 Enhancement to supply an external UUID for Things and Channels. Resolve conflicts. Signed-off-by: Q.s <wangqs_eclipse@yahoo.com> * MF-1425 - Test cases changes for SDK MF-1425 Enhancement to supply an external UUID for Things and Channels. These are the new testcases added for - Things Service Testcases - SDK Things and Channel Testcases Signed-off-by: Anand Sivaram Palassery <aspnair@gmail.com> Signed-off-by: Q.s <wangqs_eclipse@yahoo.com> * MF-1425 - Fixing Testcases MF-1425 Enhancement to supply an external UUID for Things and Channels. Because of the previous commits, the testcases were getting failed because the way ID was modified. This change is to make sure that all testcases are revisited to get them fixed. Signed-off-by: Anand Sivaram Palassery <aspnair@gmail.com> Signed-off-by: Q.s <wangqs_eclipse@yahoo.com> * MF-1425 - Fixing review comments Fixing the review comments provided. Signed-off-by: Anand Sivaram Palassery <aspnair@gmail.com> Signed-off-by: Q.s <wangqs_eclipse@yahoo.com> * MF-1425 - Fixing more review comments Signed-off-by: Anand Sivaram Palassery <aspnair@gmail.com> Signed-off-by: Q.s <wangqs_eclipse@yahoo.com> * MF-1425 - Fixing conflicts MF-1425 Enhancement to supply an external UUID for Things and Channels. Fixing the conflicts between aspnair master, and the mainflux master. Signed-off-by: Q.s <wangqs_eclipse@yahoo.com> * MF-1425 Fix the comment and code format per review comments MF-1425 Enhancement to supply an external UUID for Things and Channels. 1. Remove un-valued comment for a private function 2. Format the code for better readibility Signed-off-by: Q.S. Wang <wangqs_eclipse@yahoo.com> * MF-1425 Enhancement to supply an external UUID for Things and Channels. Fix the format of the API document Signed-off-by: Q.S. Wang <wangqs_eclipse@yahoo.com> * MF-1425 Enhancement to supply an external UUID for Things and Channels. Rename the variable to make it readible. Signed-off-by: Q.s <wangqs_eclipse@yahoo.com> Co-authored-by: Anand Sivaram Palassery <aspnair@gmail.com> Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
1413 lines
34 KiB
Go
1413 lines
34 KiB
Go
// Copyright (c) Mainflux
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package things_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/mainflux/mainflux/pkg/errors"
|
|
"github.com/mainflux/mainflux/pkg/uuid"
|
|
"github.com/mainflux/mainflux/things"
|
|
"github.com/mainflux/mainflux/things/mocks"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
const (
|
|
wrongID = ""
|
|
wrongValue = "wrong-value"
|
|
adminEmail = "admin@example.com"
|
|
email = "user@example.com"
|
|
email2 = "user2@example.com"
|
|
token = "token"
|
|
token2 = "token2"
|
|
n = uint64(10)
|
|
prefix = "fe6b4e92-cc98-425e-b0aa-"
|
|
)
|
|
|
|
var (
|
|
thing = things.Thing{Name: "test"}
|
|
thingList = [n]things.Thing{}
|
|
channel = things.Channel{Name: "test"}
|
|
thsExtID = []things.Thing{{ID: prefix + "000000000001", Name: "a"}, {ID: prefix + "000000000002", Name: "b"}}
|
|
chsExtID = []things.Channel{{ID: prefix + "000000000001", Name: "a"}, {ID: prefix + "000000000002", Name: "b"}}
|
|
)
|
|
|
|
func newService(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 TestInit(t *testing.T) {
|
|
for i := uint64(0); i < n; i++ {
|
|
thingList[i].Name = fmt.Sprintf("name-%d", i+1)
|
|
thingList[i].ID = fmt.Sprintf("%s%012d", prefix, i+1)
|
|
thingList[i].Key = fmt.Sprintf("%s1%011d", prefix, i+1)
|
|
}
|
|
}
|
|
|
|
func TestCreateThings(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
cases := []struct {
|
|
desc string
|
|
things []things.Thing
|
|
token string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "create new things",
|
|
things: []things.Thing{{Name: "a"}, {Name: "b"}, {Name: "c"}, {Name: "d"}},
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "create thing with wrong credentials",
|
|
things: []things.Thing{{Name: "e"}},
|
|
token: wrongValue,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "create new things with external UUID",
|
|
things: thsExtID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "create new things with external wrong UUID",
|
|
things: []things.Thing{{ID: "b0aa-000000000001", Name: "a"}, {ID: "b0aa-000000000002", Name: "b"}},
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
_, err := svc.CreateThings(context.Background(), tc.token, tc.things...)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestUpdateThing(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
th := ths[0]
|
|
other := things.Thing{ID: wrongID, Key: "x"}
|
|
|
|
cases := []struct {
|
|
desc string
|
|
thing things.Thing
|
|
token string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "update existing thing",
|
|
thing: th,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update thing with wrong credentials",
|
|
thing: th,
|
|
token: wrongValue,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "update non-existing thing",
|
|
thing: other,
|
|
token: token,
|
|
err: things.ErrAuthorization,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := svc.UpdateThing(context.Background(), tc.token, tc.thing)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestUpdateKey(t *testing.T) {
|
|
key := "new-key"
|
|
svc := newService(map[string]string{token: email})
|
|
ths, err := svc.CreateThings(context.Background(), token, thing)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
th := ths[0]
|
|
|
|
cases := []struct {
|
|
desc string
|
|
token string
|
|
id string
|
|
key string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "update key of an existing thing",
|
|
token: token,
|
|
id: th.ID,
|
|
key: key,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update key with invalid credentials",
|
|
token: wrongValue,
|
|
id: th.ID,
|
|
key: key,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "update key of non-existing thing",
|
|
token: token,
|
|
id: wrongID,
|
|
key: wrongValue,
|
|
err: things.ErrAuthorization,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := svc.UpdateKey(context.Background(), tc.token, tc.id, tc.key)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestShareThing(t *testing.T) {
|
|
svc := newService(map[string]string{token: email, token2: email2})
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
th := ths[0]
|
|
policies := []string{"read"}
|
|
|
|
cases := []struct {
|
|
desc string
|
|
token string
|
|
thingID string
|
|
policies []string
|
|
userIDs []string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "share a thing with a valid user",
|
|
token: token,
|
|
thingID: th.ID,
|
|
policies: policies,
|
|
userIDs: []string{email2},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "share a thing via unauthorized access",
|
|
token: token2,
|
|
thingID: th.ID,
|
|
policies: policies,
|
|
userIDs: []string{email2},
|
|
err: things.ErrAuthorization,
|
|
},
|
|
{
|
|
desc: "share a thing with invalid token",
|
|
token: wrongValue,
|
|
thingID: th.ID,
|
|
policies: policies,
|
|
userIDs: []string{email2},
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "share a thing with partially invalid policies",
|
|
token: token,
|
|
thingID: th.ID,
|
|
policies: []string{"", "read"},
|
|
userIDs: []string{email2},
|
|
err: fmt.Errorf("cannot claim ownership on object '%s' by user '%s': %s", th.ID, email2, things.ErrMalformedEntity),
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := svc.ShareThing(context.Background(), tc.token, tc.thingID, tc.policies, tc.userIDs)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
|
|
}
|
|
|
|
func TestViewThing(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
th := ths[0]
|
|
|
|
cases := map[string]struct {
|
|
id string
|
|
token string
|
|
err error
|
|
}{
|
|
"view existing thing": {
|
|
id: th.ID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
"view thing with wrong credentials": {
|
|
id: th.ID,
|
|
token: wrongValue,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
"view non-existing thing": {
|
|
id: wrongID,
|
|
token: token,
|
|
err: things.ErrAuthorization,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
_, err := svc.ViewThing(context.Background(), tc.token, tc.id)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestListThings(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
m := make(map[string]interface{})
|
|
m["serial"] = "123456"
|
|
thingList[0].Metadata = m
|
|
|
|
var ths []things.Thing
|
|
for i := uint64(0); i < n; i++ {
|
|
th := thingList[i]
|
|
ths = append(ths, th)
|
|
}
|
|
|
|
_, err := svc.CreateThings(context.Background(), token, ths...)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
|
|
|
cases := map[string]struct {
|
|
token string
|
|
pageMetadata things.PageMetadata
|
|
size uint64
|
|
err error
|
|
}{
|
|
"list all things": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
"list half": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n / 2,
|
|
Limit: n,
|
|
},
|
|
size: n / 2,
|
|
err: nil,
|
|
},
|
|
"list last thing": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n - 1,
|
|
Limit: n,
|
|
},
|
|
size: 1,
|
|
err: nil,
|
|
},
|
|
"list empty set": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n + 1,
|
|
Limit: n,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list with zero limit": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 1,
|
|
Limit: 0,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list with wrong credentials": {
|
|
token: wrongValue,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: 0,
|
|
},
|
|
size: 0,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
"list with metadata": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Metadata: m,
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
"list all things sorted by name ascendent": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Order: "name",
|
|
Dir: "asc",
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
"list all things sorted by name descendent": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Order: "name",
|
|
Dir: "desc",
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
page, err := svc.ListThings(context.Background(), tc.token, tc.pageMetadata)
|
|
size := uint64(len(page.Things))
|
|
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected %d got %d\n", desc, tc.size, size))
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
|
|
// Check if Things list have been sorted properly
|
|
testSortThings(t, tc.pageMetadata, page.Things)
|
|
}
|
|
}
|
|
|
|
func TestListThingsByChannel(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
|
ch := chs[0]
|
|
|
|
thsDisconNum := uint64(4)
|
|
|
|
var ths []things.Thing
|
|
for i := uint64(0); i < n; i++ {
|
|
th := thingList[i]
|
|
ths = append(ths, th)
|
|
}
|
|
|
|
thsc, err := svc.CreateThings(context.Background(), token, ths...)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
|
|
|
var thIDs []string
|
|
for _, thID := range thsc {
|
|
thIDs = append(thIDs, thID.ID)
|
|
}
|
|
chIDs := []string{chs[0].ID}
|
|
|
|
err = svc.Connect(context.Background(), token, chIDs, thIDs[0:n-thsDisconNum])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
|
|
// Wait for things and channels to connect
|
|
time.Sleep(time.Second)
|
|
|
|
cases := map[string]struct {
|
|
token string
|
|
chID string
|
|
pageMetadata things.PageMetadata
|
|
size uint64
|
|
err error
|
|
}{
|
|
"list all things by existing channel": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
},
|
|
size: n - thsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list half of things by existing channel": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n / 2,
|
|
Limit: n,
|
|
},
|
|
size: (n / 2) - thsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list last thing by existing channel": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n - 1 - thsDisconNum,
|
|
Limit: n,
|
|
},
|
|
size: 1,
|
|
err: nil,
|
|
},
|
|
"list empty set of things by existing channel": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n + 1,
|
|
Limit: n,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list things by existing channel with zero limit": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 1,
|
|
Limit: 0,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list things by existing channel with wrong credentials": {
|
|
token: wrongValue,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: 0,
|
|
},
|
|
size: 0,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
"list things by non-existent channel with wrong credentials": {
|
|
token: token,
|
|
chID: "non-existent",
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list all non connected things by existing channel": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Disconnected: true,
|
|
},
|
|
size: thsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list all things by channel sorted by name ascendent": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Order: "name",
|
|
Dir: "asc",
|
|
},
|
|
size: n - thsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list all non-connected things by channel sorted by name ascendent": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Disconnected: true,
|
|
Order: "name",
|
|
Dir: "asc",
|
|
},
|
|
size: thsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list all things by channel sorted by name descendent": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Order: "name",
|
|
Dir: "desc",
|
|
},
|
|
size: n - thsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list all non-connected things by channel sorted by name descendent": {
|
|
token: token,
|
|
chID: ch.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Disconnected: true,
|
|
Order: "name",
|
|
Dir: "desc",
|
|
},
|
|
size: thsDisconNum,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
page, err := svc.ListThingsByChannel(context.Background(), tc.token, tc.chID, tc.pageMetadata)
|
|
size := uint64(len(page.Things))
|
|
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected %d got %d\n", desc, tc.size, size))
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
|
|
// Check if Things by Channel list have been sorted properly
|
|
testSortThings(t, tc.pageMetadata, page.Things)
|
|
}
|
|
}
|
|
|
|
func TestRemoveThing(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
sth := ths[0]
|
|
|
|
cases := []struct {
|
|
desc string
|
|
id string
|
|
token string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "remove thing with wrong credentials",
|
|
id: sth.ID,
|
|
token: wrongValue,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "remove existing thing",
|
|
id: sth.ID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove removed thing",
|
|
id: sth.ID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove non-existing thing",
|
|
id: wrongID,
|
|
token: token,
|
|
err: things.ErrAuthorization,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := svc.RemoveThing(context.Background(), tc.token, tc.id)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestCreateChannels(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
cases := []struct {
|
|
desc string
|
|
channels []things.Channel
|
|
token string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "create new channels",
|
|
channels: []things.Channel{{Name: "a"}, {Name: "b"}, {Name: "c"}, {Name: "d"}},
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "create channel with wrong credentials",
|
|
channels: []things.Channel{{Name: "e"}},
|
|
token: wrongValue,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "create new channels with external UUID",
|
|
channels: chsExtID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "create new channels with invalid external UUID",
|
|
channels: []things.Channel{{ID: "b0aa-000000000001", Name: "a"}, {ID: "b0aa-000000000002", Name: "b"}},
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, cc := range cases {
|
|
_, err := svc.CreateChannels(context.Background(), cc.token, cc.channels...)
|
|
assert.True(t, errors.Contains(err, cc.err), fmt.Sprintf("%s: expected %s got %s\n", cc.desc, cc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestUpdateChannel(t *testing.T) {
|
|
svc := newService(map[string]string{token: adminEmail})
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
ch := chs[0]
|
|
other := things.Channel{ID: wrongID}
|
|
|
|
cases := []struct {
|
|
desc string
|
|
channel things.Channel
|
|
token string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "update existing channel",
|
|
channel: ch,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update channel with wrong credentials",
|
|
channel: ch,
|
|
token: wrongValue,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "update non-existing channel",
|
|
channel: other,
|
|
token: token,
|
|
err: things.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := svc.UpdateChannel(context.Background(), tc.token, tc.channel)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestViewChannel(t *testing.T) {
|
|
svc := newService(map[string]string{token: adminEmail})
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
ch := chs[0]
|
|
|
|
cases := map[string]struct {
|
|
id string
|
|
token string
|
|
err error
|
|
metadata things.Metadata
|
|
}{
|
|
"view existing channel": {
|
|
id: ch.ID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
"view channel with wrong credentials": {
|
|
id: ch.ID,
|
|
token: wrongValue,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
"view non-existing channel": {
|
|
id: wrongID,
|
|
token: token,
|
|
err: things.ErrNotFound,
|
|
},
|
|
"view channel with metadata": {
|
|
id: wrongID,
|
|
token: token,
|
|
err: things.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
_, err := svc.ViewChannel(context.Background(), tc.token, tc.id)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestListChannels(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
meta := things.Metadata{}
|
|
meta["name"] = "test-channel"
|
|
channel.Metadata = meta
|
|
|
|
var chs []things.Channel
|
|
for i := uint64(0); i < n; i++ {
|
|
ch := channel
|
|
ch.Name = fmt.Sprintf("name-%d", i)
|
|
chs = append(chs, ch)
|
|
}
|
|
|
|
_, err := svc.CreateChannels(context.Background(), token, chs...)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
|
|
|
cases := map[string]struct {
|
|
token string
|
|
pageMetadata things.PageMetadata
|
|
size uint64
|
|
err error
|
|
}{
|
|
"list all channels": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
"list half": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n / 2,
|
|
Limit: n,
|
|
},
|
|
size: n / 2,
|
|
err: nil,
|
|
},
|
|
"list last channel": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n - 1,
|
|
Limit: n,
|
|
},
|
|
size: 1,
|
|
err: nil,
|
|
},
|
|
"list empty set": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n + 1,
|
|
Limit: n,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list with zero limit and offset 1": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 1,
|
|
Limit: 0,
|
|
},
|
|
size: n - 1,
|
|
err: nil,
|
|
},
|
|
"list with wrong credentials": {
|
|
token: wrongValue,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: 0,
|
|
},
|
|
size: 0,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
"list with existing name": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Name: "chanel_name",
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
"list with non-existent name": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Name: "wrong",
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
"list all channels with metadata": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Metadata: meta,
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
"list all channels sorted by name ascendent": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Order: "name",
|
|
Dir: "asc",
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
"list all channels sorted by name descendent": {
|
|
token: token,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Order: "name",
|
|
Dir: "desc",
|
|
},
|
|
size: n,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
page, err := svc.ListChannels(context.Background(), tc.token, tc.pageMetadata)
|
|
size := uint64(len(page.Channels))
|
|
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected %d got %d\n", desc, tc.size, size))
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
|
|
// Check if channels list have been sorted properly
|
|
testSortChannels(t, tc.pageMetadata, page.Channels)
|
|
}
|
|
}
|
|
|
|
func TestListChannelsByThing(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
|
th := ths[0]
|
|
|
|
chsDisconNum := uint64(4)
|
|
|
|
var chs []things.Channel
|
|
for i := uint64(0); i < n; i++ {
|
|
ch := channel
|
|
ch.Name = fmt.Sprintf("name-%d", i)
|
|
chs = append(chs, ch)
|
|
}
|
|
|
|
chsc, err := svc.CreateChannels(context.Background(), token, chs...)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
|
|
|
var chIDs []string
|
|
for _, chID := range chsc {
|
|
chIDs = append(chIDs, chID.ID)
|
|
}
|
|
thIDs := []string{ths[0].ID}
|
|
|
|
err = svc.Connect(context.Background(), token, chIDs[0:n-chsDisconNum], thIDs)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
|
|
// Wait for things and channels to connect.
|
|
time.Sleep(time.Second)
|
|
|
|
cases := map[string]struct {
|
|
token string
|
|
thID string
|
|
pageMetadata things.PageMetadata
|
|
size uint64
|
|
err error
|
|
}{
|
|
"list all channels by existing thing": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
},
|
|
size: n - chsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list half of channels by existing thing": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: (n - chsDisconNum) / 2,
|
|
Limit: n,
|
|
},
|
|
size: (n - chsDisconNum) / 2,
|
|
err: nil,
|
|
},
|
|
"list last channel by existing thing": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n - 1 - chsDisconNum,
|
|
Limit: n,
|
|
},
|
|
size: 1,
|
|
err: nil,
|
|
},
|
|
"list empty set of channels by existing thing": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: n + 1,
|
|
Limit: n,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list channels by existing thing with zero limit": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 1,
|
|
Limit: 0,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list channels by existing thing with wrong credentials": {
|
|
token: wrongValue,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: 0,
|
|
},
|
|
size: 0,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
"list channels by non-existent thing": {
|
|
token: token,
|
|
thID: "non-existent",
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
},
|
|
size: 0,
|
|
err: nil,
|
|
},
|
|
"list all non-connected channels by existing thing": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Disconnected: true,
|
|
},
|
|
size: chsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list all channels by thing sorted by name ascendent": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Order: "name",
|
|
Dir: "asc",
|
|
},
|
|
size: n - chsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list all non-connected channels by thing sorted by name ascendent": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Disconnected: true,
|
|
Order: "name",
|
|
Dir: "asc",
|
|
},
|
|
size: chsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list all channels by thing sorted by name descendent": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Order: "name",
|
|
Dir: "desc",
|
|
},
|
|
size: n - chsDisconNum,
|
|
err: nil,
|
|
},
|
|
"list all non-connected channels by thing sorted by name descendent": {
|
|
token: token,
|
|
thID: th.ID,
|
|
pageMetadata: things.PageMetadata{
|
|
Offset: 0,
|
|
Limit: n,
|
|
Disconnected: true,
|
|
Order: "name",
|
|
Dir: "desc",
|
|
},
|
|
size: chsDisconNum,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
page, err := svc.ListChannelsByThing(context.Background(), tc.token, tc.thID, tc.pageMetadata)
|
|
size := uint64(len(page.Channels))
|
|
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected %d got %d\n", desc, tc.size, size))
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
|
|
// Check if Channels by Thing list have been sorted properly
|
|
testSortChannels(t, tc.pageMetadata, page.Channels)
|
|
}
|
|
}
|
|
|
|
func TestRemoveChannel(t *testing.T) {
|
|
svc := newService(map[string]string{token: adminEmail})
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
ch := chs[0]
|
|
|
|
cases := []struct {
|
|
desc string
|
|
id string
|
|
token string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "remove channel with wrong credentials",
|
|
id: ch.ID,
|
|
token: wrongValue,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "remove existing channel",
|
|
id: ch.ID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove removed channel",
|
|
id: ch.ID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove non-existing channel",
|
|
id: ch.ID,
|
|
token: token,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := svc.RemoveChannel(context.Background(), tc.token, tc.id)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestConnect(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
th := ths[0]
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
ch := chs[0]
|
|
|
|
cases := []struct {
|
|
desc string
|
|
token string
|
|
chanID string
|
|
thingID string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "connect thing",
|
|
token: token,
|
|
chanID: ch.ID,
|
|
thingID: th.ID,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "connect thing with wrong credentials",
|
|
token: wrongValue,
|
|
chanID: ch.ID,
|
|
thingID: th.ID,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "connect thing to non-existing channel",
|
|
token: token,
|
|
chanID: wrongID,
|
|
thingID: th.ID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "connect non-existing thing to channel",
|
|
token: token,
|
|
chanID: ch.ID,
|
|
thingID: wrongID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := svc.Connect(context.Background(), tc.token, []string{tc.chanID}, []string{tc.thingID})
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestDisconnect(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
th := ths[0]
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
ch := chs[0]
|
|
err = svc.Connect(context.Background(), token, []string{ch.ID}, []string{th.ID})
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
token string
|
|
chanID string
|
|
thingID string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "disconnect connected thing",
|
|
token: token,
|
|
chanID: ch.ID,
|
|
thingID: th.ID,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "disconnect disconnected thing",
|
|
token: token,
|
|
chanID: ch.ID,
|
|
thingID: th.ID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "disconnect with wrong credentials",
|
|
token: wrongValue,
|
|
chanID: ch.ID,
|
|
thingID: th.ID,
|
|
err: things.ErrUnauthorizedAccess,
|
|
},
|
|
{
|
|
desc: "disconnect from non-existing channel",
|
|
token: token,
|
|
chanID: wrongID,
|
|
thingID: th.ID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "disconnect non-existing thing",
|
|
token: token,
|
|
chanID: ch.ID,
|
|
thingID: wrongID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := svc.Disconnect(context.Background(), tc.token, []string{tc.chanID}, []string{tc.thingID})
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
|
|
}
|
|
|
|
func TestCanAccessByKey(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
err = svc.Connect(context.Background(), token, []string{chs[0].ID}, []string{ths[0].ID})
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
|
|
cases := map[string]struct {
|
|
token string
|
|
channel string
|
|
err error
|
|
}{
|
|
"allowed access": {
|
|
token: ths[0].Key,
|
|
channel: chs[0].ID,
|
|
err: nil,
|
|
},
|
|
"non-existing thing": {
|
|
token: wrongValue,
|
|
channel: chs[0].ID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
"non-existing chan": {
|
|
token: ths[0].Key,
|
|
channel: wrongValue,
|
|
err: things.ErrEntityConnected,
|
|
},
|
|
"non-connected channel": {
|
|
token: ths[0].Key,
|
|
channel: chs[1].ID,
|
|
err: things.ErrEntityConnected,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
_, err := svc.CanAccessByKey(context.Background(), tc.channel, tc.token)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected '%s' got '%s'\n", desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestCanAccessByID(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0], thingList[1])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
th := ths[0]
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
ch := chs[0]
|
|
err = svc.Connect(context.Background(), token, []string{ch.ID}, []string{th.ID})
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
|
|
cases := map[string]struct {
|
|
thingID string
|
|
channel string
|
|
err error
|
|
}{
|
|
"allowed access": {
|
|
thingID: th.ID,
|
|
channel: ch.ID,
|
|
err: nil,
|
|
},
|
|
"access to non-existing thing": {
|
|
thingID: wrongValue,
|
|
channel: ch.ID,
|
|
err: things.ErrEntityConnected,
|
|
},
|
|
"access to non-existing channel": {
|
|
thingID: th.ID,
|
|
channel: wrongID,
|
|
err: things.ErrEntityConnected,
|
|
},
|
|
"access to not-connected thing": {
|
|
thingID: ths[1].ID,
|
|
channel: ch.ID,
|
|
err: things.ErrEntityConnected,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
err := svc.CanAccessByID(context.Background(), tc.channel, tc.thingID)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestIsChannelOwner(t *testing.T) {
|
|
svc := newService(map[string]string{token: email, token2: "john.doe@email.net"})
|
|
|
|
chs, err := svc.CreateChannels(context.Background(), token, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
ownedCh := chs[0]
|
|
chs, err = svc.CreateChannels(context.Background(), token2, channel)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
nonOwnedCh := chs[0]
|
|
|
|
cases := map[string]struct {
|
|
channel string
|
|
err error
|
|
}{
|
|
"user owns channel": {
|
|
channel: ownedCh.ID,
|
|
err: nil,
|
|
},
|
|
"user does not own channel": {
|
|
channel: nonOwnedCh.ID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
"access to non-existing channel": {
|
|
channel: wrongID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
err := svc.IsChannelOwner(context.Background(), email, tc.channel)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestIdentify(t *testing.T) {
|
|
svc := newService(map[string]string{token: email})
|
|
|
|
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
|
th := ths[0]
|
|
|
|
cases := map[string]struct {
|
|
token string
|
|
id string
|
|
err error
|
|
}{
|
|
"identify existing thing": {
|
|
token: th.Key,
|
|
id: th.ID,
|
|
err: nil,
|
|
},
|
|
"identify non-existing thing": {
|
|
token: wrongValue,
|
|
id: wrongID,
|
|
err: things.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for desc, tc := range cases {
|
|
id, err := svc.Identify(context.Background(), tc.token)
|
|
assert.Equal(t, tc.id, id, fmt.Sprintf("%s: expected %s got %s\n", desc, tc.id, id))
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func testSortThings(t *testing.T, pm things.PageMetadata, ths []things.Thing) {
|
|
switch pm.Order {
|
|
case "name":
|
|
current := ths[0]
|
|
for _, res := range ths {
|
|
if pm.Dir == "asc" {
|
|
assert.GreaterOrEqual(t, res.Name, current.Name)
|
|
}
|
|
if pm.Dir == "desc" {
|
|
assert.GreaterOrEqual(t, current.Name, res.Name)
|
|
}
|
|
current = res
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func testSortChannels(t *testing.T, pm things.PageMetadata, chs []things.Channel) {
|
|
switch pm.Order {
|
|
case "name":
|
|
current := chs[0]
|
|
for _, res := range chs {
|
|
if pm.Dir == "asc" {
|
|
assert.GreaterOrEqual(t, res.Name, current.Name)
|
|
}
|
|
if pm.Dir == "desc" {
|
|
assert.GreaterOrEqual(t, current.Name, res.Name)
|
|
}
|
|
current = res
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|