1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-05-02 22:17:10 +08:00
Mainflux.mainflux/things/service_test.go
b1ackd0t e6f34e1546
NOISSUE - Fix WS Tests (#1927)
* feat(testsutil): Add function to generate random UUID

This commit adds a new function to the `common.go` file in the `testsutil` package. The function `GenerateRandomUUID` generates a random UUID using the `github.com/mainflux/mainflux/pkg/uuid` package. This function will be used in tests to generate unique identifiers for testing purposes.

The function is added to the existing `common.go` file in the `testsutil` package, which is used for common utilities in tests.

This change improves the testability of the codebase by providing a convenient way to generate random UUIDs for testing purposes.

Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com>

* feat(auth): add error constants

This commit adds two error constants, InvalidID and InvalidToken, to the auth package. These constants will be used to represent invalid ID and token values in the authentication service.

Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com>

* feat(ws): add validation for empty message payload

This commit adds a validation check for an empty message payload in the Publish method of the adapterService struct in the ws/adapter.go file. If the payload is empty, the method will now return an ErrFailedMessagePublish error. This validation ensures that only non-empty payloads are published.

Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com>

* feat(auth): add constant for invalid value

Added a constant named InvalidValue to the auth/mocks/service.go file. This constant is set to "invalid" and will be used to represent an invalid value in the codebase.

Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com>

---------

Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com>
2023-10-18 22:40:55 +02:00

1220 lines
36 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package things_test
import (
"context"
"fmt"
"testing"
"time"
"github.com/mainflux/mainflux"
authmocks "github.com/mainflux/mainflux/auth/mocks"
"github.com/mainflux/mainflux/internal/apiutil"
gmocks "github.com/mainflux/mainflux/internal/groups/mocks"
"github.com/mainflux/mainflux/internal/testsutil"
mfclients "github.com/mainflux/mainflux/pkg/clients"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/things"
"github.com/mainflux/mainflux/things/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
var (
idProvider = uuid.New()
secret = "strongsecret"
validCMetadata = mfclients.Metadata{"role": "client"}
ID = testsutil.GenerateUUID(&testing.T{})
client = mfclients.Client{
ID: ID,
Name: "clientname",
Tags: []string{"tag1", "tag2"},
Credentials: mfclients.Credentials{Identity: "clientidentity", Secret: secret},
Metadata: validCMetadata,
Status: mfclients.EnabledStatus,
}
withinDuration = 5 * time.Second
adminEmail = "admin@example.com"
myKey = "mine"
validToken = "token"
inValidToken = "invalidToken"
validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22"
)
func newService() (things.Service, *mocks.Repository, *authmocks.Service) {
auth := new(authmocks.Service)
thingCache := mocks.NewCache()
idProvider := uuid.NewMock()
cRepo := new(mocks.Repository)
gRepo := new(gmocks.Repository)
return things.NewService(auth, cRepo, gRepo, thingCache, idProvider), cRepo, auth
}
func TestRegisterClient(t *testing.T) {
svc, cRepo, auth := newService()
cases := []struct {
desc string
client mfclients.Client
token string
err error
}{
{
desc: "register new client",
client: client,
token: validToken,
err: nil,
},
{
desc: "register existing client",
client: client,
token: validToken,
err: errors.ErrConflict,
},
{
desc: "register a new enabled client with name",
client: mfclients.Client{
Name: "clientWithName",
Credentials: mfclients.Credentials{
Identity: "newclientwithname@example.com",
Secret: secret,
},
Status: mfclients.EnabledStatus,
},
err: nil,
token: validToken,
},
{
desc: "register a new disabled client with name",
client: mfclients.Client{
Name: "clientWithName",
Credentials: mfclients.Credentials{
Identity: "newclientwithname@example.com",
Secret: secret,
},
},
err: nil,
token: validToken,
},
{
desc: "register a new enabled client with tags",
client: mfclients.Client{
Tags: []string{"tag1", "tag2"},
Credentials: mfclients.Credentials{
Identity: "newclientwithtags@example.com",
Secret: secret,
},
Status: mfclients.EnabledStatus,
},
err: nil,
token: validToken,
},
{
desc: "register a new disabled client with tags",
client: mfclients.Client{
Tags: []string{"tag1", "tag2"},
Credentials: mfclients.Credentials{
Identity: "newclientwithtags@example.com",
Secret: secret,
},
Status: mfclients.DisabledStatus,
},
err: nil,
token: validToken,
},
{
desc: "register a new enabled client with metadata",
client: mfclients.Client{
Credentials: mfclients.Credentials{
Identity: "newclientwithmetadata@example.com",
Secret: secret,
},
Metadata: validCMetadata,
Status: mfclients.EnabledStatus,
},
err: nil,
token: validToken,
},
{
desc: "register a new disabled client with metadata",
client: mfclients.Client{
Credentials: mfclients.Credentials{
Identity: "newclientwithmetadata@example.com",
Secret: secret,
},
Metadata: validCMetadata,
},
err: nil,
token: validToken,
},
{
desc: "register a new disabled client",
client: mfclients.Client{
Credentials: mfclients.Credentials{
Identity: "newclientwithvalidstatus@example.com",
Secret: secret,
},
},
err: nil,
token: validToken,
},
{
desc: "register a new client with valid disabled status",
client: mfclients.Client{
Credentials: mfclients.Credentials{
Identity: "newclientwithvalidstatus@example.com",
Secret: secret,
},
Status: mfclients.DisabledStatus,
},
err: nil,
token: validToken,
},
{
desc: "register a new client with all fields",
client: mfclients.Client{
Name: "newclientwithallfields",
Tags: []string{"tag1", "tag2"},
Credentials: mfclients.Credentials{
Identity: "newclientwithallfields@example.com",
Secret: secret,
},
Metadata: mfclients.Metadata{
"name": "newclientwithallfields",
},
Status: mfclients.EnabledStatus,
},
err: nil,
token: validToken,
},
{
desc: "register a new client with missing identity",
client: mfclients.Client{
Name: "clientWithMissingIdentity",
Credentials: mfclients.Credentials{
Secret: secret,
},
},
err: errors.ErrMalformedEntity,
token: validToken,
},
{
desc: "register a new client with invalid owner",
client: mfclients.Client{
Owner: mocks.WrongID,
Credentials: mfclients.Credentials{
Identity: "newclientwithinvalidowner@example.com",
Secret: secret,
},
},
err: errors.ErrMalformedEntity,
token: validToken,
},
{
desc: "register a new client with empty secret",
client: mfclients.Client{
Owner: testsutil.GenerateUUID(t),
Credentials: mfclients.Credentials{
Identity: "newclientwithemptysecret@example.com",
},
},
err: apiutil.ErrMissingSecret,
token: validToken,
},
{
desc: "register a new client with invalid status",
client: mfclients.Client{
Credentials: mfclients.Credentials{
Identity: "newclientwithinvalidstatus@example.com",
Secret: secret,
},
Status: mfclients.AllStatus,
},
err: apiutil.ErrInvalidStatus,
token: validToken,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("AddPolicy", mock.Anything, mock.Anything).Return(&mainflux.AddPolicyRes{Authorized: true}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall2 := cRepo.On("Save", context.Background(), mock.Anything).Return(&mfclients.Client{}, tc.err)
registerTime := time.Now()
expected, err := svc.CreateThings(context.Background(), tc.token, tc.client)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
if err == nil {
assert.NotEmpty(t, expected[0].ID, fmt.Sprintf("%s: expected %s not to be empty\n", tc.desc, expected[0].ID))
assert.WithinDuration(t, expected[0].CreatedAt, registerTime, withinDuration, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, expected[0].CreatedAt, registerTime))
tc.client.ID = expected[0].ID
tc.client.CreatedAt = expected[0].CreatedAt
tc.client.UpdatedAt = expected[0].UpdatedAt
tc.client.Credentials.Secret = expected[0].Credentials.Secret
tc.client.Owner = expected[0].Owner
tc.client.UpdatedBy = expected[0].UpdatedBy
assert.Equal(t, tc.client, expected[0], fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client, expected[0]))
}
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
}
}
func TestViewClient(t *testing.T) {
svc, cRepo, auth := newService()
cases := []struct {
desc string
token string
clientID string
response mfclients.Client
err error
}{
{
desc: "view client successfully",
response: client,
token: validToken,
clientID: client.ID,
err: nil,
},
{
desc: "view client with an invalid token",
response: mfclients.Client{},
token: inValidToken,
clientID: "",
err: errors.ErrAuthentication,
},
{
desc: "view client with valid token and invalid client id",
response: mfclients.Client{},
token: validToken,
clientID: mocks.WrongID,
err: errors.ErrNotFound,
},
{
desc: "view client with an invalid token and invalid client id",
response: mfclients.Client{},
token: inValidToken,
clientID: mocks.WrongID,
err: errors.ErrAuthorization,
},
}
for _, tc := range cases {
repoCall := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, tc.err)
if tc.token == inValidToken {
repoCall = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall1 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.response, tc.err)
rClient, err := svc.ViewClient(context.Background(), tc.token, tc.clientID)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.response, rClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, rClient))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestListClients(t *testing.T) {
svc, cRepo, auth := newService()
nClients := uint64(200)
aClients := []mfclients.Client{}
OwnerID := testsutil.GenerateUUID(t)
for i := uint64(1); i < nClients; i++ {
identity := fmt.Sprintf("TestListClients_%d@example.com", i)
client := mfclients.Client{
Name: identity,
Credentials: mfclients.Credentials{
Identity: identity,
Secret: "password",
},
Tags: []string{"tag1", "tag2"},
Metadata: mfclients.Metadata{"role": "client"},
}
if i%50 == 0 {
client.Owner = OwnerID
client.Owner = testsutil.GenerateUUID(t)
}
aClients = append(aClients, client)
}
cases := []struct {
desc string
token string
page mfclients.Page
response mfclients.ClientsPage
size uint64
err error
}{
{
desc: "list clients with authorized token",
token: validToken,
page: mfclients.Page{
Status: mfclients.AllStatus,
},
size: 0,
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 0,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{},
},
err: nil,
},
{
desc: "list clients with an invalid token",
token: inValidToken,
page: mfclients.Page{
Status: mfclients.AllStatus,
},
size: 0,
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 0,
Offset: 0,
Limit: 0,
},
},
err: errors.ErrAuthentication,
},
{
desc: "list clients that are shared with me",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Status: mfclients.EnabledStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 4,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{aClients[0], aClients[50], aClients[100], aClients[150]},
},
size: 4,
},
{
desc: "list clients that are shared with me with a specific name",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Name: "TestListClients3",
Status: mfclients.EnabledStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 4,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{aClients[0], aClients[50], aClients[100], aClients[150]},
},
size: 4,
},
{
desc: "list clients that are shared with me with an invalid name",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Name: "notpresentclient",
Status: mfclients.EnabledStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 0,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{},
},
size: 0,
},
{
desc: "list clients that I own",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Owner: myKey,
Status: mfclients.EnabledStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 4,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{aClients[0], aClients[50], aClients[100], aClients[150]},
},
size: 4,
},
{
desc: "list clients that I own with a specific name",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Owner: myKey,
Name: "TestListClients3",
Status: mfclients.AllStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 4,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{aClients[0], aClients[50], aClients[100], aClients[150]},
},
size: 4,
},
{
desc: "list clients that I own with an invalid name",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Owner: myKey,
Name: "notpresentclient",
Status: mfclients.AllStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 0,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{},
},
size: 0,
},
{
desc: "list clients that I own and are shared with me",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Owner: myKey,
Status: mfclients.AllStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 4,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{aClients[0], aClients[50], aClients[100], aClients[150]},
},
size: 4,
},
{
desc: "list clients that I own and are shared with me with a specific name",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Owner: myKey,
Name: "TestListClients3",
Status: mfclients.AllStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 4,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{aClients[0], aClients[50], aClients[100], aClients[150]},
},
size: 4,
},
{
desc: "list clients that I own and are shared with me with an invalid name",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Owner: myKey,
Name: "notpresentclient",
Status: mfclients.AllStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 0,
Offset: 0,
Limit: 0,
},
Clients: []mfclients.Client{},
},
size: 0,
},
{
desc: "list clients with offset and limit",
token: validToken,
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Status: mfclients.AllStatus,
},
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: nClients - 6,
Offset: 0,
Limit: 0,
},
Clients: aClients[6:nClients],
},
size: nClients - 6,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&mainflux.ListObjectsRes{}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&mainflux.ListObjectsRes{}, errors.ErrAuthorization)
}
repoCall2 := cRepo.On("RetrieveAllByIDs", context.Background(), mock.Anything).Return(tc.response, tc.err)
page, err := svc.ListClients(context.Background(), tc.token, "", tc.page)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
}
}
func TestUpdateClient(t *testing.T) {
svc, cRepo, auth := newService()
client1 := client
client2 := client
client1.Name = "Updated client"
client2.Metadata = mfclients.Metadata{"role": "test"}
cases := []struct {
desc string
client mfclients.Client
response mfclients.Client
token string
err error
}{
{
desc: "update client name with valid token",
client: client1,
response: client1,
token: validToken,
err: nil,
},
{
desc: "update client name with invalid token",
client: client1,
response: mfclients.Client{},
token: "non-existent",
err: errors.ErrAuthentication,
},
{
desc: "update client name with invalid ID",
client: mfclients.Client{
ID: mocks.WrongID,
Name: "Updated Client",
},
response: mfclients.Client{},
token: validToken,
err: errors.ErrNotFound,
},
{
desc: "update client metadata with valid token",
client: client2,
response: client2,
token: validToken,
err: nil,
},
{
desc: "update client metadata with invalid token",
client: client2,
response: mfclients.Client{},
token: "non-existent",
err: errors.ErrAuthentication,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall2 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(mfclients.Client{}, tc.err)
repoCall3 := cRepo.On("Update", context.Background(), mock.Anything).Return(tc.response, tc.err)
updatedClient, err := svc.UpdateClient(context.Background(), tc.token, tc.client)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.response, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, updatedClient))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
}
}
func TestUpdateClientTags(t *testing.T) {
svc, cRepo, auth := newService()
client.Tags = []string{"updated"}
cases := []struct {
desc string
client mfclients.Client
response mfclients.Client
token string
err error
}{
{
desc: "update client tags with valid token",
client: client,
token: validToken,
response: client,
err: nil,
},
{
desc: "update client tags with invalid token",
client: client,
token: "non-existent",
response: mfclients.Client{},
err: errors.ErrAuthentication,
},
{
desc: "update client name with invalid ID",
client: mfclients.Client{
ID: mocks.WrongID,
Name: "Updated name",
},
response: mfclients.Client{},
token: validToken,
err: errors.ErrNotFound,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall2 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(mfclients.Client{}, tc.err)
repoCall3 := cRepo.On("UpdateTags", context.Background(), mock.Anything).Return(tc.response, tc.err)
updatedClient, err := svc.UpdateClientTags(context.Background(), tc.token, tc.client)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.response, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, updatedClient))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
}
}
func TestUpdateClientOwner(t *testing.T) {
svc, cRepo, auth := newService()
client.Owner = "newowner@mail.com"
cases := []struct {
desc string
client mfclients.Client
response mfclients.Client
token string
err error
}{
{
desc: "update client owner with valid token",
client: client,
token: validToken,
response: client,
err: nil,
},
{
desc: "update client owner with invalid token",
client: client,
token: "non-existent",
response: mfclients.Client{},
err: errors.ErrAuthentication,
},
{
desc: "update client owner with invalid ID",
client: mfclients.Client{
ID: mocks.WrongID,
Owner: "updatedowner@mail.com",
},
response: mfclients.Client{},
token: validToken,
err: errors.ErrNotFound,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall2 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(mfclients.Client{}, tc.err)
repoCall3 := cRepo.On("UpdateOwner", context.Background(), mock.Anything).Return(tc.response, tc.err)
updatedClient, err := svc.UpdateClientOwner(context.Background(), tc.token, tc.client)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.response, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, updatedClient))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
}
}
func TestUpdateClientSecret(t *testing.T) {
svc, cRepo, auth := newService()
cases := []struct {
desc string
id string
newSecret string
token string
response mfclients.Client
err error
}{
{
desc: "update client secret with valid token",
id: client.ID,
newSecret: "newSecret",
token: validToken,
response: client,
err: nil,
},
{
desc: "update client secret with invalid token",
id: client.ID,
newSecret: "newPassword",
token: "non-existent",
response: mfclients.Client{},
err: errors.ErrAuthentication,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall2 := cRepo.On("UpdateSecret", context.Background(), mock.Anything).Return(tc.response, tc.err)
updatedClient, err := svc.UpdateClientSecret(context.Background(), tc.token, tc.id, tc.newSecret)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.response, updatedClient, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, updatedClient))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
}
}
func TestEnableClient(t *testing.T) {
svc, cRepo, auth := newService()
enabledClient1 := mfclients.Client{ID: ID, Credentials: mfclients.Credentials{Identity: "client1@example.com", Secret: "password"}, Status: mfclients.EnabledStatus}
disabledClient1 := mfclients.Client{ID: ID, Credentials: mfclients.Credentials{Identity: "client3@example.com", Secret: "password"}, Status: mfclients.DisabledStatus}
endisabledClient1 := disabledClient1
endisabledClient1.Status = mfclients.EnabledStatus
cases := []struct {
desc string
id string
token string
client mfclients.Client
response mfclients.Client
err error
}{
{
desc: "enable disabled client",
id: disabledClient1.ID,
token: validToken,
client: disabledClient1,
response: endisabledClient1,
err: nil,
},
{
desc: "enable enabled client",
id: enabledClient1.ID,
token: validToken,
client: enabledClient1,
response: enabledClient1,
err: mfclients.ErrStatusAlreadyAssigned,
},
{
desc: "enable non-existing client",
id: mocks.WrongID,
token: validToken,
client: mfclients.Client{},
response: mfclients.Client{},
err: errors.ErrNotFound,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall2 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.client, tc.err)
repoCall3 := cRepo.On("ChangeStatus", context.Background(), mock.Anything).Return(tc.response, tc.err)
_, err := svc.EnableClient(context.Background(), tc.token, tc.id)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
}
cases2 := []struct {
desc string
status mfclients.Status
size uint64
response mfclients.ClientsPage
}{
{
desc: "list enabled clients",
status: mfclients.EnabledStatus,
size: 2,
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 2,
Offset: 0,
Limit: 100,
},
Clients: []mfclients.Client{enabledClient1, endisabledClient1},
},
},
{
desc: "list disabled clients",
status: mfclients.DisabledStatus,
size: 1,
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 1,
Offset: 0,
Limit: 100,
},
Clients: []mfclients.Client{disabledClient1},
},
},
{
desc: "list enabled and disabled clients",
status: mfclients.AllStatus,
size: 3,
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 3,
Offset: 0,
Limit: 100,
},
Clients: []mfclients.Client{enabledClient1, disabledClient1, endisabledClient1},
},
},
}
for _, tc := range cases2 {
pm := mfclients.Page{
Offset: 0,
Limit: 100,
Status: tc.status,
}
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&mainflux.ListObjectsRes{}, nil)
repoCall2 := cRepo.On("RetrieveAllByIDs", context.Background(), mock.Anything).Return(tc.response, nil)
page, err := svc.ListClients(context.Background(), validToken, "", pm)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
size := uint64(len(page.Clients))
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
}
}
func TestDisableClient(t *testing.T) {
svc, cRepo, auth := newService()
enabledClient1 := mfclients.Client{ID: ID, Credentials: mfclients.Credentials{Identity: "client1@example.com", Secret: "password"}, Status: mfclients.EnabledStatus}
disabledClient1 := mfclients.Client{ID: ID, Credentials: mfclients.Credentials{Identity: "client3@example.com", Secret: "password"}, Status: mfclients.DisabledStatus}
disenabledClient1 := enabledClient1
disenabledClient1.Status = mfclients.DisabledStatus
cases := []struct {
desc string
id string
token string
client mfclients.Client
response mfclients.Client
err error
}{
{
desc: "disable enabled client",
id: enabledClient1.ID,
token: validToken,
client: enabledClient1,
response: disenabledClient1,
err: nil,
},
{
desc: "disable disabled client",
id: disabledClient1.ID,
token: validToken,
client: disabledClient1,
response: mfclients.Client{},
err: mfclients.ErrStatusAlreadyAssigned,
},
{
desc: "disable non-existing client",
id: mocks.WrongID,
client: mfclients.Client{},
token: validToken,
response: mfclients.Client{},
err: errors.ErrNotFound,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall2 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.client, tc.err)
repoCall3 := cRepo.On("ChangeStatus", context.Background(), mock.Anything).Return(tc.response, tc.err)
_, err := svc.DisableClient(context.Background(), tc.token, tc.id)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
}
cases2 := []struct {
desc string
status mfclients.Status
size uint64
response mfclients.ClientsPage
}{
{
desc: "list enabled clients",
status: mfclients.EnabledStatus,
size: 1,
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 1,
Offset: 0,
Limit: 100,
},
Clients: []mfclients.Client{enabledClient1},
},
},
{
desc: "list disabled clients",
status: mfclients.DisabledStatus,
size: 2,
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 2,
Offset: 0,
Limit: 100,
},
Clients: []mfclients.Client{disenabledClient1, disabledClient1},
},
},
{
desc: "list enabled and disabled clients",
status: mfclients.AllStatus,
size: 3,
response: mfclients.ClientsPage{
Page: mfclients.Page{
Total: 3,
Offset: 0,
Limit: 100,
},
Clients: []mfclients.Client{enabledClient1, disabledClient1, disenabledClient1},
},
},
}
for _, tc := range cases2 {
pm := mfclients.Page{
Offset: 0,
Limit: 100,
Status: tc.status,
}
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&mainflux.ListObjectsRes{}, nil)
repoCall2 := cRepo.On("RetrieveAllByIDs", context.Background(), mock.Anything).Return(tc.response, nil)
page, err := svc.ListClients(context.Background(), validToken, "", pm)
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
size := uint64(len(page.Clients))
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
}
}
func TestListMembers(t *testing.T) {
svc, cRepo, auth := newService()
nClients := uint64(10)
aClients := []mfclients.Client{}
owner := testsutil.GenerateUUID(t)
for i := uint64(0); i < nClients; i++ {
identity := fmt.Sprintf("member_%d@example.com", i)
client := mfclients.Client{
ID: testsutil.GenerateUUID(t),
Name: identity,
Credentials: mfclients.Credentials{
Identity: identity,
Secret: "password",
},
Tags: []string{"tag1", "tag2"},
Metadata: mfclients.Metadata{"role": "client"},
}
if i%3 == 0 {
client.Owner = owner
}
aClients = append(aClients, client)
}
cases := []struct {
desc string
token string
groupID string
page mfclients.Page
response mfclients.MembersPage
err error
}{
{
desc: "list clients with authorized token",
token: validToken,
groupID: testsutil.GenerateUUID(t),
page: mfclients.Page{
Owner: adminEmail,
},
response: mfclients.MembersPage{
Page: mfclients.Page{
Total: 0,
Offset: 0,
Limit: 0,
},
Members: []mfclients.Client{},
},
err: nil,
},
{
desc: "list clients with offset and limit",
token: validToken,
groupID: testsutil.GenerateUUID(t),
page: mfclients.Page{
Offset: 6,
Limit: nClients,
Status: mfclients.AllStatus,
Owner: adminEmail,
},
response: mfclients.MembersPage{
Page: mfclients.Page{
Total: nClients - 6 - 1,
},
Members: aClients[6 : nClients-1],
},
},
{
desc: "list clients with an invalid token",
token: inValidToken,
groupID: testsutil.GenerateUUID(t),
page: mfclients.Page{
Owner: adminEmail,
},
response: mfclients.MembersPage{
Page: mfclients.Page{
Total: 0,
Offset: 0,
Limit: 0,
},
},
err: errors.ErrAuthentication,
},
{
desc: "list clients with an invalid id",
token: validToken,
groupID: mocks.WrongID,
page: mfclients.Page{
Owner: adminEmail,
},
response: mfclients.MembersPage{
Page: mfclients.Page{
Total: 0,
Offset: 0,
Limit: 0,
},
},
err: errors.ErrNotFound,
},
{
desc: "list clients for an owner",
token: validToken,
groupID: testsutil.GenerateUUID(t),
page: mfclients.Page{
Owner: adminEmail,
},
response: mfclients.MembersPage{
Page: mfclients.Page{
Total: 4,
},
Members: []mfclients.Client{aClients[0], aClients[3], aClients[6], aClients[9]},
},
err: nil,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, nil)
if tc.token == inValidToken {
repoCall = auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: inValidToken}).Return(&mainflux.IdentityRes{}, errors.ErrAuthentication)
repoCall1 = auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: false}, errors.ErrAuthorization)
}
repoCall2 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&mainflux.ListObjectsRes{}, nil)
repoCall3 := cRepo.On("RetrieveAllByIDs", context.Background(), tc.page).Return(mfclients.ClientsPage{Page: tc.response.Page, Clients: tc.response.Members}, tc.err)
page, err := svc.ListClientsByGroup(context.Background(), tc.token, tc.groupID, tc.page)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
}
}