chore: import clean Agent Desk snapshot (3/7)
This commit is contained in:
150
internal/services/conversation_satisfaction_service_test.go
Normal file
150
internal/services/conversation_satisfaction_service_test.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/openidentity"
|
||||
"agent-desk/internal/repositories"
|
||||
"testing"
|
||||
|
||||
"github.com/mlogclub/simple/sqls"
|
||||
)
|
||||
|
||||
func setupSatisfactionTest(t *testing.T) (*conversationService, *conversationSatisfactionService, openidentity.ExternalUser, int64) {
|
||||
t.Helper()
|
||||
convSvc, external, aiAgentID := setupCustomerConversationTest(t, 5)
|
||||
if err := sqls.DB().AutoMigrate(&models.ConversationSatisfaction{}); err != nil {
|
||||
t.Fatalf("auto migrate conversation satisfaction error = %v", err)
|
||||
}
|
||||
return convSvc, ConversationSatisfactionService, external, aiAgentID
|
||||
}
|
||||
|
||||
func TestSubmitSatisfaction(t *testing.T) {
|
||||
convSvc, csatSvc, external, aiAgentID := setupSatisfactionTest(t)
|
||||
|
||||
// Create conversation and close it
|
||||
conv, err := convSvc.CreateNew(external, 1, aiAgentID, "Need help with refund")
|
||||
if err != nil {
|
||||
t.Fatalf("CreateNew() error = %v", err)
|
||||
}
|
||||
if err := convSvc.CloseCustomerConversation(conv.ID, external); err != nil {
|
||||
t.Fatalf("CloseCustomerConversation() error = %v", err)
|
||||
}
|
||||
|
||||
t.Run("rejects invalid score", func(t *testing.T) {
|
||||
invalidScores := []int{0, -1, 6, 10}
|
||||
for _, score := range invalidScores {
|
||||
_, err := csatSvc.SubmitSatisfaction(conv.ID, external, score, "Bad score")
|
||||
if err == nil {
|
||||
t.Fatalf("SubmitSatisfaction() with score %d expected error, got nil", score)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("rejects if external user is not conversation owner", func(t *testing.T) {
|
||||
unauthorizedUser := openidentity.ExternalUser{
|
||||
ExternalSource: "user",
|
||||
ExternalID: "other_user",
|
||||
ExternalName: "Attacker",
|
||||
}
|
||||
_, err := csatSvc.SubmitSatisfaction(conv.ID, unauthorizedUser, 5, "Nice")
|
||||
if err == nil {
|
||||
t.Fatal("SubmitSatisfaction() with unauthorized user expected forbidden error, got nil")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("creates record when valid and closed", func(t *testing.T) {
|
||||
res, err := csatSvc.SubmitSatisfaction(conv.ID, external, 5, "Very helpful!")
|
||||
if err != nil {
|
||||
t.Fatalf("SubmitSatisfaction() error = %v", err)
|
||||
}
|
||||
if res == nil {
|
||||
t.Fatal("expected satisfaction record, got nil")
|
||||
}
|
||||
if res.ConversationID != conv.ID {
|
||||
t.Fatalf("ConversationID = %d, want %d", res.ConversationID, conv.ID)
|
||||
}
|
||||
if res.Score != 5 {
|
||||
t.Fatalf("Score = %d, want 5", res.Score)
|
||||
}
|
||||
if res.Feedback != "Very helpful!" {
|
||||
t.Fatalf("Feedback = %q, want %q", res.Feedback, "Very helpful!")
|
||||
}
|
||||
if res.CustomerID != conv.CustomerID {
|
||||
t.Fatalf("CustomerID = %d, want %d", res.CustomerID, conv.CustomerID)
|
||||
}
|
||||
if res.ChannelID != conv.ChannelID {
|
||||
t.Fatalf("ChannelID = %d, want %d", res.ChannelID, conv.ChannelID)
|
||||
}
|
||||
|
||||
// Verify retrieval
|
||||
fetched := csatSvc.GetByConversationID(conv.ID)
|
||||
if fetched == nil {
|
||||
t.Fatal("GetByConversationID() returned nil")
|
||||
}
|
||||
if fetched.ID != res.ID || fetched.Score != 5 {
|
||||
t.Fatalf("fetched record mismatch: %+v", fetched)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns existing record if already rated (idempotent)", func(t *testing.T) {
|
||||
initial := csatSvc.GetByConversationID(conv.ID)
|
||||
if initial == nil {
|
||||
t.Fatal("initial satisfaction record not found")
|
||||
}
|
||||
|
||||
updated, err := csatSvc.SubmitSatisfaction(conv.ID, external, 4, "Updated: Good overall")
|
||||
if err != nil {
|
||||
t.Fatalf("SubmitSatisfaction() update error = %v", err)
|
||||
}
|
||||
if updated.ID != initial.ID {
|
||||
t.Fatalf("expected updated record ID to be %d, got %d", initial.ID, updated.ID)
|
||||
}
|
||||
if updated.Score != 4 {
|
||||
t.Fatalf("Score = %d, want 4", updated.Score)
|
||||
}
|
||||
if updated.Feedback != "Updated: Good overall" {
|
||||
t.Fatalf("Feedback = %q, want %q", updated.Feedback, "Updated: Good overall")
|
||||
}
|
||||
|
||||
// Count should still be 1 for this conversation
|
||||
count := repositories.ConversationSatisfactionRepository.Count(sqls.DB(), "conversation_id = ?", conv.ID)
|
||||
if count != 1 {
|
||||
t.Fatalf("expected count = 1, got %d", count)
|
||||
}
|
||||
|
||||
// Average score should be 4.0
|
||||
avg := repositories.ConversationSatisfactionRepository.AverageScore(sqls.DB(), "conversation_id = ?", conv.ID)
|
||||
if avg != 4.0 {
|
||||
t.Fatalf("expected avg = 4.0, got %f", avg)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns error when conversation does not exist", func(t *testing.T) {
|
||||
_, err := csatSvc.SubmitSatisfaction(999999, external, 5, "Non-existent")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for non-existent conversation, got nil")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns nil for non-positive conversation ID in GetByConversationID", func(t *testing.T) {
|
||||
if got := csatSvc.GetByConversationID(0); got != nil {
|
||||
t.Fatalf("expected nil for conversationID 0, got %+v", got)
|
||||
}
|
||||
if got := csatSvc.GetByConversationID(-1); got != nil {
|
||||
t.Fatalf("expected nil for conversationID -1, got %+v", got)
|
||||
}
|
||||
if got := repositories.ConversationSatisfactionRepository.Get(sqls.DB(), 0); got != nil {
|
||||
t.Fatalf("expected nil for ID 0, got %+v", got)
|
||||
}
|
||||
if got := repositories.ConversationSatisfactionRepository.GetByConversationID(sqls.DB(), 0); got != nil {
|
||||
t.Fatalf("expected nil for conversationID 0, got %+v", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns zero average when no records match", func(t *testing.T) {
|
||||
avg := repositories.ConversationSatisfactionRepository.AverageScore(sqls.DB(), "conversation_id = ?", 888888)
|
||||
if avg != 0 {
|
||||
t.Fatalf("expected 0 average for unmatched condition, got %f", avg)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user