| | |
| | jest.mock('~/models/File', () => ({ |
| | updateFileUsage: jest.fn(), |
| | })); |
| |
|
| | |
| | jest.mock('~/config', () => ({ |
| | logger: { |
| | info: jest.fn(), |
| | warn: jest.fn(), |
| | debug: jest.fn(), |
| | error: jest.fn(), |
| | }, |
| | })); |
| |
|
| | |
| | jest.mock('librechat-data-provider', () => ({ |
| | isUUID: { parse: jest.fn() }, |
| | megabyte: 1024 * 1024, |
| | PrincipalType: { |
| | USER: 'user', |
| | GROUP: 'group', |
| | PUBLIC: 'public', |
| | }, |
| | PrincipalModel: { |
| | USER: 'User', |
| | GROUP: 'Group', |
| | }, |
| | ResourceType: { |
| | AGENT: 'agent', |
| | PROJECT: 'project', |
| | FILE: 'file', |
| | PROMPTGROUP: 'promptGroup', |
| | }, |
| | FileContext: { message_attachment: 'message_attachment' }, |
| | FileSources: { local: 'local' }, |
| | EModelEndpoint: { assistants: 'assistants' }, |
| | EToolResources: { file_search: 'file_search' }, |
| | mergeFileConfig: jest.fn(), |
| | removeNullishValues: jest.fn((obj) => obj), |
| | isAssistantsEndpoint: jest.fn(), |
| | Constants: { COMMANDS_MAX_LENGTH: 56 }, |
| | PermissionTypes: { |
| | BOOKMARKS: 'BOOKMARKS', |
| | PROMPTS: 'PROMPTS', |
| | MEMORIES: 'MEMORIES', |
| | MULTI_CONVO: 'MULTI_CONVO', |
| | AGENTS: 'AGENTS', |
| | TEMPORARY_CHAT: 'TEMPORARY_CHAT', |
| | RUN_CODE: 'RUN_CODE', |
| | WEB_SEARCH: 'WEB_SEARCH', |
| | FILE_CITATIONS: 'FILE_CITATIONS', |
| | }, |
| | Permissions: { |
| | USE: 'USE', |
| | OPT_OUT: 'OPT_OUT', |
| | }, |
| | SystemRoles: { |
| | USER: 'USER', |
| | ADMIN: 'ADMIN', |
| | }, |
| | })); |
| |
|
| | jest.mock('~/server/services/Files/images', () => ({ |
| | convertImage: jest.fn(), |
| | resizeAndConvert: jest.fn(), |
| | resizeImageBuffer: jest.fn(), |
| | })); |
| |
|
| | jest.mock('~/server/controllers/assistants/v2', () => ({ |
| | addResourceFileId: jest.fn(), |
| | deleteResourceFileId: jest.fn(), |
| | })); |
| |
|
| | jest.mock('~/models/Agent', () => ({ |
| | addAgentResourceFile: jest.fn(), |
| | removeAgentResourceFiles: jest.fn(), |
| | })); |
| |
|
| | jest.mock('~/server/controllers/assistants/helpers', () => ({ |
| | getOpenAIClient: jest.fn(), |
| | })); |
| |
|
| | jest.mock('~/server/services/Tools/credentials', () => ({ |
| | loadAuthValues: jest.fn(), |
| | })); |
| |
|
| | jest.mock('~/server/services/Config', () => ({ |
| | checkCapability: jest.fn(), |
| | })); |
| |
|
| | jest.mock('~/server/utils/queue', () => ({ |
| | LB_QueueAsyncCall: jest.fn(), |
| | })); |
| |
|
| | jest.mock('./strategies', () => ({ |
| | getStrategyFunctions: jest.fn(), |
| | })); |
| |
|
| | jest.mock('~/server/utils', () => ({ |
| | determineFileType: jest.fn(), |
| | })); |
| |
|
| | jest.mock('@librechat/api', () => ({ |
| | parseText: jest.fn(), |
| | parseTextNative: jest.fn(), |
| | })); |
| |
|
| | |
| | const { processFiles } = require('./process'); |
| | const { updateFileUsage } = require('~/models/File'); |
| |
|
| | describe('processFiles', () => { |
| | beforeEach(() => { |
| | jest.clearAllMocks(); |
| | }); |
| |
|
| | describe('null filtering functionality', () => { |
| | it('should filter out null results from updateFileUsage when files do not exist', async () => { |
| | const mockFiles = [ |
| | { file_id: 'existing-file-1' }, |
| | { file_id: 'non-existent-file' }, |
| | { file_id: 'existing-file-2' }, |
| | ]; |
| |
|
| | |
| | updateFileUsage.mockImplementation(({ file_id }) => { |
| | if (file_id === 'non-existent-file') { |
| | return Promise.resolve(null); |
| | } |
| | return Promise.resolve({ file_id, usage: 1 }); |
| | }); |
| |
|
| | const result = await processFiles(mockFiles); |
| |
|
| | expect(updateFileUsage).toHaveBeenCalledTimes(3); |
| | expect(result).toEqual([ |
| | { file_id: 'existing-file-1', usage: 1 }, |
| | { file_id: 'existing-file-2', usage: 1 }, |
| | ]); |
| |
|
| | |
| | expect(result).not.toContain(null); |
| | expect(result).not.toContain(undefined); |
| | expect(result.length).toBe(2); |
| | }); |
| |
|
| | it('should return empty array when all updateFileUsage calls return null', async () => { |
| | const mockFiles = [{ file_id: 'non-existent-1' }, { file_id: 'non-existent-2' }]; |
| |
|
| | |
| | updateFileUsage.mockResolvedValue(null); |
| |
|
| | const result = await processFiles(mockFiles); |
| |
|
| | expect(updateFileUsage).toHaveBeenCalledTimes(2); |
| | expect(result).toEqual([]); |
| | expect(result).not.toContain(null); |
| | expect(result.length).toBe(0); |
| | }); |
| |
|
| | it('should work correctly when all files exist', async () => { |
| | const mockFiles = [{ file_id: 'file-1' }, { file_id: 'file-2' }]; |
| |
|
| | updateFileUsage.mockImplementation(({ file_id }) => { |
| | return Promise.resolve({ file_id, usage: 1 }); |
| | }); |
| |
|
| | const result = await processFiles(mockFiles); |
| |
|
| | expect(result).toEqual([ |
| | { file_id: 'file-1', usage: 1 }, |
| | { file_id: 'file-2', usage: 1 }, |
| | ]); |
| | expect(result).not.toContain(null); |
| | expect(result.length).toBe(2); |
| | }); |
| |
|
| | it('should handle fileIds parameter and filter nulls correctly', async () => { |
| | const mockFiles = [{ file_id: 'file-1' }]; |
| | const mockFileIds = ['file-2', 'non-existent-file']; |
| |
|
| | updateFileUsage.mockImplementation(({ file_id }) => { |
| | if (file_id === 'non-existent-file') { |
| | return Promise.resolve(null); |
| | } |
| | return Promise.resolve({ file_id, usage: 1 }); |
| | }); |
| |
|
| | const result = await processFiles(mockFiles, mockFileIds); |
| |
|
| | expect(result).toEqual([ |
| | { file_id: 'file-1', usage: 1 }, |
| | { file_id: 'file-2', usage: 1 }, |
| | ]); |
| | expect(result).not.toContain(null); |
| | expect(result).not.toContain(undefined); |
| | expect(result.length).toBe(2); |
| | }); |
| |
|
| | it('should handle duplicate file_ids correctly', async () => { |
| | const mockFiles = [ |
| | { file_id: 'duplicate-file' }, |
| | { file_id: 'duplicate-file' }, |
| | { file_id: 'unique-file' }, |
| | ]; |
| |
|
| | updateFileUsage.mockImplementation(({ file_id }) => { |
| | return Promise.resolve({ file_id, usage: 1 }); |
| | }); |
| |
|
| | const result = await processFiles(mockFiles); |
| |
|
| | |
| | expect(updateFileUsage).toHaveBeenCalledTimes(2); |
| | expect(result).toEqual([ |
| | { file_id: 'duplicate-file', usage: 1 }, |
| | { file_id: 'unique-file', usage: 1 }, |
| | ]); |
| | expect(result.length).toBe(2); |
| | }); |
| | }); |
| |
|
| | describe('edge cases', () => { |
| | it('should handle empty files array', async () => { |
| | const result = await processFiles([]); |
| | expect(result).toEqual([]); |
| | expect(updateFileUsage).not.toHaveBeenCalled(); |
| | }); |
| |
|
| | it('should handle mixed null and undefined returns from updateFileUsage', async () => { |
| | const mockFiles = [{ file_id: 'file-1' }, { file_id: 'file-2' }, { file_id: 'file-3' }]; |
| |
|
| | updateFileUsage.mockImplementation(({ file_id }) => { |
| | if (file_id === 'file-1') return Promise.resolve(null); |
| | if (file_id === 'file-2') return Promise.resolve(undefined); |
| | return Promise.resolve({ file_id, usage: 1 }); |
| | }); |
| |
|
| | const result = await processFiles(mockFiles); |
| |
|
| | expect(result).toEqual([{ file_id: 'file-3', usage: 1 }]); |
| | expect(result).not.toContain(null); |
| | expect(result).not.toContain(undefined); |
| | expect(result.length).toBe(1); |
| | }); |
| | }); |
| | }); |
| |
|