| import { Providers } from '@librechat/agents'; |
| import { mbToBytes } from 'librechat-data-provider'; |
| import { validatePdf, validateVideo, validateAudio } from './validation'; |
|
|
| describe('PDF Validation with fileConfig.endpoints.*.fileSizeLimit', () => { |
| |
| const createMockPdfBuffer = (sizeInMB: number): Buffer => { |
| const bytes = Math.floor(sizeInMB * 1024 * 1024); |
| const buffer = Buffer.alloc(bytes); |
| buffer.write('%PDF-1.4\n', 0); |
| return buffer; |
| }; |
|
|
| describe('validatePdf - OpenAI provider', () => { |
| const provider = Providers.OPENAI; |
|
|
| it('should accept PDF within provider limit when no config provided', async () => { |
| const pdfBuffer = createMockPdfBuffer(8); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should reject PDF exceeding provider limit when no config provided', async () => { |
| const pdfBuffer = createMockPdfBuffer(12); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('12MB'); |
| expect(result.error).toContain('10MB'); |
| }); |
|
|
| it('should use configured limit when it is lower than provider limit', async () => { |
| const configuredLimit = 5 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(7); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('7MB'); |
| expect(result.error).toContain('5MB'); |
| }); |
|
|
| it('should allow configured limit higher than provider default', async () => { |
| const configuredLimit = 50 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(12); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should accept PDF within both configured and provider limits', async () => { |
| const configuredLimit = 50 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(8); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should accept PDF within lower configured limit', async () => { |
| const configuredLimit = 5 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(4); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should handle exact limit size correctly', async () => { |
| const configuredLimit = 10 * 1024 * 1024; |
| const pdfBuffer = Buffer.alloc(10 * 1024 * 1024); |
| pdfBuffer.write('%PDF-1.4\n', 0); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(true); |
| }); |
| }); |
|
|
| describe('validatePdf - Anthropic provider', () => { |
| const provider = Providers.ANTHROPIC; |
|
|
| it('should accept PDF within provider limit when no config provided', async () => { |
| const pdfBuffer = createMockPdfBuffer(20); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should reject PDF exceeding provider limit when no config provided', async () => { |
| const pdfBuffer = createMockPdfBuffer(35); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('35MB'); |
| expect(result.error).toContain('32MB'); |
| }); |
|
|
| it('should use configured limit when it is lower than provider limit', async () => { |
| const configuredLimit = mbToBytes(15); |
| const pdfBuffer = createMockPdfBuffer(20); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('20MB'); |
| expect(result.error).toContain('15MB'); |
| }); |
|
|
| it('should allow configured limit higher than provider default', async () => { |
| const configuredLimit = mbToBytes(50); |
| const pdfBuffer = createMockPdfBuffer(35); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should reject encrypted PDFs regardless of size', async () => { |
| const pdfBuffer = Buffer.alloc(1024); |
| pdfBuffer.write('%PDF-1.4\n', 0); |
| pdfBuffer.write('/Encrypt ', 100); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('encrypted'); |
| }); |
|
|
| it('should reject PDFs with invalid header', async () => { |
| const pdfBuffer = Buffer.alloc(1024); |
| pdfBuffer.write('INVALID', 0); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('PDF header'); |
| }); |
|
|
| it('should reject PDFs that are too small', async () => { |
| const pdfBuffer = Buffer.alloc(3); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('too small'); |
| }); |
| }); |
|
|
| describe('validatePdf - Google provider', () => { |
| const provider = Providers.GOOGLE; |
|
|
| it('should accept PDF within provider limit when no config provided', async () => { |
| const pdfBuffer = createMockPdfBuffer(15); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should reject PDF exceeding provider limit when no config provided', async () => { |
| const pdfBuffer = createMockPdfBuffer(25); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('25MB'); |
| expect(result.error).toContain('20MB'); |
| }); |
|
|
| it('should use configured limit when it is lower than provider limit', async () => { |
| const configuredLimit = 10 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(15); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('15MB'); |
| expect(result.error).toContain('10MB'); |
| }); |
|
|
| it('should allow configured limit higher than provider default', async () => { |
| const configuredLimit = 50 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(25); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
| }); |
|
|
| describe('validatePdf - VertexAI provider', () => { |
| const provider = Providers.VERTEXAI; |
|
|
| it('should accept PDF within provider limit', async () => { |
| const pdfBuffer = createMockPdfBuffer(15); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| }); |
|
|
| it('should respect configured limit', async () => { |
| const configuredLimit = 10 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(15); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('10MB'); |
| }); |
| }); |
|
|
| describe('validatePdf - Azure OpenAI provider', () => { |
| const provider = Providers.AZURE; |
|
|
| it('should accept PDF within OpenAI-like provider limit', async () => { |
| const pdfBuffer = createMockPdfBuffer(8); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| }); |
|
|
| it('should respect configured limit for Azure', async () => { |
| const configuredLimit = 5 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(7); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider, configuredLimit); |
|
|
| expect(result.isValid).toBe(false); |
| }); |
| }); |
|
|
| describe('validatePdf - Unsupported providers', () => { |
| it('should return valid for providers without specific validation', async () => { |
| const pdfBuffer = createMockPdfBuffer(100); |
| const provider = 'unsupported' as Providers; |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| }); |
| }); |
|
|
| describe('Edge cases', () => { |
| it('should handle zero-configured limit', async () => { |
| const configuredLimit = 0; |
| const pdfBuffer = createMockPdfBuffer(1); |
| const result = await validatePdf( |
| pdfBuffer, |
| pdfBuffer.length, |
| Providers.OPENAI, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('0MB'); |
| }); |
|
|
| it('should handle very small PDF files', async () => { |
| const pdfBuffer = Buffer.alloc(100); |
| pdfBuffer.write('%PDF-1.4\n', 0); |
| const result = await validatePdf( |
| pdfBuffer, |
| pdfBuffer.length, |
| Providers.OPENAI, |
| 10 * 1024 * 1024, |
| ); |
|
|
| expect(result.isValid).toBe(true); |
| }); |
|
|
| it('should handle configured limit equal to provider limit', async () => { |
| const configuredLimit = 10 * 1024 * 1024; |
| const pdfBuffer = createMockPdfBuffer(12); |
| const result = await validatePdf( |
| pdfBuffer, |
| pdfBuffer.length, |
| Providers.OPENAI, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('10MB'); |
| }); |
|
|
| it('should use provider limit when configured limit is undefined', async () => { |
| const pdfBuffer = createMockPdfBuffer(12); |
| const result = await validatePdf(pdfBuffer, pdfBuffer.length, Providers.OPENAI, undefined); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('10MB'); |
| }); |
| }); |
|
|
| describe('Bug reproduction - Original issue', () => { |
| it('should reproduce the original bug scenario from issue description', async () => { |
| |
| |
| |
| |
| |
| |
| const configuredLimit = mbToBytes(50); |
| const pdfBuffer = createMockPdfBuffer(15); |
|
|
| const result = await validatePdf( |
| pdfBuffer, |
| pdfBuffer.length, |
| Providers.OPENAI, |
| configuredLimit, |
| ); |
|
|
| |
| |
| |
| |
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should allow user to set stricter limits than provider', async () => { |
| |
| |
| |
| |
| |
| |
| const configuredLimit = mbToBytes(5); |
| const pdfBuffer = createMockPdfBuffer(7); |
|
|
| const result = await validatePdf( |
| pdfBuffer, |
| pdfBuffer.length, |
| Providers.OPENAI, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('7MB'); |
| expect(result.error).toContain('5MB'); |
| }); |
|
|
| it('should allow upload within stricter user-configured limit', async () => { |
| |
| |
| |
| |
| |
| const configuredLimit = mbToBytes(5); |
| const pdfBuffer = createMockPdfBuffer(4); |
|
|
| const result = await validatePdf( |
| pdfBuffer, |
| pdfBuffer.length, |
| Providers.OPENAI, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
| }); |
|
|
| describe('Video and Audio Validation with fileConfig', () => { |
| |
| const createMockMediaBuffer = (sizeInMB: number): Buffer => { |
| const bytes = Math.floor(sizeInMB * 1024 * 1024); |
| return Buffer.alloc(bytes); |
| }; |
|
|
| describe('validateVideo - Google provider', () => { |
| const provider = Providers.GOOGLE; |
|
|
| it('should accept video within provider limit when no config provided', async () => { |
| const videoBuffer = createMockMediaBuffer(15); |
| const result = await validateVideo(videoBuffer, videoBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should reject video exceeding provider limit when no config provided', async () => { |
| const videoBuffer = createMockMediaBuffer(25); |
| const result = await validateVideo(videoBuffer, videoBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('25MB'); |
| expect(result.error).toContain('20MB'); |
| }); |
|
|
| it('should use configured limit when it is lower than provider limit', async () => { |
| const configuredLimit = mbToBytes(10); |
| const videoBuffer = createMockMediaBuffer(15); |
| const result = await validateVideo( |
| videoBuffer, |
| videoBuffer.length, |
| provider, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('15MB'); |
| expect(result.error).toContain('10MB'); |
| }); |
|
|
| it('should allow configured limit higher than provider default', async () => { |
| const configuredLimit = mbToBytes(50); |
| const videoBuffer = createMockMediaBuffer(25); |
| const result = await validateVideo( |
| videoBuffer, |
| videoBuffer.length, |
| provider, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should accept video within lower configured limit', async () => { |
| const configuredLimit = mbToBytes(8); |
| const videoBuffer = createMockMediaBuffer(7); |
| const result = await validateVideo( |
| videoBuffer, |
| videoBuffer.length, |
| provider, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should reject videos that are too small', async () => { |
| const videoBuffer = Buffer.alloc(5); |
| const result = await validateVideo(videoBuffer, videoBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('too small'); |
| }); |
| }); |
|
|
| describe('validateAudio - Google provider', () => { |
| const provider = Providers.GOOGLE; |
|
|
| it('should accept audio within provider limit when no config provided', async () => { |
| const audioBuffer = createMockMediaBuffer(15); |
| const result = await validateAudio(audioBuffer, audioBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should reject audio exceeding provider limit when no config provided', async () => { |
| const audioBuffer = createMockMediaBuffer(25); |
| const result = await validateAudio(audioBuffer, audioBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('25MB'); |
| expect(result.error).toContain('20MB'); |
| }); |
|
|
| it('should use configured limit when it is lower than provider limit', async () => { |
| const configuredLimit = mbToBytes(10); |
| const audioBuffer = createMockMediaBuffer(15); |
| const result = await validateAudio( |
| audioBuffer, |
| audioBuffer.length, |
| provider, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('15MB'); |
| expect(result.error).toContain('10MB'); |
| }); |
|
|
| it('should allow configured limit higher than provider default', async () => { |
| const configuredLimit = mbToBytes(50); |
| const audioBuffer = createMockMediaBuffer(25); |
| const result = await validateAudio( |
| audioBuffer, |
| audioBuffer.length, |
| provider, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should accept audio within lower configured limit', async () => { |
| const configuredLimit = mbToBytes(8); |
| const audioBuffer = createMockMediaBuffer(7); |
| const result = await validateAudio( |
| audioBuffer, |
| audioBuffer.length, |
| provider, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(true); |
| expect(result.error).toBeUndefined(); |
| }); |
|
|
| it('should reject audio files that are too small', async () => { |
| const audioBuffer = Buffer.alloc(5); |
| const result = await validateAudio(audioBuffer, audioBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('too small'); |
| }); |
| }); |
|
|
| describe('validateVideo and validateAudio - VertexAI provider', () => { |
| const provider = Providers.VERTEXAI; |
|
|
| it('should respect configured video limit for VertexAI', async () => { |
| const configuredLimit = mbToBytes(10); |
| const videoBuffer = createMockMediaBuffer(15); |
| const result = await validateVideo( |
| videoBuffer, |
| videoBuffer.length, |
| provider, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('10MB'); |
| }); |
|
|
| it('should respect configured audio limit for VertexAI', async () => { |
| const configuredLimit = mbToBytes(10); |
| const audioBuffer = createMockMediaBuffer(15); |
| const result = await validateAudio( |
| audioBuffer, |
| audioBuffer.length, |
| provider, |
| configuredLimit, |
| ); |
|
|
| expect(result.isValid).toBe(false); |
| expect(result.error).toContain('10MB'); |
| }); |
| }); |
|
|
| describe('validateVideo and validateAudio - Unsupported providers', () => { |
| it('should return valid for video from unsupported provider', async () => { |
| const videoBuffer = createMockMediaBuffer(100); |
| const provider = Providers.OPENAI; |
| const result = await validateVideo(videoBuffer, videoBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| }); |
|
|
| it('should return valid for audio from unsupported provider', async () => { |
| const audioBuffer = createMockMediaBuffer(100); |
| const provider = Providers.OPENAI; |
| const result = await validateAudio(audioBuffer, audioBuffer.length, provider); |
|
|
| expect(result.isValid).toBe(true); |
| }); |
| }); |
| }); |
| }); |
|
|