262 lines
8.9 KiB
Go
262 lines
8.9 KiB
Go
package v1
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
"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"
|
|
)
|
|
|
|
// --- ConversationParticipant Handler Test Suite ---
|
|
|
|
type ConversationParticipantHandlerTestSuite struct {
|
|
suite.Suite
|
|
router *gin.Engine
|
|
db *gorm.DB
|
|
testAccount *model.Account
|
|
testUser *model.User
|
|
testConv *model.Conversation
|
|
}
|
|
|
|
func (s *ConversationParticipantHandlerTestSuite) SetupSuite() {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
s.Require().NoError(err)
|
|
s.db = db
|
|
|
|
err = db.AutoMigrate(
|
|
&model.Account{},
|
|
&model.User{},
|
|
&model.Inbox{},
|
|
&model.Contact{},
|
|
&model.ContactInbox{},
|
|
&model.Conversation{},
|
|
&model.ConversationParticipant{},
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
// Create test account
|
|
account := &model.Account{Name: "ParticipantHandlerOrg", Locale: "en", Active: true}
|
|
s.Require().NoError(db.Create(account).Error)
|
|
s.testAccount = account
|
|
|
|
// Create test user
|
|
user := &model.User{Name: "ParticipantHandlerUser", Email: "participant-handler@test.com", Password: "hashed", Role: "agent", Active: true}
|
|
s.Require().NoError(db.Create(user).Error)
|
|
s.testUser = user
|
|
|
|
// Create inbox and contact
|
|
inbox := &model.Inbox{AccountID: account.ID, Name: "ParticipantHandlerInbox", ChannelType: "web_widget", ChannelID: 1}
|
|
s.Require().NoError(db.Create(inbox).Error)
|
|
|
|
contact := &model.Contact{AccountID: account.ID, Name: "ParticipantHandlerContact"}
|
|
s.Require().NoError(db.Create(contact).Error)
|
|
|
|
// Create conversation
|
|
conv := &model.Conversation{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", ChannelType: "web_widget", Channel: "web_widget"}
|
|
s.Require().NoError(db.Create(conv).Error)
|
|
s.testConv = conv
|
|
|
|
// Wire up repos, services, handlers
|
|
convRepo := repository.NewConversationRepo(db)
|
|
participantRepo := repository.NewConversationParticipantRepo(db)
|
|
participantSvc := service.NewConversationParticipantService(participantRepo, convRepo)
|
|
handler := NewConversationParticipantHandler(participantSvc)
|
|
|
|
// Setup router
|
|
r := gin.New()
|
|
s.router = r
|
|
|
|
// Register routes
|
|
accountGroup := r.Group("/api/v1/accounts/:account_id")
|
|
{
|
|
convGroup := accountGroup.Group("/conversations/:conversation_id")
|
|
{
|
|
participants := convGroup.Group("/participants")
|
|
{
|
|
participants.GET("", handler.List)
|
|
participants.POST("", handler.Add)
|
|
participants.PATCH("", handler.BatchUpdate)
|
|
participants.PATCH("/:user_id", handler.Update)
|
|
participants.DELETE("/:user_id", handler.Remove)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *ConversationParticipantHandlerTestSuite) Test_AddParticipant() {
|
|
body := map[string]interface{}{
|
|
"user_id": s.testUser.ID,
|
|
"role": "assignee",
|
|
}
|
|
b, _ := json.Marshal(body)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants", bytes.NewReader(b))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
|
|
var resp map[string]interface{}
|
|
json.Unmarshal(w.Body.Bytes(), &resp)
|
|
data, ok := resp["data"].([]interface{})
|
|
if ok && len(data) > 0 {
|
|
item := data[0].(map[string]interface{})
|
|
assert.Equal(s.T(), "assignee", item["role"])
|
|
}
|
|
}
|
|
|
|
func (s *ConversationParticipantHandlerTestSuite) Test_ListParticipants() {
|
|
// First add a participant
|
|
body := map[string]interface{}{
|
|
"user_id": s.testUser.ID,
|
|
"role": "participant",
|
|
}
|
|
b, _ := json.Marshal(body)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants", bytes.NewReader(b))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Now list
|
|
w = httptest.NewRecorder()
|
|
req, _ = http.NewRequest("GET", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants", nil)
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *ConversationParticipantHandlerTestSuite) Test_RemoveParticipant() {
|
|
// First add a participant
|
|
body := map[string]interface{}{
|
|
"user_id": s.testUser.ID,
|
|
"role": "participant",
|
|
}
|
|
b, _ := json.Marshal(body)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants", bytes.NewReader(b))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Now remove
|
|
w = httptest.NewRecorder()
|
|
req, _ = http.NewRequest("DELETE", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants/"+strconv.FormatUint(uint64(s.testUser.ID), 10), nil)
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *ConversationParticipantHandlerTestSuite) Test_UpdateParticipantRole() {
|
|
// First add a participant
|
|
body := map[string]interface{}{
|
|
"user_id": s.testUser.ID,
|
|
"role": "participant",
|
|
}
|
|
b, _ := json.Marshal(body)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants", bytes.NewReader(b))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
// Now update role
|
|
body = map[string]interface{}{
|
|
"role": "assignee",
|
|
}
|
|
b, _ = json.Marshal(body)
|
|
|
|
w = httptest.NewRecorder()
|
|
req, _ = http.NewRequest("PATCH", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants/"+strconv.FormatUint(uint64(s.testUser.ID), 10), bytes.NewReader(b))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *ConversationParticipantHandlerTestSuite) Test_AddParticipant_InvalidAccountID() {
|
|
body := map[string]interface{}{
|
|
"user_id": 1,
|
|
"role": "participant",
|
|
}
|
|
b, _ := json.Marshal(body)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/accounts/invalid/conversations/1/participants", bytes.NewReader(b))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(s.T(), http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// ========== BatchUpdate Handler Tests ==========
|
|
|
|
func (s *ConversationParticipantHandlerTestSuite) Test_BatchUpdate_AddAndRemove() {
|
|
// Create a second user for testing batch add/remove
|
|
user2 := &model.User{Name: "BatchUser2", Email: "batch2@test.com", Password: "hashed", Role: "agent", Active: true}
|
|
s.Require().NoError(s.db.Create(user2).Error)
|
|
|
|
// First add s.testUser as participant
|
|
addBody := map[string]interface{}{
|
|
"user_id": s.testUser.ID,
|
|
"role": "assignee",
|
|
}
|
|
addBytes, _ := json.Marshal(addBody)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("POST", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants", bytes.NewReader(addBytes))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
|
|
// Now batch update: add user2, remove s.testUser
|
|
batchBody := map[string]interface{}{
|
|
"user_ids": []uint{user2.ID},
|
|
"removed_user_ids": []uint{s.testUser.ID},
|
|
}
|
|
batchBytes, _ := json.Marshal(batchBody)
|
|
|
|
w = httptest.NewRecorder()
|
|
req, _ = http.NewRequest("PATCH", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccount.ID), 10)+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/participants", bytes.NewReader(batchBytes))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *ConversationParticipantHandlerTestSuite) Test_BatchUpdate_InvalidAccountID() {
|
|
batchBody := map[string]interface{}{
|
|
"user_ids": []uint{1},
|
|
}
|
|
batchBytes, _ := json.Marshal(batchBody)
|
|
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("PATCH", "/api/v1/accounts/invalid/conversations/1/participants", bytes.NewReader(batchBytes))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(s.T(), http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
func TestConversationParticipantHandlerTestSuite(t *testing.T) {
|
|
suite.Run(t, new(ConversationParticipantHandlerTestSuite))
|
|
}
|