1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-27 13:48:49 +08:00
Mainflux.mainflux/things/service_test.go
Mirko Teodorovic 7195cad0f6
MF-397 - Introduce Thing Groups (#1259)
* add things group

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add things group repository

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add things group repository

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add things group repository

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add parents and children methods

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add parents and children methods

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix logging message and temporary test fix

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix bootstrap test fail

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* move groups to pkg

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* move groups to pkg

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* move groups to pkg

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* move groups to internal

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* move groups to internal

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix import

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix linter errors

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix comments

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* resolve comments, add hierarchy info when retrieving groups

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* code refactor, separate http into multiple files

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* code refactor, separate http into multiple files

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix group update

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* use user id when saving

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* use user id when saving

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* rename methods

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* move code

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* move code

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* remove temporary test

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add groups test

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix comments, fix responses in api for groups

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* revert changes

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

add checks for name length

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

fix validation

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

small change to response

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

add comment for Level

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

add level to limit hierarchy retrieval

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

tidy vendor

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

add level to limit hierarchy retrieval

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

mod tidy

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

revert

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

resolve comments

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

small naming and code organize refactor

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

revert Member type

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

fix typo

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

use ltree

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

use ltree

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

add level for retrieving

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

add level

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

add ltre

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

upgrade postgres version in test

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

add ltre

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

remove test for now

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

minor fixes

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

fix id setting

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

fix tree endpoint

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

minor style changes

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* small changes, adding new lines

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* minor changes

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* change function signature

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* change primary key

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* change function signature

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* simplufy code

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* remove groups test for now

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix tabulation

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix whitespace

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* remove white space, fix grammar

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix sqls so that not additional retrieve is needed

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix sqls so that not additional retrieve is needed

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

fix primary key

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

remove retrive by name

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* remove name and parent update

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix cound sql

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add line

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* simplify sql, fix table name

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add date

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add date

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add timestamp to api

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix var name

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix var name

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>
2020-11-23 11:34:29 +01:00

1031 lines
24 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"
email = "user@example.com"
token = "token"
)
var (
thing = things.Thing{Name: "test"}
channel = things.Channel{Name: "test"}
)
func newService(tokens map[string]string) things.Service {
auth := mocks.NewAuthService(tokens)
conns := make(chan mocks.Connection)
thingsRepo := mocks.NewThingRepository(conns)
channelsRepo := mocks.NewChannelRepository(thingsRepo, conns)
chanCache := mocks.NewChannelCache()
thingCache := mocks.NewThingCache()
uuidProvider := uuid.NewMock()
return things.New(auth, thingsRepo, channelsRepo, nil, chanCache, thingCache, uuidProvider)
}
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,
},
}
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, thing)
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.ErrNotFound,
},
}
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.ErrNotFound,
},
}
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 TestViewThing(t *testing.T) {
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 := 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.ErrNotFound,
},
}
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"
thing.Metadata = m
n := uint64(10)
for i := uint64(0); i < n; i++ {
_, err := svc.CreateThings(context.Background(), token, thing)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
}
cases := map[string]struct {
token string
offset uint64
limit uint64
name string
size uint64
metadata map[string]interface{}
err error
}{
"list all things": {
token: token,
offset: 0,
limit: n,
size: n,
err: nil,
},
"list half": {
token: token,
offset: n / 2,
limit: n,
size: n / 2,
err: nil,
},
"list last thing": {
token: token,
offset: n - 1,
limit: n,
size: 1,
err: nil,
},
"list empty set": {
token: token,
offset: n + 1,
limit: n,
size: 0,
err: nil,
},
"list with zero limit": {
token: token,
offset: 1,
limit: 0,
size: 0,
err: nil,
},
"list with wrong credentials": {
token: wrongValue,
offset: 0,
limit: 0,
size: 0,
err: things.ErrUnauthorizedAccess,
},
"list with metadata": {
token: token,
offset: 0,
limit: n,
size: n,
err: nil,
metadata: m,
},
}
for desc, tc := range cases {
page, err := svc.ListThings(context.Background(), tc.token, tc.offset, tc.limit, tc.name, tc.metadata)
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))
}
}
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]
n := uint64(10)
thsDisconNum := uint64(1)
for i := uint64(0); i < n; i++ {
ths, err := svc.CreateThings(context.Background(), token, thing)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th := ths[0]
// Don't connect last Channel
if i == n-thsDisconNum {
break
}
err = svc.Connect(context.Background(), token, []string{ch.ID}, []string{th.ID})
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
channel string
offset uint64
limit uint64
connected bool
size uint64
err error
}{
"list all things by existing channel": {
token: token,
channel: ch.ID,
offset: 0,
limit: n,
connected: true,
size: n - thsDisconNum,
err: nil,
},
"list half of things by existing channel": {
token: token,
channel: ch.ID,
offset: n / 2,
limit: n,
connected: true,
size: (n / 2) - thsDisconNum,
err: nil,
},
"list last thing by existing channel": {
token: token,
channel: ch.ID,
offset: n - 1 - thsDisconNum,
limit: n,
connected: true,
size: 1,
err: nil,
},
"list empty set of things by existing channel": {
token: token,
channel: ch.ID,
offset: n + 1,
limit: n,
connected: true,
size: 0,
err: nil,
},
"list things by existing channel with zero limit": {
token: token,
channel: ch.ID,
offset: 1,
limit: 0,
connected: true,
size: 0,
err: nil,
},
"list things by existing channel with wrong credentials": {
token: wrongValue,
channel: ch.ID,
offset: 0,
limit: 0,
connected: true,
size: 0,
err: things.ErrUnauthorizedAccess,
},
"list things by non-existent channel with wrong credentials": {
token: token,
channel: "non-existent",
offset: 0,
limit: 10,
connected: true,
size: 0,
err: nil,
},
"list all non connected things by existing channel": {
token: token,
channel: ch.ID,
offset: 0,
limit: n,
connected: false,
size: thsDisconNum,
err: nil,
},
}
for desc, tc := range cases {
page, err := svc.ListThingsByChannel(context.Background(), tc.token, tc.channel, tc.offset, tc.limit, tc.connected)
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))
}
}
func TestRemoveThing(t *testing.T) {
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))
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: nil,
},
}
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,
},
}
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: email})
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: email})
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
n := uint64(10)
for i := uint64(0); i < n; i++ {
svc.CreateChannels(context.Background(), token, channel)
}
cases := map[string]struct {
token string
offset uint64
limit uint64
size uint64
name string
err error
metadata things.Metadata
}{
"list all channels": {
token: token,
offset: 0,
limit: n,
size: n,
err: nil,
},
"list half": {
token: token,
offset: n / 2,
limit: n,
size: n / 2,
err: nil,
},
"list last channel": {
token: token,
offset: n - 1,
limit: n,
size: 1,
err: nil,
},
"list empty set": {
token: token,
offset: n + 1,
limit: n,
size: 0,
err: nil,
},
"list with zero limit": {
token: token,
offset: 1,
limit: 0,
size: 0,
err: nil,
},
"list with wrong credentials": {
token: wrongValue,
offset: 0,
limit: 0,
size: 0,
err: things.ErrUnauthorizedAccess,
},
"list with existing name": {
token: token,
offset: 0,
limit: n,
size: n,
name: "chanel_name",
err: nil,
},
"list with non-existent name": {
token: token,
offset: 0,
limit: n,
size: n,
name: "wrong",
err: nil,
},
"list all channels with metadata": {
token: token,
offset: 0,
limit: n,
size: n,
err: nil,
metadata: meta,
},
}
for desc, tc := range cases {
page, err := svc.ListChannels(context.Background(), tc.token, tc.offset, tc.limit, tc.name, tc.metadata)
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))
}
}
func TestListChannelsByThing(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th := ths[0]
n := uint64(10)
chsDisconNum := uint64(1)
for i := uint64(0); i < n; i++ {
schs, err := svc.CreateChannels(context.Background(), token, channel)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
sch := schs[0]
// Don't connect last Channel
if i == n-chsDisconNum {
break
}
err = svc.Connect(context.Background(), token, []string{sch.ID}, []string{th.ID})
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
thing string
offset uint64
limit uint64
connected bool
size uint64
err error
}{
"list all channels by existing thing": {
token: token,
thing: th.ID,
offset: 0,
limit: n,
connected: true,
size: n - chsDisconNum,
err: nil,
},
"list half of channels by existing thing": {
token: token,
thing: th.ID,
offset: n / 2,
limit: n,
connected: true,
size: (n / 2) - chsDisconNum,
err: nil,
},
"list last channel by existing thing": {
token: token,
thing: th.ID,
offset: n - 1 - chsDisconNum,
limit: n,
connected: true,
size: 1,
err: nil,
},
"list empty set of channels by existing thing": {
token: token,
thing: th.ID,
offset: n + 1,
limit: n,
connected: true,
size: 0,
err: nil,
},
"list channels by existing thing with zero limit": {
token: token,
thing: th.ID,
offset: 1,
limit: 0,
connected: true,
size: 0,
err: nil,
},
"list channels by existing thing with wrong credentials": {
token: wrongValue,
thing: th.ID,
offset: 0,
limit: 0,
connected: true,
size: 0,
err: things.ErrUnauthorizedAccess,
},
"list channels by non-existent thing": {
token: token,
thing: "non-existent",
offset: 0,
limit: 10,
connected: true,
size: 0,
err: nil,
},
"list all non connected channels by existing thing": {
token: token,
thing: th.ID,
offset: 0,
limit: n,
connected: false,
size: chsDisconNum,
err: nil,
},
}
for desc, tc := range cases {
page, err := svc.ListChannelsByThing(context.Background(), tc.token, tc.thing, tc.offset, tc.limit, tc.connected)
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))
}
}
func TestRemoveChannel(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\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, thing)
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, thing)
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, tc.chanID, 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, thing)
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, thing, thing)
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 TestIdentify(t *testing.T) {
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 := 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))
}
}