mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-06-29 15:31:05 +08:00
close #16132 ## Summary This PR completes the Go-side merge and cleanup for chat channel APIs, including handler/service wiring, route registration, and test coverage. Implemented and aligned 5 chat channel APIs: ``` - POST `/api/v1/chat-channels` - GET `/api/v1/chat-channels` - GET `/api/v1/chat-channels/:channel_id` - PATCH `/api/v1/chat-channels/:channel_id` - DELETE `/api/v1/chat-channels/:channel_id` ``` Co-authored-by: Haruko386 <tryeverypossible@163.com>
239 lines
6.3 KiB
Go
239 lines
6.3 KiB
Go
package service
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/glebarez/sqlite"
|
|
"gorm.io/gorm"
|
|
|
|
"ragflow/internal/common"
|
|
"ragflow/internal/dao"
|
|
"ragflow/internal/entity"
|
|
)
|
|
|
|
func setupChatChannelServiceTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
|
TranslateError: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to open sqlite: %v", err)
|
|
}
|
|
|
|
if err := db.AutoMigrate(&entity.ChatChannel{}, &entity.Chat{}, &entity.UserTenant{}); err != nil {
|
|
t.Fatalf("failed to migrate test schema: %v", err)
|
|
}
|
|
|
|
origDB := dao.DB
|
|
dao.DB = db
|
|
t.Cleanup(func() {
|
|
dao.DB = origDB
|
|
})
|
|
|
|
return db
|
|
}
|
|
|
|
func createServiceTestDialog(t *testing.T, db *gorm.DB, id, tenantID, name string) *entity.Chat {
|
|
t.Helper()
|
|
|
|
dialogName := name
|
|
dialog := &entity.Chat{
|
|
ID: id,
|
|
TenantID: tenantID,
|
|
Name: &dialogName,
|
|
LLMID: "model-a",
|
|
LLMSetting: entity.JSONMap{"temperature": 0.1},
|
|
PromptType: "simple",
|
|
PromptConfig: entity.JSONMap{"system": "sys"},
|
|
KBIDs: entity.JSONSlice{"kb-1"},
|
|
}
|
|
if err := db.Create(dialog).Error; err != nil {
|
|
t.Fatalf("failed to create dialog: %v", err)
|
|
}
|
|
return dialog
|
|
}
|
|
|
|
func createServiceTestChannel(t *testing.T, db *gorm.DB, channel *entity.ChatChannel) *entity.ChatChannel {
|
|
t.Helper()
|
|
|
|
if err := db.Create(channel).Error; err != nil {
|
|
t.Fatalf("failed to create chat channel: %v", err)
|
|
}
|
|
return channel
|
|
}
|
|
|
|
func createServiceTestMembership(t *testing.T, db *gorm.DB, userID, tenantID string) {
|
|
t.Helper()
|
|
|
|
status := "1"
|
|
member := &entity.UserTenant{
|
|
ID: userID + "_" + tenantID,
|
|
UserID: userID,
|
|
TenantID: tenantID,
|
|
Role: "normal",
|
|
Status: &status,
|
|
}
|
|
if err := db.Create(member).Error; err != nil {
|
|
t.Fatalf("failed to create tenant membership: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestChatChannelServiceCreateAndList(t *testing.T) {
|
|
db := setupChatChannelServiceTestDB(t)
|
|
createServiceTestDialog(t, db, "dialog-1", "tenant-1", "Assistant A")
|
|
|
|
svc := NewChatChannelService()
|
|
chatID := "dialog-1"
|
|
|
|
channel, err := svc.CreateChatChannel(
|
|
"tenant-1",
|
|
"bot-a",
|
|
"dingtalk",
|
|
entity.JSONMap{"token": "abc"},
|
|
&chatID,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("CreateChatChannel failed: %v", err)
|
|
}
|
|
if channel.ID == "" {
|
|
t.Fatal("expected generated id")
|
|
}
|
|
if channel.TenantID != "tenant-1" || channel.Name != "bot-a" || channel.Channel != "dingtalk" {
|
|
t.Fatalf("unexpected created channel: %+v", channel)
|
|
}
|
|
|
|
list, err := svc.List("tenant-1")
|
|
if err != nil {
|
|
t.Fatalf("List failed: %v", err)
|
|
}
|
|
if len(list) != 1 {
|
|
t.Fatalf("expected 1 channel, got %d", len(list))
|
|
}
|
|
if list[0].DialogName == nil || *list[0].DialogName != "Assistant A" {
|
|
t.Fatalf("expected joined dialog name, got %+v", list[0])
|
|
}
|
|
}
|
|
|
|
func TestChatChannelServiceGetChatChannelAllowsJoinedTenant(t *testing.T) {
|
|
db := setupChatChannelServiceTestDB(t)
|
|
createServiceTestChannel(t, db, &entity.ChatChannel{
|
|
ID: "cc-1",
|
|
TenantID: "tenant-1",
|
|
Name: "bot-a",
|
|
Channel: "wecom",
|
|
Config: entity.JSONMap{"token": "abc"},
|
|
Status: 1,
|
|
})
|
|
createServiceTestMembership(t, db, "user-2", "tenant-1")
|
|
|
|
channel, code, err := NewChatChannelService().GetChatChannel("user-2", "cc-1")
|
|
if err != nil {
|
|
t.Fatalf("GetChatChannel failed: %v", err)
|
|
}
|
|
if code != common.CodeSuccess {
|
|
t.Fatalf("expected success code, got %v", code)
|
|
}
|
|
if channel == nil || channel.ID != "cc-1" {
|
|
t.Fatalf("unexpected channel: %+v", channel)
|
|
}
|
|
}
|
|
|
|
func TestChatChannelServiceUpdateChatChannelSuccess(t *testing.T) {
|
|
db := setupChatChannelServiceTestDB(t)
|
|
createServiceTestDialog(t, db, "dialog-1", "tenant-1", "Assistant A")
|
|
createServiceTestDialog(t, db, "dialog-2", "tenant-1", "Assistant B")
|
|
chatID := "dialog-1"
|
|
createServiceTestChannel(t, db, &entity.ChatChannel{
|
|
ID: "cc-1",
|
|
TenantID: "tenant-1",
|
|
Name: "bot-a",
|
|
Channel: "wecom",
|
|
Config: entity.JSONMap{"token": "old"},
|
|
ChatID: &chatID,
|
|
Status: 1,
|
|
})
|
|
|
|
updated, code, err := NewChatChannelService().UpdateChatChannel("tenant-1", "cc-1", map[string]interface{}{
|
|
"name": "bot-b",
|
|
"config": map[string]interface{}{"token": "new"},
|
|
"chat_id": "dialog-2",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("UpdateChatChannel failed: %v", err)
|
|
}
|
|
if code != common.CodeSuccess {
|
|
t.Fatalf("expected success code, got %v", code)
|
|
}
|
|
if updated.Name != "bot-b" {
|
|
t.Fatalf("expected updated name, got %+v", updated)
|
|
}
|
|
if updated.ChatID == nil || *updated.ChatID != "dialog-2" {
|
|
t.Fatalf("expected updated chat_id, got %+v", updated.ChatID)
|
|
}
|
|
if updated.Config["token"] != "new" {
|
|
t.Fatalf("expected updated config, got %+v", updated.Config)
|
|
}
|
|
}
|
|
|
|
func TestChatChannelServiceUpdateChatChannelRejectsCrossTenantDialog(t *testing.T) {
|
|
db := setupChatChannelServiceTestDB(t)
|
|
createServiceTestDialog(t, db, "dialog-2", "tenant-2", "Assistant B")
|
|
createServiceTestChannel(t, db, &entity.ChatChannel{
|
|
ID: "cc-1",
|
|
TenantID: "tenant-1",
|
|
Name: "bot-a",
|
|
Channel: "wecom",
|
|
Config: entity.JSONMap{"token": "old"},
|
|
Status: 1,
|
|
})
|
|
|
|
_, code, err := NewChatChannelService().UpdateChatChannel("tenant-1", "cc-1", map[string]interface{}{
|
|
"chat_id": "dialog-2",
|
|
})
|
|
if code != common.CodeAuthenticationError {
|
|
t.Fatalf("expected authentication error, got %v", code)
|
|
}
|
|
if err == nil || !strings.Contains(err.Error(), "No authorization.") {
|
|
t.Fatalf("expected authorization error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestChatChannelServiceDeleteChatChannel(t *testing.T) {
|
|
db := setupChatChannelServiceTestDB(t)
|
|
createServiceTestChannel(t, db, &entity.ChatChannel{
|
|
ID: "cc-1",
|
|
TenantID: "tenant-1",
|
|
Name: "bot-a",
|
|
Channel: "wecom",
|
|
Config: entity.JSONMap{"token": "old"},
|
|
Status: 1,
|
|
})
|
|
|
|
svc := NewChatChannelService()
|
|
|
|
deleted, code, err := svc.DeleteChatChannel("user-2", "cc-1")
|
|
if code != common.CodeAuthenticationError {
|
|
t.Fatalf("expected authentication error, got %v", code)
|
|
}
|
|
if err == nil || !strings.Contains(err.Error(), "No authorization.") {
|
|
t.Fatalf("expected authorization error, got %v", err)
|
|
}
|
|
if deleted {
|
|
t.Fatal("expected delete to be rejected")
|
|
}
|
|
|
|
deleted, code, err = svc.DeleteChatChannel("tenant-1", "cc-1")
|
|
if err != nil {
|
|
t.Fatalf("DeleteChatChannel failed: %v", err)
|
|
}
|
|
if code != common.CodeSuccess || !deleted {
|
|
t.Fatalf("unexpected delete result: deleted=%v code=%v err=%v", deleted, code, err)
|
|
}
|
|
|
|
if _, err := svc.GetByID("cc-1"); err == nil {
|
|
t.Fatal("expected deleted record to be gone")
|
|
}
|
|
}
|