Files
Dušan Borovčanin 61d0427898 NOISSUE - Rename to Magistrala (#3427)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-06 15:23:42 +02:00

1144 lines
33 KiB
Go

// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package domains_test
import (
"context"
"fmt"
"testing"
"time"
"github.com/absmach/magistrala/domains"
"github.com/absmach/magistrala/domains/mocks"
"github.com/absmach/magistrala/groups"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/authn"
"github.com/absmach/magistrala/pkg/errors"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
policiesMocks "github.com/absmach/magistrala/pkg/policies/mocks"
"github.com/absmach/magistrala/pkg/roles"
"github.com/absmach/magistrala/pkg/sid"
"github.com/absmach/magistrala/pkg/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
const (
groupName = "smqx"
validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22"
)
var (
ErrExpiry = errors.New("session is expired")
errAddPolicies = errors.New("failed to add policies")
inValid = "invalid"
valid = "valid"
domain = domains.Domain{
ID: validID,
Name: groupName,
Tags: []string{"tag1", "tag2"},
Route: "test",
RoleID: "test_role_id",
CreatedBy: validID,
UpdatedBy: validID,
}
validRoles = []roles.MemberRoleActions{
{
RoleID: "domain_role_id",
RoleName: "domain_role_name",
Actions: []string{"read", "delete"},
AccessType: "direct",
},
}
domainWithRoles = domains.Domain{
ID: validID,
Name: groupName,
Tags: []string{"tag1", "tag2"},
Route: "test",
RoleID: "test_role_id",
CreatedBy: validID,
UpdatedBy: validID,
Roles: validRoles,
}
userID = testsutil.GenerateUUID(&testing.T{})
validSession = authn.Session{UserID: userID}
validInvitation = domains.Invitation{
InviteeUserID: testsutil.GenerateUUID(&testing.T{}),
DomainID: testsutil.GenerateUUID(&testing.T{}),
RoleID: testsutil.GenerateUUID(&testing.T{}),
}
)
var (
drepo *mocks.Repository
dcache *mocks.Cache
policy *policiesMocks.Service
)
func newService() domains.Service {
drepo = new(mocks.Repository)
dcache = new(mocks.Cache)
idProvider := uuid.NewMock()
sidProvider := sid.NewMock()
policy = new(policiesMocks.Service)
availableActions := []roles.Action{}
builtInRoles := map[roles.BuiltInRoleName][]roles.Action{
groups.BuiltInRoleAdmin: availableActions,
}
ds, _ := domains.New(drepo, dcache, policy, idProvider, sidProvider, availableActions, builtInRoles)
return ds
}
func TestCreateDomain(t *testing.T) {
svc := newService()
cases := []struct {
desc string
d domains.Domain
session authn.Session
userID string
addPoliciesErr error
addRolesErr error
saveDomainErr error
deleteDomainErr error
deletePoliciesErr error
err error
}{
{
desc: "create domain successfully",
d: domains.Domain{
Name: groupName,
Status: domains.EnabledStatus,
},
session: validSession,
err: nil,
},
{
desc: "create domain with custom id",
d: domains.Domain{
ID: validID,
Name: groupName,
Status: domains.EnabledStatus,
},
session: validSession,
err: nil,
},
{
desc: "create domain with invalid status",
d: domains.Domain{
Name: groupName,
Status: domains.AllStatus,
},
session: validSession,
err: svcerr.ErrInvalidStatus,
},
{
desc: "create domain with failed to save domain",
d: domains.Domain{
Name: groupName,
Status: domains.EnabledStatus,
},
session: validSession,
saveDomainErr: svcerr.ErrCreateEntity,
err: svcerr.ErrCreateEntity,
},
{
desc: "create domain with failed to add policies",
d: domains.Domain{
Name: groupName,
Status: domains.EnabledStatus,
},
session: validSession,
addPoliciesErr: errAddPolicies,
err: errAddPolicies,
},
{
desc: "create domain with failed to add policies and failed rollback",
d: domains.Domain{
Name: groupName,
Status: domains.EnabledStatus,
},
session: validSession,
addPoliciesErr: errAddPolicies,
deleteDomainErr: svcerr.ErrRemoveEntity,
err: svcerr.ErrRemoveEntity,
},
{
desc: "create domain with failed to add roles",
d: domains.Domain{
Name: groupName,
Status: domains.EnabledStatus,
},
session: validSession,
addRolesErr: errors.ErrMalformedEntity,
err: errors.ErrMalformedEntity,
},
{
desc: "create domain with failed to add roles and failed rollback",
d: domains.Domain{
Name: groupName,
Status: domains.EnabledStatus,
},
session: validSession,
addRolesErr: errors.ErrMalformedEntity,
deleteDomainErr: errors.ErrMalformedEntity,
err: errors.ErrMalformedEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("SaveDomain", mock.Anything, mock.Anything).Return(tc.d, tc.saveDomainErr)
repoCall1 := drepo.On("DeleteDomain", mock.Anything, mock.Anything).Return(tc.deleteDomainErr)
repoCall2 := drepo.On("AddRoles", mock.Anything, mock.Anything).Return([]roles.RoleProvision{}, tc.addRolesErr)
policyCall := policy.On("AddPolicies", mock.Anything, mock.Anything).Return(tc.addPoliciesErr)
policyCall1 := policy.On("DeletePolicies", mock.Anything, mock.Anything).Return(tc.deletePoliciesErr)
_, _, err := svc.CreateDomain(context.Background(), tc.session, tc.d)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.err, err))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
policyCall.Unset()
policyCall1.Unset()
})
}
}
func TestRetrieveDomain(t *testing.T) {
svc := newService()
superAdminSession := validSession
superAdminSession.SuperAdmin = true
cases := []struct {
desc string
session authn.Session
domainID string
withRoles bool
retrieveDomainRes domains.Domain
retrieveDomainErr error
err error
}{
{
desc: "retrieve domain successfully as super admin",
session: superAdminSession,
withRoles: false,
domainID: validID,
retrieveDomainRes: domain,
err: nil,
},
{
desc: "retrieve domain successfully as non super admin",
session: validSession,
withRoles: false,
domainID: validID,
retrieveDomainRes: domain,
err: nil,
},
{
desc: "retrieve domain successfully as non super admin with roles",
session: validSession,
withRoles: true,
domainID: validID,
retrieveDomainRes: domainWithRoles,
err: nil,
},
{
desc: "retrieve domain with empty domain id",
session: validSession,
withRoles: false,
domainID: "",
retrieveDomainErr: repoerr.ErrNotFound,
err: svcerr.ErrViewEntity,
},
{
desc: "retrieve non-existing domain",
session: validSession,
withRoles: false,
domainID: inValid,
retrieveDomainErr: repoerr.ErrNotFound,
err: svcerr.ErrViewEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveDomainByID", context.Background(), tc.domainID).Return(tc.retrieveDomainRes, tc.retrieveDomainErr)
repoCall1 := drepo.On("RetrieveDomainByIDWithRoles", context.Background(), tc.domainID, tc.session.UserID).Return(tc.retrieveDomainRes, tc.retrieveDomainErr)
domain, err := svc.RetrieveDomain(context.Background(), tc.session, tc.domainID, tc.withRoles)
assert.True(t, errors.Contains(err, tc.err))
switch tc.withRoles {
case true:
assert.Equal(t, domain.Roles, validRoles, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, validRoles, domain.Roles))
ok := drepo.AssertCalled(t, "RetrieveDomainByIDWithRoles", context.Background(), tc.domainID, tc.session.UserID)
assert.True(t, ok, fmt.Sprintf("RetrieveDomainByIDWithRoles was not called on %s", tc.desc))
default:
assert.Empty(t, domain.Roles)
ok := drepo.AssertCalled(t, "RetrieveDomainByID", context.Background(), tc.domainID)
assert.True(t, ok, fmt.Sprintf("RetrieveDomainByID was not called on %s", tc.desc))
}
assert.Equal(t, tc.retrieveDomainRes, domain)
repoCall.Unset()
repoCall1.Unset()
})
}
}
func TestUpdateDomain(t *testing.T) {
svc := newService()
updatedDomain := domain
updatedDomain.Name = valid
updatedDomain.Route = valid
cases := []struct {
desc string
session authn.Session
domainID string
updateReq domains.DomainReq
updateRes domains.Domain
updateErr error
err error
}{
{
desc: "update domain successfully",
session: validSession,
domainID: domain.ID,
updateReq: domains.DomainReq{
Name: &valid,
},
updateRes: updatedDomain,
err: nil,
},
{
desc: "update domain with empty domainID",
session: validSession,
domainID: "",
updateReq: domains.DomainReq{
Name: &valid,
},
updateErr: repoerr.ErrNotFound,
err: svcerr.ErrUpdateEntity,
},
{
desc: "update domain with failed to update",
session: validSession,
domainID: domain.ID,
updateReq: domains.DomainReq{
Name: &valid,
},
updateErr: errors.ErrMalformedEntity,
err: svcerr.ErrUpdateEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("UpdateDomain", context.Background(), tc.domainID, mock.Anything).Return(tc.updateRes, tc.updateErr)
domain, err := svc.UpdateDomain(context.Background(), tc.session, tc.domainID, tc.updateReq)
assert.True(t, errors.Contains(err, tc.err))
assert.Equal(t, tc.updateRes, domain)
repoCall.Unset()
})
}
}
func TestEnableDomain(t *testing.T) {
svc := newService()
enabledDomain := domain
enabledDomain.Status = domains.EnabledStatus
cases := []struct {
desc string
session authn.Session
domainID string
enableRes domains.Domain
enableErr error
cacheErr error
resp domains.Domain
err error
}{
{
desc: "enable domain successfully",
session: validSession,
domainID: domain.ID,
enableRes: enabledDomain,
resp: enabledDomain,
err: nil,
},
{
desc: "enable domain with empty domainID",
session: validSession,
domainID: "",
enableErr: repoerr.ErrNotFound,
resp: domains.Domain{},
err: svcerr.ErrUpdateEntity,
},
{
desc: "enable domain with failed to enable",
session: validSession,
domainID: domain.ID,
enableErr: errors.ErrMalformedEntity,
resp: domains.Domain{},
err: svcerr.ErrUpdateEntity,
},
{
desc: "enable domain with failed to remove cache",
session: validSession,
domainID: domain.ID,
enableRes: enabledDomain,
cacheErr: errors.ErrMalformedEntity,
resp: enabledDomain,
err: svcerr.ErrRemoveEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("UpdateDomain", context.Background(), tc.domainID, mock.Anything).Return(tc.enableRes, tc.enableErr)
cacheCall := dcache.On("RemoveStatus", context.Background(), tc.domainID).Return(tc.cacheErr)
domain, err := svc.EnableDomain(context.Background(), tc.session, tc.domainID)
assert.True(t, errors.Contains(err, tc.err))
assert.Equal(t, tc.resp, domain)
repoCall.Unset()
cacheCall.Unset()
})
}
}
func TestDisableDomain(t *testing.T) {
svc := newService()
disabledDomain := domain
disabledDomain.Status = domains.DisabledStatus
cases := []struct {
desc string
session authn.Session
domainID string
disableRes domains.Domain
disableErr error
cacheErr error
resp domains.Domain
err error
}{
{
desc: "disable domain successfully",
session: validSession,
domainID: domain.ID,
disableRes: disabledDomain,
resp: disabledDomain,
err: nil,
},
{
desc: "disable domain with empty domainID",
session: validSession,
domainID: "",
disableErr: repoerr.ErrNotFound,
resp: domains.Domain{},
err: svcerr.ErrUpdateEntity,
},
{
desc: "disable domain with failed to disable",
session: validSession,
domainID: domain.ID,
disableErr: errors.ErrMalformedEntity,
resp: domains.Domain{},
err: svcerr.ErrUpdateEntity,
},
{
desc: "disable domain with failed to remove cache",
session: validSession,
domainID: domain.ID,
disableRes: disabledDomain,
cacheErr: errors.ErrMalformedEntity,
resp: disabledDomain,
err: svcerr.ErrRemoveEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("UpdateDomain", context.Background(), tc.domainID, mock.Anything).Return(tc.disableRes, tc.disableErr)
cacheCall := dcache.On("RemoveStatus", context.Background(), tc.domainID).Return(tc.cacheErr)
domain, err := svc.DisableDomain(context.Background(), tc.session, tc.domainID)
assert.True(t, errors.Contains(err, tc.err))
assert.Equal(t, tc.disableRes, domain)
repoCall.Unset()
cacheCall.Unset()
})
}
}
func TestFreezeDomain(t *testing.T) {
svc := newService()
freezeDomain := domain
freezeDomain.Status = domains.FreezeStatus
cases := []struct {
desc string
session authn.Session
domainID string
freezeRes domains.Domain
freezeErr error
cacheErr error
resp domains.Domain
err error
}{
{
desc: "freeze domain successfully",
session: validSession,
domainID: domain.ID,
freezeRes: freezeDomain,
resp: freezeDomain,
err: nil,
},
{
desc: "freeze domain with empty domainID",
session: validSession,
domainID: "",
freezeErr: repoerr.ErrNotFound,
resp: domains.Domain{},
err: svcerr.ErrUpdateEntity,
},
{
desc: "freeze domain with failed to freeze",
session: validSession,
domainID: domain.ID,
freezeErr: errors.ErrMalformedEntity,
resp: domains.Domain{},
err: svcerr.ErrUpdateEntity,
},
{
desc: "freeze domain with failed to remove cache",
session: validSession,
domainID: domain.ID,
freezeRes: freezeDomain,
cacheErr: errors.ErrMalformedEntity,
resp: freezeDomain,
err: svcerr.ErrRemoveEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("UpdateDomain", context.Background(), tc.domainID, mock.Anything).Return(tc.freezeRes, tc.freezeErr)
cacheCall := dcache.On("RemoveStatus", context.Background(), tc.domainID).Return(tc.cacheErr)
domain, err := svc.FreezeDomain(context.Background(), tc.session, tc.domainID)
assert.True(t, errors.Contains(err, tc.err))
assert.Equal(t, tc.freezeRes, domain)
repoCall.Unset()
cacheCall.Unset()
})
}
}
func TestListDomains(t *testing.T) {
svc := newService()
cases := []struct {
desc string
session authn.Session
domainID string
pageMeta domains.Page
listDomainsRes domains.DomainsPage
listDomainErr error
err error
}{
{
desc: "list domains successfully",
session: validSession,
domainID: validID,
pageMeta: domains.Page{
UserID: userID,
Offset: 0,
Limit: 10,
Status: domains.EnabledStatus,
},
listDomainsRes: domains.DomainsPage{
Domains: []domains.Domain{domain},
Offset: 0,
Limit: 10,
Total: 1,
},
err: nil,
},
{
desc: "list domains as admin successfully",
session: authn.Session{UserID: validID, SuperAdmin: true},
domainID: validID,
pageMeta: domains.Page{
Offset: 0,
Limit: 10,
Status: domains.EnabledStatus,
},
listDomainsRes: domains.DomainsPage{
Domains: []domains.Domain{domain},
Offset: 0,
Limit: 10,
Total: 1,
},
err: nil,
},
{
desc: "list domains with repository error on list domains",
session: validSession,
domainID: validID,
pageMeta: domains.Page{
UserID: userID,
Offset: 0,
Limit: 10,
Status: domains.EnabledStatus,
},
listDomainErr: errors.ErrMalformedEntity,
err: svcerr.ErrViewEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall1 := drepo.On("ListDomains", context.Background(), tc.pageMeta).Return(tc.listDomainsRes, tc.listDomainErr)
dp, err := svc.ListDomains(context.Background(), tc.session, tc.pageMeta)
assert.True(t, errors.Contains(err, tc.err))
assert.Equal(t, tc.listDomainsRes, dp)
repoCall1.Unset()
})
}
}
func TestSendInvitation(t *testing.T) {
svc := newService()
rejectedInvitation := validInvitation
rejectedInvitation.RejectedAt = time.Now()
acceptedInvitation := validInvitation
acceptedInvitation.ConfirmedAt = time.Now()
resentInvitation := validInvitation
resentInvitation.Resend = true
cases := []struct {
desc string
session authn.Session
req domains.Invitation
retrieveRoleErr error
retrieveDomainErr error
createInvitationErr error
retrieveInvRes domains.Invitation
retrieveInvErr error
updateRejectionErr error
err error
}{
{
desc: "send invitation successful",
session: validSession,
req: validInvitation,
err: nil,
},
{
desc: "send invitation with invalid role id",
session: validSession,
req: domains.Invitation{
DomainID: testsutil.GenerateUUID(t),
InviteeUserID: testsutil.GenerateUUID(t),
RoleID: inValid,
},
retrieveRoleErr: repoerr.ErrNotFound,
err: svcerr.ErrInvalidRole,
},
{
desc: "send invitation with failed to retrieve domain",
session: validSession,
req: validInvitation,
retrieveDomainErr: repoerr.ErrNotFound,
err: svcerr.ErrViewEntity,
},
{
desc: "send invitations with failed to save invitation",
session: validSession,
req: validInvitation,
createInvitationErr: repoerr.ErrCreateEntity,
err: svcerr.ErrCreateEntity,
},
{
desc: "resend invitation successfully",
session: validSession,
req: resentInvitation,
retrieveInvRes: rejectedInvitation,
retrieveInvErr: nil,
err: nil,
},
{
desc: "resend invitation with failed to retrieve invitation",
session: validSession,
req: resentInvitation,
retrieveInvRes: domains.Invitation{},
retrieveInvErr: repoerr.ErrNotFound,
err: svcerr.ErrViewEntity,
},
{
desc: "resend an invitation that is already accepted",
session: validSession,
req: resentInvitation,
retrieveInvRes: acceptedInvitation,
retrieveInvErr: nil,
err: svcerr.ErrInvitationAlreadyAccepted,
},
{
desc: "resend invitation with failed to update rejection",
session: validSession,
req: resentInvitation,
retrieveInvRes: rejectedInvitation,
retrieveInvErr: nil,
updateRejectionErr: repoerr.ErrUpdateEntity,
err: svcerr.ErrUpdateEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveRole", context.Background(), tc.req.RoleID).Return(roles.Role{Name: "admin"}, tc.retrieveRoleErr)
repoCall1 := drepo.On("RetrieveDomainByID", context.Background(), tc.req.DomainID).Return(domains.Domain{Name: "test_domain"}, tc.retrieveDomainErr)
repoCall2 := drepo.On("SaveInvitation", context.Background(), mock.Anything).Return(tc.createInvitationErr)
repoCall3 := drepo.On("RetrieveInvitation", context.Background(), tc.req.InviteeUserID, tc.req.DomainID).Return(tc.retrieveInvRes, tc.retrieveInvErr)
repoCall4 := drepo.On("UpdateRejection", context.Background(), mock.Anything).Return(tc.updateRejectionErr)
_, err := svc.SendInvitation(context.Background(), tc.session, tc.req)
assert.True(t, errors.Contains(err, tc.err))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
repoCall4.Unset()
})
}
}
func TestListInvitations(t *testing.T) {
svc := newService()
validPageMeta := domains.InvitationPageMeta{
Offset: 0,
Limit: 10,
}
validResp := domains.InvitationPage{
Total: 1,
Offset: 0,
Limit: 10,
Invitations: []domains.Invitation{
{
InvitedBy: testsutil.GenerateUUID(t),
InviteeUserID: testsutil.GenerateUUID(t),
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
RoleName: "admin",
CreatedAt: time.Now().Add(-time.Hour),
UpdatedAt: time.Now().Add(-time.Hour),
ConfirmedAt: time.Now().Add(-time.Hour),
},
},
}
cases := []struct {
desc string
session authn.Session
page domains.InvitationPageMeta
resp domains.InvitationPage
err error
repoErr error
}{
{
desc: "list invitations successful",
session: validSession,
page: validPageMeta,
resp: validResp,
err: nil,
repoErr: nil,
},
{
desc: "list invitations unsuccessful",
session: validSession,
page: validPageMeta,
err: svcerr.ErrViewEntity,
resp: domains.InvitationPage{},
repoErr: repoerr.ErrViewEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveAllInvitations", context.Background(), mock.Anything).Return(tc.resp, tc.repoErr)
resp, err := svc.ListInvitations(context.Background(), tc.session, tc.page)
assert.True(t, errors.Contains(err, tc.err), tc.desc)
assert.Equal(t, tc.resp, resp, tc.desc)
repoCall.Unset()
})
}
}
func TestListDomainInvitations(t *testing.T) {
svc := newService()
validPageMeta := domains.InvitationPageMeta{
Offset: 0,
Limit: 10,
}
validResp := domains.InvitationPage{
Total: 1,
Offset: 0,
Limit: 10,
Invitations: []domains.Invitation{
{
InvitedBy: testsutil.GenerateUUID(t),
InviteeUserID: testsutil.GenerateUUID(t),
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
RoleName: "admin",
CreatedAt: time.Now().Add(-time.Hour),
UpdatedAt: time.Now().Add(-time.Hour),
ConfirmedAt: time.Now().Add(-time.Hour),
},
},
}
cases := []struct {
desc string
session authn.Session
page domains.InvitationPageMeta
resp domains.InvitationPage
repoErr error
err error
}{
{
desc: "list domain invitations successful",
session: validSession,
page: validPageMeta,
resp: validResp,
repoErr: nil,
err: nil,
},
{
desc: "list domain invitations unsuccessful",
session: validSession,
page: validPageMeta,
resp: domains.InvitationPage{},
repoErr: repoerr.ErrViewEntity,
err: svcerr.ErrViewEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveAllInvitations", context.Background(), mock.Anything).Return(tc.resp, tc.repoErr)
resp, err := svc.ListDomainInvitations(context.Background(), tc.session, tc.page)
assert.True(t, errors.Contains(err, tc.err), tc.desc)
assert.Equal(t, tc.resp, resp, tc.desc)
repoCall.Unset()
})
}
}
func TestAcceptInvitation(t *testing.T) {
svc := newService()
cases := []struct {
desc string
domainID string
session authn.Session
resp domains.Invitation
retrieveInvitationErr error
retrieveDomainErr error
retrieveRoleErr error
updateConfirmationErr error
addRoleMemberErr error
err error
}{
{
desc: "accept invitation successful",
domainID: validID,
session: validSession,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
},
err: nil,
},
{
desc: "accept invitation with failed to retrieve invitation",
session: validSession,
retrieveInvitationErr: repoerr.ErrNotFound,
err: svcerr.ErrNotFound,
},
{
desc: "accept invitation with of different user",
session: validSession,
resp: domains.Invitation{
InviteeUserID: testsutil.GenerateUUID(t),
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
},
err: svcerr.ErrAuthorization,
},
{
desc: "accept invitation with failed to add role member",
domainID: validID,
session: validSession,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
},
addRoleMemberErr: repoerr.ErrMalformedEntity,
err: svcerr.ErrUpdateEntity,
},
{
desc: "accept invitation with failed update confirmation",
session: validSession,
domainID: validID,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: validID,
RoleID: testsutil.GenerateUUID(t),
},
updateConfirmationErr: repoerr.ErrNotFound,
err: svcerr.ErrUpdateEntity,
},
{
desc: "accept invitation that is already confirmed",
session: validSession,
domainID: validID,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
ConfirmedAt: time.Now(),
},
err: svcerr.ErrInvitationAlreadyAccepted,
},
{
desc: "accept rejected invitation",
session: validSession,
domainID: validID,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
RejectedAt: time.Now(),
},
err: svcerr.ErrInvitationAlreadyRejected,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveInvitation", context.Background(), tc.session.UserID, tc.domainID).Return(tc.resp, tc.retrieveInvitationErr)
repoCall1 := drepo.On("RetrieveDomainByID", context.Background(), tc.domainID).Return(domains.Domain{Name: "test_domain"}, tc.retrieveDomainErr)
repoCall2 := drepo.On("RetrieveRole", context.Background(), tc.resp.RoleID).Return(roles.Role{Name: "admin"}, tc.retrieveRoleErr)
repoCall3 := drepo.On("RetrieveEntityRole", context.Background(), tc.domainID, tc.resp.RoleID).Return(roles.Role{}, tc.addRoleMemberErr)
policyCall := policy.On("AddPolicies", context.Background(), mock.Anything).Return(tc.addRoleMemberErr)
repoCall4 := drepo.On("RoleAddMembers", context.Background(), mock.Anything, []string{tc.resp.InviteeUserID}).Return([]string{}, tc.addRoleMemberErr)
repoCall5 := drepo.On("UpdateConfirmation", context.Background(), mock.Anything).Return(tc.updateConfirmationErr)
_, err := svc.AcceptInvitation(context.Background(), tc.session, tc.domainID)
assert.True(t, errors.Contains(err, tc.err))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
policyCall.Unset()
repoCall4.Unset()
repoCall5.Unset()
})
}
}
func TestRejectInvitation(t *testing.T) {
svc := newService()
cases := []struct {
desc string
domainID string
session authn.Session
resp domains.Invitation
retrieveInvitationErr error
updateConfirmationErr error
addRoleMemberErr error
err error
}{
{
desc: "reject invitation successful",
domainID: validID,
session: validSession,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
},
err: nil,
},
{
desc: "reject invitation with failed to retrieve invitation",
session: validSession,
retrieveInvitationErr: repoerr.ErrNotFound,
err: svcerr.ErrNotFound,
},
{
desc: "reject invitation with of different user",
session: validSession,
resp: domains.Invitation{
InviteeUserID: testsutil.GenerateUUID(t),
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
},
err: svcerr.ErrAuthorization,
},
{
desc: "reject invitation with failed update confirmation",
session: validSession,
domainID: validID,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: validID,
RoleID: testsutil.GenerateUUID(t),
},
updateConfirmationErr: repoerr.ErrNotFound,
err: svcerr.ErrUpdateEntity,
},
{
desc: "reject invitation that is already confirmed",
session: validSession,
domainID: validID,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
ConfirmedAt: time.Now(),
},
err: svcerr.ErrInvitationAlreadyAccepted,
},
{
desc: "reject rejected invitation",
session: validSession,
domainID: validID,
resp: domains.Invitation{
InviteeUserID: userID,
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
RejectedAt: time.Now(),
},
err: svcerr.ErrInvitationAlreadyRejected,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveInvitation", context.Background(), tc.session.UserID, tc.domainID).Return(tc.resp, tc.retrieveInvitationErr)
repoCall1 := drepo.On("RetrieveDomainByID", context.Background(), tc.domainID).Return(domains.Domain{Name: "test_domain"}, nil)
repoCall2 := drepo.On("RetrieveRole", context.Background(), tc.resp.RoleID).Return(roles.Role{Name: "admin"}, nil)
repoCall3 := drepo.On("UpdateRejection", context.Background(), mock.Anything).Return(tc.updateConfirmationErr)
_, err := svc.RejectInvitation(context.Background(), tc.session, tc.domainID)
assert.True(t, errors.Contains(err, tc.err))
repoCall.Unset()
repoCall1.Unset()
repoCall2.Unset()
repoCall3.Unset()
})
}
}
func TestDeleteInvitation(t *testing.T) {
svc := newService()
acceptedInv := validInvitation
acceptedInv.ConfirmedAt = time.Now()
rejectedInv := validInvitation
rejectedInv.RejectedAt = time.Now()
cases := []struct {
desc string
userID string
domainID string
session authn.Session
resp domains.Invitation
retrieveInvitationErr error
deleteInvitationErr error
err error
}{
{
desc: "delete invitations successful",
userID: testsutil.GenerateUUID(t),
domainID: testsutil.GenerateUUID(t),
session: validSession,
resp: validInvitation,
err: nil,
},
{
desc: "delete invitations for the same user",
userID: validInvitation.InviteeUserID,
domainID: validInvitation.DomainID,
resp: validInvitation,
session: authn.Session{UserID: validInvitation.InviteeUserID},
err: nil,
},
{
desc: "delete invitations for the invited user",
userID: validInvitation.InviteeUserID,
domainID: validInvitation.DomainID,
session: validSession,
resp: validInvitation,
err: nil,
},
{
desc: "delete accepted invitation as non invitee user",
userID: validID,
domainID: validInvitation.DomainID,
session: validSession,
resp: acceptedInv,
err: svcerr.ErrInvitationAlreadyAccepted,
},
{
desc: "delete rejected invitation as non invitee user",
userID: validID,
domainID: validInvitation.DomainID,
session: validSession,
resp: rejectedInv,
err: svcerr.ErrInvitationAlreadyRejected,
},
{
desc: "delete invitation with error retrieving invitation",
userID: validInvitation.InviteeUserID,
domainID: validInvitation.DomainID,
session: validSession,
resp: domains.Invitation{},
retrieveInvitationErr: repoerr.ErrNotFound,
err: svcerr.ErrRemoveEntity,
},
{
desc: "delete invitation with error deleting invitation",
userID: validInvitation.InviteeUserID,
domainID: validInvitation.DomainID,
session: validSession,
resp: domains.Invitation{},
deleteInvitationErr: repoerr.ErrNotFound,
err: svcerr.ErrRemoveEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveInvitation", context.Background(), mock.Anything, mock.Anything).Return(tc.resp, tc.retrieveInvitationErr)
repoCall1 := drepo.On("DeleteUsersInvitations", context.Background(), mock.Anything, mock.Anything).Return(tc.deleteInvitationErr)
err := svc.DeleteInvitation(context.Background(), tc.session, tc.userID, tc.domainID)
assert.True(t, errors.Contains(err, tc.err))
repoCall.Unset()
repoCall1.Unset()
})
}
}