🌐 chore: translate non-English comments to English in database-tests (#13771)

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
LobeHub Bot 2026-04-13 16:14:09 +08:00 committed by GitHub
parent f0f2feb015
commit 012214205e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 250 additions and 250 deletions

View file

@ -69,17 +69,17 @@ describe('ChunkModel', () => {
expect(createdChunks[1]).toMatchObject(params[1]);
});
// 测试空参数场景
// Test empty params scenario
it('should handle empty params array', async () => {
const result = await chunkModel.bulkCreate([], '1');
expect(result).toHaveLength(0);
});
// 测试事务回滚
// Test transaction rollback
it('should rollback transaction on error', async () => {
const invalidParams = [
{ text: 'Chunk 1', userId },
{ index: 'abc', userId }, // 这会导致错误
{ index: 'abc', userId }, // This will cause an error
] as any;
await expect(chunkModel.bulkCreate(invalidParams, '1')).rejects.toThrow();
@ -203,7 +203,7 @@ describe('ChunkModel', () => {
expect(result[1].id).toBe(chunk2.id);
expect(result[0].similarity).toBeGreaterThan(result[1].similarity);
});
// 补充无文件 ID 的搜索场景
// Additional search scenario without file ID
it('should perform semantic search without fileIds', async () => {
const [chunk1, chunk2] = await serverDB
.insert(chunks)
@ -228,7 +228,7 @@ describe('ChunkModel', () => {
expect(result).toHaveLength(2);
});
// 测试空结果场景
// Test empty result scenario
it('should return empty array when no matches found', async () => {
const result = await chunkModel.semanticSearch({
embedding: designThinkingQuery,
@ -524,7 +524,7 @@ content in Table html is below:
});
describe('semanticSearchForChat', () => {
// 测试空文件 ID 列表场景
// Test empty file ID list scenario
it('should return empty array when fileIds is empty', async () => {
const result = await chunkModel.semanticSearchForChat({
embedding: designThinkingQuery,
@ -535,7 +535,7 @@ content in Table html is below:
expect(result).toHaveLength(0);
});
// 测试结果限制
// Test result limit
it('should limit results to 15 items', async () => {
const fileId = '1';
// Create 24 chunks

View file

@ -631,7 +631,7 @@ describe('FileModel', () => {
describe('findByNames', () => {
it('should find files by names', async () => {
// 准备测试数据
// Prepare test data
const fileList = [
{
name: 'test1.txt',
@ -658,7 +658,7 @@ describe('FileModel', () => {
await serverDB.insert(files).values(fileList);
// 测试查找文件
// Test finding files
const result = await fileModel.findByNames(['test1', 'test2']);
expect(result).toHaveLength(2);
expect(result.map((f) => f.name)).toContain('test1.txt');
@ -671,7 +671,7 @@ describe('FileModel', () => {
});
it('should only find files belonging to current user', async () => {
// 准备测试数据
// Prepare test data
await serverDB.insert(files).values([
{
name: 'test1.txt',
@ -685,7 +685,7 @@ describe('FileModel', () => {
url: 'https://example.com/test2.txt',
size: 200,
fileType: 'text/plain',
userId: 'user2', // 不同用户的文件
userId: 'user2', // file from a different user
},
]);
@ -697,7 +697,7 @@ describe('FileModel', () => {
describe('deleteGlobalFile', () => {
it('should delete global file by hashId', async () => {
// 准备测试数据
// Prepare test data
const globalFile = {
hashId: 'test-hash',
fileType: 'text/plain',
@ -709,10 +709,10 @@ describe('FileModel', () => {
await serverDB.insert(globalFiles).values(globalFile);
// 执行删除操作
// Execute delete operation
await fileModel.deleteGlobalFile('test-hash');
// 验证文件已被删除
// Verify file has been deleted
const result = await serverDB.query.globalFiles.findFirst({
where: eq(globalFiles.hashId, 'test-hash'),
});
@ -720,12 +720,12 @@ describe('FileModel', () => {
});
it('should not throw error when deleting non-existent global file', async () => {
// 删除不存在的文件不应抛出错误
// Deleting a non-existent file should not throw an error
await expect(fileModel.deleteGlobalFile('non-existent-hash')).resolves.not.toThrow();
});
it('should only delete specified global file', async () => {
// 准备测试数据
// Prepare test data
const globalFiles1 = {
hashId: 'hash1',
fileType: 'text/plain',
@ -743,10 +743,10 @@ describe('FileModel', () => {
await serverDB.insert(globalFiles).values([globalFiles1, globalFiles2]);
// 删除一个文件
// Delete one file
await fileModel.deleteGlobalFile('hash1');
// 验证只有指定文件被删除
// Verify only the specified file was deleted
const remainingFiles = await serverDB.query.globalFiles.findMany();
expect(remainingFiles).toHaveLength(1);
expect(remainingFiles[0].hashId).toBe('hash2');
@ -764,22 +764,22 @@ describe('FileModel', () => {
fileHash: 'test-hash-txn',
};
// 在事务中创建文件
// Create file in transaction
const result = await serverDB.transaction(async (trx) => {
const { id } = await fileModel.create(params, true, trx);
// 在事务内验证文件已创建
// Verify file was created inside the transaction
const file = await trx.query.files.findFirst({ where: eq(files.id, id) });
expect(file).toMatchObject({ ...params, userId });
return { id };
});
// 事务提交后,验证文件仍然存在
// After transaction commit, verify file still exists
const file = await serverDB.query.files.findFirst({ where: eq(files.id, result.id) });
expect(file).toMatchObject({ ...params, userId });
// 验证全局文件也被创建
// Verify global file was also created
const globalFile = await serverDB.query.globalFiles.findFirst({
where: eq(globalFiles.hashId, params.fileHash),
});
@ -797,22 +797,22 @@ describe('FileModel', () => {
let createdFileId: string | undefined;
// 故意让事务失败
// Intentionally fail the transaction
await expect(
serverDB.transaction(async (trx) => {
const { id } = await fileModel.create(params, true, trx);
createdFileId = id;
// 在事务内验证文件已创建
// Verify file was created inside the transaction
const file = await trx.query.files.findFirst({ where: eq(files.id, id) });
expect(file).toMatchObject({ ...params, userId });
// 抛出错误导致事务回滚
// Throw an error to cause transaction rollback
throw new Error('Intentional rollback');
}),
).rejects.toThrow('Intentional rollback');
// 验证文件创建被回滚
// Verify file creation was rolled back
if (createdFileId) {
const file = await serverDB.query.files.findFirst({
where: eq(files.id, createdFileId),
@ -820,7 +820,7 @@ describe('FileModel', () => {
expect(file).toBeUndefined();
}
// 验证全局文件创建也被回滚
// Verify global file creation was also rolled back
const globalFile = await serverDB.query.globalFiles.findFirst({
where: eq(globalFiles.hashId, params.fileHash),
});
@ -839,7 +839,7 @@ describe('FileModel', () => {
const result = await serverDB.transaction(async (trx) => {
const { id } = await fileModel.create(params, false, trx);
// 验证知识库文件关联已创建
// Verify knowledge base file association was created
const kbFile = await trx.query.knowledgeBaseFiles.findFirst({
where: eq(knowledgeBaseFiles.fileId, id),
});
@ -848,7 +848,7 @@ describe('FileModel', () => {
return { id };
});
// 事务提交后验证
// Verify after transaction commit
const kbFile = await serverDB.query.knowledgeBaseFiles.findFirst({
where: eq(knowledgeBaseFiles.fileId, result.id),
});
@ -862,7 +862,7 @@ describe('FileModel', () => {
describe('delete with transaction', () => {
it('should delete file within provided transaction', async () => {
// 先创建文件和全局文件
// First create the file and global file
await fileModel.createGlobalFile({
hashId: 'delete-txn-hash',
url: 'https://example.com/delete-txn.txt',
@ -879,20 +879,20 @@ describe('FileModel', () => {
fileHash: 'delete-txn-hash',
});
// 在事务中删除文件
// Delete file in transaction
await serverDB.transaction(async (trx) => {
await fileModel.delete(id, true, trx);
// 在事务内验证文件已删除
// Verify file was deleted inside the transaction
const file = await trx.query.files.findFirst({ where: eq(files.id, id) });
expect(file).toBeUndefined();
});
// 事务提交后验证文件仍然被删除
// After transaction commit, verify file is still deleted
const file = await serverDB.query.files.findFirst({ where: eq(files.id, id) });
expect(file).toBeUndefined();
// 验证全局文件也被删除(因为没有其他引用)
// Verify global file was also deleted (no other references)
const globalFile = await serverDB.query.globalFiles.findFirst({
where: eq(globalFiles.hashId, 'delete-txn-hash'),
});
@ -900,7 +900,7 @@ describe('FileModel', () => {
});
it('should rollback file deletion when transaction fails', async () => {
// 先创建文件和全局文件
// First create the file and global file
await fileModel.createGlobalFile({
hashId: 'rollback-delete-hash',
url: 'https://example.com/rollback-delete.txt',
@ -917,26 +917,26 @@ describe('FileModel', () => {
fileHash: 'rollback-delete-hash',
});
// 故意让事务失败
// Intentionally fail the transaction
await expect(
serverDB.transaction(async (trx) => {
await fileModel.delete(id, true, trx);
// 在事务内验证文件已删除
// Verify file was deleted inside the transaction
const file = await trx.query.files.findFirst({ where: eq(files.id, id) });
expect(file).toBeUndefined();
// 抛出错误导致事务回滚
// Throw an error to cause transaction rollback
throw new Error('Intentional rollback for delete');
}),
).rejects.toThrow('Intentional rollback for delete');
// 验证文件删除被回滚,文件仍然存在
// Verify file deletion was rolled back, file still exists
const file = await serverDB.query.files.findFirst({ where: eq(files.id, id) });
expect(file).toBeDefined();
expect(file?.name).toBe('rollback-delete-file.txt');
// 验证全局文件也被回滚,仍然存在
// Verify global file was also rolled back, still exists
const globalFile = await serverDB.query.globalFiles.findFirst({
where: eq(globalFiles.hashId, 'rollback-delete-hash'),
});
@ -944,7 +944,7 @@ describe('FileModel', () => {
});
it('should delete file but preserve global file when removeGlobalFile=false in transaction', async () => {
// 先创建文件和全局文件
// First create the file and global file
await fileModel.createGlobalFile({
hashId: 'preserve-global-hash',
url: 'https://example.com/preserve-global.txt',
@ -961,16 +961,16 @@ describe('FileModel', () => {
fileHash: 'preserve-global-hash',
});
// 在事务中删除文件,但不删除全局文件
// Delete file in transaction, but keep global file
await serverDB.transaction(async (trx) => {
await fileModel.delete(id, false, trx);
});
// 验证文件被删除
// Verify file was deleted
const file = await serverDB.query.files.findFirst({ where: eq(files.id, id) });
expect(file).toBeUndefined();
// 验证全局文件被保留
// Verify global file was retained
const globalFile = await serverDB.query.globalFiles.findFirst({
where: eq(globalFiles.hashId, 'preserve-global-hash'),
});
@ -980,7 +980,7 @@ describe('FileModel', () => {
describe('mixed operations in transaction', () => {
it('should support create and delete operations in same transaction', async () => {
// 先创建一个要删除的文件
// First create a file to be deleted
await fileModel.createGlobalFile({
hashId: 'mixed-delete-hash',
url: 'https://example.com/mixed-delete.txt',
@ -997,12 +997,12 @@ describe('FileModel', () => {
fileHash: 'mixed-delete-hash',
});
// 在同一个事务中删除旧文件并创建新文件
// Delete old file and create new file in the same transaction
const result = await serverDB.transaction(async (trx) => {
// 删除旧文件
// Delete old file
await fileModel.delete(deleteFileId, true, trx);
// 创建新文件
// Create new file
const { id: newFileId } = await fileModel.create(
{
name: 'mixed-create-file.txt',
@ -1018,20 +1018,20 @@ describe('FileModel', () => {
return { newFileId };
});
// 验证旧文件被删除
// Verify old file was deleted
const deletedFile = await serverDB.query.files.findFirst({
where: eq(files.id, deleteFileId),
});
expect(deletedFile).toBeUndefined();
// 验证新文件被创建
// Verify new file was created
const newFile = await serverDB.query.files.findFirst({
where: eq(files.id, result.newFileId),
});
expect(newFile).toBeDefined();
expect(newFile?.name).toBe('mixed-create-file.txt');
// 验证新的全局文件被创建
// Verify new global file was created
const newGlobalFile = await serverDB.query.globalFiles.findFirst({
where: eq(globalFiles.hashId, 'mixed-create-hash'),
});
@ -1152,7 +1152,7 @@ describe('FileModel', () => {
});
it('should delete file even when chunks deletion fails', async () => {
// 创建测试文件
// Create test file
const testFile = {
name: 'error-test-file.txt',
url: 'https://example.com/error-test-file.txt',
@ -1163,52 +1163,52 @@ describe('FileModel', () => {
const { id: fileId } = await fileModel.create(testFile, true);
// 创建一些测试数据来模拟chunks关联
// Create some test data to simulate chunk associations
const chunkId1 = '550e8400-e29b-41d4-a716-446655440001';
const chunkId2 = '550e8400-e29b-41d4-a716-446655440002';
// 插入chunks
// Insert chunks
await serverDB.insert(chunks).values([
{ id: chunkId1, text: 'chunk 1', userId, type: 'text' },
{ id: chunkId2, text: 'chunk 2', userId, type: 'text' },
]);
// 插入fileChunks关联
// Insert fileChunks associations
await serverDB.insert(fileChunks).values([
{ fileId, chunkId: chunkId1, userId },
{ fileId, chunkId: chunkId2, userId },
]);
// 插入embeddings (1024维向量)
// Insert embeddings (1024-dimensional vectors)
const testEmbedding = Array.from({ length: 1024 }).fill(0.1) as number[];
await serverDB
.insert(embeddings)
.values([{ chunkId: chunkId1, embeddings: testEmbedding, model: 'test-model', userId }]);
// 跳过 documentChunks 测试,因为需要先创建 documents 记录
// Skip documentChunks test, requires creating documents records first
// 删除文件,应该会清理所有相关数据
// Delete file, should clean up all related data
const result = await fileModel.delete(fileId, true);
// 验证文件被删除
// Verify file was deleted
const deletedFile = await serverDB.query.files.findFirst({
where: eq(files.id, fileId),
});
expect(deletedFile).toBeUndefined();
// 验证chunks被删除
// Verify chunks were deleted
const remainingChunks = await serverDB.query.chunks.findMany({
where: inArray(chunks.id, [chunkId1, chunkId2]),
});
expect(remainingChunks).toHaveLength(0);
// 验证embeddings被删除
// Verify embeddings were deleted
const remainingEmbeddings = await serverDB.query.embeddings.findMany({
where: inArray(embeddings.chunkId, [chunkId1, chunkId2]),
});
expect(remainingEmbeddings).toHaveLength(0);
// 验证fileChunks被删除
// Verify fileChunks were deleted
const remainingFileChunks = await serverDB.query.fileChunks.findMany({
where: eq(fileChunks.fileId, fileId),
});
@ -1218,7 +1218,7 @@ describe('FileModel', () => {
});
it('should successfully delete file with all related chunks and embeddings', async () => {
// 简化测试:只验证正常的完整删除流程(移除知识库保护后)
// Simplified test: only verify the normal full deletion flow (after removing knowledge base protection)
const testFile = {
name: 'complete-deletion-test.txt',
url: 'https://example.com/complete-deletion-test.txt',
@ -1231,42 +1231,42 @@ describe('FileModel', () => {
const chunkId = '550e8400-e29b-41d4-a716-446655440003';
// 插入chunk
// Insert chunk
await serverDB
.insert(chunks)
.values([{ id: chunkId, text: 'complete test chunk', userId, type: 'text' }]);
// 插入fileChunks关联
// Insert fileChunks associations
await serverDB.insert(fileChunks).values([{ fileId, chunkId, userId }]);
// 插入embeddings
// Insert embeddings
const testEmbedding = Array.from({ length: 1024 }).fill(0.1) as number[];
await serverDB
.insert(embeddings)
.values([{ chunkId, embeddings: testEmbedding, model: 'test-model', userId }]);
// 删除文件
// Delete file
await fileModel.delete(fileId, true);
// 验证文件被删除
// Verify file was deleted
const deletedFile = await serverDB.query.files.findFirst({
where: eq(files.id, fileId),
});
expect(deletedFile).toBeUndefined();
// 验证chunks被删除
// Verify chunks were deleted
const remainingChunks = await serverDB.query.chunks.findMany({
where: eq(chunks.id, chunkId),
});
expect(remainingChunks).toHaveLength(0);
// 验证embeddings被删除
// Verify embeddings were deleted
const remainingEmbeddings = await serverDB.query.embeddings.findMany({
where: eq(embeddings.chunkId, chunkId),
});
expect(remainingEmbeddings).toHaveLength(0);
// 验证fileChunks被删除
// Verify fileChunks were deleted
const remainingFileChunks = await serverDB.query.fileChunks.findMany({
where: eq(fileChunks.fileId, fileId),
});
@ -1274,7 +1274,7 @@ describe('FileModel', () => {
});
it('should delete files that are in knowledge bases (removed protection)', async () => {
// 测试修复后的逻辑:知识库中的文件也应该被删除
// Test the fixed logic: files in knowledge bases should also be deleted
const testFile = {
name: 'knowledge-base-file.txt',
url: 'https://example.com/knowledge-base-file.txt',
@ -1288,47 +1288,47 @@ describe('FileModel', () => {
const chunkId = '550e8400-e29b-41d4-a716-446655440007';
// 插入chunk和关联数据
// Insert chunk and association data
await serverDB
.insert(chunks)
.values([{ id: chunkId, text: 'knowledge base chunk', userId, type: 'text' }]);
await serverDB.insert(fileChunks).values([{ fileId, chunkId, userId }]);
// 插入embeddings (1024维向量)
// Insert embeddings (1024-dimensional vectors)
const testEmbedding = Array.from({ length: 1024 }).fill(0.1) as number[];
await serverDB
.insert(embeddings)
.values([{ chunkId, embeddings: testEmbedding, model: 'test-model', userId }]);
// 验证文件确实在知识库中
// Verify file is indeed in the knowledge base
const kbFile = await serverDB.query.knowledgeBaseFiles.findFirst({
where: eq(knowledgeBaseFiles.fileId, fileId),
});
expect(kbFile).toBeDefined();
// 删除文件
// Delete file
await fileModel.delete(fileId, true);
// 验证知识库中的文件也被完全删除
// Verify files in knowledge base were also completely deleted
const deletedFile = await serverDB.query.files.findFirst({
where: eq(files.id, fileId),
});
expect(deletedFile).toBeUndefined();
// 验证chunks被删除这是修复的核心之前知识库文件的chunks不会被删除
// Verify chunks were deleted (this is the core of the fix: previously chunks of knowledge base files would not be deleted)
const remainingChunks = await serverDB.query.chunks.findMany({
where: eq(chunks.id, chunkId),
});
expect(remainingChunks).toHaveLength(0);
// 验证embeddings被删除
// Verify embeddings were deleted
const remainingEmbeddings = await serverDB.query.embeddings.findMany({
where: eq(embeddings.chunkId, chunkId),
});
expect(remainingEmbeddings).toHaveLength(0);
// 验证fileChunks被删除
// Verify fileChunks were deleted
const remainingFileChunks = await serverDB.query.fileChunks.findMany({
where: eq(fileChunks.fileId, fileId),
});

View file

@ -25,19 +25,19 @@ const sessionModel = new SessionModel(serverDB, userId);
beforeEach(async () => {
await serverDB.delete(users);
// 并创建初始用户
// and create the initial user
await serverDB.insert(users).values({ id: userId });
});
afterEach(async () => {
// 在每个测试用例之后, 清空用户表 (应该会自动级联删除所有数据)
// After each test case, clear the users table (should auto-cascade delete all data)
await serverDB.delete(users);
});
describe('SessionModel', () => {
describe('query', () => {
it('should query sessions by user ID', async () => {
// 创建一些测试数据
// Create some test data
await serverDB.insert(users).values([{ id: '456' }]);
await serverDB.insert(sessions).values([
@ -46,10 +46,10 @@ describe('SessionModel', () => {
{ id: '3', userId: '456', updatedAt: new Date('2023-03-01') },
]);
// 调用 query 方法
// Call the query method
const result = await sessionModel.query();
// 断言结果
// Assert results
expect(result).toHaveLength(2);
expect(result[0].id).toBe('2');
expect(result[1].id).toBe('1');
@ -76,7 +76,7 @@ describe('SessionModel', () => {
describe('queryWithGroups', () => {
it('should return sessions grouped by group', async () => {
// 创建测试数据
// Create test data
await serverDB.transaction(async (trx) => {
await trx.insert(users).values([{ id: '456' }]);
await trx.insert(sessionGroups).values([
@ -94,10 +94,10 @@ describe('SessionModel', () => {
]);
});
// 调用 queryWithGroups 方法
// Call the queryWithGroups method
const result = await sessionModel.queryWithGroups();
// 断言结果
// Assert results
expect(result.sessions).toHaveLength(6);
expect(result.sessionGroups).toHaveLength(2);
expect(result.sessionGroups[0].id).toBe('group1');
@ -107,10 +107,10 @@ describe('SessionModel', () => {
});
it('should return empty groups if no sessions', async () => {
// 调用 queryWithGroups 方法
// Call the queryWithGroups method
const result = await sessionModel.queryWithGroups();
// 断言结果
// Assert results
expect(result.sessions).toHaveLength(0);
expect(result.sessionGroups).toHaveLength(0);
});
@ -236,7 +236,7 @@ describe('SessionModel', () => {
describe('count', () => {
it('should return the count of sessions for the user', async () => {
// 创建测试数据
// Create test data
await serverDB.insert(users).values([{ id: '456' }]);
await serverDB.insert(sessions).values([
{ id: '1', userId },
@ -244,22 +244,22 @@ describe('SessionModel', () => {
{ id: '3', userId: '456' },
]);
// 调用 count 方法
// Call the count method
const result = await sessionModel.count();
// 断言结果
// Assert results
expect(result).toBe(2);
});
it('should return 0 if no sessions exist for the user', async () => {
// 创建测试数据
// Create test data
await serverDB.insert(users).values([{ id: '456' }]);
await serverDB.insert(sessions).values([{ id: '3', userId: '456' }]);
// 调用 count 方法
// Call the count method
const result = await sessionModel.count();
// 断言结果
// Assert results
expect(result).toBe(0);
});
@ -366,7 +366,7 @@ describe('SessionModel', () => {
describe('create', () => {
it('should create a new session', async () => {
// 调用 create 方法
// Call the create method
const result = await sessionModel.create({
type: 'agent',
session: {
@ -375,7 +375,7 @@ describe('SessionModel', () => {
config: { model: 'gpt-3.5-turbo' },
});
// 断言结果
// Assert results
const sessionId = result.id;
expect(sessionId).toBeDefined();
expect(sessionId.startsWith('ssn_')).toBeTruthy();
@ -390,7 +390,7 @@ describe('SessionModel', () => {
});
it('should create a new session with custom ID', async () => {
// 调用 create 方法,传入自定义 ID
// Call the create method with a custom ID
const customId = 'custom-id';
const result = await sessionModel.create({
type: 'agent',
@ -399,7 +399,7 @@ describe('SessionModel', () => {
id: customId,
});
// 断言结果
// Assert results
expect(result.id).toBe(customId);
});
@ -471,7 +471,7 @@ describe('SessionModel', () => {
describe('batchCreate', () => {
it('should batch create sessions', async () => {
// 调用 batchCreate 方法
// Call the batchCreate method
const sessions: NewSession[] = [
{
id: '1',
@ -490,13 +490,13 @@ describe('SessionModel', () => {
];
const result = await sessionModel.batchCreate(sessions);
// 断言结果
// Assert results
// pglite return affectedRows while postgres return rowCount
expect((result as any).affectedRows || result.rowCount).toEqual(2);
});
it.skip('should set group to default if group does not exist', async () => {
// 调用 batchCreate 方法,传入不存在的 group
// Call the batchCreate method with a non-existent group
const sessions: NewSession[] = [
{
id: '1',
@ -509,14 +509,14 @@ describe('SessionModel', () => {
];
const result = await sessionModel.batchCreate(sessions);
// 断言结果
// Assert results
// expect(result[0].group).toBe('default');
});
});
describe('duplicate', () => {
it('should duplicate a session', async () => {
// 创建一个用户和一个 session
// Create a user and a session
await serverDB.transaction(async (trx) => {
await trx
.insert(sessions)
@ -525,10 +525,10 @@ describe('SessionModel', () => {
await trx.insert(agentsToSessions).values({ agentId: 'agent-1', sessionId: '1', userId });
});
// 调用 duplicate 方法
// Call the duplicate method
const result = (await sessionModel.duplicate('1', 'Duplicated Session')) as SessionItem;
// 断言结果
// Assert results
expect(result.id).not.toBe('1');
expect(result.userId).toBe(userId);
expect(result.type).toBe('agent');
@ -542,34 +542,34 @@ describe('SessionModel', () => {
});
it('should return undefined if session does not exist', async () => {
// 调用 duplicate 方法,传入不存在的 session ID
// Call the duplicate method with a non-existent session ID
const result = await sessionModel.duplicate('non-existent-id');
// 断言结果
// Assert results
expect(result).toBeUndefined();
});
});
describe('update', () => {
it('should update a session', async () => {
// 创建一个测试 session
// Create a test session
const sessionId = '123';
await serverDB.insert(sessions).values({ userId, id: sessionId, title: 'Test Session' });
// 调用 update 方法更新 session
// Call the update method to update the session
const updatedSessions = await sessionModel.update(sessionId, {
title: 'Updated Test Session',
description: 'This is an updated test session',
});
// 断言更新后的结果
// Assert the updated results
expect(updatedSessions).toHaveLength(1);
expect(updatedSessions[0].title).toBe('Updated Test Session');
expect(updatedSessions[0].description).toBe('This is an updated test session');
});
it('should not update a session if user ID does not match', async () => {
// 创建一个测试 session,但使用不同的 user ID
// Create a test session with a different user ID
await serverDB.insert(users).values([{ id: '777' }]);
const sessionId = '123';
@ -578,7 +578,7 @@ describe('SessionModel', () => {
.insert(sessions)
.values({ userId: '777', id: sessionId, title: 'Test Session' });
// 尝试更新这个 session,应该不会有任何更新
// Attempt to update this session — should produce no updates
const updatedSessions = await sessionModel.update(sessionId, {
title: 'Updated Test Session',
});
@ -589,26 +589,26 @@ describe('SessionModel', () => {
describe('delete', () => {
it('should handle deleting a session with no associated messages or topics', async () => {
// 创建测试数据
// Create test data
await serverDB.insert(sessions).values({ id: '1', userId });
// 调用 delete 方法
// Call the delete method
await sessionModel.delete('1');
// 断言删除结果
// Assert deletion results
const result = await serverDB.select({ id: sessions.id }).from(sessions);
expect(result).toHaveLength(0);
});
it('should handle concurrent deletions gracefully', async () => {
// 创建测试数据
// Create test data
await serverDB.insert(sessions).values({ id: '1', userId });
// 并发调用 delete 方法
// Concurrently call the delete method
await Promise.all([sessionModel.delete('1'), sessionModel.delete('1')]);
// 断言删除结果
// Assert deletion results
const result = await serverDB.select({ id: sessions.id }).from(sessions);
expect(result).toHaveLength(0);
@ -673,35 +673,35 @@ describe('SessionModel', () => {
describe('batchDelete', () => {
it('should handle deleting sessions with no associated messages or topics', async () => {
// 创建测试数据
// Create test data
await serverDB.insert(sessions).values([
{ id: '1', userId },
{ id: '2', userId },
]);
// 调用 batchDelete 方法
// Call the batchDelete method
await sessionModel.batchDelete(['1', '2']);
// 断言删除结果
// Assert deletion results
const result = await serverDB.select({ id: sessions.id }).from(sessions);
expect(result).toHaveLength(0);
});
it('should handle concurrent batch deletions gracefully', async () => {
// 创建测试数据
// Create test data
await serverDB.insert(sessions).values([
{ id: '1', userId },
{ id: '2', userId },
]);
// 并发调用 batchDelete 方法
// Concurrently call the batchDelete method
await Promise.all([
sessionModel.batchDelete(['1', '2']),
sessionModel.batchDelete(['1', '2']),
]);
// 断言删除结果
// Assert deletion results
const result = await serverDB.select({ id: sessions.id }).from(sessions);
expect(result).toHaveLength(0);
@ -1519,7 +1519,7 @@ describe('SessionModel', () => {
describe('findSessionsByKeywords', () => {
it('should handle errors gracefully and return empty array', async () => {
// 这个测试旨在覆盖 findSessionsByKeywords 中的错误处理逻辑
// This test aims to cover the error-handling logic in findSessionsByKeywords
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
// Mock the database query to throw an error
@ -1528,7 +1528,7 @@ describe('SessionModel', () => {
const result = await sessionModel.findSessionsByKeywords({ keyword: 'test' });
// 即使发生错误,方法也应该返回一个空数组
// Even when an error occurs, the method should return an empty array
expect(Array.isArray(result)).toBe(true);
expect(result).toEqual([]);
expect(consoleSpy).toHaveBeenCalledWith('findSessionsByKeywords error:', expect.any(Error), {

View file

@ -225,7 +225,7 @@ describe('AgentEvalBenchmarkModel', () => {
it('should order by createdAt descending', async () => {
const results = await benchmarkModel.query(true);
// 最新的应该在前面
// The newest should come first
// Order may vary in PGlite due to timing
expect(results.length).toBeGreaterThanOrEqual(3);
});

View file

@ -195,7 +195,7 @@ describe('AgentEvalDatasetModel', () => {
it('should order by createdAt descending', async () => {
const results = await datasetModel.query();
// 最新的应该在前面
// The newest should come first
// Order may vary, just check we got results
expect(results.length).toBeGreaterThanOrEqual(2);
});

View file

@ -267,7 +267,7 @@ describe('AiInfraRepos', () => {
expect(merged.settings).toEqual({ searchImpl: 'params' });
});
// 测试场景:用户模型 abilitie 为空Empty而基础模型有搜索能力和设置
// Test scenario: user model abilities is empty (Empty) while the base model has search capability and settings
it('should retain builtin abilities and settings when user model has no abilities (empty) and builtin has settings', async () => {
const providerId = 'openai';
@ -285,7 +285,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: { search: false }, // 使用 builtin abilities
abilities: { search: false }, // Use builtin abilities
settings: { searchImpl: 'params', searchProvider: 'google' }, // builtin has settings
},
];
@ -297,9 +297,9 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// 使用 builtin abilities
// Use builtin abilities
expect(merged?.abilities?.search).toEqual(false);
// 保留 builtin settings
// Retain builtin settings
expect(merged?.settings).toBeUndefined();
});
@ -320,7 +320,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: { search: true }, // 使用 builtin abilities
abilities: { search: true }, // Use builtin abilities
settings: { searchImpl: 'params', searchProvider: 'google' }, // builtin has settings
},
];
@ -332,13 +332,13 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// 使用 builtin abilities
// Use builtin abilities
expect(merged?.abilities?.search).toEqual(true);
// 保留 builtin settings
// Retain builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'google' });
});
// 测试场景用户模型未启用搜索abilities.search 为 undefined而基础模型有搜索能力和设置
// Test scenario: user model has search disabled (abilities.search is undefined) while the base model has search capability and settings
it('should retain builtin settings when user model has no abilities (empty) and builtin has settings', async () => {
const providerId = 'openai';
@ -347,7 +347,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: { vision: true }, // 启用 vision 能力, no search
abilities: { vision: true }, // Enable vision ability, no search
},
];
@ -368,9 +368,9 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// abilities.search 会被 merge 为 false此处和 getEnabledAiModel 不同
// abilities.search will be merged as false, differs from getEnabledAiModel
expect(merged?.abilities?.search).toEqual(false);
// 删去 builtin settings
// Remove builtin settings
expect(merged?.settings).toBeUndefined();
});
@ -382,7 +382,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: { vision: true }, // 启用 vision 能力, no search
abilities: { vision: true }, // Enable vision ability, no search
},
];
@ -391,7 +391,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: { search: true }, // builtin abilities 会被 merge
abilities: { search: true }, // builtin abilities will be merged
settings: { searchImpl: 'params', searchProvider: 'google' }, // builtin has settings
},
];
@ -403,13 +403,13 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// abilities.search 会被 merge 为 true此处和 getEnabledAiModel 不同
// abilities.search will be merged as true, differs from getEnabledAiModel
expect(merged?.abilities?.search).toEqual(true);
// 保留 builtin settings
// Retain builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'google' });
});
// 测试:用户模型无 abilities.searchundefined保留 builtin settingsmergeArrayById 优先用户,但用户无则 builtin
// Test: user model has no abilities.search (undefined), retains builtin settings (mergeArrayById prefers user, falls back to builtin when absent)
it('should retain builtin settings when user model has no abilities.search (undefined) and builtin has settings', async () => {
const providerId = 'openai';
@ -418,7 +418,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: {}, // search
abilities: {}, // no search
},
];
@ -440,7 +440,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities?.search).toBeUndefined();
// 保留 builtin settings
// Retain builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'google' });
});
@ -452,7 +452,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: {}, // search
abilities: {}, // no search
},
];
@ -461,7 +461,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
// settings
// no settings
},
];
@ -473,11 +473,11 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities?.search).toBeUndefined();
// settings
// no settings
expect(merged?.settings).toBeUndefined();
});
// 测试:用户模型有 abilities.search: true
// Test: user model has abilities.search: true
it('should inject defaults when user has search: true, no existing settings (builtin none)', async () => {
const providerId = 'openai';
@ -486,7 +486,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: { search: true }, // 用户启用
abilities: { search: true }, // user-enabled
},
];
@ -495,7 +495,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
// settings
// no settings
},
];
@ -507,7 +507,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities).toEqual({ search: true });
// 注入 defaults
// Inject defaults
expect(merged?.settings).toEqual({ searchImpl: 'params' });
});
@ -540,11 +540,11 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities).toEqual({ search: true });
// 使用 builtin settings
// Use builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'tool' });
});
// 测试:用户模型有 abilities.search: false
// Test: user model has abilities.search: false
it('should remove settings when user has search: false and builtin has settings', async () => {
const providerId = 'openai';
@ -553,7 +553,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
abilities: { search: false }, // 用户禁用
abilities: { search: false }, // user-disabled
},
];
@ -574,7 +574,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities).toEqual({ search: false });
// 移除 search 相关,保留其他
// Remove search-related settings, retain others
expect(merged?.settings).toEqual({ extendParams: [] });
});
@ -595,7 +595,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
// settings
// no settings
},
];
@ -607,7 +607,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities).toEqual({ search: false });
// settings
// no settings
expect(merged?.settings).toBeUndefined();
});
@ -640,7 +640,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// 应该使用用户的 settings
// Should use user settings
expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'user-provider' });
});
@ -653,7 +653,7 @@ describe('AiInfraRepos', () => {
type: 'chat',
enabled: true,
abilities: { vision: true },
// 用户未设置 settings
// user has not set settings
},
];
@ -673,7 +673,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// 应该使用内置的 settings
// Should use builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'tool', searchProvider: 'google' });
});
@ -686,7 +686,7 @@ describe('AiInfraRepos', () => {
type: 'chat',
enabled: true,
abilities: { vision: true },
// 用户未设置 settings
// user has not set settings
},
];
@ -695,7 +695,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
type: 'chat',
enabled: true,
// 内置也无 settings
// builtin also has no settings
},
];
@ -706,7 +706,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// settings
// no settings
expect(merged?.settings).toBeUndefined();
});

View file

@ -328,7 +328,7 @@ describe('AiInfraRepos', () => {
expect(merged?.settings).toEqual({ searchImpl: 'params' });
});
// 测试场景:用户模型 abilitie 为空Empty而基础模型有搜索能力和设置
// Test scenario: user model abilities is empty (Empty) while the base model has search capability and settings
it('should retain builtin abilities and settings when user model has no abilities (empty) and builtin has settings', async () => {
const mockProviders = [
{ enabled: true, id: 'openai', name: 'OpenAI', source: 'builtin' as const },
@ -346,7 +346,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
enabled: true,
type: 'chat' as const,
abilities: { search: false }, // 使用 builtin abilities
abilities: { search: false }, // Use builtin abilities
settings: { searchImpl: 'params', searchProvider: 'google' }, // builtin has settings
};
@ -358,9 +358,9 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// 使用 builtin abilities
// Use builtin abilities
expect(merged?.abilities?.search).toEqual(false);
// 删去 builtin settings
// Remove builtin settings
expect(merged?.settings).toBeUndefined();
});
@ -381,7 +381,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
enabled: true,
type: 'chat' as const,
abilities: { search: true }, // 使用 builtin abilities
abilities: { search: true }, // Use builtin abilities
settings: { searchImpl: 'params', searchProvider: 'google' }, // builtin has settings
};
@ -393,13 +393,13 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// 使用 builtin abilities
// Use builtin abilities
expect(merged?.abilities?.search).toEqual(true);
// 保留 builtin settings
// Retain builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'google' });
});
// 测试场景用户模型未启用搜索abilities.search 为 undefined而基础模型有搜索能力和设置
// Test scenario: user model has search disabled (abilities.search is undefined) while the base model has search capability and settings
it('should retain builtin settings when user model has no abilities.search (undefined) and builtin has settings', async () => {
const mockProviders = [
{ enabled: true, id: 'openai', name: 'OpenAI', source: 'builtin' as const },
@ -410,14 +410,14 @@ describe('AiInfraRepos', () => {
providerId: 'openai',
enabled: true,
type: 'chat',
abilities: { vision: true }, // 启用 vision 能力, no search
abilities: { vision: true }, // Enable vision ability, no search
};
const builtinModel = {
id: 'gpt-4',
enabled: true,
type: 'chat' as const,
abilities: { search: false }, // builtin abilities 不生效
abilities: { search: false }, // builtin abilities have no effect
settings: { searchImpl: 'params', searchProvider: 'google' }, // builtin has settings
};
@ -429,9 +429,9 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// abilities.search 仍 undefined兼容老版本
// abilities.search remains undefined (backward compatible)
expect(merged?.abilities?.search).toBeUndefined();
// 保留 builtin settings
// Retain builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'google' });
});
@ -445,14 +445,14 @@ describe('AiInfraRepos', () => {
providerId: 'openai',
enabled: true,
type: 'chat',
abilities: { vision: true }, // 启用 vision 能力, no search
abilities: { vision: true }, // Enable vision ability, no search
};
const builtinModel = {
id: 'gpt-4',
enabled: true,
type: 'chat' as const,
abilities: { search: true }, // builtin abilities 不生效
abilities: { search: true }, // builtin abilities have no effect
settings: { searchImpl: 'params', searchProvider: 'google' }, // builtin has settings
};
@ -464,13 +464,13 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// abilities.search 仍 undefined兼容老版本
// abilities.search remains undefined (backward compatible)
expect(merged?.abilities?.search).toBeUndefined();
// 保留 builtin settings
// Retain builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'google' });
});
// 测试场景用户模型未启用搜索abilities.search 为 undefined而基础模型也无搜索能力和设置
// Test scenario: user model has search disabled (abilities.search is undefined) and the base model also has no search capability or settings
it('should retain no settings when user model has no abilities.search (undefined) and builtin has no settings', async () => {
const mockProviders = [
{ enabled: true, id: 'openai', name: 'OpenAI', source: 'builtin' as const },
@ -481,7 +481,7 @@ describe('AiInfraRepos', () => {
providerId: 'openai',
enabled: true,
type: 'chat',
abilities: {}, // search
abilities: {}, // no search
};
const builtinModel = {
@ -489,7 +489,7 @@ describe('AiInfraRepos', () => {
enabled: true,
type: 'chat' as const,
abilities: {},
// builtin settings
// builtin has no settings
};
vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
@ -501,11 +501,11 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities?.search).toBeUndefined();
// settings
// no settings
expect(merged?.settings).toBeUndefined();
});
// 测试:用户模型有 abilities.search: true
// Test: user model has abilities.search: true
it('should inject defaults when user has search: true, no existing settings (builtin none)', async () => {
const mockProviders = [
{ enabled: true, id: 'openai', name: 'OpenAI', source: 'builtin' as const },
@ -516,7 +516,7 @@ describe('AiInfraRepos', () => {
providerId: 'openai',
enabled: true,
type: 'chat',
abilities: { search: true }, // 用户启用 search
abilities: { search: true }, // user-enabled search
};
const builtinModel = {
@ -524,7 +524,7 @@ describe('AiInfraRepos', () => {
enabled: true,
type: 'chat' as const,
abilities: {},
// settings
// no settings
};
vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
@ -536,7 +536,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities).toEqual({ search: true });
// 注入 defaults (openai: params)
// Inject defaults (openai: params)
expect(merged?.settings).toEqual({ searchImpl: 'params' });
});
@ -557,7 +557,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
enabled: true,
type: 'chat' as const,
settings: { searchImpl: 'tool' }, // builtin settings
settings: { searchImpl: 'tool' }, // builtin has settings
};
vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
@ -569,11 +569,11 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities).toEqual({ search: true });
// 使用 builtin settings
// Use builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'tool' });
});
// 测试:用户模型有 abilities.search: false
// Test: user model has abilities.search: false
it('should remove settings when user has search: false and builtin has settings', async () => {
const mockProviders = [
{ enabled: true, id: 'openai', name: 'OpenAI', source: 'builtin' as const },
@ -584,14 +584,14 @@ describe('AiInfraRepos', () => {
providerId: 'openai',
enabled: true,
type: 'chat',
abilities: { search: false }, // 用户禁用 search
abilities: { search: false }, // user-disabled search
};
const builtinModel = {
id: 'gpt-4',
enabled: true,
type: 'chat' as const,
settings: { searchImpl: 'tool', extendParams: [] }, // builtin settings
settings: { searchImpl: 'tool', extendParams: [] }, // builtin has settings
};
vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
@ -603,7 +603,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities).toEqual({ search: false });
// 移除 search 相关,保留其他
// Remove search-related settings, retain others
expect(merged?.settings).toEqual({ extendParams: [] });
});
@ -624,7 +624,7 @@ describe('AiInfraRepos', () => {
id: 'gpt-4',
enabled: true,
type: 'chat' as const,
// settings
// no settings
};
vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
@ -636,7 +636,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
expect(merged?.abilities).toEqual({ search: false });
// settings
// no settings
expect(merged?.settings).toBeUndefined();
});
@ -669,7 +669,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// 应该使用用户的 settings不是内置的
// Should use user settings, not builtin
expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'user-provider' });
});
@ -684,7 +684,7 @@ describe('AiInfraRepos', () => {
enabled: true,
type: 'chat',
abilities: { vision: true },
// 用户未设置 settings
// user has not set settings
};
const builtinModel = {
@ -702,7 +702,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// 应该使用内置的 settings
// Should use builtin settings
expect(merged?.settings).toEqual({ searchImpl: 'tool', searchProvider: 'google' });
});
@ -757,14 +757,14 @@ describe('AiInfraRepos', () => {
enabled: true,
type: 'chat',
abilities: { vision: true },
// 用户未设置 settings
// user has not set settings
};
const builtinModel = {
id: 'gpt-4',
enabled: true,
type: 'chat' as const,
// 内置也无 settings
// builtin also has no settings
};
vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
@ -775,7 +775,7 @@ describe('AiInfraRepos', () => {
const merged = result.find((m) => m.id === 'gpt-4');
expect(merged).toBeDefined();
// settings
// no settings
expect(merged?.settings).toBeUndefined();
});

View file

@ -22,9 +22,9 @@ import { DATA_EXPORT_CONFIG, DataExporterRepos } from './index';
let db: LobeChatDatabase;
// 设置测试数据
// Set up test data
describe('DataExporterRepos', () => {
// 测试数据 ID
// Test data IDs
const testIds = {
userId: 'test-user-id',
fileId: 'test-file-id',
@ -36,7 +36,7 @@ describe('DataExporterRepos', () => {
knowledgeBaseId: 'test-kb-id',
};
// 设置测试环境
// Set up test environment
const userId: string = testIds.userId;
beforeAll(async () => {
@ -45,20 +45,20 @@ describe('DataExporterRepos', () => {
const setupTestData = async () => {
await db.transaction(async (trx) => {
// 用户数据
// User data
await trx.insert(users).values({
id: testIds.userId,
username: 'testuser',
email: 'test@example.com',
});
// 用户设置
// User settings
await trx.insert(userSettings).values({
id: testIds.userId,
general: { theme: 'light' },
});
// 全局文件
// Global files
await trx.insert(globalFiles).values({
hashId: testIds.fileHash,
fileType: 'text/plain',
@ -67,7 +67,7 @@ describe('DataExporterRepos', () => {
creator: testIds.userId,
});
// 文件数据
// File data
await trx.insert(files).values({
id: testIds.fileId,
userId: testIds.userId,
@ -78,13 +78,13 @@ describe('DataExporterRepos', () => {
url: 'https://example.com/test-file.txt',
});
// 会话组
// Session groups
await trx.insert(sessionGroups).values({
name: 'Test Group',
userId: testIds.userId,
});
// 会话
// Sessions
await trx.insert(sessions).values({
id: testIds.sessionId,
slug: 'test-session',
@ -92,7 +92,7 @@ describe('DataExporterRepos', () => {
userId: testIds.userId,
});
// 主题
// Topics
await trx.insert(topics).values({
id: testIds.topicId,
title: 'Test Topic',
@ -100,7 +100,7 @@ describe('DataExporterRepos', () => {
userId: testIds.userId,
});
// 消息
// Messages
await trx.insert(messages).values({
id: testIds.messageId,
role: 'user',
@ -110,42 +110,42 @@ describe('DataExporterRepos', () => {
topicId: testIds.topicId,
});
// 代理
// Agents
await trx.insert(agents).values({
id: testIds.agentId,
title: 'Test Agent',
userId: testIds.userId,
});
// 代理到会话的关联
// Agent-to-session associations
await trx.insert(agentsToSessions).values({
agentId: testIds.agentId,
sessionId: testIds.sessionId,
userId: testIds.userId,
});
// 文件到会话的关联
// File-to-session associations
await trx.insert(filesToSessions).values({
fileId: testIds.fileId,
sessionId: testIds.sessionId,
userId: testIds.userId,
});
// 知识库
// Knowledge bases
await trx.insert(knowledgeBases).values({
id: testIds.knowledgeBaseId,
name: 'Test Knowledge Base',
userId: testIds.userId,
});
// 知识库文件
// Knowledge base files
await trx.insert(knowledgeBaseFiles).values({
knowledgeBaseId: testIds.knowledgeBaseId,
fileId: testIds.fileId,
userId: testIds.userId,
});
// 代理知识库
// Agent knowledge bases
await trx.insert(agentsKnowledgeBases).values({
agentId: testIds.agentId,
knowledgeBaseId: testIds.knowledgeBaseId,
@ -155,7 +155,7 @@ describe('DataExporterRepos', () => {
};
beforeEach(async () => {
// 清理并插入测试数据
// Clean up and insert test data
await db.delete(users);
await db.delete(globalFiles);
await setupTestData();
@ -170,17 +170,17 @@ describe('DataExporterRepos', () => {
describe('export', () => {
it('should export all user data correctly', async () => {
// 创建导出器实例
// Create exporter instance
const dataExporter = new DataExporterRepos(db, userId);
// 执行导出
// Execute export
const result = await dataExporter.export();
// 验证基础表导出结果
// Verify base table export results
// expect(result).toHaveProperty('users');
// expect(result.users).toHaveLength(1);
// expect(result.users[0]).toHaveProperty('id', testIds.userId);
// expect(result.users[0]).not.toHaveProperty('userId'); // userId 字段应该被移除
// expect(result.users[0]).not.toHaveProperty('userId'); // the userId field should be removed
expect(result).toHaveProperty('userSettings');
expect(result.userSettings).toHaveLength(1);
@ -212,7 +212,7 @@ describe('DataExporterRepos', () => {
// expect(result.knowledgeBases).toHaveLength(1);
// expect(result.knowledgeBases[0]).toHaveProperty('id', testIds.knowledgeBaseId);
// 验证关联表导出结果
// Verify relation table export results
// expect(result).toHaveProperty('globalFiles');
// expect(result.globalFiles).toHaveLength(1);
// expect(result.globalFiles[0]).toHaveProperty('hashId', testIds.fileHash);
@ -237,18 +237,18 @@ describe('DataExporterRepos', () => {
});
it('should handle empty database gracefully', async () => {
// 清空数据库
// Clear the database
await db.delete(users);
await db.delete(globalFiles);
// 创建导出器实例
// Create exporter instance
const dataExporter = new DataExporterRepos(db, userId);
// 执行导出
// Execute export
const result = await dataExporter.export();
// 验证所有表都返回空数组
// Verify all tables return empty arrays
DATA_EXPORT_CONFIG.baseTables.forEach(({ table }) => {
expect(result).toHaveProperty(table);
expect(result[table]).toEqual([]);
@ -261,17 +261,17 @@ describe('DataExporterRepos', () => {
});
it('should handle database query errors', async () => {
// 模拟查询错误
// Simulate a query error
// @ts-ignore
vi.spyOn(db.query.users, 'findMany').mockRejectedValueOnce(new Error('Database error'));
// 创建导出器实例
// Create exporter instance
const dataExporter = new DataExporterRepos(db, userId);
// 执行导出
// Execute export
const result = await dataExporter.export();
// 验证其他表仍然被导出
// Verify other tables are still exported
expect(result).toHaveProperty('sessions');
expect(result.sessions).toHaveLength(1);
});
@ -329,7 +329,7 @@ describe('DataExporterRepos', () => {
});
it('should export data for a different user', async () => {
// 创建另一个用户
// Create another user
const anotherUserId = 'another-user-id';
await db.transaction(async (trx) => {
await trx.insert(users).values({
@ -345,13 +345,13 @@ describe('DataExporterRepos', () => {
});
});
// 创建导出器实例,使用另一个用户 ID
// Create exporter instance using another user ID
const dataExporter = new DataExporterRepos(db, anotherUserId);
// 执行导出
// Execute export
const result = await dataExporter.export();
// 验证只导出了另一个用户的数据
// Verify only the other user's data was exported
// expect(result).toHaveProperty('users');
// expect(result.users).toHaveLength(1);
// expect(result.users[0]).toHaveProperty('id', anotherUserId);

View file

@ -18,7 +18,7 @@ let importer: DataImporterRepos;
beforeEach(async () => {
await clientDB.delete(Schema.users);
// 创建测试数据
// Create test data
await clientDB.transaction(async (tx) => {
await tx.insert(Schema.users).values({ id: userId });
});

View file

@ -27,7 +27,7 @@ let importer: DataImporterRepos;
beforeEach(async () => {
await serverDB.delete(users);
// 创建测试数据
// Create test data
await serverDB.transaction(async (tx) => {
await tx.insert(users).values({ id: userId });
});
@ -323,13 +323,13 @@ describe('DataImporter', () => {
await importer.importData(data);
// 验证是否为每个 session 创建了对应的 agent
// Verify that a corresponding agent was created for each session
const agentCount = await serverDB.query.agents.findMany({
where: eq(agents.userId, userId),
});
expect(agentCount).toHaveLength(2);
// 验证 agent 的属性是否正确设置
// Verify that agent attributes are correctly set
const agent1 = await serverDB.query.agents.findFirst({
where: eq(agents.systemRole, 'Test Agent 1'),
});
@ -340,7 +340,7 @@ describe('DataImporter', () => {
});
expect(agent2?.model).toBe('def');
// 验证 agentsToSessions 关联是否正确建立
// Verify that the agentsToSessions association is correctly established
const session1 = await serverDB.query.sessions.findFirst({
where: eq(sessions.clientId, 'session1'),
});
@ -363,7 +363,7 @@ describe('DataImporter', () => {
});
it('should not create duplicate agents for existing sessions', async () => {
// 先导入一些 sessions
// First import some sessions
await importer.importData({
sessions: [
{
@ -387,7 +387,7 @@ describe('DataImporter', () => {
version: CURRENT_CONFIG_VERSION,
});
// 再次导入相同的 sessions
// Import the same sessions again
await importer.importData({
sessions: [
{
@ -411,7 +411,7 @@ describe('DataImporter', () => {
version: CURRENT_CONFIG_VERSION,
});
// 验证只创建了一个 agent
// Verify that only one agent was created
const agentCount = await serverDB.query.agents.findMany({
where: eq(agents.userId, userId),
});

View file

@ -254,7 +254,7 @@ describe('UserModel', () => {
it('should handle decrypt failure and return empty object', async () => {
const userId = 'user-api-test-id';
// 模拟解密失败的情况
// Simulate decrypt failure scenario
const invalidEncryptedData = 'invalid:-encrypted-:data';
await serverDB.insert(users).values({ id: userId });
await serverDB.insert(userSettings).values({
@ -306,7 +306,7 @@ describe('UserModel', () => {
});
});
// 补充一些边界情况的测试
// Additional edge case tests
describe('edge cases', () => {
describe('updatePreference', () => {
it('should handle undefined preference', async () => {