mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-24 13:48:49 +08:00
MF-488 - Remove Thing type (app or device) (#718)
* MF-488 - Remove Thing type (app or device) Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Typo fix Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix reviews Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix reviews Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix reviews Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
This commit is contained in:
parent
44615c5ff0
commit
b97deb50b2
@ -10,7 +10,7 @@
|
||||
|
||||
Mainflux is modern, scalable, secure open source and patent-free IoT cloud platform written in Go.
|
||||
|
||||
It accepts user, device, and application connections over various network protocols (i.e. HTTP,
|
||||
It accepts user and thing connections over various network protocols (i.e. HTTP,
|
||||
MQTT, WebSocket, CoAP), thus making a seamless bridge between them. It is used as the IoT middleware
|
||||
for building complex IoT solutions.
|
||||
|
||||
|
@ -29,7 +29,7 @@ Enabling and disabling Thing (adding Thing to/from whitelist) is as simple as co
|
||||
|
||||
Switching between states `Active` and `Inactive` enables and disables Thing, respectively.
|
||||
|
||||
Thing configuration also contains the so-called `external ID` and `external key`. An external ID is a unique identifier of the device/app for the corresponding Thing. For example, the device MAC address is a good choice for external ID. External key is a secret key that is used for authentication during the bootstrapping procedure.
|
||||
Thing configuration also contains the so-called `external ID` and `external key`. An external ID is a unique identifier of corresponding Thing. For example, a device MAC address is a good choice for external ID. External key is a secret key that is used for authentication during the bootstrapping procedure.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
@ -16,11 +16,6 @@ import (
|
||||
mfsdk "github.com/mainflux/mainflux/sdk/go"
|
||||
)
|
||||
|
||||
const (
|
||||
thingType = "device"
|
||||
chanName = "channel"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotFound indicates a non-existent entity request.
|
||||
ErrNotFound = errors.New("non-existent entity")
|
||||
@ -332,7 +327,7 @@ func (bs bootstrapService) thing(key, id string) (mfsdk.Thing, error) {
|
||||
var err error
|
||||
|
||||
if id == "" {
|
||||
thingID, err = bs.sdk.CreateThing(mfsdk.Thing{Type: thingType}, key)
|
||||
thingID, err = bs.sdk.CreateThing(mfsdk.Thing{}, key)
|
||||
if err != nil {
|
||||
return mfsdk.Thing{}, err
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
swagger: "2.0"
|
||||
info:
|
||||
title: Mainflux Bootstrap service
|
||||
description: HTTP API for managing platform devices and applications configuration.
|
||||
description: HTTP API for managing platform things configuration.
|
||||
version: "1.0.0"
|
||||
consumes:
|
||||
- "application/json"
|
||||
|
@ -26,12 +26,12 @@ mainflux-cli users token john.doe@email.com password
|
||||
### System Provisioning
|
||||
#### Create Thing (type Device)
|
||||
```
|
||||
mainflux-cli things create '{"type":"device", "name":"myDevice"}' <user_auth_token>
|
||||
mainflux-cli things create '{"name":"myDevice"}' <user_auth_token>
|
||||
```
|
||||
|
||||
#### Create Thing (type Application)
|
||||
```
|
||||
mainflux-cli things create '{"type":"app", "name":"myDevice"}' <user_auth_token>
|
||||
mainflux-cli things create '{"name":"myDevice"}' <user_auth_token>
|
||||
```
|
||||
|
||||
#### Update Thing
|
||||
|
@ -22,8 +22,8 @@ import (
|
||||
|
||||
var errMalformedCSV = errors.New("malformed CSV")
|
||||
|
||||
func createThing(name, kind, token string) (mfxsdk.Thing, error) {
|
||||
id, err := sdk.CreateThing(mfxsdk.Thing{Name: name, Type: kind}, token)
|
||||
func createThing(name, token string) (mfxsdk.Thing, error) {
|
||||
id, err := sdk.CreateThing(mfxsdk.Thing{Name: name}, token)
|
||||
if err != nil {
|
||||
return mfxsdk.Thing{}, err
|
||||
}
|
||||
@ -36,7 +36,6 @@ func createThing(name, kind, token string) (mfxsdk.Thing, error) {
|
||||
m := mfxsdk.Thing{
|
||||
ID: id,
|
||||
Name: name,
|
||||
Type: kind,
|
||||
Key: t.Key,
|
||||
}
|
||||
|
||||
@ -87,12 +86,12 @@ var cmdProvision = []cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
if len(l) < 2 {
|
||||
if len(l) < 1 {
|
||||
logError(errMalformedCSV)
|
||||
return
|
||||
}
|
||||
|
||||
m, err := createThing(l[0], l[1], args[1])
|
||||
m, err := createThing(l[0], args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
@ -187,12 +186,8 @@ var cmdProvision = []cobra.Command{
|
||||
// Create things
|
||||
for i := 0; i < numThings; i++ {
|
||||
n := fmt.Sprintf("d%d", i)
|
||||
k := "device"
|
||||
if i%2 != 0 {
|
||||
k = "app"
|
||||
}
|
||||
|
||||
m, err := createThing(n, k, ut)
|
||||
m, err := createThing(n, ut)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
|
BIN
cmd/cli/cli
Executable file
BIN
cmd/cli/cli
Executable file
Binary file not shown.
@ -26,11 +26,8 @@ an access token. Once logged into the system, user can manage his resources (i.e
|
||||
things and channels) in CRUD fashion, and define access control policies by
|
||||
connecting them.
|
||||
|
||||
`Thing` represents devices and applications connected to Mainflux. There are
|
||||
two types of "things" supported at the moment: `device` and `app`. While device
|
||||
is used to represent any physical device connected to the platform, app represents
|
||||
any 3rd party service that uses the platform for message exchange with other
|
||||
"things".
|
||||
`Thing` represents devices (or applications) connected to Mainflux that uses the
|
||||
platform for message exchange with other "things".
|
||||
|
||||
`Channel` represents a communication channel. It serves as message topic that
|
||||
can be consumed by all of the things connected to it.
|
||||
|
@ -81,14 +81,9 @@ mainflux-cli users token john.doe@email.com password
|
||||
```
|
||||
|
||||
### System Provisioning
|
||||
#### Create Thing (type Device)
|
||||
#### Create Thing
|
||||
```
|
||||
mainflux-cli things create '{"type":"device", "name":"myDevice"}' <user_auth_token>
|
||||
```
|
||||
|
||||
#### Create Thing (type Application)
|
||||
```
|
||||
mainflux-cli things create '{"type":"app", "name":"myDevice"}' <user_auth_token>
|
||||
mainflux-cli things create '{"name":"myThing"}' <user_auth_token>
|
||||
```
|
||||
|
||||
#### Update Thing
|
||||
|
@ -266,18 +266,16 @@ Whenever thing is created, `things` service will generate new `create` event. Th
|
||||
event will have the following format:
|
||||
```
|
||||
1) "1555334740911-0"
|
||||
2) 1) "type"
|
||||
2) "device"
|
||||
3) "operation"
|
||||
4) "thing.create"
|
||||
5) "name"
|
||||
6) "d0"
|
||||
7) "id"
|
||||
8) "3c36273a-94ea-4802-84d6-a51de140112e"
|
||||
9) "owner"
|
||||
10) "john.doe@email.com"
|
||||
11) "metadata"
|
||||
12) "{}"
|
||||
2) 1) "operation"
|
||||
2) "thing.create"
|
||||
3) "name"
|
||||
4) "d0"
|
||||
5) "id"
|
||||
6) "3c36273a-94ea-4802-84d6-a51de140112e"
|
||||
7) "owner"
|
||||
8) "john.doe@email.com"
|
||||
9) "metadata"
|
||||
10) "{}"
|
||||
```
|
||||
|
||||
As you can see from this example, every odd field represents field name while every
|
||||
@ -296,8 +294,6 @@ This event will have the following format:
|
||||
4) "weio"
|
||||
5) "id"
|
||||
6) "3c36273a-94ea-4802-84d6-a51de140112e"
|
||||
7) "type"
|
||||
8) "device"
|
||||
```
|
||||
Note that thing update event will contain only those fields that were updated using
|
||||
update endpoint.
|
||||
@ -526,7 +522,6 @@ Example of connect event:
|
||||
6) "connect"
|
||||
7) "instance"
|
||||
8) "mqtt-adapter-1"
|
||||
|
||||
```
|
||||
|
||||
Example of disconnect event:
|
||||
|
@ -50,13 +50,11 @@ Output of the command is something like this:
|
||||
"id": "513d02d2-16c1-4f23-98be-9e12f8fee898",
|
||||
"key": "69590b3a-9d76-4baa-adae-9b5fec0ea14f",
|
||||
"name": "d0",
|
||||
"type": "device"
|
||||
},
|
||||
{
|
||||
"id": "bf78ca98-2fef-4cfc-9f26-e02da5ecdf67",
|
||||
"key": "840c1ea1-2e8d-4809-a6d3-3433a5c489d2",
|
||||
"name": "d1",
|
||||
"type": "app"
|
||||
}
|
||||
]
|
||||
|
||||
@ -106,4 +104,4 @@ mainflux-http | {"level":"info","message":"Method publish took 336.685µs to c
|
||||
mainflux-normalizer | {"level":"info","message":"Method normalize took 108.126µs to complete without errors.","ts":"2019-01-08T22:19:30.149500543Z"}
|
||||
```
|
||||
|
||||
This proves that messages have been well send through the system, via protocol adapter (`mainflux-http`) and `normalizer` service which corectly parsed messages.
|
||||
This proves that messages have been well send through the system, via protocol adapter (`mainflux-http`) and `normalizer` service which correctly parsed messages.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
Mainflux is modern, scalable, secure open source and patent-free IoT cloud platform written in Go.
|
||||
|
||||
It accepts user, device, and application connections over various network protocols (i.e. HTTP,
|
||||
It accepts user and thing connections over various network protocols (i.e. HTTP,
|
||||
MQTT, WebSocket, CoAP), thus making a seamless bridge between them. It is used as the IoT middleware
|
||||
for building complex IoT solutions.
|
||||
|
||||
|
@ -35,15 +35,14 @@ Response should look like this:
|
||||
Before proceeding, make sure that you have created a new account, and obtained
|
||||
an authorization key.
|
||||
|
||||
### Provisioning devices
|
||||
### Provisioning things
|
||||
|
||||
Devices are provisioned by executing request `POST /things`, with a
|
||||
`"type":"device"` specified in JSON payload. Note that you will also need
|
||||
`user_auth_token` in order to provision things (both devices and application)
|
||||
Things are provisioned by executing request `POST /things` with a JSON payload.
|
||||
Note that you will also need `user_auth_token` in order to provision things
|
||||
that belong to this particular user.
|
||||
|
||||
```
|
||||
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: <user_auth_token>" https://localhost/things -d '{"type":"device", "name":"weio"}'
|
||||
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: <user_auth_token>" https://localhost/things -d '{"name":"weio"}'
|
||||
```
|
||||
|
||||
Response will contain `Location` header whose value represents path to newly
|
||||
@ -57,26 +56,6 @@ Date: Tue, 10 Apr 2018 10:02:59 GMT
|
||||
Content-Length: 0
|
||||
```
|
||||
|
||||
### Provisioning applications
|
||||
|
||||
Applications are provisioned by executing HTTP request `POST /things`, with
|
||||
`"type":"app"` specified in JSON payload.
|
||||
|
||||
```
|
||||
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: <user_auth_token>" https://localhost/things -d '{"type":"app", "name":"myapp"}'
|
||||
```
|
||||
|
||||
Response will contain `Location` header whose value represents path to newly
|
||||
created thing (same as for devices):
|
||||
|
||||
```
|
||||
HTTP/1.1 201 Created
|
||||
Content-Type: application/json
|
||||
Location: /things/cb63f852-2d48-44f0-a0cf-e450496c6c92
|
||||
Date: Tue, 10 Apr 2018 10:33:17 GMT
|
||||
Content-Length: 0
|
||||
```
|
||||
|
||||
### Retrieving provisioned things
|
||||
|
||||
In order to retrieve data of provisioned things that is written in database, you
|
||||
@ -102,13 +81,11 @@ Content-Length: 1105
|
||||
"things": [
|
||||
{
|
||||
"id": "81380742-7116-4f6f-9800-14fe464f6773",
|
||||
"type": "device",
|
||||
"name": "weio",
|
||||
"key": "7aa91f7a-cbea-4fed-b427-07e029577590"
|
||||
},
|
||||
{
|
||||
"id": "cb63f852-2d48-44f0-a0cf-e450496c6c92",
|
||||
"type": "app",
|
||||
"name": "myapp",
|
||||
"key": "cbf02d60-72f2-4180-9f82-2c957db929d1"
|
||||
}
|
||||
@ -237,14 +214,12 @@ Response that you'll get should look like this:
|
||||
"things": [
|
||||
{
|
||||
"id": "3ffb3880-d1e6-4edd-acd9-4294d013f35b",
|
||||
"type": "device",
|
||||
"name": "d0",
|
||||
"key": "b1996995-237a-4552-94b2-83ec2e92a040",
|
||||
"metadata": "{}"
|
||||
},
|
||||
{
|
||||
"id": "94d166d6-6477-43dc-93b7-5c3707dbef1e",
|
||||
"type": "app",
|
||||
"name": "d1",
|
||||
"key": "e4588a68-6028-4740-9f12-c356796aebe8",
|
||||
"metadata": "{}"
|
||||
@ -281,7 +256,7 @@ Response that you'll get should look like this:
|
||||
}
|
||||
```
|
||||
|
||||
If you want to disconnect your device from the channel, send following request:
|
||||
If you want to disconnect your thing from the channel, send following request:
|
||||
|
||||
```
|
||||
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X DELETE -H "Authorization: <user_auth_token>" https://localhost/channels/<channel_id>/things/<thing_id>
|
||||
|
@ -16,7 +16,7 @@ import io.gatling.http.request.builder.HttpRequestBuilder.toActionBuilder
|
||||
final class CreateAndRetrieveThings extends TestCase {
|
||||
override def prepareAndExecute(): SetUp = {
|
||||
val token = authenticate()
|
||||
val thing = """{"type":"device", "name":"weio"}"""
|
||||
val thing = """{"name":"weio"}"""
|
||||
|
||||
val scn = scenario("create and retrieve things")
|
||||
.exec(http("create thing")
|
||||
|
@ -14,7 +14,7 @@ import scalaj.http.Http
|
||||
|
||||
abstract class PublishMessages extends TestCase {
|
||||
def makeThing(token: String): (String, String) = {
|
||||
val thing = """{"type":"device", "name":"weio"}"""
|
||||
val thing = """{"name":"weio"}"""
|
||||
|
||||
val id = Http(s"$ThingsURL/things")
|
||||
.postData(thing)
|
||||
|
@ -41,7 +41,7 @@ go get github.com/mainflux/mainflux
|
||||
|
||||
cd $GOPATH/src/github.com/mainflux/mainflux
|
||||
|
||||
# compile the app; make sure to set the proper GOOS value
|
||||
# compile the service; make sure to set the proper GOOS value
|
||||
make normalizer
|
||||
|
||||
# copy binary to bin
|
||||
|
@ -9,6 +9,7 @@ package cassandra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/readers"
|
||||
|
@ -1,3 +1,3 @@
|
||||
c1
|
||||
c2
|
||||
c3
|
||||
channel_1
|
||||
channel_2
|
||||
channel_3
|
||||
|
|
@ -1,8 +1,10 @@
|
||||
d1,device
|
||||
d2,device
|
||||
d3,device
|
||||
d4,device
|
||||
d5,device
|
||||
a1,app
|
||||
a2,app
|
||||
a3,app
|
||||
thing_1
|
||||
thing_2
|
||||
thing_3
|
||||
thing_4
|
||||
thing_5
|
||||
thing_6
|
||||
thing_7
|
||||
thing_8
|
||||
thing_9
|
||||
thing_10
|
||||
|
|
@ -7,7 +7,7 @@
|
||||
#
|
||||
|
||||
###
|
||||
# Provisions example user, device and channel on a clean Mainflux installation.
|
||||
# Provisions example user, thing and channel on a clean Mainflux installation.
|
||||
#
|
||||
# Expects a running Mainflux installation.
|
||||
#
|
||||
@ -33,11 +33,11 @@ curl -s -S --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "
|
||||
JWTTOKEN=$(curl -s -S --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" https://localhost/tokens -d '{"email":"'"$EMAIL"'", "password":"'"$PASSWORD"'"}' | grep -Po "token\":\"\K(.*)(?=\")")
|
||||
printf "JWT TOKEN for user is $JWTTOKEN \n"
|
||||
|
||||
#provision device
|
||||
printf "Provisioning device with name $DEVICE \n"
|
||||
curl -s -S --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: $JWTTOKEN" https://localhost/things -d '{"type":"device", "name":"'"$DEVICE"'"}'
|
||||
#provision thing
|
||||
printf "Provisioning thing with name $DEVICE \n"
|
||||
curl -s -S --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: $JWTTOKEN" https://localhost/things -d '{"name":"'"$DEVICE"'"}'
|
||||
|
||||
#get device token
|
||||
#get thing token
|
||||
DEVICETOKEN=$(curl -s -S --cacert docker/ssl/certs/mainflux-server.crt --insecure -H "Authorization: $JWTTOKEN" https://localhost/things/1 | grep -Po "key\":\"\K(.*)(?=\")")
|
||||
printf "Device token is $DEVICETOKEN \n"
|
||||
|
||||
@ -45,6 +45,6 @@ printf "Device token is $DEVICETOKEN \n"
|
||||
printf "Provisioning channel with name $CHANNEL \n"
|
||||
curl -s -S --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: $JWTTOKEN" https://localhost/channels -d '{"name":"'"$CHANNEL"'"}'
|
||||
|
||||
#connect device to channel
|
||||
printf "Connecting device to channel \n"
|
||||
#connect thing to channel
|
||||
printf "Connecting thing to channel \n"
|
||||
curl -s -S --cacert docker/ssl/certs/mainflux-server.crt --insecure -X PUT -H "Authorization: $JWTTOKEN" https://localhost/channels/1/things/1
|
||||
|
@ -244,7 +244,7 @@ func TestChannelsByThing(t *testing.T) {
|
||||
var channels []sdk.Channel
|
||||
mainfluxSDK := sdk.NewSDK(sdkConf)
|
||||
|
||||
th := sdk.Thing{Type: "device", Name: "test_device"}
|
||||
th := sdk.Thing{Name: "test_device"}
|
||||
tid, err := mainfluxSDK.CreateThing(th, token)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
|
@ -84,7 +84,6 @@ type User struct {
|
||||
// Thing represents mainflux thing.
|
||||
type Thing struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
|
@ -36,7 +36,7 @@ const (
|
||||
var (
|
||||
metadata = map[string]interface{}{"meta": "data"}
|
||||
metadata2 = map[string]interface{}{"meta": "data2"}
|
||||
thing = sdk.Thing{ID: "1", Type: "device", Name: "test_device", Metadata: metadata}
|
||||
thing = sdk.Thing{ID: "1", Name: "test_device", Metadata: metadata}
|
||||
emptyThing = sdk.Thing{}
|
||||
)
|
||||
|
||||
@ -87,6 +87,13 @@ func TestCreateThing(t *testing.T) {
|
||||
err: nil,
|
||||
location: "1",
|
||||
},
|
||||
{
|
||||
desc: "create new empty thing",
|
||||
thing: emptyThing,
|
||||
token: token,
|
||||
err: nil,
|
||||
location: "2",
|
||||
},
|
||||
{
|
||||
desc: "create new thing with empty token",
|
||||
thing: thing,
|
||||
@ -101,13 +108,6 @@ func TestCreateThing(t *testing.T) {
|
||||
err: sdk.ErrUnauthorized,
|
||||
location: "",
|
||||
},
|
||||
{
|
||||
desc: "create new epmty thing",
|
||||
thing: emptyThing,
|
||||
token: token,
|
||||
err: sdk.ErrInvalidArgs,
|
||||
location: "",
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
loc, err := mainfluxSDK.CreateThing(tc.thing, tc.token)
|
||||
@ -191,7 +191,7 @@ func TestThings(t *testing.T) {
|
||||
mainfluxSDK := sdk.NewSDK(sdkConf)
|
||||
for i := 1; i < 101; i++ {
|
||||
|
||||
th := sdk.Thing{ID: strconv.Itoa(i), Type: "device", Name: "test_device", Metadata: metadata}
|
||||
th := sdk.Thing{ID: strconv.Itoa(i), Name: "test_device", Metadata: metadata}
|
||||
mainfluxSDK.CreateThing(th, token)
|
||||
th.Key = fmt.Sprintf("%s%012d", keyPrefix, 2*i)
|
||||
things = append(things, th)
|
||||
@ -290,7 +290,7 @@ func TestThingsByChannel(t *testing.T) {
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
for i := 1; i < 101; i++ {
|
||||
th := sdk.Thing{Type: "device", Name: "test_device", Metadata: metadata}
|
||||
th := sdk.Thing{Name: "test_device", Metadata: metadata}
|
||||
tid, err := mainfluxSDK.CreateThing(th, token)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
th.ID = tid
|
||||
@ -408,7 +408,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
desc: "update existing thing",
|
||||
thing: sdk.Thing{
|
||||
ID: id,
|
||||
Type: "app",
|
||||
Name: "test_app",
|
||||
Metadata: metadata2,
|
||||
},
|
||||
@ -419,7 +418,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
desc: "update non-existing thing",
|
||||
thing: sdk.Thing{
|
||||
ID: "0",
|
||||
Type: "device",
|
||||
Name: "test_device",
|
||||
Metadata: metadata,
|
||||
},
|
||||
@ -430,7 +428,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
desc: "update channel with invalid id",
|
||||
thing: sdk.Thing{
|
||||
ID: "",
|
||||
Type: "device",
|
||||
Name: "test_device",
|
||||
Metadata: metadata,
|
||||
},
|
||||
@ -441,7 +438,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
desc: "update channel with invalid token",
|
||||
thing: sdk.Thing{
|
||||
ID: id,
|
||||
Type: "app",
|
||||
Name: "test_app",
|
||||
Metadata: metadata2,
|
||||
},
|
||||
@ -452,7 +448,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
desc: "update channel with empty token",
|
||||
thing: sdk.Thing{
|
||||
ID: id,
|
||||
Type: "app",
|
||||
Name: "test_app",
|
||||
Metadata: metadata2,
|
||||
},
|
||||
|
@ -1,10 +1,9 @@
|
||||
# Things
|
||||
|
||||
Things service provides an HTTP API for managing platform resources: devices,
|
||||
applications and channels. Through this API clients are able to do the following
|
||||
actions:
|
||||
Things service provides an HTTP API for managing platform resources: things and channels.
|
||||
Through this API clients are able to do the following actions:
|
||||
|
||||
- provision new things (i.e. devices & applications)
|
||||
- provision new things
|
||||
- create new channels
|
||||
- "connect" things into the channels
|
||||
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
const wrongID = ""
|
||||
|
||||
var (
|
||||
thing = things.Thing{Type: "app", Name: "test_app", Metadata: map[string]interface{}{"test": "test"}}
|
||||
thing = things.Thing{Name: "test_app", Metadata: map[string]interface{}{"test": "test"}}
|
||||
channel = things.Channel{Name: "test", Metadata: map[string]interface{}{"test": "test"}}
|
||||
)
|
||||
|
||||
|
@ -23,7 +23,6 @@ func addThingEndpoint(svc things.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
thing := things.Thing{
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
@ -50,7 +49,6 @@ func updateThingEndpoint(svc things.Service) endpoint.Endpoint {
|
||||
|
||||
thing := things.Thing{
|
||||
ID: req.id,
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
Metadata: req.Metadata,
|
||||
}
|
||||
@ -80,7 +78,6 @@ func viewThingEndpoint(svc things.Service) endpoint.Endpoint {
|
||||
res := viewThingRes{
|
||||
ID: thing.ID,
|
||||
Owner: thing.Owner,
|
||||
Type: thing.Type,
|
||||
Name: thing.Name,
|
||||
Key: thing.Key,
|
||||
Metadata: thing.Metadata,
|
||||
@ -114,7 +111,6 @@ func listThingsEndpoint(svc things.Service) endpoint.Endpoint {
|
||||
view := viewThingRes{
|
||||
ID: thing.ID,
|
||||
Owner: thing.Owner,
|
||||
Type: thing.Type,
|
||||
Name: thing.Name,
|
||||
Key: thing.Key,
|
||||
Metadata: thing.Metadata,
|
||||
@ -151,7 +147,6 @@ func listThingsByChannelEndpoint(svc things.Service) endpoint.Endpoint {
|
||||
view := viewThingRes{
|
||||
ID: thing.ID,
|
||||
Owner: thing.Owner,
|
||||
Type: thing.Type,
|
||||
Key: thing.Key,
|
||||
Name: thing.Name,
|
||||
Metadata: thing.Metadata,
|
||||
|
@ -35,7 +35,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
thing = things.Thing{Type: "app", Name: "test_app", Metadata: map[string]interface{}{"test": "data"}}
|
||||
thing = things.Thing{Name: "test_app", Metadata: map[string]interface{}{"test": "data"}}
|
||||
channel = things.Channel{Name: "test", Metadata: map[string]interface{}{"test": "data"}}
|
||||
)
|
||||
|
||||
@ -90,7 +90,6 @@ func TestAddThing(t *testing.T) {
|
||||
defer ts.Close()
|
||||
|
||||
data := toJSON(thing)
|
||||
invalidData := toJSON(things.Thing{Type: "foo"})
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@ -109,12 +108,12 @@ func TestAddThing(t *testing.T) {
|
||||
location: "/things/1",
|
||||
},
|
||||
{
|
||||
desc: "add thing with invalid data",
|
||||
req: invalidData,
|
||||
desc: "add thing with empty JSON request",
|
||||
req: "{}",
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
location: "",
|
||||
status: http.StatusCreated,
|
||||
location: "/things/2",
|
||||
},
|
||||
{
|
||||
desc: "add thing with invalid auth token",
|
||||
@ -140,14 +139,6 @@ func TestAddThing(t *testing.T) {
|
||||
status: http.StatusBadRequest,
|
||||
location: "",
|
||||
},
|
||||
{
|
||||
desc: "add thing with empty JSON request",
|
||||
req: "{}",
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
location: "",
|
||||
},
|
||||
{
|
||||
desc: "add thing with empty request",
|
||||
req: "",
|
||||
@ -190,7 +181,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
defer ts.Close()
|
||||
|
||||
data := toJSON(thing)
|
||||
invalidData := toJSON(things.Thing{Type: "foo"})
|
||||
sth, _ := svc.AddThing(token, thing)
|
||||
|
||||
cases := []struct {
|
||||
@ -209,6 +199,14 @@ func TestUpdateThing(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "update thing with empty JSON request",
|
||||
req: "{}",
|
||||
id: sth.ID,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "update non-existent thing",
|
||||
req: data,
|
||||
@ -217,14 +215,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
desc: "update thing with invalid data",
|
||||
req: invalidData,
|
||||
id: sth.ID,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "update thing with invalid id",
|
||||
req: data,
|
||||
@ -257,14 +247,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "update thing with empty JSON request",
|
||||
req: "{}",
|
||||
id: sth.ID,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "update thing with empty request",
|
||||
req: "",
|
||||
@ -308,7 +290,6 @@ func TestViewThing(t *testing.T) {
|
||||
|
||||
thres := thingRes{
|
||||
ID: sth.ID,
|
||||
Type: sth.Type,
|
||||
Name: sth.Name,
|
||||
Key: sth.Key,
|
||||
Metadata: sth.Metadata,
|
||||
@ -387,7 +368,6 @@ func TestListThings(t *testing.T) {
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
thres := thingRes{
|
||||
ID: sth.ID,
|
||||
Type: sth.Type,
|
||||
Name: sth.Name,
|
||||
Key: sth.Key,
|
||||
Metadata: sth.Metadata,
|
||||
@ -535,7 +515,6 @@ func TestListThingsByChannel(t *testing.T) {
|
||||
|
||||
thres := thingRes{
|
||||
ID: sth.ID,
|
||||
Type: sth.Type,
|
||||
Name: sth.Name,
|
||||
Key: sth.Key,
|
||||
Metadata: sth.Metadata,
|
||||
@ -1540,7 +1519,6 @@ func TestDisconnnect(t *testing.T) {
|
||||
|
||||
type thingRes struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Key string `json:"key"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
|
@ -29,7 +29,6 @@ func (req identityReq) validate() error {
|
||||
|
||||
type addThingReq struct {
|
||||
key string
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
@ -39,17 +38,12 @@ func (req addThingReq) validate() error {
|
||||
return things.ErrUnauthorizedAccess
|
||||
}
|
||||
|
||||
if req.Type == "" {
|
||||
return things.ErrMalformedEntity
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type updateThingReq struct {
|
||||
key string
|
||||
id string
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
@ -59,7 +53,7 @@ func (req updateThingReq) validate() error {
|
||||
return things.ErrUnauthorizedAccess
|
||||
}
|
||||
|
||||
if req.id == "" || req.Type == "" {
|
||||
if req.id == "" {
|
||||
return things.ErrMalformedEntity
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,7 @@ func TestIdentityReqValidation(t *testing.T) {
|
||||
|
||||
func TestAddThingReqValidation(t *testing.T) {
|
||||
key := uuid.NewV4().String()
|
||||
valid := things.Thing{Type: "app"}
|
||||
invalid := things.Thing{ID: "0", Type: ""}
|
||||
valid := things.Thing{}
|
||||
|
||||
cases := map[string]struct {
|
||||
thing things.Thing
|
||||
@ -58,18 +57,12 @@ func TestAddThingReqValidation(t *testing.T) {
|
||||
thing: valid,
|
||||
key: "", err: things.ErrUnauthorizedAccess,
|
||||
},
|
||||
"empty thing type": {
|
||||
thing: invalid,
|
||||
key: key,
|
||||
err: things.ErrMalformedEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
req := addThingReq{
|
||||
key: tc.key,
|
||||
Name: tc.thing.Name,
|
||||
Type: tc.thing.Type,
|
||||
Metadata: tc.thing.Metadata,
|
||||
}
|
||||
|
||||
@ -80,8 +73,7 @@ func TestAddThingReqValidation(t *testing.T) {
|
||||
|
||||
func TestUpdateThingReqValidation(t *testing.T) {
|
||||
key := uuid.NewV4().String()
|
||||
valid := things.Thing{ID: "1", Type: "app"}
|
||||
invalid := things.Thing{ID: "0", Type: ""}
|
||||
valid := things.Thing{ID: "1"}
|
||||
|
||||
cases := map[string]struct {
|
||||
thing things.Thing
|
||||
@ -101,12 +93,6 @@ func TestUpdateThingReqValidation(t *testing.T) {
|
||||
key: "",
|
||||
err: things.ErrUnauthorizedAccess,
|
||||
},
|
||||
"empty thing type": {
|
||||
thing: invalid,
|
||||
id: valid.ID,
|
||||
key: key,
|
||||
err: things.ErrMalformedEntity,
|
||||
},
|
||||
"empty thing id": {
|
||||
thing: valid,
|
||||
id: "",
|
||||
@ -120,7 +106,6 @@ func TestUpdateThingReqValidation(t *testing.T) {
|
||||
key: tc.key,
|
||||
id: tc.id,
|
||||
Name: tc.thing.Name,
|
||||
Type: tc.thing.Type,
|
||||
Metadata: tc.thing.Metadata,
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,6 @@ func (res thingRes) Empty() bool {
|
||||
type viewThingRes struct {
|
||||
ID string `json:"id"`
|
||||
Owner string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Key string `json:"key"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
|
@ -216,7 +216,6 @@ func TestMultiChannelRetrievalByThing(t *testing.T) {
|
||||
tid, err := thingRepo.Save(things.Thing{
|
||||
ID: idp.ID(),
|
||||
Owner: email,
|
||||
Type: "device",
|
||||
})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
n := uint64(10)
|
||||
|
@ -55,7 +55,6 @@ func migrateDB(db *sqlx.DB) error {
|
||||
`CREATE TABLE IF NOT EXISTS things (
|
||||
id UUID,
|
||||
owner VARCHAR(254),
|
||||
type VARCHAR(10) NOT NULL,
|
||||
key CHAR(36) UNIQUE NOT NULL,
|
||||
name TEXT,
|
||||
metadata JSON,
|
||||
|
@ -32,8 +32,8 @@ func NewThingRepository(db *sqlx.DB, log logger.Logger) things.ThingRepository {
|
||||
}
|
||||
|
||||
func (tr thingRepository) Save(thing things.Thing) (string, error) {
|
||||
q := `INSERT INTO things (id, owner, type, name, key, metadata)
|
||||
VALUES (:id, :owner, :type, :name, :key, :metadata);`
|
||||
q := `INSERT INTO things (id, owner, name, key, metadata)
|
||||
VALUES (:id, :owner, :name, :key, :metadata);`
|
||||
|
||||
dbth, err := toDBThing(thing)
|
||||
if err != nil {
|
||||
@ -84,7 +84,7 @@ func (tr thingRepository) Update(thing things.Thing) error {
|
||||
}
|
||||
|
||||
func (tr thingRepository) RetrieveByID(owner, id string) (things.Thing, error) {
|
||||
q := `SELECT name, type, key, metadata FROM things WHERE id = $1 AND owner = $2;`
|
||||
q := `SELECT name, key, metadata FROM things WHERE id = $1 AND owner = $2;`
|
||||
|
||||
dbth := dbThing{
|
||||
ID: id,
|
||||
@ -119,7 +119,7 @@ func (tr thingRepository) RetrieveByKey(key string) (string, error) {
|
||||
}
|
||||
|
||||
func (tr thingRepository) RetrieveAll(owner string, offset, limit uint64) things.ThingsPage {
|
||||
q := `SELECT id, name, type, key, metadata FROM things
|
||||
q := `SELECT id, name, key, metadata FROM things
|
||||
WHERE owner = :owner ORDER BY id LIMIT :limit OFFSET :offset;`
|
||||
|
||||
params := map[string]interface{}{
|
||||
@ -173,7 +173,7 @@ func (tr thingRepository) RetrieveAll(owner string, offset, limit uint64) things
|
||||
}
|
||||
|
||||
func (tr thingRepository) RetrieveByChannel(owner, channel string, offset, limit uint64) things.ThingsPage {
|
||||
q := `SELECT id, type, name, key, metadata
|
||||
q := `SELECT id, name, key, metadata
|
||||
FROM things th
|
||||
INNER JOIN connections co
|
||||
ON th.id = co.thing_id
|
||||
@ -248,7 +248,6 @@ func (tr thingRepository) Remove(owner, id string) error {
|
||||
type dbThing struct {
|
||||
ID string `db:"id"`
|
||||
Owner string `db:"owner"`
|
||||
Type string `db:"type"`
|
||||
Name string `db:"name"`
|
||||
Key string `db:"key"`
|
||||
Metadata string `db:"metadata"`
|
||||
@ -263,7 +262,6 @@ func toDBThing(th things.Thing) (dbThing, error) {
|
||||
return dbThing{
|
||||
ID: th.ID,
|
||||
Owner: th.Owner,
|
||||
Type: th.Type,
|
||||
Name: th.Name,
|
||||
Key: th.Key,
|
||||
Metadata: string(data),
|
||||
@ -279,7 +277,6 @@ func toThing(dbth dbThing) (things.Thing, error) {
|
||||
return things.Thing{
|
||||
ID: dbth.ID,
|
||||
Owner: dbth.Owner,
|
||||
Type: dbth.Type,
|
||||
Name: dbth.Name,
|
||||
Key: dbth.Key,
|
||||
Metadata: metadata,
|
||||
|
@ -34,7 +34,6 @@ var (
|
||||
type createThingEvent struct {
|
||||
id string
|
||||
owner string
|
||||
kind string
|
||||
name string
|
||||
metadata map[string]interface{}
|
||||
}
|
||||
@ -43,7 +42,6 @@ func (cte createThingEvent) Encode() map[string]interface{} {
|
||||
val := map[string]interface{}{
|
||||
"id": cte.id,
|
||||
"owner": cte.owner,
|
||||
"type": cte.kind,
|
||||
"operation": thingCreate,
|
||||
}
|
||||
|
||||
@ -65,7 +63,6 @@ func (cte createThingEvent) Encode() map[string]interface{} {
|
||||
|
||||
type updateThingEvent struct {
|
||||
id string
|
||||
kind string
|
||||
name string
|
||||
metadata map[string]interface{}
|
||||
}
|
||||
@ -73,7 +70,6 @@ type updateThingEvent struct {
|
||||
func (ute updateThingEvent) Encode() map[string]interface{} {
|
||||
val := map[string]interface{}{
|
||||
"id": ute.id,
|
||||
"type": ute.kind,
|
||||
"operation": thingUpdate,
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,6 @@ func (es eventStore) AddThing(key string, thing things.Thing) (things.Thing, err
|
||||
event := createThingEvent{
|
||||
id: sth.ID,
|
||||
owner: sth.Owner,
|
||||
kind: sth.Type,
|
||||
name: sth.Name,
|
||||
metadata: sth.Metadata,
|
||||
}
|
||||
@ -63,7 +62,6 @@ func (es eventStore) UpdateThing(key string, thing things.Thing) error {
|
||||
|
||||
event := updateThingEvent{
|
||||
id: thing.ID,
|
||||
kind: thing.Type,
|
||||
name: thing.Name,
|
||||
metadata: thing.Metadata,
|
||||
}
|
||||
|
@ -67,7 +67,6 @@ func TestAddThing(t *testing.T) {
|
||||
{
|
||||
desc: "create thing successfully",
|
||||
thing: things.Thing{
|
||||
Type: "app",
|
||||
Name: "a",
|
||||
Metadata: map[string]interface{}{"test": "test"},
|
||||
},
|
||||
@ -77,18 +76,10 @@ func TestAddThing(t *testing.T) {
|
||||
"id": "1",
|
||||
"name": "a",
|
||||
"owner": email,
|
||||
"type": "app",
|
||||
"metadata": "{\"test\":\"test\"}",
|
||||
"operation": thingCreate,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "create invalid thing",
|
||||
thing: things.Thing{Type: "a", Name: "a"},
|
||||
key: token,
|
||||
err: things.ErrMalformedEntity,
|
||||
event: nil,
|
||||
},
|
||||
}
|
||||
|
||||
lastID := "0"
|
||||
@ -118,7 +109,7 @@ func TestUpdateThing(t *testing.T) {
|
||||
|
||||
svc := newService(map[string]string{token: email})
|
||||
// Create thing without sending event.
|
||||
th := things.Thing{Type: "app", Name: "a", Metadata: map[string]interface{}{"test": "test"}}
|
||||
th := things.Thing{Name: "a", Metadata: map[string]interface{}{"test": "test"}}
|
||||
sth, err := svc.AddThing(token, th)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
|
||||
@ -135,7 +126,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
desc: "update existing thing successfully",
|
||||
thing: things.Thing{
|
||||
ID: sth.ID,
|
||||
Type: "app",
|
||||
Name: "a",
|
||||
Metadata: map[string]interface{}{"test": "test"},
|
||||
},
|
||||
@ -144,22 +134,10 @@ func TestUpdateThing(t *testing.T) {
|
||||
event: map[string]interface{}{
|
||||
"id": sth.ID,
|
||||
"name": "a",
|
||||
"type": "app",
|
||||
"metadata": "{\"test\":\"test\"}",
|
||||
"operation": thingUpdate,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "update invalid thing",
|
||||
thing: things.Thing{
|
||||
ID: strconv.FormatUint(math.MaxUint64, 10),
|
||||
Type: "a",
|
||||
Name: "a",
|
||||
},
|
||||
key: token,
|
||||
err: things.ErrMalformedEntity,
|
||||
event: nil,
|
||||
},
|
||||
}
|
||||
|
||||
lastID := "0"
|
||||
@ -189,7 +167,7 @@ func TestViewThing(t *testing.T) {
|
||||
|
||||
svc := newService(map[string]string{token: email})
|
||||
// Create thing without sending event.
|
||||
sth, err := svc.AddThing(token, things.Thing{Type: "app", Name: "a"})
|
||||
sth, err := svc.AddThing(token, things.Thing{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
|
||||
essvc := redis.NewEventStoreMiddleware(svc, redisClient)
|
||||
@ -204,7 +182,7 @@ func TestListThings(t *testing.T) {
|
||||
|
||||
svc := newService(map[string]string{token: email})
|
||||
// Create thing without sending event.
|
||||
_, err := svc.AddThing(token, things.Thing{Type: "app", Name: "a"})
|
||||
_, err := svc.AddThing(token, things.Thing{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
|
||||
essvc := redis.NewEventStoreMiddleware(svc, redisClient)
|
||||
@ -219,7 +197,7 @@ func TestListThingsByChannel(t *testing.T) {
|
||||
|
||||
svc := newService(map[string]string{token: email})
|
||||
// Create thing without sending event.
|
||||
sth, err := svc.AddThing(token, things.Thing{Type: "app", Name: "a"})
|
||||
sth, err := svc.AddThing(token, things.Thing{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
sch, err := svc.CreateChannel(token, things.Channel{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
@ -238,7 +216,7 @@ func TestRemoveThing(t *testing.T) {
|
||||
|
||||
svc := newService(map[string]string{token: email})
|
||||
// Create thing without sending event.
|
||||
sth, err := svc.AddThing(token, things.Thing{Type: "app", Name: "a"})
|
||||
sth, err := svc.AddThing(token, things.Thing{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
|
||||
svc = redis.NewEventStoreMiddleware(svc, redisClient)
|
||||
@ -450,7 +428,7 @@ func TestListChannelsByThing(t *testing.T) {
|
||||
|
||||
svc := newService(map[string]string{token: email})
|
||||
// Create thing without sending event.
|
||||
sth, err := svc.AddThing(token, things.Thing{Type: "app", Name: "a"})
|
||||
sth, err := svc.AddThing(token, things.Thing{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
sch, err := svc.CreateChannel(token, things.Channel{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
@ -527,7 +505,7 @@ func TestConnectEvent(t *testing.T) {
|
||||
|
||||
svc := newService(map[string]string{token: email})
|
||||
// Create thing and channel that will be connected.
|
||||
sth, err := svc.AddThing(token, things.Thing{Type: "device", Name: "a"})
|
||||
sth, err := svc.AddThing(token, things.Thing{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
sch, err := svc.CreateChannel(token, things.Channel{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
@ -591,7 +569,7 @@ func TestDisconnectEvent(t *testing.T) {
|
||||
|
||||
svc := newService(map[string]string{token: email})
|
||||
// Create thing and channel that will be connected.
|
||||
sth, err := svc.AddThing(token, things.Thing{Type: "device", Name: "a"})
|
||||
sth, err := svc.AddThing(token, things.Thing{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
sch, err := svc.CreateChannel(token, things.Channel{Name: "a"})
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error %s", err))
|
||||
|
@ -26,7 +26,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
thing = things.Thing{Type: "app", Name: "test"}
|
||||
thing = things.Thing{Name: "test"}
|
||||
channel = things.Channel{Name: "test"}
|
||||
)
|
||||
|
||||
@ -52,29 +52,17 @@ func TestAddThing(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "add new app",
|
||||
thing: things.Thing{Type: "app", Name: "a"},
|
||||
key: token,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "add new device",
|
||||
thing: things.Thing{Type: "device", Name: "b"},
|
||||
desc: "add new thing",
|
||||
thing: things.Thing{Name: "a"},
|
||||
key: token,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "add thing with wrong credentials",
|
||||
thing: things.Thing{Type: "app", Name: "d"},
|
||||
thing: things.Thing{Name: "d"},
|
||||
key: wrongValue,
|
||||
err: things.ErrUnauthorizedAccess,
|
||||
},
|
||||
{
|
||||
desc: "add thing with invalid type",
|
||||
thing: things.Thing{Type: "invalid", Name: "d"},
|
||||
key: wrongValue,
|
||||
err: things.ErrMalformedEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@ -86,7 +74,7 @@ func TestAddThing(t *testing.T) {
|
||||
func TestUpdateThing(t *testing.T) {
|
||||
svc := newService(map[string]string{token: email})
|
||||
saved, _ := svc.AddThing(token, thing)
|
||||
other := things.Thing{ID: wrongID, Type: "app", Key: "x"}
|
||||
other := things.Thing{ID: wrongID, Key: "x"}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@ -112,12 +100,6 @@ func TestUpdateThing(t *testing.T) {
|
||||
key: token,
|
||||
err: things.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "update thing with invalid type",
|
||||
thing: things.Thing{Type: "invalid", Name: "d"},
|
||||
key: wrongValue,
|
||||
err: things.ErrMalformedEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
@ -1,7 +1,7 @@
|
||||
swagger: "2.0"
|
||||
info:
|
||||
title: Mainflux things service
|
||||
description: HTTP API for managing platform devices, applications and channels.
|
||||
description: HTTP API for managing platform things and channels.
|
||||
version: "1.0.0"
|
||||
consumes:
|
||||
- "application/json"
|
||||
@ -262,7 +262,7 @@ paths:
|
||||
summary: Removes a channel
|
||||
description: |
|
||||
Removes a channel. The service will ensure that the subscribed apps and
|
||||
devices are unsubscribed from the removed channel.
|
||||
things are unsubscribed from the removed channel.
|
||||
tags:
|
||||
- channels
|
||||
parameters:
|
||||
@ -448,12 +448,6 @@ definitions:
|
||||
id:
|
||||
type: string
|
||||
description: Unique thing identifier generated by the service.
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- app
|
||||
- device
|
||||
description: Type of the thing.
|
||||
name:
|
||||
type: string
|
||||
description: Free-form thing name.
|
||||
@ -470,12 +464,6 @@ definitions:
|
||||
ThingReq:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- app
|
||||
- device
|
||||
description: Type of the thing.
|
||||
name:
|
||||
type: string
|
||||
description: Free-form thing name.
|
||||
|
@ -7,14 +7,11 @@
|
||||
|
||||
package things
|
||||
|
||||
import "strings"
|
||||
|
||||
// Thing represents a Mainflux thing. Each thing is owned by one user, and
|
||||
// it is assigned with the unique identifier and (temporary) access key.
|
||||
type Thing struct {
|
||||
ID string
|
||||
Owner string
|
||||
Type string
|
||||
Name string
|
||||
Key string
|
||||
Metadata map[string]interface{}
|
||||
@ -27,17 +24,8 @@ type ThingsPage struct {
|
||||
Things []Thing
|
||||
}
|
||||
|
||||
var thingTypes = map[string]bool{
|
||||
"app": true,
|
||||
"device": true,
|
||||
}
|
||||
|
||||
// Validate returns an error if thing representation is invalid.
|
||||
func (c *Thing) Validate() error {
|
||||
if c.Type = strings.ToLower(c.Type); !thingTypes[c.Type] {
|
||||
return ErrMalformedEntity
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ go get github.com/mainflux/mainflux
|
||||
|
||||
cd $GOPATH/src/github.com/mainflux/mainflux
|
||||
|
||||
# compile the app
|
||||
# compile the service
|
||||
make users
|
||||
|
||||
# copy binary to bin
|
||||
|
Loading…
x
Reference in New Issue
Block a user