media-pipeline.test.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { getMediaStatus, uploadMedia } from '../../src/actions/media';
  2. import { mediaQueue } from '../../src/lib/queue/index';
  3. import { startMediaWorker } from '../../src/workers/media-processor';
  4. import * as fs from 'fs';
  5. import * as path from 'path';
  6. import * as os from 'os';
  7. import { cleanupMediaRecord } from '../helpers/media-cleanup';
  8. async function runTest() {
  9. console.log('🧪 Starting Media Pipeline Integration Test...');
  10. let exitCode = 1;
  11. let mediaId: string | null = null;
  12. // 1. Setup: Create a dummy video file (mp4)
  13. const testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-media-'));
  14. const testFilePath = path.join(testDir, 'test_video.mp4');
  15. // Note: In a real environment, we'd use a real small mp4.
  16. // For this test, we'll assume a file exists or create a dummy one if possible.
  17. if (!fs.existsSync('test_sample.mp4')) {
  18. console.error('❌ Error: Please place a small "test_sample.mp4" file in the project root for testing.');
  19. process.exit(1);
  20. }
  21. fs.copyFileSync('test_sample.mp4', testFilePath);
  22. try {
  23. await mediaQueue.drain(true);
  24. await mediaQueue.clean(0, 1000, 'failed');
  25. await mediaQueue.clean(0, 1000, 'completed');
  26. console.log('✅ Queue cleaned');
  27. // 2. Start Worker
  28. const worker = await startMediaWorker();
  29. console.log('✅ Worker started');
  30. // 3. Simulate Upload (Producer)
  31. console.log('📤 Simulating upload...');
  32. const fileMock = {
  33. name: 'e2e-pipeline-test_sample.mp4',
  34. type: 'video/mp4',
  35. size: fs.statSync(testFilePath).size,
  36. arrayBuffer: async () => {
  37. const fileBuffer = fs.readFileSync(testFilePath);
  38. return fileBuffer.buffer.slice(
  39. fileBuffer.byteOffset,
  40. fileBuffer.byteOffset + fileBuffer.byteLength
  41. );
  42. },
  43. };
  44. const record = await uploadMedia(fileMock as any);
  45. mediaId = record.media.id;
  46. console.log(`✅ Uploaded. Media ID: ${record.media.id}, Status: ${record.media.status}`);
  47. // 4. Wait for Worker to process (Polling)
  48. console.log('⏳ Waiting for worker to complete processing...');
  49. let attempts = 0;
  50. const maxAttempts = 60; // ~60 seconds
  51. let completed = false;
  52. while (attempts < maxAttempts) {
  53. await new Promise(r => setTimeout(r, 1000));
  54. const updatedRecord = await getMediaStatus(record.media.id);
  55. if (updatedRecord?.status === 'completed') {
  56. console.log('🎉 Success! Media status is COMPLETED');
  57. console.log('Metadata:', updatedRecord.metadata);
  58. console.log('HLS URL generated:', Boolean(updatedRecord.hlsUrl));
  59. completed = true;
  60. break;
  61. } else if (updatedRecord?.status === 'failed') {
  62. console.error('❌ Processing failed according to DB status');
  63. break;
  64. }
  65. attempts++;
  66. process.stdout.write('.');
  67. }
  68. if (!completed) {
  69. console.error('\n❌ Timeout: Worker did not complete processing in time.');
  70. } else {
  71. console.log('\n✨ Integration Test Passed!');
  72. exitCode = 0;
  73. }
  74. await worker.close();
  75. } catch (err) {
  76. console.error('❌ Test failed with error:', err);
  77. } finally {
  78. // Cleanup
  79. fs.rmSync(testDir, { recursive: true, force: true });
  80. if (mediaId) {
  81. await cleanupMediaRecord(mediaId);
  82. }
  83. await mediaQueue.close();
  84. process.exit(exitCode);
  85. }
  86. }
  87. runTest();