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:
parent
309ef512cb
commit
7e9ab453d4
@ -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:
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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})
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user