mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-20 01:06:45 +00:00
643 lines
20 KiB
Go
643 lines
20 KiB
Go
package users
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
|
"github.com/netbirdio/netbird/management/server/mock_server"
|
|
"github.com/netbirdio/netbird/management/server/types"
|
|
"github.com/netbirdio/netbird/shared/auth"
|
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
|
"github.com/netbirdio/netbird/shared/management/status"
|
|
)
|
|
|
|
const (
|
|
testAccountID = "test-account-id"
|
|
testUserID = "test-user-id"
|
|
testInviteID = "test-invite-id"
|
|
testInviteToken = "nbi_testtoken123456789012345678"
|
|
testEmail = "invite@example.com"
|
|
testName = "Test User"
|
|
)
|
|
|
|
func setupInvitesTestHandler(am *mock_server.MockAccountManager) *invitesHandler {
|
|
return &invitesHandler{
|
|
accountManager: am,
|
|
}
|
|
}
|
|
|
|
func TestListInvites(t *testing.T) {
|
|
now := time.Now().UTC()
|
|
testInvites := []*types.UserInvite{
|
|
{
|
|
UserInfo: &types.UserInfo{
|
|
ID: "invite-1",
|
|
Email: "user1@example.com",
|
|
Name: "User One",
|
|
Role: "user",
|
|
AutoGroups: []string{"group-1"},
|
|
},
|
|
InviteExpiresAt: now.Add(24 * time.Hour),
|
|
InviteCreatedAt: now,
|
|
},
|
|
{
|
|
UserInfo: &types.UserInfo{
|
|
ID: "invite-2",
|
|
Email: "user2@example.com",
|
|
Name: "User Two",
|
|
Role: "admin",
|
|
AutoGroups: nil,
|
|
},
|
|
InviteExpiresAt: now.Add(-1 * time.Hour), // Expired
|
|
InviteCreatedAt: now.Add(-48 * time.Hour),
|
|
},
|
|
}
|
|
|
|
tt := []struct {
|
|
name string
|
|
expectedStatus int
|
|
mockFunc func(ctx context.Context, accountID, initiatorUserID string) ([]*types.UserInvite, error)
|
|
expectedCount int
|
|
}{
|
|
{
|
|
name: "successful list",
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string) ([]*types.UserInvite, error) {
|
|
return testInvites, nil
|
|
},
|
|
expectedCount: 2,
|
|
},
|
|
{
|
|
name: "empty list",
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string) ([]*types.UserInvite, error) {
|
|
return []*types.UserInvite{}, nil
|
|
},
|
|
expectedCount: 0,
|
|
},
|
|
{
|
|
name: "permission denied",
|
|
expectedStatus: http.StatusForbidden,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string) ([]*types.UserInvite, error) {
|
|
return nil, status.NewPermissionDeniedError()
|
|
},
|
|
expectedCount: 0,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
am := &mock_server.MockAccountManager{
|
|
ListUserInvitesFunc: tc.mockFunc,
|
|
}
|
|
handler := setupInvitesTestHandler(am)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/users/invites", nil)
|
|
req = nbcontext.SetUserAuthInRequest(req, auth.UserAuth{
|
|
UserId: testUserID,
|
|
AccountId: testAccountID,
|
|
})
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.listInvites(rr, req)
|
|
|
|
assert.Equal(t, tc.expectedStatus, rr.Code)
|
|
|
|
if tc.expectedStatus == http.StatusOK {
|
|
var resp []api.UserInvite
|
|
err := json.NewDecoder(rr.Body).Decode(&resp)
|
|
require.NoError(t, err)
|
|
assert.Len(t, resp, tc.expectedCount)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreateInvite(t *testing.T) {
|
|
now := time.Now().UTC()
|
|
expiresAt := now.Add(72 * time.Hour)
|
|
|
|
tt := []struct {
|
|
name string
|
|
requestBody string
|
|
expectedStatus int
|
|
mockFunc func(ctx context.Context, accountID, initiatorUserID string, invite *types.UserInfo, expiresIn int) (*types.UserInvite, error)
|
|
}{
|
|
{
|
|
name: "successful create",
|
|
requestBody: `{"email":"test@example.com","name":"Test User","role":"user","auto_groups":["group-1"]}`,
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string, invite *types.UserInfo, expiresIn int) (*types.UserInvite, error) {
|
|
return &types.UserInvite{
|
|
UserInfo: &types.UserInfo{
|
|
ID: testInviteID,
|
|
Email: invite.Email,
|
|
Name: invite.Name,
|
|
Role: invite.Role,
|
|
AutoGroups: invite.AutoGroups,
|
|
Status: string(types.UserStatusInvited),
|
|
},
|
|
InviteToken: testInviteToken,
|
|
InviteExpiresAt: expiresAt,
|
|
}, nil
|
|
},
|
|
},
|
|
{
|
|
name: "successful create with custom expiration",
|
|
requestBody: `{"email":"test@example.com","name":"Test User","role":"admin","auto_groups":[],"expires_in":3600}`,
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string, invite *types.UserInfo, expiresIn int) (*types.UserInvite, error) {
|
|
assert.Equal(t, 3600, expiresIn)
|
|
return &types.UserInvite{
|
|
UserInfo: &types.UserInfo{
|
|
ID: testInviteID,
|
|
Email: invite.Email,
|
|
Name: invite.Name,
|
|
Role: invite.Role,
|
|
AutoGroups: []string{},
|
|
Status: string(types.UserStatusInvited),
|
|
},
|
|
InviteToken: testInviteToken,
|
|
InviteExpiresAt: expiresAt,
|
|
}, nil
|
|
},
|
|
},
|
|
{
|
|
name: "user already exists",
|
|
requestBody: `{"email":"existing@example.com","name":"Existing User","role":"user","auto_groups":[]}`,
|
|
expectedStatus: http.StatusConflict,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string, invite *types.UserInfo, expiresIn int) (*types.UserInvite, error) {
|
|
return nil, status.Errorf(status.UserAlreadyExists, "user with this email already exists")
|
|
},
|
|
},
|
|
{
|
|
name: "invite already exists",
|
|
requestBody: `{"email":"invited@example.com","name":"Invited User","role":"user","auto_groups":[]}`,
|
|
expectedStatus: http.StatusConflict,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string, invite *types.UserInfo, expiresIn int) (*types.UserInvite, error) {
|
|
return nil, status.Errorf(status.AlreadyExists, "invite already exists for this email")
|
|
},
|
|
},
|
|
{
|
|
name: "permission denied",
|
|
requestBody: `{"email":"test@example.com","name":"Test User","role":"user","auto_groups":[]}`,
|
|
expectedStatus: http.StatusForbidden,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string, invite *types.UserInfo, expiresIn int) (*types.UserInvite, error) {
|
|
return nil, status.NewPermissionDeniedError()
|
|
},
|
|
},
|
|
{
|
|
name: "embedded IDP not enabled",
|
|
requestBody: `{"email":"test@example.com","name":"Test User","role":"user","auto_groups":[]}`,
|
|
expectedStatus: http.StatusPreconditionFailed,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID string, invite *types.UserInfo, expiresIn int) (*types.UserInvite, error) {
|
|
return nil, status.Errorf(status.PreconditionFailed, "invite links are only available with embedded identity provider")
|
|
},
|
|
},
|
|
{
|
|
name: "invalid JSON",
|
|
requestBody: `{invalid json}`,
|
|
expectedStatus: http.StatusBadRequest,
|
|
mockFunc: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
am := &mock_server.MockAccountManager{
|
|
CreateUserInviteFunc: tc.mockFunc,
|
|
}
|
|
handler := setupInvitesTestHandler(am)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/users/invites", bytes.NewBufferString(tc.requestBody))
|
|
req = nbcontext.SetUserAuthInRequest(req, auth.UserAuth{
|
|
UserId: testUserID,
|
|
AccountId: testAccountID,
|
|
})
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.createInvite(rr, req)
|
|
|
|
assert.Equal(t, tc.expectedStatus, rr.Code)
|
|
|
|
if tc.expectedStatus == http.StatusOK {
|
|
var resp api.UserInvite
|
|
err := json.NewDecoder(rr.Body).Decode(&resp)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, testInviteID, resp.Id)
|
|
assert.NotNil(t, resp.InviteToken)
|
|
assert.NotEmpty(t, *resp.InviteToken)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetInviteInfo(t *testing.T) {
|
|
now := time.Now().UTC()
|
|
|
|
tt := []struct {
|
|
name string
|
|
token string
|
|
expectedStatus int
|
|
mockFunc func(ctx context.Context, token string) (*types.UserInviteInfo, error)
|
|
}{
|
|
{
|
|
name: "successful get valid invite",
|
|
token: testInviteToken,
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, token string) (*types.UserInviteInfo, error) {
|
|
return &types.UserInviteInfo{
|
|
Email: testEmail,
|
|
Name: testName,
|
|
ExpiresAt: now.Add(24 * time.Hour),
|
|
Valid: true,
|
|
InvitedBy: "Admin User",
|
|
}, nil
|
|
},
|
|
},
|
|
{
|
|
name: "successful get expired invite",
|
|
token: testInviteToken,
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, token string) (*types.UserInviteInfo, error) {
|
|
return &types.UserInviteInfo{
|
|
Email: testEmail,
|
|
Name: testName,
|
|
ExpiresAt: now.Add(-24 * time.Hour),
|
|
Valid: false,
|
|
InvitedBy: "Admin User",
|
|
}, nil
|
|
},
|
|
},
|
|
{
|
|
name: "invite not found",
|
|
token: "nbi_invalidtoken1234567890123456",
|
|
expectedStatus: http.StatusNotFound,
|
|
mockFunc: func(ctx context.Context, token string) (*types.UserInviteInfo, error) {
|
|
return nil, status.Errorf(status.NotFound, "invite not found")
|
|
},
|
|
},
|
|
{
|
|
name: "invalid token format",
|
|
token: "invalid",
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: func(ctx context.Context, token string) (*types.UserInviteInfo, error) {
|
|
return nil, status.Errorf(status.InvalidArgument, "invalid invite token")
|
|
},
|
|
},
|
|
{
|
|
name: "missing token",
|
|
token: "",
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
am := &mock_server.MockAccountManager{
|
|
GetUserInviteInfoFunc: tc.mockFunc,
|
|
}
|
|
handler := setupInvitesTestHandler(am)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/users/invites/"+tc.token, nil)
|
|
if tc.token != "" {
|
|
req = mux.SetURLVars(req, map[string]string{"token": tc.token})
|
|
}
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.getInviteInfo(rr, req)
|
|
|
|
assert.Equal(t, tc.expectedStatus, rr.Code)
|
|
|
|
if tc.expectedStatus == http.StatusOK {
|
|
var resp api.UserInviteInfo
|
|
err := json.NewDecoder(rr.Body).Decode(&resp)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, testEmail, resp.Email)
|
|
assert.Equal(t, testName, resp.Name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAcceptInvite(t *testing.T) {
|
|
tt := []struct {
|
|
name string
|
|
token string
|
|
requestBody string
|
|
expectedStatus int
|
|
mockFunc func(ctx context.Context, token, password string) error
|
|
}{
|
|
{
|
|
name: "successful accept",
|
|
token: testInviteToken,
|
|
requestBody: `{"password":"SecurePass123!"}`,
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, token, password string) error {
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
name: "invite not found",
|
|
token: "nbi_invalidtoken1234567890123456",
|
|
requestBody: `{"password":"SecurePass123!"}`,
|
|
expectedStatus: http.StatusNotFound,
|
|
mockFunc: func(ctx context.Context, token, password string) error {
|
|
return status.Errorf(status.NotFound, "invite not found")
|
|
},
|
|
},
|
|
{
|
|
name: "invite expired",
|
|
token: testInviteToken,
|
|
requestBody: `{"password":"SecurePass123!"}`,
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: func(ctx context.Context, token, password string) error {
|
|
return status.Errorf(status.InvalidArgument, "invite has expired")
|
|
},
|
|
},
|
|
{
|
|
name: "embedded IDP not enabled",
|
|
token: testInviteToken,
|
|
requestBody: `{"password":"SecurePass123!"}`,
|
|
expectedStatus: http.StatusPreconditionFailed,
|
|
mockFunc: func(ctx context.Context, token, password string) error {
|
|
return status.Errorf(status.PreconditionFailed, "invite links are only available with embedded identity provider")
|
|
},
|
|
},
|
|
{
|
|
name: "missing token",
|
|
token: "",
|
|
requestBody: `{"password":"SecurePass123!"}`,
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: nil,
|
|
},
|
|
{
|
|
name: "invalid JSON",
|
|
token: testInviteToken,
|
|
requestBody: `{invalid}`,
|
|
expectedStatus: http.StatusBadRequest,
|
|
mockFunc: nil,
|
|
},
|
|
{
|
|
name: "password too short",
|
|
token: testInviteToken,
|
|
requestBody: `{"password":"Short1!"}`,
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: func(ctx context.Context, token, password string) error {
|
|
return status.Errorf(status.InvalidArgument, "password must be at least 8 characters long")
|
|
},
|
|
},
|
|
{
|
|
name: "password missing digit",
|
|
token: testInviteToken,
|
|
requestBody: `{"password":"NoDigitPass!"}`,
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: func(ctx context.Context, token, password string) error {
|
|
return status.Errorf(status.InvalidArgument, "password must contain at least one digit")
|
|
},
|
|
},
|
|
{
|
|
name: "password missing uppercase",
|
|
token: testInviteToken,
|
|
requestBody: `{"password":"nouppercase1!"}`,
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: func(ctx context.Context, token, password string) error {
|
|
return status.Errorf(status.InvalidArgument, "password must contain at least one uppercase letter")
|
|
},
|
|
},
|
|
{
|
|
name: "password missing special character",
|
|
token: testInviteToken,
|
|
requestBody: `{"password":"NoSpecial123"}`,
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: func(ctx context.Context, token, password string) error {
|
|
return status.Errorf(status.InvalidArgument, "password must contain at least one special character")
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
am := &mock_server.MockAccountManager{
|
|
AcceptUserInviteFunc: tc.mockFunc,
|
|
}
|
|
handler := setupInvitesTestHandler(am)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/users/invites/"+tc.token+"/accept", bytes.NewBufferString(tc.requestBody))
|
|
if tc.token != "" {
|
|
req = mux.SetURLVars(req, map[string]string{"token": tc.token})
|
|
}
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.acceptInvite(rr, req)
|
|
|
|
assert.Equal(t, tc.expectedStatus, rr.Code)
|
|
|
|
if tc.expectedStatus == http.StatusOK {
|
|
var resp api.UserInviteAcceptResponse
|
|
err := json.NewDecoder(rr.Body).Decode(&resp)
|
|
require.NoError(t, err)
|
|
assert.True(t, resp.Success)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRegenerateInvite(t *testing.T) {
|
|
now := time.Now().UTC()
|
|
expiresAt := now.Add(72 * time.Hour)
|
|
|
|
tt := []struct {
|
|
name string
|
|
inviteID string
|
|
requestBody string
|
|
expectedStatus int
|
|
mockFunc func(ctx context.Context, accountID, initiatorUserID, inviteID string, expiresIn int) (*types.UserInvite, error)
|
|
}{
|
|
{
|
|
name: "successful regenerate with empty body",
|
|
inviteID: testInviteID,
|
|
requestBody: "",
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID, inviteID string, expiresIn int) (*types.UserInvite, error) {
|
|
assert.Equal(t, 0, expiresIn)
|
|
return &types.UserInvite{
|
|
UserInfo: &types.UserInfo{
|
|
ID: inviteID,
|
|
Email: testEmail,
|
|
},
|
|
InviteToken: "nbi_newtoken12345678901234567890",
|
|
InviteExpiresAt: expiresAt,
|
|
}, nil
|
|
},
|
|
},
|
|
{
|
|
name: "successful regenerate with custom expiration",
|
|
inviteID: testInviteID,
|
|
requestBody: `{"expires_in":7200}`,
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID, inviteID string, expiresIn int) (*types.UserInvite, error) {
|
|
assert.Equal(t, 7200, expiresIn)
|
|
return &types.UserInvite{
|
|
UserInfo: &types.UserInfo{
|
|
ID: inviteID,
|
|
Email: testEmail,
|
|
},
|
|
InviteToken: "nbi_newtoken12345678901234567890",
|
|
InviteExpiresAt: expiresAt,
|
|
}, nil
|
|
},
|
|
},
|
|
{
|
|
name: "invite not found",
|
|
inviteID: "non-existent-invite",
|
|
requestBody: "",
|
|
expectedStatus: http.StatusNotFound,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID, inviteID string, expiresIn int) (*types.UserInvite, error) {
|
|
return nil, status.Errorf(status.NotFound, "invite not found")
|
|
},
|
|
},
|
|
{
|
|
name: "permission denied",
|
|
inviteID: testInviteID,
|
|
requestBody: "",
|
|
expectedStatus: http.StatusForbidden,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID, inviteID string, expiresIn int) (*types.UserInvite, error) {
|
|
return nil, status.NewPermissionDeniedError()
|
|
},
|
|
},
|
|
{
|
|
name: "missing invite ID",
|
|
inviteID: "",
|
|
requestBody: "",
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: nil,
|
|
},
|
|
{
|
|
name: "invalid JSON should return error",
|
|
inviteID: testInviteID,
|
|
requestBody: `{invalid json}`,
|
|
expectedStatus: http.StatusBadRequest,
|
|
mockFunc: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
am := &mock_server.MockAccountManager{
|
|
RegenerateUserInviteFunc: tc.mockFunc,
|
|
}
|
|
handler := setupInvitesTestHandler(am)
|
|
|
|
var body io.Reader
|
|
if tc.requestBody != "" {
|
|
body = bytes.NewBufferString(tc.requestBody)
|
|
}
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/users/invites/"+tc.inviteID+"/regenerate", body)
|
|
req = nbcontext.SetUserAuthInRequest(req, auth.UserAuth{
|
|
UserId: testUserID,
|
|
AccountId: testAccountID,
|
|
})
|
|
if tc.inviteID != "" {
|
|
req = mux.SetURLVars(req, map[string]string{"inviteId": tc.inviteID})
|
|
}
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.regenerateInvite(rr, req)
|
|
|
|
assert.Equal(t, tc.expectedStatus, rr.Code)
|
|
|
|
if tc.expectedStatus == http.StatusOK {
|
|
var resp api.UserInviteRegenerateResponse
|
|
err := json.NewDecoder(rr.Body).Decode(&resp)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, resp.InviteToken)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteInvite(t *testing.T) {
|
|
tt := []struct {
|
|
name string
|
|
inviteID string
|
|
expectedStatus int
|
|
mockFunc func(ctx context.Context, accountID, initiatorUserID, inviteID string) error
|
|
}{
|
|
{
|
|
name: "successful delete",
|
|
inviteID: testInviteID,
|
|
expectedStatus: http.StatusOK,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID, inviteID string) error {
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
name: "invite not found",
|
|
inviteID: "non-existent-invite",
|
|
expectedStatus: http.StatusNotFound,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID, inviteID string) error {
|
|
return status.Errorf(status.NotFound, "invite not found")
|
|
},
|
|
},
|
|
{
|
|
name: "permission denied",
|
|
inviteID: testInviteID,
|
|
expectedStatus: http.StatusForbidden,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID, inviteID string) error {
|
|
return status.NewPermissionDeniedError()
|
|
},
|
|
},
|
|
{
|
|
name: "embedded IDP not enabled",
|
|
inviteID: testInviteID,
|
|
expectedStatus: http.StatusPreconditionFailed,
|
|
mockFunc: func(ctx context.Context, accountID, initiatorUserID, inviteID string) error {
|
|
return status.Errorf(status.PreconditionFailed, "invite links are only available with embedded identity provider")
|
|
},
|
|
},
|
|
{
|
|
name: "missing invite ID",
|
|
inviteID: "",
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
mockFunc: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
am := &mock_server.MockAccountManager{
|
|
DeleteUserInviteFunc: tc.mockFunc,
|
|
}
|
|
handler := setupInvitesTestHandler(am)
|
|
|
|
req := httptest.NewRequest(http.MethodDelete, "/api/users/invites/"+tc.inviteID, nil)
|
|
req = nbcontext.SetUserAuthInRequest(req, auth.UserAuth{
|
|
UserId: testUserID,
|
|
AccountId: testAccountID,
|
|
})
|
|
if tc.inviteID != "" {
|
|
req = mux.SetURLVars(req, map[string]string{"inviteId": tc.inviteID})
|
|
}
|
|
|
|
rr := httptest.NewRecorder()
|
|
handler.deleteInvite(rr, req)
|
|
|
|
assert.Equal(t, tc.expectedStatus, rr.Code)
|
|
})
|
|
}
|
|
}
|