Files
ragflow/internal/ingestion/testutil/helpers.go
Jack 8ac80284c4 Feat: add embedding support (#16769)
### Summary

Feat: add embedding support
2026-07-09 16:24:39 +08:00

255 lines
7.3 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 testutil
import (
"fmt"
"strings"
"testing"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/entity"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// ──────────────────────────────────────────────────────────
// Simple Helper Functions
// ──────────────────────────────────────────────────────────
// StrPtr returns a pointer to the given string.
func StrPtr(s string) *string {
return &s
}
// ──────────────────────────────────────────────────────────
// Database Helpers
// ──────────────────────────────────────────────────────────
// SetupTestDB sets up an in-memory SQLite database for testing.
// It auto-migrates the given tables (or all common tables if none provided).
func SetupTestDB(t *testing.T, tables ...any) *gorm.DB {
t.Helper()
dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", strings.NewReplacer("/", "_", " ", "_").Replace(t.Name()))
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
sqlDB, err := db.DB()
if err != nil {
t.Fatalf("failed to get sql DB: %v", err)
}
sqlDB.SetMaxOpenConns(1)
if len(tables) == 0 {
tables = []any{
&entity.IngestionTask{},
&entity.IngestionTaskLog{},
&entity.Task{},
&entity.Document{},
&entity.Knowledgebase{},
&entity.Tenant{},
&entity.File{},
&entity.File2Document{},
}
}
if err := db.AutoMigrate(tables...); err != nil {
t.Fatalf("auto-migrate: %v", err)
}
return db
}
// ReplaceDBForTest replaces dao.DB with the given test database
// and returns a cleanup function to restore the original.
func ReplaceDBForTest(t *testing.T, db *gorm.DB) func() {
t.Helper()
origDB := dao.DB
dao.DB = db
return func() { dao.DB = origDB }
}
// ──────────────────────────────────────────────────────────
// Test Data Configuration (Options Pattern)
// ──────────────────────────────────────────────────────────
// TestDataOption configures the test data setup.
type TestDataOption func(*testDataConfig)
type testDataConfig struct {
tenantID string
kbID string
docID string
taskID string
pipelineID *string
docName string
docType string
}
// WithTenantID sets the tenant ID for test data.
func WithTenantID(id string) TestDataOption {
return func(c *testDataConfig) { c.tenantID = id }
}
// WithKBID sets the knowledgebase ID for test data.
func WithKBID(id string) TestDataOption {
return func(c *testDataConfig) { c.kbID = id }
}
// WithDocID sets the document ID for test data.
func WithDocID(id string) TestDataOption {
return func(c *testDataConfig) { c.docID = id }
}
// WithTaskID sets the task ID for test data.
func WithTaskID(id string) TestDataOption {
return func(c *testDataConfig) { c.taskID = id }
}
// WithPipelineID sets the pipeline ID for test data.
func WithPipelineID(id string) TestDataOption {
return func(c *testDataConfig) {
pid := id
c.pipelineID = &pid
}
}
// WithDocName sets the document name for test data.
func WithDocName(name string) TestDataOption {
return func(c *testDataConfig) { c.docName = name }
}
// WithDocType sets the document type for test data.
func WithDocType(docType string) TestDataOption {
return func(c *testDataConfig) { c.docType = docType }
}
// SeedTestData seeds the database with test data.
// Returns: tenantID, kbID, docID, taskID
func SeedTestData(t *testing.T, db *gorm.DB, opts ...TestDataOption) (string, string, string, string) {
t.Helper()
cfg := &testDataConfig{
tenantID: "tenant-1",
kbID: "kb-1",
docID: "doc-1",
taskID: "task-1",
docName: "test.pdf",
docType: "pdf",
}
for _, opt := range opts {
opt(cfg)
}
// Create Tenant
if err := db.Create(&entity.Tenant{
ID: cfg.tenantID,
LLMID: "gpt-4",
Status: StrPtr("1"),
}).Error; err != nil {
t.Fatalf("create tenant: %v", err)
}
// Create Knowledgebase
if err := db.Create(&entity.Knowledgebase{
ID: cfg.kbID,
TenantID: cfg.tenantID,
EmbdID: "embd-1",
Status: StrPtr("1"),
ParserConfig: entity.JSONMap{},
}).Error; err != nil {
t.Fatalf("create kb: %v", err)
}
// Create Document
doc := &entity.Document{
ID: cfg.docID,
KbID: cfg.kbID,
Name: &cfg.docName,
ParserID: "naive",
ParserConfig: entity.JSONMap{},
PipelineID: cfg.pipelineID,
Status: StrPtr("1"),
Type: cfg.docType,
}
loc := "doc_store/" + cfg.docID
doc.Location = &loc
if err := db.Create(doc).Error; err != nil {
t.Fatalf("create doc: %v", err)
}
// Create Task
if err := db.Create(&entity.Task{
ID: cfg.taskID,
DocID: cfg.docID,
TaskType: "dataflow",
FromPage: 0,
ToPage: 100000,
}).Error; err != nil {
t.Fatalf("create task: %v", err)
}
// Create IngestionTask
if err := db.Create(&entity.IngestionTask{
ID: cfg.taskID,
UserID: "u1",
DocumentID: cfg.docID,
DatasetID: cfg.kbID,
Status: common.RUNNING,
}).Error; err != nil {
t.Fatalf("create ingestion task: %v", err)
}
return cfg.tenantID, cfg.kbID, cfg.docID, cfg.taskID
}
// ──────────────────────────────────────────────────────────
// Test Entity Helpers
// ──────────────────────────────────────────────────────────
// TestTask creates a test IngestionTask.
func TestTask(docID string) *entity.IngestionTask {
return &entity.IngestionTask{
ID: "task-1",
DocumentID: docID,
DatasetID: "kb-1",
}
}
// TestDoc creates a test Document.
func TestDoc(id string, docType string, suffix string, kbID ...string) *entity.Document {
name := "test." + suffix
loc := "doc_store/" + id
kb := "kb-1"
if len(kbID) > 0 {
kb = kbID[0]
}
return &entity.Document{
ID: id,
KbID: kb,
Type: docType,
Suffix: suffix,
Name: &name,
Location: &loc,
ParserID: "naive",
}
}