package repository import ( "context" "fmt" "testing" "time" "code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/entity" "code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/repository" 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/mon" "github.com/zeromicro/go-zero/core/stores/redis" "go.mongodb.org/mongo-driver/bson/primitive" "google.golang.org/protobuf/proto" ) func SetupTestCommentRepository(db string) (repository.CommentRepository, func(), error) { h, p, tearDown, err := startMongoContainer() if err != nil { return nil, nil, err } s, _ := miniredis.Run() conf := &mgo.Conf{ Schema: Schema, Host: fmt.Sprintf("%s:%s", h, 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), } dbOpts := []mon.Option{ mgo.SetCustomDecimalType(), mgo.InitMongoOptions(*conf), } param := CommentRepositoryParam{ Conf: conf, CacheConf: cacheConf, CacheOpts: cacheOpts, DBOpts: dbOpts, } repo := MustCommentRepository(param) //_, _ = repo.Index20241230001UP(context.Background()) return repo, tearDown, nil } func TestCommentRepository_CreateCommentItem(t *testing.T) { repo, tearDown, err := SetupTestCommentRepository("testDB") assert.NoError(t, err) defer tearDown() tests := []struct { name string input *entity.Comments expectError bool }{ { name: "Valid comment creation", input: &entity.Comments{ UID: "test-uid", ReferenceID: "ref-001", ParentCommentID: "", Message: "This is a test comment", }, expectError: false, }, { name: "Comment with existing ID", input: &entity.Comments{ ID: primitive.NewObjectID(), UID: "test-uid", ReferenceID: "ref-002", ParentCommentID: "", Message: "This is another test comment", }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := repo.CreateComment(context.Background(), tt.input) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err) // 驗證插入的數據是否存在於資料庫中 result, _, err := repo.ListComments(context.Background(), repository.ListCommentRequest{ PageSize: 10, PageIndex: 1, ReferenceID: &tt.input.ReferenceID, }) assert.NoError(t, err) assert.NotNil(t, result, "應該能找到插入的留言") assert.Equal(t, tt.input.UID, result[0].UID, "UID 應該匹配") assert.Equal(t, tt.input.ReferenceID, result[0].ReferenceID, "ReferenceID 應該匹配") assert.Equal(t, tt.input.Message, result[0].Message, "Message 應該匹配") } }) } } func TestCommentRepository_ListComment(t *testing.T) { repo, tearDown, err := SetupTestCommentRepository("testDB") assert.NoError(t, err) defer tearDown() // 插入測試留言資料 testComments := []entity.Comments{ { ID: primitive.NewObjectID(), UID: "user1", ReferenceID: "ref-001", ParentCommentID: "", Message: "This is a parent comment", CreatedAt: time.Now().Add(-10 * time.Minute).UnixNano(), }, { ID: primitive.NewObjectID(), UID: "user2", ReferenceID: "ref-001", ParentCommentID: "", Message: "This is another parent comment", CreatedAt: time.Now().Add(-5 * time.Minute).UnixNano(), }, { ID: primitive.NewObjectID(), UID: "user3", ReferenceID: "ref-002", ParentCommentID: "parent-id", Message: "This is a child comment", CreatedAt: time.Now().Add(-3 * time.Minute).UnixNano(), }, } for _, comment := range testComments { err := repo.CreateComment(context.Background(), &comment) assert.NoError(t, err, "插入應成功") } tests := []struct { name string req repository.ListCommentRequest expectedTotal int64 expectedIDs []primitive.ObjectID expectError bool }{ { name: "List all comments for ReferenceID", req: repository.ListCommentRequest{ ReferenceID: proto.String("ref-001"), PageIndex: 1, PageSize: 10, }, expectedTotal: 2, expectedIDs: []primitive.ObjectID{testComments[1].ID, testComments[0].ID}, // 根據 CreatedAt 排序 expectError: false, }, { name: "List child comments by ParentID", req: repository.ListCommentRequest{ ParentID: proto.String("parent-id"), PageIndex: 1, PageSize: 10, }, expectedTotal: 1, expectedIDs: []primitive.ObjectID{testComments[2].ID}, expectError: false, }, { name: "Pagination test", req: repository.ListCommentRequest{ ReferenceID: proto.String("ref-001"), PageIndex: 1, PageSize: 1, }, expectedTotal: 2, expectedIDs: []primitive.ObjectID{testComments[1].ID}, // 第一頁應只有一條 expectError: false, }, { name: "No matching comments", req: repository.ListCommentRequest{ ReferenceID: proto.String("non-existent"), PageIndex: 1, PageSize: 10, }, expectedTotal: 0, expectedIDs: nil, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { comments, total, err := repo.ListComments(context.Background(), tt.req) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err) assert.Equal(t, tt.expectedTotal, total, "返回的總數應該正確") assert.Len(t, comments, len(tt.expectedIDs), "返回的留言數量應該正確") for i, comment := range comments { assert.Equal(t, tt.expectedIDs[i], comment.ID, "留言 ID 應匹配") } } }) } } func TestCommentRepository_DeleteCommentByID(t *testing.T) { repo, tearDown, err := SetupTestCommentRepository("testDB") assert.NoError(t, err) defer tearDown() // 插入測試留言 comment := &entity.Comments{ UID: "test-uid", ReferenceID: "ref-001", ParentCommentID: "", Message: "This is a test comment", } err = repo.CreateComment(context.Background(), comment) assert.NoError(t, err, "插入應成功") invalidID := "invalid-id" // 無效的 ObjectID 格式 nonExistentID := primitive.NewObjectID().Hex() // 不存在的 ID tests := []struct { name string id string expectError bool expectedErr error expectedRes int64 }{ { name: "Valid delete", id: comment.ID.Hex(), expectError: false, expectedErr: ErrNotFound, expectedRes: 1, }, { name: "Invalid ID format", id: invalidID, expectError: true, expectedErr: ErrInvalidObjectID, expectedRes: 0, }, { name: "Non-existent ID", id: nonExistentID, expectError: false, expectedRes: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // 調用刪除方法 err := repo.DeleteCommentByID(context.Background(), tt.id) if tt.expectError { // 驗證錯誤是否正確 assert.Error(t, err) assert.Equal(t, tt.expectedErr, err) } else { // 驗證刪除是否成功 assert.NoError(t, err) // 驗證刪除後是否還存在 // 驗證插入的數據是否存在於資料庫中 result, _, err := repo.ListComments(context.Background(), repository.ListCommentRequest{ PageSize: 10, PageIndex: 1, ReferenceID: &comment.ReferenceID, }) assert.NoError(t, err) assert.Nil(t, result, "留言應該被刪除或不存在") } }) } } func TestCommentRepository_UpdateCommentMessage(t *testing.T) { repo, tearDown, err := SetupTestCommentRepository("testDB") assert.NoError(t, err) defer tearDown() // 插入測試留言 comment := &entity.Comments{ ID: primitive.NewObjectID(), UID: "user123", Message: "Original message", ReferenceID: "ref-001", CreatedAt: time.Now().UTC().UnixNano(), UpdatedAt: time.Now().UTC().UnixNano(), } err = repo.CreateComment(context.Background(), comment) assert.NoError(t, err, "插入應成功") tests := []struct { name string id string newMessage string expectError bool expectedError error }{ { name: "Valid update", id: comment.ID.Hex(), newMessage: "Updated message", expectError: false, }, { name: "Invalid ObjectID", id: "invalid-id", newMessage: "Should not update", expectError: true, expectedError: ErrInvalidObjectID, }, { name: "Comment not found", id: primitive.NewObjectID().Hex(), newMessage: "Should not update", expectError: true, expectedError: ErrNotFound, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := repo.UpdateCommentMessage(context.Background(), tt.id, tt.newMessage) if tt.expectError { // 驗證錯誤是否正確 assert.Error(t, err) assert.Equal(t, tt.expectedError, err) } else { // 驗證無錯誤返回 assert.NoError(t, err) // 驗證刪除後是否還存在 // 驗證插入的數據是否存在於資料庫中 result, _, err := repo.ListComments(context.Background(), repository.ListCommentRequest{ PageSize: 10, PageIndex: 1, ReferenceID: &comment.ReferenceID, }) assert.NoError(t, err) assert.NotNil(t, result, "更新後的留言應存在") assert.Equal(t, tt.newMessage, result[0].Message, "留言內容應更新") } }) } }