/** * JavaScript Mix Payloads Receiver Test * Tests the smartreceive function with mixed payload types */ const NATSBridge = require('../src/natsbridge.js'); const nats = require('nats'); const crypto = require('crypto'); const TEST_SUBJECT = '/test/mix'; const TEST_BROKER_URL = process.env.NATS_URL || 'nats://localhost:4222'; const TEST_FILESERVER_URL = process.env.FILESERVER_URL || 'http://localhost:8080'; async function runTest() { console.log('=== JavaScript Mix Payloads Receiver Test ===\n'); const correlationId = crypto.randomUUID(); console.log(`Correlation ID: ${correlationId}`); console.log(`Subject: ${TEST_SUBJECT}`); console.log(`Broker URL: ${TEST_BROKER_URL}\n`); // Expected test data - same as sender const expectedTextData = 'Hello, NATSBridge!'; const expectedDictData = { key1: 'value1', key2: 42, nested: { a: 1, b: 2 } }; const expectedBinaryData = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]); // PNG header const expectedTableData = [ { id: 1, name: 'Alice', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 3, name: 'Charlie', age: 35 } ]; const expectedDatanames = ['message', 'config', 'image', 'users']; const expectedTypes = ['text', 'dictionary', 'image', 'table']; let testPassed = true; let messagesReceived = 0; const receivedPayloads = []; try { // Connect to NATS console.log('Connecting to NATS server...'); const nc = await nats.connect({ servers: TEST_BROKER_URL }); console.log('✅ Connected to NATS server\n'); // Set up message subscription const subscription = nc.subscribe(TEST_SUBJECT); // Wait for messages with timeout const messagePromise = new Promise(async (resolve, reject) => { const timeout = setTimeout(() => { resolve('timeout'); }, 10000); // 10 second timeout (async () => { for await (const msg of subscription) { clearTimeout(timeout); messagesReceived++; console.log(`\n=== Message ${messagesReceived} Received ===`); console.log(`Raw payload length: ${msg.payload.length} bytes`); try { // Process the message using smartreceive const envelope = await NATSBridge.smartreceive(msg, { fileserver_download_handler: NATSBridge.fetchWithBackoff, max_retries: 5, base_delay: 100, max_delay: 5000 }); console.log(`Correlation ID: ${envelope.correlation_id}`); console.log(`Message ID: ${envelope.msg_id}`); console.log(`Number of payloads: ${envelope.payloads.length}`); receivedPayloads.push(envelope); // Validate envelope structure console.log('\n=== Envelope Validation ==='); if (envelope.payloads.length < 4) { console.log(`❌ Expected at least 4 payloads, got ${envelope.payloads.length}`); testPassed = false; } else { console.log(`✅ Correct number of payloads: ${envelope.payloads.length}`); } // Validate each payload for (let i = 0; i < envelope.payloads.length; i++) { const [dataname, data, dataType] = envelope.payloads[i]; console.log(`\n--- Payload ${i + 1}: ${dataname} (type: ${dataType}) ---`); // Check dataname if (i < expectedDatanames.length && dataname !== expectedDatanames[i]) { console.log(`❌ Expected dataname '${expectedDatanames[i]}', got '${dataname}'`); testPassed = false; } else { console.log(`✅ Correct dataname: ${dataname}`); } // Check data type if (i < expectedTypes.length && dataType !== expectedTypes[i]) { console.log(`❌ Expected type '${expectedTypes[i]}', got '${dataType}'`); testPassed = false; } else { console.log(`✅ Correct type: ${dataType}`); } // Validate data based on type if (dataType === 'text') { if (typeof data === 'string' && data === expectedTextData) { console.log(`✅ Text data verified: "${data}"`); } else { console.log(`❌ Text data mismatch. Expected: "${expectedTextData}", Got: "${data}"`); testPassed = false; } } else if (dataType === 'dictionary') { if (typeof data === 'object' && JSON.stringify(data) === JSON.stringify(expectedDictData)) { console.log(`✅ Dictionary data verified`); console.log(` Keys: ${Object.keys(data).join(', ')}`); } else { console.log(`❌ Dictionary data mismatch`); console.log(` Expected: ${JSON.stringify(expectedDictData)}`); console.log(` Got: ${JSON.stringify(data)}`); testPassed = false; } } else if (dataType === 'image') { if (data instanceof Buffer || data instanceof Uint8Array) { const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data); if (dataBuffer.length === expectedBinaryData.length) { let dataMatch = true; for (let j = 0; j < expectedBinaryData.length; j++) { if (dataBuffer[j] !== expectedBinaryData[j]) { dataMatch = false; break; } } if (dataMatch) { console.log(`✅ Image data verified (${dataBuffer.length} bytes)`); } else { console.log(`❌ Image data mismatch`); testPassed = false; } } else { console.log(`❌ Image data length mismatch. Expected: ${expectedBinaryData.length}, Got: ${dataBuffer.length}`); testPassed = false; } } else { console.log(`❌ Image data is not a Buffer or Uint8Array`); testPassed = false; } } else if (dataType === 'table') { // For table data, check if it's an Arrow table-like object if (data && typeof data === 'object') { // Arrow tables have specific properties if (data.numRows !== undefined && data.numCols !== undefined) { console.log(`✅ Table data verified`); console.log(` Rows: ${data.numRows}, Columns: ${data.numCols}`); } else { console.log(`⚠️ Table data received but not standard Arrow format`); console.log(` Keys: ${Object.keys(data).join(', ')}`); } } else { console.log(`❌ Table data is not a valid object`); testPassed = false; } } } // Stop after receiving at least one valid message if (messagesReceived >= 1) { resolve('done'); } } catch (error) { console.error(`❌ Error processing message: ${error.message}`); console.error(error.stack); testPassed = false; resolve('error'); } } })(); }); console.log('Waiting for messages...\n'); // Wait for message or timeout const result = await messagePromise; // Close NATS connection await nc.close(); console.log('\n✅ NATS connection closed'); // Final result console.log('\n=== Test Result ==='); if (messagesReceived === 0) { console.log('❌ NO MESSAGES RECEIVED'); console.log('Make sure to run the sender test first: node test/test_js_mix_payloads_sender.js'); process.exit(1); } else if (result === 'error') { console.log('❌ ERROR PROCESSING MESSAGES'); process.exit(1); } else if (testPassed) { console.log('✅ ALL TESTS PASSED'); process.exit(0); } else { console.log('❌ SOME TESTS FAILED'); process.exit(1); } } catch (error) { console.error('❌ Test failed with error:', error.message); console.error(error.stack); process.exit(1); } } runTest();