Files
ragflow/internal/service/dataset_create_test.go
Jack 10c00a9614 Feat: add built in DSL file API (#17003)
### 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
2026-07-18 11:00:08 +08:00

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)
}
}