package usecase_test import ( "context" "fmt" "testing" "gateway/internal/model/notification/config" domentity "gateway/internal/model/notification/domain/entity" "gateway/internal/model/notification/domain/enum" domrepo "gateway/internal/model/notification/domain/repository" domtpl "gateway/internal/model/notification/domain/template" domusecase "gateway/internal/model/notification/domain/usecase" mocknotifrepo "gateway/internal/model/notification/mock/repository" "gateway/internal/model/notification/provider/email" "gateway/internal/model/notification/template" "gateway/internal/model/notification/usecase" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/v2/bson" "go.uber.org/mock/gomock" ) func TestRetryWorker_ProcessJob_Success(t *testing.T) { ctrl := gomock.NewController(t) repo := mocknotifrepo.NewMockNotificationRepository(ctrl) docID := bson.NewObjectID() doc := &domentity.Notification{ ID: docID, TenantID: testTenantID, Status: enum.NotifyStatusPending, Locale: domtpl.LocaleZhTW, Attempts: 0, } repo.EXPECT().FindByID(gomock.Any(), testTenantID, docID.Hex()).Return(doc, nil) repo.EXPECT().UpdateDelivery(gomock.Any(), testTenantID, docID.Hex(), gomock.Any()).Return(nil) worker := usecase.NewRetryWorker(usecase.RetryWorkerParam{ Repo: repo, Renderer: template.NewRenderer(template.DefaultRegistry(), domtpl.LocaleZhTW), Email: email.NewChain(email.NewMockSender( email.WithMockName("mock"), email.WithMockMessageID("ok"), )), Config: config.Config{Email: config.EmailConfig{From: testEmailFrom}}, }) job := &domusecase.RetryJob{ NotificationID: docID.Hex(), TenantID: testTenantID, Channel: enum.ChannelEmail, Kind: enum.NotifyTenantWelcome, Target: testEmailTarget, Locale: domtpl.LocaleZhTW, Data: map[string]any{varTenantName: testTenantName}, } require.NoError(t, worker.ProcessJob(context.Background(), job)) } func TestRetryWorker_ProcessJob_DropsToDLQ(t *testing.T) { ctrl := gomock.NewController(t) repo := mocknotifrepo.NewMockNotificationRepository(ctrl) dlq := mocknotifrepo.NewMockNotificationDLQRepository(ctrl) queue := mocknotifrepo.NewMockRetryQueue(ctrl) docID := bson.NewObjectID() doc := &domentity.Notification{ ID: docID, TenantID: testTenantID, Status: enum.NotifyStatusRetrying, Locale: domtpl.LocaleZhTW, Attempts: 4, } repo.EXPECT().FindByID(gomock.Any(), testTenantID, docID.Hex()).Return(doc, nil) repo.EXPECT().UpdateDelivery(gomock.Any(), testTenantID, docID.Hex(), gomock.Any()).DoAndReturn( func(_ context.Context, _, _ string, u *domrepo.NotificationDeliveryUpdate) error { require.Equal(t, enum.NotifyStatusDropped, u.Status) return nil }, ) dlq.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil) worker := usecase.NewRetryWorker(usecase.RetryWorkerParam{ Repo: repo, DLQ: dlq, Queue: queue, Renderer: template.NewRenderer(template.DefaultRegistry(), domtpl.LocaleZhTW), Email: email.NewChain(email.NewMockSender(email.WithMockError(fmt.Errorf("fail")))), Config: config.Config{Async: config.AsyncConfig{MaxRetry: 5}, Email: config.EmailConfig{From: testEmailFrom}}, }) job := &domusecase.RetryJob{ NotificationID: docID.Hex(), TenantID: testTenantID, Channel: enum.ChannelEmail, Kind: enum.NotifyTenantWelcome, Target: testEmailTarget, Data: map[string]any{varTenantName: testTenantName}, } require.NoError(t, worker.ProcessJob(context.Background(), job)) }