Files
supermq/cli/bootstrap_test.go
Dusan Borovcanin c35bc42210 NOISSUE - Fix typos
Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>
2025-06-06 14:05:18 +02:00

634 lines
18 KiB
Go

// 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"
mgsdk "github.com/absmach/magistrala/pkg/sdk"
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
"github.com/absmach/supermq/pkg/errors"
svcerr "github.com/absmach/supermq/pkg/errors/service"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var (
clientID = testsutil.GenerateUUID(&testing.T{})
channelID = testsutil.GenerateUUID(&testing.T{})
domainID = testsutil.GenerateUUID(&testing.T{})
bootConfig = mgsdk.BootstrapConfig{
ClientID: clientID,
Channels: []string{channelID},
Name: "Test Bootstrap",
ExternalID: "09:6:0:sb:sa",
ExternalKey: "key",
}
validToken = "validToken"
invalidToken = "invalidToken"
extraArg = "extra-arg"
invalidID = "invalidID"
all = "all"
)
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\", \"client_id\": \"%s\", \"external_key\":\"key\", \"name\": \"%s\", \"channels\":[\"%s\"]}", clientID, "Test Bootstrap", channelID)
invalidJson := fmt.Sprintf("{\"external_id\":\"09:6:0:sb:sa\", \"client_id\": \"%s\", \"external_key\":\"key\", \"name\": \"%s\", \"channels\":[\"%s\"]", clientID, "Test Bootstrap", channelID)
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: clientID,
response: fmt.Sprintf("\ncreated: %s\n\n", clientID),
},
{
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, 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,
validToken,
},
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{
channelID,
domainID,
validToken,
},
logType: entityLog,
boot: bootConfig,
},
{
desc: "get bootstrap config with invalid args",
args: []string{
all,
domainID,
validToken,
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,
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("ViewBootstrap", mock.Anything, tc.args[0], tc.args[1], tc.args[2]).Return(tc.boot, tc.sdkErr)
sdkCall1 := sdkMock.On("Bootstraps", mock.Anything, 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{
clientID,
domainID,
validToken,
},
logType: okLog,
},
{
desc: "remove bootstrap config with invalid args",
args: []string{
clientID,
domainID,
validToken,
extraArg,
},
logType: usageLog,
},
{
desc: "remove bootstrap config with invalid client id",
args: []string{
invalidID,
domainID,
validToken,
},
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{
clientID,
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", mock.Anything, 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\"]", channelID)
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,
validToken,
},
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,
clientID,
chanIDsJson,
domainID,
validToken,
},
logType: okLog,
},
{
desc: "update bootstrap connections with invalid json",
args: []string{
connection,
clientID,
fmt.Sprintf("[\"%s\"", clientID),
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: "update bootstrap connections with invalid token",
args: []string{
connection,
clientID,
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",
clientID,
"client cert",
"client key",
"ca",
domainID,
validToken,
},
boot: bootConfig,
logType: entityLog,
},
{
desc: "update bootstrap certs with invalid token",
args: []string{
"certs",
clientID,
"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,
validToken,
},
logType: usageLog,
},
{
desc: "update bootstrap config with invalid json",
args: []string{
config,
"{\"name\" : \"New Bootstrap\"",
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: "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, mock.Anything).Return(tc.sdkErr)
sdkCall1 := sdkMock.On("UpdateBootstrapConnection", mock.Anything, 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, 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("{\"client_id\": \"%s\", \"state\":%d}", clientID, 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("{\"client_id\": \"%s\", \"state\":%d", clientID, 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, 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
cryptoKey := "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,
cryptoKey,
},
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{
cryptoKey,
},
logType: usageLog,
},
{
desc: "bootstrap secure config with invalid key",
args: []string{
"secure",
bootConfig.ExternalID,
invalidKey,
cryptoKey,
},
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, mock.Anything).Return(tc.boot, tc.sdkErr)
sdkCall1 := sdkMock.On("Bootstrap", mock.Anything, 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()
})
}
}