package v1 import ( "encoding/json" "net/http" "net/http/httptest" "fmt" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/suite" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/repository" "github.com/gochat/gochat/internal/service" ) // ContactInboxHandlerTestSuite tests ContactInboxHandler with real SQLite DB. type ContactInboxHandlerTestSuite struct { suite.Suite db *gorm.DB router *gin.Engine handler *ContactInboxHandler } func (s *ContactInboxHandlerTestSuite) SetupSuite() { gin.SetMode(gin.TestMode) db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) s.Require().NoError(err, "failed to open SQLite test database") // Auto-migrate required models (including FK dependencies) s.Require().NoError(db.AutoMigrate( &model.Account{}, &model.Inbox{}, &model.Contact{}, &model.ContactInbox{}, ), "failed to auto-migrate models") s.db = db repo := repository.NewContactInboxRepo(db) svc := service.NewContactInboxService(repo) s.handler = NewContactInboxHandler(svc) r := gin.New() s.router = r accounts := r.Group("/api/v1/accounts/:id") { accounts.GET("/contact_inboxes/filter", s.handler.Filter) } } func (s *ContactInboxHandlerTestSuite) TearDownSuite() { sqlDB, err := s.db.DB() if err == nil { sqlDB.Close() } } func (s *ContactInboxHandlerTestSuite) SetupTest() { s.db.Exec("DELETE FROM contact_inboxes") s.db.Exec("DELETE FROM contacts") s.db.Exec("DELETE FROM inboxes") s.db.Exec("DELETE FROM accounts") } // helper: create an account func (s *ContactInboxHandlerTestSuite) createAccount(name string) *model.Account { a := &model.Account{Name: name} s.Require().NoError(s.db.Create(a).Error) return a } // helper: create an inbox scoped to an account func (s *ContactInboxHandlerTestSuite) createInbox(accountID uint, name string) *model.Inbox { i := &model.Inbox{AccountID: accountID, Name: name, ChannelType: "channel_email"} s.Require().NoError(s.db.Create(i).Error) return i } // helper: create a contact scoped to an account func (s *ContactInboxHandlerTestSuite) createContact(accountID uint, name string) *model.Contact { c := &model.Contact{AccountID: accountID, Name: name} s.Require().NoError(s.db.Create(c).Error) return c } // helper: create a contact_inbox record directly via DB func (s *ContactInboxHandlerTestSuite) createContactInbox(contactID, inboxID uint, sourceID string) *model.ContactInbox { ci := &model.ContactInbox{ ContactID: contactID, InboxID: inboxID, SourceID: sourceID, HMACToken: "test_hmac", PubsubToken: "test_pubsub", } s.Require().NoError(s.db.Create(ci).Error) return ci } // --- Filter tests --- func (s *ContactInboxHandlerTestSuite) TestFilter_InvalidAccountID() { w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/accounts/abc/contact_inboxes/filter", nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) var body map[string]interface{} s.NoError(json.Unmarshal(w.Body.Bytes(), &body)) s.Contains(body, "error") } func (s *ContactInboxHandlerTestSuite) TestFilter_EmptyResult() { a := s.createAccount("TestAccount") w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/accounts/"+fmt.Sprintf("%d", a.ID)+"/contact_inboxes/filter", nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusOK, w.Code) var body map[string]interface{} s.NoError(json.Unmarshal(w.Body.Bytes(), &body)) s.NotNil(body["contact_inboxes"]) cis := body["contact_inboxes"].([]interface{}) s.Len(cis, 0) } func (s *ContactInboxHandlerTestSuite) TestFilter_WithResults() { a := s.createAccount("TestAccount") i := s.createInbox(a.ID, "TestInbox") c := s.createContact(a.ID, "TestContact") s.createContactInbox(c.ID, i.ID, "src123") w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/accounts/"+fmt.Sprintf("%d", a.ID)+"/contact_inboxes/filter", nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusOK, w.Code) var body map[string]interface{} s.NoError(json.Unmarshal(w.Body.Bytes(), &body)) s.NotNil(body["contact_inboxes"]) } func (s *ContactInboxHandlerTestSuite) TestFilter_WithInboxIDFilter() { a := s.createAccount("TestAccount") i1 := s.createInbox(a.ID, "Inbox1") i2 := s.createInbox(a.ID, "Inbox2") c := s.createContact(a.ID, "TestContact") s.createContactInbox(c.ID, i1.ID, "src1") s.createContactInbox(c.ID, i2.ID, "src2") w := httptest.NewRecorder() url := "/api/v1/accounts/" + fmt.Sprintf("%d", a.ID) + "/contact_inboxes/filter?inbox_id=" + fmt.Sprintf("%d", i1.ID) req := httptest.NewRequest(http.MethodGet, url, nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusOK, w.Code) } func (s *ContactInboxHandlerTestSuite) TestFilter_WithContactIDFilter() { a := s.createAccount("TestAccount") i := s.createInbox(a.ID, "Inbox") c1 := s.createContact(a.ID, "Contact1") c2 := s.createContact(a.ID, "Contact2") s.createContactInbox(c1.ID, i.ID, "src1") s.createContactInbox(c2.ID, i.ID, "src2") w := httptest.NewRecorder() url := "/api/v1/accounts/" + fmt.Sprintf("%d", a.ID) + "/contact_inboxes/filter?contact_id=" + fmt.Sprintf("%d", c1.ID) req := httptest.NewRequest(http.MethodGet, url, nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusOK, w.Code) } func (s *ContactInboxHandlerTestSuite) TestFilter_WithSourceIDFilter() { a := s.createAccount("TestAccount") i := s.createInbox(a.ID, "Inbox") c := s.createContact(a.ID, "Contact") s.createContactInbox(c.ID, i.ID, "special_source") w := httptest.NewRecorder() url := "/api/v1/accounts/" + fmt.Sprintf("%d", a.ID) + "/contact_inboxes/filter?source_id=special_source" req := httptest.NewRequest(http.MethodGet, url, nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusOK, w.Code) } func (s *ContactInboxHandlerTestSuite) TestFilter_Pagination() { a := s.createAccount("TestAccount") i := s.createInbox(a.ID, "Inbox") c := s.createContact(a.ID, "Contact") for j := 0; j < 5; j++ { s.createContactInbox(c.ID, i.ID, "src"+fmt.Sprintf("%d", j)) } w := httptest.NewRecorder() url := "/api/v1/accounts/" + fmt.Sprintf("%d", a.ID) + "/contact_inboxes/filter?page=1&page_size=2" req := httptest.NewRequest(http.MethodGet, url, nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusOK, w.Code) var body map[string]interface{} s.NoError(json.Unmarshal(w.Body.Bytes(), &body)) meta := body["meta"].(map[string]interface{}) s.Equal(float64(5), meta["count"]) } func TestContactInboxHandlerTestSuite(t *testing.T) { suite.Run(t, new(ContactInboxHandlerTestSuite)) }