251 lines
8.2 KiB
TypeScript
251 lines
8.2 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
serializeBaggage,
|
|
parseBaggage,
|
|
createBaggageFromTransaction,
|
|
} from '../src/utils/baggage';
|
|
import type { BaggageFields } from '../src/types';
|
|
|
|
describe('baggage utils', () => {
|
|
describe('serializeBaggage', () => {
|
|
it('should serialize empty baggage', () => {
|
|
const result = serializeBaggage({});
|
|
expect(result).toBe('');
|
|
});
|
|
|
|
it('should serialize baggage with all fields', () => {
|
|
const baggage: BaggageFields = {
|
|
trace_id: 'abc123',
|
|
public_key: 'key123',
|
|
sample_rate: '0.5',
|
|
sampled: 'true',
|
|
user_id: 'user1',
|
|
user_segment: 'premium',
|
|
release: '1.0.0',
|
|
environment: 'production',
|
|
};
|
|
|
|
const result = serializeBaggage(baggage);
|
|
|
|
expect(result).toContain('sentry-trace_id=abc123');
|
|
expect(result).toContain('sentry-public_key=key123');
|
|
expect(result).toContain('sentry-sample_rate=0.5');
|
|
expect(result).toContain('sentry-sampled=true');
|
|
expect(result).toContain('sentry-user_id=user1');
|
|
expect(result).toContain('sentry-user_segment=premium');
|
|
expect(result).toContain('sentry-release=1.0.0');
|
|
expect(result).toContain('sentry-environment=production');
|
|
});
|
|
|
|
it('should skip null, undefined, and empty string values', () => {
|
|
const baggage: BaggageFields = {
|
|
trace_id: 'abc123',
|
|
public_key: undefined as any,
|
|
sampled: '',
|
|
};
|
|
|
|
const result = serializeBaggage(baggage);
|
|
|
|
expect(result).toContain('sentry-trace_id=abc123');
|
|
expect(result).not.toContain('public_key');
|
|
expect(result).not.toContain('sampled');
|
|
});
|
|
|
|
it('should add sentry- prefix to non-sentry keys', () => {
|
|
const baggage: BaggageFields = {
|
|
trace_id: 'abc123',
|
|
custom_field: 'value',
|
|
};
|
|
|
|
const result = serializeBaggage(baggage);
|
|
|
|
expect(result).toContain('sentry-trace_id=abc123');
|
|
expect(result).toContain('sentry-custom_field=value');
|
|
});
|
|
|
|
it('should preserve sentry- prefix on sentry keys', () => {
|
|
const baggage: BaggageFields = {
|
|
'sentry-trace_id': 'abc123',
|
|
};
|
|
|
|
const result = serializeBaggage(baggage);
|
|
|
|
expect(result).toContain('sentry-trace_id=abc123');
|
|
// Should not double-prefix
|
|
expect(result).not.toContain('sentry-sentry-');
|
|
});
|
|
|
|
it('should truncate long baggage to 8192 characters', () => {
|
|
const longBaggage: BaggageFields = {};
|
|
// Create a very long value
|
|
const longValue = 'a'.repeat(10000);
|
|
longBaggage.trace_id = longValue;
|
|
|
|
const result = serializeBaggage(longBaggage);
|
|
|
|
expect(result.length).toBeLessThanOrEqual(8192);
|
|
});
|
|
|
|
it('should URL encode values', () => {
|
|
const baggage: BaggageFields = {
|
|
user_id: 'user with spaces',
|
|
custom_field: 'value=special&chars',
|
|
};
|
|
|
|
const result = serializeBaggage(baggage);
|
|
|
|
expect(result).toContain(encodeURIComponent('user with spaces'));
|
|
expect(result).toContain(encodeURIComponent('value=special&chars'));
|
|
});
|
|
});
|
|
|
|
describe('parseBaggage', () => {
|
|
it('should parse empty baggage', () => {
|
|
const result = parseBaggage('');
|
|
expect(result).toEqual({});
|
|
});
|
|
|
|
it('should parse valid baggage header', () => {
|
|
const header = 'sentry-trace_id=abc123,sentry-sampled=true,sentry-user_id=user1';
|
|
const result = parseBaggage(header);
|
|
|
|
expect(result.trace_id).toBe('abc123');
|
|
expect(result.sampled).toBe('true');
|
|
expect(result.user_id).toBe('user1');
|
|
});
|
|
|
|
it('should remove sentry- prefix from keys', () => {
|
|
const header = 'sentry-public_key=key123,sentry-release=1.0.0';
|
|
const result = parseBaggage(header);
|
|
|
|
expect(result.public_key).toBe('key123');
|
|
expect(result.release).toBe('1.0.0');
|
|
expect(result['sentry-public_key']).toBeUndefined();
|
|
});
|
|
|
|
it('should handle custom fields without prefix', () => {
|
|
const header = 'custom_field=value,another=data';
|
|
const result = parseBaggage(header);
|
|
|
|
expect(result.custom_field).toBe('value');
|
|
expect(result.another).toBe('data');
|
|
});
|
|
|
|
it('should URL decode values', () => {
|
|
const header = `sentry-user_id=${encodeURIComponent('user with spaces')}`;
|
|
const result = parseBaggage(header);
|
|
|
|
expect(result.user_id).toBe('user with spaces');
|
|
});
|
|
|
|
it('should skip malformed entries', () => {
|
|
const header = 'valid=key,invalid-entry-no-equals,sentry-trace_id=abc123';
|
|
const result = parseBaggage(header);
|
|
|
|
expect(result.valid).toBe('key');
|
|
expect(result['sentry-trace_id']).toBeUndefined();
|
|
expect(result.trace_id).toBe('abc123');
|
|
});
|
|
|
|
it('should handle whitespace around entries', () => {
|
|
const header = ' sentry-trace_id=abc123 , sentry-sampled=true ';
|
|
const result = parseBaggage(header);
|
|
|
|
expect(result.trace_id).toBe('abc123');
|
|
expect(result.sampled).toBe('true');
|
|
});
|
|
});
|
|
|
|
describe('createBaggageFromTransaction', () => {
|
|
it('should create baggage with only trace_id', () => {
|
|
const result = createBaggageFromTransaction('abc123');
|
|
|
|
expect(result.trace_id).toBe('abc123');
|
|
expect(Object.keys(result)).toHaveLength(1);
|
|
});
|
|
|
|
it('should create baggage with all options', () => {
|
|
const result = createBaggageFromTransaction('abc123', {
|
|
dsnPublicKey: 'key123',
|
|
sampled: true,
|
|
sampleRate: 0.5,
|
|
user: { id: 'user1', segment: 'premium' },
|
|
release: '1.0.0',
|
|
environment: 'production',
|
|
});
|
|
|
|
expect(result.trace_id).toBe('abc123');
|
|
expect(result.public_key).toBe('key123');
|
|
expect(result.sampled).toBe('true');
|
|
expect(result.sample_rate).toBe('0.5');
|
|
expect(result.user_id).toBe('user1');
|
|
expect(result.user_segment).toBe('premium');
|
|
expect(result.release).toBe('1.0.0');
|
|
expect(result.environment).toBe('production');
|
|
});
|
|
|
|
it('should convert sampled boolean to string', () => {
|
|
expect(createBaggageFromTransaction('abc', { sampled: true }).sampled).toBe('true');
|
|
expect(createBaggageFromTransaction('abc', { sampled: false }).sampled).toBe('false');
|
|
});
|
|
|
|
it('should convert sampleRate number to string', () => {
|
|
const result = createBaggageFromTransaction('abc', { sampleRate: 0.1 });
|
|
expect(result.sample_rate).toBe('0.1');
|
|
});
|
|
|
|
it('should handle optional user object', () => {
|
|
const result1 = createBaggageFromTransaction('abc', { user: { id: 'user1' } });
|
|
expect(result1.user_id).toBe('user1');
|
|
expect(result1.user_segment).toBeUndefined();
|
|
|
|
const result2 = createBaggageFromTransaction('abc', { user: { id: 'user2', segment: 'vip' } });
|
|
expect(result2.user_id).toBe('user2');
|
|
expect(result2.user_segment).toBe('vip');
|
|
});
|
|
|
|
it('should not include undefined options', () => {
|
|
const result = createBaggageFromTransaction('abc', {
|
|
dsnPublicKey: 'key',
|
|
sampled: undefined,
|
|
sampleRate: undefined,
|
|
});
|
|
|
|
expect(result.trace_id).toBe('abc');
|
|
expect(result.public_key).toBe('key');
|
|
expect(result.sampled).toBeUndefined();
|
|
expect(result.sample_rate).toBeUndefined();
|
|
});
|
|
|
|
it('should work without options', () => {
|
|
const result = createBaggageFromTransaction('abc');
|
|
expect(result.trace_id).toBe('abc');
|
|
});
|
|
});
|
|
|
|
describe('serialize/parse roundtrip', () => {
|
|
it('should preserve baggage through serialize/parse cycle', () => {
|
|
const original: BaggageFields = {
|
|
trace_id: 'abc123',
|
|
public_key: 'key123',
|
|
sampled: 'true',
|
|
user_id: 'user1',
|
|
release: '1.0.0',
|
|
environment: 'production',
|
|
custom: 'value',
|
|
};
|
|
|
|
const serialized = serializeBaggage(original);
|
|
const parsed = parseBaggage(serialized);
|
|
|
|
expect(parsed.trace_id).toBe(original.trace_id);
|
|
expect(parsed.public_key).toBe(original.public_key);
|
|
expect(parsed.sampled).toBe(original.sampled);
|
|
expect(parsed.user_id).toBe(original.user_id);
|
|
expect(parsed.release).toBe(original.release);
|
|
expect(parsed.environment).toBe(original.environment);
|
|
expect(parsed.custom).toBe(original.custom);
|
|
});
|
|
});
|
|
});
|