mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-26 13:48:53 +08:00

* List Members and Membership To also include Owner Signed-off-by: rodneyosodo <blackd0t@protonmail.com> * Add Member Repository Tests Signed-off-by: rodneyosodo <blackd0t@protonmail.com> * Add Service Tests Signed-off-by: rodneyosodo <blackd0t@protonmail.com> * Add More Test Signed-off-by: rodneyosodo <blackd0t@protonmail.com> --------- Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
1460 lines
48 KiB
Go
1460 lines
48 KiB
Go
// Copyright (c) Mainflux
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package clients_test
|
|
|
|
import (
|
|
context "context"
|
|
fmt "fmt"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/mainflux/mainflux/internal/apiutil"
|
|
"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/users/clients"
|
|
"github.com/mainflux/mainflux/users/clients/mocks"
|
|
"github.com/mainflux/mainflux/users/hasher"
|
|
"github.com/mainflux/mainflux/users/jwt"
|
|
pmocks "github.com/mainflux/mainflux/users/policies/mocks"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var (
|
|
idProvider = uuid.New()
|
|
phasher = hasher.New()
|
|
secret = "strongsecret"
|
|
validCMetadata = mfclients.Metadata{"role": "client"}
|
|
client = mfclients.Client{
|
|
ID: testsutil.GenerateUUID(&testing.T{}, idProvider),
|
|
Name: "clientname",
|
|
Tags: []string{"tag1", "tag2"},
|
|
Credentials: mfclients.Credentials{Identity: "clientidentity", Secret: secret},
|
|
Metadata: validCMetadata,
|
|
Status: mfclients.EnabledStatus,
|
|
}
|
|
inValidToken = "invalidToken"
|
|
withinDuration = 5 * time.Second
|
|
passRegex = regexp.MustCompile("^.{8,}$")
|
|
accessDuration = time.Minute * 1
|
|
refreshDuration = time.Minute * 10
|
|
)
|
|
|
|
func TestRegisterClient(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
client mfclients.Client
|
|
token string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "register new client",
|
|
client: client,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "register existing client",
|
|
client: client,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
desc: "register a new disabled client",
|
|
client: mfclients.Client{
|
|
Credentials: mfclients.Credentials{
|
|
Identity: "newclientwithvalidstatus@example.com",
|
|
Secret: secret,
|
|
},
|
|
},
|
|
err: nil,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
desc: "register a new client with missing identity",
|
|
client: mfclients.Client{
|
|
Name: "clientWithMissingIdentity",
|
|
Credentials: mfclients.Credentials{
|
|
Secret: secret,
|
|
},
|
|
},
|
|
err: errors.ErrMalformedEntity,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
desc: "register a new client with empty secret",
|
|
client: mfclients.Client{
|
|
Owner: testsutil.GenerateUUID(t, idProvider),
|
|
Credentials: mfclients.Credentials{
|
|
Identity: "newclientwithemptysecret@example.com",
|
|
},
|
|
},
|
|
err: apiutil.ErrMissingSecret,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
{
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := cRepo.On("Save", context.Background(), mock.Anything).Return(&mfclients.Client{}, tc.err)
|
|
registerTime := time.Now()
|
|
expected, err := svc.RegisterClient(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.ID, fmt.Sprintf("%s: expected %s not to be empty\n", tc.desc, expected.ID))
|
|
assert.WithinDuration(t, expected.CreatedAt, registerTime, withinDuration, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, expected.CreatedAt, registerTime))
|
|
tc.client.ID = expected.ID
|
|
tc.client.CreatedAt = expected.CreatedAt
|
|
tc.client.UpdatedAt = expected.UpdatedAt
|
|
tc.client.Credentials.Secret = expected.Credentials.Secret
|
|
tc.client.Owner = expected.Owner
|
|
tc.client.UpdatedBy = expected.UpdatedBy
|
|
assert.Equal(t, tc.client, expected, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client, expected))
|
|
ok := repoCall.Parent.AssertCalled(t, "Save", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("Save was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
}
|
|
}
|
|
|
|
func TestViewClient(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
token string
|
|
clientID string
|
|
response mfclients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "view client successfully",
|
|
response: client,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
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.ErrAuthentication,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := pRepo.On("Evaluate", context.Background(), "client", mock.Anything).Return(nil)
|
|
repoCall1 := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall2 := cRepo.On("RetrieveByID", context.Background(), tc.clientID).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))
|
|
if tc.err == nil {
|
|
ok := repoCall1.Parent.AssertCalled(t, "CheckAdmin", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("CheckAdmin was not called on %s", tc.desc))
|
|
ok = repoCall2.Parent.AssertCalled(t, "RetrieveByID", context.Background(), tc.clientID)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
|
|
}
|
|
repoCall2.Unset()
|
|
repoCall1.Unset()
|
|
repoCall.Unset()
|
|
}
|
|
}
|
|
|
|
func TestListClients(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
var nClients = uint64(200)
|
|
var aClients = []mfclients.Client{}
|
|
var OwnerID = testsutil.GenerateUUID(t, idProvider)
|
|
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, idProvider)
|
|
}
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
SharedBy: clients.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 are shared with me with a specific name",
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
SharedBy: clients.MyKey,
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
SharedBy: clients.MyKey,
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
Owner: clients.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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
Owner: clients.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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
Owner: clients.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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
Owner: clients.MyKey,
|
|
SharedBy: clients.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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
SharedBy: clients.MyKey,
|
|
Owner: clients.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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
SharedBy: clients.MyKey,
|
|
Owner: clients.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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
|
|
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 := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(tc.err)
|
|
repoCall1 := cRepo.On("RetrieveAll", 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))
|
|
if tc.err == nil {
|
|
ok := repoCall1.Parent.AssertCalled(t, "RetrieveAll", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveAll was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
}
|
|
}
|
|
|
|
func TestUpdateClient(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
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: "non-existent",
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
{
|
|
desc: "update client metadata with valid token",
|
|
client: client2,
|
|
response: client2,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
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 := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall1 := 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))
|
|
if tc.err == nil {
|
|
ok := repoCall.Parent.AssertCalled(t, "CheckAdmin", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("CheckAdmin was not called on %s", tc.desc))
|
|
ok = repoCall1.Parent.AssertCalled(t, "Update", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("Update was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
}
|
|
}
|
|
|
|
func TestUpdateClientTags(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
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: "non-existent",
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall1 := 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))
|
|
if tc.err == nil {
|
|
ok := repoCall.Parent.AssertCalled(t, "CheckAdmin", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("CheckAdmin was not called on %s", tc.desc))
|
|
ok = repoCall1.Parent.AssertCalled(t, "UpdateTags", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("UpdateTags was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
}
|
|
}
|
|
|
|
func TestUpdateClientIdentity(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
client2 := client
|
|
client2.Credentials.Identity = "updated@example.com"
|
|
|
|
cases := []struct {
|
|
desc string
|
|
identity string
|
|
response mfclients.Client
|
|
token string
|
|
id string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "update client identity with valid token",
|
|
identity: "updated@example.com",
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
id: client.ID,
|
|
response: client2,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update client identity with invalid id",
|
|
identity: "updated@example.com",
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
id: mocks.WrongID,
|
|
response: mfclients.Client{},
|
|
err: errors.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "update client identity with invalid token",
|
|
identity: "updated@example.com",
|
|
token: "non-existent",
|
|
id: client2.ID,
|
|
response: mfclients.Client{},
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall1 := cRepo.On("UpdateIdentity", context.Background(), mock.Anything).Return(tc.response, tc.err)
|
|
updatedClient, err := svc.UpdateClientIdentity(context.Background(), tc.token, tc.id, tc.identity)
|
|
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))
|
|
if tc.err == nil {
|
|
ok := repoCall.Parent.AssertCalled(t, "CheckAdmin", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("CheckAdmin was not called on %s", tc.desc))
|
|
ok = repoCall1.Parent.AssertCalled(t, "UpdateIdentity", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("UpdateIdentity was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
}
|
|
}
|
|
|
|
func TestUpdateClientOwner(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
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: "non-existent",
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall1 := 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))
|
|
if tc.err == nil {
|
|
ok := repoCall.Parent.AssertCalled(t, "CheckAdmin", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("CheckAdmin was not called on %s", tc.desc))
|
|
ok = repoCall1.Parent.AssertCalled(t, "UpdateOwner", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("UpdateOwner was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
}
|
|
}
|
|
|
|
func TestUpdateClientSecret(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
rClient := client
|
|
rClient.Credentials.Secret, _ = phasher.Hash(client.Credentials.Secret)
|
|
|
|
repoCall := cRepo.On("RetrieveByIdentity", context.Background(), client.Credentials.Identity).Return(rClient, nil)
|
|
token, err := svc.IssueToken(context.Background(), client.Credentials.Identity, client.Credentials.Secret)
|
|
assert.Nil(t, err, fmt.Sprintf("Issue token expected nil got %s\n", err))
|
|
repoCall.Unset()
|
|
|
|
cases := []struct {
|
|
desc string
|
|
oldSecret string
|
|
newSecret string
|
|
token string
|
|
response mfclients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "update client secret with valid token",
|
|
oldSecret: client.Credentials.Secret,
|
|
newSecret: "newSecret",
|
|
token: token.AccessToken,
|
|
response: rClient,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update client secret with invalid token",
|
|
oldSecret: client.Credentials.Secret,
|
|
newSecret: "newPassword",
|
|
token: "non-existent",
|
|
response: mfclients.Client{},
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
{
|
|
desc: "update client secret with wrong old secret",
|
|
oldSecret: "oldSecret",
|
|
newSecret: "newSecret",
|
|
token: token.AccessToken,
|
|
response: mfclients.Client{},
|
|
err: apiutil.ErrInvalidSecret,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := cRepo.On("RetrieveByID", context.Background(), client.ID).Return(tc.response, tc.err)
|
|
repoCall1 := cRepo.On("RetrieveByIdentity", context.Background(), client.Credentials.Identity).Return(tc.response, tc.err)
|
|
repoCall2 := cRepo.On("UpdateSecret", context.Background(), mock.Anything).Return(tc.response, tc.err)
|
|
updatedClient, err := svc.UpdateClientSecret(context.Background(), tc.token, tc.oldSecret, 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))
|
|
if tc.err == nil {
|
|
ok := repoCall.Parent.AssertCalled(t, "RetrieveByID", context.Background(), tc.response.ID)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
|
|
ok = repoCall1.Parent.AssertCalled(t, "RetrieveByIdentity", context.Background(), tc.response.Credentials.Identity)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveByIdentity was not called on %s", tc.desc))
|
|
ok = repoCall2.Parent.AssertCalled(t, "UpdateSecret", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("UpdateSecret was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
repoCall2.Unset()
|
|
}
|
|
}
|
|
|
|
func TestEnableClient(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
enabledClient1 := mfclients.Client{ID: testsutil.GenerateUUID(t, idProvider), Credentials: mfclients.Credentials{Identity: "client1@example.com", Secret: "password"}, Status: mfclients.EnabledStatus}
|
|
disabledClient1 := mfclients.Client{ID: testsutil.GenerateUUID(t, idProvider), 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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
client: disabledClient1,
|
|
response: endisabledClient1,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "enable enabled client",
|
|
id: enabledClient1.ID,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
client: enabledClient1,
|
|
response: enabledClient1,
|
|
err: mfclients.ErrStatusAlreadyAssigned,
|
|
},
|
|
{
|
|
desc: "enable non-existing client",
|
|
id: mocks.WrongID,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
client: mfclients.Client{},
|
|
response: mfclients.Client{},
|
|
err: errors.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall1 := cRepo.On("RetrieveByID", context.Background(), tc.id).Return(tc.client, tc.err)
|
|
repoCall2 := 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))
|
|
if tc.err == nil {
|
|
ok := repoCall.Parent.AssertCalled(t, "CheckAdmin", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("CheckAdmin was not called on %s", tc.desc))
|
|
ok = repoCall1.Parent.AssertCalled(t, "RetrieveByID", context.Background(), tc.id)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
|
|
ok = repoCall2.Parent.AssertCalled(t, "ChangeStatus", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("ChangeStatus was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
repoCall2.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,
|
|
Action: "c_list",
|
|
}
|
|
repoCall := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall1 := cRepo.On("RetrieveAll", context.Background(), mock.Anything).Return(tc.response, nil)
|
|
page, err := svc.ListClients(context.Background(), testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher), 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()
|
|
}
|
|
}
|
|
|
|
func TestDisableClient(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
enabledClient1 := mfclients.Client{ID: testsutil.GenerateUUID(t, idProvider), Credentials: mfclients.Credentials{Identity: "client1@example.com", Secret: "password"}, Status: mfclients.EnabledStatus}
|
|
disabledClient1 := mfclients.Client{ID: testsutil.GenerateUUID(t, idProvider), 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: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
client: enabledClient1,
|
|
response: disenabledClient1,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "disable disabled client",
|
|
id: disabledClient1.ID,
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
client: disabledClient1,
|
|
response: mfclients.Client{},
|
|
err: mfclients.ErrStatusAlreadyAssigned,
|
|
},
|
|
{
|
|
desc: "disable non-existing client",
|
|
id: mocks.WrongID,
|
|
client: mfclients.Client{},
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
response: mfclients.Client{},
|
|
err: errors.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall1 := cRepo.On("RetrieveByID", context.Background(), tc.id).Return(tc.client, tc.err)
|
|
repoCall2 := 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))
|
|
if tc.err == nil {
|
|
ok := repoCall.Parent.AssertCalled(t, "CheckAdmin", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("CheckAdmin was not called on %s", tc.desc))
|
|
ok = repoCall1.Parent.AssertCalled(t, "RetrieveByID", context.Background(), tc.id)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
|
|
ok = repoCall2.Parent.AssertCalled(t, "ChangeStatus", context.Background(), mock.Anything)
|
|
assert.True(t, ok, fmt.Sprintf("ChangeStatus was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
repoCall2.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,
|
|
Action: "c_list",
|
|
}
|
|
repoCall := pRepo.On("CheckAdmin", context.Background(), mock.Anything).Return(nil)
|
|
repoCall1 := cRepo.On("RetrieveAll", context.Background(), mock.Anything).Return(tc.response, nil)
|
|
page, err := svc.ListClients(context.Background(), testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher), 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()
|
|
}
|
|
}
|
|
|
|
func TestListMembers(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
var nClients = uint64(10)
|
|
var aClients = []mfclients.Client{}
|
|
owner := testsutil.GenerateUUID(t, idProvider)
|
|
for i := uint64(0); i < nClients; i++ {
|
|
identity := fmt.Sprintf("member_%d@example.com", i)
|
|
client := mfclients.Client{
|
|
ID: testsutil.GenerateUUID(t, idProvider),
|
|
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)
|
|
}
|
|
validID := testsutil.GenerateUUID(t, idProvider)
|
|
validToken := testsutil.GenerateValidToken(t, validID, svc, cRepo, phasher)
|
|
|
|
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, idProvider),
|
|
page: mfclients.Page{
|
|
Subject: validID,
|
|
Action: "g_list",
|
|
},
|
|
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, idProvider),
|
|
page: mfclients.Page{
|
|
Offset: 6,
|
|
Limit: nClients,
|
|
Status: mfclients.AllStatus,
|
|
Subject: validID,
|
|
Action: "g_list",
|
|
},
|
|
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, idProvider),
|
|
page: mfclients.Page{
|
|
Subject: validID,
|
|
Action: "g_list",
|
|
},
|
|
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{
|
|
Subject: validID,
|
|
Action: "g_list",
|
|
},
|
|
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, idProvider),
|
|
page: mfclients.Page{
|
|
Subject: owner,
|
|
Action: "g_list",
|
|
},
|
|
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 := pRepo.On("CheckAdmin", context.Background(), validID).Return(nil)
|
|
repoCall1 := cRepo.On("Members", context.Background(), tc.groupID, tc.page).Return(tc.response, tc.err)
|
|
page, err := svc.ListMembers(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))
|
|
if tc.err == nil {
|
|
ok := repoCall.Parent.AssertCalled(t, "CheckAdmin", context.Background(), validID)
|
|
assert.True(t, ok, fmt.Sprintf("CheckAdmin was not called on %s", tc.desc))
|
|
ok = repoCall1.Parent.AssertCalled(t, "Members", context.Background(), tc.groupID, tc.page)
|
|
assert.True(t, ok, fmt.Sprintf("Members was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
repoCall1.Unset()
|
|
}
|
|
}
|
|
|
|
func TestIssueToken(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
rClient := client
|
|
rClient2 := client
|
|
rClient3 := client
|
|
rClient.Credentials.Secret, _ = phasher.Hash(client.Credentials.Secret)
|
|
rClient2.Credentials.Secret = "wrongsecret"
|
|
rClient3.Credentials.Secret, _ = phasher.Hash("wrongsecret")
|
|
|
|
cases := []struct {
|
|
desc string
|
|
client mfclients.Client
|
|
rClient mfclients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "issue token for an existing client",
|
|
client: client,
|
|
rClient: rClient,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "issue token for a non-existing client",
|
|
client: client,
|
|
rClient: mfclients.Client{},
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
{
|
|
desc: "issue token for a client with wrong secret",
|
|
client: rClient2,
|
|
rClient: rClient3,
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall := cRepo.On("RetrieveByIdentity", context.Background(), tc.client.Credentials.Identity).Return(tc.rClient, tc.err)
|
|
token, err := svc.IssueToken(context.Background(), tc.client.Credentials.Identity, tc.client.Credentials.Secret)
|
|
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, token.AccessToken, fmt.Sprintf("%s: expected %s not to be empty\n", tc.desc, token.AccessToken))
|
|
assert.NotEmpty(t, token.RefreshToken, fmt.Sprintf("%s: expected %s not to be empty\n", tc.desc, token.RefreshToken))
|
|
ok := repoCall.Parent.AssertCalled(t, "RetrieveByIdentity", context.Background(), tc.client.Credentials.Identity)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveByIdentity was not called on %s", tc.desc))
|
|
}
|
|
repoCall.Unset()
|
|
}
|
|
}
|
|
|
|
func TestRefreshToken(t *testing.T) {
|
|
cRepo := new(mocks.Repository)
|
|
pRepo := new(pmocks.Repository)
|
|
tokenizer := jwt.NewRepository([]byte(secret), accessDuration, refreshDuration)
|
|
e := mocks.NewEmailer()
|
|
svc := clients.NewService(cRepo, pRepo, tokenizer, e, phasher, idProvider, passRegex)
|
|
|
|
rClient := client
|
|
rClient.Credentials.Secret, _ = phasher.Hash(client.Credentials.Secret)
|
|
|
|
repoCall := cRepo.On("RetrieveByIdentity", context.Background(), client.Credentials.Identity).Return(rClient, nil)
|
|
token, err := svc.IssueToken(context.Background(), client.Credentials.Identity, client.Credentials.Secret)
|
|
assert.Nil(t, err, fmt.Sprintf("Issue token expected nil got %s\n", err))
|
|
repoCall.Unset()
|
|
|
|
cases := []struct {
|
|
desc string
|
|
token string
|
|
client mfclients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "refresh token with refresh token for an existing client",
|
|
token: token.RefreshToken,
|
|
client: client,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "refresh token with refresh token for a non-existing client",
|
|
token: token.RefreshToken,
|
|
client: mfclients.Client{},
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
{
|
|
desc: "refresh token with access token for an existing client",
|
|
token: token.AccessToken,
|
|
client: client,
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
{
|
|
desc: "refresh token with access token for a non-existing client",
|
|
token: token.AccessToken,
|
|
client: mfclients.Client{},
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
{
|
|
desc: "refresh token with invalid token for an existing client",
|
|
token: testsutil.GenerateValidToken(t, testsutil.GenerateUUID(t, idProvider), svc, cRepo, phasher),
|
|
client: client,
|
|
err: errors.ErrAuthentication,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
repoCall1 := cRepo.On("RetrieveByIdentity", context.Background(), tc.client.Credentials.Identity).Return(tc.client, nil)
|
|
repoCall2 := cRepo.On("RetrieveByID", context.Background(), mock.Anything).Return(tc.client, tc.err)
|
|
token, err := svc.RefreshToken(context.Background(), tc.token)
|
|
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, token.AccessToken, fmt.Sprintf("%s: expected %s not to be empty\n", tc.desc, token.AccessToken))
|
|
assert.NotEmpty(t, token.RefreshToken, fmt.Sprintf("%s: expected %s not to be empty\n", tc.desc, token.RefreshToken))
|
|
ok := repoCall1.Parent.AssertCalled(t, "RetrieveByIdentity", context.Background(), tc.client.Credentials.Identity)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveByIdentity was not called on %s", tc.desc))
|
|
ok = repoCall2.Parent.AssertCalled(t, "RetrieveByID", context.Background(), tc.client.ID)
|
|
assert.True(t, ok, fmt.Sprintf("RetrieveByID was not called on %s", tc.desc))
|
|
}
|
|
repoCall1.Unset()
|
|
repoCall2.Unset()
|
|
}
|
|
}
|