package repository import ( "app-cloudep-member-server/pkg/domain/entity" "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" "go.mongodb.org/mongo-driver/bson/primitive" "github.com/zeromicro/go-zero/core/stores/redis" ) func SetupTestAccountRepository(db string) (repository.AccountRepository, 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 := AccountRepositoryParam{ Conf: conf, CacheConf: cacheConf, CacheOpts: cacheOpts, } repo := NewAccountRepository(param) _, _ = repo.Index20241226001UP(context.Background()) return repo, tearDown, nil } func TestAccountModel_Insert(t *testing.T) { repo, tearDown, err := SetupTestAccountRepository("testDB") defer tearDown() assert.NoError(t, err) tests := []struct { name string account *entity.Account expectError bool }{ { name: "Valid account insert", account: &entity.Account{ LoginID: "testuser1", Token: "testtoken1", Platform: 1, }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // 插入測試帳戶 err := repo.Insert(context.Background(), tt.account) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err, "插入操作應該成功") // 檢查是否生成了 ObjectID 和時間戳 assert.NotZero(t, tt.account.ID, "ID 應該被生成") assert.NotNil(t, tt.account.CreateAt, "CreateAt 應該被設置") assert.NotNil(t, tt.account.UpdateAt, "UpdateAt 應該被設置") // 檢查插入的時間是否合理 now := time.Now().UTC().UnixNano() assert.LessOrEqual(t, *tt.account.CreateAt, now, "CreateAt 應在當前時間之前") assert.LessOrEqual(t, *tt.account.UpdateAt, now, "UpdateAt 應在當前時間之前") // 確認插入的資料 insertedAccount, err := repo.FindOne(context.Background(), tt.account.ID.Hex()) assert.NoError(t, err, "應該可以找到插入的帳號資料") assert.Equal(t, tt.account.LoginID, insertedAccount.LoginID, "LoginID 應相同") assert.Equal(t, tt.account.Token, insertedAccount.Token, "Token 應相同") assert.Equal(t, tt.account.Platform, insertedAccount.Platform, "Platform 應相同") } }) } } func TestAccountModel_FindOne(t *testing.T) { repo, tearDown, err := SetupTestAccountRepository("testDB") assert.NoError(t, err) defer tearDown() // 插入測試帳戶 account := &entity.Account{ LoginID: "testuser1", Token: "testtoken1", Platform: 1, } err = repo.Insert(context.TODO(), account) assert.NoError(t, err, "插入應成功") nid := primitive.NewObjectID() t.Logf("Inserted account ID: %s, nid:%s", account.ID.Hex(), nid.Hex()) tests := []struct { name string id string expectError bool expectedErr error }{ { name: "Valid ID", id: account.ID.Hex(), expectError: false, }, { name: "Non-existent ID", id: nid.Hex(), expectError: true, expectedErr: ErrNotFound, }, { name: "Invalid ID format", id: "invalid-id", expectError: true, expectedErr: ErrInvalidObjectID, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := repo.FindOne(context.TODO(), tt.id) if tt.expectError { assert.Error(t, err) assert.Equal(t, tt.expectedErr, err) } else { assert.NoError(t, err) assert.Equal(t, account.LoginID, result.LoginID) assert.Equal(t, account.Token, result.Token) } }) } } func TestAccountModel_Update(t *testing.T) { repo, tearDown, err := SetupTestAccountRepository("testDB") assert.NoError(t, err) defer tearDown() // 插入測試帳戶 account := &entity.Account{ LoginID: "testuser1", Token: "testtoken1", Platform: 1, } err = repo.Insert(context.Background(), account) assert.NoError(t, err, "插入應成功") // 更新測試 newToken := "updatedToken" account.Token = newToken _, err = repo.Update(context.Background(), account) assert.NoError(t, err, "更新應成功") // 驗證更新結果 updatedAccount, err := repo.FindOne(context.Background(), account.ID.Hex()) assert.NoError(t, err) assert.Equal(t, newToken, updatedAccount.Token, "Token 應更新") } func TestAccountModel_Delete(t *testing.T) { repo, tearDown, err := SetupTestAccountRepository("testDB") assert.NoError(t, err) defer tearDown() // 插入測試帳戶 account := &entity.Account{ LoginID: "testuser1", Token: "testtoken1", Platform: 1, } err = repo.Insert(context.Background(), account) assert.NoError(t, err, "插入應成功") tests := []struct { name string id string expectError bool expectedErr error }{ { name: "Valid delete", id: account.ID.Hex(), expectError: false, }, { name: "Invalid ID format", id: "invalid-id", expectError: true, expectedErr: ErrInvalidObjectID, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { deletedCount, err := repo.Delete(context.Background(), tt.id) if tt.expectError { assert.Error(t, err) assert.Equal(t, tt.expectedErr, err) } else { assert.NoError(t, err) assert.Equal(t, int64(1), deletedCount, "刪除應成功") } }) } } func TestAccountModel_FindOneByAccount(t *testing.T) { repo, tearDown, err := SetupTestAccountRepository("testDB") assert.NoError(t, err) defer tearDown() // 插入測試帳戶 account := &entity.Account{ LoginID: "testuser1", Token: "testtoken1", Platform: 1, } err = repo.Insert(context.Background(), account) assert.NoError(t, err, "插入應成功") tests := []struct { name string loginID string expectedErr error expectFound bool }{ { name: "Valid Account Found", loginID: "testuser1", expectedErr: nil, expectFound: true, }, { name: "Account Not Found", loginID: "nonexistentuser", expectedErr: ErrNotFound, expectFound: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := repo.FindOneByAccount(context.Background(), tt.loginID) if tt.expectFound { assert.NoError(t, err) assert.Equal(t, account.LoginID, result.LoginID) assert.Equal(t, account.Token, result.Token) } else { assert.Error(t, err) assert.True(t, errors.Is(err, tt.expectedErr)) } }) } } func TestAccountModel_UpdateTokenByLoginID(t *testing.T) { repo, tearDown, err := SetupTestAccountRepository("testDB") assert.NoError(t, err) defer tearDown() // 插入測試帳戶 account := &entity.Account{ LoginID: "testuser2", Token: "initialtoken", Platform: 1, } err = repo.Insert(context.Background(), account) assert.NoError(t, err, "插入應成功") tests := []struct { name string loginID string newToken string expectedErr error expectFound bool }{ { name: "Valid Update Token", loginID: "testuser2", newToken: "newtoken123", expectedErr: nil, expectFound: true, }, { name: "Account Not Found for Update", loginID: "nonexistentuser", newToken: "newtoken456", expectedErr: ErrNotFound, expectFound: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := repo.UpdateTokenByLoginID(context.Background(), tt.loginID, tt.newToken) if tt.expectFound { assert.NoError(t, err) // 驗證更新後的 token 值 updatedAccount, findErr := repo.FindOneByAccount(context.Background(), tt.loginID) assert.NoError(t, findErr) assert.Equal(t, tt.newToken, updatedAccount.Token) } else { assert.Error(t, err) assert.True(t, errors.Is(err, tt.expectedErr)) } }) } }