All checks were successful
Server Check Build (NixCN CMS) TeamCity build finished
Signed-off-by: Asai Neko <sugar@sne.moe>
273 lines
6.4 KiB
Go
273 lines
6.4 KiB
Go
package service_user
|
||
|
||
import (
|
||
"context"
|
||
"encoding/base64"
|
||
"testing"
|
||
|
||
"github.com/google/uuid"
|
||
"github.com/stretchr/testify/assert"
|
||
"github.com/stretchr/testify/require"
|
||
"nixcn-cms/data"
|
||
"nixcn-cms/testutil"
|
||
)
|
||
|
||
func newUserSvc() UserService { return NewUserService() }
|
||
|
||
func strPtr(s string) *string { return &s }
|
||
func uintPtr(u uint) *uint { return &u }
|
||
|
||
// ---- GetInfo ----
|
||
|
||
func TestUserGetInfoSelf(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
u := testutil.SeedUser(t, "getinfo@example.com", 10)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.GetInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: u.UserId,
|
||
OperatorId: u.UserId,
|
||
IsOther: false,
|
||
Data: &UserInfoData{},
|
||
})
|
||
|
||
assert.Equal(t, 200, result.Common.HttpCode)
|
||
require.NotNil(t, result.Data)
|
||
assert.Equal(t, u.Email, result.Data.Email)
|
||
}
|
||
|
||
func TestUserGetInfoOtherPublic(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
target := testutil.SeedUser(t, "public@example.com", 10)
|
||
require.NoError(t, new(data.User).PatchByUserId(ctx, target.UserId, data.WithAllowPublic(true)))
|
||
|
||
svc := newUserSvc()
|
||
result := svc.GetInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: target.UserId,
|
||
OperatorId: uuid.New(),
|
||
IsOther: true,
|
||
Data: &UserInfoData{},
|
||
})
|
||
|
||
assert.Equal(t, 200, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserGetInfoOtherPrivate(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
target := testutil.SeedUser(t, "private@example.com", 10)
|
||
// AllowPublic defaults to false – no patch needed
|
||
|
||
svc := newUserSvc()
|
||
result := svc.GetInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: target.UserId,
|
||
OperatorId: uuid.New(),
|
||
IsOther: true,
|
||
Data: &UserInfoData{},
|
||
})
|
||
|
||
assert.Equal(t, 403, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserGetInfoNotFound(t *testing.T) {
|
||
testutil.Setup(t)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.GetInfo(&UserInfoPayload{
|
||
Context: context.Background(),
|
||
UserId: uuid.New(),
|
||
Data: &UserInfoData{},
|
||
})
|
||
|
||
assert.Equal(t, 404, result.Common.HttpCode)
|
||
}
|
||
|
||
// ---- UpdateInfo ----
|
||
|
||
func TestUserUpdateInfoNickname(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
u := testutil.SeedUser(t, "update@example.com", 10)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.UpdateInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: u.UserId,
|
||
OperatorId: u.UserId,
|
||
Data: &UserInfoData{Nickname: strPtr("New Nick")},
|
||
})
|
||
|
||
assert.Equal(t, 200, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserUpdateInfoEmptyNickname(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
u := testutil.SeedUser(t, "update2@example.com", 10)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.UpdateInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: u.UserId,
|
||
OperatorId: u.UserId,
|
||
Data: &UserInfoData{Nickname: strPtr("")},
|
||
})
|
||
|
||
assert.Equal(t, 400, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserUpdateInfoUsernameTooShort(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
u := testutil.SeedUser(t, "update3@example.com", 10)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.UpdateInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: u.UserId,
|
||
OperatorId: u.UserId,
|
||
Data: &UserInfoData{Username: strPtr("abc")},
|
||
})
|
||
|
||
assert.Equal(t, 400, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserUpdateInfoBioMustBeBase64(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
u := testutil.SeedUser(t, "update4@example.com", 10)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.UpdateInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: u.UserId,
|
||
OperatorId: u.UserId,
|
||
Data: &UserInfoData{Bio: strPtr("not-base64!!!")},
|
||
})
|
||
|
||
assert.Equal(t, 400, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserUpdateInfoBioBase64Valid(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
u := testutil.SeedUser(t, "update5@example.com", 10)
|
||
bio := base64.StdEncoding.EncodeToString([]byte("my bio"))
|
||
|
||
svc := newUserSvc()
|
||
result := svc.UpdateInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: u.UserId,
|
||
OperatorId: u.UserId,
|
||
Data: &UserInfoData{Bio: strPtr(bio)},
|
||
})
|
||
|
||
assert.Equal(t, 200, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserUpdateInfoAdminPermissionMatrix(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
admin := testutil.SeedUser(t, "admin@example.com", 40)
|
||
target := testutil.SeedUser(t, "target@example.com", 30)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.UpdateInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: target.UserId,
|
||
OperatorId: admin.UserId,
|
||
OperatorLevel: admin.PermissionLevel,
|
||
Data: &UserInfoData{Nickname: strPtr("Admin Edited")},
|
||
})
|
||
|
||
assert.Equal(t, 200, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserUpdateInfoAdminCannotEditPeer(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
admin1 := testutil.SeedUser(t, "admin1@example.com", 40)
|
||
admin2 := testutil.SeedUser(t, "admin2@example.com", 40)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.UpdateInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: admin2.UserId,
|
||
OperatorId: admin1.UserId,
|
||
OperatorLevel: admin1.PermissionLevel,
|
||
Data: &UserInfoData{Nickname: strPtr("Hacked")},
|
||
})
|
||
|
||
assert.Equal(t, 403, result.Common.HttpCode)
|
||
}
|
||
|
||
func TestUserUpdateInfoAdminCannotGrantSameLevel(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
admin := testutil.SeedUser(t, "adminlvl@example.com", 40)
|
||
target := testutil.SeedUser(t, "targetlvl@example.com", 10)
|
||
newLevel := uint(40)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.UpdateInfo(&UserInfoPayload{
|
||
Context: ctx,
|
||
UserId: target.UserId,
|
||
OperatorId: admin.UserId,
|
||
OperatorLevel: admin.PermissionLevel,
|
||
Data: &UserInfoData{PermissionLevel: &newLevel},
|
||
})
|
||
|
||
assert.Equal(t, 403, result.Common.HttpCode)
|
||
}
|
||
|
||
// ---- List ----
|
||
|
||
func TestUserListRequiresOffset(t *testing.T) {
|
||
testutil.Setup(t)
|
||
|
||
svc := newUserSvc()
|
||
result := svc.List(&UserListPayload{
|
||
Context: context.Background(),
|
||
Data: &UserListData{},
|
||
})
|
||
|
||
assert.Equal(t, 400, result.Common.HttpCode)
|
||
}
|
||
|
||
// The list service has a known bug where the offset variable is never
|
||
// assigned from payload.Offset, causing strconv.Atoi to fail on "".
|
||
// This test documents the actual (buggy) behaviour so we can track it.
|
||
func TestUserListWithOffset(t *testing.T) {
|
||
testutil.Setup(t)
|
||
ctx := context.Background()
|
||
|
||
for i := 0; i < 3; i++ {
|
||
testutil.SeedUser(t, uuid.New().String()+"@example.com", 10)
|
||
}
|
||
|
||
offset := "0"
|
||
svc := newUserSvc()
|
||
result := svc.List(&UserListPayload{
|
||
Context: ctx,
|
||
Data: &UserListData{Offset: &offset},
|
||
})
|
||
|
||
assert.Equal(t, 200, result.Common.HttpCode)
|
||
}
|