Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
214 lines
5.5 KiB
Go
214 lines
5.5 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"testing"
|
|
|
|
"quyun/v2/app/commands/testx"
|
|
|
|
user_dto "quyun/v2/app/http/v1/dto"
|
|
"quyun/v2/database"
|
|
"quyun/v2/database/models"
|
|
"quyun/v2/pkg/consts"
|
|
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
"github.com/stretchr/testify/suite"
|
|
"go.ipao.vip/atom/contracts"
|
|
"go.ipao.vip/gen/types"
|
|
"go.uber.org/dig"
|
|
)
|
|
|
|
type UserTestSuiteInjectParams struct {
|
|
dig.In
|
|
|
|
DB *sql.DB
|
|
Initials []contracts.Initial `group:"initials"`
|
|
}
|
|
|
|
type UserTestSuite struct {
|
|
suite.Suite
|
|
UserTestSuiteInjectParams
|
|
}
|
|
|
|
func Test_User(t *testing.T) {
|
|
providers := testx.Default().With(Provide)
|
|
|
|
testx.Serve(providers, t, func(p UserTestSuiteInjectParams) {
|
|
suite.Run(t, &UserTestSuite{UserTestSuiteInjectParams: p})
|
|
})
|
|
}
|
|
|
|
func (s *UserTestSuite) Test_LoginWithOTP() {
|
|
Convey("LoginWithOTP", s.T(), func() {
|
|
ctx := s.T().Context()
|
|
database.Truncate(ctx, s.DB, models.TableNameTenantUser, models.TableNameTenant, models.TableNameUser)
|
|
|
|
tenant := &models.Tenant{
|
|
UserID: 1000,
|
|
Name: "Tenant A",
|
|
Code: "tenant_a",
|
|
Status: consts.TenantStatusVerified,
|
|
}
|
|
models.TenantQuery.WithContext(ctx).Create(tenant)
|
|
|
|
Convey("should create user and login success without tenant", func() {
|
|
phone := "13800138000"
|
|
resp, err := User.LoginWithOTP(ctx, 0, phone, "1234")
|
|
So(err, ShouldBeNil)
|
|
So(resp, ShouldNotBeNil)
|
|
So(resp.Token, ShouldNotBeEmpty)
|
|
So(resp.User.Phone, ShouldEqual, phone)
|
|
So(resp.User.Nickname, ShouldStartWith, "User_")
|
|
})
|
|
|
|
Convey("should allow login when not tenant member", func() {
|
|
phone := "13800138001"
|
|
resp, err := User.LoginWithOTP(ctx, tenant.ID, phone, "1234")
|
|
So(err, ShouldBeNil)
|
|
So(resp, ShouldNotBeNil)
|
|
So(resp.Token, ShouldNotBeEmpty)
|
|
So(resp.User.Phone, ShouldEqual, phone)
|
|
})
|
|
|
|
Convey("should login existing tenant member", func() {
|
|
phone := "13800138002"
|
|
resp, err := User.LoginWithOTP(ctx, 0, phone, "1234")
|
|
So(err, ShouldBeNil)
|
|
|
|
models.TenantUserQuery.WithContext(ctx).Create(&models.TenantUser{
|
|
TenantID: tenant.ID,
|
|
UserID: resp.User.ID,
|
|
Role: types.Array[consts.TenantUserRole]{consts.TenantUserRoleMember},
|
|
Status: consts.UserStatusVerified,
|
|
})
|
|
|
|
resp2, err := User.LoginWithOTP(ctx, tenant.ID, phone, "1234")
|
|
So(err, ShouldBeNil)
|
|
So(resp2.User.Phone, ShouldEqual, phone)
|
|
})
|
|
|
|
Convey("should fail with incorrect OTP", func() {
|
|
resp, err := User.LoginWithOTP(ctx, 0, "13800138003", "000000")
|
|
So(err, ShouldNotBeNil)
|
|
So(resp, ShouldBeNil)
|
|
})
|
|
})
|
|
}
|
|
|
|
func (s *UserTestSuite) Test_Me() {
|
|
Convey("Me", s.T(), func() {
|
|
ctx := s.T().Context()
|
|
tenantID := int64(0)
|
|
database.Truncate(ctx, s.DB, models.TableNameUser)
|
|
|
|
// Create user
|
|
phone := "13800138003"
|
|
resp, _ := User.LoginWithOTP(ctx, tenantID, phone, "1234")
|
|
userID := resp.User.ID
|
|
|
|
Convey("should return user profile", func() {
|
|
// Mock context with user ID
|
|
ctx = context.WithValue(ctx, consts.CtxKeyUser, userID)
|
|
|
|
user, err := User.Me(ctx, userID)
|
|
So(err, ShouldBeNil)
|
|
So(user.ID, ShouldEqual, resp.User.ID)
|
|
So(user.Phone, ShouldEqual, phone)
|
|
})
|
|
|
|
Convey("should fail without auth", func() {
|
|
// No user ID in context
|
|
user, err := User.Me(ctx, 0)
|
|
So(err, ShouldNotBeNil)
|
|
So(user, ShouldBeNil)
|
|
})
|
|
})
|
|
}
|
|
|
|
func (s *UserTestSuite) Test_Update() {
|
|
Convey("Update", s.T(), func() {
|
|
ctx := s.T().Context()
|
|
tenantID := int64(0)
|
|
database.Truncate(ctx, s.DB, models.TableNameUser)
|
|
|
|
phone := "13800138004"
|
|
resp, _ := User.LoginWithOTP(ctx, tenantID, phone, "1234")
|
|
userID := resp.User.ID
|
|
ctx = context.WithValue(ctx, consts.CtxKeyUser, userID)
|
|
|
|
Convey("should update nickname and bio", func() {
|
|
form := &user_dto.UserUpdate{
|
|
Nickname: "NewName",
|
|
Bio: "New Bio",
|
|
Gender: consts.GenderMale,
|
|
}
|
|
err := User.Update(ctx, userID, form)
|
|
So(err, ShouldBeNil)
|
|
|
|
// Verify
|
|
u, _ := User.Me(ctx, userID)
|
|
So(u.Nickname, ShouldEqual, "NewName")
|
|
So(u.Bio, ShouldEqual, "New Bio")
|
|
So(u.Gender, ShouldEqual, consts.GenderMale)
|
|
})
|
|
})
|
|
}
|
|
|
|
func (s *UserTestSuite) Test_RealName() {
|
|
Convey("RealName", s.T(), func() {
|
|
ctx := s.T().Context()
|
|
tenantID := int64(0)
|
|
database.Truncate(ctx, s.DB, models.TableNameUser)
|
|
|
|
phone := "13800138005"
|
|
resp, _ := User.LoginWithOTP(ctx, tenantID, phone, "1234")
|
|
userID := resp.User.ID
|
|
ctx = context.WithValue(ctx, consts.CtxKeyUser, userID)
|
|
|
|
Convey("should update realname status", func() {
|
|
form := &user_dto.RealNameForm{
|
|
Realname: "张三",
|
|
IDCard: "123456789012345678",
|
|
}
|
|
err := User.RealName(ctx, userID, form)
|
|
So(err, ShouldBeNil)
|
|
|
|
// Verify
|
|
u, _ := User.Me(ctx, userID)
|
|
So(u.IsRealNameVerified, ShouldBeTrue)
|
|
})
|
|
})
|
|
}
|
|
|
|
func (s *UserTestSuite) Test_GetNotifications() {
|
|
Convey("GetNotifications", s.T(), func() {
|
|
ctx := s.T().Context()
|
|
tenantID := int64(0)
|
|
database.Truncate(ctx, s.DB, models.TableNameUser, models.TableNameNotification)
|
|
|
|
phone := "13800138006"
|
|
resp, _ := User.LoginWithOTP(ctx, tenantID, phone, "1234")
|
|
userID := resp.User.ID
|
|
ctx = context.WithValue(ctx, consts.CtxKeyUser, userID)
|
|
|
|
// Mock notifications
|
|
_ = models.Q.Notification.WithContext(ctx).Create(&models.Notification{
|
|
TenantID: tenantID,
|
|
UserID: userID,
|
|
Type: "system",
|
|
Title: "Welcome",
|
|
Content: "Hello World",
|
|
IsRead: false,
|
|
})
|
|
|
|
Convey("should return notifications", func() {
|
|
list, err := User.GetNotifications(ctx, tenantID, userID, "all")
|
|
So(err, ShouldBeNil)
|
|
So(len(list), ShouldEqual, 1)
|
|
So(list[0].Title, ShouldEqual, "Welcome")
|
|
So(list[0].Type, ShouldEqual, "system")
|
|
})
|
|
})
|
|
}
|