1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-05-01 13:48:56 +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

334 lines
6.6 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package mocks
import (
"context"
"fmt"
"strings"
"sync"
"github.com/mainflux/mainflux/things"
)
var _ things.ThingRepository = (*thingRepositoryMock)(nil)
type thingRepositoryMock struct {
mu sync.Mutex
counter uint64
conns chan Connection
tconns map[string]map[string]things.Thing
things map[string]things.Thing
}
// NewThingRepository creates in-memory thing repository.
func NewThingRepository(conns chan Connection) things.ThingRepository {
repo := &thingRepositoryMock{
conns: conns,
things: make(map[string]things.Thing),
tconns: make(map[string]map[string]things.Thing),
}
go func(conns chan Connection, repo *thingRepositoryMock) {
for conn := range conns {
if !conn.connected {
repo.disconnect(conn)
continue
}
repo.connect(conn)
}
}(conns, repo)
return repo
}
func (trm *thingRepositoryMock) Save(_ context.Context, ths ...things.Thing) ([]things.Thing, error) {
trm.mu.Lock()
defer trm.mu.Unlock()
for i := range ths {
for _, th := range trm.things {
if th.Key == ths[i].Key {
return []things.Thing{}, things.ErrConflict
}
}
trm.counter++
if ths[i].ID == "" {
ths[i].ID = fmt.Sprintf("%03d", trm.counter)
}
trm.things[key(ths[i].Owner, ths[i].ID)] = ths[i]
}
return ths, nil
}
func (trm *thingRepositoryMock) Update(_ context.Context, thing things.Thing) error {
trm.mu.Lock()
defer trm.mu.Unlock()
dbKey := key(thing.Owner, thing.ID)
if _, ok := trm.things[dbKey]; !ok {
return things.ErrNotFound
}
trm.things[dbKey] = thing
return nil
}
func (trm *thingRepositoryMock) UpdateKey(_ context.Context, owner, id, val string) error {
trm.mu.Lock()
defer trm.mu.Unlock()
for _, th := range trm.things {
if th.Key == val {
return things.ErrConflict
}
}
dbKey := key(owner, id)
th, ok := trm.things[dbKey]
if !ok {
return things.ErrNotFound
}
th.Key = val
trm.things[dbKey] = th
return nil
}
func (trm *thingRepositoryMock) RetrieveByID(_ context.Context, owner, id string) (things.Thing, error) {
trm.mu.Lock()
defer trm.mu.Unlock()
if c, ok := trm.things[key(owner, id)]; ok {
return c, nil
}
return things.Thing{}, things.ErrNotFound
}
func (trm *thingRepositoryMock) RetrieveAll(_ context.Context, owner string, pm things.PageMetadata) (things.Page, error) {
trm.mu.Lock()
defer trm.mu.Unlock()
if pm.Limit < 0 {
return things.Page{}, nil
}
first := uint64(pm.Offset) + 1
last := first + uint64(pm.Limit)
var ths []things.Thing
// 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 trm.things {
id := parseID(v.ID)
if strings.HasPrefix(k, prefix) && id >= first && id < last {
ths = append(ths, v)
}
}
// Sort Things list
ths = sortThings(pm, ths)
page := things.Page{
Things: ths,
PageMetadata: things.PageMetadata{
Total: trm.counter,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (trm *thingRepositoryMock) RetrieveByIDs(_ context.Context, thingIDs []string, pm things.PageMetadata) (things.Page, error) {
trm.mu.Lock()
defer trm.mu.Unlock()
items := make([]things.Thing, 0)
if pm.Limit == 0 {
return things.Page{}, nil
}
first := uint64(pm.Offset) + 1
last := first + uint64(pm.Limit)
// This obscure way to examine map keys is enforced by the key structure
// itself (see mocks/commons.go).
for _, id := range thingIDs {
suffix := fmt.Sprintf("-%s", id)
for k, v := range trm.things {
id := parseID(v.ID)
if strings.HasSuffix(k, suffix) && id >= first && id < last {
items = append(items, v)
}
}
}
items = sortThings(pm, items)
page := things.Page{
Things: items,
PageMetadata: things.PageMetadata{
Total: trm.counter,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (trm *thingRepositoryMock) RetrieveByChannel(_ context.Context, owner, chID string, pm things.PageMetadata) (things.Page, error) {
trm.mu.Lock()
defer trm.mu.Unlock()
if pm.Limit <= 0 {
return things.Page{}, nil
}
first := uint64(pm.Offset) + 1
last := first + uint64(pm.Limit)
var ths []things.Thing
// Append connected or not connected channels
switch pm.Disconnected {
case false:
for _, co := range trm.tconns[chID] {
id := parseID(co.ID)
if id >= first && id < last {
ths = append(ths, co)
}
}
default:
for _, th := range trm.things {
conn := false
id := parseID(th.ID)
if id >= first && id < last {
for _, co := range trm.tconns[chID] {
if th.ID == co.ID {
conn = true
}
}
// Append if not found in connections list
if !conn {
ths = append(ths, th)
}
}
}
}
// Sort Things by Channel list
ths = sortThings(pm, ths)
page := things.Page{
Things: ths,
PageMetadata: things.PageMetadata{
Total: trm.counter,
Offset: pm.Offset,
Limit: pm.Limit,
},
}
return page, nil
}
func (trm *thingRepositoryMock) Remove(_ context.Context, owner, id string) error {
trm.mu.Lock()
defer trm.mu.Unlock()
delete(trm.things, key(owner, id))
return nil
}
func (trm *thingRepositoryMock) RetrieveByKey(_ context.Context, key string) (string, error) {
trm.mu.Lock()
defer trm.mu.Unlock()
for _, thing := range trm.things {
if thing.Key == key {
return thing.ID, nil
}
}
return "", things.ErrNotFound
}
func (trm *thingRepositoryMock) connect(conn Connection) {
trm.mu.Lock()
defer trm.mu.Unlock()
if _, ok := trm.tconns[conn.chanID]; !ok {
trm.tconns[conn.chanID] = make(map[string]things.Thing)
}
trm.tconns[conn.chanID][conn.thing.ID] = conn.thing
}
func (trm *thingRepositoryMock) disconnect(conn Connection) {
trm.mu.Lock()
defer trm.mu.Unlock()
if conn.thing.ID == "" {
delete(trm.tconns, conn.chanID)
return
}
delete(trm.tconns[conn.chanID], conn.thing.ID)
}
type thingCacheMock struct {
mu sync.Mutex
things map[string]string
}
// NewThingCache returns mock cache instance.
func NewThingCache() things.ThingCache {
return &thingCacheMock{
things: make(map[string]string),
}
}
func (tcm *thingCacheMock) Save(_ context.Context, key, id string) error {
tcm.mu.Lock()
defer tcm.mu.Unlock()
tcm.things[key] = id
return nil
}
func (tcm *thingCacheMock) ID(_ context.Context, key string) (string, error) {
tcm.mu.Lock()
defer tcm.mu.Unlock()
id, ok := tcm.things[key]
if !ok {
return "", things.ErrNotFound
}
return id, nil
}
func (tcm *thingCacheMock) Remove(_ context.Context, id string) error {
tcm.mu.Lock()
defer tcm.mu.Unlock()
for key, val := range tcm.things {
if val == id {
delete(tcm.things, key)
return nil
}
}
return nil
}