mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
@@ -1,379 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
channelsOps "github.com/absmach/magistrala/channels/operations"
|
||||
clientsOps "github.com/absmach/magistrala/clients/operations"
|
||||
groupsOps "github.com/absmach/magistrala/groups/operations"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestScopeAuthorized(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
scope *auth.Scope
|
||||
entityType auth.EntityType
|
||||
domainID string
|
||||
operation string
|
||||
entityID string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
desc: "Authorized with matching entity type, domain, operation and entity ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "entity1",
|
||||
},
|
||||
entityType: auth.GroupsType,
|
||||
domainID: "domain1",
|
||||
operation: "view",
|
||||
entityID: "entity1",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "Authorized with wildcard entity ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "*",
|
||||
},
|
||||
entityType: auth.GroupsType,
|
||||
domainID: "domain1",
|
||||
operation: "view",
|
||||
entityID: "any-entity",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "Authorized without domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.ClientsType,
|
||||
DomainID: "",
|
||||
Operation: "view",
|
||||
EntityID: "client1",
|
||||
},
|
||||
entityType: auth.ClientsType,
|
||||
domainID: "domain1",
|
||||
operation: "view",
|
||||
entityID: "client1",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "Not authorized with different entity type",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "entity1",
|
||||
},
|
||||
entityType: auth.ChannelsType,
|
||||
domainID: "domain1",
|
||||
operation: "view",
|
||||
entityID: "entity1",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "Not authorized with different domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "entity1",
|
||||
},
|
||||
entityType: auth.GroupsType,
|
||||
domainID: "domain2",
|
||||
operation: "view",
|
||||
entityID: "entity1",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "Not authorized with different operation",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "entity1",
|
||||
},
|
||||
entityType: auth.GroupsType,
|
||||
domainID: "domain1",
|
||||
operation: "delete",
|
||||
entityID: "entity1",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "Not authorized with different entity ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "entity1",
|
||||
},
|
||||
entityType: auth.GroupsType,
|
||||
domainID: "domain1",
|
||||
operation: "view",
|
||||
entityID: "entity2",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "Not authorized with nil scope",
|
||||
scope: nil,
|
||||
entityType: auth.GroupsType,
|
||||
domainID: "domain1",
|
||||
operation: "view",
|
||||
entityID: "entity1",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
result := tc.scope.Authorized(tc.entityType, tc.domainID, tc.operation, tc.entityID)
|
||||
assert.Equal(t, tc.expected, result, "Authorized() = %v, expected %v", result, tc.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScopeValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
scope *auth.Scope
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "Valid scope for groups with domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "entity1",
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Valid scope for channels with domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.ChannelsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "channel1",
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Valid scope for clients with domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.ClientsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "update",
|
||||
EntityID: "client1",
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Valid scope for messages with domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.MessagesType,
|
||||
DomainID: "domain1",
|
||||
Operation: "message_publish",
|
||||
EntityID: "message1",
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Valid scope for dashboard with domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.DashboardType,
|
||||
DomainID: "domain1",
|
||||
Operation: "dashboard_share",
|
||||
EntityID: "dashboard1",
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Valid scope with wildcard entity ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: "view",
|
||||
EntityID: "*",
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "Invalid nil scope",
|
||||
scope: nil,
|
||||
err: assert.AnError, // Will be checked with Contains
|
||||
},
|
||||
{
|
||||
desc: "Invalid scope without entity ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "domain1",
|
||||
Operation: groupsOps.OperationDetails()[groupsOps.OpViewGroup].Name,
|
||||
EntityID: "",
|
||||
},
|
||||
err: apiutil.ErrMissingEntityID,
|
||||
},
|
||||
{
|
||||
desc: "Invalid scope for groups without domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.GroupsType,
|
||||
DomainID: "",
|
||||
Operation: groupsOps.OperationDetails()[groupsOps.OpViewGroup].Name,
|
||||
EntityID: "entity1",
|
||||
},
|
||||
err: apiutil.ErrMissingDomainID,
|
||||
},
|
||||
{
|
||||
desc: "Invalid scope for channels without domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.ChannelsType,
|
||||
DomainID: "",
|
||||
Operation: channelsOps.OperationDetails()[channelsOps.OpViewChannel].Name,
|
||||
EntityID: "channel1",
|
||||
},
|
||||
err: apiutil.ErrMissingDomainID,
|
||||
},
|
||||
{
|
||||
desc: "Invalid scope for clients without domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.ClientsType,
|
||||
DomainID: "",
|
||||
Operation: clientsOps.OperationDetails()[clientsOps.OpViewClient].Name,
|
||||
EntityID: "client1",
|
||||
},
|
||||
err: apiutil.ErrMissingDomainID,
|
||||
},
|
||||
{
|
||||
desc: "Invalid scope for dashboard without domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.DashboardType,
|
||||
DomainID: "",
|
||||
Operation: auth.OpShare,
|
||||
EntityID: "dashboard1",
|
||||
},
|
||||
err: apiutil.ErrMissingDomainID,
|
||||
},
|
||||
{
|
||||
desc: "Invalid scope for messages without domain ID",
|
||||
scope: &auth.Scope{
|
||||
EntityType: auth.MessagesType,
|
||||
DomainID: "",
|
||||
Operation: auth.OpPublish,
|
||||
EntityID: "message1",
|
||||
},
|
||||
err: apiutil.ErrMissingDomainID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
err := tc.scope.Validate()
|
||||
if tc.err != nil {
|
||||
assert.Error(t, err, "Validate() should return error")
|
||||
if tc.err != assert.AnError {
|
||||
assert.Equal(t, tc.err, err, "Validate() error = %v, expected %v", err, tc.err)
|
||||
}
|
||||
} else {
|
||||
assert.NoError(t, err, "Validate() should not return error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPATValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
pat *auth.PAT
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
desc: "Valid PAT",
|
||||
pat: &auth.PAT{
|
||||
ID: "pat-id",
|
||||
User: "user-id",
|
||||
Name: "test-pat",
|
||||
Description: "test description",
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
desc: "Invalid nil PAT",
|
||||
pat: nil,
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
desc: "Invalid PAT without name",
|
||||
pat: &auth.PAT{
|
||||
ID: "pat-id",
|
||||
User: "user-id",
|
||||
Name: "",
|
||||
Description: "test description",
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
desc: "Invalid PAT without user",
|
||||
pat: &auth.PAT{
|
||||
ID: "pat-id",
|
||||
User: "",
|
||||
Name: "test-pat",
|
||||
Description: "test description",
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
err := tc.pat.Validate()
|
||||
if tc.err {
|
||||
assert.Error(t, err, "Validate() should return error")
|
||||
} else {
|
||||
assert.NoError(t, err, "Validate() should not return error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPATMarshalUnmarshalBinary(t *testing.T) {
|
||||
pat := auth.PAT{
|
||||
ID: "pat-id",
|
||||
User: "user-id",
|
||||
Name: "test-pat",
|
||||
Description: "test description",
|
||||
Secret: "secret",
|
||||
IssuedAt: time.Now().UTC().Round(time.Second),
|
||||
ExpiresAt: time.Now().UTC().Add(24 * time.Hour).Round(time.Second),
|
||||
Status: auth.ActiveStatus,
|
||||
}
|
||||
|
||||
// Marshal
|
||||
data, err := pat.MarshalBinary()
|
||||
assert.NoError(t, err, "MarshalBinary() should not return error")
|
||||
assert.NotNil(t, data, "MarshalBinary() should return data")
|
||||
|
||||
// Unmarshal
|
||||
var newPAT auth.PAT
|
||||
err = newPAT.UnmarshalBinary(data)
|
||||
assert.NoError(t, err, "UnmarshalBinary() should not return error")
|
||||
|
||||
assert.Equal(t, pat.ID, newPAT.ID, "ID mismatch")
|
||||
assert.Equal(t, pat.User, newPAT.User, "User mismatch")
|
||||
assert.Equal(t, pat.Name, newPAT.Name, "Name mismatch")
|
||||
assert.Equal(t, pat.Description, newPAT.Description, "Description mismatch")
|
||||
assert.Equal(t, pat.Secret, newPAT.Secret, "Secret mismatch")
|
||||
assert.Equal(t, pat.Status, newPAT.Status, "Status mismatch")
|
||||
}
|
||||
@@ -1,875 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// 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"
|
||||
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
|
||||
"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{})
|
||||
profileID = testsutil.GenerateUUID(&testing.T{})
|
||||
bootConfig = mgsdk.BootstrapConfig{
|
||||
ID: clientID,
|
||||
Name: "Test Bootstrap",
|
||||
ExternalID: "09:6:0:sb:sa",
|
||||
ExternalKey: "key",
|
||||
}
|
||||
bootProfile = mgsdk.BootstrapProfile{
|
||||
ID: profileID,
|
||||
Name: "Test Profile",
|
||||
Description: "Test profile",
|
||||
ContentFormat: "go-template",
|
||||
ContentTemplate: "{\"device_id\":\"{{ .Device.ID }}\"}",
|
||||
Version: 1,
|
||||
}
|
||||
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\", \"external_key\":\"key\", \"name\": \"%s\"}", "Test Bootstrap")
|
||||
invalidJson := fmt.Sprintf("{\"external_id\":\"09:6:0:sb:sa\", \"external_key\":\"key\", \"name\": \"%s\"", "Test Bootstrap")
|
||||
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\", \"status\":%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\", \"status\":%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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBootstrapProfilesCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
bootCmd := cli.NewBootstrapCmd()
|
||||
rootCmd := setFlags(bootCmd)
|
||||
|
||||
profilePayload, err := json.Marshal(bootProfile)
|
||||
assert.Nil(t, err)
|
||||
jsonProfile := string(profilePayload)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
profile mgsdk.BootstrapProfile
|
||||
page mgsdk.BootstrapProfilesPage
|
||||
sdkErr errors.SDKError
|
||||
logType outputLog
|
||||
errLogMessage string
|
||||
}{
|
||||
{
|
||||
desc: "create bootstrap profile successfully",
|
||||
args: []string{
|
||||
"create",
|
||||
jsonProfile,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
profile: bootProfile,
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "get all bootstrap profiles successfully",
|
||||
args: []string{
|
||||
"get",
|
||||
all,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
page: mgsdk.BootstrapProfilesPage{
|
||||
PageRes: mgsdk.PageRes{
|
||||
Total: 1,
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
Profiles: []mgsdk.BootstrapProfile{bootProfile},
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "view bootstrap profile successfully",
|
||||
args: []string{
|
||||
"get",
|
||||
profileID,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
profile: bootProfile,
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "update bootstrap profile successfully",
|
||||
args: []string{
|
||||
"update",
|
||||
jsonProfile,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
profile: bootProfile,
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "remove bootstrap profile successfully",
|
||||
args: []string{
|
||||
"remove",
|
||||
profileID,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
var gotProfile mgsdk.BootstrapProfile
|
||||
var gotPage mgsdk.BootstrapProfilesPage
|
||||
|
||||
createCall := sdkMock.On("CreateBootstrapProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.profile, tc.sdkErr)
|
||||
listCall := sdkMock.On("BootstrapProfiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.page, tc.sdkErr)
|
||||
viewCall := sdkMock.On("ViewBootstrapProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.profile, tc.sdkErr)
|
||||
updateCall := sdkMock.On("UpdateBootstrapProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.profile, tc.sdkErr)
|
||||
removeCall := sdkMock.On("RemoveBootstrapProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
|
||||
|
||||
out := executeCommand(t, rootCmd, append([]string{"profiles"}, tc.args...)...)
|
||||
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
if tc.args[0] == "get" && tc.args[1] == all {
|
||||
err := json.Unmarshal([]byte(out), &gotPage)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.page, gotPage, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.page, gotPage))
|
||||
} else {
|
||||
err := json.Unmarshal([]byte(out), &gotProfile)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.profile, gotProfile, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.profile, gotProfile))
|
||||
}
|
||||
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))
|
||||
}
|
||||
|
||||
createCall.Unset()
|
||||
listCall.Unset()
|
||||
viewCall.Unset()
|
||||
updateCall.Unset()
|
||||
removeCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBootstrapEnrollmentsCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
bootCmd := cli.NewBootstrapCmd()
|
||||
rootCmd := setFlags(bootCmd)
|
||||
|
||||
bindings := []mgsdk.BootstrapBindingRequest{
|
||||
{
|
||||
Slot: "mqtt_client",
|
||||
Type: "client",
|
||||
ResourceID: clientID,
|
||||
},
|
||||
}
|
||||
snapshots := []mgsdk.BootstrapBindingSnapshot{
|
||||
{
|
||||
ConfigID: clientID,
|
||||
Slot: "mqtt_client",
|
||||
Type: "client",
|
||||
ResourceID: clientID,
|
||||
},
|
||||
}
|
||||
jsonBindings := fmt.Sprintf("[{\"slot\":\"%s\",\"type\":\"%s\",\"resource_id\":\"%s\"}]", bindings[0].Slot, bindings[0].Type, bindings[0].ResourceID)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
snapshots []mgsdk.BootstrapBindingSnapshot
|
||||
sdkErr errors.SDKError
|
||||
logType outputLog
|
||||
errLogMessage string
|
||||
}{
|
||||
{
|
||||
desc: "assign bootstrap profile successfully",
|
||||
args: []string{
|
||||
"assign-profile",
|
||||
clientID,
|
||||
profileID,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "bind bootstrap resources successfully",
|
||||
args: []string{
|
||||
"bind",
|
||||
clientID,
|
||||
jsonBindings,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "get bootstrap bindings successfully",
|
||||
args: []string{
|
||||
"get-bindings",
|
||||
clientID,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
snapshots: snapshots,
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "refresh bootstrap bindings successfully",
|
||||
args: []string{
|
||||
"refresh-bindings",
|
||||
clientID,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
var gotSnapshots []mgsdk.BootstrapBindingSnapshot
|
||||
|
||||
assignCall := sdkMock.On("AssignBootstrapProfile", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
|
||||
bindCall := sdkMock.On("BindBootstrapResources", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
|
||||
listCall := sdkMock.On("BootstrapBindings", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.snapshots, tc.sdkErr)
|
||||
refreshCall := sdkMock.On("RefreshBootstrapBindings", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
|
||||
|
||||
out := executeCommand(t, rootCmd, append([]string{"enrollments"}, tc.args...)...)
|
||||
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
err := json.Unmarshal([]byte(out), &gotSnapshots)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.snapshots, gotSnapshots, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.snapshots, gotSnapshots))
|
||||
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))
|
||||
}
|
||||
|
||||
assignCall.Unset()
|
||||
bindCall.Unset()
|
||||
listCall.Unset()
|
||||
refreshCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,908 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/magistrala/certs"
|
||||
"github.com/absmach/magistrala/cli"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/sdk"
|
||||
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
const (
|
||||
revokeCmd = "revoke"
|
||||
deleteCmd = "delete"
|
||||
issueCmd = "issue"
|
||||
renewCmd = "renew"
|
||||
certsListCmd = "get"
|
||||
downloadCACmd = "download-ca"
|
||||
CATokenCmd = "certsToken-ca"
|
||||
viewCACmd = "view-ca"
|
||||
filePermission = 0o644
|
||||
)
|
||||
|
||||
var (
|
||||
serialNumber = "39054620502613157373429341617471746606"
|
||||
id = "5b4c9ee3-e719-4a0a-9ee5-354932c5e6a4"
|
||||
commonName = "test-name"
|
||||
certsToken = "certsToken"
|
||||
certsDomainID = "domain-id"
|
||||
)
|
||||
|
||||
func TestIssueCertCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
ipAddrs := "[\"192.168.100.22\"]"
|
||||
|
||||
var cert sdk.Certificate
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
cert sdk.Certificate
|
||||
}{
|
||||
{
|
||||
desc: "issue cert successfully",
|
||||
args: []string{
|
||||
id,
|
||||
commonName,
|
||||
ipAddrs,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
cert: sdk.Certificate{SerialNumber: serialNumber},
|
||||
},
|
||||
{
|
||||
desc: "issue cert with invalid args",
|
||||
args: []string{
|
||||
id,
|
||||
ipAddrs,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "issue cert failed",
|
||||
args: []string{
|
||||
id,
|
||||
commonName,
|
||||
ipAddrs,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrCreateEntity, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrCreateEntity, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "issue cert with 6 args",
|
||||
args: []string{
|
||||
id,
|
||||
commonName,
|
||||
ipAddrs,
|
||||
"{\"organization\":[\"organization_name\"]}",
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
cert: sdk.Certificate{SerialNumber: serialNumber},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
defer func() {
|
||||
cleanupFiles(t, []string{"cert.pem", "key.pem"})
|
||||
}()
|
||||
sdkCall := sdkMock.On("IssueCert", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.cert, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{issueCmd}, tc.args...)...)
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
lines := strings.Split(out, "\n")
|
||||
var jsonLines []string
|
||||
var inJSON bool
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "{") {
|
||||
inJSON = true
|
||||
jsonLines = append(jsonLines, line)
|
||||
} else if inJSON && strings.HasSuffix(line, "}") {
|
||||
jsonLines = append(jsonLines, line)
|
||||
break
|
||||
} else if inJSON {
|
||||
jsonLines = append(jsonLines, line)
|
||||
}
|
||||
}
|
||||
|
||||
if len(jsonLines) == 0 {
|
||||
t.Fatalf("No JSON found in output: %s", out)
|
||||
}
|
||||
|
||||
jsonPart := strings.Join(jsonLines, "")
|
||||
|
||||
err := json.Unmarshal([]byte(jsonPart), &cert)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.cert, cert, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.cert, cert))
|
||||
assert.True(t, strings.Contains(out, "All certificate files have been saved successfully"), fmt.Sprintf("%s should save files", tc.desc))
|
||||
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 TestRevokeCertCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
}{
|
||||
{
|
||||
desc: "revoke cert successfully",
|
||||
args: []string{
|
||||
serialNumber,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "revoke cert with invalid args",
|
||||
args: []string{
|
||||
serialNumber,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "revoke cert failed",
|
||||
args: []string{
|
||||
serialNumber,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrUpdateEntity, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("RevokeCert", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{revokeCmd}, 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 TestDeleteCertCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
}{
|
||||
{
|
||||
desc: "delete certs successfully",
|
||||
args: []string{
|
||||
id,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "delete certs with invalid args",
|
||||
args: []string{
|
||||
id,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "delete certs failed",
|
||||
args: []string{
|
||||
id,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrUpdateEntity, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("DeleteCert", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{deleteCmd}, 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 TestRenewCertCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
}{
|
||||
{
|
||||
desc: "renew cert successfully",
|
||||
args: []string{
|
||||
serialNumber,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "renew cert with invalid args",
|
||||
args: []string{
|
||||
serialNumber,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "renew cert failed",
|
||||
args: []string{
|
||||
serialNumber,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrUpdateEntity, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("RenewCert", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Certificate{}, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{renewCmd}, 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 TestListCertsCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
var page sdk.CertificatePage
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
page sdk.CertificatePage
|
||||
}{
|
||||
{
|
||||
desc: "list certs successfully",
|
||||
args: []string{
|
||||
all,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
page: sdk.CertificatePage{
|
||||
Total: 1,
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Certificates: []sdk.Certificate{
|
||||
{SerialNumber: serialNumber},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "list certs successfully with entity ID",
|
||||
args: []string{
|
||||
id,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
page: sdk.CertificatePage{
|
||||
Total: 1,
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Certificates: []sdk.Certificate{
|
||||
{SerialNumber: serialNumber},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "list certs with invalid args",
|
||||
args: []string{
|
||||
all,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "failed list certs with all",
|
||||
args: []string{
|
||||
all,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrViewEntity, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrViewEntity, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "failed list certs with entity ID",
|
||||
args: []string{
|
||||
id,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrViewEntity, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrViewEntity, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("ListCerts", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.page, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{certsListCmd}, 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), &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))
|
||||
}
|
||||
|
||||
sdkCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadCACmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logMessage string
|
||||
logType outputLog
|
||||
certBundle sdk.CertificateBundle
|
||||
}{
|
||||
{
|
||||
desc: "download CA successfully",
|
||||
args: []string{},
|
||||
logType: entityLog,
|
||||
certBundle: sdk.CertificateBundle{
|
||||
Certificate: []byte("certificate"),
|
||||
},
|
||||
logMessage: "Saved ca.crt\n\nAll certificate files have been saved successfully.\n",
|
||||
},
|
||||
{
|
||||
desc: "download CA with invalid args",
|
||||
args: []string{
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
defer func() {
|
||||
cleanupFiles(t, []string{"ca.crt"})
|
||||
}()
|
||||
sdkCall := sdkMock.On("DownloadCA", mock.Anything).Return(tc.certBundle, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{downloadCACmd}, tc.args...)...)
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
assert.True(t, strings.Contains(out, "Saved ca.crt"), fmt.Sprintf("%s invalid output: %s", 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 TestViewCACmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
var cert sdk.Certificate
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
cert sdk.Certificate
|
||||
}{
|
||||
{
|
||||
desc: "view cert successfully",
|
||||
args: []string{},
|
||||
logType: entityLog,
|
||||
cert: sdk.Certificate{
|
||||
Certificate: "certificate",
|
||||
Key: "privatekey",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "view cert failed",
|
||||
args: []string{},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrUpdateEntity, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
cert: sdk.Certificate{},
|
||||
},
|
||||
{
|
||||
desc: "view cert with invalid args",
|
||||
args: []string{extraArg},
|
||||
logType: usageLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("ViewCA", mock.Anything).Return(tc.cert, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{viewCACmd}, tc.args...)...)
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
err := json.Unmarshal([]byte(out), &cert)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.cert, cert, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.cert, cert))
|
||||
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 TestGenerateCRLCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
crlBytes []byte
|
||||
}{
|
||||
{
|
||||
desc: "generate CRL successfully",
|
||||
args: []string{},
|
||||
logType: entityLog,
|
||||
crlBytes: []byte("crl-data"),
|
||||
},
|
||||
{
|
||||
desc: "generate CRL failed",
|
||||
args: []string{},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrFailedCertCreation, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrFailedCertCreation, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "generate CRL with invalid args",
|
||||
args: []string{"invalid"},
|
||||
logType: usageLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
defer func() {
|
||||
cleanupFiles(t, []string{"ca.crl"})
|
||||
}()
|
||||
|
||||
sdkCall := sdkMock.On("GenerateCRL", mock.Anything).Return(tc.crlBytes, tc.sdkErr)
|
||||
defer sdkCall.Unset()
|
||||
|
||||
out := executeCommand(t, rootCmd, append([]string{"crl"}, tc.args...)...)
|
||||
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
assert.True(t, strings.Contains(out, "CRL file has been saved successfully"), fmt.Sprintf("%s invalid output: %s", 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))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEntityIDCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
entityID := "test-entity-id"
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
entityID string
|
||||
}{
|
||||
{
|
||||
desc: "get entity ID successfully",
|
||||
args: []string{serialNumber, certsDomainID, certsToken},
|
||||
logType: entityLog,
|
||||
entityID: entityID,
|
||||
},
|
||||
{
|
||||
desc: "get entity ID with invalid args",
|
||||
args: []string{serialNumber, extraArg},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "get entity ID failed",
|
||||
args: []string{serialNumber, certsDomainID, certsToken},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrViewEntity, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrViewEntity, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("EntityID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.entityID, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{"entity-id"}, tc.args...)...)
|
||||
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
assert.True(t, strings.Contains(out, tc.entityID), fmt.Sprintf("%s invalid output: %s", 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 cleanupFiles(t *testing.T, filenames []string) {
|
||||
for _, filename := range filenames {
|
||||
err := os.Remove(filename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
t.Logf("Failed to remove file %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssueFromCSRInternalCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
agentToken := "agent-certsToken-123"
|
||||
csrPath := "test.csr"
|
||||
bytes := []byte("-----BEGIN CERTIFICATE REQUEST-----\n-csr-content\n-----END CERTIFICATE REQUEST-----")
|
||||
|
||||
err := os.WriteFile(csrPath, bytes, filePermission)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test CSR file: %v", err)
|
||||
}
|
||||
defer os.Remove(csrPath)
|
||||
|
||||
var cert sdk.Certificate
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
cert sdk.Certificate
|
||||
}{
|
||||
{
|
||||
desc: "issue cert from CSR internal successfully",
|
||||
args: []string{
|
||||
id,
|
||||
"10h",
|
||||
csrPath,
|
||||
agentToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
cert: sdk.Certificate{SerialNumber: serialNumber},
|
||||
},
|
||||
{
|
||||
desc: "issue cert from CSR internal with invalid args",
|
||||
args: []string{
|
||||
id,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "issue cert from CSR internal failed",
|
||||
args: []string{
|
||||
id,
|
||||
"10h",
|
||||
csrPath,
|
||||
agentToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrFailedCertCreation, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrFailedCertCreation, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "issue cert from CSR internal with non-existent file",
|
||||
args: []string{
|
||||
id,
|
||||
"10h",
|
||||
"non-existent.csr",
|
||||
agentToken,
|
||||
},
|
||||
logType: errLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
defer func() {
|
||||
cleanupFiles(t, []string{"cert.pem", "key.pem"})
|
||||
}()
|
||||
sdkCall := sdkMock.On("IssueFromCSRInternal", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.cert, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{"issue-csr-internal"}, tc.args...)...)
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
lines := strings.Split(out, "\n")
|
||||
var jsonLines []string
|
||||
var inJSON bool
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "{") {
|
||||
inJSON = true
|
||||
jsonLines = append(jsonLines, line)
|
||||
} else if inJSON && strings.HasSuffix(line, "}") {
|
||||
jsonLines = append(jsonLines, line)
|
||||
break
|
||||
} else if inJSON {
|
||||
jsonLines = append(jsonLines, line)
|
||||
}
|
||||
}
|
||||
|
||||
if len(jsonLines) == 0 {
|
||||
t.Fatalf("No JSON found in output: %s", out)
|
||||
}
|
||||
|
||||
jsonPart := strings.Join(jsonLines, "")
|
||||
|
||||
err := json.Unmarshal([]byte(jsonPart), &cert)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.cert, cert, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.cert, cert))
|
||||
assert.True(t, strings.Contains(out, "All certificate files have been saved successfully"), fmt.Sprintf("%s should save files", tc.desc))
|
||||
case errLog:
|
||||
if tc.errLogMessage != "" {
|
||||
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
|
||||
} else {
|
||||
assert.True(t, strings.Contains(out, "error"), fmt.Sprintf("%s should contain error message: %s", tc.desc, out))
|
||||
}
|
||||
case usageLog:
|
||||
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
|
||||
}
|
||||
sdkCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssueFromCSRCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
certCmd := cli.NewCertsCmd()
|
||||
rootCmd := setFlags(certCmd)
|
||||
|
||||
csrPath := "test.csr"
|
||||
bytes := []byte("-----BEGIN CERTIFICATE REQUEST-----\n-csr-content\n-----END CERTIFICATE REQUEST-----")
|
||||
|
||||
err := os.WriteFile(csrPath, bytes, filePermission)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test CSR file: %v", err)
|
||||
}
|
||||
defer os.Remove(csrPath)
|
||||
|
||||
var cert sdk.Certificate
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
cert sdk.Certificate
|
||||
}{
|
||||
{
|
||||
desc: "issue cert from CSR successfully",
|
||||
args: []string{
|
||||
id,
|
||||
"10h",
|
||||
csrPath,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
cert: sdk.Certificate{SerialNumber: serialNumber},
|
||||
},
|
||||
{
|
||||
desc: "issue cert from CSR with invalid args",
|
||||
args: []string{
|
||||
id,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "issue cert from CSR failed",
|
||||
args: []string{
|
||||
id,
|
||||
"10h",
|
||||
csrPath,
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
sdkErr: errors.NewSDKErrorWithStatus(certs.ErrFailedCertCreation, http.StatusUnprocessableEntity),
|
||||
errLogMessage: fmt.Sprintf("\nerror: %s\n\n", errors.NewSDKErrorWithStatus(certs.ErrFailedCertCreation, http.StatusUnprocessableEntity)),
|
||||
logType: errLog,
|
||||
},
|
||||
{
|
||||
desc: "issue cert from CSR with non-existent file",
|
||||
args: []string{
|
||||
id,
|
||||
"10h",
|
||||
"non-existent.csr",
|
||||
certsDomainID,
|
||||
certsToken,
|
||||
},
|
||||
logType: errLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
defer func() {
|
||||
cleanupFiles(t, []string{"cert.pem", "key.pem"})
|
||||
}()
|
||||
sdkCall := sdkMock.On("IssueFromCSR", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.cert, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{"issue-csr"}, tc.args...)...)
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
lines := strings.Split(out, "\n")
|
||||
var jsonLines []string
|
||||
var inJSON bool
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "{") {
|
||||
inJSON = true
|
||||
jsonLines = append(jsonLines, line)
|
||||
} else if inJSON && strings.HasSuffix(line, "}") {
|
||||
jsonLines = append(jsonLines, line)
|
||||
break
|
||||
} else if inJSON {
|
||||
jsonLines = append(jsonLines, line)
|
||||
}
|
||||
}
|
||||
|
||||
if len(jsonLines) == 0 {
|
||||
t.Fatalf("No JSON found in output: %s", out)
|
||||
}
|
||||
|
||||
jsonPart := strings.Join(jsonLines, "")
|
||||
|
||||
err := json.Unmarshal([]byte(jsonPart), &cert)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.cert, cert, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.cert, cert))
|
||||
assert.True(t, strings.Contains(out, "All certificate files have been saved successfully"), fmt.Sprintf("%s should save files", tc.desc))
|
||||
case errLog:
|
||||
if tc.errLogMessage != "" {
|
||||
assert.Equal(t, tc.errLogMessage, out, fmt.Sprintf("%s unexpected error response: expected %s got errLogMessage:%s", tc.desc, tc.errLogMessage, out))
|
||||
} else {
|
||||
assert.True(t, strings.Contains(out, "error"), fmt.Sprintf("%s should contain error message: %s", tc.desc, out))
|
||||
}
|
||||
case usageLog:
|
||||
assert.False(t, strings.Contains(out, rootCmd.Use), fmt.Sprintf("%s invalid usage: %s", tc.desc, out))
|
||||
}
|
||||
sdkCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,660 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// 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"
|
||||
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
var channel = mgsdk.Channel{
|
||||
ID: testsutil.GenerateUUID(&testing.T{}),
|
||||
Name: "testchannel",
|
||||
}
|
||||
|
||||
func TestCreateChannelCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
channelJson := "{\"name\":\"testchannel\", \"metadata\":{\"key1\":\"value1\"}}"
|
||||
channelCmd := cli.NewChannelsCmd()
|
||||
rootCmd := setFlags(channelCmd)
|
||||
|
||||
cp := mgsdk.Channel{}
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
logType outputLog
|
||||
channel mgsdk.Channel
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
}{
|
||||
{
|
||||
desc: "create channel successfully",
|
||||
args: []string{
|
||||
createCmd,
|
||||
channelJson,
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
channel: channel,
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "create channel with invalid args",
|
||||
args: []string{
|
||||
createCmd,
|
||||
channelJson,
|
||||
domainID,
|
||||
token,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "create channel with invalid json",
|
||||
args: []string{
|
||||
createCmd,
|
||||
"{\"name\":\"testchannel\", \"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 channel with invalid token",
|
||||
args: []string{
|
||||
createCmd,
|
||||
channelJson,
|
||||
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) {
|
||||
var sdkCall *mock.Call
|
||||
if len(tc.args) >= 4 {
|
||||
sdkCall = sdkMock.On("CreateChannel", mock.Anything, mock.Anything, tc.args[2], tc.args[3]).Return(tc.channel, tc.sdkErr)
|
||||
}
|
||||
out := executeCommand(t, rootCmd, tc.args...)
|
||||
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
err := json.Unmarshal([]byte(out), &cp)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.channel, cp, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.channel, cp))
|
||||
case usageLog:
|
||||
assert.True(t, strings.Contains(out, "cli channels create"), fmt.Sprintf("%s invalid usage: expected to contain create usage, got: %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))
|
||||
}
|
||||
if sdkCall != nil {
|
||||
sdkCall.Unset()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetChannelsCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
channelCmd := cli.NewChannelsCmd()
|
||||
rootCmd := setFlags(channelCmd)
|
||||
|
||||
var ch mgsdk.Channel
|
||||
var page mgsdk.ChannelsPage
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
page mgsdk.ChannelsPage
|
||||
channel mgsdk.Channel
|
||||
logType outputLog
|
||||
errLogMessage string
|
||||
}{
|
||||
{
|
||||
desc: "get all channels successfully",
|
||||
args: []string{
|
||||
all,
|
||||
getCmd,
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
page: mgsdk.ChannelsPage{
|
||||
Channels: []mgsdk.Channel{channel},
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "get channel with id",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
getCmd,
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
logType: entityLog,
|
||||
channel: channel,
|
||||
},
|
||||
{
|
||||
desc: "get channels with invalid args",
|
||||
args: []string{
|
||||
all,
|
||||
getCmd,
|
||||
domainID,
|
||||
token,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "get all channels with invalid token",
|
||||
args: []string{
|
||||
all,
|
||||
getCmd,
|
||||
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 channel with invalid id",
|
||||
args: []string{
|
||||
invalidID,
|
||||
getCmd,
|
||||
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("Channel", mock.Anything, tc.args[0], tc.args[2], tc.args[3]).Return(tc.channel, tc.sdkErr)
|
||||
sdkCall1 := sdkMock.On("Channels", mock.Anything, mock.Anything, tc.args[2], tc.args[3]).Return(tc.page, tc.sdkErr)
|
||||
|
||||
out := executeCommand(t, rootCmd, 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), &ch)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.channel, ch, fmt.Sprintf("%v unexpected response, expected: %v, got: %v", tc.desc, tc.channel, 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteChannelCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
channelCmd := cli.NewChannelsCmd()
|
||||
rootCmd := setFlags(channelCmd)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
logType outputLog
|
||||
errLogMessage string
|
||||
}{
|
||||
{
|
||||
desc: "delete channel successfully",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
delCmd,
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "delete channel with invalid args",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
delCmd,
|
||||
domainID,
|
||||
token,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "delete channel with invalid channel id",
|
||||
args: []string{
|
||||
invalidID,
|
||||
delCmd,
|
||||
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 channel with invalid token",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
delCmd,
|
||||
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("DeleteChannel", mock.Anything, tc.args[0], tc.args[2], tc.args[3]).Return(tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, 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 TestUpdateChannelCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
channelCmd := cli.NewChannelsCmd()
|
||||
rootCmd := setFlags(channelCmd)
|
||||
|
||||
newChannelJson := "{\"name\" : \"channel1\"}"
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
channel mgsdk.Channel
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
logType outputLog
|
||||
}{
|
||||
{
|
||||
desc: "update channel successfully",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
updateCmd,
|
||||
newChannelJson,
|
||||
domainID,
|
||||
token,
|
||||
},
|
||||
channel: mgsdk.Channel{
|
||||
Name: "newchannel1",
|
||||
ID: channel.ID,
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "update channel with invalid args",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
updateCmd,
|
||||
newChannelJson,
|
||||
domainID,
|
||||
token,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "update channel with invalid channel id",
|
||||
args: []string{
|
||||
invalidID,
|
||||
updateCmd,
|
||||
newChannelJson,
|
||||
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 channel with invalid json syntax",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
updateCmd,
|
||||
"{\"name\" : \"channel1\"",
|
||||
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.Channel
|
||||
sdkCall := sdkMock.On("UpdateChannel", mock.Anything, mock.Anything, tc.args[3], tc.args[4]).Return(tc.channel, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, tc.args...)
|
||||
|
||||
switch tc.logType {
|
||||
case entityLog:
|
||||
err := json.Unmarshal([]byte(out), &ch)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tc.channel, ch, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.channel, 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 TestEnableChannelCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
channelCmd := cli.NewChannelsCmd()
|
||||
rootCmd := setFlags(channelCmd)
|
||||
var ch mgsdk.Channel
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
channel mgsdk.Channel
|
||||
logType outputLog
|
||||
}{
|
||||
{
|
||||
desc: "enable channel successfully",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
enableCmd,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
channel: channel,
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "delete channel with invalid token",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
enableCmd,
|
||||
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 channel with invalid channel ID",
|
||||
args: []string{
|
||||
invalidID,
|
||||
enableCmd,
|
||||
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 channel with invalid args",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
enableCmd,
|
||||
domainID,
|
||||
validToken,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("EnableChannel", mock.Anything, tc.args[0], tc.args[2], tc.args[3]).Return(tc.channel, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, 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.channel, ch, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.channel, ch))
|
||||
}
|
||||
|
||||
sdkCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableChannelCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
channelsCmd := cli.NewChannelsCmd()
|
||||
rootCmd := setFlags(channelsCmd)
|
||||
|
||||
var ch mgsdk.Channel
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
channel mgsdk.Channel
|
||||
logType outputLog
|
||||
}{
|
||||
{
|
||||
desc: "disable channel successfully",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
disableCmd,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
channel: channel,
|
||||
},
|
||||
{
|
||||
desc: "disable channel with invalid token",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
disableCmd,
|
||||
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 channel with invalid id",
|
||||
args: []string{
|
||||
invalidID,
|
||||
disableCmd,
|
||||
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 client with invalid args",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
disableCmd,
|
||||
domainID,
|
||||
validToken,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("DisableChannel", mock.Anything, tc.args[0], tc.args[2], tc.args[3]).Return(tc.channel, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, 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.channel, ch, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.channel, ch))
|
||||
}
|
||||
|
||||
sdkCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChannelUsersCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
channelsCmd := cli.NewChannelsCmd()
|
||||
rootCmd := setFlags(channelsCmd)
|
||||
|
||||
var mp mgsdk.EntityMembersPage
|
||||
|
||||
memberRole := mgsdk.MemberRoles{
|
||||
MemberID: testsutil.GenerateUUID(t),
|
||||
Roles: []mgsdk.MemberRole{},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
errLogMessage string
|
||||
usersPage mgsdk.EntityMembersPage
|
||||
logType outputLog
|
||||
}{
|
||||
{
|
||||
desc: "list channel users successfully",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
usersCmd,
|
||||
domainID,
|
||||
validToken,
|
||||
},
|
||||
usersPage: mgsdk.EntityMembersPage{
|
||||
Members: []mgsdk.MemberRoles{memberRole},
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "list channel users with invalid token",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
usersCmd,
|
||||
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: "list channel users with invalid channel id",
|
||||
args: []string{
|
||||
invalidID,
|
||||
usersCmd,
|
||||
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: "list channel users with invalid args",
|
||||
args: []string{
|
||||
channel.ID,
|
||||
usersCmd,
|
||||
domainID,
|
||||
validToken,
|
||||
extraArg,
|
||||
},
|
||||
errLogMessage: rootCmd.Use,
|
||||
logType: usageLog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("ListChannelMembers", mock.Anything, tc.args[0], tc.args[2], mock.Anything, tc.args[3]).Return(tc.usersPage, tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, 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), &mp)
|
||||
if err != nil {
|
||||
t.Fatalf("json.Unmarshal failed: %v", err)
|
||||
}
|
||||
assert.Equal(t, tc.usersPage, mp, fmt.Sprintf("%s unexpected response: expected: %v, got: %v", tc.desc, tc.usersPage, mp))
|
||||
}
|
||||
|
||||
sdkCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
-701
@@ -1,701 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/absmach/magistrala/clients"
|
||||
smqsdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
connect = "connect"
|
||||
disconnect = "disconnect"
|
||||
roles = "roles"
|
||||
actions = "actions"
|
||||
members = "members"
|
||||
secret = "secret"
|
||||
|
||||
// Usage strings for client operations.
|
||||
usageClientCreate = "cli clients create <JSON_client> <domain_id> <user_auth_token>"
|
||||
usageClientGet = "cli clients <client_id|all> get <domain_id> <user_auth_token>"
|
||||
usageClientDelete = "cli clients <client_id> delete <domain_id> <user_auth_token>"
|
||||
usageClientUpdate = "cli clients <client_id> update <JSON_string> <domain_id> <user_auth_token>"
|
||||
usageClientUpdateTags = "cli clients <client_id> update tags <tags> <domain_id> <user_auth_token>"
|
||||
usageClientUpdateSecret = "cli clients <client_id> update secret <secret> <domain_id> <user_auth_token>"
|
||||
usageClientEnable = "cli clients <client_id> enable <domain_id> <user_auth_token>"
|
||||
usageClientDisable = "cli clients <client_id> disable <domain_id> <user_auth_token>"
|
||||
usageClientConnect = "cli clients <client_id> connect <channel_id> <conn_types_json_list> <domain_id> <user_auth_token>"
|
||||
usageClientDisconnect = "cli clients <client_id> disconnect <channel_id> <conn_types_json_list> <domain_id> <user_auth_token>"
|
||||
usageClientUsers = "cli clients <client_id> users <domain_id> <user_auth_token>"
|
||||
|
||||
// Usage strings for client roles operations.
|
||||
usageClientRolesCreate = "cli clients <client_id> roles create <JSON_role> <domain_id> <user_auth_token>"
|
||||
usageClientRolesGet = "cli clients <client_id> roles get <role_id|all> <domain_id> <user_auth_token>"
|
||||
usageClientRolesUpdate = "cli clients <client_id> roles update <role_id> <new_name> <domain_id> <user_auth_token>"
|
||||
usageClientRolesDelete = "cli clients <client_id> roles delete <role_id> <domain_id> <user_auth_token>"
|
||||
|
||||
// Usage strings for client role actions operations.
|
||||
usageClientRoleActionsAdd = "cli clients <client_id> roles actions add <role_id> <JSON_actions> <domain_id> <user_auth_token>"
|
||||
usageClientRoleActionsList = "cli clients <client_id> roles actions list <role_id> <domain_id> <user_auth_token>"
|
||||
usageClientRoleActionsDelete = "cli clients <client_id> roles actions delete <role_id> <JSON_actions|all> <domain_id> <user_auth_token>"
|
||||
usageClientRoleActionsAvailable = "cli clients roles actions available-actions <domain_id> <user_auth_token>"
|
||||
|
||||
// Usage strings for client role members operations.
|
||||
usageClientRoleMembersAdd = "cli clients <client_id> roles members add <role_id> <JSON_members> <domain_id> <user_auth_token>"
|
||||
usageClientRoleMembersList = "cli clients <client_id> roles members list <role_id> <domain_id> <user_auth_token>"
|
||||
usageClientRoleMembersDelete = "cli clients <client_id> roles members delete <role_id> <JSON_members|all> <domain_id> <user_auth_token>"
|
||||
)
|
||||
|
||||
func NewClientsCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "clients <client_id|all|create> [operation] [args...]",
|
||||
Short: "Clients management",
|
||||
Long: `Format:
|
||||
clients create [args...]
|
||||
clients <client_id|all> <operation> [args...]
|
||||
|
||||
Operations (require client_id/all): get, update, delete, enable, disable, connect, disconnect, users, roles
|
||||
|
||||
Examples:
|
||||
clients create <JSON_client> <domain_id> <user_auth_token>
|
||||
clients all get <domain_id> <user_auth_token>
|
||||
clients <client_id> get <domain_id> <user_auth_token>
|
||||
clients <client_id> update <JSON_string> <domain_id> <user_auth_token>
|
||||
clients <client_id> delete <domain_id> <user_auth_token>
|
||||
clients <client_id> enable <domain_id> <user_auth_token>
|
||||
clients <client_id> disable <domain_id> <user_auth_token>
|
||||
clients <client_id> connect <channel_id> <conn_types_json_list> <domain_id> <user_auth_token>
|
||||
clients <client_id> users <domain_id> <user_auth_token>`,
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
logUsageCmd(*cmd, cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == create {
|
||||
handleClientCreate(cmd, args[1:])
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, "clients <client_id|all> <get|update|delete|enable|disable|connect|disconnect|users|roles> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
clientParams := args[0]
|
||||
operation := args[1]
|
||||
opArgs := args[2:]
|
||||
|
||||
switch operation {
|
||||
case get:
|
||||
handleClientGet(cmd, clientParams, opArgs)
|
||||
case update:
|
||||
handleClientUpdate(cmd, clientParams, opArgs)
|
||||
case delete:
|
||||
handleClientDelete(cmd, clientParams, opArgs)
|
||||
case enable:
|
||||
handleClientEnable(cmd, clientParams, opArgs)
|
||||
case disable:
|
||||
handleClientDisable(cmd, clientParams, opArgs)
|
||||
case connect:
|
||||
handleClientConnect(cmd, clientParams, opArgs)
|
||||
case disconnect:
|
||||
handleClientDisconnect(cmd, clientParams, opArgs)
|
||||
case users:
|
||||
handleClientUsers(cmd, clientParams, opArgs)
|
||||
case roles:
|
||||
handleClientRoles(cmd, clientParams, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown operation: %s", operation))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func handleClientCreate(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageClientCreate)
|
||||
return
|
||||
}
|
||||
|
||||
var client smqsdk.Client
|
||||
if err := json.Unmarshal([]byte(args[0]), &client); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
client.Status = clients.EnabledStatus.String()
|
||||
client, err := sdk.CreateClient(cmd.Context(), client, args[1], args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, client)
|
||||
}
|
||||
|
||||
func handleClientGet(cmd *cobra.Command, clientParams string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageClientGet)
|
||||
return
|
||||
}
|
||||
|
||||
if clientParams == all {
|
||||
metadata, err := convertMetadata(Metadata)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Name: Name,
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
Metadata: metadata,
|
||||
}
|
||||
|
||||
l, err := sdk.Clients(cmd.Context(), pageMetadata, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
return
|
||||
}
|
||||
|
||||
t, err := sdk.Client(cmd.Context(), clientParams, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, t)
|
||||
}
|
||||
|
||||
func handleClientUpdate(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) < 3 || len(args) > 4 {
|
||||
if args[0] == tags {
|
||||
logUsageCmd(*cmd, usageClientUpdateTags)
|
||||
return
|
||||
}
|
||||
if args[0] == secret {
|
||||
logUsageCmd(*cmd, usageClientUpdateSecret)
|
||||
return
|
||||
}
|
||||
logUsageCmd(*cmd, usageClientUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) == 4 && args[0] == "tags" {
|
||||
var client smqsdk.Client
|
||||
if err := json.Unmarshal([]byte(args[1]), &client.Tags); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
client.ID = clientID
|
||||
client, err := sdk.UpdateClientTags(cmd.Context(), client, args[2], args[3])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, client)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) == 4 && args[0] == "secret" {
|
||||
client, err := sdk.UpdateClientSecret(cmd.Context(), clientID, args[1], args[2], args[3])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, client)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageClientUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
var client smqsdk.Client
|
||||
if err := json.Unmarshal([]byte(args[0]), &client); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
client.ID = clientID
|
||||
client, err := sdk.UpdateClient(cmd.Context(), client, args[1], args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, client)
|
||||
}
|
||||
|
||||
func handleClientDelete(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageClientDelete)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.DeleteClient(cmd.Context(), clientID, args[0], args[1]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleClientEnable(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageClientEnable)
|
||||
return
|
||||
}
|
||||
|
||||
client, err := sdk.EnableClient(cmd.Context(), clientID, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, client)
|
||||
}
|
||||
|
||||
func handleClientDisable(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageClientDisable)
|
||||
return
|
||||
}
|
||||
|
||||
client, err := sdk.DisableClient(cmd.Context(), clientID, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, client)
|
||||
}
|
||||
|
||||
func handleClientConnect(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageClientConnect)
|
||||
return
|
||||
}
|
||||
|
||||
var conn_types []string
|
||||
err := json.Unmarshal([]byte(args[1]), &conn_types)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
connIDs := smqsdk.Connection{
|
||||
ChannelIDs: []string{args[0]},
|
||||
ClientIDs: []string{clientID},
|
||||
Types: conn_types,
|
||||
}
|
||||
if err := sdk.Connect(cmd.Context(), connIDs, args[2], args[3]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleClientDisconnect(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageClientDisconnect)
|
||||
return
|
||||
}
|
||||
|
||||
var conn_types []string
|
||||
err := json.Unmarshal([]byte(args[1]), &conn_types)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
connIDs := smqsdk.Connection{
|
||||
ClientIDs: []string{clientID},
|
||||
ChannelIDs: []string{args[0]},
|
||||
Types: conn_types,
|
||||
}
|
||||
if err := sdk.Disconnect(cmd.Context(), connIDs, args[2], args[3]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleClientUsers(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageClientUsers)
|
||||
return
|
||||
}
|
||||
|
||||
pm := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
ul, err := sdk.ListClientMembers(cmd.Context(), clientID, args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, ul)
|
||||
}
|
||||
|
||||
func handleClientRoles(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli clients <client_id> roles <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case create:
|
||||
handleClientRoleCreate(cmd, clientID, opArgs)
|
||||
case get:
|
||||
handleClientRoleGet(cmd, clientID, opArgs)
|
||||
case update:
|
||||
handleClientRoleUpdate(cmd, clientID, opArgs)
|
||||
case delete:
|
||||
handleClientRoleDelete(cmd, clientID, opArgs)
|
||||
case actions:
|
||||
handleClientRoleActions(cmd, clientID, opArgs)
|
||||
case members:
|
||||
handleClientRoleMembers(cmd, clientID, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown roles operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleClientRoleCreate(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageClientRolesCreate)
|
||||
return
|
||||
}
|
||||
|
||||
var roleReq smqsdk.RoleReq
|
||||
if err := json.Unmarshal([]byte(args[0]), &roleReq); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
r, err := sdk.CreateClientRole(cmd.Context(), clientID, args[1], roleReq, args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleClientRoleGet(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageClientRolesGet)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
domainID := args[1]
|
||||
token := args[2]
|
||||
|
||||
if roleID == all {
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
rs, err := sdk.ClientRoles(cmd.Context(), clientID, domainID, pageMetadata, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, rs)
|
||||
return
|
||||
}
|
||||
|
||||
r, err := sdk.ClientRole(cmd.Context(), clientID, roleID, domainID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleClientRoleUpdate(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageClientRolesUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
newName := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
r, err := sdk.UpdateClientRole(cmd.Context(), clientID, roleID, newName, domainID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleClientRoleDelete(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageClientRolesDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
domainID := args[1]
|
||||
token := args[2]
|
||||
|
||||
if err := sdk.DeleteClientRole(cmd.Context(), clientID, roleID, domainID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleClientRoleActions(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli clients <client_id> roles actions <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case add:
|
||||
handleClientRoleActionsAdd(cmd, clientID, opArgs)
|
||||
case list:
|
||||
handleClientRoleActionsList(cmd, clientID, opArgs)
|
||||
case delete:
|
||||
handleClientRoleActionsDelete(cmd, clientID, opArgs)
|
||||
case availableActions:
|
||||
handleClientRoleActionsAvailable(cmd, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown actions operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleClientRoleActionsAdd(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageClientRoleActionsAdd)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
actionsJSON := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
actions := struct {
|
||||
Actions []string `json:"actions"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(actionsJSON), &actions); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
acts, err := sdk.AddClientRoleActions(cmd.Context(), clientID, roleID, domainID, actions.Actions, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, acts)
|
||||
}
|
||||
|
||||
func handleClientRoleActionsList(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageClientRoleActionsList)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
domainID := args[1]
|
||||
token := args[2]
|
||||
|
||||
l, err := sdk.ClientRoleActions(cmd.Context(), clientID, roleID, domainID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
}
|
||||
|
||||
func handleClientRoleActionsDelete(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageClientRoleActionsDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
actionsJSON := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
if actionsJSON == all {
|
||||
if err := sdk.RemoveAllClientRoleActions(cmd.Context(), clientID, roleID, domainID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
return
|
||||
}
|
||||
|
||||
actions := struct {
|
||||
Actions []string `json:"actions"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(actionsJSON), &actions); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.RemoveClientRoleActions(cmd.Context(), clientID, roleID, domainID, actions.Actions, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleClientRoleActionsAvailable(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageClientRoleActionsAvailable)
|
||||
return
|
||||
}
|
||||
|
||||
domainID := args[0]
|
||||
token := args[1]
|
||||
|
||||
acts, err := sdk.AvailableClientRoleActions(cmd.Context(), domainID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, acts)
|
||||
}
|
||||
|
||||
func handleClientRoleMembers(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli clients <client_id> roles members <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case add:
|
||||
handleClientRoleMembersAdd(cmd, clientID, opArgs)
|
||||
case list:
|
||||
handleClientRoleMembersList(cmd, clientID, opArgs)
|
||||
case delete:
|
||||
handleClientRoleMembersDelete(cmd, clientID, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown members operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleClientRoleMembersAdd(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageClientRoleMembersAdd)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
membersJSON := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
members := struct {
|
||||
Members []string `json:"members"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(membersJSON), &members); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
memb, err := sdk.AddClientRoleMembers(cmd.Context(), clientID, roleID, domainID, members.Members, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, memb)
|
||||
}
|
||||
|
||||
func handleClientRoleMembersList(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageClientRoleMembersList)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
domainID := args[1]
|
||||
token := args[2]
|
||||
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
|
||||
l, err := sdk.ClientRoleMembers(cmd.Context(), clientID, roleID, domainID, pageMetadata, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
}
|
||||
|
||||
func handleClientRoleMembersDelete(cmd *cobra.Command, clientID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageClientRoleMembersDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
membersJSON := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
if membersJSON == all {
|
||||
if err := sdk.RemoveAllClientRoleMembers(cmd.Context(), clientID, roleID, domainID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
return
|
||||
}
|
||||
|
||||
members := struct {
|
||||
Members []string `json:"members"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(membersJSON), &members); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.RemoveClientRoleMembers(cmd.Context(), clientID, roleID, domainID, members.Members, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
-1943
File diff suppressed because it is too large
Load Diff
@@ -1,64 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// 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"
|
||||
freezeCmd = "freeze"
|
||||
delCmd = "delete"
|
||||
)
|
||||
|
||||
// Users commands
|
||||
const (
|
||||
tokCmd = "token"
|
||||
refTokCmd = "refreshtoken"
|
||||
profCmd = "profile"
|
||||
resPassReqCmd = "resetpasswordrequest"
|
||||
resPassCmd = "resetpassword"
|
||||
passCmd = "password"
|
||||
)
|
||||
|
||||
// Clients commands
|
||||
const (
|
||||
connCmd = "connect"
|
||||
disconnCmd = "disconnect"
|
||||
usersCmd = "users"
|
||||
)
|
||||
|
||||
// Messages commands
|
||||
const sendCmd = "send"
|
||||
|
||||
// Invitations commands
|
||||
const (
|
||||
acceptCmd = "accept"
|
||||
rejectCmd = "reject"
|
||||
userCmd = "user"
|
||||
domainCmd = "domain"
|
||||
)
|
||||
|
||||
// Role commands
|
||||
const (
|
||||
rolesCmd = "roles"
|
||||
actionsCmd = "actions"
|
||||
availableActionsCmd = "available-actions"
|
||||
addCmd = "add"
|
||||
listCmd = "list"
|
||||
membersCmd = "members"
|
||||
)
|
||||
|
||||
// Bootstrap commands
|
||||
const (
|
||||
updCmd = "update"
|
||||
rmCmd = "remove"
|
||||
whitelistCmd = "whitelist"
|
||||
bootStrapCmd = "bootstrap"
|
||||
)
|
||||
@@ -1,269 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// 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"
|
||||
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
var (
|
||||
userID = testsutil.GenerateUUID(&testing.T{})
|
||||
subscription = mgsdk.Subscription{
|
||||
ID: testsutil.GenerateUUID(&testing.T{}),
|
||||
OwnerID: userID,
|
||||
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: userID,
|
||||
response: fmt.Sprintf("\ncreated: %s\n\n", userID),
|
||||
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", mock.Anything, 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,
|
||||
validToken,
|
||||
},
|
||||
page: mgsdk.SubscriptionPage{
|
||||
Subscriptions: []mgsdk.Subscription{subscription},
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "get subscription with id",
|
||||
args: []string{
|
||||
subscription.ID,
|
||||
validToken,
|
||||
},
|
||||
logType: entityLog,
|
||||
subscription: subscription,
|
||||
},
|
||||
{
|
||||
desc: "get subscriptions with invalid args",
|
||||
args: []string{
|
||||
all,
|
||||
validToken,
|
||||
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 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("ViewSubscription", mock.Anything, tc.args[0], tc.args[1]).Return(tc.subscription, tc.sdkErr)
|
||||
sdkCall1 := sdkMock.On("ListSubscriptions", mock.Anything, 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,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "remove subscription with invalid args",
|
||||
args: []string{
|
||||
subscription.ID,
|
||||
validToken,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "remove subscription with invalid subscription 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,
|
||||
},
|
||||
{
|
||||
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", mock.Anything, 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
-583
@@ -1,583 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
smqsdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
freeze = "freeze"
|
||||
|
||||
// Usage strings for domain operations.
|
||||
usageDomainCreate = "cli domains create <domain_name> <route> <user_auth_token>"
|
||||
usageDomainGet = "cli domains <domain_id|all> get <user_auth_token>"
|
||||
usageDomainUpdate = "cli domains <domain_id> update <JSON_string> <user_auth_token>"
|
||||
usageDomainEnable = "cli domains <domain_id> enable <user_auth_token>"
|
||||
usageDomainDisable = "cli domains <domain_id> disable <user_auth_token>"
|
||||
usageDomainFreeze = "cli domains <domain_id> freeze <user_auth_token>"
|
||||
usageDomainUsers = "cli domains <domain_id> users <user_auth_token>"
|
||||
|
||||
// Usage strings for domain roles operations.
|
||||
usageDomainRolesCreate = "cli domains <domain_id> roles create <JSON_role> <user_auth_token>"
|
||||
usageDomainRolesGet = "cli domains <domain_id> roles get <role_id|all> <user_auth_token>"
|
||||
usageDomainRolesUpdate = "cli domains <domain_id> roles update <role_id> <new_name> <user_auth_token>"
|
||||
usageDomainRolesDelete = "cli domains <domain_id> roles delete <role_id> <user_auth_token>"
|
||||
|
||||
// Usage strings for domain role actions operations.
|
||||
usageDomainRoleActionsAdd = "cli domains <domain_id> roles actions add <role_id> <JSON_actions> <user_auth_token>"
|
||||
usageDomainRoleActionsList = "cli domains <domain_id> roles actions list <role_id> <user_auth_token>"
|
||||
usageDomainRoleActionsDelete = "cli domains <domain_id> roles actions delete <role_id> <JSON_actions|all> <user_auth_token>"
|
||||
usageDomainRoleActionsAvailable = "cli domains roles actions available-actions <user_auth_token>"
|
||||
|
||||
// Usage strings for domain role members operations.
|
||||
usageDomainRoleMembersAdd = "cli domains <domain_id> roles members add <role_id> <JSON_members> <user_auth_token>"
|
||||
usageDomainRoleMembersList = "cli domains <domain_id> roles members list <role_id> <user_auth_token>"
|
||||
usageDomainRoleMembersDelete = "cli domains <domain_id> roles members delete <role_id> <JSON_members|all> <user_auth_token>"
|
||||
)
|
||||
|
||||
func NewDomainsCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "domains <domain_id|all|create> [operation] [args...]",
|
||||
Short: "Domains management",
|
||||
Long: `Format:
|
||||
domains create [args...]
|
||||
domains <domain_id|all> <operation> [args...]
|
||||
|
||||
Operations (require domain_id/all): get, update, enable, disable, freeze, users, roles
|
||||
|
||||
Examples:
|
||||
domains create <domain_name> <route> <user_auth_token>
|
||||
domains all get <user_auth_token>
|
||||
domains <domain_id> get <user_auth_token>
|
||||
domains <domain_id> update <JSON_string> <user_auth_token>
|
||||
domains <domain_id> enable <user_auth_token>
|
||||
domains <domain_id> disable <user_auth_token>
|
||||
domains <domain_id> freeze <user_auth_token>
|
||||
domains <domain_id> users <user_auth_token>`,
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
logUsageCmd(*cmd, cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == create {
|
||||
handleDomainCreate(cmd, args[1:])
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, "domains <domain_id|all> <get|update|enable|disable|freeze|users|roles> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
domainParams := args[0]
|
||||
operation := args[1]
|
||||
opArgs := args[2:]
|
||||
|
||||
switch operation {
|
||||
case get:
|
||||
handleDomainGet(cmd, domainParams, opArgs)
|
||||
case update:
|
||||
handleDomainUpdate(cmd, domainParams, opArgs)
|
||||
case enable:
|
||||
handleDomainEnable(cmd, domainParams, opArgs)
|
||||
case disable:
|
||||
handleDomainDisable(cmd, domainParams, opArgs)
|
||||
case freeze:
|
||||
handleDomainFreeze(cmd, domainParams, opArgs)
|
||||
case users:
|
||||
handleDomainUsers(cmd, domainParams, opArgs)
|
||||
case roles:
|
||||
handleDomainRoles(cmd, domainParams, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown operation: %s", operation))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func handleDomainCreate(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageDomainCreate)
|
||||
return
|
||||
}
|
||||
|
||||
dom := smqsdk.Domain{
|
||||
Name: args[0],
|
||||
Route: args[1],
|
||||
}
|
||||
d, err := sdk.CreateDomain(cmd.Context(), dom, args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, d)
|
||||
}
|
||||
|
||||
func handleDomainGet(cmd *cobra.Command, domainParams string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageDomainGet)
|
||||
return
|
||||
}
|
||||
|
||||
if domainParams == all {
|
||||
metadata, err := convertMetadata(Metadata)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Name: Name,
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
Metadata: metadata,
|
||||
Status: Status,
|
||||
}
|
||||
|
||||
l, err := sdk.Domains(cmd.Context(), pageMetadata, args[0])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
return
|
||||
}
|
||||
|
||||
d, err := sdk.Domain(cmd.Context(), domainParams, args[0])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, d)
|
||||
}
|
||||
|
||||
func handleDomainUpdate(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageDomainUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
var d smqsdk.Domain
|
||||
if err := json.Unmarshal([]byte(args[0]), &d); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
d.ID = domainID
|
||||
d, err := sdk.UpdateDomain(cmd.Context(), d, args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, d)
|
||||
}
|
||||
|
||||
func handleDomainEnable(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageDomainEnable)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.EnableDomain(cmd.Context(), domainID, args[0]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleDomainDisable(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageDomainDisable)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.DisableDomain(cmd.Context(), domainID, args[0]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleDomainFreeze(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageDomainFreeze)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.FreezeDomain(cmd.Context(), domainID, args[0]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleDomainUsers(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageDomainUsers)
|
||||
return
|
||||
}
|
||||
|
||||
metadata, err := convertMetadata(Metadata)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
Metadata: metadata,
|
||||
Status: Status,
|
||||
}
|
||||
|
||||
l, err := sdk.ListDomainMembers(cmd.Context(), domainID, pageMetadata, args[0])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
}
|
||||
|
||||
func handleDomainRoles(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli domains <domain_id> roles <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case create:
|
||||
handleDomainRoleCreate(cmd, domainID, opArgs)
|
||||
case get:
|
||||
handleDomainRoleGet(cmd, domainID, opArgs)
|
||||
case update:
|
||||
handleDomainRoleUpdate(cmd, domainID, opArgs)
|
||||
case delete:
|
||||
handleDomainRoleDelete(cmd, domainID, opArgs)
|
||||
case actions:
|
||||
handleDomainRoleActions(cmd, domainID, opArgs)
|
||||
case members:
|
||||
handleDomainRoleMembers(cmd, domainID, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown roles operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleDomainRoleCreate(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageDomainRolesCreate)
|
||||
return
|
||||
}
|
||||
|
||||
var roleReq smqsdk.RoleReq
|
||||
if err := json.Unmarshal([]byte(args[0]), &roleReq); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
r, err := sdk.CreateDomainRole(cmd.Context(), domainID, roleReq, args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleDomainRoleGet(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageDomainRolesGet)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
token := args[1]
|
||||
|
||||
if roleID == all {
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
rs, err := sdk.DomainRoles(cmd.Context(), domainID, pageMetadata, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, rs)
|
||||
return
|
||||
}
|
||||
|
||||
r, err := sdk.DomainRole(cmd.Context(), domainID, roleID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleDomainRoleUpdate(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageDomainRolesUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
newName := args[1]
|
||||
token := args[2]
|
||||
|
||||
r, err := sdk.UpdateDomainRole(cmd.Context(), domainID, roleID, newName, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleDomainRoleDelete(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageDomainRolesDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
token := args[1]
|
||||
|
||||
if err := sdk.DeleteDomainRole(cmd.Context(), domainID, roleID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleDomainRoleActions(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli domains <domain_id> roles actions <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case add:
|
||||
handleDomainRoleActionsAdd(cmd, domainID, opArgs)
|
||||
case list:
|
||||
handleDomainRoleActionsList(cmd, domainID, opArgs)
|
||||
case delete:
|
||||
handleDomainRoleActionsDelete(cmd, domainID, opArgs)
|
||||
case availableActions:
|
||||
handleDomainRoleActionsAvailable(cmd, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown actions operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleDomainRoleActionsAdd(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageDomainRoleActionsAdd)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
actionsJSON := args[1]
|
||||
token := args[2]
|
||||
|
||||
actions := struct {
|
||||
Actions []string `json:"actions"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(actionsJSON), &actions); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
acts, err := sdk.AddDomainRoleActions(cmd.Context(), domainID, roleID, actions.Actions, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, acts)
|
||||
}
|
||||
|
||||
func handleDomainRoleActionsList(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageDomainRoleActionsList)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
token := args[1]
|
||||
|
||||
l, err := sdk.DomainRoleActions(cmd.Context(), domainID, roleID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
}
|
||||
|
||||
func handleDomainRoleActionsDelete(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageDomainRoleActionsDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
actionsJSON := args[1]
|
||||
token := args[2]
|
||||
|
||||
if actionsJSON == all {
|
||||
if err := sdk.RemoveAllDomainRoleActions(cmd.Context(), domainID, roleID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
return
|
||||
}
|
||||
|
||||
actions := struct {
|
||||
Actions []string `json:"actions"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(actionsJSON), &actions); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.RemoveDomainRoleActions(cmd.Context(), domainID, roleID, actions.Actions, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleDomainRoleActionsAvailable(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageDomainRoleActionsAvailable)
|
||||
return
|
||||
}
|
||||
|
||||
token := args[0]
|
||||
|
||||
acts, err := sdk.AvailableDomainRoleActions(cmd.Context(), token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, acts)
|
||||
}
|
||||
|
||||
func handleDomainRoleMembers(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli domains <domain_id> roles members <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case add:
|
||||
handleDomainRoleMembersAdd(cmd, domainID, opArgs)
|
||||
case list:
|
||||
handleDomainRoleMembersList(cmd, domainID, opArgs)
|
||||
case delete:
|
||||
handleDomainRoleMembersDelete(cmd, domainID, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown members operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleDomainRoleMembersAdd(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageDomainRoleMembersAdd)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
membersJSON := args[1]
|
||||
token := args[2]
|
||||
|
||||
members := struct {
|
||||
Members []string `json:"members"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(membersJSON), &members); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
memb, err := sdk.AddDomainRoleMembers(cmd.Context(), domainID, roleID, members.Members, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, memb)
|
||||
}
|
||||
|
||||
func handleDomainRoleMembersList(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageDomainRoleMembersList)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
token := args[1]
|
||||
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
|
||||
l, err := sdk.DomainRoleMembers(cmd.Context(), domainID, roleID, pageMetadata, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
}
|
||||
|
||||
func handleDomainRoleMembersDelete(cmd *cobra.Command, domainID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageDomainRoleMembersDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
membersJSON := args[1]
|
||||
token := args[2]
|
||||
|
||||
if membersJSON == all {
|
||||
if err := sdk.RemoveAllDomainRoleMembers(cmd.Context(), domainID, roleID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
return
|
||||
}
|
||||
|
||||
members := struct {
|
||||
Members []string `json:"members"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(membersJSON), &members); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.RemoveDomainRoleMembers(cmd.Context(), domainID, roleID, members.Members, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
-1435
File diff suppressed because it is too large
Load Diff
-601
@@ -1,601 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/absmach/magistrala/groups"
|
||||
smqsdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
tags = "tags"
|
||||
add = "add"
|
||||
list = "list"
|
||||
availableActions = "available-actions"
|
||||
|
||||
// Usage strings for group operations.
|
||||
usageGroupCreate = "cli groups create <JSON_group> <domain_id> <user_auth_token>"
|
||||
usageGroupGet = "cli groups <group_id|all> get <domain_id> <user_auth_token>"
|
||||
usageGroupUpdate = "cli groups <group_id> update <JSON_string> <domain_id> <user_auth_token>"
|
||||
usageGroupUpdateTags = "cli groups <group_id> update tags <tags> <domain_id> <user_auth_token>"
|
||||
usageGroupDelete = "cli groups <group_id> delete <domain_id> <user_auth_token>"
|
||||
usageGroupEnable = "cli groups <group_id> enable <domain_id> <user_auth_token>"
|
||||
usageGroupDisable = "cli groups <group_id> disable <domain_id> <user_auth_token>"
|
||||
|
||||
// Usage strings for group roles operations.
|
||||
usageGroupRolesCreate = "cli groups <group_id> roles create <JSON_role> <domain_id> <user_auth_token>"
|
||||
usageGroupRolesGet = "cli groups <group_id> roles get <role_id|all> <domain_id> <user_auth_token>"
|
||||
usageGroupRolesUpdate = "cli groups <group_id> roles update <role_id> <new_name> <domain_id> <user_auth_token>"
|
||||
usageGroupRolesDelete = "cli groups <group_id> roles delete <role_id> <domain_id> <user_auth_token>"
|
||||
|
||||
// Usage strings for group role actions operations.
|
||||
usageGroupRoleActionsAdd = "cli groups <group_id> roles actions add <role_id> <JSON_actions> <domain_id> <user_auth_token>"
|
||||
usageGroupRoleActionsList = "cli groups <group_id> roles actions list <role_id> <domain_id> <user_auth_token>"
|
||||
usageGroupRoleActionsDelete = "cli groups <group_id> roles actions delete <role_id> <JSON_actions|all> <domain_id> <user_auth_token>"
|
||||
usageGroupRoleActionsAvailable = "cli groups roles actions available-actions <domain_id> <user_auth_token>"
|
||||
|
||||
// Usage strings for group role members operations.
|
||||
usageGroupRoleMembersAdd = "cli groups <group_id> roles members add <role_id> <JSON_members> <domain_id> <user_auth_token>"
|
||||
usageGroupRoleMembersList = "cli groups <group_id> roles members list <role_id> <domain_id> <user_auth_token>"
|
||||
usageGroupRoleMembersDelete = "cli groups <group_id> roles members delete <role_id> <JSON_members|all> <domain_id> <user_auth_token>"
|
||||
)
|
||||
|
||||
func NewGroupsCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "groups <group_id|all|create> [operation] [args...]",
|
||||
Short: "Groups management",
|
||||
Long: `Format:
|
||||
groups create [args...]
|
||||
groups <group_id|all> <operation> [args...]
|
||||
|
||||
Operations (require group_id/all): get, update, delete, enable, disable, roles
|
||||
|
||||
Examples:
|
||||
groups create <JSON_group> <domain_id> <user_auth_token>
|
||||
groups all get <domain_id> <user_auth_token>
|
||||
groups <group_id> get <domain_id> <user_auth_token>
|
||||
groups <group_id> update <JSON_string> <domain_id> <user_auth_token>
|
||||
groups <group_id> update tags <tags> <domain_id> <user_auth_token>
|
||||
groups <group_id> delete <domain_id> <user_auth_token>
|
||||
groups <group_id> enable <domain_id> <user_auth_token>
|
||||
groups <group_id> disable <domain_id> <user_auth_token>`,
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
logUsageCmd(*cmd, cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == create {
|
||||
handleGroupCreate(cmd, args[1:])
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, "groups <group_id|all> <get|update|delete|enable|disable|roles> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
groupParams := args[0]
|
||||
operation := args[1]
|
||||
opArgs := args[2:]
|
||||
|
||||
switch operation {
|
||||
case get:
|
||||
handleGroupGet(cmd, groupParams, opArgs)
|
||||
case update:
|
||||
handleGroupUpdate(cmd, groupParams, opArgs)
|
||||
case delete:
|
||||
handleGroupDelete(cmd, groupParams, opArgs)
|
||||
case enable:
|
||||
handleGroupEnable(cmd, groupParams, opArgs)
|
||||
case disable:
|
||||
handleGroupDisable(cmd, groupParams, opArgs)
|
||||
case roles:
|
||||
handleGroupRoles(cmd, groupParams, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown operation: %s", operation))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func handleGroupCreate(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageGroupCreate)
|
||||
return
|
||||
}
|
||||
|
||||
var group smqsdk.Group
|
||||
if err := json.Unmarshal([]byte(args[0]), &group); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
group.Status = groups.EnabledStatus.String()
|
||||
group, err := sdk.CreateGroup(cmd.Context(), group, args[1], args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, group)
|
||||
}
|
||||
|
||||
func handleGroupGet(cmd *cobra.Command, groupParams string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageGroupGet)
|
||||
return
|
||||
}
|
||||
|
||||
if groupParams == all {
|
||||
metadata, err := convertMetadata(Metadata)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Name: Name,
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
Metadata: metadata,
|
||||
}
|
||||
|
||||
l, err := sdk.Groups(cmd.Context(), pageMetadata, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
return
|
||||
}
|
||||
|
||||
g, err := sdk.Group(cmd.Context(), groupParams, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, g)
|
||||
}
|
||||
|
||||
func handleGroupUpdate(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) < 3 || len(args) > 4 {
|
||||
if args[0] == tags {
|
||||
logUsageCmd(*cmd, usageGroupUpdateTags)
|
||||
return
|
||||
}
|
||||
logUsageCmd(*cmd, usageGroupUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) == 4 && args[0] == tags {
|
||||
var group smqsdk.Group
|
||||
if err := json.Unmarshal([]byte(args[1]), &group.Tags); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
group.ID = groupID
|
||||
group, err := sdk.UpdateGroupTags(cmd.Context(), group, args[2], args[3])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, group)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageGroupUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
var group smqsdk.Group
|
||||
if err := json.Unmarshal([]byte(args[0]), &group); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
group.ID = groupID
|
||||
group, err := sdk.UpdateGroup(cmd.Context(), group, args[1], args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, group)
|
||||
}
|
||||
|
||||
func handleGroupDelete(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageGroupDelete)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.DeleteGroup(cmd.Context(), groupID, args[0], args[1]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleGroupEnable(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageGroupEnable)
|
||||
return
|
||||
}
|
||||
|
||||
group, err := sdk.EnableGroup(cmd.Context(), groupID, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, group)
|
||||
}
|
||||
|
||||
func handleGroupDisable(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageGroupDisable)
|
||||
return
|
||||
}
|
||||
|
||||
group, err := sdk.DisableGroup(cmd.Context(), groupID, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, group)
|
||||
}
|
||||
|
||||
func handleGroupRoles(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli groups <group_id> roles <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case create:
|
||||
handleGroupRoleCreate(cmd, groupID, opArgs)
|
||||
case get:
|
||||
handleGroupRoleGet(cmd, groupID, opArgs)
|
||||
case update:
|
||||
handleGroupRoleUpdate(cmd, groupID, opArgs)
|
||||
case delete:
|
||||
handleGroupRoleDelete(cmd, groupID, opArgs)
|
||||
case actions:
|
||||
handleGroupRoleActions(cmd, groupID, opArgs)
|
||||
case members:
|
||||
handleGroupRoleMembers(cmd, groupID, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown roles operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleGroupRoleCreate(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageGroupRolesCreate)
|
||||
return
|
||||
}
|
||||
|
||||
var roleReq smqsdk.RoleReq
|
||||
if err := json.Unmarshal([]byte(args[0]), &roleReq); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
r, err := sdk.CreateGroupRole(cmd.Context(), groupID, args[1], roleReq, args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleGroupRoleGet(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageGroupRolesGet)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
domainID := args[1]
|
||||
token := args[2]
|
||||
|
||||
if roleID == all {
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
rs, err := sdk.GroupRoles(cmd.Context(), groupID, domainID, pageMetadata, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, rs)
|
||||
return
|
||||
}
|
||||
|
||||
r, err := sdk.GroupRole(cmd.Context(), groupID, roleID, domainID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleGroupRoleUpdate(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageGroupRolesUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
newName := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
r, err := sdk.UpdateGroupRole(cmd.Context(), groupID, roleID, newName, domainID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, r)
|
||||
}
|
||||
|
||||
func handleGroupRoleDelete(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageGroupRolesDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
domainID := args[1]
|
||||
token := args[2]
|
||||
|
||||
if err := sdk.DeleteGroupRole(cmd.Context(), groupID, roleID, domainID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleGroupRoleActions(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli groups <group_id> roles actions <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case add:
|
||||
handleGroupRoleActionsAdd(cmd, groupID, opArgs)
|
||||
case list:
|
||||
handleGroupRoleActionsList(cmd, groupID, opArgs)
|
||||
case delete:
|
||||
handleGroupRoleActionsDelete(cmd, groupID, opArgs)
|
||||
case availableActions:
|
||||
handleGroupRoleActionsAvailable(cmd, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown actions operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleGroupRoleActionsAdd(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageGroupRoleActionsAdd)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
actionsJSON := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
actions := struct {
|
||||
Actions []string `json:"actions"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(actionsJSON), &actions); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
acts, err := sdk.AddGroupRoleActions(cmd.Context(), groupID, roleID, domainID, actions.Actions, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, acts)
|
||||
}
|
||||
|
||||
func handleGroupRoleActionsList(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageGroupRoleActionsList)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
domainID := args[1]
|
||||
token := args[2]
|
||||
|
||||
l, err := sdk.GroupRoleActions(cmd.Context(), groupID, roleID, domainID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
}
|
||||
|
||||
func handleGroupRoleActionsDelete(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageGroupRoleActionsDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
actionsJSON := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
if actionsJSON == all {
|
||||
if err := sdk.RemoveAllGroupRoleActions(cmd.Context(), groupID, roleID, domainID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
return
|
||||
}
|
||||
|
||||
actions := struct {
|
||||
Actions []string `json:"actions"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(actionsJSON), &actions); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.RemoveGroupRoleActions(cmd.Context(), groupID, roleID, domainID, actions.Actions, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleGroupRoleActionsAvailable(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageGroupRoleActionsAvailable)
|
||||
return
|
||||
}
|
||||
|
||||
domainID := args[0]
|
||||
token := args[1]
|
||||
|
||||
acts, err := sdk.AvailableGroupRoleActions(cmd.Context(), domainID, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, acts)
|
||||
}
|
||||
|
||||
func handleGroupRoleMembers(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, "cli groups <group_id> roles members <operation> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
operation := args[0]
|
||||
opArgs := args[1:]
|
||||
|
||||
switch operation {
|
||||
case add:
|
||||
handleGroupRoleMembersAdd(cmd, groupID, opArgs)
|
||||
case list:
|
||||
handleGroupRoleMembersList(cmd, groupID, opArgs)
|
||||
case delete:
|
||||
handleGroupRoleMembersDelete(cmd, groupID, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown members operation: %s", operation))
|
||||
}
|
||||
}
|
||||
|
||||
func handleGroupRoleMembersAdd(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageGroupRoleMembersAdd)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
membersJSON := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
members := struct {
|
||||
Members []string `json:"members"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(membersJSON), &members); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
memb, err := sdk.AddGroupRoleMembers(cmd.Context(), groupID, roleID, domainID, members.Members, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, memb)
|
||||
}
|
||||
|
||||
func handleGroupRoleMembersList(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageGroupRoleMembersList)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
domainID := args[1]
|
||||
token := args[2]
|
||||
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
|
||||
l, err := sdk.GroupRoleMembers(cmd.Context(), groupID, roleID, domainID, pageMetadata, token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
}
|
||||
|
||||
func handleGroupRoleMembersDelete(cmd *cobra.Command, groupID string, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsageCmd(*cmd, usageGroupRoleMembersDelete)
|
||||
return
|
||||
}
|
||||
|
||||
roleID := args[0]
|
||||
membersJSON := args[1]
|
||||
domainID := args[2]
|
||||
token := args[3]
|
||||
|
||||
if membersJSON == all {
|
||||
if err := sdk.RemoveAllGroupRoleMembers(cmd.Context(), groupID, roleID, domainID, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
return
|
||||
}
|
||||
|
||||
members := struct {
|
||||
Members []string `json:"members"`
|
||||
}{}
|
||||
if err := json.Unmarshal([]byte(membersJSON), &members); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.RemoveGroupRoleMembers(cmd.Context(), groupID, roleID, domainID, members.Members, token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
-1325
File diff suppressed because it is too large
Load Diff
@@ -1,87 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// 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"
|
||||
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()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// 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"
|
||||
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{}),
|
||||
InviteeUserID: user.ID,
|
||||
DomainID: domain.ID,
|
||||
}
|
||||
|
||||
func TestSendDomainInvitationCmd(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 domain invitation successfully",
|
||||
args: []string{
|
||||
user.ID,
|
||||
domain.ID,
|
||||
relation,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "send domain invitation with invalid args",
|
||||
args: []string{
|
||||
user.ID,
|
||||
domain.ID,
|
||||
relation,
|
||||
validToken,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "send domain 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, mock.Anything).Return(tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{domainCmd, 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 TestGetUserInvitationsCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
invCmd := cli.NewInvitationsCmd()
|
||||
rootCmd := setFlags(invCmd)
|
||||
|
||||
var page mgsdk.InvitationPage
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
page mgsdk.InvitationPage
|
||||
logType outputLog
|
||||
errLogMessage string
|
||||
}{
|
||||
{
|
||||
desc: "get user invitations successfully",
|
||||
args: []string{
|
||||
token,
|
||||
},
|
||||
page: mgsdk.InvitationPage{
|
||||
Total: 1,
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Invitations: []mgsdk.Invitation{invitation},
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "get user invitations with invalid args",
|
||||
args: []string{
|
||||
token,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "get user invitations with invalid token",
|
||||
args: []string{
|
||||
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("Invitations", mock.Anything, mock.Anything, tc.args[0]).Return(tc.page, tc.sdkErr)
|
||||
|
||||
out := executeCommand(t, rootCmd, append([]string{userCmd, 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDomainInvitationsCmd(t *testing.T) {
|
||||
sdkMock := new(sdkmocks.SDK)
|
||||
cli.SetSDK(sdkMock)
|
||||
invCmd := cli.NewInvitationsCmd()
|
||||
rootCmd := setFlags(invCmd)
|
||||
|
||||
var page mgsdk.InvitationPage
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
sdkErr errors.SDKError
|
||||
page mgsdk.InvitationPage
|
||||
logType outputLog
|
||||
errLogMessage string
|
||||
}{
|
||||
{
|
||||
desc: "get domain invitations successfully",
|
||||
args: []string{
|
||||
domain.ID,
|
||||
token,
|
||||
},
|
||||
page: mgsdk.InvitationPage{
|
||||
Total: 1,
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Invitations: []mgsdk.Invitation{invitation},
|
||||
},
|
||||
logType: entityLog,
|
||||
},
|
||||
{
|
||||
desc: "get domain invitations with invalid args",
|
||||
args: []string{
|
||||
domain.ID,
|
||||
token,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "get domain invitations 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,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
sdkCall := sdkMock.On("DomainInvitations", mock.Anything, mock.Anything, tc.args[1], tc.args[0]).Return(tc.page, tc.sdkErr)
|
||||
|
||||
out := executeCommand(t, rootCmd, append([]string{domainCmd, 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptUserInvitationCmd(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 user invitation successfully",
|
||||
args: []string{
|
||||
domain.ID,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "accept user invitation with invalid args",
|
||||
args: []string{
|
||||
domain.ID,
|
||||
validToken,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "accept user 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, mock.Anything).Return(tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{userCmd, 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 TestRejectUserInvitationCmd(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 user invitation successfully",
|
||||
args: []string{
|
||||
domain.ID,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "reject user invitation with invalid args",
|
||||
args: []string{
|
||||
domain.ID,
|
||||
validToken,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "reject user 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, mock.Anything).Return(tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{userCmd, 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 TestDeleteDomainInvitationCmd(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 domain invitation successfully",
|
||||
args: []string{
|
||||
user.ID,
|
||||
domain.ID,
|
||||
validToken,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "delete domain invitation with invalid args",
|
||||
args: []string{
|
||||
user.ID,
|
||||
domain.ID,
|
||||
validToken,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "delete domain 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, mock.Anything).Return(tc.sdkErr)
|
||||
out := executeCommand(t, rootCmd, append([]string{domainCmd, 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// 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"
|
||||
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", mock.Anything, 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", mock.Anything, 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/magistrala/cli"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
sdkmocks "github.com/absmach/magistrala/pkg/sdk/mocks"
|
||||
"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{
|
||||
domainID,
|
||||
channel.ID,
|
||||
message,
|
||||
client.Credentials.Secret,
|
||||
},
|
||||
logType: okLog,
|
||||
},
|
||||
{
|
||||
desc: "send message with invalid args",
|
||||
args: []string{
|
||||
domainID,
|
||||
channel.ID,
|
||||
message,
|
||||
client.Credentials.Secret,
|
||||
extraArg,
|
||||
},
|
||||
logType: usageLog,
|
||||
},
|
||||
{
|
||||
desc: "send message with invalid client secret",
|
||||
args: []string{
|
||||
domainID,
|
||||
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", mock.Anything, tc.args[0], tc.args[1], tc.args[2], tc.args[3]).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()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// 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.Topic,
|
||||
"topic",
|
||||
"T",
|
||||
"",
|
||||
"Subscription topic query parameter",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(
|
||||
&cli.Contact,
|
||||
"contact",
|
||||
"C",
|
||||
"",
|
||||
"Subscription contact query parameter",
|
||||
)
|
||||
|
||||
return rootCmd
|
||||
}
|
||||
-595
@@ -1,595 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
smqsdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
smqusers "github.com/absmach/magistrala/users"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
token = "token"
|
||||
refreshToken = "refreshtoken"
|
||||
profile = "profile"
|
||||
resetPasswordRequest = "resetpasswordrequest"
|
||||
resetPassword = "resetpassword"
|
||||
password = "password"
|
||||
search = "search"
|
||||
username = "username"
|
||||
email = "email"
|
||||
role = "role"
|
||||
|
||||
// Usage strings for user operations.
|
||||
usageUserCreate = "cli users create <first_name> <last_name> <email> <username> <password> [user_auth_token]"
|
||||
usageUserGet = "cli users <user_id|all> get <user_auth_token>"
|
||||
usageUserToken = "cli users token <username> <password>"
|
||||
usageUserRefreshToken = "cli users refreshtoken <token>"
|
||||
usageUserUpdate = "cli users <user_id> update <JSON_string> <user_auth_token>"
|
||||
usageUserUpdateTags = "cli users <user_id> update tags <tags> <user_auth_token>"
|
||||
usageUserUpdateUsername = "cli users <user_id> update username <username> <user_auth_token>"
|
||||
usageUserUpdateEmail = "cli users <user_id> update email <email> <user_auth_token>"
|
||||
usageUserUpdateRole = "cli users <user_id> update role <role> <user_auth_token>"
|
||||
usageUserUpdateAll = `cli users <user_id> update <JSON_string|tags|username|email|role> [args...]
|
||||
Available update options:
|
||||
cli users <user_id> update <JSON_string> <user_auth_token>
|
||||
cli users <user_id> update tags <tags> <user_auth_token>
|
||||
cli users <user_id> update username <username> <user_auth_token>
|
||||
cli users <user_id> update email <email> <user_auth_token>
|
||||
cli users <user_id> update role <role> <user_auth_token>`
|
||||
usageUserProfile = "cli users profile <user_auth_token>"
|
||||
usageUserResetPasswordReq = "cli users resetpasswordrequest <email>"
|
||||
usageUserResetPassword = "cli users resetpassword <password> <confpass> <password_request_token>"
|
||||
usageUserPassword = "cli users password <old_password> <password> <user_auth_token>"
|
||||
usageUserEnable = "cli users <user_id> enable <user_auth_token>"
|
||||
usageUserDisable = "cli users <user_id> disable <user_auth_token>"
|
||||
usageUserDelete = "cli users <user_id> delete <user_auth_token>"
|
||||
usageUserSearch = "cli users search <query> <user_auth_token>\nQuery format: username=<value>|firstname=<value>|lastname=<value>|id=<value>[&offset=<value>][&limit=<value>]\nExample: cli users search \"username=john_doe\" <user_auth_token>"
|
||||
usageUserSendVerification = "cli users sendverification <user_auth_token>"
|
||||
usageUserVerifyEmail = "cli users verifyemail <verification_token>"
|
||||
)
|
||||
|
||||
func NewUsersCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "users <user_id|all|create|token|refreshtoken|profile|resetpasswordrequest|resetpassword|password|search|sendverification|verifyemail> [operation] [args...]",
|
||||
Short: "Users management",
|
||||
Long: `Format:
|
||||
users <create|token|refreshtoken|profile|resetpasswordrequest|resetpassword|password|search|sendverification|verifyemail> [args...]
|
||||
users <user_id|all> <operation> [args...]
|
||||
|
||||
Operations (require user_id/all): get, update, enable, disable, delete
|
||||
|
||||
Examples:
|
||||
users create <first_name> <last_name> <email> <username> <password> [user_auth_token]
|
||||
users token <username> <password>
|
||||
users refreshtoken <refresh_token>
|
||||
users profile <user_auth_token>
|
||||
users resetpasswordrequest <email>
|
||||
users resetpassword <password> <confpass> <password_request_token>
|
||||
users password <old_password> <new_password> <user_auth_token>
|
||||
users search "username=john_doe" <user_auth_token>
|
||||
users search "firstname=john&limit=10" <user_auth_token>
|
||||
users sendverification <user_auth_token>
|
||||
users verifyemail <verification_token>
|
||||
users all get <user_auth_token>
|
||||
users <user_id> get <user_auth_token>
|
||||
users <user_id> update <JSON_string> <user_auth_token>
|
||||
users <user_id> update tags <tags> <user_auth_token>
|
||||
users <user_id> update username <username> <user_auth_token>
|
||||
users <user_id> update email <email> <user_auth_token>
|
||||
users <user_id> enable <user_auth_token>
|
||||
users <user_id> disable <user_auth_token>
|
||||
users <user_id> delete <user_auth_token>`,
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
logUsageCmd(*cmd, cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case create:
|
||||
handleUserCreate(cmd, args[1:])
|
||||
return
|
||||
case sendVerification:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserSendVerification)
|
||||
return
|
||||
}
|
||||
handleSendVerification(cmd, args[1])
|
||||
return
|
||||
case verifyEmail:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserVerifyEmail)
|
||||
return
|
||||
}
|
||||
handleVerify(cmd, args[1])
|
||||
return
|
||||
case token:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserToken)
|
||||
return
|
||||
}
|
||||
if len(args) < 3 {
|
||||
logUsageCmd(*cmd, usageUserToken)
|
||||
return
|
||||
}
|
||||
handleUserToken(cmd, args[1], args[2:])
|
||||
return
|
||||
case refreshToken:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserRefreshToken)
|
||||
return
|
||||
}
|
||||
handleUserRefreshToken(cmd, args[1], args[2:])
|
||||
return
|
||||
case profile:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserProfile)
|
||||
return
|
||||
}
|
||||
handleUserProfile(cmd, args[1], args[2:])
|
||||
return
|
||||
case resetPasswordRequest:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserResetPasswordReq)
|
||||
return
|
||||
}
|
||||
handleUserResetPasswordRequest(cmd, args[1], args[2:])
|
||||
return
|
||||
case resetPassword:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserResetPassword)
|
||||
return
|
||||
}
|
||||
if len(args) < 4 {
|
||||
logUsageCmd(*cmd, usageUserResetPassword)
|
||||
return
|
||||
}
|
||||
handleUserResetPassword(cmd, args[1], args[2:])
|
||||
return
|
||||
case password:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserPassword)
|
||||
return
|
||||
}
|
||||
if len(args) < 4 {
|
||||
logUsageCmd(*cmd, usageUserPassword)
|
||||
return
|
||||
}
|
||||
handleUserPassword(cmd, args[1], args[2:])
|
||||
return
|
||||
case search:
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, usageUserSearch)
|
||||
return
|
||||
}
|
||||
if len(args) < 3 {
|
||||
logUsageCmd(*cmd, usageUserSearch)
|
||||
return
|
||||
}
|
||||
handleUserSearch(cmd, args[1], args[2:])
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) < 2 {
|
||||
logUsageCmd(*cmd, "users <user_id|all> <get|update|enable|disable|delete> [args...]")
|
||||
return
|
||||
}
|
||||
|
||||
userParams := args[0]
|
||||
operation := args[1]
|
||||
opArgs := args[2:]
|
||||
|
||||
switch operation {
|
||||
case get:
|
||||
handleUserGet(cmd, userParams, opArgs)
|
||||
case update:
|
||||
handleUserUpdate(cmd, userParams, opArgs)
|
||||
case enable:
|
||||
handleUserEnable(cmd, userParams, opArgs)
|
||||
case disable:
|
||||
handleUserDisable(cmd, userParams, opArgs)
|
||||
case delete:
|
||||
handleUserDelete(cmd, userParams, opArgs)
|
||||
default:
|
||||
logErrorCmd(*cmd, fmt.Errorf("unknown operation: %s", operation))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func handleUserCreate(cmd *cobra.Command, args []string) {
|
||||
if len(args) < 5 || len(args) > 6 {
|
||||
logUsageCmd(*cmd, usageUserCreate)
|
||||
return
|
||||
}
|
||||
if len(args) == 5 {
|
||||
args = append(args, "")
|
||||
}
|
||||
|
||||
user := smqsdk.User{
|
||||
FirstName: args[0],
|
||||
LastName: args[1],
|
||||
Email: args[2],
|
||||
Credentials: smqsdk.Credentials{
|
||||
Username: args[3],
|
||||
Secret: args[4],
|
||||
},
|
||||
Status: smqusers.EnabledStatus.String(),
|
||||
}
|
||||
user, err := sdk.CreateUser(cmd.Context(), user, args[5])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, user)
|
||||
}
|
||||
|
||||
func handleSendVerification(cmd *cobra.Command, token string) {
|
||||
if token == "" {
|
||||
logUsageCmd(*cmd, usageUserToken)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.SendVerification(cmd.Context(), token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, "sent verification successfully")
|
||||
}
|
||||
|
||||
func handleVerify(cmd *cobra.Command, token string) {
|
||||
if token == "" {
|
||||
logUsageCmd(*cmd, usageUserToken)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.VerifyEmail(cmd.Context(), token); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, "verified successfully")
|
||||
}
|
||||
|
||||
func handleUserGet(cmd *cobra.Command, userParams string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageUserGet)
|
||||
return
|
||||
}
|
||||
|
||||
if userParams == all {
|
||||
metadata, err := convertMetadata(Metadata)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
pageMetadata := smqsdk.PageMetadata{
|
||||
Username: Username,
|
||||
Identity: Identity,
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
Metadata: metadata,
|
||||
Status: Status,
|
||||
}
|
||||
|
||||
l, err := sdk.Users(cmd.Context(), pageMetadata, args[0])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, l)
|
||||
return
|
||||
}
|
||||
|
||||
u, err := sdk.User(cmd.Context(), userParams, args[0])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, u)
|
||||
}
|
||||
|
||||
func handleUserUpdate(cmd *cobra.Command, userID string, args []string) {
|
||||
if len(args) < 1 {
|
||||
logUsageCmd(*cmd, usageUserUpdateAll)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) < 2 || len(args) > 3 {
|
||||
if len(args) >= 1 {
|
||||
switch args[0] {
|
||||
case tags:
|
||||
logUsageCmd(*cmd, usageUserUpdateTags)
|
||||
return
|
||||
case username:
|
||||
logUsageCmd(*cmd, usageUserUpdateUsername)
|
||||
return
|
||||
case email:
|
||||
logUsageCmd(*cmd, usageUserUpdateEmail)
|
||||
return
|
||||
case role:
|
||||
logUsageCmd(*cmd, usageUserUpdateRole)
|
||||
return
|
||||
}
|
||||
}
|
||||
logUsageCmd(*cmd, usageUserUpdateAll)
|
||||
return
|
||||
}
|
||||
|
||||
var user smqsdk.User
|
||||
if args[0] == "tags" {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageUserUpdateTags)
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal([]byte(args[1]), &user.Tags); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
user.ID = userID
|
||||
user, err := sdk.UpdateUserTags(cmd.Context(), user, args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, user)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == "email" {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageUserUpdateEmail)
|
||||
return
|
||||
}
|
||||
user.ID = userID
|
||||
user.Email = args[1]
|
||||
user, err := sdk.UpdateUserEmail(cmd.Context(), user, args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, user)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == "username" {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageUserUpdateUsername)
|
||||
return
|
||||
}
|
||||
user.ID = userID
|
||||
user.Credentials.Username = args[1]
|
||||
user, err := sdk.UpdateUsername(cmd.Context(), user, args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, user)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == "role" {
|
||||
if len(args) != 3 {
|
||||
logUsageCmd(*cmd, usageUserUpdateRole)
|
||||
return
|
||||
}
|
||||
user.ID = userID
|
||||
user.Role = args[1]
|
||||
user, err := sdk.UpdateUserRole(cmd.Context(), user, args[2])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logJSONCmd(*cmd, user)
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageUserUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.Unmarshal([]byte(args[0]), &user); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
user.ID = userID
|
||||
user, err := sdk.UpdateUser(cmd.Context(), user, args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, user)
|
||||
}
|
||||
|
||||
func handleUserEnable(cmd *cobra.Command, userID string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageUserEnable)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := sdk.EnableUser(cmd.Context(), userID, args[0])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, user)
|
||||
}
|
||||
|
||||
func handleUserDisable(cmd *cobra.Command, userID string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageUserDisable)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := sdk.DisableUser(cmd.Context(), userID, args[0])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, user)
|
||||
}
|
||||
|
||||
func handleUserDelete(cmd *cobra.Command, userID string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageUserDelete)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.DeleteUser(cmd.Context(), userID, args[0]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleUserToken(cmd *cobra.Command, username string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageUserToken)
|
||||
return
|
||||
}
|
||||
|
||||
loginReq := smqsdk.Login{
|
||||
Username: username,
|
||||
Password: args[0],
|
||||
}
|
||||
|
||||
token, err := sdk.CreateToken(cmd.Context(), loginReq)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, token)
|
||||
}
|
||||
|
||||
func handleUserRefreshToken(cmd *cobra.Command, refreshToken string, args []string) {
|
||||
if len(args) != 0 {
|
||||
logUsageCmd(*cmd, usageUserRefreshToken)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := sdk.RefreshToken(cmd.Context(), refreshToken)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, token)
|
||||
}
|
||||
|
||||
func handleUserProfile(cmd *cobra.Command, token string, args []string) {
|
||||
if len(args) != 0 {
|
||||
logUsageCmd(*cmd, usageUserProfile)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := sdk.UserProfile(cmd.Context(), token)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, user)
|
||||
}
|
||||
|
||||
func handleUserResetPasswordRequest(cmd *cobra.Command, email string, args []string) {
|
||||
if len(args) != 0 {
|
||||
logUsageCmd(*cmd, usageUserResetPasswordReq)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.ResetPasswordRequest(cmd.Context(), email); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleUserResetPassword(cmd *cobra.Command, password string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageUserResetPassword)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.ResetPassword(cmd.Context(), password, args[0], args[1]); err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logOKCmd(*cmd)
|
||||
}
|
||||
|
||||
func handleUserPassword(cmd *cobra.Command, oldPassword string, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsageCmd(*cmd, usageUserPassword)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := sdk.UpdatePassword(cmd.Context(), oldPassword, args[0], args[1])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, user)
|
||||
}
|
||||
|
||||
func handleUserSearch(cmd *cobra.Command, query string, args []string) {
|
||||
if len(args) != 1 {
|
||||
logUsageCmd(*cmd, usageUserSearch)
|
||||
return
|
||||
}
|
||||
|
||||
values, err := url.ParseQuery(query)
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, fmt.Errorf("failed to parse query: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
pm := smqsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
ID: values.Get("id"),
|
||||
Username: values.Get("username"),
|
||||
FirstName: values.Get("firstname"),
|
||||
LastName: values.Get("lastname"),
|
||||
}
|
||||
|
||||
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(cmd.Context(), pm, args[0])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSONCmd(*cmd, users)
|
||||
}
|
||||
-1406
File diff suppressed because it is too large
Load Diff
@@ -8,9 +8,6 @@ require (
|
||||
github.com/absmach/callhome v0.18.2
|
||||
github.com/absmach/fluxmq v0.30.0
|
||||
github.com/absmach/senml v1.0.8
|
||||
github.com/authzed/authzed-go v1.10.0
|
||||
github.com/authzed/grpcutil v0.0.0-20260105210157-e237581949c2
|
||||
github.com/authzed/spicedb v1.54.0
|
||||
github.com/caarlos0/env/v10 v10.0.0
|
||||
github.com/caarlos0/env/v11 v11.4.1
|
||||
github.com/dgraph-io/ristretto/v2 v2.4.0
|
||||
@@ -30,7 +27,6 @@ require (
|
||||
github.com/jackc/pgx/v5 v5.10.0
|
||||
github.com/jmoiron/sqlx v1.4.0
|
||||
github.com/lestrrat-go/jwx/v2 v2.1.6
|
||||
github.com/lib/pq v1.12.3
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nats-io/nats.go v1.52.0
|
||||
github.com/oklog/ulid/v2 v2.1.1
|
||||
@@ -57,10 +53,8 @@ require (
|
||||
go.opentelemetry.io/otel/sdk v1.44.0
|
||||
go.opentelemetry.io/otel/trace v1.44.0
|
||||
golang.org/x/crypto v0.53.0
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
golang.org/x/sync v0.21.0
|
||||
gonum.org/v1/gonum v0.17.0
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad
|
||||
google.golang.org/grpc v1.81.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
@@ -69,28 +63,22 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/lib/pq v1.12.3 // indirect
|
||||
github.com/smarty/assertions v1.16.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.8.1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 // indirect
|
||||
buf.build/go/protovalidate v1.2.0 // indirect
|
||||
cel.dev/expr v0.25.2 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||
connectrpc.com/connect v1.20.0
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||
github.com/authzed/cel-go v0.20.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/ccoveille/go-safecast/v2 v2.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/containerd/continuity v0.5.0 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
@@ -103,12 +91,9 @@ require (
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dsnet/golib/memfile v1.0.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect
|
||||
github.com/felixge/httpsnoop v1.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.2 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
@@ -118,9 +103,7 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.10.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||
github.com/goccy/go-json v0.10.6 // indirect
|
||||
github.com/google/cel-go v0.28.1 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
@@ -135,7 +118,6 @@ require (
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jzelinskie/stringz v0.0.3 // indirect
|
||||
github.com/klauspost/compress v1.18.6 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
@@ -156,17 +138,15 @@ require (
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runc v1.2.8 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.4.0
|
||||
github.com/pelletier/go-toml/v2 v2.3.1 // indirect
|
||||
github.com/pion/dtls/v3 v3.1.4 // indirect
|
||||
github.com/pion/logging v0.2.4 // indirect
|
||||
github.com/pion/transport/v4 v4.0.2 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240917153116-6f2963f01587 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.68.1 // indirect
|
||||
github.com/prometheus/procfs v0.20.1 // indirect
|
||||
github.com/rabbitmq/amqp091-go v1.12.0
|
||||
github.com/rs/zerolog v1.35.1 // indirect
|
||||
github.com/rabbitmq/amqp091-go v1.11.0
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.12.0 // indirect
|
||||
github.com/segmentio/asm v1.2.1 // indirect
|
||||
@@ -174,7 +154,6 @@ require (
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/stoewer/go-strcase v1.3.1 // indirect
|
||||
github.com/stretchr/objx v0.5.3 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 h1:s6hzCXtND/ICdGPTMGk7C+/BFlr2Jg5GyH0NKf4XGXg=
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM=
|
||||
buf.build/go/protovalidate v1.2.0 h1:DQVrUWkmGTBij+kOYv/x2LLxwcLaGKMdzShj1/6/3H0=
|
||||
buf.build/go/protovalidate v1.2.0/go.mod h1:7rYiQEhqvAipoazpVNBBH2S2f8bjG4huMVy1V2Yofn4=
|
||||
cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs=
|
||||
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
|
||||
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
|
||||
connectrpc.com/otelconnect v0.9.0 h1:NggB3pzRC3pukQWaYbRHJulxuXvmCKCKkQ9hbrHAWoA=
|
||||
@@ -42,26 +33,13 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||
github.com/authzed/authzed-go v1.10.0 h1:GUPzYFnStk1PIBZOkQzqcYA3iHaOlVYVl1UnHIRofKU=
|
||||
github.com/authzed/authzed-go v1.10.0/go.mod h1:2DL7pg4iqMltwWOSw+wvbEzAK7uRt3545+bkcGYD8D8=
|
||||
github.com/authzed/cel-go v0.20.2 h1:GlmLecGry7Z8HU0k+hmaHHUV05ZHrsFxduXHtIePvck=
|
||||
github.com/authzed/cel-go v0.20.2/go.mod h1:pJHVFWbqUHV1J+klQoZubdKswlbxcsbojda3mye9kiU=
|
||||
github.com/authzed/grpcutil v0.0.0-20260105210157-e237581949c2 h1:ymPD1ugBsXVUpLIG/lnRn1ndgOrsrki/0ZX7uP/S1GI=
|
||||
github.com/authzed/grpcutil v0.0.0-20260105210157-e237581949c2/go.mod h1:FLssYBs1DrwuItfI411kzqcV8QSqGb/B7PC6snNhjvU=
|
||||
github.com/authzed/spicedb v1.54.0 h1:XQiFm/G/YpQktYmcLCVrQRWkkLpAjUBZa1SBoEbmd0A=
|
||||
github.com/authzed/spicedb v1.54.0/go.mod h1:9McK3CNkb831IzWZ1pVsswVoqjZTyDPy3fUF7GcvvOY=
|
||||
github.com/aws/aws-sdk-go v1.34.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.40.45 h1:QN1nsY27ssD/JmW4s83qmSb+uL6DG4GmCDzjmJB4xUI=
|
||||
github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=
|
||||
github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
@@ -72,15 +50,10 @@ github.com/caarlos0/env/v11 v11.4.1 h1:fYwH0sWEsBSMPG7t4e/PEfTFzrWrpjyygXyUnWiSw
|
||||
github.com/caarlos0/env/v11 v11.4.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
|
||||
github.com/cbroglie/mustache v1.0.1 h1:ivMg8MguXq/rrz2eu3tw6g3b16+PQhoTn6EZAhst2mw=
|
||||
github.com/cbroglie/mustache v1.0.1/go.mod h1:R/RUa+SobQ14qkP4jtx5Vke5sDytONDQXNLPY/PO69g=
|
||||
github.com/ccoveille/go-safecast/v2 v2.0.1 h1:2+mIu3gXtwmWelBia2kkxfB8eP4orTHDH7ClSlWkd6I=
|
||||
github.com/ccoveille/go-safecast/v2 v2.0.1/go.mod h1:JIYA4CAR33blIDuE6fSwCp2sz1oOBahXnvmdBhOAABs=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s=
|
||||
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
@@ -88,8 +61,6 @@ github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+Yv
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/containerd/continuity v0.5.0 h1:7a85HZpCSs+1Zps0Ee3DPSuAWY+0SJM1JNM51nlEVDg=
|
||||
github.com/containerd/continuity v0.5.0/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
|
||||
@@ -130,14 +101,6 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2ISgCl2W7nE=
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
|
||||
@@ -154,8 +117,6 @@ github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh
|
||||
github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-chi/chi/v5 v5.3.0 h1:halUjDxhshgXHMrao5bB8eNBXo/rnzwr8m5m36glehM=
|
||||
github.com/go-chi/chi/v5 v5.3.0/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
|
||||
@@ -192,13 +153,9 @@ github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
|
||||
github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
|
||||
github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
@@ -208,9 +165,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/cel-go v0.28.1 h1:YWIwi77J4xIsYUwAF/iIuS6haffzIHS8yWI8glSbLWM=
|
||||
github.com/google/cel-go v0.28.1/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@@ -232,8 +186,6 @@ github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25d
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@@ -332,9 +284,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/jzelinskie/stringz v0.0.3 h1:0GhG3lVMYrYtIvRbxvQI6zqRTT1P1xyQlpa0FhfUXas=
|
||||
github.com/jzelinskie/stringz v0.0.3/go.mod h1:hHYbgxJuNLRw91CmpuFsYEOyQqpDVFg8pvEh23vy4P0=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
|
||||
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
@@ -430,7 +379,6 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw
|
||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||
github.com/opencontainers/runc v1.2.8 h1:RnEICeDReapbZ5lZEgHvj7E9Q3Eex9toYmaGBsbvU5Q=
|
||||
github.com/opencontainers/runc v1.2.8/go.mod h1:cC0YkmZcuvr+rtBZ6T7NBoVbMGNAdLa/21vIElJDOzI=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw=
|
||||
github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE=
|
||||
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
||||
@@ -447,8 +395,6 @@ github.com/pion/transport/v4 v4.0.2/go.mod h1:06hFI+jCFcok2X2MekVufNZ/uzNZXivGBP
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240917153116-6f2963f01587 h1:xzZOeCMQLA/W198ZkdVdt4EKFKJtS26B773zNU377ZY=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240917153116-6f2963f01587/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/plgd-dev/go-coap/v3 v3.5.1 h1:jRJXJAIQ2/YmjNycM+P+oabrqjpWQGl2HHuImvF3OJ8=
|
||||
github.com/plgd-dev/go-coap/v3 v3.5.1/go.mod h1:kgdxil4mi3Bi9s5av/NbQeVwRJ+8N6zGHFEPy7qTRWI=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -464,7 +410,6 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
@@ -483,16 +428,12 @@ github.com/rabbitmq/amqp091-go v1.12.0 h1:V0v14Iqfs+MwHWihJt/nGS5Ulu0vw572b2Co3m
|
||||
github.com/rabbitmq/amqp091-go v1.12.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
|
||||
github.com/redis/go-redis/v9 v9.20.1 h1:sfCU6A8P3dXbKyWes02uxA2baehGux9dZHfEKtsTB1w=
|
||||
github.com/redis/go-redis/v9 v9.20.1/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA=
|
||||
github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8=
|
||||
github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
|
||||
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
|
||||
github.com/rubenv/sql-migrate v1.8.1 h1:EPNwCvjAowHI3TnZ+4fQu3a915OpnQoPAjTXCGOy2U0=
|
||||
github.com/rubenv/sql-migrate v1.8.1/go.mod h1:BTIKBORjzyxZDS6dzoiw6eAFYJ1iNlGAtjn4LGeVjS8=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -534,8 +475,6 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||
github.com/sqids/sqids-go v0.4.1 h1:eQKYzmAZbLlRwHeHYPF35QhgxwZHLnlmVj9AkIj/rrw=
|
||||
github.com/sqids/sqids-go v0.4.1/go.mod h1:EMwHuPQgSNFS0A49jESTfIQS+066XQTVhukrzEPScl8=
|
||||
github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs=
|
||||
github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
@@ -576,8 +515,6 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 h1:noHsffKZsNfU38DwcXWEPldrTjIZ8FPNKx8mYMGnqjs=
|
||||
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7/go.mod h1:bbMEM6aU1WDF1ErA5YJ0p91652pGv140gGw4Ww3RGp8=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
|
||||
github.com/yuin/gopher-lua v1.1.2 h1:yF/FjE3hD65tBbt0VXLE13HWS9h34fdzJmrWRXwobGA=
|
||||
@@ -611,21 +548,17 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
@@ -645,33 +578,23 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
|
||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M=
|
||||
golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
@@ -679,22 +602,16 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -711,14 +628,12 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -748,20 +663,14 @@ golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -772,20 +681,11 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260610212136-7ab31c22f7ad h1:3iLyITS/sySRwbUKoC7ogfj2Yr1Cjs0pfaRKj5U5HEw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260610212136-7ab31c22f7ad/go.mod h1:KdNqO+rCIWgFumrNBSEDlDNrkrQnpkax7Tv1WxNY8V4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad h1:45WmJvIV6C2+O/jjLkPUH+F3aOj/1miDoU2DD0+NWbg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
|
||||
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
@@ -815,18 +715,14 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/pkg/connections"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/roles"
|
||||
rconsumer "github.com/absmach/magistrala/pkg/roles/rolemanager/events/consumer"
|
||||
)
|
||||
|
||||
const layout = "2006-01-02T15:04:05.999999Z"
|
||||
|
||||
var (
|
||||
errDecodeCreateChannelEvent = errors.New("failed to decode channel create event")
|
||||
errDecodeUpdateChannelEvent = errors.New("failed to decode channel update event")
|
||||
errDecodeChangeStatusChannelEvent = errors.New("failed to decode channel change status event")
|
||||
errDecodeRemoveChannelEvent = errors.New("failed to decode channel remove event")
|
||||
errDecodeSetParentGroupEvent = errors.New("failed to decode channel set parent event")
|
||||
errDecodeRemoveParentGroupEvent = errors.New("failed to decode channel remove parent event")
|
||||
errDecodeConnectEvent = errors.New("failed to decode channel connect event")
|
||||
errDeocodeDisconnectEvent = errors.New("failed to decode channel disconnect event")
|
||||
|
||||
errID = errors.New("missing or invalid 'id'")
|
||||
errDomain = errors.New("missing or invalid 'domain'")
|
||||
errStatus = errors.New("missing or invalid 'status'")
|
||||
errTags = errors.New("invalid 'tags'")
|
||||
errConvertStatus = errors.New("failed to convert status")
|
||||
errChannelIDs = errors.New("missing or invalid 'channel_ids' in connection")
|
||||
errClientIDs = errors.New("missing or invalid 'client_ids' in connection")
|
||||
errConnType = errors.New("missing or invalid 'type' in connection")
|
||||
errCreatedAt = errors.New("failed to parse 'created_at' time")
|
||||
errUpdatedAt = errors.New("failed to parse 'updated_at' time")
|
||||
)
|
||||
|
||||
func ToChannel(data map[string]any) (channels.Channel, error) {
|
||||
var c channels.Channel
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errID
|
||||
}
|
||||
c.ID = id
|
||||
|
||||
dom, ok := data["domain"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errDomain
|
||||
}
|
||||
c.Domain = dom
|
||||
|
||||
st, ok := data["status"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errStatus
|
||||
}
|
||||
status, err := channels.ToStatus(st)
|
||||
if err != nil {
|
||||
return channels.Channel{}, errConvertStatus
|
||||
}
|
||||
c.Status = status
|
||||
|
||||
cat, ok := data["created_at"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errCreatedAt
|
||||
}
|
||||
ct, err := time.Parse(layout, cat)
|
||||
if err != nil {
|
||||
return channels.Channel{}, errors.Wrap(errCreatedAt, err)
|
||||
}
|
||||
c.CreatedAt = ct
|
||||
|
||||
// Following fields of channels are allowed to be empty.
|
||||
name, ok := data["name"].(string)
|
||||
if ok {
|
||||
c.Name = name
|
||||
}
|
||||
|
||||
parent, ok := data["parent_group_id"].(string)
|
||||
if ok {
|
||||
c.ParentGroup = parent
|
||||
}
|
||||
|
||||
itags, ok := data["tags"].([]any)
|
||||
if ok {
|
||||
tags, err := rconsumer.ToStrings(itags)
|
||||
if err != nil {
|
||||
return channels.Channel{}, errors.Wrap(errTags, err)
|
||||
}
|
||||
c.Tags = tags
|
||||
}
|
||||
|
||||
meta, ok := data["metadata"].(map[string]any)
|
||||
if ok {
|
||||
c.Metadata = meta
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
c.UpdatedBy = uby
|
||||
}
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return channels.Channel{}, errors.Wrap(errUpdatedAt, err)
|
||||
}
|
||||
c.UpdatedAt = ut
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func ToConnections(data map[string]any) ([]channels.Connection, error) {
|
||||
var connTypes []connections.ConnType
|
||||
domain, ok := data["domain"].(string)
|
||||
if !ok {
|
||||
return nil, errDomain
|
||||
}
|
||||
|
||||
ityp, ok := data["types"].([]any)
|
||||
if !ok {
|
||||
return nil, errConnType
|
||||
}
|
||||
typs, err := rconsumer.ToStrings(ityp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errConnType, err)
|
||||
}
|
||||
for _, typ := range typs {
|
||||
connType, err := connections.ParseConnType(typ)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errConnType, err)
|
||||
}
|
||||
connTypes = append(connTypes, connType)
|
||||
}
|
||||
|
||||
ichanIDs, ok := data["channel_ids"].([]any)
|
||||
if !ok {
|
||||
return []channels.Connection{}, errChannelIDs
|
||||
}
|
||||
channelIDs, err := rconsumer.ToStrings(ichanIDs)
|
||||
if err != nil {
|
||||
return []channels.Connection{}, errors.Wrap(errChannelIDs, err)
|
||||
}
|
||||
|
||||
iclIDs, ok := data["client_ids"].([]any)
|
||||
if !ok {
|
||||
return []channels.Connection{}, errClientIDs
|
||||
}
|
||||
clientIDs, err := rconsumer.ToStrings(iclIDs)
|
||||
if err != nil {
|
||||
return []channels.Connection{}, errors.Wrap(errClientIDs, err)
|
||||
}
|
||||
|
||||
var conns []channels.Connection
|
||||
for _, chanID := range channelIDs {
|
||||
for _, clientID := range clientIDs {
|
||||
for _, connType := range connTypes {
|
||||
conns = append(conns, channels.Connection{
|
||||
ChannelID: chanID,
|
||||
ClientID: clientID,
|
||||
Type: connType,
|
||||
DomainID: domain,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conns, nil
|
||||
}
|
||||
|
||||
func decodeCreateChannelEvent(data map[string]any) (channels.Channel, []roles.RoleProvision, error) {
|
||||
c, err := ToChannel(data)
|
||||
if err != nil {
|
||||
return channels.Channel{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateChannelEvent, err)
|
||||
}
|
||||
irps, ok := data["roles_provisioned"].([]any)
|
||||
if !ok {
|
||||
return channels.Channel{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateChannelEvent, errors.New("missing or invalid 'roles_provisioned'"))
|
||||
}
|
||||
rps, err := rconsumer.ToRoleProvisions(irps)
|
||||
if err != nil {
|
||||
return channels.Channel{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateChannelEvent, err)
|
||||
}
|
||||
|
||||
return c, rps, nil
|
||||
}
|
||||
|
||||
func decodeUpdateChannelEvent(data map[string]any) (channels.Channel, error) {
|
||||
c, err := ToChannel(data)
|
||||
if err != nil {
|
||||
return channels.Channel{}, errors.Wrap(errDecodeUpdateChannelEvent, err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func decodeChangeStatusChannelEvent(data map[string]any) (channels.Channel, error) {
|
||||
c, err := ToChannelStatus(data)
|
||||
if err != nil {
|
||||
return channels.Channel{}, errors.Wrap(errDecodeChangeStatusChannelEvent, err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func ToChannelStatus(data map[string]any) (channels.Channel, error) {
|
||||
var c channels.Channel
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errID
|
||||
}
|
||||
c.ID = id
|
||||
|
||||
stat, ok := data["status"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errStatus
|
||||
}
|
||||
st, err := channels.ToStatus(stat)
|
||||
if err != nil {
|
||||
return channels.Channel{}, errors.Wrap(errConvertStatus, err)
|
||||
}
|
||||
c.Status = st
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return channels.Channel{}, errors.Wrap(errUpdatedAt, err)
|
||||
}
|
||||
c.UpdatedAt = ut
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
c.UpdatedBy = uby
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func decodeRemoveChannelEvent(data map[string]any) (channels.Channel, error) {
|
||||
var c channels.Channel
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errors.Wrap(errDecodeRemoveChannelEvent, errID)
|
||||
}
|
||||
c.ID = id
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func decodeConnectEvent(data map[string]any) ([]channels.Connection, error) {
|
||||
conns, err := ToConnections(data)
|
||||
if err != nil {
|
||||
return []channels.Connection{}, errors.Wrap(errDecodeConnectEvent, err)
|
||||
}
|
||||
|
||||
return conns, nil
|
||||
}
|
||||
|
||||
func decodeDisconnectEvent(data map[string]any) ([]channels.Connection, error) {
|
||||
conns, err := ToConnections(data)
|
||||
if err != nil {
|
||||
return []channels.Connection{}, errors.Wrap(errDeocodeDisconnectEvent, err)
|
||||
}
|
||||
|
||||
return conns, nil
|
||||
}
|
||||
|
||||
func decodeSetParentGroupEvent(data map[string]any) (channels.Channel, error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errors.Wrap(errDecodeSetParentGroupEvent, errID)
|
||||
}
|
||||
|
||||
parent, ok := data["parent_group_id"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errors.Wrap(errDecodeSetParentGroupEvent, errID)
|
||||
}
|
||||
|
||||
return channels.Channel{
|
||||
ID: id,
|
||||
ParentGroup: parent,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeRemoveParentGroupEvent(data map[string]any) (channels.Channel, error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return channels.Channel{}, errors.Wrap(errDecodeRemoveParentGroupEvent, errID)
|
||||
}
|
||||
|
||||
return channels.Channel{
|
||||
ID: id,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package consumer contains events consumer for events
|
||||
// published by channels service.
|
||||
package consumer
|
||||
@@ -1,220 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/events"
|
||||
"github.com/absmach/magistrala/pkg/events/store"
|
||||
rconsumer "github.com/absmach/magistrala/pkg/roles/rolemanager/events/consumer"
|
||||
)
|
||||
|
||||
const (
|
||||
stream = "events.magistrala.channel.*"
|
||||
|
||||
create = "channel.create"
|
||||
update = "channel.update"
|
||||
updateTags = "channel.update_tags"
|
||||
enable = "channel.enable"
|
||||
disable = "channel.disable"
|
||||
remove = "channel.remove"
|
||||
connect = "channel.connect"
|
||||
disconnect = "channel.disconnect"
|
||||
setParentGroup = "channel.set_parent"
|
||||
removeParentGroup = "channel.remove_parent"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoOperationKey = errors.New("operation key is not found in event message")
|
||||
errCreateChannelEvent = errors.New("failed to consume channel create event")
|
||||
errUpdateChannelEvent = errors.New("failed to consume channel update event")
|
||||
errChangeStatusChannelEvent = errors.New("failed to consume channel change status event")
|
||||
errRemoveChannelEvent = errors.New("failed to consume channel remove event")
|
||||
errConnectEvent = errors.New("failed to consume channel connect event")
|
||||
errDisconnectEvent = errors.New("failed to consume channel disconnect event")
|
||||
errSetParentGroupEvent = errors.New("failed to consume channel add parent group event")
|
||||
errRemoveParentGroupEvent = errors.New("failed to consume channel remove parent group event")
|
||||
)
|
||||
|
||||
type eventHandler struct {
|
||||
repo channels.Repository
|
||||
rolesEventHandler rconsumer.EventHandler
|
||||
}
|
||||
|
||||
func ChannelsEventsSubscribe(ctx context.Context, repo channels.Repository, esURL, esConsumerName string, logger *slog.Logger) error {
|
||||
subscriber, err := store.NewSubscriber(ctx, esURL, "channels-es-sub", logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subConfig := events.SubscriberConfig{
|
||||
Stream: stream,
|
||||
Consumer: esConsumerName,
|
||||
Handler: NewEventHandler(repo),
|
||||
Ordered: true,
|
||||
}
|
||||
return subscriber.Subscribe(ctx, subConfig)
|
||||
}
|
||||
|
||||
// NewEventHandler returns new event store handler.
|
||||
func NewEventHandler(repo channels.Repository) events.EventHandler {
|
||||
reh := rconsumer.NewEventHandler("channel", repo)
|
||||
return &eventHandler{
|
||||
repo: repo,
|
||||
rolesEventHandler: reh,
|
||||
}
|
||||
}
|
||||
|
||||
func (es *eventHandler) Handle(ctx context.Context, event events.Event) error {
|
||||
msg, err := event.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, ok := msg["operation"]
|
||||
|
||||
if !ok {
|
||||
return errNoOperationKey
|
||||
}
|
||||
switch op {
|
||||
case create:
|
||||
return es.createChannelHandler(ctx, msg)
|
||||
case update:
|
||||
return es.updateChannelHandler(ctx, msg)
|
||||
case updateTags:
|
||||
return es.updateChannelTagsHandler(ctx, msg)
|
||||
case enable, disable:
|
||||
return es.changeStatusChannelHandler(ctx, msg)
|
||||
case remove:
|
||||
return es.removeChannelHandler(ctx, msg)
|
||||
case connect:
|
||||
return es.connectChannelHandler(ctx, msg)
|
||||
case disconnect:
|
||||
return es.disconnectChannelHandler(ctx, msg)
|
||||
case setParentGroup:
|
||||
return es.setParentGroupHandler(ctx, msg)
|
||||
case removeParentGroup:
|
||||
return es.removeParentGroupHandler(ctx, msg)
|
||||
}
|
||||
|
||||
return es.rolesEventHandler.Handle(ctx, op, msg)
|
||||
}
|
||||
|
||||
func (es *eventHandler) createChannelHandler(ctx context.Context, data map[string]any) error {
|
||||
c, rps, err := decodeCreateChannelEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errCreateChannelEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.Save(ctx, c); err != nil {
|
||||
return errors.Wrap(errCreateChannelEvent, err)
|
||||
}
|
||||
if _, err := es.repo.AddRoles(ctx, rps); err != nil {
|
||||
return errors.Wrap(errCreateChannelEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) updateChannelHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeUpdateChannelEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errUpdateChannelEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.Update(ctx, c); err != nil {
|
||||
return errors.Wrap(errUpdateChannelEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) updateChannelTagsHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeUpdateChannelEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errUpdateChannelEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.UpdateTags(ctx, c); err != nil {
|
||||
return errors.Wrap(errUpdateChannelEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) changeStatusChannelHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeChangeStatusChannelEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errChangeStatusChannelEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.ChangeStatus(ctx, c); err != nil {
|
||||
return errors.Wrap(errChangeStatusChannelEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) removeChannelHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeRemoveChannelEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveChannelEvent, err)
|
||||
}
|
||||
|
||||
if err := es.repo.Remove(ctx, c.ID); err != nil {
|
||||
return errors.Wrap(errRemoveChannelEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) connectChannelHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeConnectEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errConnectEvent, err)
|
||||
}
|
||||
if err := es.repo.AddConnections(ctx, c); err != nil {
|
||||
return errors.Wrap(errConnectEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) disconnectChannelHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeDisconnectEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errDisconnectEvent, err)
|
||||
}
|
||||
if err := es.repo.RemoveConnections(ctx, c); err != nil {
|
||||
return errors.Wrap(errDisconnectEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) setParentGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeSetParentGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errSetParentGroupEvent, err)
|
||||
}
|
||||
if err := es.repo.SetParentGroup(ctx, c); err != nil {
|
||||
return errors.Wrap(errSetParentGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) removeParentGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeRemoveParentGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveParentGroupEvent, err)
|
||||
}
|
||||
if err := es.repo.RemoveParentGroup(ctx, c); err != nil {
|
||||
return errors.Wrap(errRemoveParentGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/clients"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/roles"
|
||||
rconsumer "github.com/absmach/magistrala/pkg/roles/rolemanager/events/consumer"
|
||||
)
|
||||
|
||||
const layout = "2006-01-02T15:04:05.999999Z"
|
||||
|
||||
var (
|
||||
errDecodeCreateClientEvent = errors.New("failed to decode client create event")
|
||||
errDecodeUpdateClientEvent = errors.New("failed to decode client update event")
|
||||
errDecodeChangeStatusClientEvent = errors.New("failed to decode client change status event")
|
||||
errDecodeRemoveClientEvent = errors.New("failed to decode client remove event")
|
||||
errDecodeSetParentGroupEvent = errors.New("failed to decode client set parent event")
|
||||
errDecodeRemoveParentGroupEvent = errors.New("failed to decode client remove parent event")
|
||||
|
||||
errID = errors.New("missing or invalid 'id'")
|
||||
errDomain = errors.New("missing or invalid 'domain'")
|
||||
errStatus = errors.New("missing or invalid 'status'")
|
||||
errTags = errors.New("invalid 'tags'")
|
||||
errConvertStatus = errors.New("failed to convert status")
|
||||
errCreatedAt = errors.New("failed to parse 'created_at' time")
|
||||
errUpdatedAt = errors.New("failed to parse 'updated_at' time")
|
||||
)
|
||||
|
||||
func ToClient(data map[string]any) (clients.Client, error) {
|
||||
var c clients.Client
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errID
|
||||
}
|
||||
c.ID = id
|
||||
|
||||
dom, ok := data["domain"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errDomain
|
||||
}
|
||||
c.Domain = dom
|
||||
|
||||
st, ok := data["status"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errStatus
|
||||
}
|
||||
status, err := clients.ToStatus(st)
|
||||
if err != nil {
|
||||
return clients.Client{}, errConvertStatus
|
||||
}
|
||||
c.Status = status
|
||||
|
||||
cat, ok := data["created_at"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errCreatedAt
|
||||
}
|
||||
ct, err := time.Parse(layout, cat)
|
||||
if err != nil {
|
||||
return clients.Client{}, errors.Wrap(errCreatedAt, err)
|
||||
}
|
||||
c.CreatedAt = ct
|
||||
|
||||
// Following fields of clients are allowed to be empty.
|
||||
name, ok := data["name"].(string)
|
||||
if ok {
|
||||
c.Name = name
|
||||
}
|
||||
|
||||
identity, ok := data["identity"].(string)
|
||||
if ok {
|
||||
c.Identity = identity
|
||||
}
|
||||
|
||||
parent, ok := data["parent_group_id"].(string)
|
||||
if ok {
|
||||
c.ParentGroup = parent
|
||||
}
|
||||
|
||||
itags, ok := data["tags"].([]any)
|
||||
if ok {
|
||||
tags, err := rconsumer.ToStrings(itags)
|
||||
if err != nil {
|
||||
return clients.Client{}, errors.Wrap(errTags, err)
|
||||
}
|
||||
c.Tags = tags
|
||||
}
|
||||
|
||||
meta, ok := data["metadata"].(map[string]any)
|
||||
if ok {
|
||||
c.Metadata = meta
|
||||
}
|
||||
|
||||
pmeta, ok := data["private_metadata"].(map[string]any)
|
||||
if ok {
|
||||
c.PrivateMetadata = pmeta
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
c.UpdatedBy = uby
|
||||
}
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return clients.Client{}, errors.Wrap(errUpdatedAt, err)
|
||||
}
|
||||
c.UpdatedAt = ut
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func decodeCreateClientEvent(data map[string]any) (clients.Client, []roles.RoleProvision, error) {
|
||||
c, err := ToClient(data)
|
||||
if err != nil {
|
||||
return clients.Client{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateClientEvent, err)
|
||||
}
|
||||
irps, ok := data["roles_provisioned"].([]any)
|
||||
if !ok {
|
||||
return clients.Client{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateClientEvent, errors.New("missing or invalid 'roles_provisioned'"))
|
||||
}
|
||||
rps, err := rconsumer.ToRoleProvisions(irps)
|
||||
if err != nil {
|
||||
return clients.Client{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateClientEvent, err)
|
||||
}
|
||||
|
||||
return c, rps, nil
|
||||
}
|
||||
|
||||
func decodeUpdateClientEvent(data map[string]any) (clients.Client, error) {
|
||||
c, err := ToClient(data)
|
||||
if err != nil {
|
||||
return clients.Client{}, errors.Wrap(errDecodeUpdateClientEvent, err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func decodeChangeStatusClientEvent(data map[string]any) (clients.Client, error) {
|
||||
c, err := ToClientStatus(data)
|
||||
if err != nil {
|
||||
return clients.Client{}, errors.Wrap(errDecodeChangeStatusClientEvent, err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func ToClientStatus(data map[string]any) (clients.Client, error) {
|
||||
var c clients.Client
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errID
|
||||
}
|
||||
c.ID = id
|
||||
|
||||
stat, ok := data["status"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errStatus
|
||||
}
|
||||
st, err := clients.ToStatus(stat)
|
||||
if err != nil {
|
||||
return clients.Client{}, errors.Wrap(errConvertStatus, err)
|
||||
}
|
||||
c.Status = st
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return clients.Client{}, errors.Wrap(errUpdatedAt, err)
|
||||
}
|
||||
c.UpdatedAt = ut
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
c.UpdatedBy = uby
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func decodeRemoveClientEvent(data map[string]any) (clients.Client, error) {
|
||||
var c clients.Client
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errors.Wrap(errDecodeRemoveClientEvent, errID)
|
||||
}
|
||||
c.ID = id
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func decodeSetParentGroupEvent(data map[string]any) (clients.Client, error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errors.Wrap(errDecodeSetParentGroupEvent, errID)
|
||||
}
|
||||
|
||||
parent, ok := data["parent_group_id"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errors.Wrap(errDecodeSetParentGroupEvent, errID)
|
||||
}
|
||||
|
||||
return clients.Client{
|
||||
ID: id,
|
||||
ParentGroup: parent,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeRemoveParentGroupEvent(data map[string]any) (clients.Client, error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return clients.Client{}, errors.Wrap(errDecodeRemoveParentGroupEvent, errID)
|
||||
}
|
||||
|
||||
return clients.Client{
|
||||
ID: id,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package consumer contains events consumer for events
|
||||
// published by clients service.
|
||||
package consumer
|
||||
@@ -1,190 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/absmach/magistrala/clients"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/events"
|
||||
"github.com/absmach/magistrala/pkg/events/store"
|
||||
rconsumer "github.com/absmach/magistrala/pkg/roles/rolemanager/events/consumer"
|
||||
)
|
||||
|
||||
const (
|
||||
stream = "events.magistrala.client.*"
|
||||
|
||||
create = "client.create"
|
||||
update = "client.update"
|
||||
updateTags = "client.update_tags"
|
||||
enable = "client.enable"
|
||||
disable = "client.disable"
|
||||
remove = "client.remove"
|
||||
setParentGroup = "client.set_parent"
|
||||
removeParentGroup = "client.remove_parent"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoOperationKey = errors.New("operation key is not found in event message")
|
||||
errCreateClientEvent = errors.New("failed to consume client create event")
|
||||
errUpdateClientEvent = errors.New("failed to consume client update event")
|
||||
errChangeStatusClientEvent = errors.New("failed to consume client change status event")
|
||||
errRemoveClientEvent = errors.New("failed to consume client remove event")
|
||||
errSetParentGroupEvent = errors.New("failed to consume client add parent group event")
|
||||
errRemoveParentGroupEvent = errors.New("failed to consume client remove parent group event")
|
||||
)
|
||||
|
||||
type eventHandler struct {
|
||||
repo clients.Repository
|
||||
rolesEventHandler rconsumer.EventHandler
|
||||
}
|
||||
|
||||
func ClientsEventsSubscribe(ctx context.Context, repo clients.Repository, esURL, esConsumerName string, logger *slog.Logger) error {
|
||||
subscriber, err := store.NewSubscriber(ctx, esURL, "clients-es-sub", logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subConfig := events.SubscriberConfig{
|
||||
Stream: stream,
|
||||
Consumer: esConsumerName,
|
||||
Handler: NewEventHandler(repo),
|
||||
Ordered: true,
|
||||
}
|
||||
return subscriber.Subscribe(ctx, subConfig)
|
||||
}
|
||||
|
||||
// NewEventHandler returns new event store handler.
|
||||
func NewEventHandler(repo clients.Repository) events.EventHandler {
|
||||
reh := rconsumer.NewEventHandler("client", repo)
|
||||
return &eventHandler{
|
||||
repo: repo,
|
||||
rolesEventHandler: reh,
|
||||
}
|
||||
}
|
||||
|
||||
func (es *eventHandler) Handle(ctx context.Context, event events.Event) error {
|
||||
msg, err := event.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, ok := msg["operation"]
|
||||
|
||||
if !ok {
|
||||
return errNoOperationKey
|
||||
}
|
||||
switch op {
|
||||
case create:
|
||||
return es.createClientHandler(ctx, msg)
|
||||
case update:
|
||||
return es.updateClientHandler(ctx, msg)
|
||||
case updateTags:
|
||||
return es.updateClientTagsHandler(ctx, msg)
|
||||
case enable, disable:
|
||||
return es.changeStatusClientHandler(ctx, msg)
|
||||
case remove:
|
||||
return es.removeClientHandler(ctx, msg)
|
||||
case setParentGroup:
|
||||
return es.setParentGroupHandler(ctx, msg)
|
||||
case removeParentGroup:
|
||||
return es.removeParentGroupHandler(ctx, msg)
|
||||
}
|
||||
|
||||
return es.rolesEventHandler.Handle(ctx, op, msg)
|
||||
}
|
||||
|
||||
func (es *eventHandler) createClientHandler(ctx context.Context, data map[string]any) error {
|
||||
c, rps, err := decodeCreateClientEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errCreateClientEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.Save(ctx, c); err != nil {
|
||||
return errors.Wrap(errCreateClientEvent, err)
|
||||
}
|
||||
if _, err := es.repo.AddRoles(ctx, rps); err != nil {
|
||||
return errors.Wrap(errCreateClientEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) updateClientHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeUpdateClientEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errUpdateClientEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.Update(ctx, c); err != nil {
|
||||
return errors.Wrap(errUpdateClientEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) updateClientTagsHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeUpdateClientEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errUpdateClientEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.UpdateTags(ctx, c); err != nil {
|
||||
return errors.Wrap(errUpdateClientEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) changeStatusClientHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeChangeStatusClientEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errChangeStatusClientEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.ChangeStatus(ctx, c); err != nil {
|
||||
return errors.Wrap(errChangeStatusClientEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) removeClientHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeRemoveClientEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveClientEvent, err)
|
||||
}
|
||||
|
||||
if err := es.repo.Delete(ctx, c.ID); err != nil {
|
||||
return errors.Wrap(errRemoveClientEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) setParentGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeSetParentGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errSetParentGroupEvent, err)
|
||||
}
|
||||
if err := es.repo.SetParentGroup(ctx, c); err != nil {
|
||||
return errors.Wrap(errSetParentGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) removeParentGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
c, err := decodeRemoveParentGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveParentGroupEvent, err)
|
||||
}
|
||||
if err := es.repo.RemoveParentGroup(ctx, c); err != nil {
|
||||
return errors.Wrap(errRemoveParentGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/domains"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/roles"
|
||||
rconsumer "github.com/absmach/magistrala/pkg/roles/rolemanager/events/consumer"
|
||||
)
|
||||
|
||||
const (
|
||||
layout = "2006-01-02T15:04:05.999999Z"
|
||||
)
|
||||
|
||||
var (
|
||||
errDecodeCreateDomainEvent = errors.New("failed to decode domain create event")
|
||||
errDecodeUpdateDomainEvent = errors.New("failed to decode domain update event")
|
||||
errDecodeEnableDomainEvent = errors.New("failed to decode domain enable event")
|
||||
errDecodeDisableDomainEvent = errors.New("failed to decode domain disable event")
|
||||
errDecodeFreezeDomainEvent = errors.New("failed to decode domain freeze event")
|
||||
errDecodeRemoveDomainsEvent = errors.New("failed to decode domain remove event")
|
||||
|
||||
errID = errors.New("missing or invalid 'id'")
|
||||
errName = errors.New("missing or invalid 'name'")
|
||||
errRoute = errors.New("missing or invalid 'route'")
|
||||
errTags = errors.New("invalid 'tags'")
|
||||
errStatus = errors.New("missing or invalid 'status'")
|
||||
errConvertStatus = errors.New("failed to convert status")
|
||||
errCreatedBy = errors.New("missing or invalid 'created_by'")
|
||||
errCreatedAt = errors.New("failed to parse 'created_at' time")
|
||||
errUpdatedAt = errors.New("failed to parse 'updated_at' time")
|
||||
)
|
||||
|
||||
func ToDomains(data map[string]any) (domains.Domain, error) {
|
||||
var d domains.Domain
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errID
|
||||
}
|
||||
d.ID = id
|
||||
|
||||
name, ok := data["name"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errName
|
||||
}
|
||||
d.Name = name
|
||||
|
||||
stat, ok := data["status"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errStatus
|
||||
}
|
||||
st, err := domains.ToStatus(stat)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errConvertStatus, err)
|
||||
}
|
||||
d.Status = st
|
||||
|
||||
route, ok := data["route"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errRoute
|
||||
}
|
||||
d.Route = route
|
||||
|
||||
cby, ok := data["created_by"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errCreatedBy
|
||||
}
|
||||
d.CreatedBy = cby
|
||||
|
||||
cat, ok := data["created_at"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errCreatedAt
|
||||
}
|
||||
ct, err := time.Parse(layout, cat)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errCreatedAt, err)
|
||||
}
|
||||
d.CreatedAt = ct
|
||||
|
||||
// Following fields of groups are allowed to be empty.
|
||||
itags, ok := data["tags"].([]any)
|
||||
if ok {
|
||||
tags, err := rconsumer.ToStrings(itags)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errTags, err)
|
||||
}
|
||||
d.Tags = tags
|
||||
}
|
||||
|
||||
meta, ok := data["metadata"].(map[string]any)
|
||||
if ok {
|
||||
d.Metadata = meta
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
d.UpdatedBy = uby
|
||||
}
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errUpdatedAt, err)
|
||||
}
|
||||
d.UpdatedAt = ut
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func decodeCreateDomainEvent(data map[string]any) (domains.Domain, []roles.RoleProvision, error) {
|
||||
d, err := ToDomains(data)
|
||||
if err != nil {
|
||||
return domains.Domain{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateDomainEvent, err)
|
||||
}
|
||||
irps, ok := data["roles_provisioned"].([]any)
|
||||
if !ok {
|
||||
return domains.Domain{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateDomainEvent, errors.New("missing or invalid 'roles_provisioned'"))
|
||||
}
|
||||
rps, err := rconsumer.ToRoleProvisions(irps)
|
||||
if err != nil {
|
||||
return domains.Domain{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateDomainEvent, err)
|
||||
}
|
||||
|
||||
return d, rps, nil
|
||||
}
|
||||
|
||||
func decodeUpdateDomainEvent(data map[string]any) (domains.Domain, error) {
|
||||
var d domains.Domain
|
||||
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeUpdateDomainEvent, errID)
|
||||
}
|
||||
d.ID = id
|
||||
|
||||
name, ok := data["name"].(string)
|
||||
if ok {
|
||||
d.Name = name
|
||||
}
|
||||
|
||||
route, ok := data["route"].(string)
|
||||
if ok {
|
||||
d.Route = route
|
||||
}
|
||||
|
||||
itags, ok := data["tags"].([]any)
|
||||
if ok {
|
||||
tags, err := rconsumer.ToStrings(itags)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeUpdateDomainEvent, err)
|
||||
}
|
||||
d.Tags = tags
|
||||
}
|
||||
|
||||
meta, ok := data["metadata"].(map[string]any)
|
||||
if ok {
|
||||
d.Metadata = meta
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
d.UpdatedBy = uby
|
||||
}
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeUpdateDomainEvent, errors.Wrap(errUpdatedAt, err))
|
||||
}
|
||||
d.UpdatedAt = ut
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func decodeEnableDomainEvent(data map[string]any) (domains.Domain, error) {
|
||||
var d domains.Domain
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeEnableDomainEvent, errID)
|
||||
}
|
||||
d.ID = id
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
d.UpdatedBy = uby
|
||||
}
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeEnableDomainEvent, errors.Wrap(errUpdatedAt, err))
|
||||
}
|
||||
d.UpdatedAt = ut
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func decodeDisableDomainEvent(data map[string]any) (domains.Domain, error) {
|
||||
var d domains.Domain
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeDisableDomainEvent, errID)
|
||||
}
|
||||
d.ID = id
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
d.UpdatedBy = uby
|
||||
}
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeDisableDomainEvent, errors.Wrap(errUpdatedAt, err))
|
||||
}
|
||||
d.UpdatedAt = ut
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func decodeFreezeDomainEvent(data map[string]any) (domains.Domain, error) {
|
||||
var d domains.Domain
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeFreezeDomainEvent, errID)
|
||||
}
|
||||
d.ID = id
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
d.UpdatedBy = uby
|
||||
}
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeFreezeDomainEvent, errors.Wrap(errUpdatedAt, err))
|
||||
}
|
||||
d.UpdatedAt = ut
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func decodeUserDeleteDomainEvent(_ map[string]any) (domains.Domain, error) {
|
||||
return domains.Domain{}, fmt.Errorf("not implemented decode domain user delete event ")
|
||||
}
|
||||
|
||||
func decodeDeleteDomainEvent(data map[string]any) (domains.Domain, error) {
|
||||
var d domains.Domain
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return domains.Domain{}, errors.Wrap(errDecodeRemoveDomainsEvent, errID)
|
||||
}
|
||||
d.ID = id
|
||||
return d, nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
@@ -1,207 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/absmach/magistrala/domains"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/events"
|
||||
"github.com/absmach/magistrala/pkg/events/store"
|
||||
"github.com/absmach/magistrala/pkg/messaging"
|
||||
rconsumer "github.com/absmach/magistrala/pkg/roles/rolemanager/events/consumer"
|
||||
)
|
||||
|
||||
const (
|
||||
stream = "events.magistrala.domain.*"
|
||||
|
||||
create = "domain.create"
|
||||
update = "domain.update"
|
||||
enable = "domain.enable"
|
||||
disable = "domain.disable"
|
||||
freeze = "domain.freeze"
|
||||
delete = "domain.delete"
|
||||
userDelete = "domain.user_delete"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoOperationKey = errors.New("operation key is not found in event message")
|
||||
errCreateDomainEvent = errors.New("failed to consume domain create event")
|
||||
errUpdateDomainEvent = errors.New("failed to consume domain update event")
|
||||
errEnableDomainGroupEvent = errors.New("failed to consume domain enable event")
|
||||
errDisableDomainGroupEvent = errors.New("failed to consume domain disable event")
|
||||
errFreezeDomainGroupEvent = errors.New("failed to consume domain freeze event")
|
||||
errUserDeleteDomainEvent = errors.New("failed to consume domain user delete event")
|
||||
errDeleteDomainEvent = errors.New("failed to consume domain delete event")
|
||||
)
|
||||
|
||||
type eventHandler struct {
|
||||
repo domains.Repository
|
||||
rolesEventHandler rconsumer.EventHandler
|
||||
}
|
||||
|
||||
func DomainsEventsSubscribe(ctx context.Context, repo domains.Repository, esURL, esConsumerName string, logger *slog.Logger) error {
|
||||
subscriber, err := store.NewSubscriber(ctx, esURL, "domains-es-sub", logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subConfig := events.SubscriberConfig{
|
||||
Stream: stream,
|
||||
Consumer: esConsumerName,
|
||||
Handler: NewEventHandler(repo),
|
||||
DeliveryPolicy: messaging.DeliverNewPolicy,
|
||||
Ordered: true,
|
||||
}
|
||||
return subscriber.Subscribe(ctx, subConfig)
|
||||
}
|
||||
|
||||
// NewEventHandler returns new event store handler.
|
||||
func NewEventHandler(repo domains.Repository) events.EventHandler {
|
||||
reh := rconsumer.NewEventHandler("domain", repo)
|
||||
return &eventHandler{
|
||||
repo: repo,
|
||||
rolesEventHandler: reh,
|
||||
}
|
||||
}
|
||||
|
||||
func (es *eventHandler) Handle(ctx context.Context, event events.Event) error {
|
||||
msg, err := event.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, ok := msg["operation"]
|
||||
|
||||
if !ok {
|
||||
return errNoOperationKey
|
||||
}
|
||||
switch op {
|
||||
case create:
|
||||
return es.createDomainHandler(ctx, msg)
|
||||
case update:
|
||||
return es.updateDomainHandler(ctx, msg)
|
||||
case enable:
|
||||
return es.enableDomainHandler(ctx, msg)
|
||||
case disable:
|
||||
return es.disableDomainHandler(ctx, msg)
|
||||
case freeze:
|
||||
return es.freezeDomainHandler(ctx, msg)
|
||||
case userDelete:
|
||||
return es.userDeleteDomainHandler(ctx, msg)
|
||||
case delete:
|
||||
return es.deleteDomainHandler(ctx, msg)
|
||||
}
|
||||
|
||||
return es.rolesEventHandler.Handle(ctx, op, msg)
|
||||
}
|
||||
|
||||
func (es *eventHandler) createDomainHandler(ctx context.Context, data map[string]any) error {
|
||||
d, rps, err := decodeCreateDomainEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errCreateDomainEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.SaveDomain(ctx, d); err != nil {
|
||||
return errors.Wrap(errCreateDomainEvent, err)
|
||||
}
|
||||
if _, err := es.repo.AddRoles(ctx, rps); err != nil {
|
||||
return errors.Wrap(errCreateDomainEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) updateDomainHandler(ctx context.Context, data map[string]any) error {
|
||||
d, err := decodeUpdateDomainEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errUpdateDomainEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.UpdateDomain(
|
||||
ctx,
|
||||
d.ID,
|
||||
domains.DomainReq{
|
||||
Name: &d.Name,
|
||||
Metadata: &d.Metadata,
|
||||
Tags: &d.Tags,
|
||||
UpdatedBy: &d.UpdatedBy,
|
||||
UpdatedAt: &d.UpdatedAt,
|
||||
},
|
||||
); err != nil {
|
||||
return errors.Wrap(errUpdateDomainEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) enableDomainHandler(ctx context.Context, data map[string]any) error {
|
||||
d, err := decodeEnableDomainEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errEnableDomainGroupEvent, err)
|
||||
}
|
||||
|
||||
enabled := domains.EnabledStatus
|
||||
if _, err := es.repo.UpdateDomain(ctx, d.ID, domains.DomainReq{Status: &enabled, UpdatedBy: &d.UpdatedBy, UpdatedAt: &d.UpdatedAt}); err != nil {
|
||||
return errors.Wrap(errEnableDomainGroupEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) disableDomainHandler(ctx context.Context, data map[string]any) error {
|
||||
d, err := decodeDisableDomainEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errDisableDomainGroupEvent, err)
|
||||
}
|
||||
|
||||
disabled := domains.DisabledStatus
|
||||
if _, err := es.repo.UpdateDomain(ctx, d.ID, domains.DomainReq{Status: &disabled, UpdatedBy: &d.UpdatedBy, UpdatedAt: &d.UpdatedAt}); err != nil {
|
||||
return errors.Wrap(errDisableDomainGroupEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) freezeDomainHandler(ctx context.Context, data map[string]any) error {
|
||||
d, err := decodeFreezeDomainEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errFreezeDomainGroupEvent, err)
|
||||
}
|
||||
|
||||
freeze := domains.FreezeStatus
|
||||
if _, err := es.repo.UpdateDomain(ctx, d.ID, domains.DomainReq{Status: &freeze, UpdatedBy: &d.UpdatedBy, UpdatedAt: &d.UpdatedAt}); err != nil {
|
||||
return errors.Wrap(errFreezeDomainGroupEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) userDeleteDomainHandler(_ context.Context, data map[string]any) error {
|
||||
_, err := decodeUserDeleteDomainEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errUserDeleteDomainEvent, err)
|
||||
}
|
||||
|
||||
return fmt.Errorf("not implemented user delete domain handler")
|
||||
}
|
||||
|
||||
func (es *eventHandler) deleteDomainHandler(ctx context.Context, data map[string]any) error {
|
||||
d, err := decodeDeleteDomainEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errDeleteDomainEvent, err)
|
||||
}
|
||||
|
||||
if err := es.repo.DeleteDomain(ctx, d.ID); err != nil {
|
||||
return errors.Wrap(errDeleteDomainEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package domainscache
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala/domains"
|
||||
"github.com/absmach/magistrala/domains/private"
|
||||
pkgDomains "github.com/absmach/magistrala/pkg/domains"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
)
|
||||
|
||||
type authorization struct {
|
||||
psvc private.Service
|
||||
}
|
||||
|
||||
var _ pkgDomains.Authorization = (*authorization)(nil)
|
||||
|
||||
func NewAuthorization(psvc private.Service) pkgDomains.Authorization {
|
||||
return authorization{
|
||||
psvc: psvc,
|
||||
}
|
||||
}
|
||||
|
||||
func (a authorization) RetrieveStatus(ctx context.Context, id string) (domains.Status, error) {
|
||||
status, err := a.psvc.RetrieveStatus(ctx, id)
|
||||
if err != nil {
|
||||
return domains.AllStatus, errors.Wrap(svcerr.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/groups"
|
||||
"github.com/absmach/magistrala/internal/nullable"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/roles"
|
||||
rconsumer "github.com/absmach/magistrala/pkg/roles/rolemanager/events/consumer"
|
||||
)
|
||||
|
||||
var (
|
||||
errDecodeCreateGroupEvent = errors.New("failed to decode group create event")
|
||||
errDecodeUpdateGroupEvent = errors.New("failed to decode group update event")
|
||||
errDecodeChangeStatusGroupEvent = errors.New("failed to decode group change status event")
|
||||
errDecodeRemoveGroupEvent = errors.New("failed to decode group remove event")
|
||||
errDecodeAddParentGroupEvent = errors.New("failed to decode group add parent event")
|
||||
errDecodeRemoveParentGroupEvent = errors.New("failed to decode group remove parent event")
|
||||
errDecodeAddChildrenGroupsEvent = errors.New("failed to decode group add children groups event")
|
||||
errDecodeRemoveChildrenGroupsEvent = errors.New("failed to decode group remove children groups event")
|
||||
|
||||
errID = errors.New("missing or invalid 'id'")
|
||||
errName = errors.New("missing or invalid 'name'")
|
||||
errDomain = errors.New("missing or invalid 'domain'")
|
||||
errParent = errors.New("missing or invalid 'parent'")
|
||||
errChildrenIDs = errors.New("missing or invalid 'children_ids'")
|
||||
errStatus = errors.New("missing or invalid 'status'")
|
||||
errConvertStatus = errors.New("failed to convert status")
|
||||
errCreatedAt = errors.New("failed to parse 'created_at' time")
|
||||
errUpdatedAt = errors.New("failed to parse 'updated_at' time")
|
||||
)
|
||||
|
||||
const layout = "2006-01-02T15:04:05.999999Z"
|
||||
|
||||
func ToGroups(data map[string]any) (groups.Group, error) {
|
||||
var g groups.Group
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return groups.Group{}, errID
|
||||
}
|
||||
g.ID = id
|
||||
|
||||
name, ok := data["name"].(string)
|
||||
if !ok {
|
||||
return groups.Group{}, errName
|
||||
}
|
||||
g.Name = name
|
||||
|
||||
dom, ok := data["domain"].(string)
|
||||
if !ok {
|
||||
return groups.Group{}, errDomain
|
||||
}
|
||||
g.Domain = dom
|
||||
|
||||
stat, ok := data["status"].(string)
|
||||
if !ok {
|
||||
return groups.Group{}, errStatus
|
||||
}
|
||||
st, err := groups.ToStatus(stat)
|
||||
if err != nil {
|
||||
return groups.Group{}, errors.Wrap(errConvertStatus, err)
|
||||
}
|
||||
g.Status = st
|
||||
|
||||
cat, ok := data["created_at"].(string)
|
||||
if !ok {
|
||||
return groups.Group{}, errCreatedAt
|
||||
}
|
||||
ct, err := time.Parse(layout, cat)
|
||||
if err != nil {
|
||||
return groups.Group{}, errors.Wrap(errCreatedAt, err)
|
||||
}
|
||||
g.CreatedAt = ct
|
||||
|
||||
// Following fields of groups are allowed to be empty.
|
||||
|
||||
desc, ok := data["description"].(string)
|
||||
if ok {
|
||||
g.Description = nullable.New(desc)
|
||||
}
|
||||
|
||||
parent, ok := data["parent"].(string)
|
||||
if ok {
|
||||
g.Parent = parent
|
||||
}
|
||||
|
||||
meta, ok := data["metadata"].(map[string]any)
|
||||
if ok {
|
||||
g.Metadata = meta
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
g.UpdatedBy = uby
|
||||
}
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return groups.Group{}, errors.Wrap(errUpdatedAt, err)
|
||||
}
|
||||
g.UpdatedAt = ut
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func decodeCreateGroupEvent(data map[string]any) (groups.Group, []roles.RoleProvision, error) {
|
||||
g, err := ToGroups(data)
|
||||
if err != nil {
|
||||
return groups.Group{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateGroupEvent, err)
|
||||
}
|
||||
irps, ok := data["roles_provisioned"].([]any)
|
||||
if !ok {
|
||||
return groups.Group{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateGroupEvent, errors.New("missing or invalid 'roles_provisioned'"))
|
||||
}
|
||||
rps, err := rconsumer.ToRoleProvisions(irps)
|
||||
if err != nil {
|
||||
return groups.Group{}, []roles.RoleProvision{}, errors.Wrap(errDecodeCreateGroupEvent, err)
|
||||
}
|
||||
|
||||
return g, rps, nil
|
||||
}
|
||||
|
||||
func decodeUpdateGroupEvent(data map[string]any) (groups.Group, error) {
|
||||
g, err := ToGroups(data)
|
||||
if err != nil {
|
||||
return groups.Group{}, errors.Wrap(errDecodeUpdateGroupEvent, err)
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func ToGroupStatus(data map[string]any) (groups.Group, error) {
|
||||
var g groups.Group
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return groups.Group{}, errID
|
||||
}
|
||||
g.ID = id
|
||||
|
||||
stat, ok := data["status"].(string)
|
||||
if !ok {
|
||||
return groups.Group{}, errStatus
|
||||
}
|
||||
st, err := groups.ToStatus(stat)
|
||||
if err != nil {
|
||||
return groups.Group{}, errors.Wrap(errConvertStatus, err)
|
||||
}
|
||||
g.Status = st
|
||||
|
||||
uat, ok := data["updated_at"].(string)
|
||||
if ok {
|
||||
ut, err := time.Parse(layout, uat)
|
||||
if err != nil {
|
||||
return groups.Group{}, errors.Wrap(errUpdatedAt, err)
|
||||
}
|
||||
g.UpdatedAt = ut
|
||||
}
|
||||
|
||||
uby, ok := data["updated_by"].(string)
|
||||
if ok {
|
||||
g.UpdatedBy = uby
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func decodeChangeStatusGroupEvent(data map[string]any) (groups.Group, error) {
|
||||
g, err := ToGroupStatus(data)
|
||||
if err != nil {
|
||||
return groups.Group{}, errors.Wrap(errDecodeChangeStatusGroupEvent, err)
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func decodeRemoveGroupEvent(data map[string]any) (groups.Group, error) {
|
||||
var g groups.Group
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return groups.Group{}, errors.Wrap(errDecodeRemoveGroupEvent, errID)
|
||||
}
|
||||
g.ID = id
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func decodeAddParentGroupEvent(data map[string]any) (id string, parent string, err error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return "", "", errors.Wrap(errAddParentGroupEvent, errID)
|
||||
}
|
||||
|
||||
parent, ok = data["parent_id"].(string)
|
||||
if !ok {
|
||||
return "", "", errors.Wrap(errDecodeAddParentGroupEvent, errParent)
|
||||
}
|
||||
|
||||
return id, parent, nil
|
||||
}
|
||||
|
||||
func decodeRemoveParentGroupEvent(data map[string]any) (id string, err error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return "", errors.Wrap(errDecodeRemoveParentGroupEvent, errID)
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func decodeAddChildrenGroupEvent(data map[string]any) (id string, childrenIDs []string, err error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return "", []string{}, errors.Wrap(errDecodeAddChildrenGroupsEvent, errID)
|
||||
}
|
||||
chIDs, ok := data["children_ids"].([]any)
|
||||
if !ok {
|
||||
return "", []string{}, errors.Wrap(errDecodeAddChildrenGroupsEvent, errChildrenIDs)
|
||||
}
|
||||
cids, err := rconsumer.ToStrings(chIDs)
|
||||
if err != nil {
|
||||
return "", []string{}, errors.Wrap(errDecodeAddChildrenGroupsEvent, errors.Wrap(errChildrenIDs, err))
|
||||
}
|
||||
return id, cids, nil
|
||||
}
|
||||
|
||||
func decodeRemoveChildrenGroupEvent(data map[string]any) (id string, childrenIDs []string, err error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return "", []string{}, errors.Wrap(errDecodeRemoveChildrenGroupsEvent, errID)
|
||||
}
|
||||
chIDs, ok := data["children_ids"].([]any)
|
||||
if !ok {
|
||||
return "", []string{}, errors.Wrap(errDecodeRemoveChildrenGroupsEvent, errChildrenIDs)
|
||||
}
|
||||
cids, err := rconsumer.ToStrings(chIDs)
|
||||
if err != nil {
|
||||
return "", []string{}, errors.Wrap(errDecodeRemoveChildrenGroupsEvent, errors.Wrap(errChildrenIDs, err))
|
||||
}
|
||||
return id, cids, nil
|
||||
}
|
||||
|
||||
func decodeRemoveAllChildrenGroupEvent(data map[string]any) (id string, err error) {
|
||||
id, ok := data["id"].(string)
|
||||
if !ok {
|
||||
return "", errors.Wrap(errDecodeRemoveChildrenGroupsEvent, errID)
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package consumer contains events consumer for events
|
||||
// published by Bootstrap service.
|
||||
package consumer
|
||||
@@ -1,226 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package consumer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/absmach/magistrala/groups"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
|
||||
"github.com/absmach/magistrala/pkg/events"
|
||||
"github.com/absmach/magistrala/pkg/events/store"
|
||||
rconsumer "github.com/absmach/magistrala/pkg/roles/rolemanager/events/consumer"
|
||||
)
|
||||
|
||||
const (
|
||||
stream = "events.magistrala.group.*"
|
||||
|
||||
create = "group.create"
|
||||
update = "group.update"
|
||||
enable = "group.enable"
|
||||
disable = "group.disable"
|
||||
remove = "group.remove"
|
||||
addParentGroup = "group.add_parent_group"
|
||||
removeParentGroup = "group.remove_parent_group"
|
||||
addChildrenGroups = "group.add_children_groups"
|
||||
removeChildrenGroups = "group.remove_children_groups"
|
||||
removeAllChildrenGroups = "group.remove_all_children_groups"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoOperationKey = errors.New("operation key is not found in event message")
|
||||
errCreateGroupEvent = errors.New("failed to consume group create event")
|
||||
errUpdateGroupEvent = errors.New("failed to consume group update event")
|
||||
errChangeStatusGroupEvent = errors.New("failed to consume group change status event")
|
||||
errRemoveGroupEvent = errors.New("failed to consume group remove event")
|
||||
errAddParentGroupEvent = errors.New("failed to consume group add parent group event")
|
||||
errRemoveParentGroupEvent = errors.New("failed to consume group remove parent group event")
|
||||
errAddChildrenGroupEvent = errors.New("failed to consume group add children groups event")
|
||||
errRemoveChildrenGroupEvent = errors.New("failed to consume group remove children groups event")
|
||||
errRemoveAllChildrenGroupEvent = errors.New("failed to consume group remove all children groups event")
|
||||
)
|
||||
|
||||
type eventHandler struct {
|
||||
repo groups.Repository
|
||||
rolesEventHandler rconsumer.EventHandler
|
||||
}
|
||||
|
||||
func GroupsEventsSubscribe(ctx context.Context, repo groups.Repository, esURL, esConsumerName string, logger *slog.Logger) error {
|
||||
subscriber, err := store.NewSubscriber(ctx, esURL, "groups-es-sub", logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subConfig := events.SubscriberConfig{
|
||||
Stream: stream,
|
||||
Consumer: esConsumerName,
|
||||
Handler: NewEventHandler(repo),
|
||||
Ordered: true,
|
||||
}
|
||||
return subscriber.Subscribe(ctx, subConfig)
|
||||
}
|
||||
|
||||
// NewEventHandler returns new event store handler.
|
||||
func NewEventHandler(repo groups.Repository) events.EventHandler {
|
||||
reh := rconsumer.NewEventHandler("group", repo)
|
||||
return &eventHandler{
|
||||
repo: repo,
|
||||
rolesEventHandler: reh,
|
||||
}
|
||||
}
|
||||
|
||||
func (es *eventHandler) Handle(ctx context.Context, event events.Event) error {
|
||||
msg, err := event.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, ok := msg["operation"]
|
||||
|
||||
if !ok {
|
||||
return errNoOperationKey
|
||||
}
|
||||
switch op {
|
||||
case create:
|
||||
return es.createGroupHandler(ctx, msg)
|
||||
case update:
|
||||
return es.updateGroupHandler(ctx, msg)
|
||||
case enable, disable:
|
||||
return es.changeStatusGroupHandler(ctx, msg)
|
||||
case remove:
|
||||
return es.removeGroupHandler(ctx, msg)
|
||||
case addParentGroup:
|
||||
return es.addParentGroupHandler(ctx, msg)
|
||||
case removeParentGroup:
|
||||
return es.removeParentGroupHandler(ctx, msg)
|
||||
case addChildrenGroups:
|
||||
return es.addChildrenGroupsHandler(ctx, msg)
|
||||
case removeChildrenGroups:
|
||||
return es.removeChildrenGroupsHandler(ctx, msg)
|
||||
case removeAllChildrenGroups:
|
||||
return es.removeAllChildrenGroupsHandler(ctx, msg)
|
||||
}
|
||||
|
||||
return es.rolesEventHandler.Handle(ctx, op, msg)
|
||||
}
|
||||
|
||||
func (es *eventHandler) createGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
g, rps, err := decodeCreateGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errCreateGroupEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.Save(ctx, g); err != nil {
|
||||
return errors.Wrap(errCreateGroupEvent, err)
|
||||
}
|
||||
if _, err := es.repo.AddRoles(ctx, rps); err != nil {
|
||||
return errors.Wrap(errCreateGroupEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) updateGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
g, err := decodeUpdateGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errUpdateGroupEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.Update(ctx, g); err != nil {
|
||||
return errors.Wrap(errUpdateGroupEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) changeStatusGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
g, err := decodeChangeStatusGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errChangeStatusGroupEvent, err)
|
||||
}
|
||||
|
||||
if _, err := es.repo.ChangeStatus(ctx, g); err != nil {
|
||||
return errors.Wrap(errChangeStatusGroupEvent, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) removeGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
g, err := decodeRemoveGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveGroupEvent, err)
|
||||
}
|
||||
|
||||
if err := es.repo.Delete(ctx, g.ID); err != nil {
|
||||
return errors.Wrap(errRemoveGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) addParentGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
id, parent, err := decodeAddParentGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errAddParentGroupEvent, err)
|
||||
}
|
||||
if err := es.repo.AssignParentGroup(ctx, parent, id); err != nil {
|
||||
return errors.Wrap(errAddParentGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) removeParentGroupHandler(ctx context.Context, data map[string]any) error {
|
||||
id, err := decodeRemoveParentGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveParentGroupEvent, err)
|
||||
}
|
||||
g, err := es.repo.RetrieveByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveParentGroupEvent, err)
|
||||
}
|
||||
if err := es.repo.UnassignParentGroup(ctx, g.Parent, id); err != nil {
|
||||
return errors.Wrap(errRemoveParentGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) addChildrenGroupsHandler(ctx context.Context, data map[string]any) error {
|
||||
id, cids, err := decodeAddChildrenGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errAddChildrenGroupEvent, err)
|
||||
}
|
||||
|
||||
if err := es.repo.AssignParentGroup(ctx, id, cids...); err != nil {
|
||||
return errors.Wrap(errAddChildrenGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) removeChildrenGroupsHandler(ctx context.Context, data map[string]any) error {
|
||||
id, cids, err := decodeRemoveChildrenGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveChildrenGroupEvent, err)
|
||||
}
|
||||
|
||||
if err := es.repo.UnassignParentGroup(ctx, id, cids...); err != nil {
|
||||
return errors.Wrap(errRemoveChildrenGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *eventHandler) removeAllChildrenGroupsHandler(ctx context.Context, data map[string]any) error {
|
||||
id, err := decodeRemoveAllChildrenGroupEvent(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(errRemoveAllChildrenGroupEvent, err)
|
||||
}
|
||||
if err := es.repo.UnassignAllChildrenGroups(ctx, id); err != nil && err != repoerr.ErrNotFound {
|
||||
return errors.Wrap(errRemoveAllChildrenGroupEvent, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package grpcclient_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
grpcClientsV1 "github.com/absmach/magistrala/api/grpc/clients/v1"
|
||||
grpcDomainsV1 "github.com/absmach/magistrala/api/grpc/domains/v1"
|
||||
grpcTokenV1 "github.com/absmach/magistrala/api/grpc/token/v1"
|
||||
tokengrpcapi "github.com/absmach/magistrala/auth/api/grpc/token"
|
||||
"github.com/absmach/magistrala/auth/mocks"
|
||||
clientsgrpcapi "github.com/absmach/magistrala/clients/api/grpc"
|
||||
climocks "github.com/absmach/magistrala/clients/private/mocks"
|
||||
domainsgrpcapi "github.com/absmach/magistrala/domains/api/grpc"
|
||||
domainsMocks "github.com/absmach/magistrala/domains/private/mocks"
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/grpcclient"
|
||||
"github.com/absmach/magistrala/pkg/server"
|
||||
grpcserver "github.com/absmach/magistrala/pkg/server/grpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func TestSetupToken(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
registerAuthServiceServer := func(srv *grpc.Server) {
|
||||
grpcTokenV1.RegisterTokenServiceServer(srv, tokengrpcapi.NewTokenServer(new(mocks.Service)))
|
||||
}
|
||||
gs := grpcserver.NewServer(ctx, cancel, "auth", server.Config{Port: "12345"}, registerAuthServiceServer, mglog.NewMock())
|
||||
go func() {
|
||||
err := gs.Start()
|
||||
assert.Nil(t, err, fmt.Sprintf(`"Unexpected error creating server %s"`, err))
|
||||
}()
|
||||
defer func() {
|
||||
err := gs.Stop()
|
||||
assert.Nil(t, err, fmt.Sprintf(`"Unexpected error stopping server %s"`, err))
|
||||
}()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
config grpcclient.Config
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "successful",
|
||||
config: grpcclient.Config{
|
||||
URL: "localhost:12345",
|
||||
Timeout: time.Second,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "failed with empty URL",
|
||||
config: grpcclient.Config{
|
||||
URL: "",
|
||||
Timeout: time.Second,
|
||||
},
|
||||
err: errors.New("service is not serving"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
client, handler, err := grpcclient.SetupTokenClient(context.Background(), c.config)
|
||||
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s", err, c.err))
|
||||
if err == nil {
|
||||
assert.NotNil(t, client)
|
||||
assert.NotNil(t, handler)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupClientsClient(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
registerClientsServiceServer := func(srv *grpc.Server) {
|
||||
grpcClientsV1.RegisterClientsServiceServer(srv, clientsgrpcapi.NewServer(new(climocks.Service)))
|
||||
}
|
||||
gs := grpcserver.NewServer(ctx, cancel, "clients", server.Config{Port: "12345"}, registerClientsServiceServer, mglog.NewMock())
|
||||
go func() {
|
||||
err := gs.Start()
|
||||
assert.Nil(t, err, fmt.Sprintf(`"Unexpected error creating server %s"`, err))
|
||||
}()
|
||||
time.Sleep(time.Second)
|
||||
defer func() {
|
||||
err := gs.Stop()
|
||||
assert.Nil(t, err, fmt.Sprintf(`"Unexpected error stopping server %s"`, err))
|
||||
}()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
config grpcclient.Config
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "successful",
|
||||
config: grpcclient.Config{
|
||||
URL: "localhost:12345",
|
||||
Timeout: time.Second,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
client, handler, err := grpcclient.SetupClientsClient(context.Background(), c.config)
|
||||
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s", err, c.err))
|
||||
if err == nil {
|
||||
assert.NotNil(t, client)
|
||||
assert.NotNil(t, handler)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDomainsClient(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
registerDomainsServiceServer := func(srv *grpc.Server) {
|
||||
grpcDomainsV1.RegisterDomainsServiceServer(srv, domainsgrpcapi.NewDomainsServer(new(domainsMocks.Service)))
|
||||
}
|
||||
gs := grpcserver.NewServer(ctx, cancel, "domains", server.Config{Port: "12345"}, registerDomainsServiceServer, mglog.NewMock())
|
||||
go func() {
|
||||
err := gs.Start()
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating server %s", err))
|
||||
}()
|
||||
time.Sleep(time.Second)
|
||||
defer func() {
|
||||
err := gs.Stop()
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error stopping server %s", err))
|
||||
}()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
config grpcclient.Config
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "successfully",
|
||||
config: grpcclient.Config{
|
||||
URL: "localhost:12345",
|
||||
Timeout: time.Second,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
client, handler, err := grpcclient.SetupDomainsClient(context.Background(), c.config)
|
||||
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s", err, c.err))
|
||||
if err == nil {
|
||||
assert.NotNil(t, client)
|
||||
assert.NotNil(t, handler)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package oauth2 contains the domain concept definitions needed to support
|
||||
// Magistrala ui service OAuth2 functionality.
|
||||
package oauth2
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package google contains the domain concept definitions needed to support
|
||||
// Magistrala services for Google OAuth2 functionality.
|
||||
package google
|
||||
@@ -1,116 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
mgoauth2 "github.com/absmach/magistrala/pkg/oauth2"
|
||||
uclient "github.com/absmach/magistrala/users"
|
||||
"golang.org/x/oauth2"
|
||||
googleoauth2 "golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
const (
|
||||
providerName = "google"
|
||||
defTimeout = 1 * time.Minute
|
||||
userInfoURL = "https://www.googleapis.com/oauth2/v2/userinfo?access_token="
|
||||
tokenInfoURL = "https://oauth2.googleapis.com/tokeninfo?access_token="
|
||||
)
|
||||
|
||||
var scopes = []string{
|
||||
"https://www.googleapis.com/auth/userinfo.email",
|
||||
"https://www.googleapis.com/auth/userinfo.profile",
|
||||
}
|
||||
|
||||
var httpClient = &http.Client{
|
||||
Timeout: defTimeout,
|
||||
}
|
||||
|
||||
var _ mgoauth2.Provider = (*config)(nil)
|
||||
|
||||
type config struct {
|
||||
config *oauth2.Config
|
||||
state string
|
||||
uiRedirectURL string
|
||||
errorURL string
|
||||
}
|
||||
|
||||
// NewProvider returns a new Google OAuth provider.
|
||||
func NewProvider(cfg mgoauth2.Config, uiRedirectURL, errorURL string) mgoauth2.Provider {
|
||||
return &config{
|
||||
config: &oauth2.Config{
|
||||
ClientID: cfg.ClientID,
|
||||
ClientSecret: cfg.ClientSecret,
|
||||
Endpoint: googleoauth2.Endpoint,
|
||||
RedirectURL: cfg.RedirectURL,
|
||||
Scopes: scopes,
|
||||
},
|
||||
state: cfg.State,
|
||||
uiRedirectURL: uiRedirectURL,
|
||||
errorURL: errorURL,
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *config) Name() string {
|
||||
return providerName
|
||||
}
|
||||
|
||||
func (cfg *config) State() string {
|
||||
return cfg.state
|
||||
}
|
||||
|
||||
func (cfg *config) RedirectURL() string {
|
||||
return cfg.uiRedirectURL
|
||||
}
|
||||
|
||||
func (cfg *config) ErrorURL() string {
|
||||
return cfg.errorURL
|
||||
}
|
||||
|
||||
func (cfg *config) IsEnabled() bool {
|
||||
return cfg.config.ClientID != "" && cfg.config.ClientSecret != ""
|
||||
}
|
||||
|
||||
func (cfg *config) Exchange(ctx context.Context, code string) (oauth2.Token, error) {
|
||||
token, err := cfg.config.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
return oauth2.Token{}, err
|
||||
}
|
||||
|
||||
return *token, nil
|
||||
}
|
||||
|
||||
func (cfg *config) UserInfo(accessToken string) (uclient.User, error) {
|
||||
resp, err := httpClient.Get(userInfoURL + url.QueryEscape(accessToken))
|
||||
if err != nil {
|
||||
return uclient.User{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return uclient.User{}, svcerr.ErrAuthentication
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return uclient.User{}, err
|
||||
}
|
||||
|
||||
user, err := mgoauth2.NormalizeUser(data, providerName)
|
||||
if err != nil {
|
||||
return uclient.User{}, errors.Wrap(err, svcerr.ErrAuthentication)
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by mockery; DO NOT EDIT.
|
||||
// github.com/vektra/mockery
|
||||
// template: testify
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala/users"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// NewProvider creates a new instance of Provider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewProvider(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Provider {
|
||||
mock := &Provider{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
// Provider is an autogenerated mock type for the Provider type
|
||||
type Provider struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type Provider_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *Provider) EXPECT() *Provider_Expecter {
|
||||
return &Provider_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// ErrorURL provides a mock function for the type Provider
|
||||
func (_mock *Provider) ErrorURL() string {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ErrorURL")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if returnFunc, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// Provider_ErrorURL_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ErrorURL'
|
||||
type Provider_ErrorURL_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ErrorURL is a helper method to define mock.On call
|
||||
func (_e *Provider_Expecter) ErrorURL() *Provider_ErrorURL_Call {
|
||||
return &Provider_ErrorURL_Call{Call: _e.mock.On("ErrorURL")}
|
||||
}
|
||||
|
||||
func (_c *Provider_ErrorURL_Call) Run(run func()) *Provider_ErrorURL_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_ErrorURL_Call) Return(s string) *Provider_ErrorURL_Call {
|
||||
_c.Call.Return(s)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_ErrorURL_Call) RunAndReturn(run func() string) *Provider_ErrorURL_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Exchange provides a mock function for the type Provider
|
||||
func (_mock *Provider) Exchange(ctx context.Context, code string) (oauth2.Token, error) {
|
||||
ret := _mock.Called(ctx, code)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Exchange")
|
||||
}
|
||||
|
||||
var r0 oauth2.Token
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, string) (oauth2.Token, error)); ok {
|
||||
return returnFunc(ctx, code)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, string) oauth2.Token); ok {
|
||||
r0 = returnFunc(ctx, code)
|
||||
} else {
|
||||
r0 = ret.Get(0).(oauth2.Token)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = returnFunc(ctx, code)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Provider_Exchange_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exchange'
|
||||
type Provider_Exchange_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Exchange is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - code string
|
||||
func (_e *Provider_Expecter) Exchange(ctx interface{}, code interface{}) *Provider_Exchange_Call {
|
||||
return &Provider_Exchange_Call{Call: _e.mock.On("Exchange", ctx, code)}
|
||||
}
|
||||
|
||||
func (_c *Provider_Exchange_Call) Run(run func(ctx context.Context, code string)) *Provider_Exchange_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 context.Context
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(context.Context)
|
||||
}
|
||||
var arg1 string
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(string)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
arg1,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_Exchange_Call) Return(token oauth2.Token, err error) *Provider_Exchange_Call {
|
||||
_c.Call.Return(token, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_Exchange_Call) RunAndReturn(run func(ctx context.Context, code string) (oauth2.Token, error)) *Provider_Exchange_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// IsEnabled provides a mock function for the type Provider
|
||||
func (_mock *Provider) IsEnabled() bool {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for IsEnabled")
|
||||
}
|
||||
|
||||
var r0 bool
|
||||
if returnFunc, ok := ret.Get(0).(func() bool); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// Provider_IsEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsEnabled'
|
||||
type Provider_IsEnabled_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// IsEnabled is a helper method to define mock.On call
|
||||
func (_e *Provider_Expecter) IsEnabled() *Provider_IsEnabled_Call {
|
||||
return &Provider_IsEnabled_Call{Call: _e.mock.On("IsEnabled")}
|
||||
}
|
||||
|
||||
func (_c *Provider_IsEnabled_Call) Run(run func()) *Provider_IsEnabled_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_IsEnabled_Call) Return(b bool) *Provider_IsEnabled_Call {
|
||||
_c.Call.Return(b)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_IsEnabled_Call) RunAndReturn(run func() bool) *Provider_IsEnabled_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Name provides a mock function for the type Provider
|
||||
func (_mock *Provider) Name() string {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Name")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if returnFunc, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// Provider_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name'
|
||||
type Provider_Name_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Name is a helper method to define mock.On call
|
||||
func (_e *Provider_Expecter) Name() *Provider_Name_Call {
|
||||
return &Provider_Name_Call{Call: _e.mock.On("Name")}
|
||||
}
|
||||
|
||||
func (_c *Provider_Name_Call) Run(run func()) *Provider_Name_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_Name_Call) Return(s string) *Provider_Name_Call {
|
||||
_c.Call.Return(s)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_Name_Call) RunAndReturn(run func() string) *Provider_Name_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RedirectURL provides a mock function for the type Provider
|
||||
func (_mock *Provider) RedirectURL() string {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RedirectURL")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if returnFunc, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// Provider_RedirectURL_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RedirectURL'
|
||||
type Provider_RedirectURL_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RedirectURL is a helper method to define mock.On call
|
||||
func (_e *Provider_Expecter) RedirectURL() *Provider_RedirectURL_Call {
|
||||
return &Provider_RedirectURL_Call{Call: _e.mock.On("RedirectURL")}
|
||||
}
|
||||
|
||||
func (_c *Provider_RedirectURL_Call) Run(run func()) *Provider_RedirectURL_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_RedirectURL_Call) Return(s string) *Provider_RedirectURL_Call {
|
||||
_c.Call.Return(s)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_RedirectURL_Call) RunAndReturn(run func() string) *Provider_RedirectURL_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// State provides a mock function for the type Provider
|
||||
func (_mock *Provider) State() string {
|
||||
ret := _mock.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for State")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if returnFunc, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = returnFunc()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// Provider_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State'
|
||||
type Provider_State_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// State is a helper method to define mock.On call
|
||||
func (_e *Provider_Expecter) State() *Provider_State_Call {
|
||||
return &Provider_State_Call{Call: _e.mock.On("State")}
|
||||
}
|
||||
|
||||
func (_c *Provider_State_Call) Run(run func()) *Provider_State_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_State_Call) Return(s string) *Provider_State_Call {
|
||||
_c.Call.Return(s)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_State_Call) RunAndReturn(run func() string) *Provider_State_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// UserInfo provides a mock function for the type Provider
|
||||
func (_mock *Provider) UserInfo(accessToken string) (users.User, error) {
|
||||
ret := _mock.Called(accessToken)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UserInfo")
|
||||
}
|
||||
|
||||
var r0 users.User
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(string) (users.User, error)); ok {
|
||||
return returnFunc(accessToken)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(string) users.User); ok {
|
||||
r0 = returnFunc(accessToken)
|
||||
} else {
|
||||
r0 = ret.Get(0).(users.User)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = returnFunc(accessToken)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Provider_UserInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UserInfo'
|
||||
type Provider_UserInfo_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// UserInfo is a helper method to define mock.On call
|
||||
// - accessToken string
|
||||
func (_e *Provider_Expecter) UserInfo(accessToken interface{}) *Provider_UserInfo_Call {
|
||||
return &Provider_UserInfo_Call{Call: _e.mock.On("UserInfo", accessToken)}
|
||||
}
|
||||
|
||||
func (_c *Provider_UserInfo_Call) Run(run func(accessToken string)) *Provider_UserInfo_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 string
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(string)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_UserInfo_Call) Return(user users.User, err error) *Provider_UserInfo_Call {
|
||||
_c.Call.Return(user, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_UserInfo_Call) RunAndReturn(run func(accessToken string) (users.User, error)) *Provider_UserInfo_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/absmach/magistrala/users"
|
||||
)
|
||||
|
||||
type normalizedUser struct {
|
||||
ID string `json:"id"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Picture string `json:"picture"`
|
||||
}
|
||||
|
||||
func NormalizeUser(data []byte, provider string) (users.User, error) {
|
||||
var raw map[string]any
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return users.User{}, err
|
||||
}
|
||||
|
||||
normalized := normalizeProfile(raw)
|
||||
|
||||
userBytes, err := json.Marshal(normalized)
|
||||
if err != nil {
|
||||
return users.User{}, err
|
||||
}
|
||||
|
||||
var user normalizedUser
|
||||
if err := json.Unmarshal(userBytes, &user); err != nil {
|
||||
return users.User{}, err
|
||||
}
|
||||
|
||||
if err := validateUser(user); err != nil {
|
||||
return users.User{}, err
|
||||
}
|
||||
|
||||
return users.User{
|
||||
ID: user.ID,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Email: user.Email,
|
||||
ProfilePicture: user.Picture,
|
||||
Metadata: users.Metadata{"oauth_provider": provider},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func normalizeProfile(raw map[string]any) map[string]any {
|
||||
normalized := make(map[string]any)
|
||||
|
||||
keyMap := map[string][]string{
|
||||
"id": {"id"},
|
||||
"first_name": {"given_name", "first_name", "givenName", "firstname"},
|
||||
"last_name": {"family_name", "last_name", "familyName", "lastname"},
|
||||
"username": {"username", "user_name", "userName"},
|
||||
"email": {"email", "email_address", "emailAddress"},
|
||||
"picture": {"picture", "profile_picture", "profilePicture", "avatar"},
|
||||
}
|
||||
|
||||
for stdKey, variants := range keyMap {
|
||||
for _, variant := range variants {
|
||||
if val, ok := raw[variant]; ok {
|
||||
normalized[stdKey] = val
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
func validateUser(user normalizedUser) error {
|
||||
var missing []string
|
||||
if user.ID == "" {
|
||||
missing = append(missing, "id")
|
||||
}
|
||||
if user.FirstName == "" {
|
||||
missing = append(missing, "first_name")
|
||||
}
|
||||
if user.LastName == "" {
|
||||
missing = append(missing, "last_name")
|
||||
}
|
||||
if user.Email == "" {
|
||||
missing = append(missing, "email")
|
||||
}
|
||||
if len(missing) > 0 {
|
||||
return fmt.Errorf("missing required fields: %s", strings.Join(missing, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/magistrala/users"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNormalizeUser(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
inputJSON string
|
||||
provider string
|
||||
wantUser users.User
|
||||
wantErrStr string
|
||||
}{
|
||||
{
|
||||
desc: "valid user with standard keys",
|
||||
inputJSON: `{
|
||||
"id": "123",
|
||||
"given_name": "Jane",
|
||||
"family_name": "Doe",
|
||||
"email": "jane@example.com",
|
||||
"picture": "pic.jpg"
|
||||
}`,
|
||||
provider: "google",
|
||||
wantUser: users.User{
|
||||
ID: "123",
|
||||
FirstName: "Jane",
|
||||
LastName: "Doe",
|
||||
Email: "jane@example.com",
|
||||
ProfilePicture: "pic.jpg",
|
||||
Metadata: users.Metadata{"oauth_provider": "google"},
|
||||
},
|
||||
wantErrStr: "",
|
||||
},
|
||||
{
|
||||
desc: "missing required fields",
|
||||
inputJSON: `{
|
||||
"given_name": "Jane"
|
||||
}`,
|
||||
provider: "google",
|
||||
wantUser: users.User{},
|
||||
wantErrStr: "missing required fields: id, last_name, email",
|
||||
},
|
||||
{
|
||||
desc: "invalid JSON",
|
||||
inputJSON: `{invalid json`,
|
||||
provider: "google",
|
||||
wantUser: users.User{},
|
||||
wantErrStr: "invalid character",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
user, err := NormalizeUser([]byte(tc.inputJSON), tc.provider)
|
||||
if tc.wantErrStr != "" {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tc.wantErrStr)
|
||||
assert.Equal(t, tc.wantUser, user)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.wantUser, user)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeProfile(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
raw map[string]any
|
||||
expected map[string]any
|
||||
}{
|
||||
{
|
||||
desc: "maps all variants to normalized keys",
|
||||
raw: map[string]any{
|
||||
"id": "id123",
|
||||
"givenName": "John",
|
||||
"familyName": "Smith",
|
||||
"user_name": "jsmith",
|
||||
"emailAddress": "john@smith.com",
|
||||
"profilePicture": "pic.png",
|
||||
},
|
||||
expected: map[string]any{
|
||||
"id": "id123",
|
||||
"first_name": "John",
|
||||
"last_name": "Smith",
|
||||
"username": "jsmith",
|
||||
"email": "john@smith.com",
|
||||
"picture": "pic.png",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "missing keys returns empty map",
|
||||
raw: map[string]any{"foo": "bar"},
|
||||
expected: map[string]any{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got := normalizeProfile(tc.raw)
|
||||
assert.Equal(t, tc.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateUser(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
user normalizedUser
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
desc: "valid user returns nil error",
|
||||
user: normalizedUser{
|
||||
ID: "1",
|
||||
FirstName: "F",
|
||||
LastName: "L",
|
||||
Email: "e@example.com",
|
||||
},
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
desc: "missing id returns error",
|
||||
user: normalizedUser{
|
||||
FirstName: "F",
|
||||
LastName: "L",
|
||||
Email: "e@example.com",
|
||||
},
|
||||
wantErr: "missing required fields: id",
|
||||
},
|
||||
{
|
||||
desc: "multiple missing fields returns all in error",
|
||||
user: normalizedUser{},
|
||||
wantErr: "missing required fields: id, first_name, last_name, email",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
err := validateUser(tc.user)
|
||||
if tc.wantErr == "" {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, tc.wantErr, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/magistrala/users"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// Config is the configuration for the OAuth2 provider.
|
||||
type Config struct {
|
||||
ClientID string `env:"CLIENT_ID" envDefault:""`
|
||||
ClientSecret string `env:"CLIENT_SECRET" envDefault:""`
|
||||
State string `env:"STATE" envDefault:""`
|
||||
RedirectURL string `env:"REDIRECT_URL" envDefault:""`
|
||||
}
|
||||
|
||||
// Provider is an interface that provides the OAuth2 flow for a specific provider
|
||||
// (e.g. Google, GitHub, etc.)
|
||||
type Provider interface {
|
||||
// Name returns the name of the OAuth2 provider.
|
||||
Name() string
|
||||
|
||||
// State returns the current state for the OAuth2 flow.
|
||||
State() string
|
||||
|
||||
// RedirectURL returns the URL to redirect the user to after completing the OAuth2 flow.
|
||||
RedirectURL() string
|
||||
|
||||
// ErrorURL returns the URL to redirect the user to in case of an error during the OAuth2 flow.
|
||||
ErrorURL() string
|
||||
|
||||
// IsEnabled checks if the OAuth2 provider is enabled.
|
||||
IsEnabled() bool
|
||||
|
||||
// Exchange converts an authorization code into a token.
|
||||
Exchange(ctx context.Context, code string) (oauth2.Token, error)
|
||||
|
||||
// UserInfo retrieves the user's information using the access token.
|
||||
UserInfo(accessToken string) (users.User, error)
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/alarms"
|
||||
"github.com/absmach/magistrala/alarms/api"
|
||||
amocks "github.com/absmach/magistrala/alarms/mocks"
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
smqauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/absmach/magistrala/pkg/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
const alarmID = "alarm-1"
|
||||
|
||||
var testAlarm = sdk.Alarm{
|
||||
ID: alarmID,
|
||||
RuleID: "rule-1",
|
||||
DomainID: domainID,
|
||||
ChannelID: "chan-1",
|
||||
ClientID: "client-1",
|
||||
Subtopic: "subtopic",
|
||||
Status: "active",
|
||||
Measurement: "temperature",
|
||||
Value: "30.5",
|
||||
Unit: "C",
|
||||
Threshold: "25",
|
||||
Cause: "threshold_exceeded",
|
||||
Severity: 80,
|
||||
AssigneeID: "user-1",
|
||||
Metadata: sdk.Metadata{"key": "value"},
|
||||
}
|
||||
|
||||
func setupAlarms() (*httptest.Server, *amocks.Service, *authnmocks.Authentication) {
|
||||
asvc := new(amocks.Service)
|
||||
logger := mglog.NewMock()
|
||||
authn := new(authnmocks.Authentication)
|
||||
am := smqauthn.NewAuthNMiddleware(authn, smqauthn.WithAllowUnverifiedUser(true))
|
||||
idp := uuid.NewMock()
|
||||
mux := api.MakeHandler(asvc, logger, idp, "", am)
|
||||
return httptest.NewServer(mux), asvc, authn
|
||||
}
|
||||
|
||||
func TestUpdateAlarm(t *testing.T) {
|
||||
as, asvc, auth := setupAlarms()
|
||||
defer as.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
AlarmsURL: as.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
updated := testAlarm
|
||||
updated.Status = "cleared"
|
||||
|
||||
svcAlarm := alarms.Alarm{
|
||||
ID: alarmID,
|
||||
RuleID: "rule-1",
|
||||
DomainID: domainID,
|
||||
ChannelID: "chan-1",
|
||||
ClientID: "client-1",
|
||||
Subtopic: "subtopic",
|
||||
Status: alarms.ClearedStatus,
|
||||
Measurement: "temperature",
|
||||
Value: "30.5",
|
||||
Unit: "C",
|
||||
Threshold: "25",
|
||||
Cause: "threshold_exceeded",
|
||||
Severity: 80,
|
||||
AssigneeID: "user-1",
|
||||
Metadata: alarms.Metadata{"key": "value"},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
alarm sdk.Alarm
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes alarms.Alarm
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
resp sdk.Alarm
|
||||
}{
|
||||
{
|
||||
desc: "update alarm successfully",
|
||||
alarm: updated,
|
||||
token: validToken,
|
||||
svcRes: svcAlarm,
|
||||
resp: testAlarm,
|
||||
},
|
||||
{
|
||||
desc: "update alarm with empty token",
|
||||
alarm: updated,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "update non-existent alarm",
|
||||
alarm: sdk.Alarm{ID: "non-existent"},
|
||||
token: validToken,
|
||||
svcErr: errors.New("not found"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := asvc.On("UpdateAlarm", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.UpdateAlarm(context.Background(), tc.alarm, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewAlarm(t *testing.T) {
|
||||
as, asvc, auth := setupAlarms()
|
||||
defer as.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
AlarmsURL: as.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcAlarm := alarms.Alarm{
|
||||
ID: alarmID,
|
||||
RuleID: "rule-1",
|
||||
DomainID: domainID,
|
||||
ChannelID: "chan-1",
|
||||
ClientID: "client-1",
|
||||
Subtopic: "subtopic",
|
||||
Status: alarms.ActiveStatus,
|
||||
Measurement: "temperature",
|
||||
Value: "30.5",
|
||||
Unit: "C",
|
||||
Threshold: "25",
|
||||
Cause: "threshold_exceeded",
|
||||
Severity: 80,
|
||||
AssigneeID: "user-1",
|
||||
Metadata: alarms.Metadata{"key": "value"},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes alarms.Alarm
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "view alarm successfully",
|
||||
id: alarmID,
|
||||
token: validToken,
|
||||
svcRes: svcAlarm,
|
||||
},
|
||||
{
|
||||
desc: "view alarm with empty token",
|
||||
id: alarmID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "view non-existent alarm",
|
||||
id: "non-existent",
|
||||
token: validToken,
|
||||
svcErr: errors.New("not found"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := asvc.On("ViewAlarm", mock.Anything, tc.session, tc.id).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.ViewAlarm(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAlarms(t *testing.T) {
|
||||
as, asvc, auth := setupAlarms()
|
||||
defer as.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
AlarmsURL: as.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcAlarm := alarms.Alarm{
|
||||
ID: alarmID,
|
||||
RuleID: "rule-1",
|
||||
DomainID: domainID,
|
||||
ChannelID: "chan-1",
|
||||
ClientID: "client-1",
|
||||
Subtopic: "subtopic",
|
||||
Status: alarms.ActiveStatus,
|
||||
Measurement: "temperature",
|
||||
Value: "30.5",
|
||||
Unit: "C",
|
||||
Threshold: "25",
|
||||
Cause: "threshold_exceeded",
|
||||
Severity: 80,
|
||||
AssigneeID: "user-1",
|
||||
Metadata: alarms.Metadata{"key": "value"},
|
||||
}
|
||||
|
||||
svcAlarmsPage := alarms.AlarmsPage{
|
||||
Total: 2,
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Alarms: []alarms.Alarm{svcAlarm},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
pm sdk.PageMetadata
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes alarms.AlarmsPage
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "list alarms successfully",
|
||||
pm: sdk.PageMetadata{Offset: 0, Limit: 10},
|
||||
token: validToken,
|
||||
svcRes: svcAlarmsPage,
|
||||
},
|
||||
{
|
||||
desc: "list alarms with status and entity filters",
|
||||
pm: sdk.PageMetadata{
|
||||
Limit: 5,
|
||||
Status: "active",
|
||||
ChannelID: "chan-1",
|
||||
ClientID: "client-1",
|
||||
RuleID: "rule-1",
|
||||
AssigneeID: "user-1",
|
||||
Severity: 80,
|
||||
},
|
||||
token: validToken,
|
||||
svcRes: svcAlarmsPage,
|
||||
},
|
||||
{
|
||||
desc: "list alarms with time range and sorting",
|
||||
pm: sdk.PageMetadata{
|
||||
Limit: 10,
|
||||
CreatedFrom: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
CreatedTo: time.Date(2024, 12, 31, 0, 0, 0, 0, time.UTC),
|
||||
Order: "created_at",
|
||||
Dir: "asc",
|
||||
},
|
||||
token: validToken,
|
||||
svcRes: svcAlarmsPage,
|
||||
},
|
||||
{
|
||||
desc: "list alarms with actor filters",
|
||||
pm: sdk.PageMetadata{
|
||||
Limit: 10,
|
||||
UpdatedBy: "user-2",
|
||||
AssignedBy: "user-3",
|
||||
AcknowledgedBy: "user-4",
|
||||
ResolvedBy: "user-5",
|
||||
Subtopic: "subtopic-1",
|
||||
},
|
||||
token: validToken,
|
||||
svcRes: svcAlarmsPage,
|
||||
},
|
||||
{
|
||||
desc: "list alarms with empty metadata excludes severity",
|
||||
pm: sdk.PageMetadata{},
|
||||
token: validToken,
|
||||
svcRes: alarms.AlarmsPage{},
|
||||
},
|
||||
{
|
||||
desc: "list alarms with zero severity excluded",
|
||||
pm: sdk.PageMetadata{Status: "active", Severity: 0},
|
||||
token: validToken,
|
||||
svcRes: alarms.AlarmsPage{},
|
||||
},
|
||||
{
|
||||
desc: "list alarms with empty token",
|
||||
pm: sdk.PageMetadata{Limit: 10},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := asvc.On("ListAlarms", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.ListAlarms(context.Background(), tc.pm, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.Equal(t, tc.svcRes.Total, result.Total)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteAlarm(t *testing.T) {
|
||||
as, asvc, auth := setupAlarms()
|
||||
defer as.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
AlarmsURL: as.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "delete alarm successfully",
|
||||
id: alarmID,
|
||||
token: validToken,
|
||||
},
|
||||
{
|
||||
desc: "delete alarm with empty token",
|
||||
id: alarmID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "delete non-existent alarm",
|
||||
id: "non-existent",
|
||||
token: validToken,
|
||||
svcErr: errors.New("not found"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := asvc.On("DeleteAlarm", mock.Anything, tc.session, tc.id).Return(tc.svcErr)
|
||||
err := mgsdk.DeleteAlarm(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,77 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPageMetadataQueryWithCertFilters(t *testing.T) {
|
||||
pm := PageMetadata{
|
||||
EntityID: "entity-id",
|
||||
CommonName: "device-cn",
|
||||
Organization: []string{"Acme", "QA"},
|
||||
OrganizationalUnit: []string{"Platform"},
|
||||
Country: []string{"RS"},
|
||||
Province: []string{"Belgrade"},
|
||||
Locality: []string{"Belgrade"},
|
||||
StreetAddress: []string{"Nemanjina 4"},
|
||||
PostalCode: []string{"11000"},
|
||||
DNSNames: []string{"device.local"},
|
||||
IPAddresses: []string{"127.0.0.1"},
|
||||
EmailAddresses: []string{"device@example.com"},
|
||||
TTL: "24h",
|
||||
}
|
||||
|
||||
encoded, err := pm.query()
|
||||
require.NoError(t, err)
|
||||
|
||||
values, err := url.ParseQuery(encoded)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "entity-id", values.Get("entity_id"))
|
||||
assert.Equal(t, "device-cn", values.Get("common_name"))
|
||||
assert.Equal(t, "24h", values.Get("ttl"))
|
||||
assert.ElementsMatch(t, []string{"Acme", "QA"}, values["organization"])
|
||||
assert.Equal(t, []string{"Platform"}, values["organizational_unit"])
|
||||
assert.Equal(t, []string{"RS"}, values["country"])
|
||||
assert.Equal(t, []string{"Belgrade"}, values["province"])
|
||||
assert.Equal(t, []string{"Belgrade"}, values["locality"])
|
||||
assert.Equal(t, []string{"Nemanjina 4"}, values["street_address"])
|
||||
assert.Equal(t, []string{"11000"}, values["postal_code"])
|
||||
assert.Equal(t, []string{"device.local"}, values["dns_names"])
|
||||
assert.Equal(t, []string{"127.0.0.1"}, values["ip_addresses"])
|
||||
assert.Equal(t, []string{"device@example.com"}, values["email_addresses"])
|
||||
}
|
||||
|
||||
func TestCertStatusAliases(t *testing.T) {
|
||||
assert.Equal(t, CertValid, Valid)
|
||||
assert.Equal(t, CertRevoked, Revoked)
|
||||
assert.Equal(t, CertUnknown, Unknown)
|
||||
}
|
||||
|
||||
func TestCertTypeString(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
typ CertType
|
||||
expected string
|
||||
}{
|
||||
{desc: "root", typ: RootCA, expected: "root"},
|
||||
{desc: "intermediate", typ: IntermediateCA, expected: "intermediate"},
|
||||
{desc: "unknown", typ: CertType(99), expected: "unknown"},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
assert.Equal(t, tc.expected, tc.typ.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,457 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/consumers/notifiers"
|
||||
httpapi "github.com/absmach/magistrala/consumers/notifiers/api"
|
||||
notmocks "github.com/absmach/magistrala/consumers/notifiers/mocks"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
var (
|
||||
ownerID = testsutil.GenerateUUID(&testing.T{})
|
||||
subID = testsutil.GenerateUUID(&testing.T{})
|
||||
sdkSubReq = sdk.Subscription{
|
||||
Topic: "topic",
|
||||
Contact: "contact",
|
||||
}
|
||||
sdkSubRes = sdk.Subscription{
|
||||
Topic: "topic",
|
||||
Contact: "contact",
|
||||
OwnerID: ownerID,
|
||||
ID: subID,
|
||||
}
|
||||
notSubReq = notifiers.Subscription{
|
||||
Contact: "contact",
|
||||
Topic: "topic",
|
||||
}
|
||||
notSubRes = notifiers.Subscription{
|
||||
Contact: "contact",
|
||||
Topic: "topic",
|
||||
OwnerID: ownerID,
|
||||
ID: subID,
|
||||
}
|
||||
instanceID = "instanceID"
|
||||
)
|
||||
|
||||
func setupSubscriptions() (*httptest.Server, *notmocks.Service) {
|
||||
nsvc := new(notmocks.Service)
|
||||
logger := mglog.NewMock()
|
||||
mux := httpapi.MakeHandler(nsvc, logger, instanceID)
|
||||
|
||||
return httptest.NewServer(mux), nsvc
|
||||
}
|
||||
|
||||
func TestCreateSubscription(t *testing.T) {
|
||||
ts, nsvc := setupSubscriptions()
|
||||
defer ts.Close()
|
||||
|
||||
sdkConf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
MsgContentType: contentType,
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
subscription sdk.Subscription
|
||||
token string
|
||||
empty bool
|
||||
id string
|
||||
svcReq notifiers.Subscription
|
||||
svcErr error
|
||||
svcRes string
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "create new subscription",
|
||||
subscription: sdkSubReq,
|
||||
token: validToken,
|
||||
empty: false,
|
||||
svcReq: notSubReq,
|
||||
svcRes: subID,
|
||||
svcErr: nil,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "create new subscription with empty token",
|
||||
subscription: sdkSubReq,
|
||||
token: "",
|
||||
empty: true,
|
||||
svcReq: notifiers.Subscription{},
|
||||
svcRes: "",
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "create new subscription with invalid token",
|
||||
subscription: sdkSubReq,
|
||||
token: invalidToken,
|
||||
empty: true,
|
||||
svcReq: notSubReq,
|
||||
svcRes: "",
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "create new subscription with empty topic",
|
||||
subscription: sdk.Subscription{
|
||||
Topic: "",
|
||||
Contact: "contact",
|
||||
},
|
||||
token: validToken,
|
||||
empty: true,
|
||||
svcReq: notifiers.Subscription{},
|
||||
svcErr: nil,
|
||||
svcRes: "",
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidTopic, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "create new subscription with empty contact",
|
||||
subscription: sdk.Subscription{
|
||||
Topic: "topic",
|
||||
Contact: "",
|
||||
},
|
||||
token: validToken,
|
||||
empty: true,
|
||||
svcReq: notifiers.Subscription{},
|
||||
svcErr: nil,
|
||||
svcRes: "",
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidContact, http.StatusBadRequest),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := nsvc.On("CreateSubscription", mock.Anything, tc.token, tc.svcReq).Return(tc.svcRes, tc.svcErr)
|
||||
loc, err := mgsdk.CreateSubscription(context.Background(), tc.subscription.Topic, tc.subscription.Contact, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.empty, loc == "")
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "CreateSubscription", mock.Anything, tc.token, tc.svcReq)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewSubscription(t *testing.T) {
|
||||
ts, nsvc := setupSubscriptions()
|
||||
defer ts.Close()
|
||||
sdkConf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
MsgContentType: contentType,
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
subID string
|
||||
token string
|
||||
svcRes notifiers.Subscription
|
||||
svcErr error
|
||||
response sdk.Subscription
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "view existing subscription",
|
||||
subID: subID,
|
||||
token: validToken,
|
||||
svcRes: notSubRes,
|
||||
svcErr: nil,
|
||||
response: sdkSubRes,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "view non-existent subscription",
|
||||
subID: wrongID,
|
||||
token: validToken,
|
||||
svcRes: notifiers.Subscription{},
|
||||
svcErr: svcerr.ErrNotFound,
|
||||
response: sdk.Subscription{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
{
|
||||
desc: "view subscription with invalid token",
|
||||
subID: subID,
|
||||
token: invalidToken,
|
||||
svcRes: notifiers.Subscription{},
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
response: sdk.Subscription{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "view subscription with empty token",
|
||||
subID: subID,
|
||||
token: "",
|
||||
svcRes: notifiers.Subscription{},
|
||||
svcErr: nil,
|
||||
response: sdk.Subscription{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := nsvc.On("ViewSubscription", mock.Anything, tc.token, tc.subID).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.ViewSubscription(context.Background(), tc.subID, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "ViewSubscription", mock.Anything, tc.token, tc.subID)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListSubscription(t *testing.T) {
|
||||
ts, nsvc := setupSubscriptions()
|
||||
defer ts.Close()
|
||||
sdkConf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
MsgContentType: contentType,
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
nSubs := 10
|
||||
noSubs := []notifiers.Subscription{}
|
||||
sdSubs := []sdk.Subscription{}
|
||||
for i := 0; i < nSubs; i++ {
|
||||
nosub := notifiers.Subscription{
|
||||
OwnerID: ownerID,
|
||||
Topic: fmt.Sprintf("topic_%d", i),
|
||||
Contact: fmt.Sprintf("contact_%d", i),
|
||||
}
|
||||
noSubs = append(noSubs, nosub)
|
||||
sdsub := sdk.Subscription{
|
||||
OwnerID: ownerID,
|
||||
Topic: fmt.Sprintf("topic_%d", i),
|
||||
Contact: fmt.Sprintf("contact_%d", i),
|
||||
}
|
||||
sdSubs = append(sdSubs, sdsub)
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
pageMeta sdk.PageMetadata
|
||||
svcReq notifiers.PageMetadata
|
||||
svcRes notifiers.Page
|
||||
svcErr error
|
||||
response sdk.SubscriptionPage
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "list all subscription",
|
||||
token: validToken,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: notifiers.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcRes: notifiers.Page{
|
||||
Total: 10,
|
||||
Subscriptions: noSubs,
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.SubscriptionPage{
|
||||
PageRes: sdk.PageRes{
|
||||
Total: 10,
|
||||
},
|
||||
Subscriptions: sdSubs,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list subscription with specific topic",
|
||||
token: validToken,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Topic: "topic_1",
|
||||
},
|
||||
svcReq: notifiers.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Topic: "topic_1",
|
||||
},
|
||||
svcRes: notifiers.Page{
|
||||
Total: uint(len(noSubs[1:2])),
|
||||
Subscriptions: noSubs[1:2],
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.SubscriptionPage{
|
||||
PageRes: sdk.PageRes{
|
||||
Total: uint64(len(sdSubs[1:2])),
|
||||
},
|
||||
Subscriptions: sdSubs[1:2],
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list subscription with specific contact",
|
||||
token: validToken,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Contact: "contact_1",
|
||||
},
|
||||
svcReq: notifiers.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Contact: "contact_1",
|
||||
},
|
||||
svcRes: notifiers.Page{
|
||||
Total: uint(len(noSubs[1:2])),
|
||||
Subscriptions: noSubs[1:2],
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.SubscriptionPage{
|
||||
PageRes: sdk.PageRes{
|
||||
Total: uint64(len(sdSubs[1:2])),
|
||||
},
|
||||
Subscriptions: sdSubs[1:2],
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list subscription with invalid token",
|
||||
token: invalidToken,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: notifiers.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcRes: notifiers.Page{},
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
response: sdk.SubscriptionPage{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "list subscription with empty token",
|
||||
token: "",
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: notifiers.PageMetadata{},
|
||||
svcRes: notifiers.Page{},
|
||||
svcErr: nil,
|
||||
response: sdk.SubscriptionPage{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := nsvc.On("ListSubscriptions", mock.Anything, tc.token, tc.svcReq).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.ListSubscriptions(context.Background(), tc.pageMeta, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "ListSubscriptions", mock.Anything, tc.token, tc.svcReq)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteSubscription(t *testing.T) {
|
||||
ts, nsvc := setupSubscriptions()
|
||||
defer ts.Close()
|
||||
sdkConf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
MsgContentType: contentType,
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
subID string
|
||||
token string
|
||||
svcErr error
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "delete existing subscription",
|
||||
subID: subID,
|
||||
token: validToken,
|
||||
svcErr: nil,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete non-existent subscription",
|
||||
subID: wrongID,
|
||||
token: validToken,
|
||||
svcErr: svcerr.ErrRemoveEntity,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrRemoveEntity, http.StatusUnprocessableEntity),
|
||||
},
|
||||
{
|
||||
desc: "delete subscription with invalid token",
|
||||
subID: subID,
|
||||
token: invalidToken,
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "delete subscription with empty token",
|
||||
subID: subID,
|
||||
token: "",
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "delete subscription with empty subID",
|
||||
subID: "",
|
||||
token: validToken,
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := nsvc.On("RemoveSubscription", mock.Anything, tc.token, tc.subID).Return(tc.svcErr)
|
||||
err := mgsdk.DeleteSubscription(context.Background(), tc.subID, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "RemoveSubscription", mock.Anything, tc.token, tc.subID)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,129 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
sdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHealth(t *testing.T) {
|
||||
clientsTs, _, _ := setupClients()
|
||||
defer clientsTs.Close()
|
||||
|
||||
usersTs, _, _ := setupUsers()
|
||||
defer usersTs.Close()
|
||||
|
||||
groupsTs, _, _ := setupGroups()
|
||||
defer groupsTs.Close()
|
||||
|
||||
channelsTs, _, _ := setupChannels()
|
||||
defer channelsTs.Close()
|
||||
|
||||
domainsTs, _, _ := setupDomains()
|
||||
defer domainsTs.Close()
|
||||
|
||||
journalTs, _, _ := setupJournal()
|
||||
defer journalTs.Close()
|
||||
|
||||
fluxmqTs := setupFluxMQ("any")
|
||||
defer fluxmqTs.Close()
|
||||
|
||||
sdkConf := sdk.Config{
|
||||
ClientsURL: clientsTs.URL,
|
||||
UsersURL: usersTs.URL,
|
||||
HTTPAdapterURL: fluxmqTs.URL,
|
||||
GroupsURL: groupsTs.URL,
|
||||
ChannelsURL: channelsTs.URL,
|
||||
DomainsURL: domainsTs.URL,
|
||||
JournalURL: journalTs.URL,
|
||||
MsgContentType: contentType,
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
cases := []struct {
|
||||
desc string
|
||||
service string
|
||||
empty bool
|
||||
description string
|
||||
status string
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "get clients service health check",
|
||||
service: "clients",
|
||||
empty: false,
|
||||
err: nil,
|
||||
description: "clients service",
|
||||
status: "pass",
|
||||
},
|
||||
{
|
||||
desc: "get users service health check",
|
||||
service: "users",
|
||||
empty: false,
|
||||
err: nil,
|
||||
description: "users service",
|
||||
status: "pass",
|
||||
},
|
||||
{
|
||||
desc: "get groups service health check",
|
||||
service: "groups",
|
||||
empty: false,
|
||||
err: nil,
|
||||
description: "groups service",
|
||||
status: "pass",
|
||||
},
|
||||
{
|
||||
desc: "get channels service health check",
|
||||
service: "channels",
|
||||
empty: false,
|
||||
err: nil,
|
||||
description: "channels service",
|
||||
status: "pass",
|
||||
},
|
||||
{
|
||||
desc: "get domains service health check",
|
||||
service: "domains",
|
||||
empty: false,
|
||||
err: nil,
|
||||
description: "domains service",
|
||||
status: "pass",
|
||||
},
|
||||
{
|
||||
desc: "get journal service health check",
|
||||
service: "journal",
|
||||
empty: false,
|
||||
err: nil,
|
||||
description: "journal-log service",
|
||||
status: "pass",
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
h, err := mgsdk.Health(tc.service)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.status, h.Status, fmt.Sprintf("%s: expected %s status, got %s", tc.desc, tc.status, h.Status))
|
||||
assert.Equal(t, tc.empty, h.Version == "", fmt.Sprintf("%s: expected non-empty version", tc.desc))
|
||||
assert.Equal(t, magistrala.Commit, h.Commit, fmt.Sprintf("%s: expected non-empty commit", tc.desc))
|
||||
assert.Equal(t, tc.description, h.Description, fmt.Sprintf("%s: expected proper description, got %s", tc.desc, h.Description))
|
||||
assert.Equal(t, magistrala.BuildTime, h.BuildTime, fmt.Sprintf("%s: expected default epoch date, got %s", tc.desc, h.BuildTime))
|
||||
})
|
||||
}
|
||||
|
||||
// FluxMQ returns a simpler health response without version/commit/description.
|
||||
t.Run("get fluxmq service health check", func(t *testing.T) {
|
||||
h, err := mgsdk.Health("fluxmq")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "healthy", h.Status)
|
||||
})
|
||||
}
|
||||
@@ -1,471 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/domains"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
smqauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
sdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
var (
|
||||
sdkInvitation = generateTestInvitation(&testing.T{})
|
||||
invitation = convertInvitation(sdkInvitation)
|
||||
)
|
||||
|
||||
func TestSendInvitation(t *testing.T) {
|
||||
is, svc, auth := setupDomains()
|
||||
defer is.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
DomainsURL: is.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
sendInvitationReq := sdk.Invitation{
|
||||
InviteeUserID: invitation.InviteeUserID,
|
||||
DomainID: invitation.DomainID,
|
||||
RoleID: invitation.RoleID,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
sendInvitationReq sdk.Invitation
|
||||
svcReq domains.Invitation
|
||||
authenticateErr error
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "send invitation successfully",
|
||||
token: validToken,
|
||||
sendInvitationReq: sendInvitationReq,
|
||||
svcReq: convertInvitation(sendInvitationReq),
|
||||
svcErr: nil,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "send invitation with invalid token",
|
||||
token: invalidToken,
|
||||
sendInvitationReq: sendInvitationReq,
|
||||
svcReq: convertInvitation(sendInvitationReq),
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "send invitation with empty token",
|
||||
token: "",
|
||||
sendInvitationReq: sendInvitationReq,
|
||||
svcReq: domains.Invitation{},
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "send invitation with empty userID",
|
||||
token: validToken,
|
||||
sendInvitationReq: sdk.Invitation{
|
||||
InviteeUserID: "",
|
||||
DomainID: invitation.DomainID,
|
||||
RoleID: invitation.RoleID,
|
||||
},
|
||||
svcReq: domains.Invitation{},
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "send invitation with empty role ID",
|
||||
token: validToken,
|
||||
sendInvitationReq: sdk.Invitation{
|
||||
InviteeUserID: invitation.InviteeUserID,
|
||||
DomainID: invitation.DomainID,
|
||||
RoleID: "",
|
||||
},
|
||||
svcReq: domains.Invitation{},
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "send inviation with invalid domainID",
|
||||
token: validToken,
|
||||
sendInvitationReq: sdk.Invitation{
|
||||
InviteeUserID: invitation.InviteeUserID,
|
||||
DomainID: wrongID,
|
||||
RoleID: invitation.RoleID,
|
||||
},
|
||||
svcReq: domains.Invitation{
|
||||
InviteeUserID: invitation.InviteeUserID,
|
||||
DomainID: wrongID,
|
||||
RoleID: invitation.RoleID,
|
||||
},
|
||||
svcErr: svcerr.ErrCreateEntity,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrCreateEntity, http.StatusUnprocessableEntity),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == valid {
|
||||
tc.session = smqauthn.Session{
|
||||
UserID: tc.sendInvitationReq.InviteeUserID,
|
||||
DomainID: tc.sendInvitationReq.DomainID,
|
||||
DomainUserID: fmt.Sprintf("%s_%s", tc.sendInvitationReq.DomainID, tc.sendInvitationReq.InviteeUserID),
|
||||
}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("SendInvitation", mock.Anything, tc.session, tc.svcReq).Return(domains.Invitation{}, tc.svcErr)
|
||||
err := mgsdk.SendInvitation(context.Background(), tc.sendInvitationReq, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "SendInvitation", mock.Anything, tc.session, tc.svcReq)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListInvitation(t *testing.T) {
|
||||
is, svc, auth := setupDomains()
|
||||
defer is.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
DomainsURL: is.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
pageMeta sdk.PageMetadata
|
||||
svcReq domains.InvitationPageMeta
|
||||
svcRes domains.InvitationPage
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
response sdk.InvitationPage
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "list invitations successfully",
|
||||
token: validToken,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: domains.InvitationPageMeta{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcRes: domains.InvitationPage{
|
||||
Total: 1,
|
||||
Invitations: []domains.Invitation{invitation},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.InvitationPage{
|
||||
Total: 1,
|
||||
Invitations: []sdk.Invitation{sdkInvitation},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list invitations with invalid token",
|
||||
token: invalidToken,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: domains.InvitationPageMeta{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcRes: domains.InvitationPage{},
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
response: sdk.InvitationPage{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "list invitations with empty token",
|
||||
token: "",
|
||||
pageMeta: sdk.PageMetadata{},
|
||||
svcRes: domains.InvitationPage{},
|
||||
svcErr: nil,
|
||||
response: sdk.InvitationPage{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "list invitations with limit greater than max limit",
|
||||
token: validToken,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 101,
|
||||
},
|
||||
svcReq: domains.InvitationPageMeta{},
|
||||
svcRes: domains.InvitationPage{},
|
||||
svcErr: nil,
|
||||
response: sdk.InvitationPage{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == valid {
|
||||
tc.session = smqauthn.Session{DomainUserID: validID, UserID: validID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("ListInvitations", mock.Anything, tc.session, tc.svcReq).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.Invitations(context.Background(), tc.pageMeta, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "ListInvitations", mock.Anything, tc.session, tc.svcReq)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptInvitation(t *testing.T) {
|
||||
is, svc, auth := setupDomains()
|
||||
defer is.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
DomainsURL: is.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
domainID string
|
||||
authenticateErr error
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "accept invitation successfully",
|
||||
token: validToken,
|
||||
domainID: invitation.DomainID,
|
||||
svcErr: nil,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "accept invitation with invalid token",
|
||||
token: invalidToken,
|
||||
domainID: invitation.DomainID,
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "accept invitation with empty token",
|
||||
token: "",
|
||||
domainID: invitation.DomainID,
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "accept invitation with invalid domainID",
|
||||
token: validToken,
|
||||
domainID: wrongID,
|
||||
svcErr: svcerr.ErrNotFound,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == valid {
|
||||
tc.session = smqauthn.Session{DomainUserID: validID, UserID: validID, DomainID: validID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("AcceptInvitation", mock.Anything, tc.session, tc.domainID).Return(domains.Invitation{}, tc.svcErr)
|
||||
err := mgsdk.AcceptInvitation(context.Background(), tc.domainID, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "AcceptInvitation", mock.Anything, tc.session, tc.domainID)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRejectInvitation(t *testing.T) {
|
||||
is, svc, auth := setupDomains()
|
||||
defer is.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
DomainsURL: is.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
domainID string
|
||||
authenticateErr error
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "reject invitation successfully",
|
||||
token: validToken,
|
||||
domainID: invitation.DomainID,
|
||||
svcErr: nil,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "reject invitation with invalid token",
|
||||
token: invalidToken,
|
||||
domainID: invitation.DomainID,
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "reject invitation with empty token",
|
||||
token: "",
|
||||
domainID: invitation.DomainID,
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "reject invitation with invalid domainID",
|
||||
token: validToken,
|
||||
domainID: wrongID,
|
||||
svcErr: svcerr.ErrNotFound,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == valid {
|
||||
tc.session = smqauthn.Session{DomainUserID: validID, UserID: validID, DomainID: validID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("RejectInvitation", mock.Anything, tc.session, tc.domainID).Return(domains.Invitation{}, tc.svcErr)
|
||||
err := mgsdk.RejectInvitation(context.Background(), tc.domainID, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "RejectInvitation", mock.Anything, tc.session, tc.domainID)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteInvitation(t *testing.T) {
|
||||
is, svc, auth := setupDomains()
|
||||
defer is.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
DomainsURL: is.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
inviteeUserID string
|
||||
domainID string
|
||||
authenticateErr error
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "delete invitation successfully",
|
||||
token: validToken,
|
||||
inviteeUserID: invitation.InviteeUserID,
|
||||
domainID: invitation.DomainID,
|
||||
svcErr: nil,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete invitation with invalid token",
|
||||
token: invalidToken,
|
||||
inviteeUserID: invitation.InviteeUserID,
|
||||
domainID: invitation.DomainID,
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "delete invitation with empty token",
|
||||
token: "",
|
||||
inviteeUserID: invitation.InviteeUserID,
|
||||
domainID: invitation.DomainID,
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "delete invitation with empty domainID",
|
||||
token: validToken,
|
||||
inviteeUserID: invitation.InviteeUserID,
|
||||
domainID: "",
|
||||
svcErr: nil,
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingDomainID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "delete invitation with invalid domainID",
|
||||
token: validToken,
|
||||
inviteeUserID: invitation.InviteeUserID,
|
||||
domainID: wrongID,
|
||||
svcErr: svcerr.ErrNotFound,
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == valid {
|
||||
tc.session = smqauthn.Session{UserID: tc.inviteeUserID, DomainID: tc.domainID, DomainUserID: fmt.Sprintf("%s_%s", tc.domainID, tc.inviteeUserID)}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("DeleteInvitation", mock.Anything, tc.session, tc.inviteeUserID, tc.domainID).Return(tc.svcErr)
|
||||
err := mgsdk.DeleteInvitation(context.Background(), tc.inviteeUserID, tc.domainID, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "DeleteInvitation", mock.Anything, tc.session, tc.inviteeUserID, tc.domainID)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func generateTestInvitation(t *testing.T) sdk.Invitation {
|
||||
createdAt, err := time.Parse(time.RFC3339, "2024-01-01T00:00:00Z")
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error parsing time: %v", err))
|
||||
return sdk.Invitation{
|
||||
InvitedBy: testsutil.GenerateUUID(t),
|
||||
InviteeUserID: testsutil.GenerateUUID(t),
|
||||
DomainID: testsutil.GenerateUUID(t),
|
||||
RoleID: testsutil.GenerateUUID(t),
|
||||
RoleName: "admin",
|
||||
Actions: []string{"read", "update"},
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: createdAt,
|
||||
}
|
||||
}
|
||||
@@ -1,364 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/journal"
|
||||
"github.com/absmach/magistrala/journal/api"
|
||||
"github.com/absmach/magistrala/journal/mocks"
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
smqauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
sdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func setupJournal() (*httptest.Server, *mocks.Service, *authnmocks.Authentication) {
|
||||
svc := new(mocks.Service)
|
||||
authn := new(authnmocks.Authentication)
|
||||
logger := mglog.NewMock()
|
||||
am := smqauthn.NewAuthNMiddleware(authn, smqauthn.WithAllowUnverifiedUser(true))
|
||||
mux := api.MakeHandler(svc, am, logger, "journal-log", "test")
|
||||
|
||||
return httptest.NewServer(mux), svc, authn
|
||||
}
|
||||
|
||||
func TestRetrieveJournal(t *testing.T) {
|
||||
js, svc, authn := setupJournal()
|
||||
defer js.Close()
|
||||
|
||||
testJournal := generateTestJournal(t)
|
||||
validEntityType := "group"
|
||||
|
||||
sdkConf := sdk.Config{
|
||||
JournalURL: js.URL,
|
||||
}
|
||||
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
entityType string
|
||||
entityID string
|
||||
domainID string
|
||||
pageMeta sdk.PageMetadata
|
||||
svcReq journal.Page
|
||||
svcRes journal.JournalsPage
|
||||
svcErr error
|
||||
authnErr error
|
||||
response sdk.JournalsPage
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "retrieve user journal successfully",
|
||||
token: validToken,
|
||||
entityType: "user",
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
EntityID: validID,
|
||||
EntityType: journal.UserEntity,
|
||||
Direction: "desc",
|
||||
},
|
||||
svcRes: journal.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []journal.Journal{convertJournal(testJournal)},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []sdk.Journal{testJournal},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "retrieve channel journal successfully",
|
||||
token: validToken,
|
||||
entityType: "channel",
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
EntityID: validID,
|
||||
EntityType: journal.ChannelEntity,
|
||||
Direction: "desc",
|
||||
},
|
||||
svcRes: journal.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []journal.Journal{convertJournal(testJournal)},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []sdk.Journal{testJournal},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "retrieve group journal successfully",
|
||||
token: validToken,
|
||||
entityType: "group",
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
EntityID: validID,
|
||||
EntityType: journal.GroupEntity,
|
||||
Direction: "desc",
|
||||
},
|
||||
svcRes: journal.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []journal.Journal{convertJournal(testJournal)},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []sdk.Journal{testJournal},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "retrieve client journal successfully",
|
||||
token: validToken,
|
||||
entityType: "client",
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
EntityID: validID,
|
||||
EntityType: journal.ClientEntity,
|
||||
Direction: "desc",
|
||||
},
|
||||
svcRes: journal.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []journal.Journal{convertJournal(testJournal)},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []sdk.Journal{testJournal},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "retrieve journal with invalid token",
|
||||
token: invalidToken,
|
||||
entityType: validEntityType,
|
||||
entityID: validID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
EntityID: validID,
|
||||
EntityType: journal.GroupEntity,
|
||||
Direction: "desc",
|
||||
},
|
||||
svcRes: journal.JournalsPage{},
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
response: sdk.JournalsPage{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "retrieve journal with empty token",
|
||||
token: "",
|
||||
entityType: validEntityType,
|
||||
entityID: validID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{},
|
||||
svcRes: journal.JournalsPage{},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "retrieve journal with invalid entity type",
|
||||
token: validToken,
|
||||
entityType: "invalid",
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{},
|
||||
svcRes: journal.JournalsPage{},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrInvalidEntityType, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "retrieve journal with empty entity ID",
|
||||
token: validToken,
|
||||
entityType: validEntityType,
|
||||
entityID: "",
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{},
|
||||
svcRes: journal.JournalsPage{},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{},
|
||||
err: errors.NewSDKError(apiutil.ErrMissingID),
|
||||
},
|
||||
{
|
||||
desc: "retrieve journal with empty entity type",
|
||||
token: validToken,
|
||||
entityType: "",
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{},
|
||||
svcRes: journal.JournalsPage{},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{},
|
||||
err: errors.NewSDKError(apiutil.ErrMissingEntityType),
|
||||
},
|
||||
{
|
||||
desc: "retrieve journal with limit greater than default",
|
||||
token: validToken,
|
||||
entityType: validEntityType,
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 1000,
|
||||
},
|
||||
svcReq: journal.Page{},
|
||||
svcRes: journal.JournalsPage{},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrLimitSize, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "retrieve journal with invalid page metadata",
|
||||
token: validToken,
|
||||
entityType: validEntityType,
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Metadata: map[string]any{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
svcReq: journal.Page{},
|
||||
svcRes: journal.JournalsPage{},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{},
|
||||
err: errors.NewSDKError(fmt.Errorf("json: unsupported type: chan int")),
|
||||
},
|
||||
{
|
||||
desc: "retrieve journal with response that cannot be unmarshalled",
|
||||
token: validToken,
|
||||
entityType: validEntityType,
|
||||
entityID: validID,
|
||||
domainID: domainID,
|
||||
pageMeta: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
svcReq: journal.Page{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
EntityID: validID,
|
||||
EntityType: journal.GroupEntity,
|
||||
Direction: "desc",
|
||||
},
|
||||
svcRes: journal.JournalsPage{
|
||||
Total: 1,
|
||||
Journals: []journal.Journal{{
|
||||
ID: validID,
|
||||
Operation: "create",
|
||||
OccurredAt: time.Now(),
|
||||
Attributes: validMetadata,
|
||||
Metadata: map[string]any{
|
||||
"key": make(chan int),
|
||||
},
|
||||
}},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.JournalsPage{},
|
||||
err: errors.NewSDKError(fmt.Errorf("unexpected end of JSON input")),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: fmt.Sprintf("%s_%s", domainID, validID), UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := authn.On("Authenticate", mock.Anything, mock.Anything).Return(tc.session, tc.authnErr)
|
||||
svcCall := svc.On("RetrieveAll", mock.Anything, tc.session, tc.svcReq).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.Journal(context.Background(), tc.entityType, tc.entityID, tc.domainID, tc.pageMeta, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "RetrieveAll", mock.Anything, tc.session, tc.svcReq)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func generateTestJournal(t *testing.T) sdk.Journal {
|
||||
occuredAt, err := time.Parse(time.RFC3339, "2024-01-01T00:00:00Z")
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error parsing time: %v", err))
|
||||
return sdk.Journal{
|
||||
ID: validID,
|
||||
Operation: "create",
|
||||
OccurredAt: occuredAt,
|
||||
Attributes: validMetadata,
|
||||
Metadata: validMetadata,
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
sdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type publishReq struct {
|
||||
Topic string `json:"topic"`
|
||||
Payload []byte `json:"payload"`
|
||||
QoS byte `json:"qos"`
|
||||
Retain bool `json:"retain"`
|
||||
}
|
||||
|
||||
func setupFluxMQ(secret string, expectedTopic ...string) *httptest.Server {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.HandleFunc("POST /publish", func(w http.ResponseWriter, r *http.Request) {
|
||||
username := r.Header.Get("X-FluxMQ-Username")
|
||||
auth := r.Header.Get("Authorization")
|
||||
if username == "" || auth == "" || auth != "Bearer "+secret {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
var req publishReq
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
http.Error(w, "invalid json", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Topic == "" {
|
||||
http.Error(w, "empty topic", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if len(expectedTopic) > 0 && req.Topic != expectedTopic[0] {
|
||||
http.Error(w, fmt.Sprintf("unexpected topic: %s", req.Topic), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, `{"status":"ok"}`)
|
||||
})
|
||||
|
||||
mux.HandleFunc("GET /health", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, `{"status":"healthy"}`)
|
||||
})
|
||||
|
||||
return httptest.NewServer(mux)
|
||||
}
|
||||
|
||||
func TestSendMessage(t *testing.T) {
|
||||
clientSecret := "validSecret"
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
topic string
|
||||
domainID string
|
||||
wantTopic string
|
||||
msg string
|
||||
secret string
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "publish message successfully",
|
||||
topic: "channelID",
|
||||
domainID: "domainID",
|
||||
wantTopic: "m/domainID/c/channelID",
|
||||
msg: `[{"n":"current","t":-1,"v":1.6}]`,
|
||||
secret: clientSecret,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "publish message with subtopic",
|
||||
topic: "channelID/sub/topic",
|
||||
domainID: "domainID",
|
||||
wantTopic: "m/domainID/c/channelID/sub/topic",
|
||||
msg: `[{"n":"current","t":-1,"v":1.6}]`,
|
||||
secret: clientSecret,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "publish message with invalid secret",
|
||||
topic: "channelID",
|
||||
domainID: "domainID",
|
||||
wantTopic: "m/domainID/c/channelID",
|
||||
msg: `[{"n":"current","t":-1,"v":1.6}]`,
|
||||
secret: "invalid",
|
||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(errors.New(""), errors.New("")), http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "publish message with empty secret",
|
||||
topic: "channelID",
|
||||
domainID: "domainID",
|
||||
wantTopic: "m/domainID/c/channelID",
|
||||
msg: `[{"n":"current","t":-1,"v":1.6}]`,
|
||||
secret: "",
|
||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(errors.New(""), errors.New("")), http.StatusUnauthorized),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
ts := setupFluxMQ(clientSecret, tc.wantTopic)
|
||||
defer ts.Close()
|
||||
|
||||
sdkConf := sdk.Config{
|
||||
HTTPAdapterURL: ts.URL,
|
||||
MsgContentType: "application/senml+json",
|
||||
TLSVerification: false,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
|
||||
err := mgsdk.SendMessage(context.Background(), tc.domainID, tc.topic, tc.msg, tc.secret)
|
||||
if tc.err != nil {
|
||||
assert.NotNil(t, err, fmt.Sprintf("%s: expected error, got nil", tc.desc))
|
||||
} else {
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error: %v", tc.desc, err))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetContentType(t *testing.T) {
|
||||
sdkConf := sdk.Config{
|
||||
MsgContentType: "application/senml+json",
|
||||
TLSVerification: false,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
cType sdk.ContentType
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "set senml+json content type",
|
||||
cType: "application/senml+json",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "set json content type",
|
||||
cType: "application/json",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "set invalid content type",
|
||||
cType: "invalid",
|
||||
err: errors.NewSDKError(apiutil.ErrUnsupportedContentType),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
err := mgsdk.SetContentType(tc.cType)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
grpcChannelsV1 "github.com/absmach/magistrala/api/grpc/channels/v1"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
chmocks "github.com/absmach/magistrala/channels/mocks"
|
||||
climocks "github.com/absmach/magistrala/clients/mocks"
|
||||
smqauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/absmach/magistrala/pkg/transformers/senml"
|
||||
"github.com/absmach/magistrala/readers"
|
||||
readersapi "github.com/absmach/magistrala/readers/api/http"
|
||||
readersmocks "github.com/absmach/magistrala/readers/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func setupReaders() (*httptest.Server, *authnmocks.Authentication, *readersmocks.MessageRepository) {
|
||||
repo := new(readersmocks.MessageRepository)
|
||||
authn := new(authnmocks.Authentication)
|
||||
clientsGRPCClient = new(climocks.ClientsServiceClient)
|
||||
channelsGRPCClient = new(chmocks.ChannelsServiceClient)
|
||||
|
||||
mux := readersapi.MakeHandler(repo, authn, clientsGRPCClient, channelsGRPCClient, "test", "")
|
||||
return httptest.NewServer(mux), authn, repo
|
||||
}
|
||||
|
||||
func TestReadMessages(t *testing.T) {
|
||||
ts, authn, repo := setupReaders()
|
||||
defer ts.Close()
|
||||
|
||||
channelID := "channelID"
|
||||
msgValue := 1.6
|
||||
boolVal := true
|
||||
msg := senml.Message{
|
||||
Name: "current",
|
||||
Time: 1720000000,
|
||||
Value: &msgValue,
|
||||
Publisher: validID,
|
||||
}
|
||||
invalidMsg := "[{\"n\":\"current\",\"t\":-1,\"v\":1.6}]"
|
||||
|
||||
sdkConf := sdk.Config{
|
||||
ReaderURL: ts.URL,
|
||||
}
|
||||
|
||||
mgsdk := sdk.NewSDK(sdkConf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
chanName string
|
||||
domainID string
|
||||
messagePageMeta sdk.MessagePageMetadata
|
||||
authzErr error
|
||||
authnErr error
|
||||
repoRes readers.MessagesPage
|
||||
repoErr error
|
||||
response sdk.MessagesPage
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "read messages successfully",
|
||||
token: validToken,
|
||||
chanName: channelID,
|
||||
domainID: validID,
|
||||
messagePageMeta: sdk.MessagePageMetadata{
|
||||
PageMetadata: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Level: 0,
|
||||
},
|
||||
Publisher: validID,
|
||||
BoolValue: &boolVal,
|
||||
},
|
||||
repoRes: readers.MessagesPage{
|
||||
Total: 1,
|
||||
Messages: []readers.Message{msg},
|
||||
},
|
||||
repoErr: nil,
|
||||
response: sdk.MessagesPage{
|
||||
PageRes: sdk.PageRes{
|
||||
Total: 1,
|
||||
},
|
||||
Messages: []senml.Message{msg},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "read messages successfully with subtopic",
|
||||
token: validToken,
|
||||
chanName: channelID + "/subtopic",
|
||||
domainID: validID,
|
||||
messagePageMeta: sdk.MessagePageMetadata{
|
||||
PageMetadata: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
Publisher: validID,
|
||||
},
|
||||
repoRes: readers.MessagesPage{
|
||||
Total: 1,
|
||||
Messages: []readers.Message{msg},
|
||||
},
|
||||
repoErr: nil,
|
||||
response: sdk.MessagesPage{
|
||||
PageRes: sdk.PageRes{
|
||||
Total: 1,
|
||||
},
|
||||
Messages: []senml.Message{msg},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "read messages with invalid token",
|
||||
token: invalidToken,
|
||||
chanName: channelID,
|
||||
domainID: validID,
|
||||
messagePageMeta: sdk.MessagePageMetadata{
|
||||
PageMetadata: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
Subtopic: "subtopic",
|
||||
Publisher: validID,
|
||||
},
|
||||
authzErr: svcerr.ErrAuthorization,
|
||||
repoRes: readers.MessagesPage{},
|
||||
response: sdk.MessagesPage{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthorization, http.StatusForbidden),
|
||||
},
|
||||
{
|
||||
desc: "read messages with empty token",
|
||||
token: "",
|
||||
chanName: channelID,
|
||||
domainID: validID,
|
||||
messagePageMeta: sdk.MessagePageMetadata{
|
||||
PageMetadata: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
Subtopic: "subtopic",
|
||||
Publisher: validID,
|
||||
},
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
repoRes: readers.MessagesPage{},
|
||||
response: sdk.MessagesPage{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "read messages with empty channel ID",
|
||||
token: validToken,
|
||||
chanName: "",
|
||||
domainID: validID,
|
||||
messagePageMeta: sdk.MessagePageMetadata{
|
||||
PageMetadata: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
Subtopic: "subtopic",
|
||||
Publisher: validID,
|
||||
},
|
||||
repoRes: readers.MessagesPage{},
|
||||
repoErr: nil,
|
||||
response: sdk.MessagesPage{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingID, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "read messages with invalid message page metadata",
|
||||
token: validToken,
|
||||
chanName: channelID,
|
||||
domainID: validID,
|
||||
messagePageMeta: sdk.MessagePageMetadata{
|
||||
PageMetadata: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
Metadata: map[string]any{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
Subtopic: "subtopic",
|
||||
Publisher: validID,
|
||||
},
|
||||
repoRes: readers.MessagesPage{},
|
||||
repoErr: nil,
|
||||
response: sdk.MessagesPage{},
|
||||
err: errors.NewSDKError(errors.New("json: unsupported type: chan int")),
|
||||
},
|
||||
{
|
||||
desc: "read messages with response that cannot be unmarshalled",
|
||||
token: validToken,
|
||||
chanName: channelID,
|
||||
domainID: validID,
|
||||
messagePageMeta: sdk.MessagePageMetadata{
|
||||
PageMetadata: sdk.PageMetadata{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
},
|
||||
Subtopic: "subtopic",
|
||||
Publisher: validID,
|
||||
},
|
||||
repoRes: readers.MessagesPage{
|
||||
Total: 1,
|
||||
Messages: []readers.Message{invalidMsg},
|
||||
},
|
||||
repoErr: nil,
|
||||
response: sdk.MessagesPage{},
|
||||
err: errors.NewSDKError(errors.New("json: cannot unmarshal string into Go struct field MessagesPage.messages of type senml.Message")),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
authCall1 := authn.On("Authenticate", mock.Anything, tc.token).Return(smqauthn.Session{UserID: validID}, tc.authnErr)
|
||||
authzCall := channelsGRPCClient.On("Authorize", mock.Anything, mock.Anything).Return(&grpcChannelsV1.AuthzRes{Authorized: true}, tc.authzErr)
|
||||
repoCall := repo.On("ReadAll", channelID, mock.Anything).Return(tc.repoRes, tc.repoErr)
|
||||
response, err := mgsdk.ReadMessages(context.Background(), tc.messagePageMeta, tc.chanName, tc.domainID, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, response)
|
||||
if tc.err == nil {
|
||||
ok := repoCall.Parent.AssertCalled(t, "ReadAll", channelID, mock.Anything)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
authCall1.Unset()
|
||||
authzCall.Unset()
|
||||
repoCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,870 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
smqauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
|
||||
pkgSch "github.com/absmach/magistrala/pkg/schedule"
|
||||
"github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/absmach/magistrala/reports"
|
||||
"github.com/absmach/magistrala/reports/api"
|
||||
rmocks "github.com/absmach/magistrala/reports/mocks"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
const (
|
||||
reportConfigID = "report-config-1"
|
||||
reportName = "daily-report"
|
||||
reportUpdatedName = "updated daily-report"
|
||||
reportDescription = "Daily temperature report"
|
||||
reportUpdatedDesc = "updated Daily temperature report"
|
||||
validTemplate = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{$.Title}}</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; }
|
||||
.header { background-color: #f0f0f0; padding: 10px; }
|
||||
.content { padding: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>{{$.Title}}</h1>
|
||||
<p>Generated on: {{$.GeneratedDate}}</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<h2>Messages</h2>
|
||||
{{range .Messages}}
|
||||
<div class="message">
|
||||
<p>Time: {{formatTime .Time}}</p>
|
||||
<p>Value: {{formatValue .}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
)
|
||||
|
||||
var (
|
||||
now = time.Now().UTC().Truncate(time.Minute)
|
||||
future = now.Add(1 * time.Hour)
|
||||
schedule = pkgSch.Schedule{
|
||||
StartDateTime: future,
|
||||
Recurring: pkgSch.Daily,
|
||||
RecurringPeriod: 1,
|
||||
Time: future,
|
||||
}
|
||||
metrics = []reports.ReqMetric{
|
||||
{
|
||||
ChannelID: "channel1",
|
||||
ClientIDs: []string{"client1"},
|
||||
Name: "metric_name",
|
||||
},
|
||||
}
|
||||
config = reports.MetricConfig{
|
||||
From: "now()-1h",
|
||||
To: "now()",
|
||||
Title: "test_title",
|
||||
Aggregation: reports.AggConfig{AggType: reports.AggregationAVG, Interval: "1h"},
|
||||
}
|
||||
email = reports.EmailSetting{
|
||||
To: []string{"test@example.com"},
|
||||
Subject: "Test Report",
|
||||
}
|
||||
|
||||
testReportConfig = sdk.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
Name: reportName,
|
||||
Description: reportDescription,
|
||||
DomainID: domainID,
|
||||
Status: "enabled",
|
||||
Schedule: schedule,
|
||||
Metrics: metrics,
|
||||
Config: &config,
|
||||
Email: &email,
|
||||
}
|
||||
)
|
||||
|
||||
func setupReports() (*httptest.Server, *rmocks.Service, *authnmocks.Authentication) {
|
||||
rsvc := new(rmocks.Service)
|
||||
log := mglog.NewMock()
|
||||
authn := new(authnmocks.Authentication)
|
||||
am := smqauthn.NewAuthNMiddleware(authn, smqauthn.WithAllowUnverifiedUser(true))
|
||||
mux := chi.NewRouter()
|
||||
_ = api.MakeHandler(rsvc, am, mux, log, "")
|
||||
return httptest.NewServer(mux), rsvc, authn
|
||||
}
|
||||
|
||||
func TestAddReportConfig(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcCfg := reports.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
Name: reportName,
|
||||
Description: reportDescription,
|
||||
DomainID: domainID,
|
||||
Status: reports.EnabledStatus,
|
||||
Schedule: schedule,
|
||||
Metrics: []reports.ReqMetric{
|
||||
{
|
||||
ChannelID: "channel1",
|
||||
ClientIDs: []string{"client1"},
|
||||
Name: "metric_name",
|
||||
},
|
||||
},
|
||||
Config: &reports.MetricConfig{
|
||||
From: "now()-1h",
|
||||
To: "now()",
|
||||
Title: "test_title",
|
||||
Aggregation: reports.AggConfig{AggType: reports.AggregationAVG, Interval: "1h"},
|
||||
},
|
||||
Email: &reports.EmailSetting{
|
||||
To: []string{"test@example.com"},
|
||||
Subject: "Test Report",
|
||||
},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
cfg sdk.ReportConfig
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportConfig
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "add report config successfully",
|
||||
cfg: testReportConfig,
|
||||
token: validToken,
|
||||
svcRes: svcCfg,
|
||||
},
|
||||
{
|
||||
desc: "add report config with empty token",
|
||||
cfg: sdk.ReportConfig{Name: "daily-report"},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
svcErr: errors.New("missing or invalid bearer user token"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("AddReportConfig", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.AddReportConfig(context.Background(), tc.cfg, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewReportConfig(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcCfg := reports.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
Name: reportName,
|
||||
Description: reportDescription,
|
||||
DomainID: domainID,
|
||||
Status: reports.EnabledStatus,
|
||||
Metrics: metrics,
|
||||
Config: &config,
|
||||
Email: &email,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportConfig
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "view report config successfully",
|
||||
id: reportConfigID,
|
||||
token: validToken,
|
||||
svcRes: svcCfg,
|
||||
},
|
||||
{
|
||||
desc: "view report config with empty token",
|
||||
id: reportConfigID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "view non-existent report config",
|
||||
id: "non-existent",
|
||||
token: validToken,
|
||||
svcErr: errors.New("not found"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("ViewReportConfig", mock.Anything, tc.session, tc.id, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.ViewReportConfig(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateReportConfig(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
updatedConfig := testReportConfig
|
||||
updatedConfig.Name = reportUpdatedName
|
||||
updatedConfig.Description = reportUpdatedDesc
|
||||
|
||||
svcCfg := reports.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
Name: reportUpdatedName,
|
||||
Description: reportUpdatedDesc,
|
||||
DomainID: domainID,
|
||||
Status: reports.EnabledStatus,
|
||||
Metrics: metrics,
|
||||
Config: &config,
|
||||
Email: &email,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
cfg sdk.ReportConfig
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportConfig
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "update report config successfully",
|
||||
cfg: updatedConfig,
|
||||
token: validToken,
|
||||
svcRes: svcCfg,
|
||||
},
|
||||
{
|
||||
desc: "update report config with empty token",
|
||||
cfg: sdk.ReportConfig{ID: reportConfigID, Name: "updated-report"},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("UpdateReportConfig", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.UpdateReportConfig(context.Background(), tc.cfg, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateReportSchedule(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcCfg := reports.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
Name: reportName,
|
||||
Status: reports.EnabledStatus,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
cfg sdk.ReportConfig
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportConfig
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "update report schedule successfully",
|
||||
cfg: sdk.ReportConfig{ID: reportConfigID, Schedule: map[string]any{"cron": "0 9 * * *"}},
|
||||
token: validToken,
|
||||
svcRes: svcCfg,
|
||||
},
|
||||
{
|
||||
desc: "update report schedule with empty token",
|
||||
cfg: sdk.ReportConfig{ID: reportConfigID},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("UpdateReportSchedule", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.UpdateReportSchedule(context.Background(), tc.cfg, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveReportConfig(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "remove report config successfully",
|
||||
id: reportConfigID,
|
||||
token: validToken,
|
||||
},
|
||||
{
|
||||
desc: "remove report config with empty token",
|
||||
id: reportConfigID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "remove non-existent report config",
|
||||
id: "non-existent",
|
||||
token: validToken,
|
||||
svcErr: errors.New("not found"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("RemoveReportConfig", mock.Anything, tc.session, tc.id).Return(tc.svcErr)
|
||||
err := mgsdk.RemoveReportConfig(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListReportsConfig(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcPage := reports.ReportConfigPage{}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
pm sdk.PageMetadata
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportConfigPage
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "list reports config successfully",
|
||||
pm: sdk.PageMetadata{Offset: 0, Limit: 10},
|
||||
token: validToken,
|
||||
svcRes: svcPage,
|
||||
},
|
||||
{
|
||||
desc: "list reports config with filters",
|
||||
pm: sdk.PageMetadata{
|
||||
Limit: 10,
|
||||
Name: "daily",
|
||||
Status: "enabled",
|
||||
Dir: "desc",
|
||||
Order: "created_at",
|
||||
},
|
||||
token: validToken,
|
||||
svcRes: svcPage,
|
||||
},
|
||||
{
|
||||
desc: "list reports config with empty metadata excludes filter params",
|
||||
pm: sdk.PageMetadata{},
|
||||
token: validToken,
|
||||
svcRes: reports.ReportConfigPage{},
|
||||
},
|
||||
{
|
||||
desc: "list reports config with empty token",
|
||||
pm: sdk.PageMetadata{Limit: 10},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("ListReportsConfig", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.ListReportsConfig(context.Background(), tc.pm, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotNil(t, result)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableReportConfig(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcCfg := reports.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
Status: reports.EnabledStatus,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportConfig
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "enable report config successfully",
|
||||
id: reportConfigID,
|
||||
token: validToken,
|
||||
svcRes: svcCfg,
|
||||
},
|
||||
{
|
||||
desc: "enable report config with empty token",
|
||||
id: reportConfigID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("EnableReportConfig", mock.Anything, tc.session, tc.id).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.EnableReportConfig(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableReportConfig(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcCfg := reports.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
Status: reports.DisabledStatus,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportConfig
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "disable report config successfully",
|
||||
id: reportConfigID,
|
||||
token: validToken,
|
||||
svcRes: svcCfg,
|
||||
},
|
||||
{
|
||||
desc: "disable report config with empty token",
|
||||
id: reportConfigID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("DisableReportConfig", mock.Anything, tc.session, tc.id).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.DisableReportConfig(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateReportTemplate(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
cfg sdk.ReportConfig
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "update report template successfully",
|
||||
cfg: sdk.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
ReportTemplate: validTemplate,
|
||||
},
|
||||
token: validToken,
|
||||
},
|
||||
{
|
||||
desc: "update report template with empty token",
|
||||
cfg: sdk.ReportConfig{ID: reportConfigID},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("UpdateReportTemplate", mock.Anything, tc.session, mock.Anything).Return(tc.svcErr)
|
||||
err := mgsdk.UpdateReportTemplate(context.Background(), tc.cfg, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewReportTemplate(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcTmpl := reports.ReportTemplate(validTemplate)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportTemplate
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "view report template successfully",
|
||||
id: reportConfigID,
|
||||
token: validToken,
|
||||
svcRes: svcTmpl,
|
||||
},
|
||||
{
|
||||
desc: "view report template with empty token",
|
||||
id: reportConfigID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("ViewReportTemplate", mock.Anything, tc.session, tc.id).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.ViewReportTemplate(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteReportTemplate(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "delete report template successfully",
|
||||
id: reportConfigID,
|
||||
token: validToken,
|
||||
},
|
||||
{
|
||||
desc: "delete report template with empty token",
|
||||
id: reportConfigID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("DeleteReportTemplate", mock.Anything, tc.session, tc.id).Return(tc.svcErr)
|
||||
err := mgsdk.DeleteReportTemplate(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateReport(t *testing.T) {
|
||||
rs, rsvc, auth := setupReports()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
ReportsURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcPage := reports.ReportPage{}
|
||||
|
||||
config := sdk.ReportConfig{
|
||||
ID: reportConfigID,
|
||||
Name: reportName,
|
||||
Description: reportDescription,
|
||||
DomainID: domainID,
|
||||
Metrics: metrics,
|
||||
Config: &config,
|
||||
ReportTemplate: reports.ReportTemplate(validTemplate),
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
cfg sdk.ReportConfig
|
||||
action sdk.ReportAction
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes reports.ReportPage
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "generate report successfully",
|
||||
cfg: config,
|
||||
action: sdk.ViewReportAction,
|
||||
token: validToken,
|
||||
svcRes: svcPage,
|
||||
},
|
||||
{
|
||||
desc: "generate report with download action",
|
||||
cfg: config,
|
||||
action: sdk.DownloadReportAction,
|
||||
token: validToken,
|
||||
svcRes: svcPage,
|
||||
},
|
||||
{
|
||||
desc: "generate report with empty token",
|
||||
cfg: config,
|
||||
action: sdk.ViewReportAction,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{
|
||||
DomainUserID: domainID + "_" + validID,
|
||||
UserID: validID,
|
||||
DomainID: domainID,
|
||||
}
|
||||
}
|
||||
|
||||
authCall := auth.On(
|
||||
"Authenticate",
|
||||
mock.Anything,
|
||||
tc.token,
|
||||
).Return(tc.session, tc.authenticateErr)
|
||||
|
||||
svcCall := rsvc.On(
|
||||
"GenerateReport",
|
||||
mock.Anything,
|
||||
tc.session,
|
||||
mock.Anything,
|
||||
mock.Anything,
|
||||
).Return(tc.svcRes, tc.svcErr)
|
||||
|
||||
page, file, err := mgsdk.GenerateReport(
|
||||
context.Background(),
|
||||
tc.cfg,
|
||||
tc.action,
|
||||
domainID,
|
||||
tc.token,
|
||||
)
|
||||
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
|
||||
if !tc.wantErr {
|
||||
if tc.action == sdk.DownloadReportAction {
|
||||
// download should return file
|
||||
assert.NotNil(t, file)
|
||||
} else {
|
||||
// view/email should return page
|
||||
assert.Equal(t, tc.svcRes.Total, page.Total)
|
||||
}
|
||||
}
|
||||
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,588 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
smqauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
|
||||
"github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/absmach/magistrala/re"
|
||||
"github.com/absmach/magistrala/re/api"
|
||||
remocks "github.com/absmach/magistrala/re/mocks"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
const ruleID = "rule-1"
|
||||
|
||||
var testRule = sdk.Rule{
|
||||
ID: ruleID,
|
||||
Name: "temperature-rule",
|
||||
InputChannel: "chan-1",
|
||||
InputTopic: "sensors/temperature",
|
||||
Status: "enabled",
|
||||
Tags: []string{"temperature", "alerts"},
|
||||
}
|
||||
|
||||
func setupRules() (*httptest.Server, *remocks.Service, *authnmocks.Authentication) {
|
||||
rsvc := new(remocks.Service)
|
||||
log := mglog.NewMock()
|
||||
authn := new(authnmocks.Authentication)
|
||||
am := smqauthn.NewAuthNMiddleware(authn, smqauthn.WithAllowUnverifiedUser(true))
|
||||
mux := chi.NewRouter()
|
||||
_ = api.MakeHandler(rsvc, am, mux, log, "")
|
||||
return httptest.NewServer(mux), rsvc, authn
|
||||
}
|
||||
|
||||
func TestAddRule(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcRule := re.Rule{
|
||||
ID: ruleID,
|
||||
Name: "temperature-rule",
|
||||
InputChannel: "chan-1",
|
||||
Status: re.EnabledStatus,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
rule sdk.Rule
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes re.Rule
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "add rule successfully",
|
||||
rule: sdk.Rule{Name: "temp-rule", InputChannel: "chan-1"},
|
||||
token: validToken,
|
||||
svcRes: svcRule,
|
||||
},
|
||||
{
|
||||
desc: "add rule with empty token",
|
||||
rule: sdk.Rule{Name: "temp-rule"},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "add rule with bad request",
|
||||
rule: sdk.Rule{},
|
||||
token: validToken,
|
||||
svcErr: errors.New("bad request"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("AddRule", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.AddRule(context.Background(), tc.rule, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewRule(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcRule := re.Rule{
|
||||
ID: ruleID,
|
||||
Name: "temperature-rule",
|
||||
InputChannel: "chan-1",
|
||||
Status: re.EnabledStatus,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes re.Rule
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "view rule successfully",
|
||||
id: ruleID,
|
||||
token: validToken,
|
||||
svcRes: svcRule,
|
||||
},
|
||||
{
|
||||
desc: "view rule with empty token",
|
||||
id: ruleID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "view non-existent rule",
|
||||
id: "non-existent",
|
||||
token: validToken,
|
||||
svcErr: errors.New("not found"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("ViewRule", mock.Anything, tc.session, tc.id, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.ViewRule(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRule(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
updatedRule := testRule
|
||||
updatedRule.Name = "updated-rule"
|
||||
|
||||
svcRule := re.Rule{
|
||||
ID: ruleID,
|
||||
Name: "updated-rule",
|
||||
InputChannel: "chan-1",
|
||||
InputTopic: "sensors/temperature",
|
||||
Status: re.EnabledStatus,
|
||||
Tags: []string{"temperature", "alerts"},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
rule sdk.Rule
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes re.Rule
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "update rule successfully",
|
||||
rule: updatedRule,
|
||||
token: validToken,
|
||||
svcRes: svcRule,
|
||||
},
|
||||
{
|
||||
desc: "update rule with empty token",
|
||||
rule: updatedRule,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("UpdateRule", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.UpdateRule(context.Background(), tc.rule, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRuleTags(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcRule := re.Rule{
|
||||
ID: ruleID,
|
||||
Tags: []string{"new-tag"},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
rule sdk.Rule
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes re.Rule
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "update rule tags successfully",
|
||||
rule: sdk.Rule{ID: ruleID, Tags: []string{"new-tag"}},
|
||||
token: validToken,
|
||||
svcRes: svcRule,
|
||||
},
|
||||
{
|
||||
desc: "update rule tags with empty token",
|
||||
rule: sdk.Rule{ID: ruleID},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("UpdateRuleTags", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.UpdateRuleTags(context.Background(), tc.rule, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRuleSchedule(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcRule := re.Rule{
|
||||
ID: ruleID,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
rule sdk.Rule
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes re.Rule
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "update rule schedule successfully",
|
||||
rule: sdk.Rule{ID: ruleID, Schedule: map[string]any{"cron": "0 * * * *"}},
|
||||
token: validToken,
|
||||
svcRes: svcRule,
|
||||
},
|
||||
{
|
||||
desc: "update rule schedule with empty token",
|
||||
rule: sdk.Rule{ID: ruleID},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("UpdateRuleSchedule", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.UpdateRuleSchedule(context.Background(), tc.rule, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRules(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcPage := re.Page{}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
pm sdk.PageMetadata
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes re.Page
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "list rules successfully",
|
||||
pm: sdk.PageMetadata{Offset: 0, Limit: 10},
|
||||
token: validToken,
|
||||
svcRes: svcPage,
|
||||
},
|
||||
{
|
||||
desc: "list rules with filters",
|
||||
pm: sdk.PageMetadata{
|
||||
Limit: 5,
|
||||
Name: "temp",
|
||||
Status: "enabled",
|
||||
InputChannel: "chan-1",
|
||||
Tag: "temperature",
|
||||
Dir: "desc",
|
||||
Order: "created_at",
|
||||
},
|
||||
token: validToken,
|
||||
svcRes: svcPage,
|
||||
},
|
||||
{
|
||||
desc: "list rules with empty metadata excludes filter params",
|
||||
pm: sdk.PageMetadata{},
|
||||
token: validToken,
|
||||
svcRes: re.Page{},
|
||||
},
|
||||
{
|
||||
desc: "list rules with empty token",
|
||||
pm: sdk.PageMetadata{Limit: 10},
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("ListRules", mock.Anything, tc.session, mock.Anything).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.ListRules(context.Background(), tc.pm, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotNil(t, result)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableRule(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcRule := re.Rule{
|
||||
ID: ruleID,
|
||||
Status: re.EnabledStatus,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes re.Rule
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "enable rule successfully",
|
||||
id: ruleID,
|
||||
token: validToken,
|
||||
svcRes: svcRule,
|
||||
},
|
||||
{
|
||||
desc: "enable rule with empty token",
|
||||
id: ruleID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("EnableRule", mock.Anything, tc.session, tc.id).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.EnableRule(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisableRule(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
svcRule := re.Rule{
|
||||
ID: ruleID,
|
||||
Status: re.DisabledStatus,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcRes re.Rule
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "disable rule successfully",
|
||||
id: ruleID,
|
||||
token: validToken,
|
||||
svcRes: svcRule,
|
||||
},
|
||||
{
|
||||
desc: "disable rule with empty token",
|
||||
id: ruleID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("DisableRule", mock.Anything, tc.session, tc.id).Return(tc.svcRes, tc.svcErr)
|
||||
result, err := mgsdk.DisableRule(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
if !tc.wantErr {
|
||||
assert.NotEmpty(t, result.ID)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveRule(t *testing.T) {
|
||||
rs, rsvc, auth := setupRules()
|
||||
defer rs.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
RulesEngineURL: rs.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
session smqauthn.Session
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "remove rule successfully",
|
||||
id: ruleID,
|
||||
token: validToken,
|
||||
},
|
||||
{
|
||||
desc: "remove rule with empty token",
|
||||
id: ruleID,
|
||||
token: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "remove non-existent rule",
|
||||
id: "non-existent",
|
||||
token: validToken,
|
||||
svcErr: errors.New("not found"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = smqauthn.Session{DomainUserID: domainID + "_" + validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := rsvc.On("RemoveRule", mock.Anything, tc.session, tc.id).Return(tc.svcErr)
|
||||
err := mgsdk.RemoveRule(context.Background(), tc.id, domainID, tc.token)
|
||||
assert.Equal(t, tc.wantErr, err != nil)
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala/channels"
|
||||
chmocks "github.com/absmach/magistrala/channels/mocks"
|
||||
"github.com/absmach/magistrala/clients"
|
||||
climocks "github.com/absmach/magistrala/clients/mocks"
|
||||
"github.com/absmach/magistrala/domains"
|
||||
groups "github.com/absmach/magistrala/groups"
|
||||
"github.com/absmach/magistrala/internal/nullable"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
"github.com/absmach/magistrala/journal"
|
||||
"github.com/absmach/magistrala/pkg/roles"
|
||||
sdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/absmach/magistrala/pkg/uuid"
|
||||
"github.com/absmach/magistrala/users"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
invalidIdentity = "invalididentity"
|
||||
Identity = "identity"
|
||||
Email = "email"
|
||||
InvalidEmail = "invalidemail"
|
||||
secret = "strongsecret"
|
||||
invalidToken = "invalid"
|
||||
contentType = sdk.CTJSON
|
||||
invalid = "invalid"
|
||||
wrongID = "wrongID"
|
||||
roleName = "roleName"
|
||||
)
|
||||
|
||||
var (
|
||||
idProvider = uuid.New()
|
||||
validMetadata = sdk.Metadata{"role": "client"}
|
||||
user = generateTestUser(&testing.T{})
|
||||
description = "shortdescription"
|
||||
gName = "groupname"
|
||||
validToken = "valid"
|
||||
limit uint64 = 5
|
||||
offset uint64 = 0
|
||||
total uint64 = 200
|
||||
passRegex = regexp.MustCompile("^.{8,}$")
|
||||
validID = testsutil.GenerateUUID(&testing.T{})
|
||||
|
||||
clientsGRPCClient *climocks.ClientsServiceClient
|
||||
channelsGRPCClient *chmocks.ChannelsServiceClient
|
||||
)
|
||||
|
||||
func generateUUID(t *testing.T) string {
|
||||
ulid, err := idProvider.ID()
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
return ulid
|
||||
}
|
||||
|
||||
func convertUsers(cs []sdk.User) []users.User {
|
||||
ccs := []users.User{}
|
||||
|
||||
for _, c := range cs {
|
||||
ccs = append(ccs, convertUser(c))
|
||||
}
|
||||
|
||||
return ccs
|
||||
}
|
||||
|
||||
func convertClients(cs ...sdk.Client) []clients.Client {
|
||||
ccs := []clients.Client{}
|
||||
|
||||
for _, c := range cs {
|
||||
ccs = append(ccs, convertClient(c))
|
||||
}
|
||||
|
||||
return ccs
|
||||
}
|
||||
|
||||
func convertGroups(cs []sdk.Group) []groups.Group {
|
||||
cgs := []groups.Group{}
|
||||
|
||||
for _, c := range cs {
|
||||
cgs = append(cgs, convertGroup(c))
|
||||
}
|
||||
|
||||
return cgs
|
||||
}
|
||||
|
||||
func convertChannels(cs []sdk.Channel) []channels.Channel {
|
||||
chs := []channels.Channel{}
|
||||
|
||||
for _, c := range cs {
|
||||
chs = append(chs, convertChannel(c))
|
||||
}
|
||||
|
||||
return chs
|
||||
}
|
||||
|
||||
func convertGroup(g sdk.Group) groups.Group {
|
||||
if g.Status == "" {
|
||||
g.Status = groups.EnabledStatus.String()
|
||||
}
|
||||
status, err := groups.ToStatus(g.Status)
|
||||
if err != nil {
|
||||
return groups.Group{}
|
||||
}
|
||||
var desc nullable.Value[string]
|
||||
if g.Description != "" {
|
||||
desc = nullable.New(g.Description)
|
||||
}
|
||||
|
||||
return groups.Group{
|
||||
ID: g.ID,
|
||||
Domain: g.DomainID,
|
||||
Parent: g.ParentID,
|
||||
Name: g.Name,
|
||||
Description: desc,
|
||||
Tags: g.Tags,
|
||||
Metadata: groups.Metadata(g.Metadata),
|
||||
Level: g.Level,
|
||||
Path: g.Path,
|
||||
Children: convertChildren(g.Children),
|
||||
CreatedAt: g.CreatedAt,
|
||||
UpdatedAt: g.UpdatedAt,
|
||||
Status: status,
|
||||
RoleID: g.RoleID,
|
||||
RoleName: g.RoleName,
|
||||
Actions: g.Actions,
|
||||
AccessType: g.AccessType,
|
||||
AccessProviderId: g.AccessProviderId,
|
||||
AccessProviderRoleId: g.AccessProviderRoleId,
|
||||
AccessProviderRoleName: g.AccessProviderRoleName,
|
||||
AccessProviderRoleActions: g.AccessProviderRoleActions,
|
||||
}
|
||||
}
|
||||
|
||||
func convertChildren(gs []*sdk.Group) []*groups.Group {
|
||||
var cg []*groups.Group
|
||||
|
||||
if len(gs) == 0 {
|
||||
return cg
|
||||
}
|
||||
|
||||
for _, g := range gs {
|
||||
insert := convertGroup(*g)
|
||||
cg = append(cg, &insert)
|
||||
}
|
||||
|
||||
return cg
|
||||
}
|
||||
|
||||
func convertUser(c sdk.User) users.User {
|
||||
if c.Status == "" {
|
||||
c.Status = users.EnabledStatus.String()
|
||||
}
|
||||
status, err := users.ToStatus(c.Status)
|
||||
if err != nil {
|
||||
return users.User{}
|
||||
}
|
||||
role, err := users.ToRole(c.Role)
|
||||
if err != nil {
|
||||
return users.User{}
|
||||
}
|
||||
return users.User{
|
||||
ID: c.ID,
|
||||
FirstName: c.FirstName,
|
||||
LastName: c.LastName,
|
||||
Tags: c.Tags,
|
||||
Email: c.Email,
|
||||
Credentials: users.Credentials(c.Credentials),
|
||||
Metadata: users.Metadata(c.Metadata),
|
||||
PrivateMetadata: users.Metadata(c.PrivateMetadata),
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
Status: status,
|
||||
Role: role,
|
||||
ProfilePicture: c.ProfilePicture,
|
||||
}
|
||||
}
|
||||
|
||||
func convertClient(c sdk.Client) clients.Client {
|
||||
if c.Status == "" {
|
||||
c.Status = clients.EnabledStatus.String()
|
||||
}
|
||||
status, err := clients.ToStatus(c.Status)
|
||||
if err != nil {
|
||||
return clients.Client{}
|
||||
}
|
||||
return clients.Client{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Tags: c.Tags,
|
||||
Domain: c.DomainID,
|
||||
ParentGroup: c.ParentGroup,
|
||||
Credentials: clients.Credentials(c.Credentials),
|
||||
Metadata: clients.Metadata(c.Metadata),
|
||||
PrivateMetadata: clients.Metadata(c.PrivateMetadata),
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
UpdatedBy: c.UpdatedBy,
|
||||
Status: status,
|
||||
}
|
||||
}
|
||||
|
||||
func convertChannel(g sdk.Channel) channels.Channel {
|
||||
if g.Status == "" {
|
||||
g.Status = channels.EnabledStatus.String()
|
||||
}
|
||||
status, err := channels.ToStatus(g.Status)
|
||||
if err != nil {
|
||||
return channels.Channel{}
|
||||
}
|
||||
return channels.Channel{
|
||||
ID: g.ID,
|
||||
Name: g.Name,
|
||||
Tags: g.Tags,
|
||||
ParentGroup: g.ParentGroup,
|
||||
Route: g.Route,
|
||||
Domain: g.DomainID,
|
||||
Metadata: channels.Metadata(g.Metadata),
|
||||
CreatedAt: g.CreatedAt,
|
||||
UpdatedAt: g.UpdatedAt,
|
||||
UpdatedBy: g.UpdatedBy,
|
||||
Status: status,
|
||||
}
|
||||
}
|
||||
|
||||
func convertInvitation(i sdk.Invitation) domains.Invitation {
|
||||
return domains.Invitation{
|
||||
InvitedBy: i.InvitedBy,
|
||||
InviteeUserID: i.InviteeUserID,
|
||||
DomainID: i.DomainID,
|
||||
RoleID: i.RoleID,
|
||||
RoleName: i.RoleName,
|
||||
Actions: i.Actions,
|
||||
CreatedAt: i.CreatedAt,
|
||||
UpdatedAt: i.UpdatedAt,
|
||||
ConfirmedAt: i.ConfirmedAt,
|
||||
RejectedAt: i.RejectedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func convertJournal(j sdk.Journal) journal.Journal {
|
||||
return journal.Journal{
|
||||
ID: j.ID,
|
||||
Operation: j.Operation,
|
||||
OccurredAt: j.OccurredAt,
|
||||
Attributes: j.Attributes,
|
||||
Metadata: j.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func generateTestUser(t *testing.T) sdk.User {
|
||||
createdAt, err := time.Parse(time.RFC3339, "2024-01-01T00:00:00Z")
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error parsing time: %v", err))
|
||||
return sdk.User{
|
||||
ID: generateUUID(t),
|
||||
FirstName: "userfirstname",
|
||||
LastName: "userlastname",
|
||||
Email: "useremail@example.com",
|
||||
Credentials: sdk.Credentials{
|
||||
Username: "username",
|
||||
Secret: secret,
|
||||
},
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
Metadata: validMetadata,
|
||||
PrivateMetadata: validMetadata,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: createdAt,
|
||||
Status: users.EnabledStatus.String(),
|
||||
Role: users.UserRole.String(),
|
||||
}
|
||||
}
|
||||
|
||||
func convertRole(r roles.Role) sdk.Role {
|
||||
return sdk.Role{
|
||||
ID: r.ID,
|
||||
Name: r.Name,
|
||||
EntityID: r.EntityID,
|
||||
CreatedBy: r.CreatedBy,
|
||||
CreatedAt: r.CreatedAt,
|
||||
UpdatedBy: r.UpdatedBy,
|
||||
UpdatedAt: r.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func convertRoleProvision(r roles.RoleProvision) sdk.Role {
|
||||
return sdk.Role{
|
||||
ID: r.ID,
|
||||
Name: r.Name,
|
||||
EntityID: r.EntityID,
|
||||
CreatedBy: r.CreatedBy,
|
||||
CreatedAt: r.CreatedAt,
|
||||
UpdatedBy: r.UpdatedBy,
|
||||
UpdatedAt: r.UpdatedAt,
|
||||
OptionalActions: r.OptionalActions,
|
||||
OptionalMembers: r.OptionalMembers,
|
||||
}
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
exitCode := m.Run()
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
grpcTokenV1 "github.com/absmach/magistrala/api/grpc/token/v1"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
smqauth "github.com/absmach/magistrala/auth"
|
||||
smqauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
sdk "github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func TestIssueToken(t *testing.T) {
|
||||
ts, svc, _ := setupUsers()
|
||||
defer ts.Close()
|
||||
|
||||
client := generateTestUser(t)
|
||||
token := generateTestToken()
|
||||
|
||||
conf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
login sdk.Login
|
||||
svcRes *grpcTokenV1.Token
|
||||
svcErr error
|
||||
response sdk.Token
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "issue token successfully",
|
||||
login: sdk.Login{
|
||||
Username: client.Credentials.Username,
|
||||
Password: client.Credentials.Secret,
|
||||
},
|
||||
svcRes: &grpcTokenV1.Token{
|
||||
AccessToken: token.AccessToken,
|
||||
RefreshToken: &token.RefreshToken,
|
||||
AccessType: smqauth.AccessKey.String(),
|
||||
},
|
||||
svcErr: nil,
|
||||
response: token,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "issue token with invalid identity",
|
||||
login: sdk.Login{
|
||||
Username: invalidIdentity,
|
||||
Password: client.Credentials.Secret,
|
||||
},
|
||||
svcRes: &grpcTokenV1.Token{},
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
response: sdk.Token{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "issue token with invalid secret",
|
||||
login: sdk.Login{
|
||||
Username: client.Credentials.Username,
|
||||
Password: "invalid",
|
||||
},
|
||||
svcRes: &grpcTokenV1.Token{},
|
||||
svcErr: svcerr.ErrLogin,
|
||||
response: sdk.Token{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrLogin, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "issue token with empty identity",
|
||||
login: sdk.Login{
|
||||
Username: "",
|
||||
Password: client.Credentials.Secret,
|
||||
},
|
||||
svcRes: &grpcTokenV1.Token{},
|
||||
svcErr: nil,
|
||||
response: sdk.Token{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingUsernameEmail, http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "issue token with empty secret",
|
||||
login: sdk.Login{
|
||||
Username: client.Credentials.Username,
|
||||
Password: "",
|
||||
},
|
||||
svcRes: &grpcTokenV1.Token{},
|
||||
svcErr: nil,
|
||||
response: sdk.Token{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrMissingPass, http.StatusBadRequest),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("IssueToken", mock.Anything, tc.login.Username, tc.login.Password, tc.login.Description).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.CreateToken(context.Background(), tc.login)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "IssueToken", mock.Anything, tc.login.Username, tc.login.Password, tc.login.Description)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshToken(t *testing.T) {
|
||||
ts, svc, auth := setupUsers()
|
||||
defer ts.Close()
|
||||
|
||||
token := generateTestToken()
|
||||
|
||||
conf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
svcRes *grpcTokenV1.Token
|
||||
svcErr error
|
||||
identifyErr error
|
||||
response sdk.Token
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "refresh token successfully",
|
||||
token: token.RefreshToken,
|
||||
svcRes: &grpcTokenV1.Token{
|
||||
AccessToken: token.AccessToken,
|
||||
RefreshToken: &token.RefreshToken,
|
||||
AccessType: token.AccessType,
|
||||
},
|
||||
response: token,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "refresh token with invalid token",
|
||||
token: invalidToken,
|
||||
svcRes: nil,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
response: sdk.Token{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "refresh token with empty token",
|
||||
token: "",
|
||||
response: sdk.Token{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
authCall := auth.On("Authenticate", mock.Anything, mock.Anything).Return(smqauthn.Session{DomainUserID: validID, UserID: validID, DomainID: validID}, tc.identifyErr)
|
||||
svcCall := svc.On("RefreshToken", mock.Anything, smqauthn.Session{DomainUserID: validID, UserID: validID, DomainID: validID}, tc.token).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.RefreshToken(context.Background(), tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "RefreshToken", mock.Anything, smqauthn.Session{DomainUserID: validID, UserID: validID, DomainID: validID}, tc.token)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func generateTestToken() sdk.Token {
|
||||
return sdk.Token{
|
||||
AccessToken: "access_token",
|
||||
RefreshToken: "refresh_token",
|
||||
AccessType: smqauth.AccessKey.String(),
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/sdk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestTransport verifies that IdleConnTimeout=90s keeps connections pooled for
|
||||
// healthy servers, and that network errors (EOF, reset) surface as descriptive errors.
|
||||
func TestTransport(t *testing.T) {
|
||||
cases := []struct {
|
||||
desc string
|
||||
serverFunc func(t *testing.T) (url string, cleanup func())
|
||||
ctxFunc func() context.Context
|
||||
wantErr bool
|
||||
errContains string
|
||||
}{
|
||||
{
|
||||
desc: "make request successfully with connection reuse",
|
||||
serverFunc: func(t *testing.T) (string, func()) {
|
||||
t.Helper()
|
||||
var connCount atomic.Int32
|
||||
srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(`{"clients":[{"id":"1","name":"test-client"}]}`))
|
||||
}))
|
||||
srv.Config.ConnState = func(_ net.Conn, state http.ConnState) {
|
||||
if state == http.StateNew {
|
||||
connCount.Add(1)
|
||||
}
|
||||
}
|
||||
srv.Start()
|
||||
return srv.URL, func() {
|
||||
srv.Close()
|
||||
assert.Equal(t, int32(1), connCount.Load(), "expected connections to be reused (keep-alives enabled)")
|
||||
}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
desc: "make request with server closing connection",
|
||||
serverFunc: func(t *testing.T) (string, func()) {
|
||||
t.Helper()
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
go func() {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
return "http://" + ln.Addr().String(), func() { ln.Close() }
|
||||
},
|
||||
wantErr: true,
|
||||
errContains: "request failed",
|
||||
},
|
||||
{
|
||||
desc: "make request with connection reset by peer",
|
||||
serverFunc: func(t *testing.T) (string, func()) {
|
||||
t.Helper()
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
go func() {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tcpConn, ok := conn.(*net.TCPConn)
|
||||
if ok {
|
||||
_ = tcpConn.SetLinger(0)
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
return "http://" + ln.Addr().String(), func() { ln.Close() }
|
||||
},
|
||||
wantErr: true,
|
||||
errContains: "request failed",
|
||||
},
|
||||
{
|
||||
desc: "make request with unreachable server",
|
||||
serverFunc: func(t *testing.T) (string, func()) {
|
||||
t.Helper()
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
addr := ln.Addr().String()
|
||||
ln.Close()
|
||||
return "http://" + addr, func() {}
|
||||
},
|
||||
wantErr: true,
|
||||
errContains: "request failed",
|
||||
},
|
||||
{
|
||||
desc: "make request with cancelled context",
|
||||
serverFunc: func(t *testing.T) (string, func()) {
|
||||
t.Helper()
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
return srv.URL, srv.Close
|
||||
},
|
||||
ctxFunc: func() context.Context {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
return ctx
|
||||
},
|
||||
wantErr: true,
|
||||
errContains: "request failed",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
url, cleanup := tc.serverFunc(t)
|
||||
defer cleanup()
|
||||
|
||||
smqsdk := sdk.NewSDK(sdk.Config{ClientsURL: url})
|
||||
|
||||
ctx := context.Background()
|
||||
if tc.ctxFunc != nil {
|
||||
ctx = tc.ctxFunc()
|
||||
}
|
||||
|
||||
client := sdk.Client{Name: "test-client"}
|
||||
for i := 0; i < 2; i++ {
|
||||
_, err := smqsdk.CreateClients(ctx, []sdk.Client{client}, domainID, validToken)
|
||||
if tc.wantErr {
|
||||
require.Error(t, err)
|
||||
if tc.errContains != "" {
|
||||
assert.True(t, strings.Contains(err.Error(), tc.errContains),
|
||||
"expected error %q to contain %q", err.Error(), tc.errContains)
|
||||
}
|
||||
break
|
||||
}
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,970 +0,0 @@
|
||||
//go:build oldservices
|
||||
// +build oldservices
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package http_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
grpcChannelsV1 "github.com/absmach/magistrala/api/grpc/channels/v1"
|
||||
grpcClientsV1 "github.com/absmach/magistrala/api/grpc/clients/v1"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
chmocks "github.com/absmach/magistrala/channels/mocks"
|
||||
climocks "github.com/absmach/magistrala/clients/mocks"
|
||||
"github.com/absmach/magistrala/internal/testsutil"
|
||||
smqauthn "github.com/absmach/magistrala/pkg/authn"
|
||||
authnmocks "github.com/absmach/magistrala/pkg/authn/mocks"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/absmach/magistrala/pkg/transformers/senml"
|
||||
"github.com/absmach/magistrala/readers"
|
||||
customhttp "github.com/absmach/magistrala/readers/api/http"
|
||||
"github.com/absmach/magistrala/readers/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
const (
|
||||
svcName = "test-service"
|
||||
clientToken = "1"
|
||||
userToken = "token"
|
||||
invalidToken = "invalid"
|
||||
numOfMessages = 100
|
||||
valueFields = 5
|
||||
subtopic = "topic"
|
||||
mqttProt = "mqtt"
|
||||
httpProt = "http"
|
||||
msgName = "temperature"
|
||||
instanceID = "5de9b29a-feb9-11ed-be56-0242ac120002"
|
||||
domainID = "b4d7d79e-fd99-4c2b-ac09-524e43df6888"
|
||||
)
|
||||
|
||||
var (
|
||||
v float64 = 5
|
||||
vs = "value"
|
||||
vb = true
|
||||
vd = "dataValue"
|
||||
sum float64 = 42
|
||||
validSession = smqauthn.Session{UserID: testsutil.GenerateUUID(&testing.T{})}
|
||||
)
|
||||
|
||||
func newServer(repo *mocks.MessageRepository, authn *authnmocks.Authentication, clients *climocks.ClientsServiceClient, channels *chmocks.ChannelsServiceClient) *httptest.Server {
|
||||
mux := customhttp.MakeHandler(repo, authn, clients, channels, svcName, instanceID)
|
||||
return httptest.NewServer(mux)
|
||||
}
|
||||
|
||||
type testRequest struct {
|
||||
client *http.Client
|
||||
method string
|
||||
url string
|
||||
token string
|
||||
key string
|
||||
}
|
||||
|
||||
func (tr testRequest) make() (*http.Response, error) {
|
||||
req, err := http.NewRequest(tr.method, tr.url, http.NoBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tr.token != "" {
|
||||
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
|
||||
}
|
||||
if tr.key != "" {
|
||||
req.Header.Set("Authorization", apiutil.ClientPrefix+tr.key)
|
||||
}
|
||||
|
||||
return tr.client.Do(req)
|
||||
}
|
||||
|
||||
func TestReadAll(t *testing.T) {
|
||||
chanID := testsutil.GenerateUUID(t)
|
||||
pubID := testsutil.GenerateUUID(t)
|
||||
pubID2 := testsutil.GenerateUUID(t)
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
var messages []senml.Message
|
||||
var queryMsgs []senml.Message
|
||||
var valueMsgs []senml.Message
|
||||
var boolMsgs []senml.Message
|
||||
var stringMsgs []senml.Message
|
||||
var dataMsgs []senml.Message
|
||||
|
||||
for i := 0; i < numOfMessages; i++ {
|
||||
// Mix possible values as well as value sum.
|
||||
msg := senml.Message{
|
||||
Channel: chanID,
|
||||
Publisher: pubID,
|
||||
Protocol: mqttProt,
|
||||
Time: float64(now - int64(i)),
|
||||
Name: "name",
|
||||
}
|
||||
|
||||
count := i % valueFields
|
||||
switch count {
|
||||
case 0:
|
||||
msg.Value = &v
|
||||
valueMsgs = append(valueMsgs, msg)
|
||||
case 1:
|
||||
msg.BoolValue = &vb
|
||||
boolMsgs = append(boolMsgs, msg)
|
||||
case 2:
|
||||
msg.StringValue = &vs
|
||||
stringMsgs = append(stringMsgs, msg)
|
||||
case 3:
|
||||
msg.DataValue = &vd
|
||||
dataMsgs = append(dataMsgs, msg)
|
||||
case 4:
|
||||
msg.Sum = &sum
|
||||
msg.Subtopic = subtopic
|
||||
msg.Protocol = httpProt
|
||||
msg.Publisher = pubID2
|
||||
msg.Name = msgName
|
||||
queryMsgs = append(queryMsgs, msg)
|
||||
}
|
||||
|
||||
messages = append(messages, msg)
|
||||
}
|
||||
|
||||
repo := new(mocks.MessageRepository)
|
||||
authn := new(authnmocks.Authentication)
|
||||
clients := new(climocks.ClientsServiceClient)
|
||||
channels := new(chmocks.ChannelsServiceClient)
|
||||
ts := newServer(repo, authn, clients, channels)
|
||||
defer ts.Close()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
req string
|
||||
url string
|
||||
token string
|
||||
key string
|
||||
status int
|
||||
res pageRes
|
||||
authnErr error
|
||||
authzRes *grpcChannelsV1.AuthzRes
|
||||
authzErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "read page with valid offset and limit",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with valid offset and limit as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with negative offset as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=-1&limit=10", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with negative limit as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=-10", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with zero limit as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=0", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with non-integer offset as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=abc&limit=10", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with non-integer limit as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=abc", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with invalid channel id as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, ""),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with multiple offset as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&offset=1&limit=10", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with multiple limit as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=20&limit=10", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with empty token as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
token: "",
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "read page with default offset as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?limit=10", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with default limit as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with senml format as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?format=messages", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with subtopic as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, domainID, chanID, subtopic, httpProt),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Subtopic: subtopic, Format: "messages", Protocol: httpProt, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with subtopic and protocol as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, domainID, chanID, subtopic, httpProt),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Subtopic: subtopic, Format: "messages", Protocol: httpProt, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with publisher as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?publisher=%s", ts.URL, domainID, chanID, pubID2),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Publisher: pubID2, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with protocol as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?protocol=http", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Protocol: httpProt, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with name as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?name=%s", ts.URL, domainID, chanID, msgName),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Name: msgName, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f", ts.URL, domainID, chanID, v),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and equal comparator as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v, readers.EqualKey),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v, Comparator: readers.EqualKey, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and lower-than comparator as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v+1, readers.LowerThanKey),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v + 1, Comparator: readers.LowerThanKey, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and lower-than-or-equal comparator as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v+1, readers.LowerThanEqualKey),
|
||||
key: clientToken,
|
||||
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v + 1, Comparator: readers.LowerThanEqualKey, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and greater-than comparator as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v-1, readers.GreaterThanKey),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v - 1, Comparator: readers.GreaterThanKey, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and greater-than-or-equal comparator as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v-1, readers.GreaterThanEqualKey),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v - 1, Comparator: readers.GreaterThanEqualKey, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with non-float value as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=ab01", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with value and wrong comparator as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=wrong", ts.URL, domainID, chanID, v-1),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with boolean value as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?vb=true", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", BoolValue: true, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(boolMsgs)),
|
||||
Messages: boolMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with non-boolean value as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?vb=yes", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with string value as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?vs=%s", ts.URL, domainID, chanID, vs),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", StringValue: vs, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(stringMsgs)),
|
||||
Messages: stringMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with data value as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?vd=%s", ts.URL, domainID, chanID, vd),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", DataValue: vd, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(dataMsgs)),
|
||||
Messages: dataMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with non-float from as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?from=ABCD", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with non-float to as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?to=ABCD", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with from/to as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?from=%f&to=%f", ts.URL, domainID, chanID, messages[19].Time, messages[4].Time),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", From: messages[19].Time, To: messages[4].Time, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages[5:20])),
|
||||
Messages: messages[5:15],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with interval as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?interval=10h", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation and interval as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation, interval, to and from as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=%f", ts.URL, domainID, chanID, messages[19].Time, messages[4].Time),
|
||||
key: clientToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Aggregation: "MAX", Interval: "10h", From: messages[19].Time, To: messages[4].Time, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages[5:20])),
|
||||
Messages: messages[5:15],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with invalid aggregation and valid interval, to and from as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=invalid&interval=10h&from=%f&to=%f", ts.URL, domainID, chanID, messages[19].Time, messages[4].Time),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with invalid interval and valid aggregation, to and from as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10hrs&from=%f&to=%f", ts.URL, domainID, chanID, messages[19].Time, messages[4].Time),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation, interval and to with missing from as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h&to=%f", ts.URL, domainID, chanID, messages[4].Time),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation, interval and to with invalid from as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h&to=ABCD&from=%f", ts.URL, domainID, chanID, messages[4].Time),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation, interval and to with invalid to as client",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=ABCD", ts.URL, domainID, chanID, messages[4].Time),
|
||||
key: clientToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with valid offset and limit as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with invalid client key",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
key: "invalid",
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "read page with unauthorized client key",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
key: clientToken,
|
||||
authnErr: nil,
|
||||
authzRes: &grpcChannelsV1.AuthzRes{Authorized: false},
|
||||
status: http.StatusForbidden,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "read page with negative offset as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=-1&limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with negative limit as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=-10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with zero limit as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=0", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with non-integer offset as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=abc&limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with non-integer limit as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=abc", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with invalid channel id as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, ""),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with invalid token as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
token: invalidToken,
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "read page with unauthorized as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
authzRes: &grpcChannelsV1.AuthzRes{Authorized: false},
|
||||
status: http.StatusForbidden,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "read page with multiple offset as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&offset=1&limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with multiple limit as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=20&limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with empty token as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0&limit=10", ts.URL, domainID, chanID),
|
||||
token: "",
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "read page with default offset as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?limit=10", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with default limit as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?offset=0", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with senml format as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?format=messages", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with subtopic as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, domainID, chanID, subtopic, httpProt),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Subtopic: subtopic, Protocol: httpProt, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with subtopic and protocol as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?subtopic=%s&protocol=%s", ts.URL, domainID, chanID, subtopic, httpProt),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Subtopic: subtopic, Protocol: httpProt, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with publisher as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?publisher=%s", ts.URL, domainID, chanID, pubID2),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Publisher: pubID2, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with protocol as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?protocol=http", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Protocol: httpProt, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with name as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?name=%s", ts.URL, domainID, chanID, msgName),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Name: msgName, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(queryMsgs)),
|
||||
Messages: queryMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f", ts.URL, domainID, chanID, v),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and equal comparator as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v, readers.EqualKey),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v, Comparator: readers.EqualKey, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and lower-than comparator as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v+1, readers.LowerThanKey),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v + 1, Comparator: readers.LowerThanKey, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and lower-than-or-equal comparator as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v+1, readers.LowerThanEqualKey),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Value: v + 1, Comparator: readers.LowerThanEqualKey, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and greater-than comparator as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v-1, readers.GreaterThanKey),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Order: "time", Dir: "desc", Format: "messages", Value: v - 1, Comparator: readers.GreaterThanKey},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with value and greater-than-or-equal comparator as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=%s", ts.URL, domainID, chanID, v-1, readers.GreaterThanEqualKey),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Order: "time", Dir: "desc", Limit: 10, Format: "messages", Value: v - 1, Comparator: readers.GreaterThanEqualKey},
|
||||
Total: uint64(len(valueMsgs)),
|
||||
Messages: valueMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with non-float value as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=ab01", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with value and wrong comparator as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?v=%f&comparator=wrong", ts.URL, domainID, chanID, v-1),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with boolean value as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?vb=true", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", BoolValue: true, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(boolMsgs)),
|
||||
Messages: boolMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with non-boolean value as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?vb=yes", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with string value as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?vs=%s", ts.URL, domainID, chanID, vs),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", StringValue: vs, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(stringMsgs)),
|
||||
Messages: stringMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with data value as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?vd=%s", ts.URL, domainID, chanID, vd),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", DataValue: vd, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(dataMsgs)),
|
||||
Messages: dataMsgs[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with non-float from as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?from=ABCD", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with non-float to as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?to=ABCD", ts.URL, domainID, chanID),
|
||||
token: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with from/to as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?from=%f&to=%f", ts.URL, domainID, chanID, messages[19].Time, messages[4].Time),
|
||||
token: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", From: messages[19].Time, To: messages[4].Time, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages[5:20])),
|
||||
Messages: messages[5:15],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX", ts.URL, domainID, chanID),
|
||||
key: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with interval as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?interval=10h", ts.URL, domainID, chanID),
|
||||
key: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages)),
|
||||
Messages: messages[0:10],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation and interval as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h", ts.URL, domainID, chanID),
|
||||
key: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation, interval, to and from as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=%f", ts.URL, domainID, chanID, messages[19].Time, messages[4].Time),
|
||||
key: userToken,
|
||||
status: http.StatusOK,
|
||||
res: pageRes{
|
||||
PageMetadata: readers.PageMetadata{Limit: 10, Format: "messages", Aggregation: "MAX", Interval: "10h", From: messages[19].Time, To: messages[4].Time, Order: "time", Dir: "desc"},
|
||||
Total: uint64(len(messages[5:20])),
|
||||
Messages: messages[5:15],
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "read page with invalid aggregation and valid interval, to and from as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=invalid&interval=10h&from=%f&to=%f", ts.URL, domainID, chanID, messages[19].Time, messages[4].Time),
|
||||
key: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with invalid interval and valid aggregation, to and from as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10hrs&from=%f&to=%f", ts.URL, domainID, chanID, messages[19].Time, messages[4].Time),
|
||||
key: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation, interval and to with missing from as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h&to=%f", ts.URL, domainID, chanID, messages[4].Time),
|
||||
key: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation, interval and to with invalid from as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h&to=ABCD&from=%f", ts.URL, domainID, chanID, messages[4].Time),
|
||||
key: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "read page with aggregation, interval and to with invalid to as user",
|
||||
url: fmt.Sprintf("%s/%s/channels/%s/messages?aggregation=MAX&interval=10h&from=%f&to=ABCD", ts.URL, domainID, chanID, messages[4].Time),
|
||||
key: userToken,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(validSession, tc.authnErr)
|
||||
if tc.key != "" {
|
||||
authnCall = clients.On("Authenticate", mock.Anything, &grpcClientsV1.AuthnReq{
|
||||
Token: smqauthn.AuthPack(smqauthn.DomainAuth, domainID, tc.key),
|
||||
}).Return(&grpcClientsV1.AuthnRes{Id: testsutil.GenerateUUID(t), Authenticated: true}, tc.authnErr)
|
||||
}
|
||||
if tc.authzRes == nil {
|
||||
tc.authzRes = &grpcChannelsV1.AuthzRes{Authorized: true}
|
||||
}
|
||||
authzCall := channels.On("Authorize", mock.Anything, mock.Anything).Return(tc.authzRes, tc.authzErr)
|
||||
repoCall := repo.On("ReadAll", chanID, tc.res.PageMetadata).Return(readers.MessagesPage{Total: tc.res.Total, Messages: fromSenml(tc.res.Messages)}, nil)
|
||||
req := testRequest{
|
||||
client: ts.Client(),
|
||||
method: http.MethodGet,
|
||||
url: tc.url,
|
||||
token: tc.token,
|
||||
key: tc.key,
|
||||
}
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
|
||||
var page pageRes
|
||||
err = json.NewDecoder(res.Body).Decode(&page)
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err))
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
assert.Equal(t, tc.res.Total, page.Total, fmt.Sprintf("%s: expected %d got %d", tc.desc, tc.res.Total, page.Total))
|
||||
assert.ElementsMatch(t, tc.res.Messages, page.Messages, fmt.Sprintf("%s: got incorrect body from response", tc.desc))
|
||||
authzCall.Unset()
|
||||
authnCall.Unset()
|
||||
repoCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type pageRes struct {
|
||||
readers.PageMetadata
|
||||
Total uint64 `json:"total"`
|
||||
Messages []senml.Message `json:"messages"`
|
||||
}
|
||||
|
||||
func fromSenml(in []senml.Message) []readers.Message {
|
||||
var ret []readers.Message
|
||||
for _, m := range in {
|
||||
ret = append(ret, m)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
Reference in New Issue
Block a user