Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
84 lines
2.7 KiB
Go
84 lines
2.7 KiB
Go
//go:build unit
|
|
|
|
package service
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// 这些用例锁死"每个入口只声明自己真正要改的列":
|
|
// 任何退回整行回写的改动都会让并发写入被陈旧快照覆盖,并在这里变红。
|
|
|
|
func TestUpdateProfile_OnlyDeclaresRequestedColumns(t *testing.T) {
|
|
username := "renamed"
|
|
tests := []struct {
|
|
name string
|
|
req UpdateProfileRequest
|
|
want UserUpdateFields
|
|
}{
|
|
{
|
|
name: "username only",
|
|
req: UpdateProfileRequest{Username: &username},
|
|
want: UserUpdateFields{Username: true},
|
|
},
|
|
{
|
|
name: "notify settings only",
|
|
req: UpdateProfileRequest{BalanceNotifyEnabled: boolPtr(true)},
|
|
want: UserUpdateFields{BalanceNotifySettings: true},
|
|
},
|
|
{
|
|
name: "username and notify threshold",
|
|
req: UpdateProfileRequest{Username: &username, BalanceNotifyThreshold: float64Ptr(1.5)},
|
|
want: UserUpdateFields{Username: true, BalanceNotifySettings: true},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
repo := &mockUserRepo{getByIDUser: &User{ID: 7, Balance: 0.30, Status: StatusActive}}
|
|
svc := NewUserService(repo, nil, nil, nil)
|
|
|
|
_, err := svc.UpdateProfile(context.Background(), 7, tt.req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, []UserUpdateFields{tt.want}, repo.updateFields)
|
|
})
|
|
}
|
|
}
|
|
|
|
// 只改头像时用户行没有任何列要写,不应产生一次整行更新。
|
|
func TestUpdateProfile_AvatarOnlySkipsUserRowWrite(t *testing.T) {
|
|
repo := &mockUserRepo{getByIDUser: &User{ID: 7, Balance: 0.30}}
|
|
svc := NewUserService(repo, nil, nil, nil)
|
|
|
|
avatar := "https://cdn.example.com/a.png"
|
|
_, err := svc.UpdateProfile(context.Background(), 7, UpdateProfileRequest{AvatarURL: &avatar})
|
|
require.NoError(t, err)
|
|
require.Len(t, repo.upsertAvatarArgs, 1, "avatar must still be stored")
|
|
require.Equal(t, []UserUpdateFields{{}}, repo.updateFields, "no user column should be declared")
|
|
}
|
|
|
|
func TestChangePassword_OnlyDeclaresPasswordHash(t *testing.T) {
|
|
user := &User{ID: 7, Balance: 0.30}
|
|
require.NoError(t, user.SetPassword("old-password"))
|
|
repo := &mockUserRepo{getByIDUser: user}
|
|
svc := NewUserService(repo, nil, nil, nil)
|
|
|
|
err := svc.ChangePassword(context.Background(), 7, ChangePasswordRequest{
|
|
CurrentPassword: "old-password",
|
|
NewPassword: "new-password",
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, []UserUpdateFields{{PasswordHash: true}}, repo.updateFields)
|
|
}
|
|
|
|
func TestUpdateStatus_OnlyDeclaresStatus(t *testing.T) {
|
|
repo := &mockUserRepo{getByIDUser: &User{ID: 7, Balance: 0.30, Status: StatusActive}}
|
|
svc := NewUserService(repo, nil, nil, nil)
|
|
|
|
require.NoError(t, svc.UpdateStatus(context.Background(), 7, StatusDisabled))
|
|
require.Equal(t, []UserUpdateFields{{Status: true}}, repo.updateFields)
|
|
}
|