NOISSUE - Remove SuperMQ duplicates (#23)

* Update docker-compose to use SuperMQ

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Remove duplicate services

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Update Bootstrap

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Update other services to use SMQ

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Switch config prefix to SMQ

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Remove leftovers

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Remove duplicate interface definitions

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Remove unused actions

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Remove unused API docs

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Resolve linter comments

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

* Fix provision

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>

---------

Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>
This commit is contained in:
Dušan Borovčanin
2024-12-31 11:04:17 +01:00
committed by GitHub
parent 57c3ecb175
commit 3bbb25bd64
699 changed files with 4836 additions and 130238 deletions
-411
View File
@@ -1,411 +0,0 @@
# Magistrala CLI
## Build
From the project root:
```bash
make cli
```
## Usage
### Service
#### Get Magistrala Services Health Check
```bash
magistrala-cli health <service>
```
### Users management
#### Create User
```bash
magistrala-cli users create <user_name> <user_email> <user_password>
magistrala-cli users create <user_name> <user_email> <user_password> <user_token>
```
#### Login User
```bash
magistrala-cli users token <user_email> <user_password>
```
#### Get User
```bash
magistrala-cli users get <user_id> <user_token>
```
#### Get Users
```bash
magistrala-cli users get all <user_token>
```
#### Update User Metadata
```bash
magistrala-cli users update <user_id> '{"name":"value1", "metadata":{"value2": "value3"}}' <user_token>
```
#### Update User Password
```bash
magistrala-cli users password <old_password> <password> <user_token>
```
#### Enable User
```bash
magistrala-cli users enable <user_id> <user_token>
```
#### Disable User
```bash
magistrala-cli users disable <user_id> <user_token>
```
### System Provisioning
#### Create Thing
```bash
magistrala-cli things create '{"name":"myThing"}' <user_token>
```
#### Create Thing with metadata
```bash
magistrala-cli things create '{"name":"myThing", "metadata": {"key1":"value1"}}' <user_token>
```
#### Bulk Provision Things
```bash
magistrala-cli provision things <file> <user_token>
```
- `file` - A CSV or JSON file containing thing names (must have extension `.csv` or `.json`)
- `user_token` - A valid user auth token for the current system
An example CSV file might be:
```csv
thing1,
thing2,
thing3,
```
in which the first column is the thing's name.
A comparable JSON file would be
```json
[
{
"name": "<thing1_name>",
"status": "enabled"
},
{
"name": "<thing2_name>",
"status": "disabled"
},
{
"name": "<thing3_name>",
"status": "enabled",
"credentials": {
"identity": "<thing3_identity>",
"secret": "<thing3_secret>"
}
}
]
```
With JSON you can be able to specify more fields of the channels you want to create
#### Update Thing
```bash
magistrala-cli things update <thing_id> '{"name":"value1", "metadata":{"key1": "value2"}}' <user_token>
```
#### Identify Thing
```bash
magistrala-cli things identify <thing_key>
```
#### Enable Thing
```bash
magistrala-cli things enable <thing_id> <user_token>
```
#### Disable Thing
```bash
magistrala-cli things disable <thing_id> <user_token>
```
#### Get Thing
```bash
magistrala-cli things get <thing_id> <user_token>
```
#### Get Things
```bash
magistrala-cli things get all <user_token>
```
#### Get a subset list of provisioned Things
```bash
magistrala-cli things get all --offset=1 --limit=5 <user_token>
```
#### Create Channel
```bash
magistrala-cli channels create '{"name":"myChannel"}' <user_token>
```
#### Bulk Provision Channels
```bash
magistrala-cli provision channels <file> <user_token>
```
- `file` - A CSV or JSON file containing channel names (must have extension `.csv` or `.json`)
- `user_token` - A valid user auth token for the current system
An example CSV file might be:
```csv
<channel1_name>,
<channel2_name>,
<channel3_name>,
```
in which the first column is channel names.
A comparable JSON file would be
```json
[
{
"name": "<channel1_name>",
"description": "<channel1_description>",
"status": "enabled"
},
{
"name": "<channel2_name>",
"description": "<channel2_description>",
"status": "disabled"
},
{
"name": "<channel3_name>",
"description": "<channel3_description>",
"status": "enabled"
}
]
```
With JSON you can be able to specify more fields of the channels you want to create
#### Update Channel
```bash
magistrala-cli channels update '{"id":"<channel_id>","name":"myNewName"}' <user_token>
```
#### Enable Channel
```bash
magistrala-cli channels enable <channel_id> <user_token>
```
#### Disable Channel
```bash
magistrala-cli channels disable <channel_id> <user_token>
```
#### Get Channel
```bash
magistrala-cli channels get <channel_id> <user_token>
```
#### Get Channels
```bash
magistrala-cli channels get all <user_token>
```
#### Get a subset list of provisioned Channels
```bash
magistrala-cli channels get all --offset=1 --limit=5 <user_token>
```
### Access control
#### Connect Thing to Channel
```bash
magistrala-cli things connect <thing_id> <channel_id> <user_token>
```
#### Bulk Connect Things to Channels
```bash
magistrala-cli provision connect <file> <user_token>
```
- `file` - A CSV or JSON file containing thing and channel ids (must have extension `.csv` or `.json`)
- `user_token` - A valid user auth token for the current system
An example CSV file might be
```csv
<thing_id1>,<channel_id1>
<thing_id2>,<channel_id2>
```
in which the first column is thing IDs and the second column is channel IDs. A connection will be created for each thing to each channel. This example would result in 4 connections being created.
A comparable JSON file would be
```json
{
"client_ids": ["<thing_id1>", "<thing_id2>"],
"group_ids": ["<channel_id1>", "<channel_id2>"]
}
```
#### Disconnect Thing from Channel
```bash
magistrala-cli things disconnect <thing_id> <channel_id> <user_token>
```
#### Get a subset list of Channels connected to Thing
```bash
magistrala-cli things connections <thing_id> <user_token>
```
#### Get a subset list of Things connected to Channel
```bash
magistrala-cli channels connections <channel_id> <user_token>
```
### Messaging
#### Send a message over HTTP
```bash
magistrala-cli messages send <channel_id> '[{"bn":"Dev1","n":"temp","v":20}, {"n":"hum","v":40}, {"bn":"Dev2", "n":"temp","v":20}, {"n":"hum","v":40}]' <thing_secret>
```
#### Read messages over HTTP
```bash
magistrala-cli messages read <channel_id> <user_token> -R <reader_url>
```
### Bootstrap
#### Add configuration
```bash
magistrala-cli bootstrap create '{"external_id": "myExtID", "external_key": "myExtKey", "name": "myName", "content": "myContent"}' <user_token> -b <bootstrap-url>
```
#### View configuration
```bash
magistrala-cli bootstrap get <thing_id> <user_token> -b <bootstrap-url>
```
#### Update configuration
```bash
magistrala-cli bootstrap update '{"thing_id":"<thing_id>", "name": "newName", "content": "newContent"}' <user_token> -b <bootstrap-url>
```
#### Remove configuration
```bash
magistrala-cli bootstrap remove <thing_id> <user_token> -b <bootstrap-url>
```
#### Bootstrap configuration
```bash
magistrala-cli bootstrap bootstrap <external_id> <external_key> -b <bootstrap-url>
```
### Groups
#### Create Group
```bash
magistrala-cli groups create '{"name":"<group_name>","description":"<description>","parentID":"<parent_id>","metadata":"<metadata>"}' <user_token>
```
#### Get Group
```bash
magistrala-cli groups get <group_id> <user_token>
```
#### Get Groups
```bash
magistrala-cli groups get all <user_token>
```
#### Get Group Members
```bash
magistrala-cli groups members <group_id> <user_token>
```
#### Get Memberships
```bash
magistrala-cli groups membership <member_id> <user_token>
```
#### Assign Members to Group
```bash
magistrala-cli groups assign <member_ids> <member_type> <group_id> <user_token>
```
#### Unassign Members to Group
```bash
magistrala-cli groups unassign <member_ids> <group_id> <user_token>
```
#### Enable Group
```bash
magistrala-cli groups enable <group_id> <user_token>
```
#### Disable Group
```bash
magistrala-cli groups disable <group_id> <user_token>
```
-216
View File
@@ -1,216 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"encoding/json"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
var cmdBootstrap = []cobra.Command{
{
Use: "create <JSON_config> <domain_id> <user_auth_token>",
Short: "Create config",
Long: `Create new Thing Bootstrap Config to the user identified by the provided key`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
var cfg mgxsdk.BootstrapConfig
if err := json.Unmarshal([]byte(args[0]), &cfg); err != nil {
logErrorCmd(*cmd, err)
return
}
id, err := sdk.AddBootstrap(cfg, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logCreatedCmd(*cmd, id)
},
},
{
Use: "get [all | <thing_id>] <domain_id> <user_auth_token>",
Short: "Get config",
Long: `Get Thing Config with given ID belonging to the user identified by the given key.
all - lists all config
<thing_id> - view config of <thing_id>`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pageMetadata := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
State: State,
Name: Name,
}
if args[0] == "all" {
l, err := sdk.Bootstraps(pageMetadata, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
c, err := sdk.ViewBootstrap(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, c)
},
},
{
Use: "update [config <JSON_config> | connection <id> <channel_ids> | certs <id> <client_cert> <client_key> <ca> ] <domain_id> <user_auth_token>",
Short: "Update config",
Long: `Updates editable fields of the provided Config.
config <JSON_config> - Updates editable fields of the provided Config.
connection <id> <channel_ids> - Updates connections performs update of the channel list corresponding Thing is connected to.
channel_ids - '["channel_id1", ...]'
certs <id> <client_cert> <client_key> <ca> - Update bootstrap config certificates.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
if args[0] == "config" {
var cfg mgxsdk.BootstrapConfig
if err := json.Unmarshal([]byte(args[1]), &cfg); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.UpdateBootstrap(cfg, args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
return
}
if args[0] == "connection" {
var ids []string
if err := json.Unmarshal([]byte(args[2]), &ids); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.UpdateBootstrapConnection(args[1], ids, args[3], args[4]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
return
}
if args[0] == "certs" {
cfg, err := sdk.UpdateBootstrapCerts(args[0], args[1], args[2], args[3], args[4], args[5])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, cfg)
return
}
logUsageCmd(*cmd, cmd.Use)
},
},
{
Use: "remove <thing_id> <domain_id> <user_auth_token>",
Short: "Remove config",
Long: `Removes Config with specified key that belongs to the user identified by the given key`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.RemoveBootstrap(args[0], args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "bootstrap [<external_id> <external_key> | secure <external_id> <external_key> <crypto_key> ]",
Short: "Bootstrap config",
Long: `Returns Config to the Thing with provided external ID using external key.
secure - Retrieves a configuration with given external ID and encrypted external key.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
if args[0] == "secure" {
c, err := sdk.BootstrapSecure(args[1], args[2], args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, c)
return
}
c, err := sdk.Bootstrap(args[0], args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, c)
},
},
{
Use: "whitelist <JSON_config> <domain_id> <user_auth_token>",
Short: "Whitelist config",
Long: `Whitelist updates thing state config with given id from the authenticated user`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
var cfg mgxsdk.BootstrapConfig
if err := json.Unmarshal([]byte(args[0]), &cfg); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.Whitelist(cfg.ThingID, cfg.State, args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
// NewBootstrapCmd returns bootstrap command.
func NewBootstrapCmd() *cobra.Command {
cmd := cobra.Command{
Use: "bootstrap [create | get | update | remove | bootstrap | whitelist]",
Short: "Bootstrap management",
Long: `Bootstrap management: create, get, update, delete or whitelist Bootstrap config`,
}
for i := range cmdBootstrap {
cmd.AddCommand(&cmdBootstrap[i])
}
return &cmd
}
-622
View File
@@ -1,622 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var bootConfig = mgsdk.BootstrapConfig{
ThingID: thing.ID,
Channels: []string{channel.ID},
Name: "Test Bootstrap",
ExternalID: "09:6:0:sb:sa",
ExternalKey: "key",
}
func TestCreateBootstrapConfigCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
bootCmd := cli.NewBootstrapCmd()
rootCmd := setFlags(bootCmd)
jsonConfig := fmt.Sprintf("{\"external_id\":\"09:6:0:sb:sa\", \"thing_id\": \"%s\", \"external_key\":\"key\", \"name\": \"%s\", \"channels\":[\"%s\"]}", thing.ID, "Test Bootstrap", channel.ID)
invalidJson := fmt.Sprintf("{\"external_id\":\"09:6:0:sb:sa\", \"thing_id\": \"%s\", \"external_key\":\"key\", \"name\": \"%s\", \"channels\":[\"%s\"]", thing.ID, "Test Bootdtrap", channel.ID)
cases := []struct {
desc string
args []string
logType outputLog
response string
sdkErr errors.SDKError
errLogMessage string
id string
}{
{
desc: "create bootstrap config successfully",
args: []string{
jsonConfig,
domainID,
validToken,
},
logType: createLog,
id: thing.ID,
response: fmt.Sprintf("\ncreated: %s\n\n", thing.ID),
},
{
desc: "create bootstrap config with invald args",
args: []string{
jsonConfig,
domainID,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "create bootstrap config with invald json",
args: []string{
invalidJson,
domainID,
validToken,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
{
desc: "create bootstrap config with invald token",
args: []string{
jsonConfig,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("AddBootstrap", mock.Anything, mock.Anything, mock.Anything).Return(tc.id, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{createCmd}, tc.args...)...)
switch tc.logType {
case createLog:
assert.Equal(t, tc.response, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.response, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestGetBootstrapConfigCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
bootCmd := cli.NewBootstrapCmd()
rootCmd := setFlags(bootCmd)
var boot mgsdk.BootstrapConfig
var page mgsdk.BootstrapPage
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
page mgsdk.BootstrapPage
boot mgsdk.BootstrapConfig
logType outputLog
errLogMessage string
}{
{
desc: "get all bootstrap config successfully",
args: []string{
all,
domainID,
token,
},
page: mgsdk.BootstrapPage{
PageRes: mgsdk.PageRes{
Total: 1,
Offset: 0,
Limit: 10,
},
Configs: []mgsdk.BootstrapConfig{bootConfig},
},
logType: entityLog,
},
{
desc: "get bootstrap config with id",
args: []string{
channel.ID,
domainID,
token,
},
logType: entityLog,
boot: bootConfig,
},
{
desc: "get bootstrap config with invalid args",
args: []string{
all,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "get all bootstrap config with invalid token",
args: []string{
all,
domainID,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "get bootstrap config with invalid id",
args: []string{
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("ViewBootstrap", tc.args[0], tc.args[1], tc.args[2]).Return(tc.boot, tc.sdkErr)
sdkCall1 := sdkMock.On("Bootstraps", mock.Anything, tc.args[1], tc.args[2]).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{getCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
if tc.args[0] == all {
err := json.Unmarshal([]byte(out), &page)
assert.Nil(t, err)
assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page))
} else {
err := json.Unmarshal([]byte(out), &boot)
assert.Nil(t, err)
assert.Equal(t, tc.boot, boot, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.boot, boot))
}
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
sdkCall1.Unset()
})
}
}
func TestRemoveBootstrapConfigCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
bootCmd := cli.NewBootstrapCmd()
rootCmd := setFlags(bootCmd)
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
logType outputLog
errLogMessage string
}{
{
desc: "remove bootstrap config successfully",
args: []string{
thing.ID,
domainID,
token,
},
logType: okLog,
},
{
desc: "remove bootstrap config with invalid args",
args: []string{
thing.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "remove bootstrap config with invalid thing id",
args: []string{
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "remove bootstrap config with invalid token",
args: []string{
thing.ID,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("RemoveBootstrap", tc.args[0], tc.args[1], tc.args[2]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{rmCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestUpdateBootstrapConfigCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
bootCmd := cli.NewBootstrapCmd()
rootCmd := setFlags(bootCmd)
config := "config"
connection := "connection"
newConfigJson := "{\"name\" : \"New Bootstrap\"}"
chanIDsJson := fmt.Sprintf("[\"%s\"]", channel.ID)
cases := []struct {
desc string
args []string
boot mgsdk.BootstrapConfig
sdkErr errors.SDKError
errLogMessage string
logType outputLog
}{
{
desc: "update bootstrap config successfully",
args: []string{
config,
newConfigJson,
domainID,
token,
},
logType: okLog,
},
{
desc: "update bootstrap config with invalid token",
args: []string{
config,
newConfigJson,
domainID,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "update bootstrap connections successfully",
args: []string{
connection,
thing.ID,
chanIDsJson,
domainID,
token,
},
logType: okLog,
},
{
desc: "update bootstrap connections with invalid json",
args: []string{
connection,
thing.ID,
fmt.Sprintf("[\"%s\"", thing.ID),
domainID,
token,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
{
desc: "update bootstrap connections with invalid token",
args: []string{
connection,
thing.ID,
chanIDsJson,
domainID,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "update bootstrap certs successfully",
args: []string{
"certs",
thing.ID,
"client cert",
"client key",
"ca",
domainID,
token,
},
boot: bootConfig,
logType: entityLog,
},
{
desc: "update bootstrap certs with invalid token",
args: []string{
"certs",
thing.ID,
"client cert",
"client key",
"ca",
domainID,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "update bootstrap config with invalid args",
args: []string{
newConfigJson,
domainID,
token,
},
logType: usageLog,
},
{
desc: "update bootstrap config with invalid json",
args: []string{
config,
"{\"name\" : \"New Bootstrap\"",
domainID,
token,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
{
desc: "update bootstrap with invalid args",
args: []string{
extraArg,
extraArg,
extraArg,
extraArg,
extraArg,
},
logType: usageLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
var boot mgsdk.BootstrapConfig
sdkCall := sdkMock.On("UpdateBootstrap", mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
sdkCall1 := sdkMock.On("UpdateBootstrapConnection", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
sdkCall2 := sdkMock.On("UpdateBootstrapCerts", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.boot, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{updCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &boot)
assert.Nil(t, err)
assert.Equal(t, tc.boot, boot, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.boot, boot))
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
sdkCall1.Unset()
sdkCall2.Unset()
})
}
}
func TestWhitelistConfigCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
bootCmd := cli.NewBootstrapCmd()
rootCmd := setFlags(bootCmd)
jsonConfig := fmt.Sprintf("{\"thing_id\": \"%s\", \"state\":%d}", thing.ID, 1)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "whitelist config successfully",
args: []string{
jsonConfig,
domainID,
validToken,
},
logType: okLog,
},
{
desc: "whitelist config with invalid args",
args: []string{
jsonConfig,
domainID,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "whitelist config with invalid json",
args: []string{
fmt.Sprintf("{\"thing_id\": \"%s\", \"state\":%d", thing.ID, 1),
domainID,
validToken,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
{
desc: "whitelist config with invalid token",
args: []string{
jsonConfig,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("Whitelist", mock.Anything, mock.Anything, tc.args[1], tc.args[2]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{whitelistCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestBootstrapConfigCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
bootCmd := cli.NewBootstrapCmd()
rootCmd := setFlags(bootCmd)
var boot mgsdk.BootstrapConfig
crptoKey := "v7aT0HGxJxt2gULzr3RHwf4WIf6DusPp"
invalidKey := "invalid key"
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
boot mgsdk.BootstrapConfig
}{
{
desc: "bootstrap secure config successfully",
args: []string{
"secure",
bootConfig.ExternalID,
bootConfig.ExternalKey,
crptoKey,
},
boot: bootConfig,
logType: entityLog,
},
{
desc: "bootstrap config successfully",
args: []string{
bootConfig.ExternalID,
bootConfig.ExternalKey,
},
boot: bootConfig,
logType: entityLog,
},
{
desc: "bootstrap secure config with invalid args",
args: []string{
crptoKey,
},
logType: usageLog,
},
{
desc: "bootstrap secure config with invalid key",
args: []string{
"secure",
bootConfig.ExternalID,
invalidKey,
crptoKey,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
{
desc: "bootstrap config with invalid key",
args: []string{
bootConfig.ExternalID,
invalidKey,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("BootstrapSecure", mock.Anything, mock.Anything, mock.Anything).Return(tc.boot, tc.sdkErr)
sdkCall1 := sdkMock.On("Bootstrap", mock.Anything, mock.Anything).Return(tc.boot, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{bootStrapCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &boot)
assert.Nil(t, err)
assert.Equal(t, tc.boot, boot, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.boot, boot))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
sdkCall1.Unset()
})
}
}
-96
View File
@@ -1,96 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"github.com/spf13/cobra"
)
var cmdCerts = []cobra.Command{
{
Use: "get [<cert_serial> | thing <thing_id> ] <domain_id> <user_auth_token>",
Short: "Get certificate",
Long: `Gets a certificate for a given cert ID.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if args[0] == "thing" {
cert, err := sdk.ViewCertByThing(args[1], args[2], args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, cert)
return
}
cert, err := sdk.ViewCert(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, cert)
},
},
{
Use: "revoke <thing_id> <domain_id> <user_auth_token>",
Short: "Revoke certificate",
Long: `Revokes a certificate for a given thing ID.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
rtime, err := sdk.RevokeCert(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logRevokedTimeCmd(*cmd, rtime)
},
},
}
// NewCertsCmd returns certificate command.
func NewCertsCmd() *cobra.Command {
var ttl string
issueCmd := cobra.Command{
Use: "issue <thing_id> <domain_id> <user_auth_token> [--ttl=8760h]",
Short: "Issue certificate",
Long: `Issues new certificate for a thing`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
thingID := args[0]
c, err := sdk.IssueCert(thingID, ttl, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, c)
},
}
issueCmd.Flags().StringVar(&ttl, "ttl", "8760h", "certificate time to live in duration")
cmd := cobra.Command{
Use: "certs [issue | get | revoke ]",
Short: "Certificates management",
Long: `Certificates management: issue, get or revoke certificates for things"`,
}
cmdCerts = append(cmdCerts, issueCmd)
for i := range cmdCerts {
cmd.AddCommand(&cmdCerts[i])
}
return &cmd
}
-272
View File
@@ -1,272 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"time"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var cert = mgsdk.Cert{
ThingID: thing.ID,
}
func TestGetCertCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
certCmd := cli.NewCertsCmd()
rootCmd := setFlags(certCmd)
var ct mgsdk.Cert
var cts mgsdk.CertSerials
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
errLogMessage string
logType outputLog
serials mgsdk.CertSerials
cert mgsdk.Cert
}{
{
desc: "get cert successfully",
args: []string{
"thing",
thing.ID,
domainID,
validToken,
},
logType: entityLog,
serials: mgsdk.CertSerials{
PageRes: mgsdk.PageRes{
Total: 1,
Offset: 0,
Limit: 10,
},
Certs: []mgsdk.Cert{cert},
},
},
{
desc: "get cert successfully by id",
args: []string{
thing.ID,
domainID,
validToken,
},
logType: entityLog,
cert: cert,
},
{
desc: "get cert with invalid token",
args: []string{
"thing",
thing.ID,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
{
desc: "get cert by id with invalid token",
args: []string{
thing.ID,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
{
desc: "get cert with invalid args",
args: []string{
thing.ID,
},
logType: usageLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("ViewCertByThing", mock.Anything, mock.Anything, mock.Anything).Return(tc.serials, tc.sdkErr)
sdkCall1 := sdkMock.On("ViewCert", mock.Anything, mock.Anything, mock.Anything).Return(tc.cert, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{getCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
if tc.args[1] == "thing" {
err := json.Unmarshal([]byte(out), &cts)
assert.Nil(t, err)
assert.Equal(t, tc.serials, cts, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.serials, cts))
} else {
err := json.Unmarshal([]byte(out), &ct)
assert.Nil(t, err)
assert.Equal(t, tc.cert, ct, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.cert, ct))
}
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
sdkCall1.Unset()
})
}
}
func TestRevokeCertCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
certCmd := cli.NewCertsCmd()
rootCmd := setFlags(certCmd)
revokeTime := time.Now()
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
logType outputLog
errLogMessage string
time time.Time
response string
}{
{
desc: "revoke cert successfully",
args: []string{
thing.ID,
domainID,
token,
},
logType: revokeLog,
response: fmt.Sprintf("\nrevoked: %s\n\n", revokeTime),
time: revokeTime,
},
{
desc: "revoke cert with invalid args",
args: []string{
thing.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "revoke cert with invalid token",
args: []string{
thing.ID,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("RevokeCert", tc.args[0], tc.args[1], tc.args[2]).Return(tc.time, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{revokeCmd}, tc.args...)...)
switch tc.logType {
case revokeLog:
assert.Equal(t, tc.response, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.response, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestIssueCertCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
certCmd := cli.NewCertsCmd()
rootCmd := setFlags(certCmd)
cert := mgsdk.Cert{
SerialNumber: "serial",
}
var cs mgsdk.Cert
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
cert mgsdk.Cert
}{
{
desc: "issue cert successfully",
args: []string{
thing.ID,
domainID,
validToken,
},
cert: cert,
logType: entityLog,
},
{
desc: "issue cert with invalid args",
args: []string{
thing.ID,
domainID,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "issue cert with invalid token",
args: []string{
thing.ID,
domainID,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("IssueCert", mock.Anything, mock.Anything, tc.args[1], tc.args[2]).Return(tc.cert, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{issueCmd}, tc.args...)...)
switch tc.logType {
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case entityLog:
err := json.Unmarshal([]byte(out), &cs)
assert.Nil(t, err)
assert.Equal(t, tc.cert, cs, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.cert, cs))
}
sdkCall.Unset()
})
}
}
-376
View File
@@ -1,376 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"encoding/json"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
const all = "all"
var cmdChannels = []cobra.Command{
{
Use: "create <JSON_channel> <domain_id> <user_auth_token>",
Short: "Create channel",
Long: `Creates new channel and generates it's UUID`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
var channel mgxsdk.Channel
if err := json.Unmarshal([]byte(args[0]), &channel); err != nil {
logErrorCmd(*cmd, err)
return
}
channel, err := sdk.CreateChannel(channel, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, channel)
},
},
{
Use: "get [all | <channel_id>] <domain_id> <user_auth_token>",
Short: "Get channel",
Long: `Get all channels or get channel by id. Channels can be filtered by name or metadata.
all - lists all channels
<channel_id> - shows thing with provided <channel_id>`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
metadata, err := convertMetadata(Metadata)
if err != nil {
logErrorCmd(*cmd, err)
return
}
pageMetadata := mgxsdk.PageMetadata{
Name: "",
Offset: Offset,
Limit: Limit,
Metadata: metadata,
}
if args[0] == all {
l, err := sdk.Channels(pageMetadata, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
c, err := sdk.Channel(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, c)
},
},
{
Use: "delete <channel_id> <domain_id> <user_auth_token>",
Short: "Delete channel",
Long: "Delete channel by id.\n" +
"Usage:\n" +
"\tmagistrala-cli channels delete <channel_id> $DOMAINID $USERTOKEN - delete the given channel ID\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.DeleteChannel(args[0], args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "update <channel_id> <JSON_string> <domain_id> <user_auth_token>",
Short: "Update channel",
Long: `Updates channel record`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
var channel mgxsdk.Channel
if err := json.Unmarshal([]byte(args[1]), &channel); err != nil {
logErrorCmd(*cmd, err)
return
}
channel.ID = args[0]
channel, err := sdk.UpdateChannel(channel, args[2], args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, channel)
},
},
{
Use: "connections <channel_id> <domain_id> <user_auth_token>",
Short: "Connections list",
Long: `List of Things connected to a Channel`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
cl, err := sdk.ThingsByChannel(args[0], pm, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, cl)
},
},
{
Use: "enable <channel_id> <domain_id> <user_auth_token>",
Short: "Change channel status to enabled",
Long: `Change channel status to enabled`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
channel, err := sdk.EnableChannel(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, channel)
},
},
{
Use: "disable <channel_id> <domain_id> <user_auth_token>",
Short: "Change channel status to disabled",
Long: `Change channel status to disabled`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
channel, err := sdk.DisableChannel(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, channel)
},
},
{
Use: "users <channel_id> <domain_id> <user_auth_token>",
Short: "List users",
Long: "List users of a channel\n" +
"Usage:\n" +
"\tmagistrala-cli channels users <channel_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
ul, err := sdk.ListChannelUsers(args[0], pm, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, ul)
},
},
{
Use: "groups <channel_id> <domain_id> <user_auth_token>",
Short: "List groups",
Long: "List groups of a channel\n" +
"Usage:\n" +
"\tmagistrala-cli channels groups <channel_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
ul, err := sdk.ListChannelUserGroups(args[0], pm, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, ul)
},
},
}
var channelAssignCmds = []cobra.Command{
{
Use: "users <relation> <user_ids> <channel_id> <domain_id> <user_auth_token>",
Short: "Assign users",
Long: "Assign users to a channel\n" +
"Usage:\n" +
"\tmagistrala-cli channels assign users <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <channel_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 5 {
logUsageCmd(*cmd, cmd.Use)
return
}
var userIDs []string
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.AddUserToChannel(args[2], mgxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3], args[4]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "groups <group_ids> <channel_id> <domain_id> <user_auth_token>",
Short: "Assign groups",
Long: "Assign groups to a channel\n" +
"Usage:\n" +
"\tmagistrala-cli channels assign groups '[\"<group_id_1>\", \"<group_id_2>\"]' <channel_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
var groupIDs []string
if err := json.Unmarshal([]byte(args[0]), &groupIDs); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.AddUserGroupToChannel(args[1], mgxsdk.UserGroupsRequest{UserGroupIDs: groupIDs}, args[2], args[3]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
var channelUnassignCmds = []cobra.Command{
{
Use: "groups <group_ids> <channel_id> <domain_id> <user_auth_token>",
Short: "Unassign groups",
Long: "Unassign groups from a channel\n" +
"Usage:\n" +
"\tmagistrala-cli channels unassign groups '[\"<group_id_1>\", \"<group_id_2>\"]' <channel_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
var groupIDs []string
if err := json.Unmarshal([]byte(args[0]), &groupIDs); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.RemoveUserGroupFromChannel(args[1], mgxsdk.UserGroupsRequest{UserGroupIDs: groupIDs}, args[2], args[3]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "users <relation> <user_ids> <channel_id> <domain_id> <user_auth_token>",
Short: "Unassign users",
Long: "Unassign users from a channel\n" +
"Usage:\n" +
"\tmagistrala-cli channels unassign users <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <channel_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 5 {
logUsageCmd(*cmd, cmd.Use)
return
}
var userIDs []string
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.RemoveUserFromChannel(args[2], mgxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3], args[4]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
func NewChannelAssignCmds() *cobra.Command {
cmd := cobra.Command{
Use: "assign [users | groups]",
Short: "Assign users or groups to a channel",
Long: "Assign users or groups to a channel",
}
for i := range channelAssignCmds {
cmd.AddCommand(&channelAssignCmds[i])
}
return &cmd
}
func NewChannelUnassignCmds() *cobra.Command {
cmd := cobra.Command{
Use: "unassign [users | groups]",
Short: "Unassign users or groups from a channel",
Long: "Unassign users or groups from a channel",
}
for i := range channelUnassignCmds {
cmd.AddCommand(&channelUnassignCmds[i])
}
return &cmd
}
// NewChannelsCmd returns channels command.
func NewChannelsCmd() *cobra.Command {
cmd := cobra.Command{
Use: "channels [create | get | update | delete | connections | not-connected | assign | unassign | users | groups]",
Short: "Channels management",
Long: `Channels management: create, get, update or delete Channel and get list of Things connected or not connected to a Channel`,
}
for i := range cmdChannels {
cmd.AddCommand(&cmdChannels[i])
}
cmd.AddCommand(NewChannelAssignCmds())
cmd.AddCommand(NewChannelUnassignCmds())
return &cmd
}
-1137
View File
File diff suppressed because it is too large Load Diff
-72
View File
@@ -1,72 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
// CRUD and common commands
const (
createCmd = "create"
updateCmd = "update"
getCmd = "get"
enableCmd = "enable"
disableCmd = "disable"
updCmd = "update"
delCmd = "delete"
rmCmd = "remove"
)
// Users commands
const (
tokCmd = "token"
refTokCmd = "refreshtoken"
profCmd = "profile"
resPassReqCmd = "resetpasswordrequest"
resPassCmd = "resetpassword"
passCmd = "password"
domsCmd = "domains"
)
// Things commands
const (
thsCmd = "things"
connsCmd = "connections"
connCmd = "connect"
disconnCmd = "disconnect"
shrCmd = "share"
unshrCmd = "unshare"
)
// Groups and channels commands
const (
chansCmd = "channels"
grpCmd = "groups"
childCmd = "children"
parentCmd = "parents"
usrCmd = "users"
assignCmd = "assign"
unassignCmd = "unassign"
)
// Certs commands
const (
revokeCmd = "revoke"
issueCmd = "issue"
)
// Messages commands
const (
sendCmd = "send"
readCmd = "read"
)
// Bootstrap commands
const (
whitelistCmd = "whitelist"
bootStrapCmd = "bootstrap"
)
// Invitations commands
const (
acceptCmd = "accept"
rejectCmd = "reject"
)
-311
View File
@@ -1,311 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"io"
"net/url"
"os"
"reflect"
"strconv"
"strings"
"github.com/absmach/magistrala/pkg/errors"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/pelletier/go-toml"
"github.com/spf13/cobra"
)
const (
defURL string = "http://localhost"
defUsersURL string = defURL + ":9002"
defThingsURL string = defURL + ":9000"
defReaderURL string = defURL + ":9011"
defBootstrapURL string = defURL + ":9013"
defDomainsURL string = defURL + ":8189"
defCertsURL string = defURL + ":9019"
defInvitationsURL string = defURL + ":9020"
defHTTPURL string = defURL + ":8008"
defJournalURL string = defURL + ":9021"
defTLSVerification bool = false
defOffset string = "0"
defLimit string = "10"
defTopic string = ""
defRawOutput string = "false"
)
type remotes struct {
ThingsURL string `toml:"things_url"`
UsersURL string `toml:"users_url"`
ReaderURL string `toml:"reader_url"`
DomainsURL string `toml:"domains_url"`
HTTPAdapterURL string `toml:"http_adapter_url"`
BootstrapURL string `toml:"bootstrap_url"`
CertsURL string `toml:"certs_url"`
InvitationsURL string `toml:"invitations_url"`
JournalURL string `toml:"journal_url"`
HostURL string `toml:"host_url"`
TLSVerification bool `toml:"tls_verification"`
}
type filter struct {
Offset string `toml:"offset"`
Limit string `toml:"limit"`
Topic string `toml:"topic"`
}
type config struct {
Remotes remotes `toml:"remotes"`
Filter filter `toml:"filter"`
UserToken string `toml:"user_token"`
RawOutput string `toml:"raw_output"`
}
// Readable by all user groups but writeable by the user only.
const filePermission = 0o644
var (
errReadFail = errors.New("failed to read config file")
errNoKey = errors.New("no such key")
errUnsupportedKeyValue = errors.New("unsupported data type for key")
errWritingConfig = errors.New("error in writing the updated config to file")
errInvalidURL = errors.New("invalid url")
errURLParseFail = errors.New("failed to parse url")
defaultConfigPath = "./config.toml"
)
func read(file string) (config, error) {
c := config{}
data, err := os.Open(file)
if err != nil {
return c, errors.Wrap(errReadFail, err)
}
defer data.Close()
buf, err := io.ReadAll(data)
if err != nil {
return c, errors.Wrap(errReadFail, err)
}
if err := toml.Unmarshal(buf, &c); err != nil {
return config{}, err
}
return c, nil
}
// ParseConfig - parses the config file.
func ParseConfig(sdkConf mgxsdk.Config) (mgxsdk.Config, error) {
if ConfigPath == "" {
ConfigPath = defaultConfigPath
}
_, err := os.Stat(ConfigPath)
switch {
// If the file does not exist, create it with default values.
case os.IsNotExist(err):
defaultConfig := config{
Remotes: remotes{
ThingsURL: defThingsURL,
UsersURL: defUsersURL,
ReaderURL: defReaderURL,
DomainsURL: defDomainsURL,
HTTPAdapterURL: defHTTPURL,
BootstrapURL: defBootstrapURL,
CertsURL: defCertsURL,
InvitationsURL: defInvitationsURL,
JournalURL: defJournalURL,
HostURL: defURL,
TLSVerification: defTLSVerification,
},
Filter: filter{
Offset: defOffset,
Limit: defLimit,
Topic: defTopic,
},
RawOutput: defRawOutput,
}
buf, err := toml.Marshal(defaultConfig)
if err != nil {
return sdkConf, err
}
if err = os.WriteFile(ConfigPath, buf, filePermission); err != nil {
return sdkConf, errors.Wrap(errWritingConfig, err)
}
case err != nil:
return sdkConf, err
}
config, err := read(ConfigPath)
if err != nil {
return sdkConf, err
}
if config.Filter.Offset != "" && Offset == 0 {
offset, err := strconv.ParseUint(config.Filter.Offset, 10, 64)
if err != nil {
return sdkConf, err
}
Offset = offset
}
if config.Filter.Limit != "" && Limit == 0 {
limit, err := strconv.ParseUint(config.Filter.Limit, 10, 64)
if err != nil {
return sdkConf, err
}
Limit = limit
}
if config.Filter.Topic != "" && Topic == "" {
Topic = config.Filter.Topic
}
if config.RawOutput != "" {
rawOutput, err := strconv.ParseBool(config.RawOutput)
if err != nil {
return sdkConf, err
}
// check for config file value or flag input value is true
RawOutput = rawOutput || RawOutput
}
if sdkConf.ThingsURL == "" && config.Remotes.ThingsURL != "" {
sdkConf.ThingsURL = config.Remotes.ThingsURL
}
if sdkConf.UsersURL == "" && config.Remotes.UsersURL != "" {
sdkConf.UsersURL = config.Remotes.UsersURL
}
if sdkConf.ReaderURL == "" && config.Remotes.ReaderURL != "" {
sdkConf.ReaderURL = config.Remotes.ReaderURL
}
if sdkConf.DomainsURL == "" && config.Remotes.DomainsURL != "" {
sdkConf.DomainsURL = config.Remotes.DomainsURL
}
if sdkConf.HTTPAdapterURL == "" && config.Remotes.HTTPAdapterURL != "" {
sdkConf.HTTPAdapterURL = config.Remotes.HTTPAdapterURL
}
if sdkConf.BootstrapURL == "" && config.Remotes.BootstrapURL != "" {
sdkConf.BootstrapURL = config.Remotes.BootstrapURL
}
if sdkConf.CertsURL == "" && config.Remotes.CertsURL != "" {
sdkConf.CertsURL = config.Remotes.CertsURL
}
if sdkConf.InvitationsURL == "" && config.Remotes.InvitationsURL != "" {
sdkConf.InvitationsURL = config.Remotes.InvitationsURL
}
if sdkConf.JournalURL == "" && config.Remotes.JournalURL != "" {
sdkConf.JournalURL = config.Remotes.JournalURL
}
if sdkConf.HostURL == "" && config.Remotes.HostURL != "" {
sdkConf.HostURL = config.Remotes.HostURL
}
sdkConf.TLSVerification = config.Remotes.TLSVerification || sdkConf.TLSVerification
return sdkConf, nil
}
// New config command to store params to local TOML file.
func NewConfigCmd() *cobra.Command {
return &cobra.Command{
Use: "config <key> <value>",
Short: "CLI local config",
Long: "Local param storage to prevent repetitive passing of keys",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := setConfigValue(args[0], args[1]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
}
}
func setConfigValue(key, value string) error {
config, err := read(ConfigPath)
if err != nil {
return err
}
if strings.Contains(key, "url") {
u, err := url.Parse(value)
if err != nil {
return errors.Wrap(errInvalidURL, err)
}
if u.Scheme == "" || u.Host == "" {
return errors.Wrap(errInvalidURL, err)
}
if u.Scheme != "http" && u.Scheme != "https" {
return errors.Wrap(errURLParseFail, err)
}
}
configKeyToField := map[string]interface{}{
"things_url": &config.Remotes.ThingsURL,
"users_url": &config.Remotes.UsersURL,
"reader_url": &config.Remotes.ReaderURL,
"http_adapter_url": &config.Remotes.HTTPAdapterURL,
"bootstrap_url": &config.Remotes.BootstrapURL,
"certs_url": &config.Remotes.CertsURL,
"tls_verification": &config.Remotes.TLSVerification,
"offset": &config.Filter.Offset,
"limit": &config.Filter.Limit,
"topic": &config.Filter.Topic,
"raw_output": &config.RawOutput,
"user_token": &config.UserToken,
}
fieldPtr, ok := configKeyToField[key]
if !ok {
return errNoKey
}
fieldValue := reflect.ValueOf(fieldPtr).Elem()
switch fieldValue.Kind() {
case reflect.String:
fieldValue.SetString(value)
case reflect.Int:
intValue, err := strconv.Atoi(value)
if err != nil {
return err
}
fieldValue.SetUint(uint64(intValue))
case reflect.Bool:
boolValue, err := strconv.ParseBool(value)
if err != nil {
return err
}
fieldValue.SetBool(boolValue)
default:
return errors.Wrap(errUnsupportedKeyValue, err)
}
buf, err := toml.Marshal(config)
if err != nil {
return err
}
if err = os.WriteFile(ConfigPath, buf, filePermission); err != nil {
return errors.Wrap(errWritingConfig, err)
}
return nil
}
-100
View File
@@ -1,100 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
var cmdSubscription = []cobra.Command{
{
Use: "create <topic> <contact> <user_auth_token>",
Short: "Create subscription",
Long: `Create new subscription`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
id, err := sdk.CreateSubscription(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logCreatedCmd(*cmd, id)
},
},
{
Use: "get [all | <sub_id>] <user_auth_token>",
Short: "Get subscription",
Long: `Get subscription.
all - lists all subscriptions
<sub_id> - view subscription of <sub_id>`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
pageMetadata := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
Topic: Topic,
Contact: Contact,
}
if args[0] == "all" {
sub, err := sdk.ListSubscriptions(pageMetadata, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, sub)
return
}
c, err := sdk.ViewSubscription(args[0], args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, c)
},
},
{
Use: "remove <sub_id> <user_auth_token>",
Short: "Remove subscription",
Long: `Removes removes a subscription with the provided id`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.DeleteSubscription(args[0], args[1]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
// NewSubscriptionCmd returns subscription command.
func NewSubscriptionCmd() *cobra.Command {
cmd := cobra.Command{
Use: "subscription [create | get | remove ]",
Short: "Subscription management",
Long: `Subscription management: create, get, or delete subscription`,
}
for i := range cmdSubscription {
cmd.AddCommand(&cmdSubscription[i])
}
return &cmd
}
-273
View File
@@ -1,273 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var subscription = mgsdk.Subscription{
ID: testsutil.GenerateUUID(&testing.T{}),
OwnerID: user.ID,
Topic: "topic",
Contact: "identity@example.com",
}
func TestCreateSubscriptionCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
subCmd := cli.NewSubscriptionCmd()
rootCmd := setFlags(subCmd)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
response string
id string
}{
{
desc: "create subscription successfully",
args: []string{
subscription.Topic,
subscription.Contact,
validToken,
},
id: user.ID,
response: fmt.Sprintf("\ncreated: %s\n\n", user.ID),
logType: createLog,
},
{
desc: "create subscription with invalid args",
args: []string{
subscription.Topic,
subscription.Contact,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "create subscription with invalid token",
args: []string{
subscription.Topic,
subscription.Contact,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("CreateSubscription", tc.args[0], tc.args[1], tc.args[2]).Return(tc.id, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{createCmd}, tc.args...)...)
switch tc.logType {
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case createLog:
assert.Equal(t, tc.response, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.response, out))
}
sdkCall.Unset()
})
}
}
func TestGetSubscriptionsCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
subCmd := cli.NewSubscriptionCmd()
rootCmd := setFlags(subCmd)
var sub mgsdk.Subscription
var page mgsdk.SubscriptionPage
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
page mgsdk.SubscriptionPage
subscription mgsdk.Subscription
logType outputLog
errLogMessage string
}{
{
desc: "get all subscriptions successfully",
args: []string{
all,
token,
},
page: mgsdk.SubscriptionPage{
Subscriptions: []mgsdk.Subscription{subscription},
},
logType: entityLog,
},
{
desc: "get subscription with id",
args: []string{
subscription.ID,
token,
},
logType: entityLog,
subscription: subscription,
},
{
desc: "get subscriptions with invalid args",
args: []string{
all,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "get all subscriptions with invalid token",
args: []string{
all,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "get subscription without domain token",
args: []string{
subscription.ID,
tokenWithoutDomain,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden)),
},
{
desc: "get subscription with invalid id",
args: []string{
invalidID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("ViewSubscription", tc.args[0], tc.args[1]).Return(tc.subscription, tc.sdkErr)
sdkCall1 := sdkMock.On("ListSubscriptions", mock.Anything, tc.args[1]).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{getCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
if tc.args[1] == all {
err := json.Unmarshal([]byte(out), &page)
assert.Nil(t, err)
assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page))
} else {
err := json.Unmarshal([]byte(out), &sub)
assert.Nil(t, err)
assert.Equal(t, tc.subscription, sub, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.subscription, sub))
}
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
sdkCall1.Unset()
})
}
}
func TestRemoveSubscriptionCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
subCmd := cli.NewSubscriptionCmd()
rootCmd := setFlags(subCmd)
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
logType outputLog
errLogMessage string
}{
{
desc: "remove subscription successfully",
args: []string{
subscription.ID,
token,
},
logType: okLog,
},
{
desc: "remove subscription with invalid args",
args: []string{
subscription.ID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "remove subscription with invalid subscription id",
args: []string{
invalidID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "remove subscription with invalid token",
args: []string{
subscription.ID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("DeleteSubscription", tc.args[0], tc.args[1]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{rmCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
-6
View File
@@ -1,6 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
// Package cli contains the domain concept definitions needed to support
// Magistrala CLI functionality.
package cli
-263
View File
@@ -1,263 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"encoding/json"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
var cmdDomains = []cobra.Command{
{
Use: "create <name> <alias> <token>",
Short: "Create Domain",
Long: "Create Domain with provided name and alias. \n" +
"For example:\n" +
"\tmagistrala-cli domains create domain_1 domain_1_alias $TOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
dom := mgxsdk.Domain{
Name: args[0],
Alias: args[1],
}
d, err := sdk.CreateDomain(dom, args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, d)
},
},
{
Use: "get [all | <domain_id> ] <token>",
Short: "Get Domains",
Long: "Get all domains. Users can be filtered by name or metadata or status",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
metadata, err := convertMetadata(Metadata)
if err != nil {
logErrorCmd(*cmd, err)
return
}
pageMetadata := mgxsdk.PageMetadata{
Name: Name,
Offset: Offset,
Limit: Limit,
Metadata: metadata,
Status: Status,
}
if args[0] == all {
l, err := sdk.Domains(pageMetadata, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
d, err := sdk.Domain(args[0], args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, d)
},
},
{
Use: "users <domain_id> <token>",
Short: "List Domain users",
Long: "List Domain users",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
metadata, err := convertMetadata(Metadata)
if err != nil {
logErrorCmd(*cmd, err)
return
}
pageMetadata := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
Metadata: metadata,
Status: Status,
}
l, err := sdk.ListDomainUsers(args[0], pageMetadata, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
},
},
{
Use: "update <domain_id> <JSON_string> <user_auth_token>",
Short: "Update domains",
Long: "Updates domains name, alias and metadata \n" +
"Usage:\n" +
"\tmagistrala-cli domains update <domain_id> '{\"name\":\"new name\", \"alias\":\"new_alias\", \"metadata\":{\"key\": \"value\"}}' $TOKEN \n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 && len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
var d mgxsdk.Domain
if err := json.Unmarshal([]byte(args[1]), &d); err != nil {
logErrorCmd(*cmd, err)
return
}
d.ID = args[0]
d, err := sdk.UpdateDomain(d, args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, d)
},
},
{
Use: "enable <domain_id> <token>",
Short: "Change domain status to enabled",
Long: "Change domain status to enabled\n" +
"Usage:\n" +
"\tmagistrala-cli domains enable <domain_id> <token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.EnableDomain(args[0], args[1]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "disable <domain_id> <token>",
Short: "Change domain status to disabled",
Long: "Change domain status to disabled\n" +
"Usage:\n" +
"\tmagistrala-cli domains disable <domain_id> <token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.DisableDomain(args[0], args[1]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
var domainAssignCmds = []cobra.Command{
{
Use: "users <relation> <user_ids> <domain_id> <token>",
Short: "Assign users",
Long: "Assign users to a domain\n" +
"Usage:\n" +
"\tmagistrala-cli domains assign users <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <domain_id> $TOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
var userIDs []string
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.AddUserToDomain(args[2], mgxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
var domainUnassignCmds = []cobra.Command{
{
Use: "users <user_id> <domain_id> <token>",
Short: "Unassign users",
Long: "Unassign users from a domain\n" +
"Usage:\n" +
"\tmagistrala-cli domains unassign users <user_id> <domain_id> $TOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.RemoveUserFromDomain(args[1], args[0], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
func NewDomainAssignCmds() *cobra.Command {
cmd := cobra.Command{
Use: "assign [users]",
Short: "Assign users to a domain",
Long: "Assign users to a domain",
}
for i := range domainAssignCmds {
cmd.AddCommand(&domainAssignCmds[i])
}
return &cmd
}
func NewDomainUnassignCmds() *cobra.Command {
cmd := cobra.Command{
Use: "unassign [users]",
Short: "Unassign users from a domain",
Long: "Unassign users from a domain",
}
for i := range domainUnassignCmds {
cmd.AddCommand(&domainUnassignCmds[i])
}
return &cmd
}
// NewDomainsCmd returns domains command.
func NewDomainsCmd() *cobra.Command {
cmd := cobra.Command{
Use: "domains [create | get | update | enable | disable | enable | users | assign | unassign]",
Short: "Domains management",
Long: `Domains management: create, update, retrieve domains , assign/unassign users to domains and list users of domain"`,
}
for i := range cmdDomains {
cmd.AddCommand(&cmdDomains[i])
}
cmd.AddCommand(NewDomainAssignCmds())
cmd.AddCommand(NewDomainUnassignCmds())
return &cmd
}
-669
View File
@@ -1,669 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var domain = mgsdk.Domain{
ID: testsutil.GenerateUUID(&testing.T{}),
Name: "Test domain",
Alias: "alias",
}
func TestCreateDomainsCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
domainCmd := cli.NewDomainsCmd()
rootCmd := setFlags(domainCmd)
var dom mgsdk.Domain
cases := []struct {
desc string
args []string
domain mgsdk.Domain
errLogMessage string
sdkErr errors.SDKError
logType outputLog
}{
{
desc: "create domain successfully",
args: []string{
dom.Name,
dom.Alias,
validToken,
},
logType: entityLog,
domain: domain,
},
{
desc: "create domain with invalid args",
args: []string{
dom.Name,
dom.Alias,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "create domain with invalid token",
args: []string{
dom.Name,
dom.Alias,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("CreateDomain", mock.Anything, mock.Anything).Return(tc.domain, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{createCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &dom)
assert.Nil(t, err)
assert.Equal(t, tc.domain, dom, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.domain, dom))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestGetDomainsCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
all := "all"
domainCmd := cli.NewDomainsCmd()
rootCmd := setFlags(domainCmd)
var dom mgsdk.Domain
var page mgsdk.DomainsPage
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
page mgsdk.DomainsPage
domain mgsdk.Domain
logType outputLog
errLogMessage string
}{
{
desc: "get all domains successfully",
args: []string{
all,
validToken,
},
page: mgsdk.DomainsPage{
Domains: []mgsdk.Domain{domain},
},
logType: entityLog,
},
{
desc: "get domain with id",
args: []string{
domain.ID,
validToken,
},
logType: entityLog,
domain: domain,
},
{
desc: "get domains with invalid args",
args: []string{
all,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "get all domains with invalid token",
args: []string{
all,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "get domain with invalid id",
args: []string{
invalidID,
validToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("Domain", tc.args[0], tc.args[1]).Return(tc.domain, tc.sdkErr)
sdkCall1 := sdkMock.On("Domains", mock.Anything, tc.args[1]).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{getCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
if tc.args[1] == all {
err := json.Unmarshal([]byte(out), &page)
assert.Nil(t, err)
assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page))
} else {
err := json.Unmarshal([]byte(out), &dom)
assert.Nil(t, err)
assert.Equal(t, tc.domain, dom, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.domain, dom))
}
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
sdkCall1.Unset()
})
}
}
func TestListDomainUsers(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
domainsCmd := cli.NewDomainsCmd()
rootCmd := setFlags(domainsCmd)
page := mgsdk.UsersPage{}
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
page mgsdk.UsersPage
sdkErr errors.SDKError
}{
{
desc: "list domain users successfully",
args: []string{
domain.ID,
token,
},
page: mgsdk.UsersPage{
PageRes: mgsdk.PageRes{
Total: 1,
Offset: 0,
Limit: 10,
},
Users: []mgsdk.User{user},
},
logType: entityLog,
},
{
desc: "list domain users with invalid args",
args: []string{
domain.ID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "list domain users without domain token",
args: []string{
domain.ID,
tokenWithoutDomain,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "list domain users with invalid id",
args: []string{
invalidID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("ListDomainUsers", tc.args[0], mock.Anything, tc.args[1]).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{usrCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &page)
if err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestUpdateDomainCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
domainsCmd := cli.NewDomainsCmd()
rootCmd := setFlags(domainsCmd)
newDomainJson := "{\"name\" : \"New domain\"}"
cases := []struct {
desc string
args []string
domain mgsdk.Domain
sdkErr errors.SDKError
errLogMessage string
logType outputLog
}{
{
desc: "update domain successfully",
args: []string{
domain.ID,
newDomainJson,
token,
},
domain: mgsdk.Domain{
Name: "New domain",
ID: domain.ID,
},
logType: entityLog,
},
{
desc: "update domain with invalid args",
args: []string{
domain.ID,
newDomainJson,
token,
extraArg,
extraArg,
},
logType: usageLog,
},
{
desc: "update domain with invalid id",
args: []string{
invalidID,
newDomainJson,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "update domain with invalid json syntax",
args: []string{
domain.ID,
"{\"name\" : \"New domain\"",
token,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
var dom mgsdk.Domain
sdkCall := sdkMock.On("UpdateDomain", mock.Anything, tc.args[2]).Return(tc.domain, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{updCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &dom)
assert.Nil(t, err)
assert.Equal(t, tc.domain, dom, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.domain, dom))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestEnableDomainCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
domainsCmd := cli.NewDomainsCmd()
rootCmd := setFlags(domainsCmd)
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
errLogMessage string
logType outputLog
}{
{
desc: "enable domain successfully",
args: []string{
domain.ID,
validToken,
},
logType: entityLog,
},
{
desc: "enable domain with invalid token",
args: []string{
domain.ID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "enable domain with invalid domain id",
args: []string{
invalidID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "enable domain with invalid args",
args: []string{
domain.ID,
validToken,
extraArg,
},
logType: usageLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("EnableDomain", tc.args[0], tc.args[1]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{enableCmd}, tc.args...)...)
switch tc.logType {
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestDisableDomainCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
domainsCmd := cli.NewDomainsCmd()
rootCmd := setFlags(domainsCmd)
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
errLogMessage string
logType outputLog
}{
{
desc: "disable domain successfully",
args: []string{
domain.ID,
validToken,
},
logType: okLog,
},
{
desc: "disable domain with invalid token",
args: []string{
domain.ID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "disable domain with invalid id",
args: []string{
invalidID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "disable domain with invalid args",
args: []string{
domain.ID,
validToken,
extraArg,
},
logType: usageLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("DisableDomain", tc.args[0], tc.args[1]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{disableCmd}, tc.args...)...)
switch tc.logType {
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestAssignUserToDomainCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
domainsCmd := cli.NewDomainsCmd()
rootCmd := setFlags(domainsCmd)
userIds := fmt.Sprintf("[\"%s\"]", user.ID)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "assign user successfully",
args: []string{
relation,
userIds,
domain.ID,
token,
},
logType: okLog,
},
{
desc: "assign user with invalid args",
args: []string{
relation,
userIds,
domain.ID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "assign user with invalid json",
args: []string{
relation,
fmt.Sprintf("[\"%s\"", user.ID),
domain.ID,
token,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
{
desc: "assign user with invalid domain id",
args: []string{
relation,
userIds,
invalidID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "assign user with invalid user id",
args: []string{
relation,
fmt.Sprintf("[\"%s\"]", invalidID),
domain.ID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAddPolicies, http.StatusBadRequest),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAddPolicies, http.StatusBadRequest)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("AddUserToDomain", tc.args[2], mock.Anything, tc.args[3]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{assignCmd, usrCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestUnassignUserTodomainCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
domainsCmd := cli.NewDomainsCmd()
rootCmd := setFlags(domainsCmd)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "unassign user successfully",
args: []string{
user.ID,
domain.ID,
token,
},
logType: okLog,
},
{
desc: "unassign user with invalid args",
args: []string{
user.ID,
domain.ID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "unassign user with invalid domain id",
args: []string{
user.ID,
invalidID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "unassign user with invalid user id",
args: []string{
invalidID,
domain.ID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAddPolicies, http.StatusBadRequest),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAddPolicies, http.StatusBadRequest)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("RemoveUserFromDomain", tc.args[1], tc.args[0], tc.args[2]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{unassignCmd, usrCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
-348
View File
@@ -1,348 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"encoding/json"
"github.com/absmach/magistrala/internal/groups"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
var cmdGroups = []cobra.Command{
{
Use: "create <JSON_group> <domain_id> <user_auth_token>",
Short: "Create group",
Long: "Creates new group\n" +
"Usage:\n" +
"\tmagistrala-cli groups create '{\"name\":\"new group\", \"description\":\"new group description\", \"metadata\":{\"key\": \"value\"}}' $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
var group mgxsdk.Group
if err := json.Unmarshal([]byte(args[0]), &group); err != nil {
logErrorCmd(*cmd, err)
return
}
group.Status = groups.EnabledStatus.String()
group, err := sdk.CreateGroup(group, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, group)
},
},
{
Use: "update <JSON_group> <domain_id> <user_auth_token>",
Short: "Update group",
Long: "Updates group\n" +
"Usage:\n" +
"\tmagistrala-cli groups update '{\"id\":\"<group_id>\", \"name\":\"new group\", \"description\":\"new group description\", \"metadata\":{\"key\": \"value\"}}' $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
var group mgxsdk.Group
if err := json.Unmarshal([]byte(args[0]), &group); err != nil {
logErrorCmd(*cmd, err)
return
}
group, err := sdk.UpdateGroup(group, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, group)
},
},
{
Use: "get [all | children <group_id> | parents <group_id> | members <group_id> | <group_id>] <domain_id> <user_auth_token>",
Short: "Get group",
Long: "Get all users groups, group children or group by id.\n" +
"Usage:\n" +
"\tmagistrala-cli groups get all $DOMAINID $USERTOKEN - lists all groups\n" +
"\tmagistrala-cli groups get children <group_id> $DOMAINID $USERTOKEN - lists all children groups of <group_id>\n" +
"\tmagistrala-cli groups get parents <group_id> $DOMAINID $USERTOKEN - lists all parent groups of <group_id>\n" +
"\tmagistrala-cli groups get <group_id> $DOMAINID $USERTOKEN - shows group with provided group ID\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if args[0] == all {
if len(args) > 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
l, err := sdk.Groups(pm, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
if args[0] == "children" {
if len(args) > 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
DomainID: args[2],
}
l, err := sdk.Children(args[1], pm, args[2], args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
if args[0] == "parents" {
if len(args) > 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
l, err := sdk.Parents(args[1], pm, args[2], args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
if len(args) > 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
t, err := sdk.Group(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, t)
},
},
{
Use: "delete <group_id> <domain_id> <user_auth_token>",
Short: "Delete group",
Long: "Delete group by id.\n" +
"Usage:\n" +
"\tmagistrala-cli groups delete <group_id> $DOMAINID $USERTOKEN - delete the given group ID\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.DeleteGroup(args[0], args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "users <group_id> <domain_id> <user_auth_token>",
Short: "List users",
Long: "List users in a group\n" +
"Usage:\n" +
"\tmagistrala-cli groups users <group_id> $DOMAINID $USERTOKEN",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
Status: Status,
}
users, err := sdk.ListGroupUsers(args[0], pm, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, users)
},
},
{
Use: "channels <group_id> <domain_id> <user_auth_token>",
Short: "List channels",
Long: "List channels in a group\n" +
"Usage:\n" +
"\tmagistrala-cli groups channels <group_id> $DOMAINID $USERTOKEN",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
Status: Status,
}
channels, err := sdk.ListGroupChannels(args[0], pm, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, channels)
},
},
{
Use: "enable <group_id> <domain_id> <user_auth_token>",
Short: "Change group status to enabled",
Long: "Change group status to enabled\n" +
"Usage:\n" +
"\tmagistrala-cli groups enable <group_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
group, err := sdk.EnableGroup(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, group)
},
},
{
Use: "disable <group_id> <domain_id> <user_auth_token>",
Short: "Change group status to disabled",
Long: "Change group status to disabled\n" +
"Usage:\n" +
"\tmagistrala-cli groups disable <group_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
group, err := sdk.DisableGroup(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, group)
},
},
}
var groupAssignCmds = []cobra.Command{
{
Use: "users <relation> <user_ids> <group_id> <domain_id> <user_auth_token>",
Short: "Assign users",
Long: "Assign users to a group\n" +
"Usage:\n" +
"\tmagistrala-cli groups assign users <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <group_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 5 {
logUsageCmd(*cmd, cmd.Use)
return
}
var userIDs []string
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.AddUserToGroup(args[2], mgxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3], args[4]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
var groupUnassignCmds = []cobra.Command{
{
Use: "users <relation> <user_ids> <group_id> <domain_id> <user_auth_token>",
Short: "Unassign users",
Long: "Unassign users from a group\n" +
"Usage:\n" +
"\tmagistrala-cli groups unassign users <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <group_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 5 {
logUsageCmd(*cmd, cmd.Use)
return
}
var userIDs []string
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.RemoveUserFromGroup(args[2], mgxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3], args[4]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
func NewGroupAssignCmds() *cobra.Command {
cmd := cobra.Command{
Use: "assign [users]",
Short: "Assign users to a group",
Long: "Assign users to a group",
}
for i := range groupAssignCmds {
cmd.AddCommand(&groupAssignCmds[i])
}
return &cmd
}
func NewGroupUnassignCmds() *cobra.Command {
cmd := cobra.Command{
Use: "unassign [users]",
Short: "Unassign users from a group",
Long: "Unassign users from a group",
}
for i := range groupUnassignCmds {
cmd.AddCommand(&groupUnassignCmds[i])
}
return &cmd
}
// NewGroupsCmd returns users command.
func NewGroupsCmd() *cobra.Command {
cmd := cobra.Command{
Use: "groups [create | get | update | delete | assign | unassign | users | channels ]",
Short: "Groups management",
Long: `Groups management: create, update, delete group and assign and unassign member to groups"`,
}
for i := range cmdGroups {
cmd.AddCommand(&cmdGroups[i])
}
cmd.AddCommand(NewGroupAssignCmds())
cmd.AddCommand(NewGroupUnassignCmds())
return &cmd
}
-985
View File
@@ -1,985 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var group = mgsdk.Group{
ID: testsutil.GenerateUUID(&testing.T{}),
Name: "testgroup",
}
func TestCreateGroupCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupJson := "{\"name\":\"testgroup\", \"metadata\":{\"key1\":\"value1\"}}"
groupCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupCmd)
gp := mgsdk.Group{}
cases := []struct {
desc string
args []string
logType outputLog
group mgsdk.Group
sdkErr errors.SDKError
errLogMessage string
}{
{
desc: "create group successfully",
args: []string{
groupJson,
domainID,
token,
},
group: group,
logType: entityLog,
},
{
desc: "create group with invalid args",
args: []string{
groupJson,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "create group with invalid json",
args: []string{
"{\"name\":\"testgroup\", \"metadata\":{\"key1\":\"value1\"}",
domainID,
token,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
{
desc: "create group with invalid token",
args: []string{
groupJson,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
{
desc: "create group with invalid domain",
args: []string{
groupJson,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("CreateGroup", mock.Anything, tc.args[1], tc.args[2]).Return(tc.group, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{createCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &gp)
assert.Nil(t, err)
assert.Equal(t, tc.group, gp, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.group, gp))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestGetGroupsCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupCmd)
var ch mgsdk.Group
var page mgsdk.GroupsPage
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
page mgsdk.GroupsPage
group mgsdk.Group
logType outputLog
errLogMessage string
}{
{
desc: "get all groups successfully",
args: []string{
all,
domainID,
token,
},
page: mgsdk.GroupsPage{
Groups: []mgsdk.Group{group},
},
logType: entityLog,
},
{
desc: "get all groups with invalid args",
args: []string{
all,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "get children groups successfully",
args: []string{
childCmd,
group.ID,
domainID,
token,
},
page: mgsdk.GroupsPage{
Groups: []mgsdk.Group{group},
},
logType: entityLog,
},
{
desc: "get children groups with invalid args",
args: []string{
childCmd,
group.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "get children groups with invalid token",
args: []string{
childCmd,
group.ID,
domainID,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "get parents groups successfully",
args: []string{
parentCmd,
group.ID,
domainID,
token,
},
page: mgsdk.GroupsPage{
Groups: []mgsdk.Group{group},
},
logType: entityLog,
},
{
desc: "get parents groups with invalid args",
args: []string{
parentCmd,
group.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "get parents groups with invalid token",
args: []string{
parentCmd,
group.ID,
domainID,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "get group with id",
args: []string{
group.ID,
domainID,
token,
},
logType: entityLog,
group: group,
},
{
desc: "get groups with invalid args",
args: []string{
all,
},
logType: usageLog,
},
{
desc: "get all groups with invalid token",
args: []string{
all,
domainID,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "get group with invalid domain",
args: []string{
group.ID,
invalidID,
token,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrDomainAuthorization, http.StatusForbidden)),
},
{
desc: "get group with invalid id",
args: []string{
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "get group with invalid args",
args: []string{
group.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("Group", mock.Anything, mock.Anything, mock.Anything).Return(tc.group, tc.sdkErr)
sdkCall1 := sdkMock.On("Groups", mock.Anything, mock.Anything, mock.Anything).Return(tc.page, tc.sdkErr)
sdkCall2 := sdkMock.On("Parents", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.page, tc.sdkErr)
sdkCall3 := sdkMock.On("Children", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{getCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
if tc.args[1] == all {
err := json.Unmarshal([]byte(out), &page)
assert.Nil(t, err)
assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page))
} else {
err := json.Unmarshal([]byte(out), &ch)
assert.Nil(t, err)
assert.Equal(t, tc.group, ch, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.group, ch))
}
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
sdkCall1.Unset()
sdkCall2.Unset()
sdkCall3.Unset()
})
}
}
func TestDeletegroupCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupCmd)
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
logType outputLog
errLogMessage string
}{
{
desc: "delete group successfully",
args: []string{
group.ID,
domainID,
token,
},
logType: okLog,
},
{
desc: "delete group with invalid args",
args: []string{
group.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "delete group with invalid id",
args: []string{
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "delete group with invalid token",
args: []string{
group.ID,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("DeleteGroup", tc.args[0], tc.args[1], tc.args[2]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{delCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestUpdategroupCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupCmd)
newGroupJson := fmt.Sprintf("{\"id\":\"%s\",\"name\" : \"newgroup\"}", group.ID)
cases := []struct {
desc string
args []string
group mgsdk.Group
sdkErr errors.SDKError
errLogMessage string
logType outputLog
}{
{
desc: "update group successfully",
args: []string{
newGroupJson,
domainID,
token,
},
group: mgsdk.Group{
Name: "newgroup1",
ID: group.ID,
},
logType: entityLog,
},
{
desc: "update group with invalid args",
args: []string{
newGroupJson,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "update group with invalid group id",
args: []string{
fmt.Sprintf("{\"id\":\"%s\",\"name\" : \"group1\"}", invalidID),
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "update group with invalid json syntax",
args: []string{
fmt.Sprintf("{\"id\":\"%s\",\"name\" : \"group1\"", group.ID),
domainID,
token,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
var ch mgsdk.Group
sdkCall := sdkMock.On("UpdateGroup", mock.Anything, tc.args[1], tc.args[2]).Return(tc.group, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{updCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &ch)
assert.Nil(t, err)
assert.Equal(t, tc.group, ch, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.group, ch))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestListUsersCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupsCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupsCmd)
var up mgsdk.UsersPage
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
errLogMessage string
logType outputLog
page mgsdk.UsersPage
}{
{
desc: "list users successfully",
args: []string{
group.ID,
domainID,
token,
},
page: mgsdk.UsersPage{
PageRes: mgsdk.PageRes{
Total: 1,
Offset: 0,
Limit: 10,
},
Users: []mgsdk.User{user},
},
logType: entityLog,
},
{
desc: "list users with invalid args",
args: []string{
group.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "list users with invalid id",
args: []string{
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("ListGroupUsers", tc.args[0], mock.Anything, tc.args[1], tc.args[2]).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{usrCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &up)
if err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
assert.Equal(t, tc.page, up, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, up))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestListChannelsCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupsCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupsCmd)
var cp mgsdk.ChannelsPage
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
errLogMessage string
logType outputLog
page mgsdk.ChannelsPage
}{
{
desc: "list channels successfully",
args: []string{
group.ID,
domainID,
token,
},
page: mgsdk.ChannelsPage{
PageRes: mgsdk.PageRes{
Total: 1,
Offset: 0,
Limit: 10,
},
Channels: []mgsdk.Channel{channel},
},
logType: entityLog,
},
{
desc: "list channels with invalid args",
args: []string{
group.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "list channels with invalid id",
args: []string{
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("ListGroupChannels", tc.args[0], mock.Anything, tc.args[1], tc.args[2]).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{chansCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &cp)
if err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
assert.Equal(t, tc.page, cp, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, cp))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestEnablegroupCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupCmd)
var ch mgsdk.Group
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
errLogMessage string
group mgsdk.Group
logType outputLog
}{
{
desc: "enable group successfully",
args: []string{
group.ID,
domainID,
validToken,
},
group: group,
logType: entityLog,
},
{
desc: "delete group with invalid token",
args: []string{
group.ID,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "delete group with invalid group ID",
args: []string{
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "enable group with invalid args",
args: []string{
group.ID,
domainID,
validToken,
extraArg,
},
logType: usageLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("EnableGroup", tc.args[0], tc.args[1], tc.args[2]).Return(tc.group, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{enableCmd}, tc.args...)...)
switch tc.logType {
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case entityLog:
err := json.Unmarshal([]byte(out), &ch)
assert.Nil(t, err)
assert.Equal(t, tc.group, ch, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.group, ch))
}
sdkCall.Unset()
})
}
}
func TestDisablegroupCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupsCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupsCmd)
var ch mgsdk.Group
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
errLogMessage string
group mgsdk.Group
logType outputLog
}{
{
desc: "disable group successfully",
args: []string{
group.ID,
domainID,
validToken,
},
logType: entityLog,
group: group,
},
{
desc: "disable group with invalid token",
args: []string{
group.ID,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "disable group with invalid id",
args: []string{
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "disable thing with invalid args",
args: []string{
group.ID,
domainID,
validToken,
extraArg,
},
logType: usageLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("DisableGroup", tc.args[0], tc.args[1], tc.args[2]).Return(tc.group, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{disableCmd}, tc.args...)...)
switch tc.logType {
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case entityLog:
err := json.Unmarshal([]byte(out), &ch)
if err != nil {
t.Fatalf("json.Unmarshal failed: %v", err)
}
assert.Equal(t, tc.group, ch, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.group, ch))
}
sdkCall.Unset()
})
}
}
func TestAssignUserToGroupCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupsCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupsCmd)
userIds := fmt.Sprintf("[\"%s\"]", user.ID)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "assign user successfully",
args: []string{
relation,
userIds,
group.ID,
domainID,
token,
},
logType: okLog,
},
{
desc: "assign user with invalid args",
args: []string{
relation,
userIds,
group.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "assign user with invalid json",
args: []string{
relation,
fmt.Sprintf("[\"%s\"", user.ID),
group.ID,
domainID,
token,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
{
desc: "assign user with invalid group id",
args: []string{
relation,
userIds,
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "assign user with invalid user id",
args: []string{
relation,
fmt.Sprintf("[\"%s\"]", invalidID),
group.ID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAddPolicies, http.StatusBadRequest),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAddPolicies, http.StatusBadRequest)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("AddUserToGroup", tc.args[2], mock.Anything, tc.args[3], tc.args[4]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{assignCmd, usrCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
func TestUnassignUserToGroupCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
groupsCmd := cli.NewGroupsCmd()
rootCmd := setFlags(groupsCmd)
userIds := fmt.Sprintf("[\"%s\"]", user.ID)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "unassign user successfully",
args: []string{
relation,
userIds,
group.ID,
domainID,
token,
},
logType: okLog,
},
{
desc: "unassign user with invalid args",
args: []string{
relation,
userIds,
group.ID,
domainID,
token,
extraArg,
},
logType: usageLog,
},
{
desc: "unassign user with invalid json",
args: []string{
relation,
fmt.Sprintf("[\"%s\"", user.ID),
group.ID,
domainID,
token,
},
sdkErr: errors.NewSDKError(errors.New("unexpected end of JSON input")),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.New("unexpected end of JSON input")),
logType: errLog,
},
{
desc: "unassign user with invalid group id",
args: []string{
relation,
userIds,
invalidID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
{
desc: "unassign user with invalid user id",
args: []string{
relation,
fmt.Sprintf("[\"%s\"]", invalidID),
group.ID,
domainID,
token,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAddPolicies, http.StatusBadRequest),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAddPolicies, http.StatusBadRequest)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("RemoveUserFromGroup", tc.args[2], mock.Anything, tc.args[3], tc.args[4]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{unassignCmd, usrCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
}
sdkCall.Unset()
})
}
}
-30
View File
@@ -1,30 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import "github.com/spf13/cobra"
// NewHealthCmd returns health check command.
func NewHealthCmd() *cobra.Command {
return &cobra.Command{
Use: "health <service>",
Short: "Health Check",
Long: "Magistrala service Health Check\n" +
"usage:\n" +
"\tmagistrala-cli health <service>",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logUsageCmd(*cmd, cmd.Use)
return
}
v, err := sdk.Health(args[0])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, v)
},
}
}
-84
View File
@@ -1,84 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"strings"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/pkg/errors"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestHealthCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
healthCmd := cli.NewHealthCmd()
rootCmd := setFlags(healthCmd)
service := "users"
var health mgsdk.HealthInfo
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
health mgsdk.HealthInfo
sdkErr errors.SDKError
}{
{
desc: "Check health successfully",
args: []string{
service,
},
logType: entityLog,
health: mgsdk.HealthInfo{
Status: "pass",
Description: "users service",
},
},
{
desc: "Check health with invalid args",
args: []string{
service,
extraArg,
},
logType: usageLog,
},
{
desc: "Check health with invalid service",
args: []string{
"invalid",
},
sdkErr: errors.NewSDKErrorWithStatus(errors.New("unsupported protocol scheme"), 306),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(errors.New("unsupported protocol scheme"), 306)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("Health", mock.Anything).Return(tc.health, tc.sdkErr)
out := executeCommand(t, rootCmd, tc.args...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &health)
assert.Nil(t, err)
assert.Equal(t, tc.health, health, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.health, health))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.True(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
-148
View File
@@ -1,148 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
var cmdInvitations = []cobra.Command{
{
Use: "send <user_id> <domain_id> <relation> <user_auth_token>",
Short: "Send invitation",
Long: "Send invitation to user\n" +
"For example:\n" +
"\tmagistrala-cli invitations send 39f97daf-d6b6-40f4-b229-2697be8006ef 4ef09eff-d500-4d56-b04f-d23a512d6f2a administrator $USER_AUTH_TOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
inv := mgxsdk.Invitation{
UserID: args[0],
DomainID: args[1],
Relation: args[2],
}
if err := sdk.SendInvitation(inv, args[3]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "get [all | <user_id> <domain_id> ] <user_auth_token>",
Short: "Get invitations",
Long: "Get invitations\n" +
"Usage:\n" +
"\tmagistrala-cli invitations get all <user_auth_token> - lists all invitations\n" +
"\tmagistrala-cli invitations get all <user_auth_token> --offset <offset> --limit <limit> - lists all invitations with provided offset and limit\n" +
"\tmagistrala-cli invitations get <user_id> <domain_id> <user_auth_token> - shows invitation by user id and domain id\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 && len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pageMetadata := mgxsdk.PageMetadata{
Identity: Identity,
Offset: Offset,
Limit: Limit,
}
if args[0] == all {
l, err := sdk.Invitations(pageMetadata, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
u, err := sdk.Invitation(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, u)
},
},
{
Use: "accept <domain_id> <user_auth_token>",
Short: "Accept invitation",
Long: "Accept invitation to domain\n" +
"Usage:\n" +
"\tmagistrala-cli invitations accept 39f97daf-d6b6-40f4-b229-2697be8006ef $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.AcceptInvitation(args[0], args[1]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "reject <domain_id> <user_auth_token>",
Short: "Reject invitation",
Long: "Reject invitation to domain\n" +
"Usage:\n" +
"\tmagistrala-cli invitations reject 39f97daf-d6b6-40f4-b229-2697be8006ef $USER_AUTH_TOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.RejectInvitation(args[0], args[1]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "delete <user_id> <domain_id> <user_auth_token>",
Short: "Delete invitation",
Long: "Delete invitation\n" +
"Usage:\n" +
"\tmagistrala-cli invitations delete 39f97daf-d6b6-40f4-b229-2697be8006ef 4ef09eff-d500-4d56-b04f-d23a512d6f2a $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.DeleteInvitation(args[0], args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
}
// NewInvitationsCmd returns invitations command.
func NewInvitationsCmd() *cobra.Command {
cmd := cobra.Command{
Use: "invitations [send | get | accept | delete]",
Short: "Invitations management",
Long: `Invitations management to send, get, accept and delete invitations`,
}
for i := range cmdInvitations {
cmd.AddCommand(&cmdInvitations[i])
}
return &cmd
}
-376
View File
@@ -1,376 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var invitation = mgsdk.Invitation{
InvitedBy: testsutil.GenerateUUID(&testing.T{}),
UserID: user.ID,
DomainID: domain.ID,
}
func TestSendUserInvitationCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
invCmd := cli.NewInvitationsCmd()
rootCmd := setFlags(invCmd)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "send invitation successfully",
args: []string{
user.ID,
domain.ID,
relation,
validToken,
},
logType: okLog,
},
{
desc: "send invitation with invalid args",
args: []string{
user.ID,
domain.ID,
relation,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "send invitation with invalid token",
args: []string{
user.ID,
domain.ID,
relation,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("SendInvitation", mock.Anything, mock.Anything).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{sendCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestGetInvitationCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
invCmd := cli.NewInvitationsCmd()
rootCmd := setFlags(invCmd)
var inv mgsdk.Invitation
var page mgsdk.InvitationPage
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
page mgsdk.InvitationPage
inv mgsdk.Invitation
logType outputLog
errLogMessage string
}{
{
desc: "get all invitations successfully",
args: []string{
all,
token,
},
page: mgsdk.InvitationPage{
Total: 1,
Offset: 0,
Limit: 10,
Invitations: []mgsdk.Invitation{invitation},
},
logType: entityLog,
},
{
desc: "get invitation with user id",
args: []string{
user.ID,
domain.ID,
token,
},
logType: entityLog,
inv: invitation,
},
{
desc: "get invitation with invalid args",
args: []string{
all,
token,
extraArg,
extraArg,
},
logType: usageLog,
},
{
desc: "get all invitations with invalid token",
args: []string{
all,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
{
desc: "get invitation with invalid token",
args: []string{
user.ID,
domain.ID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("Invitation", tc.args[0], tc.args[1], mock.Anything).Return(tc.inv, tc.sdkErr)
sdkCall1 := sdkMock.On("Invitations", mock.Anything, tc.args[1]).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{getCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
if tc.args[0] == all {
err := json.Unmarshal([]byte(out), &page)
assert.Nil(t, err)
assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page))
} else {
err := json.Unmarshal([]byte(out), &inv)
assert.Nil(t, err)
assert.Equal(t, tc.inv, inv, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.inv, inv))
}
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
sdkCall1.Unset()
})
}
}
func TestAcceptInvitationCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
invCmd := cli.NewInvitationsCmd()
rootCmd := setFlags(invCmd)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "accept invitation successfully",
args: []string{
domain.ID,
validToken,
},
logType: okLog,
},
{
desc: "accept invitation with invalid args",
args: []string{
domain.ID,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "accept invitation with invalid token",
args: []string{
domain.ID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("AcceptInvitation", mock.Anything, mock.Anything).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{acceptCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestRejectInvitationCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
invCmd := cli.NewInvitationsCmd()
rootCmd := setFlags(invCmd)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "reject invitation successfully",
args: []string{
domain.ID,
validToken,
},
logType: okLog,
},
{
desc: "reject invitation with invalid args",
args: []string{
domain.ID,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "reject invitation with invalid token",
args: []string{
domain.ID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("RejectInvitation", mock.Anything, mock.Anything).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{rejectCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestDeleteInvitationCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
invCmd := cli.NewInvitationsCmd()
rootCmd := setFlags(invCmd)
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "delete invitation successfully",
args: []string{
user.ID,
domain.ID,
validToken,
},
logType: okLog,
},
{
desc: "delete invitation with invalid args",
args: []string{
user.ID,
domain.ID,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "delete invitation with invalid token",
args: []string{
user.ID,
domain.ID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("DeleteInvitation", mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{delCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
-56
View File
@@ -1,56 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
var cmdJournal = cobra.Command{
Use: "get <entity_type> <entity_id> <domain_id> <user_auth_token>",
Short: "Get journal",
Long: "Get journal\n" +
"Usage:\n" +
"\tmagistrala-cli journal get user <user_id> <user_auth_token> - lists user journal logs\n" +
"\tmagistrala-cli journal get <entity_type> <entity_id> <domain_id> <user_auth_token> - lists entity journal logs\n" +
"\tmagistrala-cli journal get <entity_type> <entity_id> <domain_id> <user_auth_token> --offset <offset> --limit <limit> - lists user journal logs with provided offset and limit\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 3 || len(args) > 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
pageMetadata := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
entityType, entityID, token := args[0], args[1], args[2]
domainID := ""
if len(args) == 4 {
entityType, entityID, domainID, token = args[0], args[1], args[2], args[3]
}
journal, err := sdk.Journal(entityType, entityID, domainID, pageMetadata, token)
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, journal)
},
}
// NewJournalCmd returns journal log command.
func NewJournalCmd() *cobra.Command {
cmd := cobra.Command{
Use: "journal get",
Short: "journal log",
Long: `journal to read journal log`,
}
cmd.AddCommand(&cmdJournal)
return &cmd
}
-123
View File
@@ -1,123 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var journal = mgsdk.Journal{
ID: testsutil.GenerateUUID(&testing.T{}),
}
func TestGetJournalCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
invCmd := cli.NewJournalCmd()
rootCmd := setFlags(invCmd)
var page mgsdk.JournalsPage
entityType := "group"
entityId := testsutil.GenerateUUID(t)
domainId := testsutil.GenerateUUID(t)
cases := []struct {
desc string
args []string
sdkErr errors.SDKError
page mgsdk.JournalsPage
logType outputLog
errLogMessage string
}{
{
desc: "get user journal",
args: []string{
"user",
entityId,
token,
},
logType: entityLog,
page: mgsdk.JournalsPage{
Total: 1,
Offset: 0,
Limit: 10,
Journals: []mgsdk.Journal{journal},
},
},
{
desc: "get group journal",
args: []string{
entityType,
entityId,
domainId,
token,
},
logType: entityLog,
page: mgsdk.JournalsPage{
Total: 1,
Offset: 0,
Limit: 10,
Journals: []mgsdk.Journal{journal},
},
},
{
desc: "get journal with invalid args",
args: []string{
entityType,
entityId,
token,
domainId,
extraArg,
},
logType: usageLog,
},
{
desc: "get journal with invalid token",
args: []string{
entityType,
entityId,
domainId,
invalidToken,
},
logType: errLog,
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden)),
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("Journal", tc.args[0], tc.args[1], "", mock.Anything, tc.args[2]).Return(tc.page, tc.sdkErr)
if tc.args[0] != "user" {
sdkCall = sdkMock.On("Journal", tc.args[0], tc.args[1], tc.args[2], mock.Anything, tc.args[3]).Return(tc.page, tc.sdkErr)
}
out := executeCommand(t, rootCmd, append([]string{getCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &page)
assert.Nil(t, err)
assert.Equal(t, tc.page, page, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.page, page))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
-72
View File
@@ -1,72 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
var cmdMessages = []cobra.Command{
{
Use: "send <channel_id.subtopic> <JSON_string> <thing_secret>",
Short: "Send messages",
Long: `Sends message on the channel`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.SendMessage(args[0], args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "read <channel_id.subtopic> <domain_id> <user_token>",
Short: "Read messages",
Long: "Reads all channel messages\n" +
"Usage:\n" +
"\tmagistrala-cli messages read <channel_id.subtopic> <domain_id> <user_token> --offset <offset> --limit <limit> - lists all messages with provided offset and limit\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pageMetadata := mgxsdk.MessagePageMetadata{
PageMetadata: mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
},
}
m, err := sdk.ReadMessages(pageMetadata, args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, m)
},
},
}
// NewMessagesCmd returns messages command.
func NewMessagesCmd() *cobra.Command {
cmd := cobra.Command{
Use: "messages [send | read]",
Short: "Send or read messages",
Long: `Send or read messages using the http-adapter and the configured database reader`,
}
for i := range cmdMessages {
cmd.AddCommand(&cmdMessages[i])
}
return &cmd
}
-165
View File
@@ -1,165 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
mgsdk "github.com/absmach/magistrala/pkg/sdk/go"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/absmach/magistrala/pkg/transformers/senml"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestSendMesageCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
messageCmd := cli.NewMessagesCmd()
rootCmd := setFlags(messageCmd)
message := "[{\"bn\":\"Dev1\",\"n\":\"temp\",\"v\":20}, {\"n\":\"hum\",\"v\":40}, {\"bn\":\"Dev2\", \"n\":\"temp\",\"v\":20}, {\"n\":\"hum\",\"v\":40}]"
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
}{
{
desc: "send message successfully",
args: []string{
channel.ID,
message,
thing.Credentials.Secret,
},
logType: okLog,
},
{
desc: "send message with invalid args",
args: []string{
channel.ID,
message,
thing.Credentials.Secret,
extraArg,
},
logType: usageLog,
},
{
desc: "send message with invalid thing secret",
args: []string{
channel.ID,
message,
"invalid_secret",
},
sdkErr: errors.NewSDKErrorWithStatus(errors.Wrap(svcerr.ErrAuthentication, errors.Wrap(svcerr.ErrAuthorization, svcerr.ErrNotFound)), http.StatusBadRequest),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(errors.Wrap(svcerr.ErrAuthentication, errors.Wrap(svcerr.ErrAuthorization, svcerr.ErrNotFound)), http.StatusBadRequest)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("SendMessage", tc.args[0], tc.args[1], tc.args[2]).Return(tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{sendCmd}, tc.args...)...)
switch tc.logType {
case okLog:
assert.True(t, strings.Contains(out, "ok"), fmt.Sprintf("%s unexpected response: expected success message, got: %v", tc.desc, out))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
func TestReadMesageCmd(t *testing.T) {
sdkMock := new(sdkmocks.SDK)
cli.SetSDK(sdkMock)
messageCmd := cli.NewMessagesCmd()
rootCmd := setFlags(messageCmd)
var mp mgsdk.MessagesPage
cases := []struct {
desc string
args []string
logType outputLog
errLogMessage string
sdkErr errors.SDKError
page mgsdk.MessagesPage
}{
{
desc: "read message successfully",
args: []string{
channel.ID,
domainID,
validToken,
},
page: mgsdk.MessagesPage{
PageRes: mgsdk.PageRes{
Total: 1,
Offset: 0,
Limit: 10,
},
Messages: []senml.Message{
{
Channel: channel.ID,
},
},
},
logType: entityLog,
},
{
desc: "read message with invalid args",
args: []string{
channel.ID,
domainID,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "read message with invalid token",
args: []string{
channel.ID,
domainID,
invalidToken,
},
sdkErr: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized),
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusUnauthorized)),
logType: errLog,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sdkCall := sdkMock.On("ReadMessages", mock.Anything, tc.args[0], tc.args[1], tc.args[2]).Return(tc.page, tc.sdkErr)
out := executeCommand(t, rootCmd, append([]string{readCmd}, tc.args...)...)
switch tc.logType {
case entityLog:
err := json.Unmarshal([]byte(out), &mp)
assert.Nil(t, err)
assert.Equal(t, tc.page, mp, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.page, mp))
case errLog:
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
case usageLog:
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
}
sdkCall.Unset()
})
}
}
-404
View File
@@ -1,404 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"encoding/csv"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand"
"os"
"path/filepath"
"time"
"github.com/0x6flab/namegenerator"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/spf13/cobra"
)
const (
jsonExt = ".json"
csvExt = ".csv"
)
var (
msgFormat = `[{"bn":"provision:", "bu":"V", "t": %d, "bver":5, "n":"voltage", "u":"V", "v":%d}]`
namesgenerator = namegenerator.NewGenerator()
)
var cmdProvision = []cobra.Command{
{
Use: "things <things_file> <domain_id> <user_token>",
Short: "Provision things",
Long: `Bulk create things`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if _, err := os.Stat(args[0]); os.IsNotExist(err) {
logErrorCmd(*cmd, err)
return
}
things, err := thingsFromFile(args[0])
if err != nil {
logErrorCmd(*cmd, err)
return
}
things, err = sdk.CreateThings(things, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, things)
},
},
{
Use: "channels <channels_file> <domain_id> <user_token>",
Short: "Provision channels",
Long: `Bulk create channels`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
channels, err := channelsFromFile(args[0])
if err != nil {
logErrorCmd(*cmd, err)
return
}
var chs []mgxsdk.Channel
for _, c := range channels {
c, err = sdk.CreateChannel(c, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
chs = append(chs, c)
}
channels = chs
logJSONCmd(*cmd, channels)
},
},
{
Use: "connect <connections_file> <domain_id> <user_token>",
Short: "Provision connections",
Long: `Bulk connect things to channels`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
connIDs, err := connectionsFromFile(args[0])
if err != nil {
logErrorCmd(*cmd, err)
return
}
for _, conn := range connIDs {
if err := sdk.Connect(conn, args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
}
logOKCmd(*cmd)
},
},
{
Use: "test",
Short: "test",
Long: `Provisions test setup: one test user, two things and two channels. \
Connect both things to one of the channels, \
and only on thing to other channel.`,
Run: func(cmd *cobra.Command, args []string) {
numThings := 2
numChan := 2
things := []mgxsdk.Thing{}
channels := []mgxsdk.Channel{}
if len(args) != 0 {
logUsageCmd(*cmd, cmd.Use)
return
}
// Create test user
name := namesgenerator.Generate()
user := mgxsdk.User{
FirstName: name,
Email: fmt.Sprintf("%s@email.com", name),
Credentials: mgxsdk.Credentials{
Username: name,
Secret: "12345678",
},
Status: mgxsdk.EnabledStatus,
}
user, err := sdk.CreateUser(user, "")
if err != nil {
logErrorCmd(*cmd, err)
return
}
ut, err := sdk.CreateToken(mgxsdk.Login{Identity: user.Credentials.Username, Secret: user.Credentials.Secret})
if err != nil {
logErrorCmd(*cmd, err)
return
}
// create domain
domain := mgxsdk.Domain{
Name: fmt.Sprintf("%s-domain", name),
Status: mgxsdk.EnabledStatus,
}
domain, err = sdk.CreateDomain(domain, ut.AccessToken)
if err != nil {
logErrorCmd(*cmd, err)
return
}
ut, err = sdk.CreateToken(mgxsdk.Login{Identity: user.Email, Secret: user.Credentials.Secret})
if err != nil {
logErrorCmd(*cmd, err)
return
}
// Create things
for i := 0; i < numThings; i++ {
t := mgxsdk.Thing{
Name: fmt.Sprintf("%s-thing-%d", name, i),
Status: mgxsdk.EnabledStatus,
}
things = append(things, t)
}
things, err = sdk.CreateThings(things, domain.ID, ut.AccessToken)
if err != nil {
logErrorCmd(*cmd, err)
return
}
// Create channels
for i := 0; i < numChan; i++ {
c := mgxsdk.Channel{
Name: fmt.Sprintf("%s-channel-%d", name, i),
Status: mgxsdk.EnabledStatus,
}
c, err = sdk.CreateChannel(c, domain.ID, ut.AccessToken)
if err != nil {
logErrorCmd(*cmd, err)
return
}
channels = append(channels, c)
}
// Connect things to channels - first thing to both channels, second only to first
conIDs := mgxsdk.Connection{
ChannelID: channels[0].ID,
ThingID: things[0].ID,
}
if err := sdk.Connect(conIDs, domain.ID, ut.AccessToken); err != nil {
logErrorCmd(*cmd, err)
return
}
conIDs = mgxsdk.Connection{
ChannelID: channels[1].ID,
ThingID: things[0].ID,
}
if err := sdk.Connect(conIDs, domain.ID, ut.AccessToken); err != nil {
logErrorCmd(*cmd, err)
return
}
conIDs = mgxsdk.Connection{
ChannelID: channels[0].ID,
ThingID: things[1].ID,
}
if err := sdk.Connect(conIDs, domain.ID, ut.AccessToken); err != nil {
logErrorCmd(*cmd, err)
return
}
// send message to test connectivity
if err := sdk.SendMessage(channels[0].ID, fmt.Sprintf(msgFormat, time.Now().Unix(), rand.Int()), things[0].Credentials.Secret); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.SendMessage(channels[0].ID, fmt.Sprintf(msgFormat, time.Now().Unix(), rand.Int()), things[1].Credentials.Secret); err != nil {
logErrorCmd(*cmd, err)
return
}
if err := sdk.SendMessage(channels[1].ID, fmt.Sprintf(msgFormat, time.Now().Unix(), rand.Int()), things[0].Credentials.Secret); err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user, ut, things, channels)
},
},
}
// NewProvisionCmd returns provision command.
func NewProvisionCmd() *cobra.Command {
cmd := cobra.Command{
Use: "provision [things | channels | connect | test]",
Short: "Provision things and channels from a config file",
Long: `Provision things and channels: use json or csv file to bulk provision things and channels`,
}
for i := range cmdProvision {
cmd.AddCommand(&cmdProvision[i])
}
return &cmd
}
func thingsFromFile(path string) ([]mgxsdk.Thing, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return []mgxsdk.Thing{}, err
}
file, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm)
if err != nil {
return []mgxsdk.Thing{}, err
}
defer file.Close()
things := []mgxsdk.Thing{}
switch filepath.Ext(path) {
case csvExt:
reader := csv.NewReader(file)
for {
l, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
return []mgxsdk.Thing{}, err
}
if len(l) < 1 {
return []mgxsdk.Thing{}, errors.New("empty line found in file")
}
thing := mgxsdk.Thing{
Name: l[0],
}
things = append(things, thing)
}
case jsonExt:
err := json.NewDecoder(file).Decode(&things)
if err != nil {
return []mgxsdk.Thing{}, err
}
default:
return []mgxsdk.Thing{}, err
}
return things, nil
}
func channelsFromFile(path string) ([]mgxsdk.Channel, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return []mgxsdk.Channel{}, err
}
file, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm)
if err != nil {
return []mgxsdk.Channel{}, err
}
defer file.Close()
channels := []mgxsdk.Channel{}
switch filepath.Ext(path) {
case csvExt:
reader := csv.NewReader(file)
for {
l, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
return []mgxsdk.Channel{}, err
}
if len(l) < 1 {
return []mgxsdk.Channel{}, errors.New("empty line found in file")
}
channel := mgxsdk.Channel{
Name: l[0],
}
channels = append(channels, channel)
}
case jsonExt:
err := json.NewDecoder(file).Decode(&channels)
if err != nil {
return []mgxsdk.Channel{}, err
}
default:
return []mgxsdk.Channel{}, err
}
return channels, nil
}
func connectionsFromFile(path string) ([]mgxsdk.Connection, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return []mgxsdk.Connection{}, err
}
file, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm)
if err != nil {
return []mgxsdk.Connection{}, err
}
defer file.Close()
connections := []mgxsdk.Connection{}
switch filepath.Ext(path) {
case csvExt:
reader := csv.NewReader(file)
for {
l, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
return []mgxsdk.Connection{}, err
}
if len(l) < 1 {
return []mgxsdk.Connection{}, errors.New("empty line found in file")
}
connections = append(connections, mgxsdk.Connection{
ThingID: l[0],
ChannelID: l[1],
})
}
case jsonExt:
err := json.NewDecoder(file).Decode(&connections)
if err != nil {
return []mgxsdk.Connection{}, err
}
default:
return []mgxsdk.Connection{}, err
}
return connections, nil
}
-14
View File
@@ -1,14 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
// Keep SDK handle in global var.
var sdk mgxsdk.SDK
// SetSDK sets magistrala SDK instance.
func SetSDK(s mgxsdk.SDK) {
sdk = s
}
-120
View File
@@ -1,120 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli_test
import (
"bytes"
"testing"
"github.com/absmach/magistrala/cli"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
)
type outputLog uint8
const (
usageLog outputLog = iota
errLog
entityLog
okLog
createLog
revokeLog
)
func executeCommand(t *testing.T, root *cobra.Command, args ...string) string {
buffer := new(bytes.Buffer)
root.SetOut(buffer)
root.SetErr(buffer)
root.SetArgs(args)
err := root.Execute()
assert.NoError(t, err, "Error executing command")
return buffer.String()
}
func setFlags(rootCmd *cobra.Command) *cobra.Command {
// Root Flags
rootCmd.PersistentFlags().BoolVarP(
&cli.RawOutput,
"raw",
"r",
cli.RawOutput,
"Enables raw output mode for easier parsing of output",
)
// Client and Channels Flags
rootCmd.PersistentFlags().Uint64VarP(
&cli.Limit,
"limit",
"l",
10,
"Limit query parameter",
)
rootCmd.PersistentFlags().Uint64VarP(
&cli.Offset,
"offset",
"o",
0,
"Offset query parameter",
)
rootCmd.PersistentFlags().StringVarP(
&cli.Name,
"name",
"n",
"",
"Name query parameter",
)
rootCmd.PersistentFlags().StringVarP(
&cli.Identity,
"identity",
"I",
"",
"User identity query parameter",
)
rootCmd.PersistentFlags().StringVarP(
&cli.Metadata,
"metadata",
"m",
"",
"Metadata query parameter",
)
rootCmd.PersistentFlags().StringVarP(
&cli.Status,
"status",
"S",
"",
"User status query parameter",
)
rootCmd.PersistentFlags().StringVarP(
&cli.State,
"state",
"z",
"",
"Bootstrap state query parameter",
)
rootCmd.PersistentFlags().StringVarP(
&cli.Topic,
"topic",
"T",
"",
"Subscription topic query parameter",
)
rootCmd.PersistentFlags().StringVarP(
&cli.Contact,
"contact",
"C",
"",
"Subscription contact query parameter",
)
return rootCmd
}
-359
View File
@@ -1,359 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"encoding/json"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/absmach/magistrala/things"
"github.com/spf13/cobra"
)
var cmdThings = []cobra.Command{
{
Use: "create <JSON_thing> <domain_id> <user_auth_token>",
Short: "Create thing",
Long: "Creates new thing with provided name and metadata\n" +
"Usage:\n" +
"\tmagistrala-cli things create '{\"name\":\"new thing\", \"metadata\":{\"key\": \"value\"}}' $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
var thing mgxsdk.Thing
if err := json.Unmarshal([]byte(args[0]), &thing); err != nil {
logErrorCmd(*cmd, err)
return
}
thing.Status = things.EnabledStatus.String()
thing, err := sdk.CreateThing(thing, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, thing)
},
},
{
Use: "get [all | <thing_id>] <domain_id> <user_auth_token>",
Short: "Get things",
Long: "Get all things or get thing by id. Things can be filtered by name or metadata\n" +
"Usage:\n" +
"\tmagistrala-cli things get all $DOMAINID $USERTOKEN - lists all things\n" +
"\tmagistrala-cli things get all $DOMAINID $USERTOKEN --offset=10 --limit=10 - lists all things with offset and limit\n" +
"\tmagistrala-cli things get <thing_id> $DOMAINID $USERTOKEN - shows thing with provided <thing_id>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
metadata, err := convertMetadata(Metadata)
if err != nil {
logErrorCmd(*cmd, err)
return
}
pageMetadata := mgxsdk.PageMetadata{
Name: Name,
Offset: Offset,
Limit: Limit,
Metadata: metadata,
}
if args[0] == all {
l, err := sdk.Things(pageMetadata, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
t, err := sdk.Thing(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, t)
},
},
{
Use: "delete <thing_id> <domain_id> <user_auth_token>",
Short: "Delete thing",
Long: "Delete thing by id\n" +
"Usage:\n" +
"\tmagistrala-cli things delete <thing_id> $DOMAINID $USERTOKEN - delete thing with <thing_id>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.DeleteThing(args[0], args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "update [<thing_id> <JSON_string> | tags <thing_id> <tags> | secret <thing_id> <secret> ] <domain_id> <user_auth_token>",
Short: "Update thing",
Long: "Updates thing with provided id, name and metadata, or updates thing tags, secret\n" +
"Usage:\n" +
"\tmagistrala-cli things update <thing_id> '{\"name\":\"new name\", \"metadata\":{\"key\": \"value\"}}' $DOMAINID $USERTOKEN\n" +
"\tmagistrala-cli things update tags <thing_id> '{\"tag1\":\"value1\", \"tag2\":\"value2\"}' $DOMAINID $USERTOKEN\n" +
"\tmagistrala-cli things update secret <thing_id> <newsecret> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 5 && len(args) != 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
var thing mgxsdk.Thing
if args[0] == "tags" {
if err := json.Unmarshal([]byte(args[2]), &thing.Tags); err != nil {
logErrorCmd(*cmd, err)
return
}
thing.ID = args[1]
thing, err := sdk.UpdateThingTags(thing, args[3], args[4])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, thing)
return
}
if args[0] == "secret" {
thing, err := sdk.UpdateThingSecret(args[1], args[2], args[3], args[4])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, thing)
return
}
if err := json.Unmarshal([]byte(args[1]), &thing); err != nil {
logErrorCmd(*cmd, err)
return
}
thing.ID = args[0]
thing, err := sdk.UpdateThing(thing, args[2], args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, thing)
},
},
{
Use: "enable <thing_id> <domain_id> <user_auth_token>",
Short: "Change thing status to enabled",
Long: "Change thing status to enabled\n" +
"Usage:\n" +
"\tmagistrala-cli things enable <thing_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
thing, err := sdk.EnableThing(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, thing)
},
},
{
Use: "disable <thing_id> <domain_id> <user_auth_token>",
Short: "Change thing status to disabled",
Long: "Change thing status to disabled\n" +
"Usage:\n" +
"\tmagistrala-cli things disable <thing_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
thing, err := sdk.DisableThing(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, thing)
},
},
{
Use: "share <thing_id> <user_id> <relation> <domain_id> <user_auth_token>",
Short: "Share thing with a user",
Long: "Share thing with a user\n" +
"Usage:\n" +
"\tmagistrala-cli things share <thing_id> <user_id> <relation> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 5 {
logUsageCmd(*cmd, cmd.Use)
return
}
req := mgxsdk.UsersRelationRequest{
Relation: args[2],
UserIDs: []string{args[1]},
}
err := sdk.ShareThing(args[0], req, args[3], args[4])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "unshare <thing_id> <user_id> <relation> <domain_id> <user_auth_token>",
Short: "Unshare thing with a user",
Long: "Unshare thing with a user\n" +
"Usage:\n" +
"\tmagistrala-cli things share <thing_id> <user_id> <relation> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 5 {
logUsageCmd(*cmd, cmd.Use)
return
}
req := mgxsdk.UsersRelationRequest{
Relation: args[2],
UserIDs: []string{args[1]},
}
err := sdk.UnshareThing(args[0], req, args[3], args[4])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "connect <thing_id> <channel_id> <domain_id> <user_auth_token>",
Short: "Connect thing",
Long: "Connect thing to the channel\n" +
"Usage:\n" +
"\tmagistrala-cli things connect <thing_id> <channel_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
connIDs := mgxsdk.Connection{
ChannelID: args[1],
ThingID: args[0],
}
if err := sdk.Connect(connIDs, args[2], args[3]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "disconnect <thing_id> <channel_id> <domain_id> <user_auth_token>",
Short: "Disconnect thing",
Long: "Disconnect thing to the channel\n" +
"Usage:\n" +
"\tmagistrala-cli things disconnect <thing_id> <channel_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 {
logUsageCmd(*cmd, cmd.Use)
return
}
connIDs := mgxsdk.Connection{
ThingID: args[0],
ChannelID: args[1],
}
if err := sdk.Disconnect(connIDs, args[2], args[3]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "connections <thing_id> <domain_id> <user_auth_token>",
Short: "Connected list",
Long: "List of Channels connected to Thing\n" +
"Usage:\n" +
"\tmagistrala-cli connections <thing_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
cl, err := sdk.ChannelsByThing(args[0], pm, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, cl)
},
},
{
Use: "users <thing_id> <domain_id> <user_auth_token>",
Short: "List users",
Long: "List users of a thing\n" +
"Usage:\n" +
"\tmagistrala-cli things users <thing_id> $DOMAINID $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
ul, err := sdk.ListThingUsers(args[0], pm, args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, ul)
},
},
}
// NewThingsCmd returns things command.
func NewThingsCmd() *cobra.Command {
cmd := cobra.Command{
Use: "things [create | get | update | delete | share | connect | disconnect | connections | not-connected | users ]",
Short: "Things management",
Long: `Things management: create, get, update, delete or share Thing, connect or disconnect Thing from Channel and get the list of Channels connected or disconnected from a Thing`,
}
for i := range cmdThings {
cmd.AddCommand(&cmdThings[i])
}
return &cmd
}
-1243
View File
File diff suppressed because it is too large Load Diff
-537
View File
@@ -1,537 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
mgxsdk "github.com/absmach/magistrala/pkg/sdk/go"
"github.com/absmach/magistrala/users"
"github.com/spf13/cobra"
)
var cmdUsers = []cobra.Command{
{
Use: "create <first_name> <last_name> <email> <username> <password> <user_auth_token>",
Short: "Create user",
Long: "Create user with provided firstname, lastname, email, username and password. Token is optional\n" +
"For example:\n" +
"\tmagistrala-cli users create jane doe janedoe@example.com jane_doe 12345678 $USER_AUTH_TOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 5 || len(args) > 6 {
logUsageCmd(*cmd, cmd.Use)
return
}
if len(args) == 5 {
args = append(args, "")
}
user := mgxsdk.User{
FirstName: args[0],
LastName: args[1],
Email: args[2],
Credentials: mgxsdk.Credentials{
Username: args[3],
Secret: args[4],
},
Status: users.EnabledStatus.String(),
}
user, err := sdk.CreateUser(user, args[5])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
},
},
{
Use: "get [all | <user_id> ] <user_auth_token>",
Short: "Get users",
Long: "Get all users or get user by id. Users can be filtered by name or metadata or status\n" +
"Usage:\n" +
"\tmagistrala-cli users get all <user_auth_token> - lists all users\n" +
"\tmagistrala-cli users get all <user_auth_token> --offset <offset> --limit <limit> - lists all users with provided offset and limit\n" +
"\tmagistrala-cli users get <user_id> <user_auth_token> - shows user with provided <user_id>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
metadata, err := convertMetadata(Metadata)
if err != nil {
logErrorCmd(*cmd, err)
return
}
pageMetadata := mgxsdk.PageMetadata{
Username: Username,
Identity: Identity,
Offset: Offset,
Limit: Limit,
Metadata: metadata,
Status: Status,
}
if args[0] == all {
l, err := sdk.Users(pageMetadata, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, l)
return
}
u, err := sdk.User(args[0], args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, u)
},
},
{
Use: "token <username> <password>",
Short: "Get token",
Long: "Generate a new token with username and password\n" +
"For example:\n" +
"\tmagistrala-cli users token jane.doe 12345678\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
loginReq := mgxsdk.Login{
Identity: args[0],
Secret: args[1],
}
token, err := sdk.CreateToken(loginReq)
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, token)
},
},
{
Use: "refreshtoken <token>",
Short: "Get token",
Long: "Generate new token from refresh token\n" +
"For example:\n" +
"\tmagistrala-cli users refreshtoken <refresh_token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logUsageCmd(*cmd, cmd.Use)
return
}
token, err := sdk.RefreshToken(args[0])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, token)
},
},
{
Use: "update [<user_id> <JSON_string> | tags <user_id> <tags> | username <user_id> <username> | email <user_id> <email>] <user_auth_token>",
Short: "Update user",
Long: "Updates either user name and metadata or user tags or user email\n" +
"Usage:\n" +
"\tmagistrala-cli users update <user_id> '{\"first_name\":\"new first_name\", \"metadata\":{\"key\": \"value\"}}' $USERTOKEN - updates user first and lastname and metadata\n" +
"\tmagistrala-cli users update tags <user_id> '[\"tag1\", \"tag2\"]' $USERTOKEN - updates user tags\n" +
"\tmagistrala-cli users update username <user_id> newusername $USERTOKEN - updates user name\n" +
"\tmagistrala-cli users update email <user_id> newemail@example.com $USERTOKEN - updates user email\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 4 && len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
var user mgxsdk.User
if args[0] == "tags" {
if err := json.Unmarshal([]byte(args[2]), &user.Tags); err != nil {
logErrorCmd(*cmd, err)
return
}
user.ID = args[1]
user, err := sdk.UpdateUserTags(user, args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
return
}
if args[0] == "email" {
user.ID = args[1]
user.Email = args[2]
user, err := sdk.UpdateUserEmail(user, args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
return
}
if args[0] == "username" {
user.ID = args[1]
user.Credentials.Username = args[2]
user, err := sdk.UpdateUsername(user, args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
return
}
if args[0] == "role" {
user.ID = args[1]
user.Role = args[2]
user, err := sdk.UpdateUserRole(user, args[3])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
return
}
if err := json.Unmarshal([]byte(args[1]), &user); err != nil {
logErrorCmd(*cmd, err)
return
}
user.ID = args[0]
user, err := sdk.UpdateUser(user, args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
},
},
{
Use: "profile <user_auth_token>",
Short: "Get user profile",
Long: "Get user profile\n" +
"Usage:\n" +
"\tmagistrala-cli users profile $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logUsageCmd(*cmd, cmd.Use)
return
}
user, err := sdk.UserProfile(args[0])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
},
},
{
Use: "resetpasswordrequest <email>",
Short: "Send reset password request",
Long: "Send reset password request\n" +
"Usage:\n" +
"\tmagistrala-cli users resetpasswordrequest example@mail.com\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.ResetPasswordRequest(args[0]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "resetpassword <password> <confpass> <password_request_token>",
Short: "Reset password",
Long: "Reset password\n" +
"Usage:\n" +
"\tmagistrala-cli users resetpassword 12345678 12345678 $REQUESTTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.ResetPassword(args[0], args[1], args[2]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "password <old_password> <password> <user_auth_token>",
Short: "Update password",
Long: "Update password\n" +
"Usage:\n" +
"\tmagistrala-cli users password old_password new_password $USERTOKEN\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
logUsageCmd(*cmd, cmd.Use)
return
}
user, err := sdk.UpdatePassword(args[0], args[1], args[2])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
},
},
{
Use: "enable <user_id> <user_auth_token>",
Short: "Change user status to enabled",
Long: "Change user status to enabled\n" +
"Usage:\n" +
"\tmagistrala-cli users enable <user_id> <user_auth_token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
user, err := sdk.EnableUser(args[0], args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
},
},
{
Use: "disable <user_id> <user_auth_token>",
Short: "Change user status to disabled",
Long: "Change user status to disabled\n" +
"Usage:\n" +
"\tmagistrala-cli users disable <user_id> <user_auth_token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
user, err := sdk.DisableUser(args[0], args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, user)
},
},
{
Use: "delete <user_id> <user_auth_token>",
Short: "Delete user",
Long: "Delete user by id\n" +
"Usage:\n" +
"\tmagistrala-cli users delete <user_id> $USERTOKEN - delete user with <user_id>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
if err := sdk.DeleteUser(args[0], args[1]); err != nil {
logErrorCmd(*cmd, err)
return
}
logOKCmd(*cmd)
},
},
{
Use: "channels <user_id> <user_auth_token>",
Short: "List channels",
Long: "List channels of user\n" +
"Usage:\n" +
"\tmagistrala-cli users channels <user_id> <user_auth_token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
cp, err := sdk.ListUserChannels(args[0], pm, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, cp)
},
},
{
Use: "things <user_id> <user_auth_token>",
Short: "List things",
Long: "List things of user\n" +
"Usage:\n" +
"\tmagistrala-cli users things <user_id> <user_auth_token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
tp, err := sdk.ListUserThings(args[0], pm, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, tp)
},
},
{
Use: "domains <user_id> <user_auth_token>",
Short: "List domains",
Long: "List user's domains\n" +
"Usage:\n" +
"\tmagistrala-cli users domains <user_id> <user_auth_token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
dp, err := sdk.ListUserDomains(args[0], pm, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, dp)
},
},
{
Use: "groups <user_id> <user_auth_token>",
Short: "List groups",
Long: "List groups of user\n" +
"Usage:\n" +
"\tmagistrala-cli users groups <user_id> <user_auth_token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
}
users, err := sdk.ListUserGroups(args[0], pm, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, users)
},
},
{
Use: "search <query> <user_auth_token>",
Short: "Search users",
Long: "Search users by query\n" +
"Usage:\n" +
"\tmagistrala-cli users search <query> <user_auth_token>\n",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
logUsageCmd(*cmd, cmd.Use)
return
}
values, err := url.ParseQuery(args[0])
if err != nil {
logErrorCmd(*cmd, fmt.Errorf("failed to parse query: %s", err))
}
pm := mgxsdk.PageMetadata{
Offset: Offset,
Limit: Limit,
Name: values.Get("name"),
ID: values.Get("id"),
}
if off, err := strconv.Atoi(values.Get("offset")); err == nil {
pm.Offset = uint64(off)
}
if lim, err := strconv.Atoi(values.Get("limit")); err == nil {
pm.Limit = uint64(lim)
}
users, err := sdk.SearchUsers(pm, args[1])
if err != nil {
logErrorCmd(*cmd, err)
return
}
logJSONCmd(*cmd, users)
},
},
}
// NewUsersCmd returns users command.
func NewUsersCmd() *cobra.Command {
cmd := cobra.Command{
Use: "users [create | get | update | token | password | enable | disable | delete | channels | things | groups | search]",
Short: "Users management",
Long: `Users management: create accounts and tokens"`,
}
for i := range cmdUsers {
cmd.AddCommand(&cmdUsers[i])
}
return &cmd
}
-1446
View File
File diff suppressed because it is too large Load Diff
-105
View File
@@ -1,105 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"encoding/json"
"fmt"
"time"
"github.com/fatih/color"
"github.com/hokaccha/go-prettyjson"
"github.com/spf13/cobra"
)
var (
// Limit query parameter.
Limit uint64 = 10
// Offset query parameter.
Offset uint64 = 0
// Name query parameter.
Name string = ""
// Identity query parameter.
Identity string = ""
// Metadata query parameter.
Metadata string = ""
// Status query parameter.
Status string = ""
// ConfigPath config path parameter.
ConfigPath string = ""
// State query parameter.
State string = ""
// Topic query parameter.
Topic string = ""
// Contact query parameter.
Contact string = ""
// RawOutput raw output mode.
RawOutput bool = false
// Username query parameter.
Username string = ""
// FirstName query parameter.
FirstName string = ""
// LastName query parameter.
LastName string = ""
)
func logJSONCmd(cmd cobra.Command, iList ...interface{}) {
for _, i := range iList {
m, err := json.Marshal(i)
if err != nil {
logErrorCmd(cmd, err)
return
}
pj, err := prettyjson.Format(m)
if err != nil {
logErrorCmd(cmd, err)
return
}
fmt.Fprintf(cmd.OutOrStdout(), "\n%s\n\n", string(pj))
}
}
func logUsageCmd(cmd cobra.Command, u string) {
fmt.Fprintf(cmd.OutOrStdout(), color.YellowString("\nusage: %s\n\n"), u)
}
func logErrorCmd(cmd cobra.Command, err error) {
boldRed := color.New(color.FgRed, color.Bold)
boldRed.Fprintf(cmd.ErrOrStderr(), "\nerror: ")
fmt.Fprintf(cmd.ErrOrStderr(), "%s\n\n", color.RedString(err.Error()))
}
func logOKCmd(cmd cobra.Command) {
fmt.Fprintf(cmd.OutOrStdout(), "\n%s\n\n", color.BlueString("ok"))
}
func logCreatedCmd(cmd cobra.Command, e string) {
if RawOutput {
fmt.Fprintln(cmd.OutOrStdout(), e)
} else {
fmt.Fprintf(cmd.OutOrStdout(), color.BlueString("\ncreated: %s\n\n"), e)
}
}
func logRevokedTimeCmd(cmd cobra.Command, t time.Time) {
if RawOutput {
fmt.Fprintln(cmd.OutOrStdout(), t)
} else {
fmt.Fprintf(cmd.OutOrStdout(), color.BlueString("\nrevoked: %v\n\n"), t)
}
}
func convertMetadata(m string) (map[string]interface{}, error) {
var metadata map[string]interface{}
if m == "" {
return nil, nil
}
if err := json.Unmarshal([]byte(Metadata), &metadata); err != nil {
return nil, err
}
return nil, nil
}