1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-29 13:49:28 +08:00
qs-wang 7e9ab453d4
MF-1425 - Support external UUIDs for Things and Channels (#1518)
* 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>
2021-12-08 12:46:59 +01:00

316 lines
6.9 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package mocks
import (
"context"
"fmt"
"strings"
"sync"
"github.com/mainflux/mainflux/things"
)
// Connection represents connection between channel and thing that is used for
// testing purposes.
type Connection struct {
chanID string
thing things.Thing
connected bool
}
var _ things.ChannelRepository = (*channelRepositoryMock)(nil)
type channelRepositoryMock struct {
mu sync.Mutex
counter uint64
channels map[string]things.Channel
tconns chan Connection // used for synchronization with thing repo
cconns map[string]map[string]things.Channel // used to track connections
things things.ThingRepository
}
// NewChannelRepository creates in-memory channel repository.
func NewChannelRepository(repo things.ThingRepository, tconns chan Connection) things.ChannelRepository {
return &channelRepositoryMock{
channels: make(map[string]things.Channel),
tconns: tconns,
cconns: make(map[string]map[string]things.Channel),
things: repo,
}
}
func (crm *channelRepositoryMock) Save(_ context.Context, channels ...things.Channel) ([]things.Channel, error) {
crm.mu.Lock()
defer crm.mu.Unlock()
for i := range channels {
crm.counter++
if channels[i].ID == "" {
channels[i].ID = fmt.Sprintf("%03d", crm.counter)
}
crm.channels[key(channels[i].Owner, channels[i].ID)] = channels[i]
}
return channels, nil
}
func (crm *channelRepositoryMock) Update(_ context.Context, channel things.Channel) error {
crm.mu.Lock()
defer crm.mu.Unlock()
dbKey := key(channel.Owner, channel.ID)
if _, ok := crm.channels[dbKey]; !ok {
return things.ErrNotFound
}
crm.channels[dbKey] = channel
return nil
}
func (crm *channelRepositoryMock) RetrieveByID(_ context.Context, owner, id string) (things.Channel, error) {
if c, ok := crm.channels[key(owner, id)]; ok {
return c, nil
}
return things.Channel{}, things.ErrNotFound
}
func (crm *channelRepositoryMock) RetrieveAll(_ context.Context, owner string, pm things.PageMetadata) (things.ChannelsPage, error) {
if pm.Limit < 0 {
return things.ChannelsPage{}, nil
}
if pm.Limit == 0 {
pm.Limit = 10
}
first := int(pm.Offset)
last := first + int(pm.Limit)
var chs []things.Channel
// This obscure way to examine map keys is enforced by the key structure
// itself (see mocks/commons.go).
prefix := fmt.Sprintf("%s-", owner)
for k, v := range crm.channels {
if strings.HasPrefix(k, prefix) {
chs = append(chs, v)
}
}
// Sort Channels list
chs = sortChannels(pm, chs)
if last > len(chs) {
last = len(chs)
}
if first > last {
return things.ChannelsPage{}, nil
}
page := things.ChannelsPage{
Channels: chs[first:last],
PageMetadata: things.PageMetadata{
Total: crm.counter,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (crm *channelRepositoryMock) RetrieveByThing(_ context.Context, owner, thID string, pm things.PageMetadata) (things.ChannelsPage, error) {
if pm.Limit <= 0 {
return things.ChannelsPage{}, nil
}
first := uint64(pm.Offset) + 1
last := first + uint64(pm.Limit)
var chs []things.Channel
// Append connected or not connected channels
switch pm.Disconnected {
case false:
for _, co := range crm.cconns[thID] {
id := parseID(co.ID)
if id >= first && id < last {
chs = append(chs, co)
}
}
default:
for _, ch := range crm.channels {
conn := false
id := parseID(ch.ID)
if id >= first && id < last {
for _, co := range crm.cconns[thID] {
if ch.ID == co.ID {
conn = true
}
}
// Append if not found in connections list
if !conn {
chs = append(chs, ch)
}
}
}
}
// Sort Channels by Thing list
chs = sortChannels(pm, chs)
page := things.ChannelsPage{
Channels: chs,
PageMetadata: things.PageMetadata{
Total: crm.counter,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (crm *channelRepositoryMock) Remove(_ context.Context, owner, id string) error {
delete(crm.channels, key(owner, id))
// delete channel from any thing list
for thk := range crm.cconns {
delete(crm.cconns[thk], key(owner, id))
}
crm.tconns <- Connection{
chanID: id,
connected: false,
}
return nil
}
func (crm *channelRepositoryMock) Connect(_ context.Context, owner string, chIDs, thIDs []string) error {
for _, chID := range chIDs {
ch, err := crm.RetrieveByID(context.Background(), owner, chID)
if err != nil {
return err
}
for _, thID := range thIDs {
th, err := crm.things.RetrieveByID(context.Background(), owner, thID)
if err != nil {
return err
}
crm.tconns <- Connection{
chanID: chID,
thing: th,
connected: true,
}
if _, ok := crm.cconns[thID]; !ok {
crm.cconns[thID] = make(map[string]things.Channel)
}
crm.cconns[thID][chID] = ch
}
}
return nil
}
func (crm *channelRepositoryMock) Disconnect(_ context.Context, owner string, chIDs, thIDs []string) error {
for _, chID := range chIDs {
for _, thID := range thIDs {
if _, ok := crm.cconns[thID]; !ok {
return things.ErrNotFound
}
if _, ok := crm.cconns[thID][chID]; !ok {
return things.ErrNotFound
}
crm.tconns <- Connection{
chanID: chID,
thing: things.Thing{ID: thID, Owner: owner},
connected: false,
}
delete(crm.cconns[thID], chID)
}
}
return nil
}
func (crm *channelRepositoryMock) HasThing(_ context.Context, chanID, token string) (string, error) {
tid, err := crm.things.RetrieveByKey(context.Background(), token)
if err != nil {
return "", err
}
chans, ok := crm.cconns[tid]
if !ok {
return "", things.ErrEntityConnected
}
if _, ok := chans[chanID]; !ok {
return "", things.ErrEntityConnected
}
return tid, nil
}
func (crm *channelRepositoryMock) HasThingByID(_ context.Context, chanID, thingID string) error {
chans, ok := crm.cconns[thingID]
if !ok {
return things.ErrEntityConnected
}
if _, ok := chans[chanID]; !ok {
return things.ErrEntityConnected
}
return nil
}
type channelCacheMock struct {
mu sync.Mutex
channels map[string]string
}
// NewChannelCache returns mock cache instance.
func NewChannelCache() things.ChannelCache {
return &channelCacheMock{
channels: make(map[string]string),
}
}
func (ccm *channelCacheMock) Connect(_ context.Context, chanID, thingID string) error {
ccm.mu.Lock()
defer ccm.mu.Unlock()
ccm.channels[chanID] = thingID
return nil
}
func (ccm *channelCacheMock) HasThing(_ context.Context, chanID, thingID string) bool {
ccm.mu.Lock()
defer ccm.mu.Unlock()
return ccm.channels[chanID] == thingID
}
func (ccm *channelCacheMock) Disconnect(_ context.Context, chanID, thingID string) error {
ccm.mu.Lock()
defer ccm.mu.Unlock()
delete(ccm.channels, chanID)
return nil
}
func (ccm *channelCacheMock) Remove(_ context.Context, chanID string) error {
ccm.mu.Lock()
defer ccm.mu.Unlock()
delete(ccm.channels, chanID)
return nil
}