package service import ( "context" "encoding/json" "testing" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/repository" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/gorm" ) // ============================================================ // ContactInboxService tests // ============================================================ func TestContactInboxService_GetByID(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewContactInboxRepo(db) svc := NewContactInboxService(repo) ci := &model.ContactInbox{ContactID: 1, InboxID: 1, SourceID: "src1"} require.NoError(t, db.Create(ci).Error) got, err := svc.GetByID(context.Background(), ci.ID) require.NoError(t, err) assert.Equal(t, "src1", got.SourceID) } func TestContactInboxService_GetByID_NotFound(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewContactInboxRepo(db) svc := NewContactInboxService(repo) _, err := svc.GetByID(context.Background(), 99999) require.Error(t, err) } func TestContactInboxService_GetByContactAndInbox(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewContactInboxRepo(db) svc := NewContactInboxService(repo) ci := &model.ContactInbox{ContactID: 1, InboxID: 1, SourceID: "src1"} require.NoError(t, db.Create(ci).Error) got, err := svc.GetByContactAndInbox(context.Background(), 1, 1) require.NoError(t, err) assert.Equal(t, "src1", got.SourceID) } func TestContactInboxService_ListByContact(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewContactInboxRepo(db) svc := NewContactInboxService(repo) require.NoError(t, db.Create(&model.ContactInbox{ContactID: 1, InboxID: 1, SourceID: "s1"}).Error) require.NoError(t, db.Create(&model.ContactInbox{ContactID: 1, InboxID: 2, SourceID: "s2"}).Error) list, err := svc.ListByContact(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 2) } func TestContactInboxService_Create(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewContactInboxRepo(db) svc := NewContactInboxService(repo) ci, err := svc.Create(context.Background(), CreateContactInboxRequest{ ContactID: 1, InboxID: 1, SourceID: "src1", }) require.NoError(t, err) assert.NotZero(t, ci.ID) } func TestContactInboxService_Delete(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewContactInboxRepo(db) svc := NewContactInboxService(repo) ci := &model.ContactInbox{ContactID: 1, InboxID: 1, SourceID: "src1"} require.NoError(t, db.Create(ci).Error) require.NoError(t, svc.Delete(context.Background(), ci.ID)) } // ============================================================ // InboxMemberService tests // ============================================================ func TestInboxMemberService_GetByID(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewInboxMemberRepo(db) svc := NewInboxMemberService(repo) im := &model.InboxMember{InboxID: 1, UserID: 1} require.NoError(t, db.Create(im).Error) got, err := svc.GetByID(context.Background(), im.ID) require.NoError(t, err) assert.Equal(t, uint(1), got.InboxID) } func TestInboxMemberService_GetByID_NotFound(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewInboxMemberRepo(db) svc := NewInboxMemberService(repo) _, err := svc.GetByID(context.Background(), 99999) require.Error(t, err) } func TestInboxMemberService_ListByInbox(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewInboxMemberRepo(db) svc := NewInboxMemberService(repo) require.NoError(t, db.Create(&model.InboxMember{InboxID: 1, UserID: 1}).Error) require.NoError(t, db.Create(&model.InboxMember{InboxID: 1, UserID: 2}).Error) list, err := svc.ListByInbox(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 2) } func TestInboxMemberService_ListByUser(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewInboxMemberRepo(db) svc := NewInboxMemberService(repo) require.NoError(t, db.Create(&model.InboxMember{InboxID: 1, UserID: 1}).Error) require.NoError(t, db.Create(&model.InboxMember{InboxID: 2, UserID: 1}).Error) list, err := svc.ListByUser(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 2) } func TestInboxMemberService_Add(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewInboxMemberRepo(db) svc := NewInboxMemberService(repo) _, err := svc.AddMember(context.Background(), AddMemberRequest{InboxID: 1, UserID: 1}) require.NoError(t, err) } func TestInboxMemberService_Remove(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewInboxMemberRepo(db) svc := NewInboxMemberService(repo) require.NoError(t, db.Create(&model.InboxMember{InboxID: 1, UserID: 1}).Error) require.NoError(t, svc.RemoveMember(context.Background(), 1, 1)) } func TestInboxMemberService_RemoveAll(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewInboxMemberRepo(db) svc := NewInboxMemberService(repo) require.NoError(t, db.Create(&model.InboxMember{InboxID: 1, UserID: 1}).Error) require.NoError(t, db.Create(&model.InboxMember{InboxID: 1, UserID: 2}).Error) require.NoError(t, svc.RemoveAllMembers(context.Background(), 1)) } // ============================================================ // WebhookSubscriptionService tests // ============================================================ func TestWebhookSubscriptionService_ListSubscriptions(t *testing.T) { db := newSimpleServiceTestDB(t) if err := db.AutoMigrate(&model.WebhookSubscription{}); err != nil { panic(err) } repo := repository.NewWebhookSubscriptionRepo(db) svc := NewWebhookSubscriptionService(repo) require.NoError(t, db.Create(&model.WebhookSubscription{AccountID: 1, URL: "http://example.com", Events: json.RawMessage(`["message_created"]`)}).Error) list, err := svc.ListSubscriptions(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 1) } func TestWebhookSubscriptionService_CreateSubscription(t *testing.T) { db := newSimpleServiceTestDB(t) if err := db.AutoMigrate(&model.WebhookSubscription{}); err != nil { panic(err) } repo := repository.NewWebhookSubscriptionRepo(db) svc := NewWebhookSubscriptionService(repo) sub, err := svc.CreateSubscription(context.Background(), 1, "http://example.com/webhook", []string{"message_created", "message_updated"}) require.NoError(t, err) assert.NotZero(t, sub.ID) assert.Equal(t, "http://example.com/webhook", sub.URL) } func TestWebhookSubscriptionService_DeleteSubscription(t *testing.T) { db := newSimpleServiceTestDB(t) if err := db.AutoMigrate(&model.WebhookSubscription{}); err != nil { panic(err) } repo := repository.NewWebhookSubscriptionRepo(db) svc := NewWebhookSubscriptionService(repo) sub := &model.WebhookSubscription{AccountID: 1, URL: "http://example.com", Events: json.RawMessage(`["message_created"]`)} require.NoError(t, db.Create(sub).Error) require.NoError(t, svc.DeleteSubscription(context.Background(), sub.ID)) } func TestWebhookSubscriptionService_UpdateSubscription(t *testing.T) { db := newSimpleServiceTestDB(t) if err := db.AutoMigrate(&model.WebhookSubscription{}); err != nil { panic(err) } repo := repository.NewWebhookSubscriptionRepo(db) svc := NewWebhookSubscriptionService(repo) sub := &model.WebhookSubscription{AccountID: 1, URL: "http://example.com", Events: json.RawMessage(`["message_created"]`)} require.NoError(t, db.Create(sub).Error) updated, err := svc.UpdateSubscription(context.Background(), sub.ID, "http://example.com/updated", []string{"message_created", "conversation_created"}, true) require.NoError(t, err) assert.Equal(t, "http://example.com/updated", updated.URL) } // ============================================================ // CategoryService tests // ============================================================ func newCategoryServiceDB(t *testing.T) *gorm.DB { db := newSimpleServiceTestDB(t) if err := db.AutoMigrate(&model.Category{}, &model.RelatedCategory{}); err != nil { panic(err) } return db } func TestCategoryService_Create_Cov5(t *testing.T) { db := newCategoryServiceDB(t) repo := repository.NewCategoryRepo(db) relatedRepo := repository.NewRelatedCategoryRepo(db) svc := NewCategoryService(repo, relatedRepo) cat, err := svc.Create(context.Background(), 1, 1, &CreateCategoryRequest{ Name: "TestCat", Description: "Test category", }) require.NoError(t, err) assert.Equal(t, "TestCat", cat.Name) } func TestCategoryService_GetByID_Cov5(t *testing.T) { db := newCategoryServiceDB(t) repo := repository.NewCategoryRepo(db) relatedRepo := repository.NewRelatedCategoryRepo(db) svc := NewCategoryService(repo, relatedRepo) c := &model.Category{PortalID: 1, AccountID: 1, Name: "C"} require.NoError(t, db.Create(c).Error) got, err := svc.GetByID(context.Background(), c.ID) require.NoError(t, err) assert.Equal(t, "C", got.Name) } func TestCategoryService_GetByID_NotFound_Cov5(t *testing.T) { db := newCategoryServiceDB(t) repo := repository.NewCategoryRepo(db) relatedRepo := repository.NewRelatedCategoryRepo(db) svc := NewCategoryService(repo, relatedRepo) _, err := svc.GetByID(context.Background(), 99999) require.Error(t, err) } func TestCategoryService_GetByPortalAndID(t *testing.T) { db := newCategoryServiceDB(t) repo := repository.NewCategoryRepo(db) relatedRepo := repository.NewRelatedCategoryRepo(db) svc := NewCategoryService(repo, relatedRepo) c := &model.Category{PortalID: 1, AccountID: 1, Name: "C"} require.NoError(t, db.Create(c).Error) got, err := svc.GetByPortalAndID(context.Background(), 1, c.ID) require.NoError(t, err) assert.Equal(t, "C", got.Name) } func TestCategoryService_Update_Cov5(t *testing.T) { db := newCategoryServiceDB(t) repo := repository.NewCategoryRepo(db) relatedRepo := repository.NewRelatedCategoryRepo(db) svc := NewCategoryService(repo, relatedRepo) c := &model.Category{PortalID: 1, AccountID: 1, Name: "Orig"} require.NoError(t, db.Create(c).Error) updated, err := svc.Update(context.Background(), c.ID, &UpdateCategoryRequest{ Name: strPtrVal("Updated"), Description: strPtrVal("New desc"), }) require.NoError(t, err) assert.Equal(t, "Updated", updated.Name) } func TestCategoryService_Delete_Cov5(t *testing.T) { db := newCategoryServiceDB(t) repo := repository.NewCategoryRepo(db) relatedRepo := repository.NewRelatedCategoryRepo(db) svc := NewCategoryService(repo, relatedRepo) c := &model.Category{PortalID: 1, AccountID: 1, Name: "Del"} require.NoError(t, db.Create(c).Error) require.NoError(t, svc.Delete(context.Background(), c.ID)) } func TestCategoryService_ListByPortal(t *testing.T) { db := newCategoryServiceDB(t) repo := repository.NewCategoryRepo(db) relatedRepo := repository.NewRelatedCategoryRepo(db) svc := NewCategoryService(repo, relatedRepo) require.NoError(t, db.Create(&model.Category{PortalID: 1, AccountID: 1, Name: "C1"}).Error) require.NoError(t, db.Create(&model.Category{PortalID: 1, AccountID: 1, Name: "C2"}).Error) list, total, err := svc.ListByPortalID(context.Background(), 1, "en", 1, 10) require.NoError(t, err) assert.Equal(t, int64(2), total) assert.Len(t, list, 2) } // ============================================================ // DraftMessageService tests // ============================================================ func newDraftMessageServiceDB(t *testing.T) *gorm.DB { db := newSimpleServiceTestDB(t) if err := db.AutoMigrate(&model.DraftMessage{}); err != nil { panic(err) } return db } func TestDraftMessageService_Ready(t *testing.T) { db := newDraftMessageServiceDB(t) repo := repository.NewDraftMessageRepo(db) convRepo := repository.NewConversationRepo(db) svc := NewDraftMessageService(repo, convRepo) assert.True(t, svc.Ready()) } func TestDraftMessageService_Set(t *testing.T) { db := newDraftMessageServiceDB(t) repo := repository.NewDraftMessageRepo(db) convRepo := repository.NewConversationRepo(db) svc := NewDraftMessageService(repo, convRepo) require.NoError(t, db.Create(&model.Conversation{AccountID: 1, Status: "open"}).Error) err := svc.SetConversationDraft(context.Background(), 1, 1, 1, "draft content") require.NoError(t, err) } func TestDraftMessageService_ShowConversationDraft(t *testing.T) { db := newDraftMessageServiceDB(t) repo := repository.NewDraftMessageRepo(db) convRepo := repository.NewConversationRepo(db) svc := NewDraftMessageService(repo, convRepo) require.NoError(t, db.Create(&model.Conversation{AccountID: 1, Status: "open"}).Error) require.NoError(t, svc.SetConversationDraft(context.Background(), 1, 1, 1, "draft content")) draft, err := svc.ShowConversationDraft(context.Background(), 1, 1) require.NoError(t, err) assert.Equal(t, "draft content", draft.Content) } func TestDraftMessageService_ShowConversationDraft_NotFound(t *testing.T) { db := newDraftMessageServiceDB(t) repo := repository.NewDraftMessageRepo(db) convRepo := repository.NewConversationRepo(db) svc := NewDraftMessageService(repo, convRepo) _, err := svc.ShowConversationDraft(context.Background(), 1, 99999) require.Error(t, err) } func TestDraftMessageService_Delete(t *testing.T) { db := newDraftMessageServiceDB(t) repo := repository.NewDraftMessageRepo(db) convRepo := repository.NewConversationRepo(db) svc := NewDraftMessageService(repo, convRepo) require.NoError(t, db.Create(&model.Conversation{AccountID: 1, Status: "open"}).Error) require.NoError(t, svc.SetConversationDraft(context.Background(), 1, 1, 1, "draft content")) require.NoError(t, svc.DeleteConversationDraft(context.Background(), 1, 1)) } func TestDraftMessageService_List(t *testing.T) { db := newDraftMessageServiceDB(t) repo := repository.NewDraftMessageRepo(db) convRepo := repository.NewConversationRepo(db) svc := NewDraftMessageService(repo, convRepo) require.NoError(t, db.Create(&model.Conversation{AccountID: 1, Status: "open"}).Error) require.NoError(t, svc.SetConversationDraft(context.Background(), 1, 1, 1, "draft1")) list, err := svc.List(context.Background(), 1, 1, 1) require.NoError(t, err) assert.Len(t, list, 1) } // ============================================================ // CaptainPreferenceService tests // ============================================================ func newCaptainPreferenceServiceDB(t *testing.T) *gorm.DB { db := newSimpleServiceTestDB(t) if err := db.AutoMigrate(&model.CaptainPreference{}); err != nil { panic(err) } return db } func TestCaptainPreferenceService_GetConfig(t *testing.T) { db := newCaptainPreferenceServiceDB(t) repo := repository.NewCaptainPreferenceRepo(db) accountRepo := repository.NewAccountRepo(db) svc := NewCaptainPreferenceService(repo, accountRepo) require.NoError(t, db.Create(&model.Account{Name: "TestAcc"}).Error) // Should return default config when no preference exists cfg, err := svc.GetConfig(context.Background(), 1) require.NoError(t, err) assert.NotNil(t, cfg) } func TestCaptainPreferenceService_UpdateConfig(t *testing.T) { db := newCaptainPreferenceServiceDB(t) repo := repository.NewCaptainPreferenceRepo(db) accountRepo := repository.NewAccountRepo(db) svc := NewCaptainPreferenceService(repo, accountRepo) require.NoError(t, db.Create(&model.Account{Name: "TestAcc"}).Error) cfg, err := svc.UpdateConfig(context.Background(), 1, &UpdateCaptainConfigRequest{ CaptainFeatures: map[string]bool{"captain_enabled": true}, }) require.NoError(t, err) assert.NotNil(t, cfg) } func TestCaptainPreferenceService_GetConfig_AfterUpdate(t *testing.T) { db := newCaptainPreferenceServiceDB(t) repo := repository.NewCaptainPreferenceRepo(db) accountRepo := repository.NewAccountRepo(db) svc := NewCaptainPreferenceService(repo, accountRepo) require.NoError(t, db.Create(&model.Account{Name: "TestAcc"}).Error) _, err := svc.UpdateConfig(context.Background(), 1, &UpdateCaptainConfigRequest{ CaptainFeatures: map[string]bool{"captain_enabled": true}, }) require.NoError(t, err) cfg, err := svc.GetConfig(context.Background(), 1) require.NoError(t, err) assert.NotNil(t, cfg) } // strPtr helper (boolPtr is defined in coverage_test.go) func strPtrVal(s string) *string { return &s }