Align GoChat with Chatwoot frontend contracts
This commit is contained in:
@@ -2,7 +2,9 @@ package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
@@ -15,6 +17,7 @@ import (
|
||||
"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"
|
||||
@@ -118,6 +121,96 @@ func TestInboxHandler_ChatwootSerializerParity(t *testing.T) {
|
||||
require.Equal(t, "Your inbox deletion request will be processed in some time.", inboxParityObject(t, destroy)["message"])
|
||||
}
|
||||
|
||||
func TestInboxHandler_HealthReturnsWhatsAppCloudRawPayload(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
db, err := gorm.Open(sqlite.Open("file:inbox_handler_health_parity?mode=memory&cache=shared"), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
sqlDB, dbErr := db.DB()
|
||||
if dbErr == nil {
|
||||
_ = sqlDB.Close()
|
||||
}
|
||||
})
|
||||
require.NoError(t, db.AutoMigrate(&model.Account{}, &model.Inbox{}, &channelmodel.ChannelWhatsApp{}))
|
||||
|
||||
account := &model.Account{Name: "Inbox Health", Locale: "en", Active: true}
|
||||
require.NoError(t, db.Create(account).Error)
|
||||
inbox := &model.Inbox{AccountID: account.ID, Name: "WhatsApp", ChannelType: "whatsapp", ChannelID: 1}
|
||||
require.NoError(t, db.Create(inbox).Error)
|
||||
channel := &channelmodel.ChannelWhatsApp{
|
||||
AccountID: account.ID,
|
||||
InboxID: inbox.ID,
|
||||
PhoneNumber: "+1555010000",
|
||||
PhoneNumberID: "phone-123",
|
||||
BusinessAccountID: "waba-456",
|
||||
AccessToken: "token-789",
|
||||
Provider: "whatsapp_cloud",
|
||||
}
|
||||
require.NoError(t, db.Create(channel).Error)
|
||||
|
||||
router := setupInboxParityRouterWithWhatsAppService(db, &fakeInboxHealthWhatsAppService{payload: map[string]interface{}{
|
||||
"id": "phone-123",
|
||||
"quality_rating": "GREEN",
|
||||
"expected_webhook_url": "https://app.test/webhooks/whatsapp/+1555010000",
|
||||
"business_id": "waba-456",
|
||||
}})
|
||||
|
||||
response := inboxParityRequest(t, router, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/inboxes/%d/health", account.ID, inbox.ID), nil)
|
||||
require.Equal(t, http.StatusOK, response.Code, response.Body.String())
|
||||
payload := inboxParityObject(t, response)
|
||||
require.Equal(t, "phone-123", payload["id"])
|
||||
require.Equal(t, "GREEN", payload["quality_rating"])
|
||||
require.Equal(t, "https://app.test/webhooks/whatsapp/+1555010000", payload["expected_webhook_url"])
|
||||
require.Equal(t, "waba-456", payload["business_id"])
|
||||
require.NotContains(t, payload, "success")
|
||||
require.NotContains(t, payload, "status")
|
||||
require.NotContains(t, payload, "healthy")
|
||||
}
|
||||
|
||||
func TestInboxHandler_HealthReturnsProviderFailureState(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
db, err := gorm.Open(sqlite.Open("file:inbox_handler_health_failure?mode=memory&cache=shared"), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
sqlDB, dbErr := db.DB()
|
||||
if dbErr == nil {
|
||||
_ = sqlDB.Close()
|
||||
}
|
||||
})
|
||||
require.NoError(t, db.AutoMigrate(&model.Account{}, &model.Inbox{}, &channelmodel.ChannelWhatsApp{}))
|
||||
|
||||
account := &model.Account{Name: "Inbox Health Failure", Locale: "en", Active: true}
|
||||
require.NoError(t, db.Create(account).Error)
|
||||
inbox := &model.Inbox{AccountID: account.ID, Name: "WhatsApp", ChannelType: "whatsapp", ChannelID: 1}
|
||||
require.NoError(t, db.Create(inbox).Error)
|
||||
wa := &channelmodel.ChannelWhatsApp{
|
||||
InboxID: inbox.ID,
|
||||
PhoneNumber: "+1555010001",
|
||||
PhoneNumberID: "phone-number-id",
|
||||
BusinessAccountID: "business-account-id",
|
||||
Provider: "whatsapp_cloud",
|
||||
AccessToken: "access-token",
|
||||
}
|
||||
require.NoError(t, db.Create(wa).Error)
|
||||
|
||||
router := setupInboxParityRouterWithWhatsAppService(db, &fakeInboxHealthWhatsAppService{err: errors.New("provider unavailable")})
|
||||
response := inboxParityRequest(t, router, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/inboxes/%d/health", account.ID, inbox.ID), nil)
|
||||
require.Equal(t, http.StatusInternalServerError, response.Code, response.Body.String())
|
||||
|
||||
var payload map[string]interface{}
|
||||
require.NoError(t, json.Unmarshal(response.Body.Bytes(), &payload))
|
||||
require.Equal(t, false, payload["success"])
|
||||
errorBody := payload["error"].(map[string]interface{})
|
||||
require.Equal(t, "INTERNAL_ERROR", errorBody["code"])
|
||||
require.Contains(t, errorBody["message"], "provider unavailable")
|
||||
}
|
||||
|
||||
func TestSerializeInboxIncludesTwitterTweetsEnabled(t *testing.T) {
|
||||
defaultInbox := &model.Inbox{AccountID: 1, Name: "Twitter", ChannelType: "Channel::TwitterProfile"}
|
||||
defaultPayload := serializeInbox(defaultInbox, nil, false)
|
||||
@@ -535,7 +628,11 @@ func TestInboxHandler_ChatwootChannelSpecificConfigDepth(t *testing.T) {
|
||||
}
|
||||
|
||||
func setupInboxParityRouter(db *gorm.DB) *gin.Engine {
|
||||
inboxSvc := service.NewInboxService(repository.NewInboxRepo(db), nil, nil, nil, nil, nil, nil)
|
||||
return setupInboxParityRouterWithWhatsAppService(db, nil)
|
||||
}
|
||||
|
||||
func setupInboxParityRouterWithWhatsAppService(db *gorm.DB, whatsappService service.WhatsAppChannelService) *gin.Engine {
|
||||
inboxSvc := service.NewInboxService(repository.NewInboxRepo(db), nil, nil, nil, nil, whatsappService, whatsappchannel.NewRepository(db))
|
||||
handler := NewInboxHandler(inboxSvc)
|
||||
router := gin.New()
|
||||
router.Use(func(c *gin.Context) {
|
||||
@@ -555,10 +652,39 @@ func setupInboxParityRouter(db *gorm.DB) *gin.Engine {
|
||||
inboxes.PATCH("/:inbox_id", handler.Update)
|
||||
inboxes.DELETE("/:inbox_id", handler.Delete)
|
||||
inboxes.DELETE("/:inbox_id/avatar", handler.DeleteAvatar)
|
||||
inboxes.GET("/:inbox_id/health", handler.Health)
|
||||
}
|
||||
return router
|
||||
}
|
||||
|
||||
type fakeInboxHealthWhatsAppService struct {
|
||||
payload map[string]interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
func (f *fakeInboxHealthWhatsAppService) FetchMessageTemplates(context.Context, *channelmodel.ChannelWhatsApp) ([]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakeInboxHealthWhatsAppService) FetchHealthStatus(context.Context, *channelmodel.ChannelWhatsApp) (map[string]interface{}, error) {
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
return f.payload, nil
|
||||
}
|
||||
|
||||
func (f *fakeInboxHealthWhatsAppService) SetupWebhook(context.Context, *channelmodel.ChannelWhatsApp, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeInboxHealthWhatsAppService) SetupWebhookFields(context.Context, *channelmodel.ChannelWhatsApp, string, []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeInboxHealthWhatsAppService) UpdateCallingStatus(context.Context, *channelmodel.ChannelWhatsApp, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func inboxParityRequest(t *testing.T, router *gin.Engine, method string, path string, body any) *httptest.ResponseRecorder {
|
||||
return inboxParityRequestWithRole(t, router, method, path, body, "")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user