528 lines
19 KiB
Go
528 lines
19 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
|
|
whatsappchannel "github.com/gochat/gochat/internal/channel/whatsapp"
|
|
"github.com/gochat/gochat/internal/model"
|
|
channelmodel "github.com/gochat/gochat/internal/model/channel"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
"github.com/gochat/gochat/internal/worker"
|
|
)
|
|
|
|
// ========== Test Setup ==========
|
|
|
|
// setupInboxServiceTest creates a test DB and InboxService using SQLite in-memory.
|
|
// WhatsApp-specific repos (whatsappService, whatsappRepo) are nil since we
|
|
// test the non-WhatsApp paths exclusively (web_widget, api channel types).
|
|
func setupInboxServiceTest(t *testing.T) (*InboxService, *gorm.DB) {
|
|
t.Helper()
|
|
|
|
db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
require.NoError(t, err, "failed to open SQLite test db")
|
|
|
|
require.NoError(t, db.AutoMigrate(
|
|
&model.Account{},
|
|
&model.AgentBot{},
|
|
&model.Inbox{},
|
|
&model.AgentBotInbox{},
|
|
&model.WebhookSubscription{},
|
|
&model.BackgroundJob{},
|
|
&channelmodel.ChannelWhatsApp{},
|
|
), "failed to auto-migrate")
|
|
|
|
t.Cleanup(func() {
|
|
sqlDB, _ := db.DB()
|
|
sqlDB.Close()
|
|
})
|
|
|
|
repo := repository.NewInboxRepo(db)
|
|
agentBotInboxRepo := repository.NewAgentBotInboxRepo(db)
|
|
agentBotRepo := repository.NewAgentBotRepo(db)
|
|
webhookSubRepo := repository.NewWebhookSubscriptionRepo(db)
|
|
|
|
waRepo := whatsappchannel.NewRepository(db)
|
|
svc := NewInboxService(repo, agentBotInboxRepo, agentBotRepo, nil, webhookSubRepo, nil, waRepo)
|
|
return svc, db
|
|
}
|
|
|
|
type fakeInboxWhatsAppService struct {
|
|
healthPayload map[string]interface{}
|
|
healthErr error
|
|
templates []interface{}
|
|
templateErr error
|
|
fetchCalls int
|
|
webhookURL string
|
|
webhookFields []string
|
|
webhookErr error
|
|
callingStatus string
|
|
callingErr error
|
|
}
|
|
|
|
func (f *fakeInboxWhatsAppService) FetchMessageTemplates(context.Context, *channelmodel.ChannelWhatsApp) ([]interface{}, error) {
|
|
f.fetchCalls++
|
|
if f.templateErr != nil {
|
|
return nil, f.templateErr
|
|
}
|
|
return f.templates, nil
|
|
}
|
|
|
|
func (f *fakeInboxWhatsAppService) FetchHealthStatus(_ context.Context, _ *channelmodel.ChannelWhatsApp) (map[string]interface{}, error) {
|
|
return f.healthPayload, f.healthErr
|
|
}
|
|
|
|
func (f *fakeInboxWhatsAppService) SetupWebhook(_ context.Context, _ *channelmodel.ChannelWhatsApp, webhookURL string) error {
|
|
f.webhookURL = webhookURL
|
|
return f.webhookErr
|
|
}
|
|
|
|
func (f *fakeInboxWhatsAppService) SetupWebhookFields(_ context.Context, _ *channelmodel.ChannelWhatsApp, webhookURL string, fields []string) error {
|
|
f.webhookURL = webhookURL
|
|
f.webhookFields = fields
|
|
return f.webhookErr
|
|
}
|
|
|
|
func (f *fakeInboxWhatsAppService) UpdateCallingStatus(_ context.Context, _ *channelmodel.ChannelWhatsApp, status string) error {
|
|
f.callingStatus = status
|
|
return f.callingErr
|
|
}
|
|
|
|
// createInboxTestPrereqs creates prerequisite Account and Inbox for service tests.
|
|
func createInboxTestPrereqs(t *testing.T, db *gorm.DB, channelType string) (*model.Account, *model.Inbox) {
|
|
t.Helper()
|
|
|
|
account := &model.Account{Name: "InboxSvcTestOrg", Locale: "en", Active: true}
|
|
require.NoError(t, db.Create(account).Error)
|
|
|
|
inbox := &model.Inbox{
|
|
AccountID: account.ID,
|
|
Name: fmt.Sprintf("SvcTest%s", channelType),
|
|
ChannelType: channelType,
|
|
ChannelID: 1,
|
|
}
|
|
require.NoError(t, db.Create(inbox).Error)
|
|
|
|
return account, inbox
|
|
}
|
|
|
|
func ptrUint(v uint) *uint { return &v }
|
|
|
|
func createWhatsAppInboxTestPrereqs(t *testing.T, db *gorm.DB, provider string) (*model.Account, *model.Inbox, *channelmodel.ChannelWhatsApp) {
|
|
t.Helper()
|
|
account, inbox := createInboxTestPrereqs(t, db, "whatsapp")
|
|
channel := &channelmodel.ChannelWhatsApp{
|
|
AccountID: account.ID,
|
|
InboxID: inbox.ID,
|
|
PhoneNumber: "+1555010000",
|
|
PhoneNumberID: "phone-123",
|
|
BusinessAccountID: "waba-456",
|
|
AccessToken: "token-789",
|
|
Provider: provider,
|
|
}
|
|
require.NoError(t, db.Create(channel).Error)
|
|
return account, inbox, channel
|
|
}
|
|
|
|
// createTestAgentBot creates an AgentBot for the given account.
|
|
func createTestAgentBot(t *testing.T, db *gorm.DB, accountID uint, suffix string) *model.AgentBot {
|
|
t.Helper()
|
|
|
|
bot := &model.AgentBot{
|
|
AccountID: &accountID,
|
|
Name: fmt.Sprintf("SvcBot-%s", suffix),
|
|
BotType: "default",
|
|
Secret: fmt.Sprintf("secret-svc-%s", suffix),
|
|
AccessToken: fmt.Sprintf("token-svc-%s", suffix),
|
|
}
|
|
require.NoError(t, db.Create(bot).Error)
|
|
return bot
|
|
}
|
|
|
|
func TestInboxService_Create_AllowsUnlimitedInboxLimit(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account := &model.Account{Name: "Unlimited Inboxes", Locale: "en", Active: true, InboxLimit: 0}
|
|
require.NoError(t, db.Create(account).Error)
|
|
require.NoError(t, db.Create(&model.Inbox{AccountID: account.ID, Name: "Existing", ChannelType: "api"}).Error)
|
|
|
|
inbox, err := svc.Create(context.Background(), account.ID, CreateInboxRequest{
|
|
Name: "New API",
|
|
ChannelType: "api",
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotZero(t, inbox.ID)
|
|
}
|
|
|
|
func TestInboxService_CreateRejectsAtAccountInboxLimit(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account := &model.Account{Name: "Limited Inboxes", Locale: "en", Active: true, InboxLimit: 1}
|
|
require.NoError(t, db.Create(account).Error)
|
|
require.NoError(t, db.Create(&model.Inbox{AccountID: account.ID, Name: "Existing", ChannelType: "api"}).Error)
|
|
|
|
inbox, err := svc.Create(context.Background(), account.ID, CreateInboxRequest{
|
|
Name: "Blocked API",
|
|
ChannelType: "api",
|
|
})
|
|
|
|
require.ErrorIs(t, err, ErrInboxLimitExceeded)
|
|
require.Nil(t, inbox)
|
|
var count int64
|
|
require.NoError(t, db.Model(&model.Inbox{}).Where("account_id = ?", account.ID).Count(&count).Error)
|
|
assert.Equal(t, int64(1), count)
|
|
}
|
|
|
|
func TestInboxService_CreateAllowsBelowAccountInboxLimit(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account := &model.Account{Name: "Below Limit", Locale: "en", Active: true, InboxLimit: 2}
|
|
require.NoError(t, db.Create(account).Error)
|
|
require.NoError(t, db.Create(&model.Inbox{AccountID: account.ID, Name: "Existing", ChannelType: "api"}).Error)
|
|
|
|
inbox, err := svc.Create(context.Background(), account.ID, CreateInboxRequest{
|
|
Name: "Allowed API",
|
|
ChannelType: "api",
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.NotZero(t, inbox.ID)
|
|
var count int64
|
|
require.NoError(t, db.Model(&model.Inbox{}).Where("account_id = ?", account.ID).Count(&count).Error)
|
|
assert.Equal(t, int64(2), count)
|
|
}
|
|
|
|
// ========================================
|
|
// SetAgentBot service tests
|
|
// ========================================
|
|
|
|
func TestInboxService_SetAgentBot_AssignBot(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox := createInboxTestPrereqs(t, db, "web_widget")
|
|
bot := createTestAgentBot(t, db, account.ID, "assign")
|
|
|
|
binding, err := svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{
|
|
AgentBotID: ptrUint(bot.ID),
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, binding)
|
|
assert.Equal(t, bot.ID, binding.AgentBotID)
|
|
assert.Equal(t, inbox.ID, binding.InboxID)
|
|
assert.Equal(t, model.AgentBotInboxActive, binding.Status)
|
|
}
|
|
|
|
func TestInboxService_SetAgentBot_RemoveBot(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox := createInboxTestPrereqs(t, db, "web_widget")
|
|
bot := createTestAgentBot(t, db, account.ID, "remove")
|
|
|
|
// First assign a bot
|
|
binding, err := svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{
|
|
AgentBotID: ptrUint(bot.ID),
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, binding)
|
|
|
|
// Now remove it (missing/null agent_bot)
|
|
result, err := svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{})
|
|
require.NoError(t, err)
|
|
assert.Nil(t, result, "removing bot should return nil binding")
|
|
|
|
bindings, err := repository.NewAgentBotInboxRepo(db).FindByInboxID(context.Background(), inbox.ID)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, bindings, "Chatwoot destroys the agent_bot_inbox row on disconnect")
|
|
}
|
|
|
|
func TestInboxService_SetAgentBot_InboxNotFound(t *testing.T) {
|
|
svc, _ := setupInboxServiceTest(t)
|
|
|
|
binding, err := svc.SetAgentBot(context.Background(), 9999, 9999, SetAgentBotRequest{
|
|
AgentBotID: ptrUint(1),
|
|
})
|
|
assert.Error(t, err)
|
|
assert.Nil(t, binding)
|
|
assert.Contains(t, err.Error(), "inbox not found")
|
|
}
|
|
|
|
func TestInboxService_SetAgentBot_BotNotFound(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox := createInboxTestPrereqs(t, db, "web_widget")
|
|
|
|
binding, err := svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{
|
|
AgentBotID: ptrUint(9999),
|
|
})
|
|
assert.Error(t, err)
|
|
assert.Nil(t, binding)
|
|
assert.Contains(t, err.Error(), "agent bot not found")
|
|
}
|
|
|
|
func TestInboxService_SetAgentBot_ReassignBot(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox := createInboxTestPrereqs(t, db, "web_widget")
|
|
bot1 := createTestAgentBot(t, db, account.ID, "first")
|
|
bot2 := createTestAgentBot(t, db, account.ID, "second")
|
|
|
|
// Assign first bot
|
|
binding1, err := svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{
|
|
AgentBotID: ptrUint(bot1.ID),
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, bot1.ID, binding1.AgentBotID)
|
|
|
|
// Reassign to second bot — Chatwoot updates the inbox's single has_one binding.
|
|
binding2, err := svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{
|
|
AgentBotID: ptrUint(bot2.ID),
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, bot2.ID, binding2.AgentBotID)
|
|
assert.Equal(t, model.AgentBotInboxActive, binding2.Status)
|
|
assert.Equal(t, binding1.ID, binding2.ID)
|
|
}
|
|
|
|
func TestInboxService_SetAgentBot_RecreatesBindingAfterDisconnect(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox := createInboxTestPrereqs(t, db, "web_widget")
|
|
bot := createTestAgentBot(t, db, account.ID, "recreate")
|
|
|
|
// Assign bot
|
|
_, err := svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{
|
|
AgentBotID: ptrUint(bot.ID),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Remove bot (destroy binding)
|
|
_, err = svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{})
|
|
require.NoError(t, err)
|
|
|
|
// Re-assign same bot — should create a fresh binding.
|
|
binding2, err := svc.SetAgentBot(context.Background(), account.ID, inbox.ID, SetAgentBotRequest{
|
|
AgentBotID: ptrUint(bot.ID),
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, binding2)
|
|
assert.Equal(t, bot.ID, binding2.AgentBotID)
|
|
assert.Equal(t, model.AgentBotInboxActive, binding2.Status)
|
|
}
|
|
|
|
// ========================================
|
|
// Health service tests
|
|
// ========================================
|
|
|
|
func TestInboxService_Health_NonWhatsAppInboxRejected(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox := createInboxTestPrereqs(t, db, "api")
|
|
|
|
result, err := svc.Health(context.Background(), account.ID, inbox.ID)
|
|
require.ErrorIs(t, err, ErrInboxHealthWhatsAppCloudOnly)
|
|
assert.Nil(t, result)
|
|
}
|
|
|
|
func TestInboxService_Health_WhatsAppCloudReturnsPayload(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, _ := createWhatsAppInboxTestPrereqs(t, db, "whatsapp_cloud")
|
|
svc.whatsappService = &fakeInboxWhatsAppService{healthPayload: map[string]interface{}{
|
|
"id": "phone-123",
|
|
"quality_rating": "GREEN",
|
|
"expected_webhook_url": "https://app.test/webhooks/whatsapp/+1555010000",
|
|
"business_id": "waba-456",
|
|
}}
|
|
|
|
result, err := svc.Health(context.Background(), account.ID, inbox.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "phone-123", result["id"])
|
|
assert.Equal(t, "GREEN", result["quality_rating"])
|
|
assert.NotContains(t, result, "healthy")
|
|
assert.NotContains(t, result, "status")
|
|
}
|
|
|
|
func TestInboxService_Health_NonCloudWhatsAppRejected(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, _ := createWhatsAppInboxTestPrereqs(t, db, "360dialog")
|
|
svc.whatsappService = &fakeInboxWhatsAppService{}
|
|
|
|
result, err := svc.Health(context.Background(), account.ID, inbox.ID)
|
|
require.ErrorIs(t, err, ErrInboxHealthWhatsAppCloudOnly)
|
|
assert.Nil(t, result)
|
|
}
|
|
|
|
func TestInboxService_Health_InboxNotFound(t *testing.T) {
|
|
svc, _ := setupInboxServiceTest(t)
|
|
|
|
result, err := svc.Health(context.Background(), 9999, 9999)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Contains(t, err.Error(), "inbox not found")
|
|
}
|
|
|
|
// ========================================
|
|
// SyncTemplates service tests
|
|
// ========================================
|
|
|
|
func TestInboxService_SyncTemplates_NonWhatsAppInbox(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox := createInboxTestPrereqs(t, db, "api")
|
|
|
|
err := svc.SyncTemplates(context.Background(), account.ID, inbox.ID)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "Template sync is only available for WhatsApp channels")
|
|
}
|
|
|
|
func TestInboxService_SyncTemplates_InboxNotFound(t *testing.T) {
|
|
svc, _ := setupInboxServiceTest(t)
|
|
|
|
err := svc.SyncTemplates(context.Background(), 9999, 9999)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "inbox not found")
|
|
}
|
|
|
|
func TestInboxService_SyncTemplates_WhatsAppQueuesWorkerJob(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, channel := createWhatsAppInboxTestPrereqs(t, db, "whatsapp_cloud")
|
|
wp := worker.NewWorkerPool(db)
|
|
svc.SetWorkerPool(wp)
|
|
svc.whatsappService = &fakeInboxWhatsAppService{}
|
|
|
|
err := svc.SyncTemplates(context.Background(), account.ID, inbox.ID)
|
|
require.NoError(t, err)
|
|
|
|
var job model.BackgroundJob
|
|
require.NoError(t, db.Where("job_type = ? AND queue = ?", TaskTypeInboxSyncTemplates, "low").First(&job).Error)
|
|
var payload inboxTemplateSyncJob
|
|
require.NoError(t, json.Unmarshal(job.Payload, &payload))
|
|
assert.Equal(t, account.ID, payload.AccountID)
|
|
assert.Equal(t, inbox.ID, payload.InboxID)
|
|
assert.Equal(t, channel.ID, payload.ChannelID)
|
|
}
|
|
|
|
func TestInboxService_SyncTemplatesWorkerFetchesTemplates(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, _ := createWhatsAppInboxTestPrereqs(t, db, "whatsapp_cloud")
|
|
fake := &fakeInboxWhatsAppService{templates: []interface{}{map[string]interface{}{"name": "hello_world"}}}
|
|
svc.whatsappService = fake
|
|
wp := worker.NewWorkerPool(db)
|
|
svc.SetWorkerPool(wp)
|
|
RegisterInboxTemplateSyncJobs(wp, svc)
|
|
|
|
require.NoError(t, svc.SyncTemplates(context.Background(), account.ID, inbox.ID))
|
|
processed, err := wp.ProcessOne(context.Background())
|
|
require.NoError(t, err)
|
|
assert.True(t, processed)
|
|
assert.Equal(t, 1, fake.fetchCalls)
|
|
}
|
|
|
|
// ========================================
|
|
// RegisterWebhook service tests
|
|
// ========================================
|
|
|
|
func TestInboxService_RegisterWebhook_NonWhatsAppInboxRejected(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox := createInboxTestPrereqs(t, db, "web_widget")
|
|
|
|
err := svc.RegisterWebhook(context.Background(), account.ID, inbox.ID, RegisterWebhookRequest{
|
|
URL: "https://example.com/webhook",
|
|
})
|
|
require.ErrorIs(t, err, ErrInboxHealthWhatsAppCloudOnly)
|
|
}
|
|
|
|
func TestInboxService_RegisterWebhook_InboxNotFound(t *testing.T) {
|
|
svc, _ := setupInboxServiceTest(t)
|
|
|
|
err := svc.RegisterWebhook(context.Background(), 9999, 9999, RegisterWebhookRequest{
|
|
URL: "https://example.com/webhook",
|
|
})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "inbox not found")
|
|
}
|
|
|
|
func TestInboxService_RegisterWebhook_WhatsAppCloudUsesExpectedCallbackURL(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, _ := createWhatsAppInboxTestPrereqs(t, db, "whatsapp_cloud")
|
|
fake := &fakeInboxWhatsAppService{}
|
|
svc.whatsappService = fake
|
|
t.Setenv("FRONTEND_URL", "https://app.example.com/")
|
|
|
|
err := svc.RegisterWebhook(context.Background(), account.ID, inbox.ID, RegisterWebhookRequest{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "https://app.example.com/webhooks/whatsapp/+1555010000", fake.webhookURL)
|
|
}
|
|
|
|
func TestInboxService_RegisterWebhook_NonCloudWhatsAppRejected(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, _ := createWhatsAppInboxTestPrereqs(t, db, "360dialog")
|
|
svc.whatsappService = &fakeInboxWhatsAppService{}
|
|
|
|
err := svc.RegisterWebhook(context.Background(), account.ID, inbox.ID, RegisterWebhookRequest{})
|
|
require.ErrorIs(t, err, ErrInboxHealthWhatsAppCloudOnly)
|
|
}
|
|
|
|
// ========================================
|
|
// WhatsApp calling service tests
|
|
// ========================================
|
|
|
|
func TestInboxService_EnableWhatsAppCalling_SetsProviderConfigAndWebhook(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, channel := createWhatsAppInboxTestPrereqs(t, db, "whatsapp_cloud")
|
|
account.FeatureFlags = `{"channel_voice":true}`
|
|
require.NoError(t, db.Save(account).Error)
|
|
fake := &fakeInboxWhatsAppService{}
|
|
svc.whatsappService = fake
|
|
t.Setenv("FRONTEND_URL", "https://app.example.test")
|
|
|
|
err := svc.EnableWhatsAppCalling(context.Background(), account.ID, inbox.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "ENABLED", fake.callingStatus)
|
|
assert.Equal(t, "https://app.example.test/webhooks/whatsapp/+1555010000", fake.webhookURL)
|
|
assert.Empty(t, fake.webhookFields)
|
|
|
|
var updated channelmodel.ChannelWhatsApp
|
|
require.NoError(t, db.First(&updated, channel.ID).Error)
|
|
providerConfig := parseJSONMap(updated.ProviderConfig)
|
|
assert.Equal(t, true, providerConfig["calling_enabled"])
|
|
|
|
var updatedInbox model.Inbox
|
|
require.NoError(t, db.First(&updatedInbox, inbox.ID).Error)
|
|
channelConfig := parseJSONMap(updatedInbox.ChannelConfig)
|
|
assert.Equal(t, true, channelConfig["voice_enabled"])
|
|
}
|
|
|
|
func TestInboxService_EnableWhatsAppCalling_RequiresCloudAndFeature(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, _ := createWhatsAppInboxTestPrereqs(t, db, "360dialog")
|
|
account.FeatureFlags = `{"channel_voice":true}`
|
|
require.NoError(t, db.Save(account).Error)
|
|
svc.whatsappService = &fakeInboxWhatsAppService{}
|
|
|
|
err := svc.EnableWhatsAppCalling(context.Background(), account.ID, inbox.ID)
|
|
require.ErrorIs(t, err, ErrInboxWhatsAppCallingUnsupported)
|
|
|
|
account, inbox, _ = createWhatsAppInboxTestPrereqs(t, db, "whatsapp_cloud")
|
|
err = svc.EnableWhatsAppCalling(context.Background(), account.ID, inbox.ID)
|
|
require.ErrorIs(t, err, ErrInboxWhatsAppCallingFeatureRequired)
|
|
}
|
|
|
|
func TestInboxService_DisableWhatsAppCalling_PersistsFalseAndIgnoresWebhookFailure(t *testing.T) {
|
|
svc, db := setupInboxServiceTest(t)
|
|
account, inbox, channel := createWhatsAppInboxTestPrereqs(t, db, "whatsapp_cloud")
|
|
channel.ProviderConfig = `{"calling_enabled":true,"phone_number_id":"phone-1","business_account_id":"waba-1"}`
|
|
require.NoError(t, db.Save(channel).Error)
|
|
fake := &fakeInboxWhatsAppService{webhookErr: fmt.Errorf("meta unavailable")}
|
|
svc.whatsappService = fake
|
|
t.Setenv("FRONTEND_URL", "https://app.example.test")
|
|
|
|
err := svc.DisableWhatsAppCalling(context.Background(), account.ID, inbox.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []string{"messages", "smb_message_echoes"}, fake.webhookFields)
|
|
|
|
var updated channelmodel.ChannelWhatsApp
|
|
require.NoError(t, db.First(&updated, channel.ID).Error)
|
|
providerConfig := parseJSONMap(updated.ProviderConfig)
|
|
assert.Equal(t, false, providerConfig["calling_enabled"])
|
|
}
|