UNPKG

@aj-archipelago/cortex

Version:

Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.

267 lines (215 loc) 10.2 kB
// shortLivedUrl.test.js // Unit tests for short-lived URL functionality import test from 'ava'; import sinon from 'sinon'; import { checkHashExists, ensureShortLivedUrl } from '../../../lib/fileUtils.js'; import { axios } from '../../../lib/requestExecutor.js'; test.beforeEach(t => { t.context.sandbox = sinon.createSandbox(); }); test.afterEach.always(t => { t.context.sandbox.restore(); }); test('checkHashExists should return long-lived URL for storage', async t => { const hash = 'test-hash-123'; const fileHandlerUrl = 'https://file-handler.example.com'; const mockResponse = { status: 200, data: { url: 'https://storage.example.com/file.pdf?sv=2023-11-03&se=2025-01-01T00:00:00Z&sig=long-lived', shortLivedUrl: 'https://storage.example.com/file.pdf?sv=2023-11-03&se=2024-01-01T10:15:00Z&sig=short-lived', gcs: 'gs://bucket/file.pdf', hash: hash, filename: 'file.pdf' } }; const axiosGetStub = t.context.sandbox.replace(axios, 'get', sinon.stub().resolves(mockResponse)); const result = await checkHashExists(hash, fileHandlerUrl); t.truthy(result); t.is(result.url, mockResponse.data.url, 'Should return long-lived URL for storage'); t.is(result.gcs, mockResponse.data.gcs, 'Should return GCS URL'); t.is(result.hash, hash, 'Should return hash'); // Verify axios was called with correct parameters t.true(axiosGetStub.calledOnce); const callArgs = axiosGetStub.getCall(0).args; t.true(callArgs[0].includes('checkHash=true')); }); test('checkHashExists should fallback to regular URL when shortLivedUrl not available', async t => { const hash = 'test-hash-456'; const fileHandlerUrl = 'https://file-handler.example.com'; const mockResponse = { status: 200, data: { url: 'https://storage.example.com/file.pdf?sv=2023-11-03&se=2025-01-01T00:00:00Z&sig=long-lived', // No shortLivedUrl in response gcs: 'gs://bucket/file.pdf', hash: hash, filename: 'file.pdf' } }; t.context.sandbox.replace(axios, 'get', sinon.stub().resolves(mockResponse)); const result = await checkHashExists(hash, fileHandlerUrl); t.truthy(result); t.is(result.url, mockResponse.data.url, 'Should fallback to regular URL'); t.is(result.gcs, mockResponse.data.gcs, 'Should return GCS URL'); }); test('checkHashExists should prefer converted URL for storage', async t => { const hash = 'test-hash-789'; const fileHandlerUrl = 'https://file-handler.example.com'; const mockResponse = { status: 200, data: { url: 'https://storage.example.com/file.xlsx?sv=2023-11-03&se=2025-01-01T00:00:00Z&sig=long-lived', shortLivedUrl: 'https://storage.example.com/file.xlsx?sv=2023-11-03&se=2024-01-01T10:15:00Z&sig=short-lived', converted: { url: 'https://storage.example.com/file.csv?sv=2023-11-03&se=2025-01-01T00:00:00Z&sig=long-lived', shortLivedUrl: 'https://storage.example.com/file.csv?sv=2023-11-03&se=2024-01-01T10:15:00Z&sig=short-lived', gcs: 'gs://bucket/file.csv' }, gcs: 'gs://bucket/file.xlsx', hash: hash } }; t.context.sandbox.replace(axios, 'get', sinon.stub().resolves(mockResponse)); const result = await checkHashExists(hash, fileHandlerUrl); t.truthy(result); // Should prefer converted.url (long-lived) for storage, then fallback to original url t.is(result.url, mockResponse.data.converted.url, 'Should prefer converted.url (long-lived) for storage'); // GCS should prefer converted t.is(result.gcs, mockResponse.data.converted.gcs, 'Should prefer converted GCS URL'); }); test('checkHashExists should return null when file not found', async t => { const hash = 'non-existent-hash'; const fileHandlerUrl = 'https://file-handler.example.com'; const mockResponse = { status: 404, data: { message: 'File not found' } }; t.context.sandbox.replace(axios, 'get', sinon.stub().resolves(mockResponse)); const result = await checkHashExists(hash, fileHandlerUrl); t.is(result, null, 'Should return null when file not found'); }); test('checkHashExists should return null when hash or fileHandlerUrl missing', async t => { t.is(await checkHashExists(null, 'https://file-handler.example.com'), null); t.is(await checkHashExists('hash-123', null), null); t.is(await checkHashExists('', 'https://file-handler.example.com'), null); }); test('checkHashExists should handle errors gracefully', async t => { const hash = 'test-hash-error'; const fileHandlerUrl = 'https://file-handler.example.com'; t.context.sandbox.replace(axios, 'get', sinon.stub().rejects(new Error('Network error'))); const result = await checkHashExists(hash, fileHandlerUrl); t.is(result, null, 'Should return null on error'); }); test('ensureShortLivedUrl should resolve file to short-lived URL when hash available', async t => { const fileObject = { url: 'https://storage.example.com/file.pdf?sv=2023-11-03&se=2025-01-01T00:00:00Z&sig=long-lived', gcs: 'gs://bucket/file.pdf', hash: 'test-hash-123', filename: 'file.pdf' }; const fileHandlerUrl = 'https://file-handler.example.com'; const shortLivedUrl = 'https://storage.example.com/file.pdf?sv=2023-11-03&se=2024-01-01T10:15:00Z&sig=short-lived'; const mockResponse = { status: 200, data: { url: fileObject.url, shortLivedUrl: shortLivedUrl, gcs: fileObject.gcs, hash: fileObject.hash } }; const axiosGetStub = t.context.sandbox.replace(axios, 'get', sinon.stub().resolves(mockResponse)); const result = await ensureShortLivedUrl(fileObject, fileHandlerUrl); t.truthy(result); t.is(result.url, shortLivedUrl, 'Should use short-lived URL'); t.is(result.gcs, fileObject.gcs, 'Should preserve GCS URL'); t.is(result.hash, fileObject.hash, 'Should preserve hash'); t.is(result.filename, fileObject.filename, 'Should preserve filename'); // Verify axios was called with shortLivedMinutes parameter t.true(axiosGetStub.calledOnce); const callArgs = axiosGetStub.getCall(0).args; t.true(callArgs[0].includes('shortLivedMinutes=5')); }); test('ensureShortLivedUrl should return original object when no hash', async t => { const fileObject = { url: 'https://storage.example.com/file.pdf', filename: 'file.pdf' // No hash }; const fileHandlerUrl = 'https://file-handler.example.com'; const result = await ensureShortLivedUrl(fileObject, fileHandlerUrl); t.deepEqual(result, fileObject, 'Should return original object when no hash'); }); test('ensureShortLivedUrl should return original object when no fileHandlerUrl', async t => { const fileObject = { url: 'https://storage.example.com/file.pdf', hash: 'test-hash-123', filename: 'file.pdf' }; const result = await ensureShortLivedUrl(fileObject, null); t.deepEqual(result, fileObject, 'Should return original object when no fileHandlerUrl'); }); test('ensureShortLivedUrl should fallback to original object on error', async t => { const fileObject = { url: 'https://storage.example.com/file.pdf', hash: 'test-hash-error', filename: 'file.pdf' }; const fileHandlerUrl = 'https://file-handler.example.com'; t.context.sandbox.replace(axios, 'get', sinon.stub().rejects(new Error('Network error'))); const result = await ensureShortLivedUrl(fileObject, fileHandlerUrl); t.deepEqual(result, fileObject, 'Should fallback to original object on error'); }); test('ensureShortLivedUrl should prefer converted.shortLivedUrl and update GCS URL', async t => { const fileObject = { url: 'https://storage.example.com/file.xlsx', gcs: 'gs://bucket/file.xlsx', hash: 'test-hash-789', filename: 'file.xlsx' }; const fileHandlerUrl = 'https://file-handler.example.com'; const convertedGcs = 'gs://bucket/file.csv'; const convertedShortLivedUrl = 'https://storage.example.com/file.csv?sv=2023-11-03&se=2024-01-01T10:15:00Z&sig=short-lived'; const mockResponse = { status: 200, data: { url: fileObject.url, shortLivedUrl: 'https://storage.example.com/file.xlsx?sv=2023-11-03&se=2024-01-01T10:15:00Z&sig=short-lived', converted: { url: 'https://storage.example.com/file.csv', shortLivedUrl: convertedShortLivedUrl, gcs: convertedGcs }, gcs: fileObject.gcs, hash: fileObject.hash } }; t.context.sandbox.replace(axios, 'get', sinon.stub().resolves(mockResponse)); const result = await ensureShortLivedUrl(fileObject, fileHandlerUrl); t.truthy(result); t.is(result.url, convertedShortLivedUrl, 'Should prefer converted.shortLivedUrl for LLM processing'); t.is(result.gcs, convertedGcs, 'Should update GCS URL from converted'); }); test('ensureShortLivedUrl should respect shortLivedMinutes parameter', async t => { const fileObject = { url: 'https://storage.example.com/file.pdf', hash: 'test-hash-123', filename: 'file.pdf' }; const fileHandlerUrl = 'https://file-handler.example.com'; const shortLivedMinutes = 10; const mockResponse = { status: 200, data: { url: fileObject.url, shortLivedUrl: 'https://storage.example.com/file.pdf?sv=2023-11-03&se=2024-01-01T10:15:00Z&sig=short-lived', hash: fileObject.hash } }; const axiosGetStub = t.context.sandbox.replace(axios, 'get', sinon.stub().resolves(mockResponse)); await ensureShortLivedUrl(fileObject, fileHandlerUrl, null, shortLivedMinutes); // Verify axios was called with correct shortLivedMinutes const callArgs = axiosGetStub.getCall(0).args; t.true(callArgs[0].includes(`shortLivedMinutes=${shortLivedMinutes}`)); });