192 lines
5.8 KiB
Go
192 lines
5.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/gochat/gochat/internal/llm"
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// --- Mock LLM Provider for bulk action tests ---
|
|
type mockBulkLLM struct {
|
|
response *llm.ChatResponse
|
|
err error
|
|
}
|
|
|
|
func (m *mockBulkLLM) ChatCompletion(_ context.Context, _ llm.ChatRequest) (*llm.ChatResponse, error) {
|
|
return m.response, m.err
|
|
}
|
|
func (m *mockBulkLLM) CreateEmbedding(_ context.Context, _ llm.EmbeddingRequest) (*llm.EmbeddingResponse, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockBulkLLM) ChatCompletionStream(_ context.Context, _ llm.ChatRequest, _ func(llm.StreamChunk) error) error {
|
|
return nil
|
|
}
|
|
|
|
func setupBulkActionTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
dbName := fmt.Sprintf("file:%s?mode=memory&cache=private", t.Name())
|
|
db, err := gorm.Open(sqlite.Open(dbName), &gorm.Config{})
|
|
require.NoError(t, err)
|
|
require.NoError(t, db.AutoMigrate(
|
|
&model.CaptainPreference{},
|
|
&model.CaptainAssistant{},
|
|
&model.Conversation{},
|
|
&model.Message{},
|
|
&model.Inbox{},
|
|
&model.Contact{},
|
|
&model.Account{},
|
|
))
|
|
return db
|
|
}
|
|
|
|
func setupBulkActionService(t *testing.T, mockLLM *mockBulkLLM) (*CaptainBulkActionService, *gorm.DB) {
|
|
t.Helper()
|
|
db := setupBulkActionTestDB(t)
|
|
convRepo := repository.NewConversationRepo(db)
|
|
msgRepo := repository.NewMessageRepo(db)
|
|
assistantRepo := repository.NewCaptainAssistantRepo(db)
|
|
prefRepo := repository.NewCaptainPreferenceRepo(db)
|
|
responseRepo := repository.NewCaptainAssistantResponseRepo(db)
|
|
taskSvc := NewCaptainTaskExtendedService(convRepo, msgRepo, assistantRepo, prefRepo, mockLLM)
|
|
responseSvc := NewCaptainAssistantResponseService(assistantRepo, responseRepo, convRepo, msgRepo, prefRepo, mockLLM)
|
|
svc := NewCaptainBulkActionService(convRepo, msgRepo, assistantRepo, prefRepo, mockLLM, taskSvc, responseSvc)
|
|
return svc, db
|
|
}
|
|
|
|
func seedBulkActionData(t *testing.T, db *gorm.DB, accountID uint) (*model.CaptainAssistant, []*model.Conversation) {
|
|
t.Helper()
|
|
inbox := &model.Inbox{AccountID: accountID, Name: "Support", ChannelType: "web_widget"}
|
|
require.NoError(t, db.Create(inbox).Error)
|
|
contact := &model.Contact{AccountID: accountID, Name: "Customer"}
|
|
require.NoError(t, db.Create(contact).Error)
|
|
|
|
cfg := &model.AssistantConfig{Instructions: "Be helpful", Temperature: 0.7}
|
|
cfgJSON, err := json.Marshal(cfg)
|
|
require.NoError(t, err)
|
|
assistant := &model.CaptainAssistant{
|
|
AccountID: accountID,
|
|
Name: "Bot",
|
|
Config: cfgJSON,
|
|
Status: model.AssistantStatusActive,
|
|
}
|
|
require.NoError(t, db.Create(assistant).Error)
|
|
|
|
var convs []*model.Conversation
|
|
for i := 0; i < 3; i++ {
|
|
conv := &model.Conversation{AccountID: accountID, InboxID: inbox.ID, Status: "open"}
|
|
require.NoError(t, db.Create(conv).Error)
|
|
msg := &model.Message{
|
|
ConversationID: conv.ID,
|
|
AccountID: accountID,
|
|
InboxID: inbox.ID,
|
|
SenderType: "contact",
|
|
Content: fmt.Sprintf("Help request %d", i),
|
|
ContentType: "text",
|
|
MessageType: "incoming",
|
|
}
|
|
require.NoError(t, db.Create(msg).Error)
|
|
convs = append(convs, conv)
|
|
}
|
|
return assistant, convs
|
|
}
|
|
|
|
func TestCaptainBulkActionService_Execute_LabelSuggestion(t *testing.T) {
|
|
mockLLM := &mockBulkLLM{
|
|
response: &llm.ChatResponse{
|
|
Choices: []llm.ChatChoice{
|
|
{Message: llm.ChatMessage{Role: "assistant", Content: `{"labels": ["support"], "priority": "medium", "reason": "routine"}`}},
|
|
},
|
|
},
|
|
}
|
|
svc, db := setupBulkActionService(t, mockLLM)
|
|
ctx := context.Background()
|
|
|
|
_, convs := seedBulkActionData(t, db, 1)
|
|
|
|
req := &BulkActionRequest{
|
|
Action: BulkActionLabelSuggestion,
|
|
ConversationIDs: []uint{convs[0].ID, convs[1].ID},
|
|
}
|
|
|
|
result, err := svc.Execute(ctx, 1, req)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, BulkActionLabelSuggestion, result.Action)
|
|
assert.Equal(t, 2, result.Processed)
|
|
assert.Len(t, result.Results, 2)
|
|
}
|
|
|
|
func TestCaptainBulkActionService_Execute_ReplySuggestion(t *testing.T) {
|
|
mockLLM := &mockBulkLLM{
|
|
response: &llm.ChatResponse{
|
|
Choices: []llm.ChatChoice{
|
|
{Message: llm.ChatMessage{Role: "assistant", Content: "Thank you for reaching out."}},
|
|
},
|
|
},
|
|
}
|
|
svc, db := setupBulkActionService(t, mockLLM)
|
|
ctx := context.Background()
|
|
|
|
assistant, convs := seedBulkActionData(t, db, 1)
|
|
|
|
req := &BulkActionRequest{
|
|
Action: BulkActionReplySuggestion,
|
|
ConversationIDs: []uint{convs[0].ID},
|
|
AssistantID: assistant.ID,
|
|
SendMessages: false,
|
|
}
|
|
|
|
result, err := svc.Execute(ctx, 1, req)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, BulkActionReplySuggestion, result.Action)
|
|
assert.Equal(t, 1, result.Processed)
|
|
assert.Equal(t, 0, result.Failed)
|
|
}
|
|
|
|
func TestCaptainBulkActionService_Execute_FollowUp(t *testing.T) {
|
|
mockLLM := &mockBulkLLM{
|
|
response: &llm.ChatResponse{
|
|
Choices: []llm.ChatChoice{
|
|
{Message: llm.ChatMessage{Role: "assistant", Content: `{"follow_ups": [{"title": "Follow up", "description": "Check back", "priority": "low"}]}`}},
|
|
},
|
|
},
|
|
}
|
|
svc, db := setupBulkActionService(t, mockLLM)
|
|
ctx := context.Background()
|
|
|
|
_, convs := seedBulkActionData(t, db, 1)
|
|
|
|
req := &BulkActionRequest{
|
|
Action: BulkActionFollowUp,
|
|
ConversationIDs: []uint{convs[0].ID},
|
|
}
|
|
|
|
result, err := svc.Execute(ctx, 1, req)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, BulkActionFollowUp, result.Action)
|
|
assert.Equal(t, 1, result.Processed)
|
|
}
|
|
|
|
func TestCaptainBulkActionService_Execute_UnsupportedAction(t *testing.T) {
|
|
mockLLM := &mockBulkLLM{}
|
|
svc, _ := setupBulkActionService(t, mockLLM)
|
|
ctx := context.Background()
|
|
|
|
req := &BulkActionRequest{
|
|
Action: "unknown_action",
|
|
ConversationIDs: []uint{1},
|
|
}
|
|
|
|
_, err := svc.Execute(ctx, 1, req)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "unsupported bulk action")
|
|
}
|