mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-20 06:31:02 +08:00
### Summary 1. list and get by id API for builtin DSL 2. add DSL default component param values validation 3. remove all hard code keys for parser config
208 lines
6.6 KiB
Go
208 lines
6.6 KiB
Go
//
|
|
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
package service
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"ragflow/internal/common"
|
|
"ragflow/internal/dao"
|
|
"ragflow/internal/entity"
|
|
)
|
|
|
|
// testDatasetCreateService builds a DatasetService for CreateDataset tests.
|
|
// CreateDataset resolves the tenant via d.tenantDAO, so it must be wired here
|
|
// (unlike the update path which does not touch it).
|
|
// insertCreateDatasetTenant seeds a tenant with status="1" (required by
|
|
// TenantDAO.GetByID, which CreateDataset calls) for the given tenant id.
|
|
func insertCreateDatasetTenant(t *testing.T, tenantID string) {
|
|
t.Helper()
|
|
var existing entity.Tenant
|
|
if err := dao.DB.Where("id = ?", tenantID).First(&existing).Error; err != nil {
|
|
tn := &entity.Tenant{
|
|
ID: tenantID,
|
|
LLMID: "llm-default",
|
|
EmbdID: "embd-default",
|
|
TenantEmbdID: sptr("embd-1"),
|
|
ASRID: "asr-default",
|
|
Status: sptr("1"),
|
|
}
|
|
if err := dao.DB.Create(tn).Error; err != nil {
|
|
t.Fatalf("insert test tenant: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testDatasetCreateService(t *testing.T) *DatasetService {
|
|
t.Helper()
|
|
|
|
return &DatasetService{
|
|
kbDAO: dao.NewKnowledgebaseDAO(),
|
|
documentDAO: dao.NewDocumentDAO(),
|
|
connectorDAO: dao.NewConnectorDAO(),
|
|
tenantDAO: dao.NewTenantDAO(),
|
|
}
|
|
}
|
|
|
|
func TestCreateDataset_NoComponentParams(t *testing.T) {
|
|
db := setupDatasetUpdateTestDB(t)
|
|
pushServiceDB(t, db)
|
|
insertCreateDatasetTenant(t, "tenant-1")
|
|
|
|
chunkMethod := "naive"
|
|
result, code, err := testDatasetCreateService(t).CreateDataset(&CreateDatasetRequest{
|
|
Name: "ds-no-cp",
|
|
ParserID: &chunkMethod,
|
|
}, "tenant-1")
|
|
if err != nil {
|
|
t.Fatalf("CreateDataset failed: %v", err)
|
|
}
|
|
if code != common.CodeSuccess {
|
|
t.Fatalf("expected success code, got %d", code)
|
|
}
|
|
if result["parser_id"] != strings.TrimSpace(chunkMethod) {
|
|
t.Fatalf("expected parser_id %q, got %#v", chunkMethod, result["parser_id"])
|
|
}
|
|
}
|
|
|
|
func TestCreateDataset_ComponentParamsPopulated(t *testing.T) {
|
|
db := setupDatasetUpdateTestDB(t)
|
|
pushServiceDB(t, db)
|
|
insertCreateDatasetTenant(t, "tenant-1")
|
|
|
|
chunkMethod := "naive"
|
|
result, code, err := testDatasetCreateService(t).CreateDataset(&CreateDatasetRequest{
|
|
Name: "ds-with-cp-defaults",
|
|
ParserID: &chunkMethod,
|
|
}, "tenant-1")
|
|
if err != nil {
|
|
t.Fatalf("CreateDataset failed: %v", err)
|
|
}
|
|
if code != common.CodeSuccess {
|
|
t.Fatalf("expected success code, got %d", code)
|
|
}
|
|
|
|
parserConfig, ok := result["parser_config"].(entity.JSONMap)
|
|
if !ok {
|
|
t.Fatalf("parser_config is not entity.JSONMap, got %T", result["parser_config"])
|
|
}
|
|
if len(parserConfig) == 0 {
|
|
t.Fatal("parser_config is empty, expected DSL component params defaults")
|
|
}
|
|
|
|
// Verify at least one component from the general/naive template has defaults.
|
|
// The general template has TokenChunker, Tokenizer, Parser, and File components.
|
|
found := false
|
|
for cpnID := range parserConfig {
|
|
if strings.Contains(cpnID, "TokenChunker") {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("parser_config does not contain any TokenChunker: %v", parserConfig)
|
|
}
|
|
}
|
|
|
|
func TestCreateDataset_ParseTypeBuiltinClearsPipelineID(t *testing.T) {
|
|
db := setupDatasetUpdateTestDB(t)
|
|
pushServiceDB(t, db)
|
|
insertCreateDatasetTenant(t, "tenant-1")
|
|
// Seed a canvas so it exists, but parse_type=1 should ignore it.
|
|
seedDatasetUpdateCanvas(t, "abcdef0123456789abcdef0123456789", "tenant-1",
|
|
datasetUpdateCanvasDSL("Parser:HipSignsRhyme", "chunk_token_num"))
|
|
|
|
chunkMethod := "naive"
|
|
pipelineID := "ABCDEF0123456789ABCDEF0123456789"
|
|
parseType := 1
|
|
|
|
result, code, err := testDatasetCreateService(t).CreateDataset(&CreateDatasetRequest{
|
|
Name: "ds-builtin-clears-pipeline",
|
|
ParserID: &chunkMethod,
|
|
PipelineID: &pipelineID,
|
|
ParseType: &parseType,
|
|
}, "tenant-1")
|
|
if err != nil {
|
|
t.Fatalf("CreateDataset failed: %v", err)
|
|
}
|
|
if code != common.CodeSuccess {
|
|
t.Fatalf("expected success code, got %d", code)
|
|
}
|
|
// parse_type=1 clears pipeline_id → only parser_id should be persisted.
|
|
if result["parser_id"] != chunkMethod {
|
|
t.Fatalf("expected parser_id %q, got %#v", chunkMethod, result["parser_id"])
|
|
}
|
|
if pid, ok := result["pipeline_id"]; ok && pid != nil && pid != "" {
|
|
t.Fatalf("expected pipeline_id to be cleared for BuiltIn mode, got %#v", pid)
|
|
}
|
|
}
|
|
|
|
func TestCreateDataset_ParseTypePipelineIgnoresParserID(t *testing.T) {
|
|
db := setupDatasetUpdateTestDB(t)
|
|
pushServiceDB(t, db)
|
|
insertCreateDatasetTenant(t, "tenant-1")
|
|
seedDatasetUpdateCanvas(t, "abcdef0123456789abcdef0123456789", "tenant-1",
|
|
datasetUpdateCanvasDSL("Parser:CustomP", "chunk_token_num"))
|
|
|
|
chunkMethod := "book"
|
|
pipelineID := "ABCDEF0123456789ABCDEF0123456789"
|
|
parseType := 2
|
|
|
|
result, code, err := testDatasetCreateService(t).CreateDataset(&CreateDatasetRequest{
|
|
Name: "ds-pipeline-ignores-parser",
|
|
ParserID: &chunkMethod,
|
|
PipelineID: &pipelineID,
|
|
ParseType: &parseType,
|
|
}, "tenant-1")
|
|
if err != nil {
|
|
t.Fatalf("CreateDataset failed: %v", err)
|
|
}
|
|
if code != common.CodeSuccess {
|
|
t.Fatalf("expected success code, got %d", code)
|
|
}
|
|
// parse_type=2 ignores parser_id → pipeline_id should be persisted;
|
|
// parser_id should fall back to the default ("naive") since it wasn't set.
|
|
if result["pipeline_id"] != strings.ToLower(pipelineID) {
|
|
t.Fatalf("expected pipeline_id %q, got %#v", strings.ToLower(pipelineID), result["pipeline_id"])
|
|
}
|
|
}
|
|
|
|
func TestCreateDataset_RejectsBothWithoutParseType(t *testing.T) {
|
|
db := setupDatasetUpdateTestDB(t)
|
|
pushServiceDB(t, db)
|
|
insertCreateDatasetTenant(t, "tenant-1")
|
|
|
|
chunkMethod := "naive"
|
|
pipelineID := "abcdef0123456789abcdef0123456789"
|
|
_, code, err := testDatasetCreateService(t).CreateDataset(&CreateDatasetRequest{
|
|
Name: "ds-both-no-parse-type",
|
|
ParserID: &chunkMethod,
|
|
PipelineID: &pipelineID,
|
|
// ParseType deliberately nil
|
|
}, "tenant-1")
|
|
if err == nil {
|
|
t.Fatal("expected mutual-exclusivity error when both set without parse_type")
|
|
}
|
|
if code != common.CodeDataError {
|
|
t.Fatalf("expected data error code, got %d", code)
|
|
}
|
|
if !strings.Contains(err.Error(), "mutually exclusive") {
|
|
t.Fatalf("expected error to mention 'mutually exclusive', got: %v", err)
|
|
}
|
|
}
|