package repository import ( "app-cloudep-member-server/pkg/domain/entity" "app-cloudep-member-server/pkg/domain/repository" "context" "testing" "time" mgo "code.30cm.net/digimon/library-go/mongo" "github.com/stretchr/testify/assert" ) func SetupTestAutoIDRepository(db string) (repository.AutoIDRepository, func(), error) { h, p, tearDown, err := startMongoContainer() if err != nil { return nil, nil, err } 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, } param := AutoIDRepositoryParam{ Conf: conf, } repo := NewAutoIDRepository(param) _, _ = repo.Index20241226001UP(context.Background()) return repo, tearDown, nil } func TestDefaultAutoIDModel_Insert(t *testing.T) { repo, tearDown, err := SetupTestAutoIDRepository("testDB") defer tearDown() assert.NoError(t, err) tests := []struct { name string data *entity.AutoID expectError bool }{ { name: "Valid AutoID insert", data: &entity.AutoID{ Name: "testCounter", Counter: 100, }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := repo.Insert(context.Background(), tt.data) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err, "插入操作應該成功") // 檢查生成的 ID 和時間戳 assert.NotZero(t, tt.data.ID, "ID 應該被生成") assert.NotNil(t, tt.data.CreateAt, "CreateAt 應該被設置") assert.NotNil(t, tt.data.UpdateAt, "UpdateAt 應該被設置") // 確認插入的資料是否正確 now := time.Now().UTC().UnixNano() assert.LessOrEqual(t, *tt.data.CreateAt, now, "CreateAt 應在當前時間之前") assert.LessOrEqual(t, *tt.data.UpdateAt, now, "UpdateAt 應在當前時間之前") insertedAutoID, err := repo.FindOne(context.Background(), tt.data.ID.Hex()) assert.NoError(t, err, "應該可以找到插入的資料") assert.Equal(t, tt.data.Name, insertedAutoID.Name, "Name 應相同") assert.Equal(t, tt.data.Counter, insertedAutoID.Counter, "Counter 應相同") } }) } } func TestDefaultAutoIDModel_FindOne(t *testing.T) { repo, tearDown, err := SetupTestAutoIDRepository("testDB") defer tearDown() assert.NoError(t, err) inserted := &entity.AutoID{ Name: "findTestCounter", Counter: 200, } err = repo.Insert(context.Background(), inserted) assert.NoError(t, err) tests := []struct { name string id string expectError bool expectedID string }{ { name: "Valid FindOne by ID", id: inserted.ID.Hex(), expectError: false, expectedID: inserted.ID.Hex(), }, { name: "Invalid ObjectID", id: "invalidObjectID", 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.expectedID, result.ID.Hex(), "ID 應相同") } }) } } func TestDefaultAutoIDModel_Update(t *testing.T) { repo, tearDown, err := SetupTestAutoIDRepository("testDB") defer tearDown() assert.NoError(t, err) inserted := &entity.AutoID{ Name: "updateTestCounter", Counter: 300, } err = repo.Insert(context.Background(), inserted) assert.NoError(t, err) updatedData := *inserted // 創建副本進行更新 updatedData.Counter = 400 tests := []struct { name string data *entity.AutoID expectError bool }{ { name: "Valid Update", data: &updatedData, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := repo.Update(context.Background(), tt.data) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err) // 驗證更新後的 Counter updatedAutoID, err := repo.FindOne(context.Background(), tt.data.ID.Hex()) assert.NoError(t, err) assert.Equal(t, tt.data.Counter, updatedAutoID.Counter, "Counter 應相同") } }) } } func TestDefaultAutoIDModel_Delete(t *testing.T) { repo, tearDown, err := SetupTestAutoIDRepository("testDB") defer tearDown() assert.NoError(t, err) inserted := &entity.AutoID{ Name: "deleteTestCounter", Counter: 500, } err = repo.Insert(context.Background(), inserted) assert.NoError(t, err) tests := []struct { name string id string expectError bool }{ { name: "Valid Delete by ID", id: inserted.ID.Hex(), expectError: false, }, { name: "Invalid ObjectID", id: "invalidObjectID", expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { count, err := repo.Delete(context.Background(), tt.id) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err) assert.Equal(t, int64(1), count, "刪除應影響 1 條記錄") // 確認已刪除 _, err = repo.FindOne(context.Background(), tt.id) assert.ErrorIs(t, err, ErrNotFound, "記錄應該不存在") } }) } } func TestCustomAutoIDModel_Inc(t *testing.T) { tests := []struct { name string initialData *entity.AutoID expectError bool }{ { name: "Increment non-existing counter (upsert)", initialData: nil, // 不提供初始數據,預期會自動插入新數據 expectError: false, }, { name: "Increment existing counter", initialData: &entity.AutoID{ Name: "auto_id", Counter: 5, }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { repo, tearDown, err := SetupTestAutoIDRepository("testDB") defer tearDown() assert.NoError(t, err) // 插入初始數據(如果有) if tt.initialData != nil { err := repo.Insert(context.Background(), tt.initialData) assert.NoError(t, err, "初始插入操作應該成功") } // 創建一個 AutoID 結構來保存增量操作後的結果 var result entity.AutoID // 執行 Inc 方法 err = repo.Inc(context.Background(), &result) if tt.expectError { assert.Error(t, err, "應該返回錯誤") } else { assert.NoError(t, err, "Inc 操作應該成功") // 驗證結果中的 Counter 值是否正確增量 expectedCounter := uint64(1) if tt.initialData != nil { expectedCounter = tt.initialData.Counter + 1 } assert.Equal(t, expectedCounter, result.Counter, "Counter 值應該自增") } }) } }