package v1 import ( "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/suite" "gorm.io/driver/sqlite" "gorm.io/gorm" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/repository" "github.com/gochat/gochat/internal/service" ) type DeliveryStatusHandlerTestSuite struct { suite.Suite db *gorm.DB handler *DeliveryStatusHandler router *gin.Engine account *model.Account } func (s *DeliveryStatusHandlerTestSuite) SetupSuite() { var err error s.db, err = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) s.Require().NoError(err) s.Require().NoError(s.db.AutoMigrate(&model.DeliveryStatus{}, &model.Account{}, &model.Conversation{}, &model.Message{}, &model.Contact{}, &model.Inbox{}, &model.User{})) messageRepo := repository.NewMessageRepo(s.db) deliveryRepo := repository.NewDeliveryStatusRepo(s.db) svc := service.NewDeliveryStatusService(messageRepo, deliveryRepo) s.handler = NewDeliveryStatusHandler(svc) gin.SetMode(gin.TestMode) r := gin.New() accountGroup := r.Group("/api/v1/accounts/:account_id") conversationGroup := accountGroup.Group("/conversations/:conversation_id") messageGroup := conversationGroup.Group("/messages/:message_id") messageGroup.GET("/delivery_status", s.handler.List) s.router = r s.account = &model.Account{Name: "TestAccount"} s.db.Create(s.account) } func (s *DeliveryStatusHandlerTestSuite) TearDownSuite() { s.db.Exec("DELETE FROM delivery_statuses") s.db.Exec("DELETE FROM messages") s.db.Exec("DELETE FROM accounts") } func (s *DeliveryStatusHandlerTestSuite) SetupTest() { s.db.Exec("DELETE FROM delivery_statuses") s.db.Exec("DELETE FROM messages") } func TestDeliveryStatusHandlerTestSuite(t *testing.T) { suite.Run(t, new(DeliveryStatusHandlerTestSuite)) } func (s *DeliveryStatusHandlerTestSuite) TestList_InvalidAccountID() { w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/accounts/abc/conversations/1/messages/1/delivery_status", nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) } func (s *DeliveryStatusHandlerTestSuite) TestList_InvalidConversationID() { w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/accounts/1/conversations/abc/messages/1/delivery_status", nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) } func (s *DeliveryStatusHandlerTestSuite) TestList_InvalidMessageID() { w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/accounts/1/conversations/1/messages/abc/delivery_status", nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) } func (s *DeliveryStatusHandlerTestSuite) TestList_Success() { // Create conversation, message with proper account association conv := &model.Conversation{AccountID: s.account.ID} s.db.Create(conv) msg := &model.Message{ConversationID: conv.ID, AccountID: s.account.ID} s.db.Create(msg) s.db.Create(&model.DeliveryStatus{MessageID: msg.ID, InboxID: 1, ContactID: 1, Status: model.MessageStatusDelivered}) s.db.Create(&model.DeliveryStatus{MessageID: msg.ID, InboxID: 1, ContactID: 2, Status: model.MessageStatusRead}) w := httptest.NewRecorder() url := fmt.Sprintf("/api/v1/accounts/%d/conversations/%d/messages/%d/delivery_status", s.account.ID, conv.ID, msg.ID) req := httptest.NewRequest(http.MethodGet, url, nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusOK, w.Code) var resp map[string]interface{} s.NoError(json.Unmarshal(w.Body.Bytes(), &resp)) s.NotNil(resp["data"]) } func (s *DeliveryStatusHandlerTestSuite) TestList_MessageNotFound() { w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/accounts/1/conversations/1/messages/999/delivery_status", nil) s.router.ServeHTTP(w, req) // Service can't find message → handleServiceError → 404 s.Equal(http.StatusNotFound, w.Code) }