1:1
This commit is contained in:
@@ -31,9 +31,11 @@ import (
|
||||
type mockMsgHandlerLLMProvider struct {
|
||||
chatResponse *llm.ChatResponse
|
||||
chatError error
|
||||
chatCalls int
|
||||
}
|
||||
|
||||
func (m *mockMsgHandlerLLMProvider) ChatCompletion(ctx context.Context, req llm.ChatRequest) (*llm.ChatResponse, error) {
|
||||
m.chatCalls++
|
||||
if m.chatError != nil {
|
||||
return nil, m.chatError
|
||||
}
|
||||
@@ -152,8 +154,10 @@ func (s *MessageHandlerTestSuite) SetupTest() {
|
||||
s.Require().NoError(s.db.Create(contact).Error)
|
||||
s.testContact = contact
|
||||
|
||||
displayID := uint(4242)
|
||||
conv := &model.Conversation{
|
||||
AccountID: account.ID,
|
||||
DisplayID: &displayID,
|
||||
InboxID: inbox.ID,
|
||||
ContactID: contact.ID,
|
||||
Status: string(model.ConversationStatusOpen),
|
||||
@@ -185,6 +189,7 @@ func (s *MessageHandlerTestSuite) SetupTest() {
|
||||
},
|
||||
}
|
||||
s.mockLLM.chatError = nil
|
||||
s.mockLLM.chatCalls = 0
|
||||
}
|
||||
|
||||
func (s *MessageHandlerTestSuite) TearDownTest() {
|
||||
@@ -329,7 +334,38 @@ func (s *MessageHandlerTestSuite) TestCreate_Success() {
|
||||
assert.NotNil(s.T(), resp["id"])
|
||||
assert.Equal(s.T(), "New message", resp["content"])
|
||||
assert.Equal(s.T(), float64(1), resp["message_type"])
|
||||
assert.Equal(s.T(), float64(s.testConv.ID), resp["conversation_id"])
|
||||
assert.Equal(s.T(), float64(*s.testConv.DisplayID), resp["conversation_id"])
|
||||
}
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestCreate_UsesRouteConversationOverBodyConversationID() {
|
||||
otherConv := &model.Conversation{
|
||||
AccountID: s.testAccount.ID,
|
||||
InboxID: s.testInbox.ID,
|
||||
ContactID: s.testContact.ID,
|
||||
Status: string(model.ConversationStatusOpen),
|
||||
Priority: string(model.ConversationPriorityMedium),
|
||||
ChannelType: "web_widget",
|
||||
Channel: "web_widget",
|
||||
}
|
||||
s.Require().NoError(s.db.Create(otherConv).Error)
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"conversation_id": otherConv.ID,
|
||||
"content": "Route scoped message",
|
||||
"message_type": "outgoing",
|
||||
}
|
||||
body, _ := json.Marshal(payload)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
url := msgListURL(s.testAccount.ID, *s.testConv.DisplayID)
|
||||
req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
s.router.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(s.T(), http.StatusOK, w.Code)
|
||||
var created model.Message
|
||||
s.Require().NoError(s.db.Where("content = ?", "Route scoped message").First(&created).Error)
|
||||
assert.Equal(s.T(), s.testConv.ID, created.ConversationID)
|
||||
}
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestCreate_ChatwootFrontendPayloadDefaultsOutgoing() {
|
||||
@@ -424,7 +460,7 @@ func (s *MessageHandlerTestSuite) TestCreate_InvalidConversationID() {
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestGet_Success() {
|
||||
w := httptest.NewRecorder()
|
||||
url := msgDetailURL(s.testAccount.ID, s.testConv.ID, s.testMessage.ID)
|
||||
url := msgDetailURL(s.testAccount.ID, *s.testConv.DisplayID, s.testMessage.ID)
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
s.router.ServeHTTP(w, req)
|
||||
|
||||
@@ -433,6 +469,7 @@ func (s *MessageHandlerTestSuite) TestGet_Success() {
|
||||
json.Unmarshal(w.Body.Bytes(), &resp)
|
||||
assert.Equal(s.T(), float64(s.testMessage.ID), resp["id"])
|
||||
assert.Equal(s.T(), "Hello world", resp["content"])
|
||||
assert.Equal(s.T(), float64(*s.testConv.DisplayID), resp["conversation_id"])
|
||||
}
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestGet_NotFound() {
|
||||
@@ -455,13 +492,16 @@ func (s *MessageHandlerTestSuite) TestGet_InvalidID() {
|
||||
// --- Update Tests ---
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestUpdate_Success() {
|
||||
s.Require().NoError(s.db.Model(s.testInbox).Update("channel_type", "api").Error)
|
||||
s.testInbox.ChannelType = "api"
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"content": "Updated content",
|
||||
"status": "delivered",
|
||||
}
|
||||
body, _ := json.Marshal(payload)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
url := msgDetailURL(s.testAccount.ID, s.testConv.ID, s.testMessage.ID)
|
||||
url := msgDetailURL(s.testAccount.ID, *s.testConv.DisplayID, s.testMessage.ID)
|
||||
req, _ := http.NewRequest("PATCH", url, bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
s.router.ServeHTTP(w, req)
|
||||
@@ -469,7 +509,8 @@ func (s *MessageHandlerTestSuite) TestUpdate_Success() {
|
||||
assert.Equal(s.T(), http.StatusOK, w.Code)
|
||||
var resp map[string]interface{}
|
||||
json.Unmarshal(w.Body.Bytes(), &resp)
|
||||
assert.Equal(s.T(), "Updated content", resp["content"])
|
||||
assert.Equal(s.T(), "Hello world", resp["content"])
|
||||
assert.Equal(s.T(), "delivered", resp["status"])
|
||||
}
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestUpdate_StatusExternalError() {
|
||||
@@ -567,7 +608,7 @@ func (s *MessageHandlerTestSuite) TestRetry_Success() {
|
||||
}).Error)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
url := msgRetryURL(s.testAccount.ID, s.testConv.ID, s.testMessage.ID)
|
||||
url := msgRetryURL(s.testAccount.ID, *s.testConv.DisplayID, s.testMessage.ID)
|
||||
req, _ := http.NewRequest("POST", url, nil)
|
||||
s.router.ServeHTTP(w, req)
|
||||
|
||||
@@ -602,8 +643,8 @@ func (s *MessageHandlerTestSuite) TestRetry_NotFound() {
|
||||
req, _ := http.NewRequest("POST", url, nil)
|
||||
s.router.ServeHTTP(w, req)
|
||||
|
||||
// Service returns "not found" error → handleServiceError → 404
|
||||
assert.Equal(s.T(), http.StatusNotFound, w.Code)
|
||||
// Chatwoot retry rescues lookup/status-update failures as unprocessable entity.
|
||||
assert.Equal(s.T(), http.StatusUnprocessableEntity, w.Code)
|
||||
}
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestRetry_AccountMismatch() {
|
||||
@@ -617,8 +658,7 @@ func (s *MessageHandlerTestSuite) TestRetry_AccountMismatch() {
|
||||
req, _ := http.NewRequest("POST", url, nil)
|
||||
s.router.ServeHTTP(w, req)
|
||||
|
||||
// The service's FindByAccountAndID won't find the message under account 2 → "not found" → 404
|
||||
assert.Equal(s.T(), http.StatusNotFound, w.Code)
|
||||
assert.Equal(s.T(), http.StatusUnprocessableEntity, w.Code)
|
||||
}
|
||||
|
||||
// --- Translate Tests ---
|
||||
@@ -630,7 +670,7 @@ func (s *MessageHandlerTestSuite) TestTranslate_Success() {
|
||||
body, _ := json.Marshal(payload)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
url := msgTranslateURL(s.testAccount.ID, s.testConv.ID, s.testMessage.ID)
|
||||
url := msgTranslateURL(s.testAccount.ID, *s.testConv.DisplayID, s.testMessage.ID)
|
||||
req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
s.router.ServeHTTP(w, req)
|
||||
@@ -638,11 +678,7 @@ func (s *MessageHandlerTestSuite) TestTranslate_Success() {
|
||||
assert.Equal(s.T(), http.StatusOK, w.Code)
|
||||
var resp map[string]interface{}
|
||||
json.Unmarshal(w.Body.Bytes(), &resp)
|
||||
assert.True(s.T(), resp["success"].(bool))
|
||||
data := resp["data"].(map[string]interface{})
|
||||
assert.Equal(s.T(), "Bonjour le monde", data["translated_content"])
|
||||
assert.Equal(s.T(), "Hello world", data["original_content"])
|
||||
assert.Equal(s.T(), "fr", data["target_language"])
|
||||
assert.Equal(s.T(), "Bonjour le monde", resp["content"])
|
||||
}
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestTranslate_EmptyTargetLanguage() {
|
||||
@@ -756,10 +792,32 @@ func (s *MessageHandlerTestSuite) TestTranslate_EmptyChoices() {
|
||||
assert.Equal(s.T(), http.StatusOK, w.Code)
|
||||
var resp map[string]interface{}
|
||||
json.Unmarshal(w.Body.Bytes(), &resp)
|
||||
assert.True(s.T(), resp["success"].(bool))
|
||||
data := resp["data"].(map[string]interface{})
|
||||
assert.Equal(s.T(), "", data["translated_content"])
|
||||
assert.Equal(s.T(), "Hello world", data["original_content"])
|
||||
assert.Equal(s.T(), "", resp["content"])
|
||||
}
|
||||
|
||||
func (s *MessageHandlerTestSuite) TestTranslate_CachesSecondCall() {
|
||||
payload := map[string]interface{}{
|
||||
"target_language": "fr",
|
||||
}
|
||||
body, _ := json.Marshal(payload)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
url := msgTranslateURL(s.testAccount.ID, s.testConv.ID, s.testMessage.ID)
|
||||
req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
s.router.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(s.T(), http.StatusOK, w.Code)
|
||||
assert.Equal(s.T(), 1, s.mockLLM.chatCalls)
|
||||
|
||||
w2 := httptest.NewRecorder()
|
||||
req2, _ := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
req2.Header.Set("Content-Type", "application/json")
|
||||
s.router.ServeHTTP(w2, req2)
|
||||
|
||||
assert.Equal(s.T(), http.StatusOK, w2.Code)
|
||||
assert.Equal(s.T(), 1, s.mockLLM.chatCalls)
|
||||
assert.Empty(s.T(), w2.Body.String())
|
||||
}
|
||||
|
||||
// --- DirectUpload Handler Tests (upload_handler_test.go extension) ---
|
||||
|
||||
Reference in New Issue
Block a user