mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 07:10:19 +00:00
NOISSUE - Update Users tests (#2498)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
This commit is contained in:
@@ -148,7 +148,7 @@ paths:
|
||||
|
||||
patch:
|
||||
operationId: updateUser
|
||||
summary: Updates name and metadata of the user.
|
||||
summary: Updates first, last name and metadata of the user.
|
||||
description: |
|
||||
Updates name and metadata of the user with provided ID. Name and metadata
|
||||
is updated using authorization token and the new received info.
|
||||
@@ -244,7 +244,7 @@ paths:
|
||||
/users/{userID}/tags:
|
||||
patch:
|
||||
operationId: updateTags
|
||||
summary: Updates tags the user.
|
||||
summary: Updates tags of the user.
|
||||
description: |
|
||||
Updates tags of the user with provided ID. Tags is updated using
|
||||
authorization token and the new tags received in request.
|
||||
@@ -345,7 +345,7 @@ paths:
|
||||
/users/{userID}/role:
|
||||
patch:
|
||||
operationId: updateRole
|
||||
summary: Updates the user role.
|
||||
summary: Updates the user's role.
|
||||
description: |
|
||||
Updates role for the user with provided ID.
|
||||
tags:
|
||||
@@ -441,7 +441,7 @@ paths:
|
||||
/users/secret:
|
||||
patch:
|
||||
operationId: updateSecret
|
||||
summary: Updates Secret of currently logged in user.
|
||||
summary: Updates secret of currently logged in user.
|
||||
description: |
|
||||
Updates secret of currently logged in user. Secret is updated using
|
||||
authorization token and the new received info.
|
||||
|
||||
+2
-2
@@ -149,7 +149,7 @@ var cmdProvision = []cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
ut, err := sdk.CreateToken(mgxsdk.Login{Username: user.Username, Secret: user.Credentials.Secret})
|
||||
ut, err := sdk.CreateToken(mgxsdk.Login{Identity: user.Credentials.Username, Secret: user.Credentials.Secret})
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
@@ -166,7 +166,7 @@ var cmdProvision = []cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
ut, err = sdk.CreateToken(mgxsdk.Login{Email: user.Email, Secret: user.Credentials.Secret})
|
||||
ut, err = sdk.CreateToken(mgxsdk.Login{Identity: user.Email, Secret: user.Credentials.Secret})
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
|
||||
+2
-2
@@ -106,7 +106,7 @@ var cmdUsers = []cobra.Command{
|
||||
}
|
||||
|
||||
loginReq := mgxsdk.Login{
|
||||
Username: args[0],
|
||||
Identity: args[0],
|
||||
Secret: args[1],
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ var cmdUsers = []cobra.Command{
|
||||
if args[0] == "username" {
|
||||
user.ID = args[1]
|
||||
user.Credentials.Username = args[2]
|
||||
user, err := sdk.UpdateUser(user, args[3])
|
||||
user, err := sdk.UpdateUsername(user, args[3])
|
||||
if err != nil {
|
||||
logErrorCmd(*cmd, err)
|
||||
return
|
||||
|
||||
+2
-2
@@ -338,8 +338,8 @@ func TestIssueTokenCmd(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
lg := mgsdk.Login{
|
||||
Email: tc.args[0],
|
||||
Secret: tc.args[1],
|
||||
Identity: tc.args[0],
|
||||
Secret: tc.args[1],
|
||||
}
|
||||
sdkCall := sdkMock.On("CreateToken", lg).Return(tc.token, tc.sdkerr)
|
||||
|
||||
|
||||
@@ -172,7 +172,9 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
errors.Contains(err, apiutil.ErrMissingUsername),
|
||||
errors.Contains(err, apiutil.ErrMissingFirstName),
|
||||
errors.Contains(err, apiutil.ErrMissingLastName),
|
||||
errors.Contains(err, apiutil.ErrInvalidUsername):
|
||||
errors.Contains(err, apiutil.ErrInvalidUsername),
|
||||
errors.Contains(err, apiutil.ErrMissingIdentity),
|
||||
errors.Contains(err, apiutil.ErrInvalidProfilePictureURL):
|
||||
err = unwrap(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
|
||||
|
||||
+1
-1
@@ -312,7 +312,7 @@ type SDK interface {
|
||||
//
|
||||
// example:
|
||||
// lt := sdk.Login{
|
||||
// Email: "john.doe@example",
|
||||
// Identity: "email"/"username",
|
||||
// Secret: "12345678",
|
||||
// }
|
||||
// token, _ := sdk.CreateToken(lt)
|
||||
|
||||
@@ -20,8 +20,7 @@ type Token struct {
|
||||
}
|
||||
|
||||
type Login struct {
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Identity string `json:"identity"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -41,7 +41,7 @@ func TestIssueToken(t *testing.T) {
|
||||
{
|
||||
desc: "issue token successfully",
|
||||
login: sdk.Login{
|
||||
Username: client.Credentials.Username,
|
||||
Identity: client.Credentials.Username,
|
||||
Secret: client.Credentials.Secret,
|
||||
},
|
||||
svcRes: &magistrala.Token{
|
||||
@@ -54,9 +54,9 @@ func TestIssueToken(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "issue token with invalid username",
|
||||
desc: "issue token with invalid identity",
|
||||
login: sdk.Login{
|
||||
Username: invalidIdentity,
|
||||
Identity: invalidIdentity,
|
||||
Secret: client.Credentials.Secret,
|
||||
},
|
||||
svcRes: &magistrala.Token{},
|
||||
@@ -67,7 +67,7 @@ func TestIssueToken(t *testing.T) {
|
||||
{
|
||||
desc: "issue token with invalid secret",
|
||||
login: sdk.Login{
|
||||
Username: client.Credentials.Username,
|
||||
Identity: client.Credentials.Username,
|
||||
Secret: "invalid",
|
||||
},
|
||||
svcRes: &magistrala.Token{},
|
||||
@@ -76,20 +76,20 @@ func TestIssueToken(t *testing.T) {
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrLogin, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "issue token with empty username",
|
||||
desc: "issue token with empty identity",
|
||||
login: sdk.Login{
|
||||
Username: "",
|
||||
Identity: "",
|
||||
Secret: client.Credentials.Secret,
|
||||
},
|
||||
svcRes: &magistrala.Token{},
|
||||
svcErr: nil,
|
||||
response: sdk.Token{},
|
||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingUsername), http.StatusBadRequest),
|
||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingIdentity), http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "issue token with empty secret",
|
||||
login: sdk.Login{
|
||||
Username: client.Credentials.Username,
|
||||
Identity: client.Credentials.Username,
|
||||
Secret: "",
|
||||
},
|
||||
svcRes: &magistrala.Token{},
|
||||
@@ -100,12 +100,12 @@ func TestIssueToken(t *testing.T) {
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("IssueToken", mock.Anything, tc.login.Username, tc.login.Secret).Return(tc.svcRes, tc.svcErr)
|
||||
svcCall := svc.On("IssueToken", mock.Anything, tc.login.Identity, tc.login.Secret).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.CreateToken(tc.login)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "IssueToken", mock.Anything, tc.login.Username, tc.login.Secret)
|
||||
ok := svcCall.Parent.AssertCalled(t, "IssueToken", mock.Anything, tc.login.Identity, tc.login.Secret)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
|
||||
@@ -28,7 +28,6 @@ const (
|
||||
// User represents magistrala user its credentials.
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Username string `json:"username,omitempty"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
|
||||
+391
-64
@@ -59,7 +59,6 @@ func TestCreateUser(t *testing.T) {
|
||||
createSdkUserReq := sdk.User{
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Tags: user.Tags,
|
||||
Credentials: user.Credentials,
|
||||
@@ -1236,7 +1235,7 @@ func TestUpdateUserEmail(t *testing.T) {
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "update user Email with valid token",
|
||||
desc: "update email with valid token",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
@@ -1252,7 +1251,7 @@ func TestUpdateUserEmail(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update user Email with invalid token",
|
||||
desc: "update email with invalid token",
|
||||
token: invalidToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
@@ -1268,7 +1267,7 @@ func TestUpdateUserEmail(t *testing.T) {
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update user Email with empty token",
|
||||
desc: "update email with empty token",
|
||||
token: "",
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
@@ -1284,7 +1283,7 @@ func TestUpdateUserEmail(t *testing.T) {
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update user Email with invalid id",
|
||||
desc: "update email with invalid id",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: wrongID,
|
||||
@@ -1300,7 +1299,7 @@ func TestUpdateUserEmail(t *testing.T) {
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
},
|
||||
{
|
||||
desc: "update user Email with empty id",
|
||||
desc: "update email with empty id",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: "",
|
||||
@@ -1316,7 +1315,7 @@ func TestUpdateUserEmail(t *testing.T) {
|
||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID), http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "update user Email with response that can't be unmarshalled",
|
||||
desc: "update email with response that can't be unmarshalled",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
@@ -1665,7 +1664,9 @@ func TestUpdateUserRole(t *testing.T) {
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
updatedUser := user
|
||||
updatedRole := users.AdminRole.String()
|
||||
updatedUser.Role = updatedRole
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -1679,23 +1680,23 @@ func TestUpdateUserRole(t *testing.T) {
|
||||
response sdk.User
|
||||
err errors.SDKError
|
||||
}{
|
||||
// {
|
||||
// desc: "update user role with valid token",
|
||||
// token: validToken,
|
||||
// updateUserReq: sdk.User{
|
||||
// ID: user.ID,
|
||||
// Role: updatedRole,
|
||||
// Email: user.Email,
|
||||
// },
|
||||
// svcReq: users.User{
|
||||
// ID: user.ID,
|
||||
// Role: users.AdminRole,
|
||||
// },
|
||||
// svcRes: convertUser(updatedUser),
|
||||
// svcErr: nil,
|
||||
// response: updatedUser,
|
||||
// err: nil,
|
||||
// },
|
||||
{
|
||||
desc: "update user role with valid token",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
Role: updatedRole,
|
||||
Email: user.Email,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
Role: users.AdminRole,
|
||||
},
|
||||
svcRes: convertUser(updatedUser),
|
||||
svcErr: nil,
|
||||
response: updatedUser,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update user role with invalid token",
|
||||
token: invalidToken,
|
||||
@@ -1725,22 +1726,22 @@ func TestUpdateUserRole(t *testing.T) {
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
// {
|
||||
// desc: "update user role with invalid id",
|
||||
// token: validToken,
|
||||
// updateUserReq: sdk.User{
|
||||
// ID: wrongID,
|
||||
// Role: updatedRole,
|
||||
// },
|
||||
// svcReq: users.User{
|
||||
// ID: wrongID,
|
||||
// Role: users.AdminRole,
|
||||
// },
|
||||
// svcRes: users.User{},
|
||||
// svcErr: svcerr.ErrUpdateEntity,
|
||||
// response: sdk.User{},
|
||||
// err: errors.NewSDKErrorWithStatus(svcerr.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
// },
|
||||
{
|
||||
desc: "update user role with invalid id",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: wrongID,
|
||||
Role: updatedRole,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: wrongID,
|
||||
Role: users.AdminRole,
|
||||
},
|
||||
svcRes: users.User{},
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
},
|
||||
{
|
||||
desc: "update user role with empty id",
|
||||
token: validToken,
|
||||
@@ -1769,28 +1770,28 @@ func TestUpdateUserRole(t *testing.T) {
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKError(errors.New("json: unsupported type: chan int")),
|
||||
},
|
||||
// {
|
||||
// desc: "update user role with response that can't be unmarshalled",
|
||||
// token: validToken,
|
||||
// updateUserReq: sdk.User{
|
||||
// ID: user.ID,
|
||||
// Role: updatedRole,
|
||||
// },
|
||||
// svcReq: users.User{
|
||||
// ID: user.ID,
|
||||
// Role: users.AdminRole,
|
||||
// },
|
||||
// svcRes: users.User{
|
||||
// ID: id,
|
||||
// Role: users.AdminRole,
|
||||
// Metadata: users.Metadata{
|
||||
// "key": make(chan int),
|
||||
// },
|
||||
// },
|
||||
// svcErr: nil,
|
||||
// response: sdk.User{},
|
||||
// err: errors.NewSDKError(errors.New("unexpected end of JSON input")),
|
||||
// },
|
||||
{
|
||||
desc: "update user role with response that can't be unmarshalled",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
Role: updatedRole,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
Role: users.AdminRole,
|
||||
},
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
Role: users.AdminRole,
|
||||
Metadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKError(errors.New("unexpected end of JSON input")),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
@@ -1798,12 +1799,338 @@ func TestUpdateUserRole(t *testing.T) {
|
||||
tc.session = mgauthn.Session{DomainUserID: validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("UpdateRole", mock.Anything, tc.session, tc.updateUserReq.ID, tc.svcReq).Return(tc.svcRes, tc.svcErr)
|
||||
svcCall := svc.On("UpdateRole", mock.Anything, tc.session, tc.svcReq).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.UpdateUserRole(tc.updateUserReq, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "UpdateRole", mock.Anything, tc.session, tc.updateUserReq.ID, tc.svcReq)
|
||||
ok := svcCall.Parent.AssertCalled(t, "UpdateRole", mock.Anything, tc.session, tc.svcReq)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateUsername(t *testing.T) {
|
||||
ts, svc, auth := setupUsers()
|
||||
defer ts.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
updatedUser := user
|
||||
updatedUsername := "updatedUsername"
|
||||
updatedUser.Credentials.Username = updatedUsername
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
session mgauthn.Session
|
||||
updateUserReq sdk.User
|
||||
svcReq users.User
|
||||
svcRes users.User
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
response sdk.User
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "update username with valid token",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
Credentials: sdk.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcRes: convertUser(updatedUser),
|
||||
svcErr: nil,
|
||||
response: updatedUser,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update username with invalid token",
|
||||
token: invalidToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
Credentials: sdk.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcRes: users.User{},
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update username with empty token",
|
||||
token: "",
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
Credentials: sdk.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcReq: users.User{},
|
||||
svcRes: users.User{},
|
||||
svcErr: nil,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update username with invalid id",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: wrongID,
|
||||
Credentials: sdk.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: wrongID,
|
||||
Credentials: users.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcRes: users.User{},
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
},
|
||||
{
|
||||
desc: "update username with empty id",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: "",
|
||||
Credentials: sdk.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcReq: users.User{},
|
||||
svcRes: users.User{},
|
||||
svcErr: nil,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID), http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "update username with response that can't be unmarshalled",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
Credentials: sdk.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
},
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
Credentials: users.Credentials{
|
||||
Username: updatedUsername,
|
||||
},
|
||||
Metadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKError(errors.New("unexpected end of JSON input")),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = mgauthn.Session{DomainUserID: validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("UpdateUsername", mock.Anything, tc.session, tc.svcReq.ID, tc.svcReq.Credentials.Username).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.UpdateUsername(tc.updateUserReq, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "UpdateUsername", mock.Anything, tc.session, tc.svcReq.ID, tc.svcReq.Credentials.Username)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
authCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateProfilePicture(t *testing.T) {
|
||||
ts, svc, auth := setupUsers()
|
||||
defer ts.Close()
|
||||
|
||||
conf := sdk.Config{
|
||||
UsersURL: ts.URL,
|
||||
}
|
||||
mgsdk := sdk.NewSDK(conf)
|
||||
|
||||
updatedProfilePicture := "http://updated.com/profile.jpg"
|
||||
updatedUser := user
|
||||
updatedUser.Email = updatedProfilePicture
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
session mgauthn.Session
|
||||
updateUserReq sdk.User
|
||||
svcReq users.User
|
||||
svcRes users.User
|
||||
svcErr error
|
||||
authenticateErr error
|
||||
response sdk.User
|
||||
err errors.SDKError
|
||||
}{
|
||||
{
|
||||
desc: "update profile picture with valid token",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcRes: convertUser(updatedUser),
|
||||
svcErr: nil,
|
||||
response: updatedUser,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with invalid token",
|
||||
token: invalidToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcRes: users.User{},
|
||||
authenticateErr: svcerr.ErrAuthentication,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with empty token",
|
||||
token: "",
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcRes: users.User{},
|
||||
svcErr: nil,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(apiutil.ErrBearerToken, http.StatusUnauthorized),
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with invalid id",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: wrongID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: wrongID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcRes: users.User{},
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(svcerr.ErrUpdateEntity, http.StatusUnprocessableEntity),
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with empty id",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: "",
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: "",
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcRes: users.User{},
|
||||
svcErr: nil,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrMissingID), http.StatusBadRequest),
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with request that can't be marshalled",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: generateUUID(t),
|
||||
Metadata: map[string]interface{}{
|
||||
"test": make(chan int),
|
||||
},
|
||||
},
|
||||
svcReq: users.User{},
|
||||
svcRes: users.User{},
|
||||
svcErr: nil,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKError(errors.New("json: unsupported type: chan int")),
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with response that can't be unmarshalled",
|
||||
token: validToken,
|
||||
updateUserReq: sdk.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcReq: users.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: updatedProfilePicture,
|
||||
},
|
||||
svcRes: users.User{
|
||||
ID: id,
|
||||
Metadata: users.Metadata{
|
||||
"key": make(chan int),
|
||||
},
|
||||
},
|
||||
svcErr: nil,
|
||||
response: sdk.User{},
|
||||
err: errors.NewSDKError(errors.New("unexpected end of JSON input")),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.token == validToken {
|
||||
tc.session = mgauthn.Session{DomainUserID: validID, UserID: validID, DomainID: domainID}
|
||||
}
|
||||
authCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authenticateErr)
|
||||
svcCall := svc.On("UpdateProfilePicture", mock.Anything, tc.session, tc.svcReq).Return(tc.svcRes, tc.svcErr)
|
||||
resp, err := mgsdk.UpdateProfilePicture(tc.updateUserReq, tc.token)
|
||||
assert.Equal(t, tc.err, err)
|
||||
assert.Equal(t, tc.response, resp)
|
||||
if tc.err == nil {
|
||||
ok := svcCall.Parent.AssertCalled(t, "UpdateProfilePicture", mock.Anything, tc.session, tc.svcReq)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
svcCall.Unset()
|
||||
|
||||
@@ -294,8 +294,7 @@ func (ps *provisionService) createTokenIfEmpty(token string) (string, error) {
|
||||
}
|
||||
|
||||
u := sdk.Login{
|
||||
Email: ps.conf.Server.MgEmail,
|
||||
Username: ps.conf.Server.MgUsername,
|
||||
Identity: ps.conf.Server.MgUsername,
|
||||
Secret: ps.conf.Server.MgPass,
|
||||
}
|
||||
tkn, err := ps.sdk.CreateToken(u)
|
||||
|
||||
@@ -219,7 +219,7 @@ func TestCert(t *testing.T) {
|
||||
mgsdk.On("IssueCert", c.thingID, c.config.Cert.TTL, c.domainID, mock.Anything).Return(sdk.Cert{SerialNumber: c.serial}, c.sdkCertErr)
|
||||
mgsdk.On("ViewCert", c.serial, mock.Anything, mock.Anything).Return(sdk.Cert{Certificate: c.cert, Key: c.key}, c.sdkCertErr)
|
||||
login := sdk.Login{
|
||||
Username: c.config.Server.MgUsername,
|
||||
Identity: c.config.Server.MgUsername,
|
||||
Secret: c.config.Server.MgPass,
|
||||
}
|
||||
mgsdk.On("CreateToken", login).Return(sdk.Token{AccessToken: validToken}, c.sdkTokenErr)
|
||||
|
||||
+2
-2
@@ -149,7 +149,7 @@ func createUser(s sdk.SDK, conf Config) (string, string, error) {
|
||||
}
|
||||
|
||||
login := sdk.Login{
|
||||
Username: user.Credentials.Username,
|
||||
Identity: user.Credentials.Username,
|
||||
Secret: user.Credentials.Secret,
|
||||
}
|
||||
token, err := s.CreateToken(login)
|
||||
@@ -170,7 +170,7 @@ func createUser(s sdk.SDK, conf Config) (string, string, error) {
|
||||
}
|
||||
|
||||
login = sdk.Login{
|
||||
Username: user.Credentials.Username,
|
||||
Identity: user.Credentials.Username,
|
||||
Secret: user.Credentials.Secret,
|
||||
}
|
||||
token, err = s.CreateToken(login)
|
||||
|
||||
@@ -95,7 +95,7 @@ func Provision(conf Config) error {
|
||||
var err error
|
||||
|
||||
// Login user
|
||||
token, err := s.CreateToken(sdk.Login{Username: user.Credentials.Username, Secret: user.Credentials.Secret})
|
||||
token, err := s.CreateToken(sdk.Login{Identity: user.Credentials.Username, Secret: user.Credentials.Secret})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to login user: %s", err.Error())
|
||||
}
|
||||
@@ -114,7 +114,7 @@ func Provision(conf Config) error {
|
||||
}
|
||||
// Login to domain
|
||||
token, err = s.CreateToken(sdk.Login{
|
||||
Username: user.Credentials.Username,
|
||||
Identity: user.Credentials.Username,
|
||||
Secret: user.Credentials.Secret,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
+399
-35
@@ -264,6 +264,7 @@ func TestView(t *testing.T) {
|
||||
status int
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -300,6 +301,15 @@ func TestView(t *testing.T) {
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "view user with invalid ID",
|
||||
token: validToken,
|
||||
id: inValid,
|
||||
status: http.StatusBadRequest,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
svcErr: svcerr.ErrViewEntity,
|
||||
err: svcerr.ErrViewEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -312,7 +322,7 @@ func TestView(t *testing.T) {
|
||||
}
|
||||
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("View", mock.Anything, tc.authnRes, tc.id).Return(users.User{}, tc.err)
|
||||
svcCall := svc.On("View", mock.Anything, tc.authnRes, tc.id).Return(users.User{}, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
var errRes respBody
|
||||
@@ -340,6 +350,7 @@ func TestViewProfile(t *testing.T) {
|
||||
status int
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -368,6 +379,15 @@ func TestViewProfile(t *testing.T) {
|
||||
authnRes: mgauthn.Session{},
|
||||
err: apiutil.ErrBearerToken,
|
||||
},
|
||||
{
|
||||
desc: "view profile with service error",
|
||||
token: validToken,
|
||||
id: user.ID,
|
||||
status: http.StatusBadRequest,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
svcErr: svcerr.ErrViewEntity,
|
||||
err: svcerr.ErrViewEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -380,7 +400,7 @@ func TestViewProfile(t *testing.T) {
|
||||
}
|
||||
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("ViewProfile", mock.Anything, tc.authnRes).Return(users.User{}, tc.err)
|
||||
svcCall := svc.On("ViewProfile", mock.Anything, tc.authnRes).Return(users.User{}, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
var errRes respBody
|
||||
@@ -778,6 +798,7 @@ func TestSearchUsers(t *testing.T) {
|
||||
query string
|
||||
listUsersResponse users.UsersPage
|
||||
authnErr error
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -865,6 +886,14 @@ func TestSearchUsers(t *testing.T) {
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrLenSearchQuery,
|
||||
},
|
||||
{
|
||||
desc: "serach users with service error",
|
||||
token: validToken,
|
||||
query: "username=username",
|
||||
status: http.StatusBadRequest,
|
||||
svcErr: svcerr.ErrViewEntity,
|
||||
err: svcerr.ErrViewEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -882,7 +911,7 @@ func TestSearchUsers(t *testing.T) {
|
||||
Page: tc.listUsersResponse.Page,
|
||||
Users: tc.listUsersResponse.Users,
|
||||
},
|
||||
tc.err)
|
||||
tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
@@ -1176,6 +1205,8 @@ func TestUpdateEmail(t *testing.T) {
|
||||
us, svc, _, authn := newUsersServer()
|
||||
defer us.Close()
|
||||
|
||||
newuseremail := "newuseremail@example.com"
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
data string
|
||||
@@ -1185,14 +1216,15 @@ func TestUpdateEmail(t *testing.T) {
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
status int
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "update user email as admin with valid token",
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, "newuseremail@example.com"),
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, newuseremail),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Email: "newuseremail@example.com",
|
||||
Email: newuseremail,
|
||||
Credentials: users.Credentials{
|
||||
Secret: "secret",
|
||||
},
|
||||
@@ -1205,10 +1237,10 @@ func TestUpdateEmail(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update user email as normal user with valid token",
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, "newuseremail@example.com"),
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, newuseremail),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Email: "newuseremail@example.com",
|
||||
Email: newuseremail,
|
||||
Credentials: users.Credentials{
|
||||
Secret: "secret",
|
||||
},
|
||||
@@ -1221,10 +1253,10 @@ func TestUpdateEmail(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update user email with empty token",
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, "newuseremail@example.com"),
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, newuseremail),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Email: "newuseremail@example.com",
|
||||
Email: newuseremail,
|
||||
Credentials: users.Credentials{
|
||||
Secret: "secret",
|
||||
},
|
||||
@@ -1237,10 +1269,10 @@ func TestUpdateEmail(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update user email with invalid token",
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, "newuseremail@example.com"),
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, newuseremail),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Email: "newuseremail@example.com",
|
||||
Email: newuseremail,
|
||||
Credentials: users.Credentials{
|
||||
Secret: "secret",
|
||||
},
|
||||
@@ -1253,10 +1285,10 @@ func TestUpdateEmail(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update user email with empty id",
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, "newuseremail@example.com"),
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, newuseremail),
|
||||
user: users.User{
|
||||
ID: "",
|
||||
Email: "newuseremail@example.com",
|
||||
Email: newuseremail,
|
||||
Credentials: users.Credentials{
|
||||
Secret: "secret",
|
||||
},
|
||||
@@ -1272,7 +1304,7 @@ func TestUpdateEmail(t *testing.T) {
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, ""),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Email: "newuseremail@example.com",
|
||||
Email: newuseremail,
|
||||
Credentials: users.Credentials{
|
||||
Secret: "secret",
|
||||
},
|
||||
@@ -1297,6 +1329,20 @@ func TestUpdateEmail(t *testing.T) {
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "update user email with service error",
|
||||
data: fmt.Sprintf(`{"email": "%s"}`, newuseremail),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Email: newuseremail,
|
||||
},
|
||||
contentType: contentType,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
status: http.StatusUnprocessableEntity,
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -1310,7 +1356,281 @@ func TestUpdateEmail(t *testing.T) {
|
||||
}
|
||||
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("UpdateEmail", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(users.User{}, tc.err)
|
||||
svcCall := svc.On("UpdateEmail", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.user, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
var resBody respBody
|
||||
err = json.NewDecoder(res.Body).Decode(&resBody)
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err))
|
||||
if resBody.Err != "" || resBody.Message != "" {
|
||||
err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message))
|
||||
}
|
||||
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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
svcCall.Unset()
|
||||
authnCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateUsername(t *testing.T) {
|
||||
us, svc, _, authn := newUsersServer()
|
||||
defer us.Close()
|
||||
|
||||
newusername := "newusername"
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
data string
|
||||
user users.User
|
||||
contentType string
|
||||
token string
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
status int
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "update username as admin with valid token",
|
||||
data: fmt.Sprintf(`{"username": "%s"}`, newusername),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: newusername,
|
||||
},
|
||||
},
|
||||
contentType: contentType,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
status: http.StatusOK,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update username with empty token",
|
||||
data: fmt.Sprintf(`{"username": "%s"}`, newusername),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: newusername,
|
||||
},
|
||||
},
|
||||
contentType: contentType,
|
||||
token: "",
|
||||
status: http.StatusUnauthorized,
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
err: apiutil.ErrBearerToken,
|
||||
},
|
||||
{
|
||||
desc: "update username with invalid token",
|
||||
data: fmt.Sprintf(`{"username": "%s"}`, newusername),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: newusername,
|
||||
},
|
||||
},
|
||||
contentType: contentType,
|
||||
token: inValid,
|
||||
status: http.StatusUnauthorized,
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "update username with empty id",
|
||||
data: fmt.Sprintf(`{"username": "%s"}`, newusername),
|
||||
user: users.User{
|
||||
ID: "",
|
||||
Credentials: users.Credentials{
|
||||
Username: newusername,
|
||||
},
|
||||
},
|
||||
contentType: contentType,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: validID},
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "update username with invalid contentype",
|
||||
data: fmt.Sprintf(`{"username": "%s"}`, ""),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: newusername,
|
||||
},
|
||||
},
|
||||
contentType: "application/xml",
|
||||
token: validToken,
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "update user email with malformed data",
|
||||
data: fmt.Sprintf(`{"email": %s}`, "invalid"),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: newusername,
|
||||
},
|
||||
},
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "update username with invalid username",
|
||||
data: fmt.Sprintf(`{"username": "%s"}`, "invalid"),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
Credentials: users.Credentials{
|
||||
Username: newusername,
|
||||
},
|
||||
},
|
||||
contentType: contentType,
|
||||
token: validToken,
|
||||
status: http.StatusUnprocessableEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
req := testRequest{
|
||||
user: us.Client(),
|
||||
method: http.MethodPatch,
|
||||
url: fmt.Sprintf("%s/users/%s/username", us.URL, tc.user.ID),
|
||||
contentType: tc.contentType,
|
||||
token: tc.token,
|
||||
body: strings.NewReader(tc.data),
|
||||
}
|
||||
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("UpdateUsername", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.user, tc.err)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
var resBody respBody
|
||||
err = json.NewDecoder(res.Body).Decode(&resBody)
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error while decoding response body: %s", tc.desc, err))
|
||||
if resBody.Err != "" || resBody.Message != "" {
|
||||
err = errors.Wrap(errors.New(resBody.Err), errors.New(resBody.Message))
|
||||
}
|
||||
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.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
svcCall.Unset()
|
||||
authnCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateProfilePicture(t *testing.T) {
|
||||
us, svc, _, authn := newUsersServer()
|
||||
defer us.Close()
|
||||
|
||||
newprofilepicture := "https://example.com/newprofilepicture"
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
data string
|
||||
user users.User
|
||||
contentType string
|
||||
token string
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
status int
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "update profile picture as admin with valid token",
|
||||
data: fmt.Sprintf(`{"profile_picture": "%s"}`, newprofilepicture),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: newprofilepicture,
|
||||
},
|
||||
contentType: contentType,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
status: http.StatusOK,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with empty token",
|
||||
data: fmt.Sprintf(`{"profile_picture": "%s"}`, newprofilepicture),
|
||||
user: users.User{},
|
||||
contentType: contentType,
|
||||
token: "",
|
||||
status: http.StatusUnauthorized,
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
err: apiutil.ErrBearerToken,
|
||||
},
|
||||
{
|
||||
desc: "update profile_picture with invalid token",
|
||||
data: fmt.Sprintf(`{"profile_picture": "%s"}`, newprofilepicture),
|
||||
user: users.User{},
|
||||
contentType: contentType,
|
||||
token: inValid,
|
||||
status: http.StatusUnauthorized,
|
||||
authnErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "update profile_picture with empty id",
|
||||
data: fmt.Sprintf(`{"profile_picture": "%s"}`, newprofilepicture),
|
||||
user: users.User{
|
||||
ID: "",
|
||||
ProfilePicture: newprofilepicture,
|
||||
},
|
||||
contentType: contentType,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: validID},
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "update profile_picture with invalid contentype",
|
||||
data: fmt.Sprintf(`{"profile_picture": "%s"}`, ""),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
ProfilePicture: newprofilepicture,
|
||||
},
|
||||
contentType: "application/xml",
|
||||
token: validToken,
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with malformed data",
|
||||
data: fmt.Sprintf(`{"profile_picture": %s}`, "invalid"),
|
||||
user: users.User{},
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "update profile picture with failed to update",
|
||||
data: fmt.Sprintf(`{"profile_picture": "%s"}`, "invalid"),
|
||||
user: users.User{
|
||||
ID: user.ID,
|
||||
},
|
||||
contentType: contentType,
|
||||
token: validToken,
|
||||
status: http.StatusUnprocessableEntity,
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
req := testRequest{
|
||||
user: us.Client(),
|
||||
method: http.MethodPatch,
|
||||
url: fmt.Sprintf("%s/users/%s/picture", us.URL, tc.user.ID),
|
||||
contentType: tc.contentType,
|
||||
token: tc.token,
|
||||
body: strings.NewReader(tc.data),
|
||||
}
|
||||
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("UpdateProfilePicture", mock.Anything, tc.authnRes, mock.Anything).Return(tc.user, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
var resBody respBody
|
||||
@@ -1438,6 +1758,7 @@ func TestPasswordReset(t *testing.T) {
|
||||
status int
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -1497,6 +1818,14 @@ func TestPasswordReset(t *testing.T) {
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "password reset with service error",
|
||||
data: fmt.Sprintf(`{"token": "%s", "password": "%s", "confirm_password": "%s"}`, validToken, strongPass, strongPass),
|
||||
token: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusUnprocessableEntity,
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -1511,7 +1840,7 @@ func TestPasswordReset(t *testing.T) {
|
||||
body: strings.NewReader(tc.data),
|
||||
}
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("ResetSecret", mock.Anything, tc.authnRes, mock.Anything).Return(tc.err)
|
||||
svcCall := svc.On("ResetSecret", mock.Anything, tc.authnRes, mock.Anything).Return(tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
@@ -1534,6 +1863,7 @@ func TestUpdateRole(t *testing.T) {
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
status int
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -1606,6 +1936,17 @@ func TestUpdateRole(t *testing.T) {
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "update user with service error",
|
||||
data: fmt.Sprintf(`{"role": "%s"}`, "admin"),
|
||||
userID: user.ID,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
contentType: contentType,
|
||||
status: http.StatusUnprocessableEntity,
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -1620,7 +1961,7 @@ func TestUpdateRole(t *testing.T) {
|
||||
}
|
||||
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("UpdateRole", mock.Anything, tc.authnRes, mock.Anything).Return(users.User{}, tc.err)
|
||||
svcCall := svc.On("UpdateRole", mock.Anything, tc.authnRes, mock.Anything).Return(users.User{}, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
var resBody respBody
|
||||
@@ -1790,50 +2131,43 @@ func TestIssueToken(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "issue token with valid username and secret",
|
||||
data: fmt.Sprintf(`{"username": "%s", "secret": "%s", "domainID": "%s"}`, validUsername, secret, validID),
|
||||
desc: "issue token with valid identity and secret",
|
||||
data: fmt.Sprintf(`{"identity": "%s", "secret": "%s"}`, validUsername, secret),
|
||||
contentType: contentType,
|
||||
status: http.StatusCreated,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "issue token with empty username",
|
||||
data: fmt.Sprintf(`{"username": "%s", "secret": "%s", "domainID": "%s"}`, "", secret, validID),
|
||||
desc: "issue token with empty identity",
|
||||
data: fmt.Sprintf(`{"identity": "%s", "secret": "%s"}`, "", secret),
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "issue token with empty secret",
|
||||
data: fmt.Sprintf(`{"username": "%s", "secret": "%s", "domainID": "%s"}`, validUsername, "", validID),
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "issue token with empty domain",
|
||||
data: fmt.Sprintf(`{"username": "%s", "secret": "%s", "domainID": "%s"}`, validUsername, secret, ""),
|
||||
data: fmt.Sprintf(`{"identity": "%s", "secret": "%s"}`, validUsername, ""),
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "issue token with invalid email",
|
||||
data: fmt.Sprintf(`{"username": "%s", "secret": "%s", "domainID": "%s"}`, "invalid", secret, validID),
|
||||
data: fmt.Sprintf(`{"identity": "%s", "secret": "%s"}`, "invalid", secret),
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "issues token with malformed data",
|
||||
data: fmt.Sprintf(`{"username": %s, "secret": %s, "domainID": %s}`, validUsername, secret, validID),
|
||||
data: fmt.Sprintf(`{"identity": %s, "secret": %s}`, validUsername, secret),
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrValidation,
|
||||
},
|
||||
{
|
||||
desc: "issue token with invalid contentype",
|
||||
data: fmt.Sprintf(`{"username": "%s", "secret": "%s", "domainID": "%s"}`, "invalid", secret, validID),
|
||||
data: fmt.Sprintf(`{"identity": "%s", "secret": "%s"}`, "invalid", secret),
|
||||
contentType: "application/xml",
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
err: apiutil.ErrValidation,
|
||||
@@ -1979,6 +2313,7 @@ func TestEnable(t *testing.T) {
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
status int
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -2023,6 +2358,15 @@ func TestEnable(t *testing.T) {
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "enable user with service error",
|
||||
user: user,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
status: http.StatusUnprocessableEntity,
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -2038,7 +2382,7 @@ func TestEnable(t *testing.T) {
|
||||
}
|
||||
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("Enable", mock.Anything, tc.authnRes, mock.Anything).Return(users.User{}, tc.err)
|
||||
svcCall := svc.On("Enable", mock.Anything, tc.authnRes, mock.Anything).Return(tc.user, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
if tc.err != nil {
|
||||
@@ -2069,6 +2413,7 @@ func TestDisable(t *testing.T) {
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
status int
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -2113,6 +2458,15 @@ func TestDisable(t *testing.T) {
|
||||
status: http.StatusBadRequest,
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "disable user with service error",
|
||||
user: user,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
status: http.StatusUnprocessableEntity,
|
||||
svcErr: svcerr.ErrUpdateEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -2128,7 +2482,7 @@ func TestDisable(t *testing.T) {
|
||||
}
|
||||
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
svcCall := svc.On("Disable", mock.Anything, mock.Anything, mock.Anything).Return(users.User{}, tc.err)
|
||||
svcCall := svc.On("Disable", mock.Anything, mock.Anything, mock.Anything).Return(tc.user, tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
@@ -2150,6 +2504,7 @@ func TestDelete(t *testing.T) {
|
||||
authnRes mgauthn.Session
|
||||
authnErr error
|
||||
status int
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -2181,6 +2536,15 @@ func TestDelete(t *testing.T) {
|
||||
status: http.StatusMethodNotAllowed,
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "delete user with service error",
|
||||
user: user,
|
||||
token: validToken,
|
||||
authnRes: mgauthn.Session{UserID: validID, DomainID: domainID},
|
||||
status: http.StatusUnprocessableEntity,
|
||||
svcErr: svcerr.ErrRemoveEntity,
|
||||
err: svcerr.ErrRemoveEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -2195,7 +2559,7 @@ func TestDelete(t *testing.T) {
|
||||
body: strings.NewReader(data),
|
||||
}
|
||||
authnCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr)
|
||||
repoCall := svc.On("Delete", mock.Anything, tc.authnRes, tc.user.ID).Return(tc.err)
|
||||
repoCall := svc.On("Delete", mock.Anything, tc.authnRes, tc.user.ID).Return(tc.svcErr)
|
||||
res, err := req.make()
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
|
||||
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
|
||||
|
||||
@@ -433,7 +433,7 @@ func updateProfilePictureEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return nil, svcerr.ErrAuthorization
|
||||
}
|
||||
|
||||
user, err := svc.Update(ctx, session, user)
|
||||
user, err := svc.UpdateProfilePicture(ctx, session, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -475,7 +475,7 @@ func issueTokenEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
token, err := svc.IssueToken(ctx, req.Username, req.Secret)
|
||||
token, err := svc.IssueToken(ctx, req.Identity, req.Secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ func (req updateUserSecretReq) validate() error {
|
||||
|
||||
type updateUsernameReq struct {
|
||||
id string
|
||||
Username string
|
||||
Username string `json:"username,omitempty"`
|
||||
}
|
||||
|
||||
func (req updateUsernameReq) validate() error {
|
||||
@@ -224,6 +224,9 @@ func (req updateUsernameReq) validate() error {
|
||||
if len(req.Username) > api.MaxNameSize {
|
||||
return apiutil.ErrNameSize
|
||||
}
|
||||
if req.Username == "" {
|
||||
return apiutil.ErrMissingUsername
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -256,13 +259,13 @@ func (req changeUserStatusReq) validate() error {
|
||||
}
|
||||
|
||||
type loginUserReq struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Identity string `json:"identity,omitempty"`
|
||||
Secret string `json:"secret,omitempty"`
|
||||
}
|
||||
|
||||
func (req loginUserReq) validate() error {
|
||||
if req.Username == "" {
|
||||
return apiutil.ErrMissingUsername
|
||||
if req.Identity == "" {
|
||||
return apiutil.ErrMissingIdentity
|
||||
}
|
||||
if req.Secret == "" {
|
||||
return apiutil.ErrMissingPass
|
||||
|
||||
@@ -509,26 +509,26 @@ func TestLoginUserReqValidate(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "valid request with username",
|
||||
desc: "valid request with identity",
|
||||
req: loginUserReq{
|
||||
Username: "example",
|
||||
Identity: "example",
|
||||
Secret: secret,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "empty Username",
|
||||
desc: "empty identity",
|
||||
req: loginUserReq{
|
||||
Username: "",
|
||||
Identity: "",
|
||||
Secret: secret,
|
||||
},
|
||||
err: apiutil.ErrMissingUsername,
|
||||
err: apiutil.ErrMissingIdentity,
|
||||
},
|
||||
{
|
||||
desc: "empty secret",
|
||||
req: loginUserReq{
|
||||
Secret: "",
|
||||
Username: "example",
|
||||
Identity: "example",
|
||||
},
|
||||
err: apiutil.ErrMissingPass,
|
||||
},
|
||||
|
||||
@@ -107,7 +107,7 @@ func (es *eventStore) UpdateUsername(ctx context.Context, session authn.Session,
|
||||
}
|
||||
|
||||
func (es *eventStore) UpdateProfilePicture(ctx context.Context, session authn.Session, user users.User) (users.User, error) {
|
||||
user, err := es.svc.Update(ctx, session, user)
|
||||
user, err := es.svc.UpdateProfilePicture(ctx, session, user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func (es *eventStore) UpdateProfilePicture(ctx context.Context, session authn.Se
|
||||
return user, err
|
||||
}
|
||||
|
||||
return es.update(ctx, "profile_picture", user)
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) UpdateEmail(ctx context.Context, session authn.Session, id, email string) (users.User, error) {
|
||||
|
||||
@@ -124,6 +124,9 @@ func (am *authorizationMiddleware) UpdateUsername(ctx context.Context, session a
|
||||
}
|
||||
|
||||
func (am *authorizationMiddleware) UpdateProfilePicture(ctx context.Context, session authn.Session, user users.User) (users.User, error) {
|
||||
if err := am.checkSuperAdmin(ctx, session.UserID); err == nil {
|
||||
session.SuperAdmin = true
|
||||
}
|
||||
return am.svc.UpdateProfilePicture(ctx, session, user)
|
||||
}
|
||||
|
||||
|
||||
@@ -286,7 +286,8 @@ func (lm *loggingMiddleware) UpdateProfilePicture(ctx context.Context, session a
|
||||
args := []any{
|
||||
slog.String("duration", time.Since(begin).String()),
|
||||
slog.Group("user",
|
||||
slog.String("id", u.ID),
|
||||
slog.String("id", user.ID),
|
||||
slog.String("profile_picture", user.ProfilePicture),
|
||||
),
|
||||
}
|
||||
if err != nil {
|
||||
@@ -296,7 +297,7 @@ func (lm *loggingMiddleware) UpdateProfilePicture(ctx context.Context, session a
|
||||
}
|
||||
lm.logger.Info("Update profile picture completed successfully", args...)
|
||||
}(time.Now())
|
||||
return lm.svc.Update(ctx, session, user)
|
||||
return lm.svc.UpdateProfilePicture(ctx, session, user)
|
||||
}
|
||||
|
||||
// GenerateResetToken logs the generate_reset_token request. It logs the time it took to complete the request.
|
||||
|
||||
@@ -144,7 +144,7 @@ func (ms *metricsMiddleware) UpdateProfilePicture(ctx context.Context, session a
|
||||
ms.counter.With("method", "update_profile_picture").Add(1)
|
||||
ms.latency.With("method", "update_profile_picture").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.Update(ctx, session, user)
|
||||
return ms.svc.UpdateProfilePicture(ctx, session, user)
|
||||
}
|
||||
|
||||
// GenerateResetToken instruments GenerateResetToken method with metrics.
|
||||
|
||||
@@ -178,7 +178,7 @@ func (repo *userRepo) UpdateUsername(ctx context.Context, user users.User) (user
|
||||
|
||||
row, err := repo.Repository.DB.NamedQueryContext(ctx, q, dbu)
|
||||
if err != nil {
|
||||
return users.User{}, postgres.HandleError(err, repoerr.ErrUpdateEntity)
|
||||
return users.User{}, postgres.HandleError(repoerr.ErrUpdateEntity, err)
|
||||
}
|
||||
|
||||
defer row.Close()
|
||||
@@ -233,7 +233,7 @@ func (repo *userRepo) Update(ctx context.Context, user users.User) (users.User,
|
||||
|
||||
q := fmt.Sprintf(`UPDATE users SET %s updated_at = :updated_at, updated_by = :updated_by
|
||||
WHERE id = :id AND status = :status
|
||||
RETURNING id, tags, metadata, status, created_at, updated_at, updated_by, last_name, first_name, username, profile_picture, email`, upq)
|
||||
RETURNING id, tags, metadata, status, created_at, updated_at, updated_by, last_name, first_name, username, profile_picture, email, role`, upq)
|
||||
|
||||
user.Status = users.EnabledStatus
|
||||
return repo.update(ctx, user, q)
|
||||
@@ -388,7 +388,7 @@ func (repo *userRepo) RetrieveAllByIDs(ctx context.Context, pm users.Page) (user
|
||||
|
||||
items = append(items, c)
|
||||
}
|
||||
cq := fmt.Sprintf(`SELECT COUNT(*) FROM clients c %s;`, query)
|
||||
cq := fmt.Sprintf(`SELECT COUNT(*) FROM users u %s;`, query)
|
||||
|
||||
total, err := postgres.Total(ctx, repo.Repository.DB, cq, dbPage)
|
||||
if err != nil {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -953,6 +953,144 @@ func TestUpdateEmail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateProfilePicture(t *testing.T) {
|
||||
svc, cRepo := newServiceMinimal()
|
||||
|
||||
user.ProfilePicture = "https://example.com/profile.jpg"
|
||||
adminID := testsutil.GenerateUUID(t)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
user users.User
|
||||
session authn.Session
|
||||
updateProfilePicResponse users.User
|
||||
updateProfilePicErr error
|
||||
checkSuperAdminErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "update profile picture as normal user successfully",
|
||||
user: user,
|
||||
session: authn.Session{UserID: user.ID},
|
||||
updateProfilePicResponse: user,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update profile picture as normal user with repo error on update",
|
||||
user: user,
|
||||
session: authn.Session{UserID: user.ID},
|
||||
updateProfilePicResponse: users.User{},
|
||||
updateProfilePicErr: errors.ErrMalformedEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
{
|
||||
desc: "update profile picture as admin successfully",
|
||||
user: user,
|
||||
session: authn.Session{UserID: adminID, SuperAdmin: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update profile picture as admin with failed check on super admin",
|
||||
user: user,
|
||||
session: authn.Session{UserID: adminID},
|
||||
checkSuperAdminErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "update profile picture as admin with repo error on update",
|
||||
user: user,
|
||||
session: authn.Session{UserID: adminID, SuperAdmin: true},
|
||||
updateProfilePicResponse: users.User{},
|
||||
updateProfilePicErr: errors.ErrMalformedEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := cRepo.On("CheckSuperAdmin", context.Background(), mock.Anything).Return(tc.checkSuperAdminErr)
|
||||
repoCall1 := cRepo.On("Update", context.Background(), mock.Anything).Return(tc.updateProfilePicResponse, tc.updateProfilePicErr)
|
||||
updatedUser, err := svc.UpdateProfilePicture(context.Background(), tc.session, tc.user)
|
||||
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.updateProfilePicResponse, updatedUser, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.updateProfilePicResponse, updatedUser))
|
||||
if tc.err == nil {
|
||||
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 TestUpdateUsername(t *testing.T) {
|
||||
svc, cRepo := newServiceMinimal()
|
||||
|
||||
nuser := user
|
||||
nuser.Credentials.Username = "newusername"
|
||||
adminID := testsutil.GenerateUUID(t)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
user users.User
|
||||
session authn.Session
|
||||
updateUsernameResponse users.User
|
||||
updateUsernameErr error
|
||||
checkSuperAdminErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "update username as normal user successfully",
|
||||
user: user,
|
||||
session: authn.Session{UserID: user.ID},
|
||||
updateUsernameResponse: nuser,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update username as normal user with repo error on update",
|
||||
user: user,
|
||||
session: authn.Session{UserID: user.ID},
|
||||
updateUsernameResponse: users.User{},
|
||||
updateUsernameErr: errors.ErrMalformedEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
{
|
||||
desc: "update username as admin successfully",
|
||||
user: user,
|
||||
session: authn.Session{UserID: adminID, SuperAdmin: true},
|
||||
updateUsernameResponse: nuser,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update username as admin with failed check on super admin",
|
||||
user: user,
|
||||
session: authn.Session{UserID: adminID},
|
||||
checkSuperAdminErr: svcerr.ErrAuthorization,
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "update username as admin with repo error on update",
|
||||
user: user,
|
||||
session: authn.Session{UserID: adminID, SuperAdmin: true},
|
||||
updateUsernameResponse: users.User{},
|
||||
updateUsernameErr: errors.ErrMalformedEntity,
|
||||
err: svcerr.ErrUpdateEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := cRepo.On("CheckSuperAdmin", context.Background(), mock.Anything).Return(tc.checkSuperAdminErr)
|
||||
repoCall1 := cRepo.On("UpdateUsername", context.Background(), mock.Anything).Return(tc.updateUsernameResponse, tc.updateUsernameErr)
|
||||
updatedUser, err := svc.UpdateUsername(context.Background(), tc.session, tc.user.ID, tc.user.Credentials.Username)
|
||||
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.updateUsernameResponse, updatedUser, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.updateUsernameResponse, updatedUser))
|
||||
if tc.err == nil {
|
||||
ok := repoCall1.Parent.AssertCalled(t, "UpdateUsername", context.Background(), mock.Anything)
|
||||
assert.True(t, ok, fmt.Sprintf("UpdateUsername was not called on %s", tc.desc))
|
||||
}
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableUser(t *testing.T) {
|
||||
svc, cRepo := newServiceMinimal()
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ func (tm *tracingMiddleware) UpdateProfilePicture(ctx context.Context, session a
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_update_profile_picture", trace.WithAttributes(attribute.String("id", usr.ID)))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.Update(ctx, session, usr)
|
||||
return tm.svc.UpdateProfilePicture(ctx, session, usr)
|
||||
}
|
||||
|
||||
// GenerateResetToken traces the "GenerateResetToken" operation of the wrapped users.Service.
|
||||
|
||||
+1
-1
@@ -169,7 +169,7 @@ type Service interface {
|
||||
// UpdateUsername updates the user's username.
|
||||
UpdateUsername(ctx context.Context, session authn.Session, id, username string) (User, error)
|
||||
|
||||
// UpdateProfile updates the user's profile picture.
|
||||
// UpdateProfilePicture updates the user's profile picture.
|
||||
UpdateProfilePicture(ctx context.Context, session authn.Session, user User) (User, error)
|
||||
|
||||
// GenerateResetToken email where mail will be sent.
|
||||
|
||||
Reference in New Issue
Block a user