mirror of https://github.com/buster-so/buster.git
318 lines
12 KiB
TypeScript
318 lines
12 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
import { extractParamFromWhere, getElectricShapeUrl } from '.';
|
|
|
|
describe('getElectricShapeUrl', () => {
|
|
let originalElectricUrl: string | undefined;
|
|
let originalSourceId: string | undefined;
|
|
|
|
beforeEach(() => {
|
|
// Save original environment variables
|
|
originalElectricUrl = process.env.ELECTRIC_PROXY_URL;
|
|
originalSourceId = process.env.ELECTRIC_SOURCE_ID;
|
|
|
|
// Set default test values
|
|
process.env.ELECTRIC_PROXY_URL = 'http://localhost:3000';
|
|
process.env.ELECTRIC_SOURCE_ID = '';
|
|
});
|
|
|
|
afterEach(() => {
|
|
// Restore original environment variables
|
|
if (originalElectricUrl !== undefined) {
|
|
process.env.ELECTRIC_PROXY_URL = originalElectricUrl;
|
|
} else {
|
|
delete process.env.ELECTRIC_PROXY_URL;
|
|
}
|
|
|
|
if (originalSourceId !== undefined) {
|
|
process.env.ELECTRIC_SOURCE_ID = originalSourceId;
|
|
} else {
|
|
delete process.env.ELECTRIC_SOURCE_ID;
|
|
}
|
|
});
|
|
|
|
it('should return default URL with /v1/shape path when no ELECTRIC_PROXY_URL is set', () => {
|
|
const requestUrl = 'http://example.com/test?table=users';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.toString()).toBe('http://localhost:3000/v1/shape?table=users');
|
|
});
|
|
|
|
it('should use ELECTRIC_PROXY_URL environment variable when set', () => {
|
|
process.env.ELECTRIC_PROXY_URL = 'https://electric.example.com';
|
|
const requestUrl = 'http://example.com/test?table=users&live=true';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.toString()).toBe('https://electric.example.com/v1/shape?table=users&live=true');
|
|
});
|
|
|
|
it('should copy allowed query parameters', () => {
|
|
const requestUrl = 'http://example.com/test?live=true&table=users&handle=abc123&offset=100';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.searchParams.get('live')).toBe('true');
|
|
expect(result.searchParams.get('table')).toBe('users');
|
|
expect(result.searchParams.get('handle')).toBe('abc123');
|
|
expect(result.searchParams.get('offset')).toBe('100');
|
|
});
|
|
|
|
it('should copy all allowed query parameters', () => {
|
|
const allowedParams = [
|
|
'live=true',
|
|
'table=users',
|
|
'handle=abc123',
|
|
'offset=100',
|
|
'cursor=xyz789',
|
|
'where=id>10',
|
|
'params={"key":"value"}',
|
|
'columns=id,name',
|
|
'replica=primary',
|
|
'secret=secret123',
|
|
];
|
|
|
|
const requestUrl = `http://example.com/test?${allowedParams.join('&')}`;
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.searchParams.get('live')).toBe('true');
|
|
expect(result.searchParams.get('table')).toBe('users');
|
|
expect(result.searchParams.get('handle')).toBe('abc123');
|
|
expect(result.searchParams.get('offset')).toBe('100');
|
|
expect(result.searchParams.get('cursor')).toBe('xyz789');
|
|
expect(result.searchParams.get('where')).toBe('id>10');
|
|
expect(result.searchParams.get('params')).toBe('{"key":"value"}');
|
|
expect(result.searchParams.get('columns')).toBe('id,name');
|
|
expect(result.searchParams.get('replica')).toBe('primary');
|
|
expect(result.searchParams.get('secret')).toBe('secret123');
|
|
});
|
|
|
|
it('should not copy disallowed query parameters', () => {
|
|
const requestUrl = 'http://example.com/test?table=users&forbidden=value&another=param&limit=50';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.searchParams.get('table')).toBe('users');
|
|
expect(result.searchParams.get('forbidden')).toBeNull();
|
|
expect(result.searchParams.get('another')).toBeNull();
|
|
expect(result.searchParams.get('limit')).toBeNull();
|
|
});
|
|
|
|
it('should handle mixed allowed and disallowed parameters', () => {
|
|
const requestUrl =
|
|
'http://example.com/test?live=true&forbidden=value&table=users&limit=50&handle=abc';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.searchParams.get('live')).toBe('true');
|
|
expect(result.searchParams.get('table')).toBe('users');
|
|
expect(result.searchParams.get('handle')).toBe('abc');
|
|
expect(result.searchParams.get('forbidden')).toBeNull();
|
|
expect(result.searchParams.get('limit')).toBeNull();
|
|
});
|
|
|
|
it('should handle URL with no query parameters', () => {
|
|
const requestUrl = 'http://example.com/test';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.toString()).toBe('http://localhost:3000/v1/shape');
|
|
expect(result.searchParams.toString()).toBe('');
|
|
});
|
|
|
|
it('should handle empty query parameter values', () => {
|
|
const requestUrl = 'http://example.com/test?table=&live=true&handle=';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.searchParams.get('table')).toBe('');
|
|
expect(result.searchParams.get('live')).toBe('true');
|
|
expect(result.searchParams.get('handle')).toBe('');
|
|
});
|
|
|
|
it('should handle URL-encoded query parameters', () => {
|
|
const requestUrl = 'http://example.com/test?where=id%3E10¶ms=%7B%22key%22%3A%22value%22%7D';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.searchParams.get('where')).toBe('id>10');
|
|
expect(result.searchParams.get('params')).toBe('{"key":"value"}');
|
|
});
|
|
|
|
it('should handle complex where clause with special characters', () => {
|
|
const whereClause = "name='John Doe' AND age>18";
|
|
const encodedWhere = encodeURIComponent(whereClause);
|
|
const requestUrl = `http://example.com/test?table=users&where=${encodedWhere}`;
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.searchParams.get('table')).toBe('users');
|
|
expect(result.searchParams.get('where')).toBe(whereClause);
|
|
});
|
|
|
|
it('should preserve multiple values for the same parameter', () => {
|
|
// Note: URL constructor handles multiple params by taking the last value
|
|
const requestUrl = 'http://example.com/test?table=users&table=posts';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.searchParams.get('table')).toBe('posts');
|
|
});
|
|
|
|
it('should handle ELECTRIC_PROXY_URL with trailing slash', () => {
|
|
process.env.ELECTRIC_PROXY_URL = 'https://electric.example.com/';
|
|
const requestUrl = 'http://example.com/test?table=users';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.toString()).toBe('https://electric.example.com/v1/shape?table=users');
|
|
});
|
|
|
|
it('should handle ELECTRIC_PROXY_URL with path', () => {
|
|
process.env.ELECTRIC_PROXY_URL = 'https://api.example.com/electric';
|
|
const requestUrl = 'http://example.com/test?table=users';
|
|
const result = getElectricShapeUrl(requestUrl);
|
|
|
|
expect(result.toString()).toBe('https://api.example.com/v1/shape?table=users');
|
|
});
|
|
});
|
|
|
|
describe('extractParamFromWhere', () => {
|
|
it('should handle a simple where clause', () => {
|
|
const testClause = "where=id='420226c8-b91d-49c5-99f8-660b04cc8c01'&offset=-1";
|
|
const url = new URL(`https://example.com/test?${testClause}`);
|
|
const result = extractParamFromWhere(url, 'id');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('420226c8-b91d-49c5-99f8-660b04cc8c01');
|
|
});
|
|
|
|
it('should extract parameter with single quotes', () => {
|
|
const url = new URL("https://example.com/test?where=chatId='123'");
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('123');
|
|
});
|
|
|
|
it('should extract parameter with double quotes', () => {
|
|
const url = new URL('https://example.com/test?where=userId="456"');
|
|
const result = extractParamFromWhere(url, 'userId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('456');
|
|
});
|
|
|
|
it('should return null when where parameter is missing', () => {
|
|
const url = new URL('https://example.com/test?table=users');
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should return null when parameter name is not found in where clause', () => {
|
|
const url = new URL("https://example.com/test?where=otherId='123'");
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should extract parameter from complex where clause', () => {
|
|
const url = new URL(
|
|
"https://example.com/test?where=status='active' AND chatId='789' AND type='message'"
|
|
);
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('789');
|
|
});
|
|
|
|
it('should extract parameter with special characters in value', () => {
|
|
const url = new URL("https://example.com/test?where=chatId='abc-123_xyz'");
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('abc-123_xyz');
|
|
});
|
|
|
|
it('should extract parameter with numeric value', () => {
|
|
const url = new URL("https://example.com/test?where=userId='12345'");
|
|
const result = extractParamFromWhere(url, 'userId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('12345');
|
|
});
|
|
|
|
it('should handle empty where clause', () => {
|
|
const url = new URL('https://example.com/test?where=');
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should extract first occurrence when parameter appears multiple times', () => {
|
|
const url = new URL("https://example.com/test?where=chatId='first' AND chatId='second'");
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('first');
|
|
});
|
|
|
|
it('should handle URL-encoded where clause', () => {
|
|
const whereClause = "chatId='test123'";
|
|
const encodedWhere = encodeURIComponent(whereClause);
|
|
const url = new URL(`https://example.com/test?where=${encodedWhere}`);
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('test123');
|
|
});
|
|
|
|
it('should handle parameter with spaces in value', () => {
|
|
const url = new URL("https://example.com/test?where=name='John Doe'");
|
|
const result = extractParamFromWhere(url, 'name');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('John Doe');
|
|
});
|
|
|
|
it('should handle parameter with empty value', () => {
|
|
const url = new URL("https://example.com/test?where=chatId=''");
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).toBeNull(); // Empty string doesn't match the regex [^'"]+
|
|
});
|
|
|
|
it('should handle mixed quote types in same where clause', () => {
|
|
const url = new URL(`https://example.com/test?where=chatId='123' AND userId="456"`);
|
|
const result1 = extractParamFromWhere(url, 'chatId');
|
|
const result2 = extractParamFromWhere(url, 'userId');
|
|
|
|
expect(result1).not.toBeNull();
|
|
expect(result1).toBe('123');
|
|
|
|
expect(result2).not.toBeNull();
|
|
expect(result2).toBe('456');
|
|
});
|
|
|
|
it('should handle multiple paramater in a realistic example', () => {
|
|
const params = 'id="420226c8-b91d-49c5-99f8-660b04cc8c01"ANDmessage_id="123"';
|
|
const url = new URL(`https://example.com/test?where=${params}`);
|
|
const result = extractParamFromWhere(url, 'id');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('420226c8-b91d-49c5-99f8-660b04cc8c01');
|
|
|
|
const result2 = extractParamFromWhere(url, 'message_id');
|
|
|
|
expect(result2).not.toBeNull();
|
|
expect(result2).toBe('123');
|
|
});
|
|
|
|
it('should handle parameter names that are substrings of other parameters', () => {
|
|
const url = new URL("https://example.com/test?where=chatId='123' AND chatIdExtra='456'");
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe('123');
|
|
});
|
|
|
|
it('should handle parameter with UUID value', () => {
|
|
const uuid = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
|
|
const url = new URL(`https://example.com/test?where=chatId='${uuid}'`);
|
|
const result = extractParamFromWhere(url, 'chatId');
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBe(uuid);
|
|
});
|
|
});
|