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

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>
This commit is contained in:
qs-wang 2021-12-08 19:46:59 +08:00 committed by GitHub
parent 309ef512cb
commit 7e9ab453d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 248 additions and 100 deletions

View File

@ -636,7 +636,10 @@ components:
id:
type: string
format: uuid
description: Thing unique identifier
description: Thing unique identifier. This can be either
provided by the user or left blank. If the user provides a UUID,
it would be validated. If there is not one provided then
the service will generate one in UUID format.
ThingReqSchema:
type: object
properties:

View File

@ -15,7 +15,10 @@ import (
)
var (
channel = sdk.Channel{ID: "001", Name: "test"}
ch1 = sdk.Channel{Name: "test1"}
ch2 = sdk.Channel{ID: "fe6b4e92-cc98-425e-b0aa-000000000001", Name: "test1"}
ch3 = sdk.Channel{ID: "fe6b4e92-cc98-425e-b0aa-000000000002", Name: "test2"}
chPrefix = "fe6b4e92-cc98-425e-b0aa-"
emptyChannel = sdk.Channel{}
)
@ -24,6 +27,8 @@ func TestCreateChannel(t *testing.T) {
ts := newThingsServer(svc)
defer ts.Close()
chWrongExtID := sdk.Channel{ID: "b0aa-000000000001", Name: "1", Metadata:metadata}
sdkConf := sdk.Config{
ThingsURL: ts.URL,
MsgContentType: contentType,
@ -41,21 +46,21 @@ func TestCreateChannel(t *testing.T) {
}{
{
desc: "create new channel",
channel: channel,
channel: ch1,
token: token,
err: nil,
empty: false,
},
{
desc: "create new channel with empty token",
channel: channel,
channel: ch1,
token: "",
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
empty: true,
},
{
desc: "create new channel with invalid token",
channel: channel,
channel: ch1,
token: wrongValue,
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
empty: true,
@ -67,6 +72,20 @@ func TestCreateChannel(t *testing.T) {
err: nil,
empty: false,
},
{
desc: "create a new channel with external UUID",
channel: ch2,
token: token,
err: nil,
empty: false,
},
{
desc: "create a new channel with wrong external UUID",
channel: chWrongExtID,
token: token,
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
empty: true,
},
}
for _, tc := range cases {
@ -90,8 +109,8 @@ func TestCreateChannels(t *testing.T) {
mainfluxSDK := sdk.NewSDK(sdkConf)
channels := []sdk.Channel{
sdk.Channel{ID: "001", Name: "1"},
sdk.Channel{ID: "002", Name: "2"},
ch2,
ch3,
}
cases := []struct {
@ -151,7 +170,7 @@ func TestChannel(t *testing.T) {
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateChannel(channel, token)
id, err := mainfluxSDK.CreateChannel(ch2, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
@ -166,7 +185,7 @@ func TestChannel(t *testing.T) {
chanID: id,
token: token,
err: nil,
response: channel,
response: ch2,
},
{
desc: "get non-existent channel",
@ -204,7 +223,9 @@ func TestChannels(t *testing.T) {
var channels []sdk.Channel
mainfluxSDK := sdk.NewSDK(sdkConf)
for i := 1; i < 101; i++ {
ch := sdk.Channel{ID: fmt.Sprintf("%03d", i), Name: "test"}
id := fmt.Sprintf("%s%012d", chPrefix, i)
name := fmt.Sprintf("test-%d", i)
ch := sdk.Channel{ID: id, Name: name}
_, err := mainfluxSDK.CreateChannel(ch, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
channels = append(channels, ch)
@ -294,10 +315,9 @@ func TestChannelsByThing(t *testing.T) {
var chsDiscoNum = 1
var channels []sdk.Channel
for i := 1; i < n+1; i++ {
ch := sdk.Channel{
ID: fmt.Sprintf("%03d", i),
Name: "test",
}
id := fmt.Sprintf("%s%012d", chPrefix, i)
name := fmt.Sprintf("test-%d", i)
ch := sdk.Channel{ID: id, Name: name}
cid, err := mainfluxSDK.CreateChannel(ch, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
@ -419,7 +439,7 @@ func TestUpdateChannel(t *testing.T) {
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateChannel(channel, token)
id, err := mainfluxSDK.CreateChannel(ch2, token)
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
cases := []struct {
@ -477,7 +497,7 @@ func TestDeleteChannel(t *testing.T) {
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateChannel(channel, token)
id, err := mainfluxSDK.CreateChannel(ch2, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {

View File

@ -29,14 +29,13 @@ const (
wrongValue = "wrong_value"
badID = "999"
emptyValue = ""
keyPrefix = "123e4567-e89b-12d3-a456-"
)
var (
metadata = map[string]interface{}{"meta": "data"}
metadata2 = map[string]interface{}{"meta": "data2"}
thing = sdk.Thing{ID: "001", Name: "test_device", Metadata: metadata}
th1 = sdk.Thing{ID: "fe6b4e92-cc98-425e-b0aa-000000000001", Name: "test1", Metadata: metadata}
th2 = sdk.Thing{ID: "fe6b4e92-cc98-425e-b0aa-000000000002", Name: "test2", Metadata: metadata}
emptyThing = sdk.Thing{}
)
@ -82,28 +81,28 @@ func TestCreateThing(t *testing.T) {
}{
{
desc: "create new thing",
thing: thing,
thing: th1,
token: token,
err: nil,
location: "001",
location: th1.ID,
},
{
desc: "create new empty thing",
thing: emptyThing,
token: token,
err: nil,
location: "002",
location: fmt.Sprintf("%s%012d", uuid.Prefix, 2),
},
{
desc: "create new thing with empty token",
thing: thing,
thing: th1,
token: "",
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
location: "",
},
{
desc: "create new thing with invalid token",
thing: thing,
thing: th1,
token: wrongValue,
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
location: "",
@ -131,8 +130,16 @@ func TestCreateThings(t *testing.T) {
mainfluxSDK := sdk.NewSDK(sdkConf)
things := []sdk.Thing{
sdk.Thing{ID: "001", Name: "1", Key: "1"},
sdk.Thing{ID: "002", Name: "2", Key: "2"},
th1,
th2,
}
thsExtID := []sdk.Thing{
{ID: th1.ID, Name: "1", Key: "1", Metadata: metadata},
{ID: th2.ID, Name: "2", Key: "2", Metadata: metadata},
}
thsWrongExtID := []sdk.Thing{
{ID: "b0aa-000000000001", Name: "1", Key: "1", Metadata: metadata},
{ID: "b0aa-000000000002", Name: "2", Key: "2", Metadata: metadata2},
}
cases := []struct {
@ -170,6 +177,20 @@ func TestCreateThings(t *testing.T) {
err: createError(sdk.ErrFailedCreation, http.StatusUnauthorized),
res: []sdk.Thing{},
},
{
desc: "create new things with external UUID",
things: thsExtID,
token: token,
err: nil,
res: things,
},
{
desc: "create new things with wrong external UUID",
things: thsWrongExtID,
token: token,
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
res: []sdk.Thing{},
},
}
for _, tc := range cases {
res, err := mainfluxSDK.CreateThings(tc.things, tc.token)
@ -193,9 +214,9 @@ func TestThing(t *testing.T) {
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateThing(thing, token)
id, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
thing.Key = fmt.Sprintf("%s%012d", keyPrefix, 2)
th1.Key = fmt.Sprintf("%s%012d", uuid.Prefix, 1)
cases := []struct {
desc string
@ -209,7 +230,7 @@ func TestThing(t *testing.T) {
thID: id,
token: token,
err: nil,
response: thing,
response: th1,
},
{
desc: "get non-existent thing",
@ -248,10 +269,12 @@ func TestThings(t *testing.T) {
mainfluxSDK := sdk.NewSDK(sdkConf)
for i := 1; i < 101; i++ {
th := sdk.Thing{ID: fmt.Sprintf("%03d", i), Name: "test_device", Metadata: metadata}
id := fmt.Sprintf("%s%012d", chPrefix, i)
name := fmt.Sprintf("test-%d", i)
th := sdk.Thing{ID: id, Name: name, Metadata: metadata}
_, err := mainfluxSDK.CreateThing(th, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th.Key = fmt.Sprintf("%s%012d", keyPrefix, 2*i)
th.Key = fmt.Sprintf("%s%012d", uuid.Prefix, i)
things = append(things, th)
}
@ -340,11 +363,13 @@ func TestThingsByChannel(t *testing.T) {
var thsDiscoNum = 1
var things []sdk.Thing
for i := 1; i < n+1; i++ {
id := fmt.Sprintf("%s%012d", chPrefix, i)
name := fmt.Sprintf("test-%d", i)
th := sdk.Thing{
ID: fmt.Sprintf("%03d", i),
Name: "test_device",
ID: id,
Name: name,
Metadata: metadata,
Key: fmt.Sprintf("%s%012d", keyPrefix, 2*i+1),
Key: fmt.Sprintf("%s%012d", uuid.Prefix, 2*i+1),
}
tid, err := mainfluxSDK.CreateThing(th, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
@ -467,9 +492,9 @@ func TestUpdateThing(t *testing.T) {
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateThing(thing, token)
id, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
thing.Name = "test2"
th1.Name = "test2"
cases := []struct {
desc string
@ -546,7 +571,7 @@ func TestDeleteThing(t *testing.T) {
}
mainfluxSDK := sdk.NewSDK(sdkConf)
id, err := mainfluxSDK.CreateThing(thing, token)
id, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
@ -614,13 +639,13 @@ func TestConnectThing(t *testing.T) {
}
mainfluxSDK := sdk.NewSDK(sdkConf)
thingID, err := mainfluxSDK.CreateThing(thing, token)
thingID, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID1, err := mainfluxSDK.CreateChannel(channel, token)
chanID1, err := mainfluxSDK.CreateChannel(ch2, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID2, err := mainfluxSDK.CreateChannel(channel, otherToken)
chanID2, err := mainfluxSDK.CreateChannel(ch3, otherToken)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
@ -715,13 +740,13 @@ func TestConnect(t *testing.T) {
}
mainfluxSDK := sdk.NewSDK(sdkConf)
thingID, err := mainfluxSDK.CreateThing(thing, token)
thingID, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID1, err := mainfluxSDK.CreateChannel(channel, token)
chanID1, err := mainfluxSDK.CreateChannel(ch2, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID2, err := mainfluxSDK.CreateChannel(channel, otherToken)
chanID2, err := mainfluxSDK.CreateChannel(ch3, otherToken)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {
@ -818,10 +843,10 @@ func TestDisconnectThing(t *testing.T) {
mainfluxSDK := sdk.NewSDK(sdkConf)
thingID, err := mainfluxSDK.CreateThing(thing, token)
thingID, err := mainfluxSDK.CreateThing(th1, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID1, err := mainfluxSDK.CreateChannel(channel, token)
chanID1, err := mainfluxSDK.CreateChannel(ch2, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
conIDs := sdk.ConnectionIDs{
@ -831,7 +856,7 @@ func TestDisconnectThing(t *testing.T) {
err = mainfluxSDK.Connect(conIDs, token)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
chanID2, err := mainfluxSDK.CreateChannel(channel, otherToken)
chanID2, err := mainfluxSDK.CreateChannel(ch2, otherToken)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
cases := []struct {

View File

@ -22,6 +22,7 @@ func createThingEndpoint(svc things.Service) endpoint.Endpoint {
th := things.Thing{
Key: req.Key,
ID: req.ID,
Name: req.Name,
Metadata: req.Metadata,
}
@ -52,6 +53,7 @@ func createThingsEndpoint(svc things.Service) endpoint.Endpoint {
th := things.Thing{
Name: tReq.Name,
Key: tReq.Key,
ID: tReq.ID,
Metadata: tReq.Metadata,
}
ths = append(ths, th)
@ -263,7 +265,11 @@ func createChannelEndpoint(svc things.Service) endpoint.Endpoint {
return nil, err
}
ch := things.Channel{Name: req.Name, Metadata: req.Metadata}
ch := things.Channel{
Name: req.Name,
ID: req.ID,
Metadata: req.Metadata}
saved, err := svc.CreateChannels(ctx, req.token, ch)
if err != nil {
return nil, err
@ -290,6 +296,7 @@ func createChannelsEndpoint(svc things.Service) endpoint.Endpoint {
ch := things.Channel{
Metadata: cReq.Metadata,
Name: cReq.Name,
ID: cReq.ID,
}
chs = append(chs, ch)
}

View File

@ -36,6 +36,7 @@ const (
nameKey = "name"
ascKey = "asc"
descKey = "desc"
prefix = "fe6b4e92-cc98-425e-b0aa-"
)
var (
@ -131,7 +132,7 @@ func TestCreateThing(t *testing.T) {
contentType: contentType,
auth: token,
status: http.StatusCreated,
location: "/things/001",
location: fmt.Sprintf("/things/%s%012d", uuid.Prefix, 1),
},
{
desc: "add thing with existing key",
@ -147,7 +148,7 @@ func TestCreateThing(t *testing.T) {
contentType: contentType,
auth: token,
status: http.StatusCreated,
location: "/things/002",
location: fmt.Sprintf("/things/%s%012d", uuid.Prefix, 3),
},
{
desc: "add thing with invalid auth token",
@ -766,7 +767,10 @@ func TestListThings(t *testing.T) {
data := []thingRes{}
for i := 0; i < 100; i++ {
ths, err := svc.CreateThings(context.Background(), token, thing)
id := fmt.Sprintf("%s%012d", prefix, i + 1)
thing1 := thing
thing1.ID = id
ths, err := svc.CreateThings(context.Background(), token, thing1)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th := ths[0]
data = append(data, thingRes{
@ -1003,7 +1007,8 @@ func TestSearchThings(t *testing.T) {
data := []thingRes{}
for i := 0; i < 100; i++ {
name := "name_" + fmt.Sprintf("%03d", i+1)
ths, err := svc.CreateThings(context.Background(), token, things.Thing{Name: name, Metadata: map[string]interface{}{"test": name}})
id := fmt.Sprintf("%s%012d", prefix, i + 1)
ths, err := svc.CreateThings(context.Background(), token, things.Thing{ID: id, Name: name, Metadata: map[string]interface{}{"test": name}})
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th := ths[0]
data = append(data, thingRes{
@ -1170,7 +1175,10 @@ func TestListThingsByChannel(t *testing.T) {
data := []thingRes{}
for i := 0; i < 101; i++ {
ths, err := svc.CreateThings(context.Background(), token, thing)
id := fmt.Sprintf("%s%012d", prefix, i + 1)
thing1 := thing
thing1.ID = id
ths, err := svc.CreateThings(context.Background(), token, thing1)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th := ths[0]
err = svc.Connect(context.Background(), token, []string{ch.ID}, []string{th.ID})
@ -1418,7 +1426,7 @@ func TestCreateChannel(t *testing.T) {
contentType: contentType,
auth: token,
status: http.StatusCreated,
location: "/channels/001",
location: fmt.Sprintf("/channels/%s%012d", uuid.Prefix, 1),
},
{
desc: "create new channel with invalid token",
@ -1450,7 +1458,7 @@ func TestCreateChannel(t *testing.T) {
contentType: contentType,
auth: token,
status: http.StatusCreated,
location: "/channels/002",
location: fmt.Sprintf("/channels/%s%012d", uuid.Prefix, 2),
},
{
desc: "create new channel with empty request",
@ -2021,7 +2029,10 @@ func TestListChannelsByThing(t *testing.T) {
channels := []channelRes{}
for i := 0; i < 101; i++ {
chs, err := svc.CreateChannels(context.Background(), token, channel)
id := fmt.Sprintf("%s%012d", prefix, i + 1)
channel1 := channel
channel1.ID = id
chs, err := svc.CreateChannels(context.Background(), token, channel1)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
ch := chs[0]
err = svc.Connect(context.Background(), token, []string{ch.ID}, []string{th.ID})

View File

@ -4,6 +4,7 @@
package http
import (
"github.com/gofrs/uuid"
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/things"
)
@ -24,14 +25,28 @@ type createThingReq struct {
token string
Name string `json:"name,omitempty"`
Key string `json:"key,omitempty"`
ID string `json:"id,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
func validateUUID(extID string) (err error) {
id, err := uuid.FromString(extID)
if id.String() != extID || err != nil {
return things.ErrMalformedEntity
}
return nil
}
func (req createThingReq) validate() error {
if req.token == "" {
return things.ErrUnauthorizedAccess
}
if req.ID != "" && validateUUID(req.ID) != nil {
return things.ErrMalformedEntity
}
if len(req.Name) > maxNameSize {
return things.ErrMalformedEntity
}
@ -54,6 +69,10 @@ func (req createThingsReq) validate() error {
}
for _, thing := range req.Things {
if thing.ID != "" && validateUUID(thing.ID) != nil {
return things.ErrMalformedEntity
}
if len(thing.Name) > maxNameSize {
return things.ErrMalformedEntity
}
@ -129,6 +148,7 @@ func (req updateKeyReq) validate() error {
type createChannelReq struct {
token string
Name string `json:"name,omitempty"`
ID string `json:"id,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
@ -137,6 +157,10 @@ func (req createChannelReq) validate() error {
return things.ErrUnauthorizedAccess
}
if req.ID != "" && validateUUID(req.ID) != nil {
return things.ErrMalformedEntity
}
if len(req.Name) > maxNameSize {
return things.ErrMalformedEntity
}
@ -159,6 +183,10 @@ func (req createChannelsReq) validate() error {
}
for _, channel := range req.Channels {
if channel.ID != "" && validateUUID(channel.ID) != nil {
return things.ErrMalformedEntity
}
if len(channel.Name) > maxNameSize {
return things.ErrMalformedEntity
}

View File

@ -69,12 +69,7 @@ func (svc authServiceMock) AddPolicy(ctx context.Context, in *mainflux.AddPolicy
return &mainflux.AddPolicyRes{}, things.ErrMalformedEntity
}
// Mock thingsRepository saves the thing ID after padding the ID by 3. (see things/mocks/things.go)
// Since we are adding policies within the Service layer, we are storing them as a full ID which is
// eventually not compatible with the one inside of the mock things repository. Therefore, we are
// getting last three part of the ID as below.
obj := in.GetObj()
obj = obj[len(obj)-3:]
svc.policies[in.GetSub()] = append(svc.policies[in.GetSub()], MockSubjectSet{Object: obj, Relation: in.GetAct()})
return &mainflux.AddPolicyRes{Authorized: true}, nil
}

View File

@ -6,7 +6,6 @@ package mocks
import (
"context"
"fmt"
"strconv"
"strings"
"sync"
@ -48,7 +47,9 @@ func (crm *channelRepositoryMock) Save(_ context.Context, channels ...things.Cha
for i := range channels {
crm.counter++
channels[i].ID = fmt.Sprintf("%03d", 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]
}
@ -136,7 +137,7 @@ func (crm *channelRepositoryMock) RetrieveByThing(_ context.Context, owner, thID
switch pm.Disconnected {
case false:
for _, co := range crm.cconns[thID] {
id, _ := strconv.ParseUint(co.ID, 10, 64)
id := parseID(co.ID)
if id >= first && id < last {
chs = append(chs, co)
}
@ -144,7 +145,7 @@ func (crm *channelRepositoryMock) RetrieveByThing(_ context.Context, owner, thID
default:
for _, ch := range crm.channels {
conn := false
id, _ := strconv.ParseUint(ch.ID, 10, 64)
id := parseID(ch.ID)
if id >= first && id < last {
for _, co := range crm.cconns[thID] {
if ch.ID == co.ID {

View File

@ -6,10 +6,13 @@ package mocks
import (
"fmt"
"sort"
"strconv"
"github.com/mainflux/mainflux/things"
)
const uuidLen = 36
// Since mocks will store data in map, and they need to resemble the real
// identifiers as much as possible, a key will be created as combination of
// owner and their own identifiers. This will allow searching either by
@ -83,3 +86,14 @@ func sortChannels(pm things.PageMetadata, chs []things.Channel) []things.Channel
return chs
}
func parseID(ID string) (id uint64) {
var serialNum string
if len(ID) == uuidLen {
serialNum = ID[len(ID)-6:]
}
id, _ = strconv.ParseUint(serialNum, 10, 64)
return
}

View File

@ -6,7 +6,6 @@ package mocks
import (
"context"
"fmt"
"strconv"
"strings"
"sync"
@ -55,7 +54,9 @@ func (trm *thingRepositoryMock) Save(_ context.Context, ths ...things.Thing) ([]
}
trm.counter++
ths[i].ID = fmt.Sprintf("%03d", 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]
}
@ -128,7 +129,7 @@ func (trm *thingRepositoryMock) RetrieveAll(_ context.Context, owner string, pm
// itself (see mocks/commons.go).
prefix := fmt.Sprintf("%s-", owner)
for k, v := range trm.things {
id, _ := strconv.ParseUint(v.ID, 10, 64)
id := parseID(v.ID)
if strings.HasPrefix(k, prefix) && id >= first && id < last {
ths = append(ths, v)
}
@ -167,7 +168,7 @@ func (trm *thingRepositoryMock) RetrieveByIDs(_ context.Context, thingIDs []stri
for _, id := range thingIDs {
suffix := fmt.Sprintf("-%s", id)
for k, v := range trm.things {
id, _ := strconv.ParseUint(v.ID, 10, 64)
id := parseID(v.ID)
if strings.HasSuffix(k, suffix) && id >= first && id < last {
items = append(items, v)
}
@ -205,7 +206,7 @@ func (trm *thingRepositoryMock) RetrieveByChannel(_ context.Context, owner, chID
switch pm.Disconnected {
case false:
for _, co := range trm.tconns[chID] {
id, _ := strconv.ParseUint(co.ID, 10, 64)
id := parseID(co.ID)
if id >= first && id < last {
ths = append(ths, co)
}
@ -213,7 +214,7 @@ func (trm *thingRepositoryMock) RetrieveByChannel(_ context.Context, owner, chID
default:
for _, th := range trm.things {
conn := false
id, _ := strconv.ParseUint(th.ID, 10, 64)
id := parseID(th.ID)
if id >= first && id < last {
for _, co := range trm.tconns[chID] {
if th.ID == co.ID {

View File

@ -76,7 +76,7 @@ func TestCreateThings(t *testing.T) {
key: token,
err: nil,
event: map[string]interface{}{
"id": "001",
"id": "123e4567-e89b-12d3-a456-000000000001",
"name": "a",
"owner": email,
"metadata": "{\"test\":\"test\"}",
@ -302,7 +302,7 @@ func TestCreateChannels(t *testing.T) {
key: token,
err: nil,
event: map[string]interface{}{
"id": "001",
"id": "123e4567-e89b-12d3-a456-000000000001",
"name": "a",
"metadata": "{\"test\":\"test\"}",
"owner": email,

View File

@ -192,6 +192,7 @@ func (ts *thingsService) CreateThings(ctx context.Context, token string, things
ths := []Thing{}
for _, thing := range things {
th, err := ts.createThing(ctx, &thing, res)
if err != nil {
return []Thing{}, err
}
@ -203,18 +204,24 @@ func (ts *thingsService) CreateThings(ctx context.Context, token string, things
// createThing saves the Thing and adds identity as an owner(Read, Write, Delete policies) of the Thing.
func (ts *thingsService) createThing(ctx context.Context, thing *Thing, identity *mainflux.UserIdentity) (Thing, error) {
thID, err := ts.idProvider.ID()
if err != nil {
return Thing{}, errors.Wrap(ErrCreateUUID, err)
}
thing.ID = thID
thing.Owner = identity.GetEmail()
if thing.Key == "" {
thing.Key, err = ts.idProvider.ID()
if thing.ID == "" {
id, err := ts.idProvider.ID()
if err != nil {
return Thing{}, errors.Wrap(ErrCreateUUID, err)
}
thing.ID = id
}
if thing.Key == "" {
key, err := ts.idProvider.ID()
if err != nil {
return Thing{}, errors.Wrap(ErrCreateUUID, err)
}
thing.Key = key
}
ths, err := ts.things.Save(ctx, *thing)
@ -401,11 +408,13 @@ func (ts *thingsService) CreateChannels(ctx context.Context, token string, chann
}
func (ts *thingsService) createChannel(ctx context.Context, channel *Channel, identity *mainflux.UserIdentity) (Channel, error) {
chID, err := ts.idProvider.ID()
if err != nil {
return Channel{}, errors.Wrap(ErrCreateUUID, err)
if channel.ID == "" {
chID, err := ts.idProvider.ID()
if err != nil {
return Channel{}, errors.Wrap(ErrCreateUUID, err)
}
channel.ID = chID
}
channel.ID = chID
channel.Owner = identity.GetEmail()
chs, err := ts.channels.Save(ctx, *channel)

View File

@ -26,11 +26,15 @@ const (
token = "token"
token2 = "token2"
n = uint64(10)
prefix = "fe6b4e92-cc98-425e-b0aa-"
)
var (
thing = things.Thing{Name: "test"}
channel = things.Channel{Name: "test"}
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 {
@ -48,6 +52,14 @@ func newService(tokens map[string]string) things.Service {
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})
@ -69,6 +81,18 @@ func TestCreateThings(t *testing.T) {
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 {
@ -79,7 +103,7 @@ func TestCreateThings(t *testing.T) {
func TestUpdateThing(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
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"}
@ -161,7 +185,7 @@ func TestUpdateKey(t *testing.T) {
func TestShareThing(t *testing.T) {
svc := newService(map[string]string{token: email, token2: email2})
ths, err := svc.CreateThings(context.Background(), token, thing)
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"}
@ -217,7 +241,7 @@ func TestShareThing(t *testing.T) {
func TestViewThing(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
th := ths[0]
@ -254,12 +278,11 @@ func TestListThings(t *testing.T) {
m := make(map[string]interface{})
m["serial"] = "123456"
thing.Metadata = m
thingList[0].Metadata = m
var ths []things.Thing
for i := uint64(0); i < n; i++ {
th := thing
th.Name = fmt.Sprintf("name-%d", i)
th := thingList[i]
ths = append(ths, th)
}
@ -382,8 +405,7 @@ func TestListThingsByChannel(t *testing.T) {
var ths []things.Thing
for i := uint64(0); i < n; i++ {
th := thing
th.Name = fmt.Sprintf("name-%d", i)
th := thingList[i]
ths = append(ths, th)
}
@ -555,7 +577,7 @@ func TestListThingsByChannel(t *testing.T) {
func TestRemoveThing(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
sth := ths[0]
@ -618,6 +640,18 @@ func TestCreateChannels(t *testing.T) {
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 {
@ -849,7 +883,7 @@ func TestListChannels(t *testing.T) {
func TestListChannelsByThing(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
th := ths[0]
@ -1075,7 +1109,7 @@ func TestRemoveChannel(t *testing.T) {
func TestConnect(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
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)
@ -1128,7 +1162,7 @@ func TestConnect(t *testing.T) {
func TestDisconnect(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
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)
@ -1191,7 +1225,7 @@ func TestDisconnect(t *testing.T) {
func TestCanAccessByKey(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
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))
@ -1234,7 +1268,7 @@ func TestCanAccessByKey(t *testing.T) {
func TestCanAccessByID(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing, thing)
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)
@ -1313,7 +1347,7 @@ func TestIsChannelOwner(t *testing.T) {
func TestIdentify(t *testing.T) {
svc := newService(map[string]string{token: email})
ths, err := svc.CreateThings(context.Background(), token, thing)
ths, err := svc.CreateThings(context.Background(), token, thingList[0])
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
th := ths[0]