import {describe, it, expect, beforeEach, afterEach} from 'bun:test'; import {RtmpPush} from '../src/RtmpPush'; describe('RtmpPush Integration Tests', () => { let rtmpPush: RtmpPush; const testMediaSourceUri = 'https://storage.googleapis.com/phenix-testing-assets/timecodes/haivision-with-sei-system-source-timecodes-utc-conversion-counting-mode-h264-constrained-baseline-1920x1080p-cbr-8700kbps-60fps-aac-lc-48000hz-stereo-124kbps-5m00s.ts'; const testRtmpIngestUri = 'rtmp://ingest-stg.phenixrts.com:80/ingest'; beforeEach(() => { rtmpPush = new RtmpPush(testMediaSourceUri, testRtmpIngestUri); }); afterEach(() => { // Always clean up if (rtmpPush.isRunning()) { rtmpPush.stop(); } }); describe('Real Process Management', () => { it('should create instance with real URIs', () => { expect(rtmpPush).toBeInstanceOf(RtmpPush); expect(rtmpPush.mediaSourceUri).toBe(testMediaSourceUri); expect(rtmpPush.rtmpIngestUri).toBe(testRtmpIngestUri); }); it('should handle invalid ffmpeg gracefully', () => { // Test with a non-existent command by using invalid URIs const invalidRtmpPush = new RtmpPush('invalid://uri', 'invalid://rtmp'); try { invalidRtmpPush.start('test', ['h264']); // If it doesn't throw, it should at least not be running expect(invalidRtmpPush.isRunning()).toBe(false); } catch (error) { // Expected to fail expect(error).toBeInstanceOf(Error); } }); }); describe('URI Construction', () => { it('should construct valid RTMP URIs', () => { const streamKey = 'test-stream-key'; const capabilities = ['h264', 'aac', 'stereo']; const expectedUri = `${testRtmpIngestUri}/${streamKey};capabilities=${capabilities.join(',')};tags=`; // The URI should be properly formatted expect(expectedUri).toContain(streamKey); expect(expectedUri).toContain(capabilities.join(',')); expect(expectedUri).toContain(';capabilities='); expect(expectedUri).toContain(';tags='); }); it('should handle various stream key formats', () => { const testCases = ['simple-key', 'key_with_underscores', 'key-with-dashes', 'key123', 'key!@#$%^&*()', 'key with spaces', 'key.with.dots']; testCases.forEach(streamKey => { const capabilities = ['h264']; const expectedIngestUri = `${testRtmpIngestUri}/${streamKey};capabilities=${capabilities.join(',')};tags=`; expect(expectedIngestUri).toContain(streamKey); expect(expectedIngestUri).toContain(';capabilities=h264;tags='); }); }); }); describe('Error Handling', () => { it('should handle network errors gracefully', () => { const invalidMediaUri = 'https://invalid-domain-that-does-not-exist.com/video.ts'; const invalidRtmpPush = new RtmpPush(invalidMediaUri, testRtmpIngestUri); try { invalidRtmpPush.start('test', ['h264']); // If it doesn't throw, it should at least not be running expect(invalidRtmpPush.isRunning()).toBe(false); } catch (error) { // Expected to fail expect(error).toBeInstanceOf(Error); } }); it('should handle invalid RTMP URIs', () => { const invalidRtmpUri = 'invalid://rtmp-uri'; const invalidRtmpPush = new RtmpPush(testMediaSourceUri, invalidRtmpUri); try { invalidRtmpPush.start('test', ['h264']); // If it doesn't throw, it should at least not be running expect(invalidRtmpPush.isRunning()).toBe(false); } catch (error) { // Expected to fail expect(error).toBeInstanceOf(Error); } }); }); describe('Process Lifecycle', () => { it('should maintain consistent state', () => { expect(rtmpPush.isRunning()).toBe(false); // Stop when not running should not change state rtmpPush.stop(); expect(rtmpPush.isRunning()).toBe(false); // Multiple stops should not cause issues rtmpPush.stop().stop().stop(); expect(rtmpPush.isRunning()).toBe(false); }); }); });