package repository import ( "app-cloudep-member-server/pkg/domain/entity" "app-cloudep-member-server/pkg/domain/member" "app-cloudep-member-server/pkg/domain/repository" "context" "errors" "testing" "time" mgo "code.30cm.net/digimon/library-go/mongo" "github.com/alicebob/miniredis/v2" "github.com/stretchr/testify/assert" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/redis" "go.mongodb.org/mongo-driver/bson/primitive" "google.golang.org/protobuf/proto" ) func SetupTestUserRepository(db string) (repository.UserRepository, func(), error) { h, p, tearDown, err := startMongoContainer() if err != nil { return nil, nil, err } s, _ := miniredis.Run() conf := &mgo.Conf{ Schema: Schema, Host: h, Port: p, Database: db, MaxStaleness: 300, MaxPoolSize: 100, MinPoolSize: 100, MaxConnIdleTime: 300, Compressors: []string{}, EnableStandardReadWriteSplitMode: false, ConnectTimeoutMs: 3000, } cacheConf := cache.CacheConf{ cache.NodeConf{ RedisConf: redis.RedisConf{ Host: s.Addr(), Type: redis.NodeType, }, Weight: 100, }, } cacheOpts := []cache.Option{ cache.WithExpiry(1000 * time.Microsecond), cache.WithNotFoundExpiry(1000 * time.Microsecond), } param := UserRepositoryParam{ Conf: conf, CacheConf: cacheConf, CacheOpts: cacheOpts, } repo := NewUserRepository(param) _, _ = repo.Index20241226001UP(context.Background()) return repo, tearDown, nil } func TestCustomUserModel_UpdateEmailVerifyStatus(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) initialUser := &entity.User{ UID: "test_uid_email", Email: proto.String("old_email@example.com"), } err = repo.Insert(context.Background(), initialUser) assert.NoError(t, err) err = repo.UpdateEmailVerifyStatus(context.Background(), "test_uid_email", "new_email@example.com") assert.NoError(t, err) updatedUser, err := repo.FindOneByUID(context.Background(), "test_uid_email") assert.NoError(t, err) assert.Equal(t, "new_email@example.com", *updatedUser.Email) } func TestCustomUserModel_UpdatePhoneVerifyStatus(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) initialUser := &entity.User{ UID: "test_uid_phone", PhoneNumber: proto.String("123456789"), } err = repo.Insert(context.Background(), initialUser) assert.NoError(t, err) err = repo.UpdatePhoneVerifyStatus(context.Background(), "test_uid_phone", "987654321") assert.NoError(t, err) updatedUser, err := repo.FindOneByUID(context.Background(), "test_uid_phone") assert.NoError(t, err) assert.Equal(t, "987654321", *updatedUser.PhoneNumber) } func TestCustomUserModel_UpdateUserDetailsByUID(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) tests := []struct { name string initialData *entity.User updateData *repository.UpdateUserInfoRequest expectError bool }{ { name: "Update user details by UID", initialData: &entity.User{ UID: "test_uid_1", Nickname: proto.String("old_nickname"), FullName: proto.String("Old Full Name"), }, updateData: &repository.UpdateUserInfoRequest{ UID: "test_uid_1", Nickname: proto.String("new_nickname"), FullName: proto.String("New Full Name"), }, expectError: false, }, { name: "User not found", initialData: nil, updateData: &repository.UpdateUserInfoRequest{ UID: "non_existent_uid", Nickname: proto.String("nickname"), }, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.initialData != nil { err := repo.Insert(context.Background(), tt.initialData) assert.NoError(t, err) } err := repo.UpdateUserDetailsByUID(context.Background(), tt.updateData) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err) updatedUser, err := repo.FindOneByUID(context.Background(), tt.updateData.UID) assert.NoError(t, err) assert.Equal(t, *tt.updateData.Nickname, *updatedUser.Nickname) assert.Equal(t, *tt.updateData.FullName, *updatedUser.FullName) } }) } } func TestCustomUserModel_FindOneByUID(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) initialUser := &entity.User{ UID: "test_uid", } err = repo.Insert(context.Background(), initialUser) assert.NoError(t, err) user, err := repo.FindOneByUID(context.Background(), "test_uid") assert.NoError(t, err) assert.Equal(t, "test_uid", user.UID) } func TestCustomUserModel_ListMembers(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) users := []*entity.User{ {UID: "uid1", UserStatus: member.AccountStatusActive}, {UID: "uid2", UserStatus: member.AccountStatusActive}, {UID: "uid3", UserStatus: member.AccountStatusUnverified}, } for _, user := range users { err := repo.Insert(context.Background(), user) assert.NoError(t, err) } activeStatus := member.AccountStatusActive params := &repository.UserQueryParams{ UserStatus: &activeStatus, PageSize: 2, PageIndex: 1, } result, count, err := repo.ListMembers(context.Background(), params) assert.NoError(t, err) assert.Equal(t, int64(2), count) assert.Len(t, result, 2) } func TestCustomUserModel_FindOne(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) // 準備測試資料 initialUser := &entity.User{ UID: "test_uid", } err = repo.Insert(context.Background(), initialUser) assert.NoError(t, err) tests := []struct { name string id string expectError bool expectedUID string }{ { name: "Valid FindOne", id: initialUser.ID.Hex(), expectError: false, expectedUID: initialUser.UID, }, { name: "Invalid ObjectID", id: "invalid_id", expectError: true, }, { name: "Non-existent ObjectID", id: primitive.NewObjectID().Hex(), expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := repo.FindOne(context.Background(), tt.id) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err) assert.Equal(t, tt.expectedUID, result.UID, "找到的 UID 應符合預期") } }) } } func TestCustomUserModel_Update(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) // 準備測試資料 initialUser := &entity.User{ UID: "test_uid", } err = repo.Insert(context.Background(), initialUser) assert.NoError(t, err) updatedUID := "test_uid" initialUser.UID = updatedUID // 執行更新操作 _, err = repo.Update(context.Background(), initialUser) assert.NoError(t, err, "應成功更新資料") // 確認更新結果 updatedAccountUid, err := repo.FindOne(context.Background(), initialUser.ID.Hex()) assert.NoError(t, err, "應能找到更新後的資料") assert.Equal(t, updatedUID, updatedAccountUid.UID, "更新後的 UID 應符合預期") } func TestCustomUserModel_Delete(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) // 準備測試資料 initialUser := &entity.User{ UID: "test_uid", } err = repo.Insert(context.Background(), initialUser) assert.NoError(t, err) // 執行刪除操作 count, err := repo.Delete(context.Background(), initialUser.ID.Hex()) assert.NoError(t, err, "應成功刪除資料") assert.Equal(t, int64(1), count, "刪除數量應為 1") // 確認資料已被刪除 _, err = repo.FindOne(context.Background(), initialUser.ID.Hex()) assert.Error(t, err, "應無法找到已刪除的資料") assert.Equal(t, ErrNotFound, err, "應返回 ErrNotFound 錯誤") } func TestUserRepository_UpdateStatus(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) // 插入測試數據 e := &entity.User{ UID: "test_uid", UserStatus: member.AccountStatusActive, } err = repo.Insert(context.TODO(), e) assert.NoError(t, err) // 測試用例 tests := []struct { name string uid string status member.Status expectError bool expectedErr error }{ { name: "Valid UID - Successful update", uid: e.UID, status: member.AccountStatusActive, expectError: false, }, { name: "Invalid UID - No mapping to ID", uid: "invalid_uid", status: 3, expectError: true, expectedErr: errors.New("invalid uid"), }, { name: "Non-existent UID", uid: "non_existent_uid", status: 4, expectError: true, expectedErr: errors.New("invalid uid"), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := repo.UpdateStatus(context.TODO(), tt.uid, tt.status.ToInt32()) if tt.expectError { assert.Error(t, err) assert.Equal(t, tt.expectedErr.Error(), err.Error()) } else { assert.NoError(t, err) // 驗證數據是否正確更新 user, err := repo.FindOneByUID(context.TODO(), tt.uid) assert.NoError(t, err) assert.Equal(t, tt.status, user.UserStatus, "UserStatus 應更新為預期值") } }) } } func TestCustomUserModel_FindOneByNickName(t *testing.T) { repo, tearDown, err := SetupTestUserRepository("testDB") defer tearDown() assert.NoError(t, err) initialUser := &entity.User{ UID: "test_uid", Nickname: proto.String("my_name"), } err = repo.Insert(context.Background(), initialUser) assert.NoError(t, err) user, err := repo.FindOneByNickName(context.Background(), "my_name") assert.NoError(t, err) assert.Equal(t, "test_uid", user.UID) }