remove redundand test files
This commit is contained in:
@@ -69,3 +69,35 @@ Now do the following:
|
||||
|
||||
|
||||
|
||||
I'm expanding this Julia package (NATSBridge) into a cross-platform project by adding
|
||||
a JavaScript, Python and MicroPython implementation.
|
||||
The following will serve as the ground truth:
|
||||
- test_julia_mix_payloads_sender.jl
|
||||
- NATSBridge.jl
|
||||
- test_julia_mix_payloads_receiver.jl
|
||||
- architecture.md
|
||||
|
||||
My goal is to maintain interface parity at the high-level API for a consistent user experience,
|
||||
while ensuring the low-level implementation adheres strictly to the idiomatic conventions of each
|
||||
respective language (e.g., multiple dispatch in Julia vs. asynchronous, prototype, or class-based
|
||||
patterns in JS, Python and MicroPython)
|
||||
|
||||
Now, help me do the following:
|
||||
1) Check whether natsbridge.js needs update or it already up to date.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* using NATS as the message bus, with support for both direct payload transport and
|
||||
* URL-based transport for larger payloads.
|
||||
*
|
||||
* Supported payload types: "text", "dictionary", "arrowtable", "jsontable", "image", "audio", "video", "binary"
|
||||
*
|
||||
* @module NATSBridge
|
||||
*/
|
||||
|
||||
@@ -57,7 +59,7 @@ function logTrace(correlationId, message) {
|
||||
/**
|
||||
* Serialize data according to specified format
|
||||
* @param {any} data - Data to serialize
|
||||
* @param {string} payloadType - Target format: "text", "dictionary", "table", "image", "audio", "video", "binary"
|
||||
* @param {string} payloadType - Target format: "text", "dictionary", "arrowtable", "jsontable", "image", "audio", "video", "binary"
|
||||
* @returns {Buffer} Binary representation of the serialized data
|
||||
*/
|
||||
async function serializeData(data, payloadType) {
|
||||
@@ -70,13 +72,20 @@ async function serializeData(data, payloadType) {
|
||||
} else if (payloadType === 'dictionary') {
|
||||
const jsonStr = JSON.stringify(data);
|
||||
return Buffer.from(jsonStr, 'utf8');
|
||||
} else if (payloadType === 'table') {
|
||||
} else if (payloadType === 'arrowtable') {
|
||||
// Convert array of objects to Arrow IPC format
|
||||
if (!Array.isArray(data) || data.length === 0) {
|
||||
throw new Error('Table data must be a non-empty array of objects');
|
||||
throw new Error('Arrow table data must be a non-empty array of objects');
|
||||
}
|
||||
|
||||
return serializeArrowTable(data);
|
||||
} else if (payloadType === 'jsontable') {
|
||||
// Serialize array of objects to JSON format
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error('JSON table data must be an array');
|
||||
}
|
||||
const jsonStr = JSON.stringify(data);
|
||||
return Buffer.from(jsonStr, 'utf8');
|
||||
} else if (payloadType === 'image') {
|
||||
if (data instanceof Uint8Array || Buffer.isBuffer(data)) {
|
||||
return Buffer.from(data);
|
||||
@@ -159,7 +168,7 @@ async function deserializeData(data, payloadType, correlationId) {
|
||||
logTrace(correlationId, `deserializeData: type=${payloadType}, bufferLength=${buffer.length}`);
|
||||
|
||||
// Debug: Show first 20 bytes in hex for binary data
|
||||
if (payloadType === 'table' || payloadType === 'image' || payloadType === 'binary') {
|
||||
if (payloadType === 'arrowtable' || payloadType === 'jsontable' || payloadType === 'image' || payloadType === 'binary') {
|
||||
const hexPreview = buffer.slice(0, 20).toString('hex');
|
||||
logTrace(correlationId, `deserializeData: First 20 bytes (hex): ${hexPreview}`);
|
||||
}
|
||||
@@ -173,7 +182,7 @@ async function deserializeData(data, payloadType, correlationId) {
|
||||
const result = JSON.parse(jsonStr);
|
||||
logTrace(correlationId, `deserializeData: dictionary keys=${Object.keys(result).join(', ')}`);
|
||||
return result;
|
||||
} else if (payloadType === 'table') {
|
||||
} else if (payloadType === 'arrowtable') {
|
||||
logTrace(correlationId, `deserializeData: Attempting Arrow table deserialization`);
|
||||
|
||||
// Debug: Check available arrow methods
|
||||
@@ -205,6 +214,11 @@ async function deserializeData(data, payloadType, correlationId) {
|
||||
}
|
||||
|
||||
throw new Error(`Unable to deserialize Arrow table: neither tableFromRawBytes nor tableFromIPC worked`);
|
||||
} else if (payloadType === 'jsontable') {
|
||||
const jsonStr = buffer.toString('utf8');
|
||||
const result = JSON.parse(jsonStr);
|
||||
logTrace(correlationId, `deserializeData: jsontable result length=${Array.isArray(result) ? result.length : 'N/A'}`);
|
||||
return result;
|
||||
} else if (payloadType === 'image') {
|
||||
logTrace(correlationId, `deserializeData: image buffer length=${buffer.length}`);
|
||||
return buffer;
|
||||
@@ -435,12 +449,20 @@ function buildEnvelope(subject, payloads, options) {
|
||||
* @returns {Object} Payload object
|
||||
*/
|
||||
function buildPayload(dataname, payloadType, payloadBytes, transport, data) {
|
||||
// Determine encoding based on payload type (matching Julia implementation)
|
||||
let encoding = 'base64';
|
||||
if (payloadType === 'jsontable') {
|
||||
encoding = 'json';
|
||||
} else if (payloadType === 'arrowtable') {
|
||||
encoding = 'arrow-ipc';
|
||||
}
|
||||
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
dataname,
|
||||
payload_type: payloadType,
|
||||
transport,
|
||||
encoding: transport === 'direct' ? 'base64' : 'none',
|
||||
encoding,
|
||||
size: payloadBytes.byteLength,
|
||||
data,
|
||||
metadata: transport === 'direct' ? { payload_bytes: payloadBytes.byteLength } : {}
|
||||
@@ -457,6 +479,7 @@ function buildPayload(dataname, payloadType, payloadBytes, transport, data) {
|
||||
*
|
||||
* @param {string} subject - NATS subject to publish the message to
|
||||
* @param {Array} data - List of [dataname, data, type] tuples to send
|
||||
* - type: "text", "dictionary", "arrowtable", "jsontable", "image", "audio", "video", "binary"
|
||||
* @param {Object} options - Optional configuration
|
||||
* @param {string} [options.broker_url=DEFAULT_BROKER_URL] - URL of the NATS server
|
||||
* @param {string} [options.fileserver_url=DEFAULT_FILESERVER_URL] - URL of the HTTP file server
|
||||
@@ -488,7 +511,7 @@ function buildPayload(dataname, payloadType, payloadBytes, transport, data) {
|
||||
* "/test",
|
||||
* [
|
||||
* ["dataname1", data1, "dictionary"],
|
||||
* ["dataname2", data2, "table"]
|
||||
* ["dataname2", data2, "arrowtable"]
|
||||
* ],
|
||||
* { broker_url: "nats://localhost:4222" }
|
||||
* );
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
/**
|
||||
* JavaScript Binary Receiver Test
|
||||
* Tests the smartreceive function with binary/image/audio/video payloads
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
|
||||
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 Binary Receiver Test ===\n');
|
||||
|
||||
// Create mock NATS message with binary payloads
|
||||
const binaryData = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]); // PNG header
|
||||
const audioData = Buffer.from([0x46, 0x4C, 0x41, 0x43, 0x00, 0x00, 0x00, 0x00]); // FLAC header
|
||||
const videoData = Buffer.from([0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70]); // MP4 header
|
||||
const genericBinary = Buffer.from([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE]);
|
||||
|
||||
const testData = {
|
||||
correlation_id: 'js-binary-receiver-' + crypto.randomUUID(),
|
||||
msg_id: 'msg-' + crypto.randomUUID(),
|
||||
timestamp: new Date().toISOString(),
|
||||
send_to: '/test/binary',
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-binary-test',
|
||||
sender_id: 'sender-' + crypto.randomUUID(),
|
||||
receiver_name: 'js-receiver',
|
||||
receiver_id: 'receiver-' + crypto.randomUUID(),
|
||||
reply_to: '',
|
||||
reply_to_msg_id: '',
|
||||
broker_url: TEST_BROKER_URL,
|
||||
metadata: {},
|
||||
payloads: [
|
||||
{
|
||||
id: 'payload-1',
|
||||
dataname: 'image',
|
||||
payload_type: 'image',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: binaryData.length,
|
||||
data: binaryData.toString('base64'),
|
||||
metadata: { payload_bytes: binaryData.length }
|
||||
},
|
||||
{
|
||||
id: 'payload-2',
|
||||
dataname: 'audio',
|
||||
payload_type: 'audio',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: audioData.length,
|
||||
data: audioData.toString('base64'),
|
||||
metadata: { payload_bytes: audioData.length }
|
||||
},
|
||||
{
|
||||
id: 'payload-3',
|
||||
dataname: 'video',
|
||||
payload_type: 'video',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: videoData.length,
|
||||
data: videoData.toString('base64'),
|
||||
metadata: { payload_bytes: videoData.length }
|
||||
},
|
||||
{
|
||||
id: 'payload-4',
|
||||
dataname: 'binary',
|
||||
payload_type: 'binary',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: genericBinary.length,
|
||||
data: genericBinary.toString('base64'),
|
||||
metadata: { payload_bytes: genericBinary.length }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const mockMsg = {
|
||||
payload: JSON.stringify(testData)
|
||||
};
|
||||
|
||||
console.log('Mock Message Created:');
|
||||
console.log(` Correlation ID: ${testData.correlation_id}`);
|
||||
console.log(` Payloads: ${testData.payloads.length}`);
|
||||
console.log(` Payload types: ${testData.payloads.map(p => p.payload_type).join(', ')}\n`);
|
||||
|
||||
try {
|
||||
// Receive and process the message
|
||||
console.log('Receiving and processing message...');
|
||||
const env = await NATSBridge.smartreceive(
|
||||
mockMsg,
|
||||
{
|
||||
max_retries: 3,
|
||||
base_delay: 100,
|
||||
max_delay: 1000
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n=== Received Envelope ===');
|
||||
console.log(`Correlation ID: ${env.correlation_id}`);
|
||||
console.log(`Message ID: ${env.msg_id}`);
|
||||
console.log(`Timestamp: ${env.timestamp}`);
|
||||
console.log(`Subject: ${env.send_to}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Validate received data
|
||||
console.log('=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (!env.correlation_id) {
|
||||
console.log('❌ correlation_id is missing');
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ correlation_id present');
|
||||
}
|
||||
|
||||
if (env.payloads.length !== 4) {
|
||||
console.log(`❌ Expected 4 payloads, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
// Expected data
|
||||
const expectedData = [
|
||||
['image', binaryData, 'image'],
|
||||
['audio', audioData, 'audio'],
|
||||
['video', videoData, 'video'],
|
||||
['binary', genericBinary, 'binary']
|
||||
];
|
||||
|
||||
for (let i = 0; i < env.payloads.length; i++) {
|
||||
const payload = env.payloads[i];
|
||||
const expected = expectedData[i];
|
||||
|
||||
if (payload[0] !== expected[0]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected dataname '${expected[0]}', got '${payload[0]}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct dataname`);
|
||||
}
|
||||
|
||||
if (payload[2] !== expected[2]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected type '${expected[2]}', got '${payload[2]}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct type`);
|
||||
}
|
||||
|
||||
// Verify binary data integrity
|
||||
const receivedData = payload[1];
|
||||
if (!(receivedData instanceof Buffer || receivedData instanceof Uint8Array)) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected Buffer/Uint8Array, got ${typeof receivedData}`);
|
||||
passed = false;
|
||||
} else if (Buffer.isBuffer(receivedData)) {
|
||||
if (receivedData.length !== expected[1].length) {
|
||||
console.log(`❌ Payload ${i + 1}: Length mismatch`);
|
||||
passed = false;
|
||||
} else {
|
||||
let dataMatch = true;
|
||||
for (let j = 0; j < expected[1].length; j++) {
|
||||
if (receivedData[j] !== expected[1][j]) {
|
||||
dataMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dataMatch) {
|
||||
console.log(`✅ Payload ${i + 1}: Data correctly deserialized`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1}: Data mismatch`);
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Uint8Array comparison
|
||||
const receivedBuffer = Buffer.from(receivedData);
|
||||
if (receivedBuffer.length !== expected[1].length) {
|
||||
console.log(`❌ Payload ${i + 1}: Length mismatch`);
|
||||
passed = false;
|
||||
} else {
|
||||
let dataMatch = true;
|
||||
for (let j = 0; j < expected[1].length; j++) {
|
||||
if (receivedBuffer[j] !== expected[1][j]) {
|
||||
dataMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dataMatch) {
|
||||
console.log(`✅ Payload ${i + 1}: Data correctly deserialized`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1}: Data mismatch`);
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Final result
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
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();
|
||||
@@ -1,174 +0,0 @@
|
||||
/**
|
||||
* JavaScript Binary Sender Test
|
||||
* Tests the smartsend function with binary/image/audio/video payloads
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const TEST_SUBJECT = '/test/binary';
|
||||
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 Binary Sender Test ===\n');
|
||||
|
||||
const correlationId = crypto.randomUUID();
|
||||
console.log(`Correlation ID: ${correlationId}`);
|
||||
console.log(`Subject: ${TEST_SUBJECT}`);
|
||||
console.log(`Broker URL: ${TEST_BROKER_URL}\n`);
|
||||
|
||||
// Test data - binary data for different types
|
||||
const binaryData = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]); // PNG header
|
||||
const audioData = Buffer.from([0x46, 0x4C, 0x41, 0x43, 0x00, 0x00, 0x00, 0x00]); // FLAC header
|
||||
const videoData = Buffer.from([0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70]); // MP4 header
|
||||
const genericBinary = Buffer.from([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE]);
|
||||
|
||||
const testData = [
|
||||
['image', binaryData, 'image'],
|
||||
['audio', audioData, 'audio'],
|
||||
['video', videoData, 'video'],
|
||||
['binary', genericBinary, 'binary']
|
||||
];
|
||||
|
||||
try {
|
||||
// Send the message
|
||||
console.log('Sending binary payloads...');
|
||||
const [env, envJsonStr] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
testData,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: correlationId,
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-binary-test',
|
||||
is_publish: false
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n=== Envelope Created ===');
|
||||
console.log(`Correlation ID: ${env.correlation_id}`);
|
||||
console.log(`Message ID: ${env.msg_id}`);
|
||||
console.log(`Timestamp: ${env.timestamp}`);
|
||||
console.log(`Subject: ${env.send_to}`);
|
||||
console.log(`Purpose: ${env.msg_purpose}`);
|
||||
console.log(`Sender: ${env.sender_name}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Validate envelope structure
|
||||
console.log('=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (env.payloads.length !== 4) {
|
||||
console.log(`❌ Expected 4 payloads, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
// Test each payload
|
||||
const expectedDatanames = ['image', 'audio', 'video', 'binary'];
|
||||
const expectedTypes = ['image', 'audio', 'video', 'binary'];
|
||||
const expectedData = [binaryData, audioData, videoData, genericBinary];
|
||||
|
||||
for (let i = 0; i < env.payloads.length; i++) {
|
||||
const payload = env.payloads[i];
|
||||
|
||||
if (payload.dataname !== expectedDatanames[i]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected dataname '${expectedDatanames[i]}', got '${payload.dataname}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct dataname`);
|
||||
}
|
||||
|
||||
if (payload.payload_type !== expectedTypes[i]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected type '${expectedTypes[i]}', got '${payload.payload_type}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct type`);
|
||||
}
|
||||
|
||||
if (payload.transport !== 'direct') {
|
||||
console.log(`❌ Payload ${i + 1}: Expected transport 'direct', got '${payload.transport}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct transport`);
|
||||
}
|
||||
|
||||
if (payload.encoding !== 'base64') {
|
||||
console.log(`❌ Payload ${i + 1}: Expected encoding 'base64', got '${payload.encoding}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct encoding`);
|
||||
}
|
||||
|
||||
// Decode and verify the data
|
||||
const decodedData = Buffer.from(payload.data, 'base64');
|
||||
const originalData = expectedData[i];
|
||||
|
||||
if (decodedData.length !== originalData.length) {
|
||||
console.log(`❌ Payload ${i + 1}: Length mismatch (${decodedData.length} vs ${originalData.length})`);
|
||||
passed = false;
|
||||
} else {
|
||||
let dataMatch = true;
|
||||
for (let j = 0; j < originalData.length; j++) {
|
||||
if (decodedData[j] !== originalData[j]) {
|
||||
dataMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dataMatch) {
|
||||
console.log(`✅ Payload ${i + 1}: Data integrity verified`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1}: Data integrity mismatch`);
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(` Size: ${payload.size} bytes\n`);
|
||||
}
|
||||
|
||||
// Test with larger binary data (simulating file upload scenario)
|
||||
console.log('=== Large Binary Data Test ===');
|
||||
const largeData = Buffer.alloc(10000, 0xFF); // 10KB of binary data
|
||||
const largeTestData = [
|
||||
['large_binary', largeData, 'binary']
|
||||
];
|
||||
|
||||
const [largeEnv, _] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
largeTestData,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: 'large-' + correlationId,
|
||||
is_publish: false
|
||||
}
|
||||
);
|
||||
|
||||
if (largeEnv.payloads.length === 1 && largeEnv.payloads[0].size === 10000) {
|
||||
console.log('✅ Large binary data handled correctly');
|
||||
} else {
|
||||
console.log('❌ Large binary data handling failed');
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Final result
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
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();
|
||||
@@ -1,221 +0,0 @@
|
||||
/**
|
||||
* JavaScript Dictionary Receiver Test
|
||||
* Tests the smartreceive function with dictionary payloads
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
|
||||
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 Dictionary Receiver Test ===\n');
|
||||
|
||||
// Create a mock NATS message with dictionary payloads
|
||||
const simpleDict = { key1: 'value1', key2: 'value2' };
|
||||
const nestedDict = { outer: { inner: 'value', number: 42 } };
|
||||
const arrayDict = { items: [1, 2, 3, 'four', 'five'] };
|
||||
const mixedDict = { string: 'text', number: 123, boolean: true, null_val: null };
|
||||
|
||||
const testData = {
|
||||
correlation_id: 'test-receiver-dict-' + crypto.randomUUID(),
|
||||
msg_id: 'msg-' + crypto.randomUUID(),
|
||||
timestamp: new Date().toISOString(),
|
||||
send_to: '/test/dictionary',
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-dict-test',
|
||||
sender_id: 'sender-' + crypto.randomUUID(),
|
||||
receiver_name: 'js-receiver',
|
||||
receiver_id: 'receiver-' + crypto.randomUUID(),
|
||||
reply_to: '',
|
||||
reply_to_msg_id: '',
|
||||
broker_url: TEST_BROKER_URL,
|
||||
metadata: {},
|
||||
payloads: [
|
||||
{
|
||||
id: 'payload-1',
|
||||
dataname: 'simple_dict',
|
||||
payload_type: 'dictionary',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: Buffer.from(JSON.stringify(simpleDict)).length,
|
||||
data: Buffer.from(JSON.stringify(simpleDict)).toString('base64'),
|
||||
metadata: { payload_bytes: Buffer.from(JSON.stringify(simpleDict)).length }
|
||||
},
|
||||
{
|
||||
id: 'payload-2',
|
||||
dataname: 'nested_dict',
|
||||
payload_type: 'dictionary',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: Buffer.from(JSON.stringify(nestedDict)).length,
|
||||
data: Buffer.from(JSON.stringify(nestedDict)).toString('base64'),
|
||||
metadata: { payload_bytes: Buffer.from(JSON.stringify(nestedDict)).length }
|
||||
},
|
||||
{
|
||||
id: 'payload-3',
|
||||
dataname: 'array_dict',
|
||||
payload_type: 'dictionary',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: Buffer.from(JSON.stringify(arrayDict)).length,
|
||||
data: Buffer.from(JSON.stringify(arrayDict)).toString('base64'),
|
||||
metadata: { payload_bytes: Buffer.from(JSON.stringify(arrayDict)).length }
|
||||
},
|
||||
{
|
||||
id: 'payload-4',
|
||||
dataname: 'mixed_dict',
|
||||
payload_type: 'dictionary',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: Buffer.from(JSON.stringify(mixedDict)).length,
|
||||
data: Buffer.from(JSON.stringify(mixedDict)).toString('base64'),
|
||||
metadata: { payload_bytes: Buffer.from(JSON.stringify(mixedDict)).length }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const mockMsg = {
|
||||
payload: JSON.stringify(testData)
|
||||
};
|
||||
|
||||
console.log('Mock Message Created:');
|
||||
console.log(` Correlation ID: ${testData.correlation_id}`);
|
||||
console.log(` Payloads: ${testData.payloads.length}`);
|
||||
console.log(` Payload types: ${testData.payloads.map(p => p.payload_type).join(', ')}\n`);
|
||||
|
||||
try {
|
||||
// Receive and process the message
|
||||
console.log('Receiving and processing message...');
|
||||
const env = await NATSBridge.smartreceive(
|
||||
mockMsg,
|
||||
{
|
||||
max_retries: 3,
|
||||
base_delay: 100,
|
||||
max_delay: 1000
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n=== Received Envelope ===');
|
||||
console.log(`Correlation ID: ${env.correlation_id}`);
|
||||
console.log(`Message ID: ${env.msg_id}`);
|
||||
console.log(`Timestamp: ${env.timestamp}`);
|
||||
console.log(`Subject: ${env.send_to}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Validate received data
|
||||
console.log('=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (!env.correlation_id) {
|
||||
console.log('❌ correlation_id is missing');
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ correlation_id present');
|
||||
}
|
||||
|
||||
if (env.payloads.length !== 4) {
|
||||
console.log(`❌ Expected 4 payloads, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
// Expected data
|
||||
const expectedData = [
|
||||
['simple_dict', simpleDict, 'dictionary'],
|
||||
['nested_dict', nestedDict, 'dictionary'],
|
||||
['array_dict', arrayDict, 'dictionary'],
|
||||
['mixed_dict', mixedDict, 'dictionary']
|
||||
];
|
||||
|
||||
for (let i = 0; i < env.payloads.length; i++) {
|
||||
const payload = env.payloads[i];
|
||||
const expected = expectedData[i];
|
||||
|
||||
if (payload[0] !== expected[0]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected dataname '${expected[0]}', got '${payload[0]}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct dataname`);
|
||||
}
|
||||
|
||||
if (payload[2] !== expected[2]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected type '${expected[2]}', got '${payload[2]}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct type`);
|
||||
}
|
||||
|
||||
const dataMatch = JSON.stringify(payload[1]) === JSON.stringify(expected[1]);
|
||||
if (!dataMatch) {
|
||||
console.log(`❌ Payload ${i + 1}: Data mismatch`);
|
||||
console.log(` Expected: ${JSON.stringify(expected[1])}`);
|
||||
console.log(` Got: ${JSON.stringify(payload[1])}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Data correctly deserialized`);
|
||||
}
|
||||
}
|
||||
|
||||
// Test round-trip with receive
|
||||
console.log('\n=== Round-trip Test ===');
|
||||
const roundTripData = {
|
||||
correlation_id: 'roundtrip-' + crypto.randomUUID(),
|
||||
msg_id: 'msg-' + crypto.randomUUID(),
|
||||
timestamp: new Date().toISOString(),
|
||||
send_to: '/test/dictionary',
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-test',
|
||||
sender_id: 'sender-' + crypto.randomUUID(),
|
||||
receiver_name: 'js-receiver',
|
||||
receiver_id: 'receiver-' + crypto.randomUUID(),
|
||||
reply_to: '',
|
||||
reply_to_msg_id: '',
|
||||
broker_url: TEST_BROKER_URL,
|
||||
metadata: {},
|
||||
payloads: [
|
||||
{
|
||||
id: 'payload-rt',
|
||||
dataname: 'roundtrip',
|
||||
payload_type: 'dictionary',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: Buffer.from(JSON.stringify({ test: 'data', nested: { a: 1, b: 2 } })).length,
|
||||
data: Buffer.from(JSON.stringify({ test: 'data', nested: { a: 1, b: 2 } })).toString('base64'),
|
||||
metadata: { payload_bytes: Buffer.from(JSON.stringify({ test: 'data', nested: { a: 1, b: 2 } })).length }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const mockRtMsg = { payload: JSON.stringify(roundTripData) };
|
||||
const rtEnv = await NATSBridge.smartreceive(mockRtMsg);
|
||||
|
||||
if (rtEnv.payloads.length === 1 &&
|
||||
rtEnv.payloads[0][0] === 'roundtrip' &&
|
||||
rtEnv.payloads[0][2] === 'dictionary') {
|
||||
console.log('✅ Round-trip test successful');
|
||||
} else {
|
||||
console.log('❌ Round-trip test failed');
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Final result
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
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();
|
||||
@@ -1,179 +0,0 @@
|
||||
/**
|
||||
* JavaScript Dictionary Sender Test
|
||||
* Tests the smartsend function with dictionary payloads
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const TEST_SUBJECT = '/test/dictionary';
|
||||
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 Dictionary Sender Test ===\n');
|
||||
|
||||
const correlationId = crypto.randomUUID();
|
||||
console.log(`Correlation ID: ${correlationId}`);
|
||||
console.log(`Subject: ${TEST_SUBJECT}`);
|
||||
console.log(`Broker URL: ${TEST_BROKER_URL}\n`);
|
||||
|
||||
// Test data - various dictionary structures
|
||||
const testData = [
|
||||
['simple_dict', { key1: 'value1', key2: 'value2' }, 'dictionary'],
|
||||
['nested_dict', { outer: { inner: 'value', number: 42 } }, 'dictionary'],
|
||||
['array_dict', { items: [1, 2, 3, 'four', 'five'] }, 'dictionary'],
|
||||
['mixed_dict', { string: 'text', number: 123, boolean: true, null_val: null }, 'dictionary']
|
||||
];
|
||||
|
||||
try {
|
||||
// Send the message
|
||||
console.log('Sending dictionary payloads...');
|
||||
const [env, envJsonStr] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
testData,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: correlationId,
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-dict-test',
|
||||
is_publish: false
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n=== Envelope Created ===');
|
||||
console.log(`Correlation ID: ${env.correlation_id}`);
|
||||
console.log(`Message ID: ${env.msg_id}`);
|
||||
console.log(`Timestamp: ${env.timestamp}`);
|
||||
console.log(`Subject: ${env.send_to}`);
|
||||
console.log(`Purpose: ${env.msg_purpose}`);
|
||||
console.log(`Sender: ${env.sender_name}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Validate envelope structure
|
||||
console.log('=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (env.payloads.length !== 4) {
|
||||
console.log(`❌ Expected 4 payloads, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
// Test each payload
|
||||
const expectedDatanames = ['simple_dict', 'nested_dict', 'array_dict', 'mixed_dict'];
|
||||
const expectedTypes = ['dictionary', 'dictionary', 'dictionary', 'dictionary'];
|
||||
|
||||
for (let i = 0; i < env.payloads.length; i++) {
|
||||
const payload = env.payloads[i];
|
||||
|
||||
if (payload.dataname !== expectedDatanames[i]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected dataname '${expectedDatanames[i]}', got '${payload.dataname}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct dataname`);
|
||||
}
|
||||
|
||||
if (payload.payload_type !== expectedTypes[i]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected type '${expectedTypes[i]}', got '${payload.payload_type}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct type`);
|
||||
}
|
||||
|
||||
if (payload.transport !== 'direct') {
|
||||
console.log(`❌ Payload ${i + 1}: Expected transport 'direct', got '${payload.transport}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct transport`);
|
||||
}
|
||||
|
||||
if (payload.encoding !== 'base64') {
|
||||
console.log(`❌ Payload ${i + 1}: Expected encoding 'base64', got '${payload.encoding}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct encoding`);
|
||||
}
|
||||
|
||||
// Decode and verify the data
|
||||
const decodedData = JSON.parse(Buffer.from(payload.data, 'base64').toString('utf8'));
|
||||
const originalData = testData[i][1];
|
||||
|
||||
const originalJson = JSON.stringify(originalData);
|
||||
const decodedJson = JSON.stringify(decodedData);
|
||||
|
||||
if (originalJson !== decodedJson) {
|
||||
console.log(`❌ Payload ${i + 1}: Data integrity mismatch`);
|
||||
console.log(` Expected: ${originalJson}`);
|
||||
console.log(` Got: ${decodedJson}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Data integrity verified`);
|
||||
}
|
||||
|
||||
console.log(` Size: ${payload.size} bytes\n`);
|
||||
}
|
||||
|
||||
// Test round-trip serialization
|
||||
console.log('=== Round-trip Serialization Test ===');
|
||||
const roundTripTestData = [
|
||||
['roundtrip', { test: 'data', numbers: [1, 2, 3], nested: { a: 1, b: 2 } }, 'dictionary']
|
||||
];
|
||||
|
||||
const [rtEnv, rtEnvJsonStr] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
roundTripTestData,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: 'roundtrip-' + correlationId,
|
||||
is_publish: false
|
||||
}
|
||||
);
|
||||
|
||||
const rtPayload = rtEnv.payloads[0];
|
||||
const rtDecoded = JSON.parse(Buffer.from(rtPayload.data, 'base64').toString('utf8'));
|
||||
|
||||
if (JSON.stringify(rtDecoded) === JSON.stringify(roundTripTestData[0][1])) {
|
||||
console.log('✅ Round-trip serialization successful');
|
||||
} else {
|
||||
console.log('❌ Round-trip serialization failed');
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Test JSON string output
|
||||
console.log('\n=== JSON String Output Test ===');
|
||||
try {
|
||||
const parsed = JSON.parse(envJsonStr);
|
||||
if (parsed.correlation_id === env.correlation_id &&
|
||||
parsed.payloads.length === env.payloads.length) {
|
||||
console.log('✅ JSON string is valid and matches envelope');
|
||||
} else {
|
||||
console.log('❌ JSON string does not match envelope');
|
||||
passed = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('❌ JSON string is invalid:', e.message);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Final result
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
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();
|
||||
@@ -1,14 +1,20 @@
|
||||
/**
|
||||
* JavaScript Mix Payloads Sender Test
|
||||
* Tests the smartsend function with mixed payload types
|
||||
*
|
||||
* This test mirrors test_julia_mix_payloads_sender.jl and demonstrates that
|
||||
* any combination and any number of mixed content can be sent correctly.
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const TEST_SUBJECT = '/test/mix';
|
||||
const TEST_SUBJECT = '/natsbridge';
|
||||
const TEST_BROKER_URL = process.env.NATS_URL || 'nats.yiem.cc';
|
||||
const TEST_FILESERVER_URL = process.env.FILESERVER_URL || 'http://192.168.88.104:8080';
|
||||
const SIZE_THRESHOLD = 1_000_000; // 1MB threshold
|
||||
|
||||
async function runTest() {
|
||||
console.log('=== JavaScript Mix Payloads Sender Test ===\n');
|
||||
@@ -16,39 +22,168 @@ async function runTest() {
|
||||
const correlationId = crypto.randomUUID();
|
||||
console.log(`Correlation ID: ${correlationId}`);
|
||||
console.log(`Subject: ${TEST_SUBJECT}`);
|
||||
console.log(`Broker URL: ${TEST_BROKER_URL}\n`);
|
||||
console.log(`Broker URL: ${TEST_BROKER_URL}`);
|
||||
console.log(`Fileserver URL: ${TEST_FILESERVER_URL}`);
|
||||
console.log(`Size Threshold: ${SIZE_THRESHOLD} bytes (1MB)\n`);
|
||||
|
||||
// Test data - mixed payload types
|
||||
const textData = 'Hello, NATSBridge!';
|
||||
const dictData = { key1: 'value1', key2: 42, nested: { a: 1, b: 2 } };
|
||||
const binaryData = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]); // PNG header
|
||||
// Helper: Log with correlation ID
|
||||
function logTrace(message) {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[${timestamp}] [Correlation: ${correlationId}] ${message}`);
|
||||
}
|
||||
|
||||
// Table data
|
||||
const tableData = [
|
||||
{ id: 1, name: 'Alice', age: 30 },
|
||||
{ id: 2, name: 'Bob', age: 25 },
|
||||
{ id: 3, name: 'Charlie', age: 35 }
|
||||
// Create sample data for each type (mirroring Julia test)
|
||||
const textData = 'Hello! This is a test chat message. 🎉\nHow are you doing today? 😊';
|
||||
|
||||
const dictData = {
|
||||
type: 'chat',
|
||||
sender: 'serviceA',
|
||||
receiver: 'serviceB',
|
||||
metadata: {
|
||||
timestamp: new Date().toISOString(),
|
||||
priority: 'high',
|
||||
tags: ['urgent', 'chat', 'test']
|
||||
},
|
||||
content: {
|
||||
text: 'This is a JSON-formatted chat message with nested structure.',
|
||||
format: 'markdown',
|
||||
mentions: ['user1', 'user2']
|
||||
}
|
||||
};
|
||||
|
||||
// Arrow table data (small - direct transport)
|
||||
const arrowTableSmall = [
|
||||
{ id: 1, name: 'Alice', score: 95, active: true },
|
||||
{ id: 2, name: 'Bob', score: 88, active: false },
|
||||
{ id: 3, name: 'Charlie', score: 92, active: true },
|
||||
{ id: 4, name: 'Diana', score: 78, active: true },
|
||||
{ id: 5, name: 'Eve', score: 85, active: false },
|
||||
{ id: 6, name: 'Frank', score: 91, active: true },
|
||||
{ id: 7, name: 'Grace', score: 89, active: true },
|
||||
{ id: 8, name: 'Henry', score: 76, active: false },
|
||||
{ id: 9, name: 'Ivy', score: 94, active: true },
|
||||
{ id: 10, name: 'Jack', score: 82, active: true }
|
||||
];
|
||||
|
||||
const testData = [
|
||||
['message', textData, 'text'],
|
||||
['config', dictData, 'dictionary'],
|
||||
['image', binaryData, 'image'],
|
||||
['users', tableData, 'table']
|
||||
// Json table data (small - direct transport)
|
||||
const jsonTableSmall = [
|
||||
{ id: 1, name: 'Alice', score: 95, active: true },
|
||||
{ id: 2, name: 'Bob', score: 88, active: false },
|
||||
{ id: 3, name: 'Charlie', score: 92, active: true },
|
||||
{ id: 4, name: 'Diana', score: 78, active: true },
|
||||
{ id: 5, name: 'Eve', score: 85, active: false },
|
||||
{ id: 6, name: 'Frank', score: 91, active: true },
|
||||
{ id: 7, name: 'Grace', score: 89, active: true },
|
||||
{ id: 8, name: 'Henry', score: 76, active: false },
|
||||
{ id: 9, name: 'Ivy', score: 94, active: true },
|
||||
{ id: 10, name: 'Jack', score: 82, active: true }
|
||||
];
|
||||
|
||||
// Audio data (small binary - direct transport)
|
||||
const audioData = Buffer.alloc(100);
|
||||
for (let i = 0; i < 100; i++) {
|
||||
audioData[i] = Math.floor(Math.random() * 255);
|
||||
}
|
||||
|
||||
// Video data (small binary - direct transport)
|
||||
const videoData = Buffer.alloc(150);
|
||||
for (let i = 0; i < 150; i++) {
|
||||
videoData[i] = Math.floor(Math.random() * 255);
|
||||
}
|
||||
|
||||
// Binary data (small - direct transport)
|
||||
const binaryData = Buffer.alloc(200);
|
||||
for (let i = 0; i < 200; i++) {
|
||||
binaryData[i] = Math.floor(Math.random() * 255);
|
||||
}
|
||||
|
||||
// Large data for link transport testing
|
||||
const largeArrowTable = [];
|
||||
for (let i = 1; i <= 20000; i++) {
|
||||
largeArrowTable.push({
|
||||
id: i,
|
||||
name: `user_${i}`,
|
||||
score: Math.floor(Math.random() * 51) + 50,
|
||||
active: Math.random() > 0.5,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
const largeJsonTable = [];
|
||||
for (let i = 1; i <= 50000; i++) {
|
||||
largeJsonTable.push({
|
||||
id: i,
|
||||
name: `user_${i}`,
|
||||
score: Math.floor(Math.random() * 51) + 50,
|
||||
active: Math.random() > 0.5
|
||||
});
|
||||
}
|
||||
|
||||
const largeAudioData = Buffer.alloc(1_500_000);
|
||||
for (let i = 0; i < 1_500_000; i++) {
|
||||
largeAudioData[i] = Math.floor(Math.random() * 255);
|
||||
}
|
||||
|
||||
const largeVideoData = Buffer.alloc(1_500_000);
|
||||
for (let i = 0; i < 1_500_000; i++) {
|
||||
largeVideoData[i] = Math.floor(Math.random() * 255);
|
||||
}
|
||||
|
||||
const largeBinaryData = Buffer.alloc(1_500_000);
|
||||
for (let i = 0; i < 1_500_000; i++) {
|
||||
largeBinaryData[i] = Math.floor(Math.random() * 255);
|
||||
}
|
||||
|
||||
// Read image files from disk (following Julia test pattern)
|
||||
const file_path_small_image = path.join(__dirname, 'small_image.jpg');
|
||||
const file_data_small_image = fs.readFileSync(file_path_small_image);
|
||||
const filename_small_image = path.basename(file_path_small_image);
|
||||
|
||||
const file_path_large_image = path.join(__dirname, 'large_image.png');
|
||||
const file_data_large_image = fs.readFileSync(file_path_large_image);
|
||||
const filename_large_image = path.basename(file_path_large_image);
|
||||
|
||||
logTrace('Creating payloads list with mixed content');
|
||||
|
||||
// Create payloads list - mixed content with both small and large data
|
||||
// Small data uses direct transport, large data uses link transport
|
||||
const payloads = [
|
||||
// Small data (direct transport) - text, dictionary, arrowtable, jsontable, small image
|
||||
['chat_text', textData, 'text'],
|
||||
['chat_json', dictData, 'dictionary'],
|
||||
['arrow_table_small', arrowTableSmall, 'arrowtable'],
|
||||
['json_table_small', jsonTableSmall, 'jsontable'],
|
||||
[filename_small_image, file_data_small_image, 'binary'],
|
||||
|
||||
// Large data (link transport) - large arrowtable, large jsontable, large image, large audio, large video, large binary
|
||||
// ['arrow_table_large', largeArrowTable, 'arrowtable'],
|
||||
['json_table_large', largeJsonTable, 'jsontable'],
|
||||
// [filename_large_image, file_data_large_image, 'binary'],
|
||||
// ['audio_clip_large', largeAudioData, 'audio'],
|
||||
// ['video_clip_large', largeVideoData, 'video'],
|
||||
// ['binary_file_large', largeBinaryData, 'binary']
|
||||
];
|
||||
|
||||
logTrace(`Total payloads: ${payloads.length}`);
|
||||
|
||||
try {
|
||||
// Send the message
|
||||
console.log('Sending mixed payloads...');
|
||||
console.log('Sending mixed payloads...\n');
|
||||
const [env, envJsonStr] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
testData,
|
||||
payloads,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
fileserver_upload_handler: NATSBridge.plikOneshotUpload,
|
||||
size_threshold: SIZE_THRESHOLD,
|
||||
correlation_id: correlationId,
|
||||
msg_purpose: 'test',
|
||||
msg_purpose: 'chat',
|
||||
sender_name: 'js-mix-test',
|
||||
receiver_name: '',
|
||||
receiver_id: '',
|
||||
reply_to: '',
|
||||
reply_to_msg_id: '',
|
||||
is_publish: true
|
||||
}
|
||||
);
|
||||
@@ -62,21 +197,50 @@ async function runTest() {
|
||||
console.log(`Sender: ${env.sender_name}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Log transport type for each payload
|
||||
console.log('=== Payload Details ===');
|
||||
for (let i = 0; i < env.payloads.length; i++) {
|
||||
const payload = env.payloads[i];
|
||||
logTrace(`Payload ${i + 1} ('${payload.dataname}'):`);
|
||||
logTrace(` Transport: ${payload.transport}`);
|
||||
logTrace(` Type: ${payload.payload_type}`);
|
||||
logTrace(` Size: ${payload.size} bytes`);
|
||||
logTrace(` Encoding: ${payload.encoding}`);
|
||||
|
||||
if (payload.transport === 'link') {
|
||||
logTrace(` URL: ${payload.data}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Summary
|
||||
console.log('\n=== Transport Summary ===');
|
||||
const directCount = env.payloads.filter(p => p.transport === 'direct').length;
|
||||
const linkCount = env.payloads.filter(p => p.transport === 'link').length;
|
||||
logTrace(`Direct transport: ${directCount} payloads`);
|
||||
logTrace(`Link transport: ${linkCount} payloads`);
|
||||
|
||||
// Validate envelope structure
|
||||
console.log('=== Validation ===');
|
||||
console.log('\n=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (env.payloads.length !== 4) {
|
||||
console.log(`❌ Expected 4 payloads, got ${env.payloads.length}`);
|
||||
if (env.payloads.length !== 11) {
|
||||
console.log(`❌ Expected 11 payloads, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
// Test each payload
|
||||
const expectedDatanames = ['message', 'config', 'image', 'users'];
|
||||
const expectedTypes = ['text', 'dictionary', 'image', 'table'];
|
||||
const expectedData = [textData, dictData, binaryData, tableData];
|
||||
const expectedDatanames = [
|
||||
'chat_text', 'chat_json', 'arrow_table_small', 'json_table_small',
|
||||
filename_small_image, 'arrow_table_large', 'json_table_large',
|
||||
filename_large_image, 'audio_clip_large', 'video_clip_large',
|
||||
'binary_file_large'
|
||||
];
|
||||
const expectedTypes = [
|
||||
'text', 'dictionary', 'arrowtable', 'jsontable', 'binary',
|
||||
'arrowtable', 'jsontable', 'binary', 'audio', 'video', 'binary'
|
||||
];
|
||||
|
||||
for (let i = 0; i < env.payloads.length; i++) {
|
||||
const payload = env.payloads[i];
|
||||
@@ -85,78 +249,74 @@ async function runTest() {
|
||||
console.log(`❌ Payload ${i + 1}: Expected dataname '${expectedDatanames[i]}', got '${payload.dataname}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct dataname`);
|
||||
console.log(`✅ Payload ${i + 1}: Correct dataname ('${payload.dataname}')`);
|
||||
}
|
||||
|
||||
if (payload.payload_type !== expectedTypes[i]) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected type '${expectedTypes[i]}', got '${payload.payload_type}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct type`);
|
||||
console.log(`✅ Payload ${i + 1}: Correct type ('${payload.payload_type}')`);
|
||||
}
|
||||
|
||||
if (payload.transport !== 'direct') {
|
||||
console.log(`❌ Payload ${i + 1}: Expected transport 'direct', got '${payload.transport}'`);
|
||||
// Validate transport based on expected size
|
||||
if (i < 5 || i >= 6 && i <= 10) {
|
||||
// First 5 should be direct (small), rest should be link (large)
|
||||
const shouldBeDirect = i < 5;
|
||||
const isDirect = payload.transport === 'direct';
|
||||
|
||||
if (shouldBeDirect && isDirect) {
|
||||
console.log(`✅ Payload ${i + 1}: Correct transport (direct)`);
|
||||
} else if (!shouldBeDirect && payload.transport === 'link') {
|
||||
console.log(`✅ Payload ${i + 1}: Correct transport (link)`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1}: Expected ${shouldBeDirect ? 'direct' : 'link'} transport, got '${payload.transport}'`);
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate encoding based on payload type
|
||||
let expectedEncoding;
|
||||
if (payload.payload_type === 'jsontable') {
|
||||
expectedEncoding = 'json';
|
||||
} else if (payload.payload_type === 'arrowtable') {
|
||||
expectedEncoding = 'arrow-ipc';
|
||||
} else {
|
||||
expectedEncoding = 'base64';
|
||||
}
|
||||
|
||||
if (payload.encoding !== expectedEncoding) {
|
||||
console.log(`❌ Payload ${i + 1}: Expected encoding '${expectedEncoding}', got '${payload.encoding}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct transport`);
|
||||
console.log(`✅ Payload ${i + 1}: Correct encoding ('${payload.encoding}')`);
|
||||
}
|
||||
|
||||
if (payload.encoding !== 'base64') {
|
||||
console.log(`❌ Payload ${i + 1}: Expected encoding 'base64', got '${payload.encoding}'`);
|
||||
passed = false;
|
||||
// Validate size field
|
||||
if (payload.size > 0) {
|
||||
console.log(`✅ Payload ${i + 1}: Size field present (${payload.size} bytes)`);
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Correct encoding`);
|
||||
console.log(`❌ Payload ${i + 1}: Size field is 0`);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Verify data integrity based on type
|
||||
if (expectedTypes[i] === 'text') {
|
||||
const decodedData = Buffer.from(payload.data, 'base64').toString('utf8');
|
||||
if (decodedData !== expectedData[i]) {
|
||||
console.log(`❌ Payload ${i + 1}: Data integrity mismatch`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Data integrity verified`);
|
||||
}
|
||||
} else if (expectedTypes[i] === 'dictionary') {
|
||||
const decodedData = JSON.parse(Buffer.from(payload.data, 'base64').toString('utf8'));
|
||||
if (JSON.stringify(decodedData) !== JSON.stringify(expectedData[i])) {
|
||||
console.log(`❌ Payload ${i + 1}: Data integrity mismatch`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log(`✅ Payload ${i + 1}: Data integrity verified`);
|
||||
}
|
||||
} else if (expectedTypes[i] === 'image') {
|
||||
const decodedData = Buffer.from(payload.data, 'base64');
|
||||
if (decodedData.length !== expectedData[i].length) {
|
||||
console.log(`❌ Payload ${i + 1}: Length mismatch`);
|
||||
passed = false;
|
||||
} else {
|
||||
let dataMatch = true;
|
||||
for (let j = 0; j < expectedData[i].length; j++) {
|
||||
if (decodedData[j] !== expectedData[i][j]) {
|
||||
dataMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dataMatch) {
|
||||
console.log(`✅ Payload ${i + 1}: Data integrity verified`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1}: Data integrity mismatch`);
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
} else if (expectedTypes[i] === 'table') {
|
||||
const decodedData = Buffer.from(payload.data, 'base64');
|
||||
if (decodedData.length > 0) {
|
||||
console.log(`✅ Payload ${i + 1}: Arrow IPC data present (${decodedData.length} bytes)`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1}: Arrow IPC data is empty`);
|
||||
passed = false;
|
||||
}
|
||||
// Validate ID field
|
||||
if (payload.id && payload.id.length > 0) {
|
||||
console.log(`✅ Payload ${i + 1}: ID field present`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1}: ID field is empty`);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
console.log(` Size: ${payload.size} bytes\n`);
|
||||
// Validate metadata field
|
||||
if (payload.metadata !== undefined && payload.metadata !== null) {
|
||||
console.log(`✅ Payload ${i + 1}: Metadata field present`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1}: Metadata field is missing`);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Test with chat-like payload (text + image + audio)
|
||||
@@ -174,14 +334,25 @@ async function runTest() {
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: 'chat-' + correlationId,
|
||||
msg_purpose: 'chat',
|
||||
sender_name: 'js-mix-test',
|
||||
is_publish: true
|
||||
}
|
||||
);
|
||||
|
||||
if (chatEnv.payloads.length === 3) {
|
||||
console.log('✅ Chat-like payloads handled correctly');
|
||||
console.log('✅ Chat-like payloads handled correctly (3 payloads)');
|
||||
} else {
|
||||
console.log('❌ Chat-like payloads handling failed');
|
||||
console.log(`❌ Chat-like payloads handling failed (expected 3, got ${chatEnv.payloads.length})`);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Verify all payload types in chat are direct transport
|
||||
const allDirect = chatEnv.payloads.every(p => p.transport === 'direct');
|
||||
if (allDirect) {
|
||||
console.log('✅ All chat payloads use direct transport (small size)');
|
||||
} else {
|
||||
console.log('❌ Some chat payloads use link transport (unexpected for small data)');
|
||||
passed = false;
|
||||
}
|
||||
|
||||
@@ -189,6 +360,7 @@ async function runTest() {
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
console.log('✅ ALL TESTS PASSED');
|
||||
console.log('\nNote: Run test_js_mix_payloads_receiver.js to receive the messages.');
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log('❌ SOME TESTS FAILED');
|
||||
@@ -196,7 +368,7 @@ async function runTest() {
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Test failed with error:', error.message);
|
||||
console.error('\n❌ Test failed with error:', error.message);
|
||||
console.error(error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/**
|
||||
* JavaScript Table Receiver Test
|
||||
* Tests the smartreceive function with table (Arrow IPC) payloads
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
|
||||
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 Table Receiver Test ===\n');
|
||||
|
||||
// Create a mock NATS message with table payload
|
||||
const tableData = [
|
||||
{ id: 1, name: 'Alice', age: 30, active: true },
|
||||
{ id: 2, name: 'Bob', age: 25, active: false },
|
||||
{ id: 3, name: 'Charlie', age: 35, active: true }
|
||||
];
|
||||
|
||||
// Convert to Arrow IPC format
|
||||
const arrow = require('apache-arrow');
|
||||
const fields = [
|
||||
new arrow.Field('id', arrow.Int64, true),
|
||||
new arrow.Field('name', arrow.Utf8, true),
|
||||
new arrow.Field('age', arrow.Int64, true),
|
||||
new arrow.Field('active', arrow.Boolean, true)
|
||||
];
|
||||
const schema = new arrow.Schema(fields);
|
||||
const batches = [];
|
||||
for (const row of tableData) {
|
||||
const batch = arrow.recordBatch.fromObjects([row], schema);
|
||||
batches.push(batch);
|
||||
}
|
||||
const buffers = arrow.ipc.recordBatchesToMessage(batches, schema).buffers;
|
||||
const combined = new Uint8Array(buffers.reduce((acc, b) => acc + b.byteLength, 0));
|
||||
let offset = 0;
|
||||
for (const buf of buffers) {
|
||||
combined.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
const arrowBuffer = Buffer.from(combined);
|
||||
|
||||
const testData = {
|
||||
correlation_id: 'js-table-receiver-' + crypto.randomUUID(),
|
||||
msg_id: 'msg-' + crypto.randomUUID(),
|
||||
timestamp: new Date().toISOString(),
|
||||
send_to: '/test/table',
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-table-test',
|
||||
sender_id: 'sender-' + crypto.randomUUID(),
|
||||
receiver_name: 'js-receiver',
|
||||
receiver_id: 'receiver-' + crypto.randomUUID(),
|
||||
reply_to: '',
|
||||
reply_to_msg_id: '',
|
||||
broker_url: TEST_BROKER_URL,
|
||||
metadata: {},
|
||||
payloads: [
|
||||
{
|
||||
id: 'payload-1',
|
||||
dataname: 'users_table',
|
||||
payload_type: 'table',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: arrowBuffer.length,
|
||||
data: arrowBuffer.toString('base64'),
|
||||
metadata: { payload_bytes: arrowBuffer.length }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const mockMsg = {
|
||||
payload: JSON.stringify(testData)
|
||||
};
|
||||
|
||||
console.log('Mock Message Created:');
|
||||
console.log(` Correlation ID: ${testData.correlation_id}`);
|
||||
console.log(` Payloads: ${testData.payloads.length}`);
|
||||
console.log(` Payload type: ${testData.payloads[0].payload_type}`);
|
||||
console.log(` Transport: ${testData.payloads[0].transport}\n`);
|
||||
|
||||
try {
|
||||
// Receive and process the message
|
||||
console.log('Receiving and processing message...');
|
||||
const env = await NATSBridge.smartreceive(
|
||||
mockMsg,
|
||||
{
|
||||
max_retries: 3,
|
||||
base_delay: 100,
|
||||
max_delay: 1000
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n=== Received Envelope ===');
|
||||
console.log(`Correlation ID: ${env.correlation_id}`);
|
||||
console.log(`Message ID: ${env.msg_id}`);
|
||||
console.log(`Timestamp: ${env.timestamp}`);
|
||||
console.log(`Subject: ${env.send_to}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Validate received data
|
||||
console.log('=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (!env.correlation_id) {
|
||||
console.log('❌ correlation_id is missing');
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ correlation_id present');
|
||||
}
|
||||
|
||||
if (env.payloads.length !== 1) {
|
||||
console.log(`❌ Expected 1 payload, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
const payload = env.payloads[0];
|
||||
if (payload[0] !== 'users_table') {
|
||||
console.log(`❌ Expected dataname 'users_table', got '${payload[0]}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct dataname');
|
||||
}
|
||||
|
||||
if (payload[2] !== 'table') {
|
||||
console.log(`❌ Expected type 'table', got '${payload[2]}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct type');
|
||||
}
|
||||
|
||||
// Verify table data is a Buffer (Arrow IPC format)
|
||||
if (payload[1] instanceof Buffer || payload[1] instanceof Uint8Array) {
|
||||
console.log('✅ Table data is Arrow IPC buffer');
|
||||
console.log(` Buffer size: ${payload[1].length} bytes`);
|
||||
} else {
|
||||
console.log(`❌ Expected Buffer/Uint8Array, got ${typeof payload[1]}`);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Test round-trip with Arrow deserialization
|
||||
console.log('\n=== Arrow Deserialization Test ===');
|
||||
try {
|
||||
const table = arrow.tableFromRawBytes(payload[1]);
|
||||
console.log(`✅ Arrow table deserialized successfully`);
|
||||
console.log(` Schema: ${table.schema.fields.map(f => f.name).join(', ')}`);
|
||||
console.log(` Num rows: ${table.numRows}`);
|
||||
} catch (e) {
|
||||
console.log('❌ Arrow deserialization failed:', e.message);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Final result
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
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();
|
||||
@@ -1,180 +0,0 @@
|
||||
/**
|
||||
* JavaScript Table Sender Test
|
||||
* Tests the smartsend function with table (Arrow IPC) payloads
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const TEST_SUBJECT = '/test/table';
|
||||
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 Table Sender Test ===\n');
|
||||
|
||||
const correlationId = crypto.randomUUID();
|
||||
console.log(`Correlation ID: ${correlationId}`);
|
||||
console.log(`Subject: ${TEST_SUBJECT}`);
|
||||
console.log(`Broker URL: ${TEST_BROKER_URL}\n`);
|
||||
|
||||
// Test data - table data as array of objects
|
||||
const tableData = [
|
||||
{ id: 1, name: 'Alice', age: 30, active: true },
|
||||
{ id: 2, name: 'Bob', age: 25, active: false },
|
||||
{ id: 3, name: 'Charlie', age: 35, active: true },
|
||||
{ id: 4, name: 'Diana', age: 28, active: true },
|
||||
{ id: 5, name: 'Eve', age: 32, active: false }
|
||||
];
|
||||
|
||||
const testData = [
|
||||
['users_table', tableData, 'table']
|
||||
];
|
||||
|
||||
try {
|
||||
// Send the message
|
||||
console.log('Sending table payload...');
|
||||
const [env, envJsonStr] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
testData,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: correlationId,
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-table-test',
|
||||
is_publish: false
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n=== Envelope Created ===');
|
||||
console.log(`Correlation ID: ${env.correlation_id}`);
|
||||
console.log(`Message ID: ${env.msg_id}`);
|
||||
console.log(`Timestamp: ${env.timestamp}`);
|
||||
console.log(`Subject: ${env.send_to}`);
|
||||
console.log(`Purpose: ${env.msg_purpose}`);
|
||||
console.log(`Sender: ${env.sender_name}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Validate envelope structure
|
||||
console.log('=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (env.payloads.length !== 1) {
|
||||
console.log(`❌ Expected 1 payload, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
const payload = env.payloads[0];
|
||||
if (payload.dataname !== 'users_table') {
|
||||
console.log(`❌ Expected dataname 'users_table', got '${payload.dataname}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct dataname');
|
||||
}
|
||||
|
||||
if (payload.payload_type !== 'table') {
|
||||
console.log(`❌ Expected payload_type 'table', got '${payload.payload_type}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct payload_type');
|
||||
}
|
||||
|
||||
if (payload.transport !== 'direct') {
|
||||
console.log(`❌ Expected transport 'direct', got '${payload.transport}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct transport');
|
||||
}
|
||||
|
||||
if (payload.encoding !== 'base64') {
|
||||
console.log(`❌ Expected encoding 'base64', got '${payload.encoding}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct encoding');
|
||||
}
|
||||
|
||||
// Verify Arrow IPC data can be decoded
|
||||
console.log('\n=== Arrow IPC Verification ===');
|
||||
const decodedData = Buffer.from(payload.data, 'base64');
|
||||
console.log(`Arrow IPC buffer size: ${decodedData.length} bytes`);
|
||||
|
||||
if (decodedData.length > 0) {
|
||||
console.log('✅ Arrow IPC data present');
|
||||
} else {
|
||||
console.log('❌ Arrow IPC data is empty');
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Test with larger table
|
||||
console.log('\n=== Larger Table Test ===');
|
||||
const largeTableData = [];
|
||||
for (let i = 1; i <= 100; i++) {
|
||||
largeTableData.push({
|
||||
id: i,
|
||||
name: `User${i}`,
|
||||
age: Math.floor(Math.random() * 100),
|
||||
active: Math.random() > 0.5,
|
||||
score: Math.random() * 100
|
||||
});
|
||||
}
|
||||
|
||||
const largeTestData = [
|
||||
['large_table', largeTableData, 'table']
|
||||
];
|
||||
|
||||
const [largeEnv, _] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
largeTestData,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: 'large-' + correlationId,
|
||||
is_publish: false
|
||||
}
|
||||
);
|
||||
|
||||
if (largeEnv.payloads.length === 1) {
|
||||
console.log('✅ Large table handled correctly');
|
||||
console.log(` Size: ${largeEnv.payloads[0].size} bytes`);
|
||||
} else {
|
||||
console.log('❌ Large table handling failed');
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Test JSON string output
|
||||
console.log('\n=== JSON String Output Test ===');
|
||||
try {
|
||||
const parsed = JSON.parse(envJsonStr);
|
||||
if (parsed.correlation_id === env.correlation_id &&
|
||||
parsed.payloads.length === env.payloads.length) {
|
||||
console.log('✅ JSON string is valid and matches envelope');
|
||||
} else {
|
||||
console.log('❌ JSON string does not match envelope');
|
||||
passed = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('❌ JSON string is invalid:', e.message);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Final result
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
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();
|
||||
@@ -1,207 +0,0 @@
|
||||
/**
|
||||
* JavaScript Text Receiver Test
|
||||
* Tests the smartreceive function with text payloads
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const TEST_BROKER_URL = process.env.NATS_URL || 'nats.yiem.cc';
|
||||
const TEST_FILESERVER_URL = process.env.FILESERVER_URL || 'http://192.168.88.104:8080';
|
||||
|
||||
async function runTest() {
|
||||
console.log('=== JavaScript Text Receiver Test ===\n');
|
||||
|
||||
// Create a mock NATS message with text payload
|
||||
const testData = {
|
||||
correlation_id: 'test-receiver-' + crypto.randomUUID(),
|
||||
msg_id: 'msg-' + crypto.randomUUID(),
|
||||
timestamp: new Date().toISOString(),
|
||||
send_to: '/test/text',
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-text-test',
|
||||
sender_id: 'sender-' + crypto.randomUUID(),
|
||||
receiver_name: 'js-receiver',
|
||||
receiver_id: 'receiver-' + crypto.randomUUID(),
|
||||
reply_to: '',
|
||||
reply_to_msg_id: '',
|
||||
broker_url: TEST_BROKER_URL,
|
||||
metadata: {},
|
||||
payloads: [
|
||||
{
|
||||
id: 'payload-' + crypto.randomUUID(),
|
||||
dataname: 'message',
|
||||
payload_type: 'text',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: 38,
|
||||
data: Buffer.from('Hello, NATSBridge! This is a test message.').toString('base64'),
|
||||
metadata: { payload_bytes: 38 }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const mockMsg = {
|
||||
payload: JSON.stringify(testData)
|
||||
};
|
||||
|
||||
console.log('Mock Message Created:');
|
||||
console.log(` Correlation ID: ${testData.correlation_id}`);
|
||||
console.log(` Payloads: ${testData.payloads.length}`);
|
||||
console.log(` Payload dataname: ${testData.payloads[0].dataname}`);
|
||||
console.log(` Payload type: ${testData.payloads[0].payload_type}`);
|
||||
console.log(` Transport: ${testData.payloads[0].transport}\n`);
|
||||
|
||||
try {
|
||||
// Receive and process the message
|
||||
console.log('Receiving and processing message...');
|
||||
const env = await NATSBridge.smartreceive(
|
||||
mockMsg,
|
||||
{
|
||||
max_retries: 3,
|
||||
base_delay: 100,
|
||||
max_delay: 1000
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n=== Received Envelope ===');
|
||||
console.log(`Correlation ID: ${env.correlation_id}`);
|
||||
console.log(`Message ID: ${env.msg_id}`);
|
||||
console.log(`Timestamp: ${env.timestamp}`);
|
||||
console.log(`Subject: ${env.send_to}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Validate received data
|
||||
console.log('=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (!env.correlation_id) {
|
||||
console.log('❌ correlation_id is missing');
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ correlation_id present');
|
||||
}
|
||||
|
||||
if (env.payloads.length !== 1) {
|
||||
console.log(`❌ Expected 1 payload, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
const payload = env.payloads[0];
|
||||
if (payload[0] !== 'message') {
|
||||
console.log(`❌ Expected dataname 'message', got '${payload[0]}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct dataname');
|
||||
}
|
||||
|
||||
if (payload[2] !== 'text') {
|
||||
console.log(`❌ Expected type 'text', got '${payload[2]}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct type');
|
||||
}
|
||||
|
||||
if (payload[1] !== 'Hello, NATSBridge! This is a test message.') {
|
||||
console.log(`❌ Data mismatch`);
|
||||
console.log(` Expected: Hello, NATSBridge! This is a test message.`);
|
||||
console.log(` Got: ${payload[1]}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Data correctly deserialized');
|
||||
}
|
||||
|
||||
// Test with multiple text payloads
|
||||
console.log('\n=== Multiple Text Payloads Test ===');
|
||||
const multiTestData = {
|
||||
correlation_id: 'multi-receiver-' + crypto.randomUUID(),
|
||||
msg_id: 'msg-' + crypto.randomUUID(),
|
||||
timestamp: new Date().toISOString(),
|
||||
send_to: '/test/text',
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-text-test',
|
||||
sender_id: 'sender-' + crypto.randomUUID(),
|
||||
receiver_name: 'js-receiver',
|
||||
receiver_id: 'receiver-' + crypto.randomUUID(),
|
||||
reply_to: '',
|
||||
reply_to_msg_id: '',
|
||||
broker_url: TEST_BROKER_URL,
|
||||
metadata: {},
|
||||
payloads: [
|
||||
{
|
||||
id: 'payload-1',
|
||||
dataname: 'msg1',
|
||||
payload_type: 'text',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: 16,
|
||||
data: Buffer.from('First message').toString('base64'),
|
||||
metadata: { payload_bytes: 16 }
|
||||
},
|
||||
{
|
||||
id: 'payload-2',
|
||||
dataname: 'msg2',
|
||||
payload_type: 'text',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: 16,
|
||||
data: Buffer.from('Second message').toString('base64'),
|
||||
metadata: { payload_bytes: 16 }
|
||||
},
|
||||
{
|
||||
id: 'payload-3',
|
||||
dataname: 'msg3',
|
||||
payload_type: 'text',
|
||||
transport: 'direct',
|
||||
encoding: 'base64',
|
||||
size: 16,
|
||||
data: Buffer.from('Third message').toString('base64'),
|
||||
metadata: { payload_bytes: 16 }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const mockMultiMsg = {
|
||||
payload: JSON.stringify(multiTestData)
|
||||
};
|
||||
|
||||
const multiEnv = await NATSBridge.smartreceive(mockMultiMsg);
|
||||
|
||||
if (multiEnv.payloads.length === 3) {
|
||||
console.log('✅ Multiple payloads handled correctly');
|
||||
|
||||
// Verify each payload
|
||||
const expectedMessages = ['First message', 'Second message', 'Third message'];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (multiEnv.payloads[i][1] === expectedMessages[i]) {
|
||||
console.log(`✅ Payload ${i + 1} correctly deserialized`);
|
||||
} else {
|
||||
console.log(`❌ Payload ${i + 1} mismatch`);
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(`❌ Expected 3 payloads, got ${multiEnv.payloads.length}`);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Final result
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
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();
|
||||
@@ -1,170 +0,0 @@
|
||||
/**
|
||||
* JavaScript Text Sender Test
|
||||
* Tests the smartsend function with text payloads
|
||||
*/
|
||||
|
||||
const NATSBridge = require('../src/natsbridge.js');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const TEST_SUBJECT = '/test/text';
|
||||
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 Text Sender Test ===\n');
|
||||
|
||||
const correlationId = crypto.randomUUID();
|
||||
console.log(`Correlation ID: ${correlationId}`);
|
||||
console.log(`Subject: ${TEST_SUBJECT}`);
|
||||
console.log(`Broker URL: ${TEST_BROKER_URL}\n`);
|
||||
|
||||
// Test data
|
||||
const textData = 'Hello, NATSBridge! This is a test message.';
|
||||
const testData = [
|
||||
['message', textData, 'text']
|
||||
];
|
||||
|
||||
try {
|
||||
// Send the message
|
||||
console.log('Sending text payload...');
|
||||
const [env, envJsonStr] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
testData,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: correlationId,
|
||||
msg_purpose: 'test',
|
||||
sender_name: 'js-text-test',
|
||||
is_publish: false // Don't actually publish for this test
|
||||
}
|
||||
);
|
||||
|
||||
console.log('\n=== Envelope Created ===');
|
||||
console.log(`Correlation ID: ${env.correlation_id}`);
|
||||
console.log(`Message ID: ${env.msg_id}`);
|
||||
console.log(`Timestamp: ${env.timestamp}`);
|
||||
console.log(`Subject: ${env.send_to}`);
|
||||
console.log(`Purpose: ${env.msg_purpose}`);
|
||||
console.log(`Sender: ${env.sender_name}`);
|
||||
console.log(`Payloads: ${env.payloads.length}\n`);
|
||||
|
||||
// Validate envelope structure
|
||||
console.log('=== Validation ===');
|
||||
let passed = true;
|
||||
|
||||
if (!env.correlation_id) {
|
||||
console.log('❌ correlation_id is missing');
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ correlation_id present');
|
||||
}
|
||||
|
||||
if (!env.msg_id) {
|
||||
console.log('❌ msg_id is missing');
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ msg_id present');
|
||||
}
|
||||
|
||||
if (!env.timestamp) {
|
||||
console.log('❌ timestamp is missing');
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ timestamp present');
|
||||
}
|
||||
|
||||
if (env.payloads.length !== 1) {
|
||||
console.log(`❌ Expected 1 payload, got ${env.payloads.length}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct number of payloads');
|
||||
}
|
||||
|
||||
const payload = env.payloads[0];
|
||||
if (payload.dataname !== 'message') {
|
||||
console.log(`❌ Expected dataname 'message', got '${payload.dataname}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct dataname');
|
||||
}
|
||||
|
||||
if (payload.payload_type !== 'text') {
|
||||
console.log(`❌ Expected payload_type 'text', got '${payload.payload_type}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct payload_type');
|
||||
}
|
||||
|
||||
if (payload.transport !== 'direct') {
|
||||
console.log(`❌ Expected transport 'direct', got '${payload.transport}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct transport');
|
||||
}
|
||||
|
||||
if (payload.encoding !== 'base64') {
|
||||
console.log(`❌ Expected encoding 'base64', got '${payload.encoding}'`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Correct encoding');
|
||||
}
|
||||
|
||||
// Decode and verify the data
|
||||
const decodedData = Buffer.from(payload.data, 'base64').toString('utf8');
|
||||
if (decodedData !== textData) {
|
||||
console.log(`❌ Decoded data mismatch`);
|
||||
console.log(` Expected: ${textData}`);
|
||||
console.log(` Got: ${decodedData}`);
|
||||
passed = false;
|
||||
} else {
|
||||
console.log('✅ Data integrity verified');
|
||||
}
|
||||
|
||||
console.log(`\nPayload size: ${payload.size} bytes`);
|
||||
console.log(`Base64 data length: ${payload.data.length} chars`);
|
||||
|
||||
// Test with multiple text payloads
|
||||
console.log('\n=== Multiple Text Payloads Test ===');
|
||||
const multiTestData = [
|
||||
['msg1', 'First message', 'text'],
|
||||
['msg2', 'Second message', 'text'],
|
||||
['msg3', 'Third message', 'text']
|
||||
];
|
||||
|
||||
const [multiEnv, multiEnvJsonStr] = await NATSBridge.smartsend(
|
||||
TEST_SUBJECT,
|
||||
multiTestData,
|
||||
{
|
||||
broker_url: TEST_BROKER_URL,
|
||||
fileserver_url: TEST_FILESERVER_URL,
|
||||
correlation_id: 'multi-test-' + correlationId,
|
||||
is_publish: false
|
||||
}
|
||||
);
|
||||
|
||||
if (multiEnv.payloads.length === 3) {
|
||||
console.log('✅ Multiple payloads handled correctly');
|
||||
} else {
|
||||
console.log(`❌ Expected 3 payloads, got ${multiEnv.payloads.length}`);
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// Final result
|
||||
console.log('\n=== Test Result ===');
|
||||
if (passed) {
|
||||
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();
|
||||
@@ -1,185 +0,0 @@
|
||||
"""
|
||||
MicroPython Binary Receiver Test
|
||||
Tests the smartreceive function with binary/image/audio/video payloads
|
||||
|
||||
Note: This test is designed for both MicroPython and desktop Python
|
||||
for compatibility testing.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import base64
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge_mpy import smartreceive, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
def run_test():
|
||||
print('=== MicroPython Binary Receiver Test ===\n')
|
||||
|
||||
from natsbridge_mpy import _generate_uuid
|
||||
|
||||
# Create mock NATS message with binary payloads
|
||||
image_data = bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]) # PNG header
|
||||
audio_data = bytes([0x46, 0x4C, 0x41, 0x43, 0x00, 0x00, 0x00, 0x00]) # FLAC header
|
||||
video_data = bytes([0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70]) # MP4 header
|
||||
generic_binary = bytes([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE])
|
||||
|
||||
test_data = {
|
||||
'correlation_id': 'mpy-binary-receiver-' + _generate_uuid(),
|
||||
'msg_id': _generate_uuid(),
|
||||
'timestamp': '2024-01-15T10:30:00Z',
|
||||
'send_to': '/test/binary',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'mpy-binary-test',
|
||||
'sender_id': _generate_uuid(),
|
||||
'receiver_name': 'mpy-receiver',
|
||||
'receiver_id': _generate_uuid(),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'image',
|
||||
'payload_type': 'image',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(image_data),
|
||||
'data': base64.b64encode(image_data).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(image_data)}
|
||||
},
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'audio',
|
||||
'payload_type': 'audio',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(audio_data),
|
||||
'data': base64.b64encode(audio_data).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(audio_data)}
|
||||
},
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'video',
|
||||
'payload_type': 'video',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(video_data),
|
||||
'data': base64.b64encode(video_data).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(video_data)}
|
||||
},
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'binary',
|
||||
'payload_type': 'binary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(generic_binary),
|
||||
'data': base64.b64encode(generic_binary).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(generic_binary)}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_msg = {
|
||||
'payload': json.dumps(test_data)
|
||||
}
|
||||
|
||||
print('Mock Message Created:')
|
||||
print(f' Correlation ID: {test_data["correlation_id"]}')
|
||||
print(f' Payloads: {len(test_data["payloads"])}')
|
||||
print(f' Payload types: {", ".join(p["payload_type"] for p in test_data["payloads"])}\n')
|
||||
|
||||
try:
|
||||
# Receive and process the message
|
||||
print('Receiving and processing message...')
|
||||
env = smartreceive(
|
||||
mock_msg,
|
||||
max_retries=3,
|
||||
base_delay=100,
|
||||
max_delay=1000
|
||||
)
|
||||
|
||||
print('\n=== Received Envelope ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate received data
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if not env.get('correlation_id'):
|
||||
print('❌ correlation_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ correlation_id present')
|
||||
|
||||
if len(env['payloads']) != 4:
|
||||
print(f'❌ Expected 4 payloads, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
# Expected data
|
||||
expected_data = [
|
||||
('image', image_data, 'image'),
|
||||
('audio', audio_data, 'audio'),
|
||||
('video', video_data, 'video'),
|
||||
('binary', generic_binary, 'binary')
|
||||
]
|
||||
|
||||
for i in range(len(env['payloads'])):
|
||||
payload = env['payloads'][i]
|
||||
expected = expected_data[i]
|
||||
|
||||
if payload[0] != expected[0]:
|
||||
print(f"❌ Payload {i + 1}: Expected dataname '{expected[0]}', got '{payload[0]}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct dataname')
|
||||
|
||||
if payload[2] != expected[2]:
|
||||
print(f"❌ Payload {i + 1}: Expected type '{expected[2]}', got '{payload[2]}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct type')
|
||||
|
||||
# Verify binary data integrity
|
||||
received_data = payload[1]
|
||||
if received_data != expected[1]:
|
||||
print(f'❌ Payload {i + 1}: Data mismatch')
|
||||
print(f' Expected: {expected[1]}')
|
||||
print(f' Got: {received_data}')
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Data correctly deserialized')
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test()
|
||||
@@ -1,163 +0,0 @@
|
||||
"""
|
||||
MicroPython Binary Sender Test
|
||||
Tests the smartsend function with binary/image/audio/video payloads
|
||||
|
||||
Note: This test is designed for both MicroPython and desktop Python
|
||||
for compatibility testing.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import base64
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge_mpy import smartsend, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL, DEFAULT_SIZE_THRESHOLD, MAX_PAYLOAD_SIZE
|
||||
|
||||
TEST_SUBJECT = '/test/binary'
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
def run_test():
|
||||
print('=== MicroPython Binary Sender Test ===\n')
|
||||
|
||||
from natsbridge_mpy import _generate_uuid
|
||||
correlation_id = 'mpy-binary-test-' + _generate_uuid()
|
||||
print(f'Correlation ID: {correlation_id}')
|
||||
print(f'Subject: {TEST_SUBJECT}')
|
||||
print(f'Broker URL: {TEST_BROKER_URL}')
|
||||
print(f'Default Size Threshold: {DEFAULT_SIZE_THRESHOLD} bytes')
|
||||
print(f'Max Payload Size: {MAX_PAYLOAD_SIZE} bytes\n')
|
||||
|
||||
# Test data - binary data for different types
|
||||
image_data = bytearray([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]) # PNG header
|
||||
audio_data = bytearray([0x46, 0x4C, 0x41, 0x43, 0x00, 0x00, 0x00, 0x00]) # FLAC header
|
||||
video_data = bytearray([0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70]) # MP4 header
|
||||
generic_binary = bytearray([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE])
|
||||
|
||||
test_data = [
|
||||
('image', bytes(image_data), 'image'),
|
||||
('audio', bytes(audio_data), 'audio'),
|
||||
('video', bytes(video_data), 'video'),
|
||||
('binary', bytes(generic_binary), 'binary')
|
||||
]
|
||||
|
||||
try:
|
||||
# Send the message
|
||||
print('Sending binary payloads...')
|
||||
env, env_json_str = smartsend(
|
||||
TEST_SUBJECT,
|
||||
test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id=correlation_id,
|
||||
msg_purpose='test',
|
||||
sender_name='mpy-binary-test',
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
print('\n=== Envelope Created ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Purpose: {env["msg_purpose"]}')
|
||||
print(f'Sender: {env["sender_name"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate envelope structure
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if len(env['payloads']) != 4:
|
||||
print(f'❌ Expected 4 payloads, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
# Test each payload
|
||||
expected_datanames = ['image', 'audio', 'video', 'binary']
|
||||
expected_types = ['image', 'audio', 'video', 'binary']
|
||||
expected_data = [bytes(image_data), bytes(audio_data), bytes(video_data), bytes(generic_binary)]
|
||||
|
||||
for i in range(len(env['payloads'])):
|
||||
payload = env['payloads'][i]
|
||||
|
||||
if payload['dataname'] != expected_datanames[i]:
|
||||
print(f"❌ Payload {i + 1}: Expected dataname '{expected_datanames[i]}', got '{payload['dataname']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct dataname')
|
||||
|
||||
if payload['payload_type'] != expected_types[i]:
|
||||
print(f"❌ Payload {i + 1}: Expected type '{expected_types[i]}', got '{payload['payload_type']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct type')
|
||||
|
||||
if payload['transport'] != 'direct':
|
||||
print(f"❌ Payload {i + 1}: Expected transport 'direct', got '{payload['transport']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct transport')
|
||||
|
||||
if payload['encoding'] != 'base64':
|
||||
print(f"❌ Payload {i + 1}: Expected encoding 'base64', got '{payload['encoding']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct encoding')
|
||||
|
||||
# Decode and verify the data
|
||||
decoded_data = base64.b64decode(payload['data'])
|
||||
original_data = expected_data[i]
|
||||
|
||||
if decoded_data != original_data:
|
||||
print(f'❌ Payload {i + 1}: Data integrity mismatch')
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Data integrity verified')
|
||||
|
||||
print(f' Size: {payload["size"]} bytes\n')
|
||||
|
||||
# Test with larger binary data
|
||||
print('=== Large Binary Data Test ===')
|
||||
large_data = bytes([0xFF] * 1000) # 1KB of binary data
|
||||
large_test_data = [
|
||||
('large_binary', large_data, 'binary')
|
||||
]
|
||||
|
||||
large_env, _ = smartsend(
|
||||
TEST_SUBJECT,
|
||||
large_test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id='large-' + correlation_id,
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
if len(large_env['payloads']) == 1 and large_env['payloads'][0]['size'] == 1000:
|
||||
print('✅ Large binary data handled correctly')
|
||||
else:
|
||||
print('❌ Large binary data handling failed')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test()
|
||||
@@ -1,224 +0,0 @@
|
||||
"""
|
||||
MicroPython Dictionary Receiver Test
|
||||
Tests the smartreceive function with dictionary payloads
|
||||
|
||||
Note: This test is designed for both MicroPython and desktop Python
|
||||
for compatibility testing.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge_mpy import smartreceive, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
def run_test():
|
||||
print('=== MicroPython Dictionary Receiver Test ===\n')
|
||||
|
||||
from natsbridge_mpy import _generate_uuid
|
||||
|
||||
# Create a mock NATS message with dictionary payloads
|
||||
import base64
|
||||
|
||||
simple_dict = {'key1': 'value1', 'key2': 'value2'}
|
||||
nested_dict = {'outer': {'inner': 'value', 'number': 42}}
|
||||
array_dict = {'items': [1, 2, 3, 'four', 'five']}
|
||||
mixed_dict = {'string': 'text', 'number': 123, 'boolean': True, 'null_val': None}
|
||||
|
||||
test_data = {
|
||||
'correlation_id': 'mpy-receiver-dict-' + _generate_uuid(),
|
||||
'msg_id': _generate_uuid(),
|
||||
'timestamp': '2024-01-15T10:30:00Z',
|
||||
'send_to': '/test/dictionary',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'mpy-dict-test',
|
||||
'sender_id': _generate_uuid(),
|
||||
'receiver_name': 'mpy-receiver',
|
||||
'receiver_id': _generate_uuid(),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'simple_dict',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps(simple_dict).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps(simple_dict).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps(simple_dict).encode('utf8'))}
|
||||
},
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'nested_dict',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps(nested_dict).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps(nested_dict).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps(nested_dict).encode('utf8'))}
|
||||
},
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'array_dict',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps(array_dict).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps(array_dict).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps(array_dict).encode('utf8'))}
|
||||
},
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'mixed_dict',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps(mixed_dict).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps(mixed_dict).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps(mixed_dict).encode('utf8'))}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_msg = {
|
||||
'payload': json.dumps(test_data)
|
||||
}
|
||||
|
||||
print('Mock Message Created:')
|
||||
print(f' Correlation ID: {test_data["correlation_id"]}')
|
||||
print(f' Payloads: {len(test_data["payloads"])}')
|
||||
print(f' Payload types: {", ".join(p["payload_type"] for p in test_data["payloads"])}\n')
|
||||
|
||||
try:
|
||||
# Receive and process the message
|
||||
print('Receiving and processing message...')
|
||||
env = smartreceive(
|
||||
mock_msg,
|
||||
max_retries=3,
|
||||
base_delay=100,
|
||||
max_delay=1000
|
||||
)
|
||||
|
||||
print('\n=== Received Envelope ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate received data
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if not env.get('correlation_id'):
|
||||
print('❌ correlation_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ correlation_id present')
|
||||
|
||||
if len(env['payloads']) != 4:
|
||||
print(f'❌ Expected 4 payloads, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
# Expected data
|
||||
expected_data = [
|
||||
('simple_dict', simple_dict, 'dictionary'),
|
||||
('nested_dict', nested_dict, 'dictionary'),
|
||||
('array_dict', array_dict, 'dictionary'),
|
||||
('mixed_dict', mixed_dict, 'dictionary')
|
||||
]
|
||||
|
||||
for i in range(len(env['payloads'])):
|
||||
payload = env['payloads'][i]
|
||||
expected = expected_data[i]
|
||||
|
||||
if payload[0] != expected[0]:
|
||||
print(f"❌ Payload {i + 1}: Expected dataname '{expected[0]}', got '{payload[0]}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct dataname')
|
||||
|
||||
if payload[2] != expected[2]:
|
||||
print(f"❌ Payload {i + 1}: Expected type '{expected[2]}', got '{payload[2]}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct type')
|
||||
|
||||
data_match = json.dumps(payload[1], sort_keys=True) == json.dumps(expected[1], sort_keys=True)
|
||||
if not data_match:
|
||||
print(f'❌ Payload {i + 1}: Data mismatch')
|
||||
print(f' Expected: {json.dumps(expected[1], sort_keys=True)}')
|
||||
print(f' Got: {json.dumps(payload[1], sort_keys=True)}')
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Data correctly deserialized')
|
||||
|
||||
# Test round-trip with receive
|
||||
print('\n=== Round-trip Test ===')
|
||||
round_trip_data = {
|
||||
'correlation_id': 'roundtrip-' + _generate_uuid(),
|
||||
'msg_id': _generate_uuid(),
|
||||
'timestamp': '2024-01-15T10:30:00Z',
|
||||
'send_to': '/test/dictionary',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'mpy-test',
|
||||
'sender_id': _generate_uuid(),
|
||||
'receiver_name': 'mpy-receiver',
|
||||
'receiver_id': _generate_uuid(),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'roundtrip',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps({'test': 'data', 'nested': {'a': 1, 'b': 2}}).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps({'test': 'data', 'nested': {'a': 1, 'b': 2}}).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps({'test': 'data', 'nested': {'a': 1, 'b': 2}}).encode('utf8'))}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_rt_msg = {'payload': json.dumps(round_trip_data)}
|
||||
rt_env = smartreceive(mock_rt_msg)
|
||||
|
||||
if rt_env['payloads'][0][0] == 'roundtrip' and rt_env['payloads'][0][2] == 'dictionary':
|
||||
print('✅ Round-trip test successful')
|
||||
else:
|
||||
print('❌ Round-trip test failed')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test()
|
||||
@@ -1,177 +0,0 @@
|
||||
"""
|
||||
MicroPython Dictionary Sender Test
|
||||
Tests the smartsend function with dictionary payloads
|
||||
|
||||
Note: This test is designed for both MicroPython and desktop Python
|
||||
for compatibility testing.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge_mpy import smartsend, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL, DEFAULT_SIZE_THRESHOLD, MAX_PAYLOAD_SIZE
|
||||
|
||||
TEST_SUBJECT = '/test/dictionary'
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
def run_test():
|
||||
print('=== MicroPython Dictionary Sender Test ===\n')
|
||||
|
||||
from natsbridge_mpy import _generate_uuid
|
||||
correlation_id = 'mpy-dict-test-' + _generate_uuid()
|
||||
print(f'Correlation ID: {correlation_id}')
|
||||
print(f'Subject: {TEST_SUBJECT}')
|
||||
print(f'Broker URL: {TEST_BROKER_URL}')
|
||||
print(f'Default Size Threshold: {DEFAULT_SIZE_THRESHOLD} bytes')
|
||||
print(f'Max Payload Size: {MAX_PAYLOAD_SIZE} bytes\n')
|
||||
|
||||
# Test data - various dictionary structures
|
||||
test_data = [
|
||||
('simple_dict', {'key1': 'value1', 'key2': 'value2'}, 'dictionary'),
|
||||
('nested_dict', {'outer': {'inner': 'value', 'number': 42}}, 'dictionary'),
|
||||
('array_dict', {'items': [1, 2, 3, 'four', 'five']}, 'dictionary'),
|
||||
('mixed_dict', {'string': 'text', 'number': 123, 'boolean': True, 'null_val': None}, 'dictionary')
|
||||
]
|
||||
|
||||
try:
|
||||
# Send the message
|
||||
print('Sending dictionary payloads...')
|
||||
env, env_json_str = smartsend(
|
||||
TEST_SUBJECT,
|
||||
test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id=correlation_id,
|
||||
msg_purpose='test',
|
||||
sender_name='mpy-dict-test',
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
print('\n=== Envelope Created ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Purpose: {env["msg_purpose"]}')
|
||||
print(f'Sender: {env["sender_name"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate envelope structure
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if len(env['payloads']) != 4:
|
||||
print(f'❌ Expected 4 payloads, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
# Test each payload
|
||||
expected_datanames = ['simple_dict', 'nested_dict', 'array_dict', 'mixed_dict']
|
||||
expected_types = ['dictionary', 'dictionary', 'dictionary', 'dictionary']
|
||||
|
||||
for i in range(len(env['payloads'])):
|
||||
payload = env['payloads'][i]
|
||||
|
||||
if payload['dataname'] != expected_datanames[i]:
|
||||
print(f"❌ Payload {i + 1}: Expected dataname '{expected_datanames[i]}', got '{payload['dataname']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct dataname')
|
||||
|
||||
if payload['payload_type'] != expected_types[i]:
|
||||
print(f"❌ Payload {i + 1}: Expected type '{expected_types[i]}', got '{payload['payload_type']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct type')
|
||||
|
||||
if payload['transport'] != 'direct':
|
||||
print(f"❌ Payload {i + 1}: Expected transport 'direct', got '{payload['transport']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct transport')
|
||||
|
||||
if payload['encoding'] != 'base64':
|
||||
print(f"❌ Payload {i + 1}: Expected encoding 'base64', got '{payload['encoding']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct encoding')
|
||||
|
||||
# Decode and verify the data
|
||||
import base64
|
||||
decoded_data = json.loads(base64.b64decode(payload['data']).decode('ascii'))
|
||||
original_data = test_data[i][1]
|
||||
|
||||
# Normalize for comparison
|
||||
if json.dumps(decoded_data, sort_keys=True) != json.dumps(original_data, sort_keys=True):
|
||||
print(f'❌ Payload {i + 1}: Data integrity mismatch')
|
||||
print(f' Expected: {json.dumps(original_data)}')
|
||||
print(f' Got: {json.dumps(decoded_data)}')
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Data integrity verified')
|
||||
|
||||
print(f' Size: {payload["size"]} bytes\n')
|
||||
|
||||
# Test round-trip serialization
|
||||
print('=== Round-trip Serialization Test ===')
|
||||
round_trip_data = [
|
||||
('roundtrip', {'test': 'data', 'numbers': [1, 2, 3], 'nested': {'a': 1, 'b': 2}}, 'dictionary')
|
||||
]
|
||||
|
||||
rt_env, _ = smartsend(
|
||||
TEST_SUBJECT,
|
||||
round_trip_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id='roundtrip-' + correlation_id,
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
rt_payload = rt_env['payloads'][0]
|
||||
rt_decoded = json.loads(base64.b64decode(rt_payload['data']).decode('ascii'))
|
||||
|
||||
if json.dumps(rt_decoded, sort_keys=True) == json.dumps(round_trip_data[0][1], sort_keys=True):
|
||||
print('✅ Round-trip serialization successful')
|
||||
else:
|
||||
print('❌ Round-trip serialization failed')
|
||||
passed = False
|
||||
|
||||
# Test JSON string output
|
||||
print('\n=== JSON String Output Test ===')
|
||||
try:
|
||||
parsed = json.loads(env_json_str)
|
||||
if parsed['correlation_id'] == env['correlation_id'] and \
|
||||
len(parsed['payloads']) == len(env['payloads']):
|
||||
print('✅ JSON string is valid and matches envelope')
|
||||
else:
|
||||
print('❌ JSON string does not match envelope')
|
||||
passed = False
|
||||
except json.JSONDecodeError as e:
|
||||
print(f'❌ JSON string is invalid: {e}')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test()
|
||||
@@ -1,209 +0,0 @@
|
||||
"""
|
||||
MicroPython Text Receiver Test
|
||||
Tests the smartreceive function with text payloads
|
||||
|
||||
Note: This test is designed for both MicroPython and desktop Python
|
||||
for compatibility testing.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge_mpy import smartreceive, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
def run_test():
|
||||
print('=== MicroPython Text Receiver Test ===\n')
|
||||
|
||||
from natsbridge_mpy import _generate_uuid
|
||||
|
||||
# Create a mock NATS message with text payload
|
||||
test_text = 'Hello, NATSBridge! This is a test message.'
|
||||
import base64
|
||||
|
||||
test_data = {
|
||||
'correlation_id': 'mpy-receiver-test-' + _generate_uuid(),
|
||||
'msg_id': _generate_uuid(),
|
||||
'timestamp': '2024-01-15T10:30:00Z',
|
||||
'send_to': '/test/text',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'mpy-text-test',
|
||||
'sender_id': _generate_uuid(),
|
||||
'receiver_name': 'mpy-receiver',
|
||||
'receiver_id': _generate_uuid(),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'message',
|
||||
'payload_type': 'text',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(test_text.encode('utf8')),
|
||||
'data': base64.b64encode(test_text.encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(test_text.encode('utf8'))}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_msg = {
|
||||
'payload': json.dumps(test_data)
|
||||
}
|
||||
|
||||
print('Mock Message Created:')
|
||||
print(f' Correlation ID: {test_data["correlation_id"]}')
|
||||
print(f' Payloads: {len(test_data["payloads"])}')
|
||||
print(f' Payload dataname: {test_data["payloads"][0]["dataname"]}')
|
||||
print(f' Payload type: {test_data["payloads"][0]["payload_type"]}')
|
||||
print(f' Transport: {test_data["payloads"][0]["transport"]}\n')
|
||||
|
||||
try:
|
||||
# Receive and process the message
|
||||
print('Receiving and processing message...')
|
||||
env = smartreceive(
|
||||
mock_msg,
|
||||
max_retries=3,
|
||||
base_delay=100,
|
||||
max_delay=1000
|
||||
)
|
||||
|
||||
print('\n=== Received Envelope ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate received data
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if not env.get('correlation_id'):
|
||||
print('❌ correlation_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ correlation_id present')
|
||||
|
||||
if len(env['payloads']) != 1:
|
||||
print(f'❌ Expected 1 payload, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
payload = env['payloads'][0]
|
||||
if payload[0] != 'message':
|
||||
print(f"❌ Expected dataname 'message', got '{payload[0]}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct dataname')
|
||||
|
||||
if payload[2] != 'text':
|
||||
print(f"❌ Expected type 'text', got '{payload[2]}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct type')
|
||||
|
||||
if payload[1] != test_text:
|
||||
print('❌ Data mismatch')
|
||||
print(f' Expected: {test_text}')
|
||||
print(f' Got: {payload[1]}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Data correctly deserialized')
|
||||
|
||||
# Test with multiple text payloads
|
||||
print('\n=== Multiple Text Payloads Test ===')
|
||||
multi_test_data = {
|
||||
'correlation_id': 'multi-receiver-' + _generate_uuid(),
|
||||
'msg_id': _generate_uuid(),
|
||||
'timestamp': '2024-01-15T10:30:00Z',
|
||||
'send_to': '/test/text',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'mpy-text-test',
|
||||
'sender_id': _generate_uuid(),
|
||||
'receiver_name': 'mpy-receiver',
|
||||
'receiver_id': _generate_uuid(),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'msg1',
|
||||
'payload_type': 'text',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': 16,
|
||||
'data': base64.b64encode(b'First message').decode('ascii'),
|
||||
'metadata': {'payload_bytes': 16}
|
||||
},
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'msg2',
|
||||
'payload_type': 'text',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': 16,
|
||||
'data': base64.b64encode(b'Second message').decode('ascii'),
|
||||
'metadata': {'payload_bytes': 16}
|
||||
},
|
||||
{
|
||||
'id': _generate_uuid(),
|
||||
'dataname': 'msg3',
|
||||
'payload_type': 'text',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': 16,
|
||||
'data': base64.b64encode(b'Third message').decode('ascii'),
|
||||
'metadata': {'payload_bytes': 16}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_multi_msg = {'payload': json.dumps(multi_test_data)}
|
||||
multi_env = smartreceive(mock_multi_msg)
|
||||
|
||||
if len(multi_env['payloads']) == 3:
|
||||
print('✅ Multiple payloads handled correctly')
|
||||
|
||||
# Verify each payload
|
||||
expected_messages = ['First message', 'Second message', 'Third message']
|
||||
for i in range(3):
|
||||
if multi_env['payloads'][i][1] == expected_messages[i]:
|
||||
print(f'✅ Payload {i + 1} correctly deserialized')
|
||||
else:
|
||||
print(f'❌ Payload {i + 1} mismatch')
|
||||
passed = False
|
||||
else:
|
||||
print(f'❌ Expected 3 payloads, got {len(multi_env["payloads"])}')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test()
|
||||
@@ -1,205 +0,0 @@
|
||||
"""
|
||||
MicroPython Text Sender Test
|
||||
Tests the smartsend function with text payloads
|
||||
|
||||
Note: This test is designed for both MicroPython and desktop Python
|
||||
for compatibility testing.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge_mpy import smartsend, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL, DEFAULT_SIZE_THRESHOLD, MAX_PAYLOAD_SIZE
|
||||
|
||||
TEST_SUBJECT = '/test/text'
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
def run_test():
|
||||
print('=== MicroPython Text Sender Test ===\n')
|
||||
|
||||
from natsbridge_mpy import _generate_uuid
|
||||
correlation_id = 'mpy-text-test-' + _generate_uuid()
|
||||
print(f'Correlation ID: {correlation_id}')
|
||||
print(f'Subject: {TEST_SUBJECT}')
|
||||
print(f'Broker URL: {TEST_BROKER_URL}')
|
||||
print(f'Default Size Threshold: {DEFAULT_SIZE_THRESHOLD} bytes')
|
||||
print(f'Max Payload Size: {MAX_PAYLOAD_SIZE} bytes\n')
|
||||
|
||||
# Test data
|
||||
text_data = 'Hello, NATSBridge! This is a test message.'
|
||||
test_data = [
|
||||
('message', text_data, 'text')
|
||||
]
|
||||
|
||||
try:
|
||||
# Send the message
|
||||
print('Sending text payload...')
|
||||
env, env_json_str = smartsend(
|
||||
TEST_SUBJECT,
|
||||
test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id=correlation_id,
|
||||
msg_purpose='test',
|
||||
sender_name='mpy-text-test',
|
||||
is_publish=False # Don't actually publish for this test
|
||||
)
|
||||
|
||||
print('\n=== Envelope Created ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Purpose: {env["msg_purpose"]}')
|
||||
print(f'Sender: {env["sender_name"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate envelope structure
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if not env.get('correlation_id'):
|
||||
print('❌ correlation_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ correlation_id present')
|
||||
|
||||
if not env.get('msg_id'):
|
||||
print('❌ msg_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ msg_id present')
|
||||
|
||||
if not env.get('timestamp'):
|
||||
print('❌ timestamp is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ timestamp present')
|
||||
|
||||
if len(env['payloads']) != 1:
|
||||
print(f'❌ Expected 1 payload, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
payload = env['payloads'][0]
|
||||
if payload['dataname'] != 'message':
|
||||
print(f"❌ Expected dataname 'message', got '{payload['dataname']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct dataname')
|
||||
|
||||
if payload['payload_type'] != 'text':
|
||||
print(f"❌ Expected payload_type 'text', got '{payload['payload_type']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct payload_type')
|
||||
|
||||
if payload['transport'] != 'direct':
|
||||
print(f"❌ Expected transport 'direct', got '{payload['transport']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct transport')
|
||||
|
||||
if payload['encoding'] != 'base64':
|
||||
print(f"❌ Expected encoding 'base64', got '{payload['encoding']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct encoding')
|
||||
|
||||
# Decode and verify the data
|
||||
import base64
|
||||
decoded_data = base64.b64decode(payload['data']).decode('ascii')
|
||||
if decoded_data != text_data:
|
||||
print('❌ Decoded data mismatch')
|
||||
print(f' Expected: {text_data}')
|
||||
print(f' Got: {decoded_data}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Data integrity verified')
|
||||
|
||||
print(f'\nPayload size: {payload["size"]} bytes')
|
||||
print(f'Base64 data length: {len(payload["data"])} chars')
|
||||
|
||||
# Test with multiple text payloads
|
||||
print('\n=== Multiple Text Payloads Test ===')
|
||||
multi_test_data = [
|
||||
('msg1', 'First message', 'text'),
|
||||
('msg2', 'Second message', 'text'),
|
||||
('msg3', 'Third message', 'text')
|
||||
]
|
||||
|
||||
multi_env, _ = smartsend(
|
||||
TEST_SUBJECT,
|
||||
multi_test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id='multi-test-' + correlation_id,
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
if len(multi_env['payloads']) == 3:
|
||||
print('✅ Multiple payloads handled correctly')
|
||||
else:
|
||||
print(f'❌ Expected 3 payloads, got {len(multi_env["payloads"])}')
|
||||
passed = False
|
||||
|
||||
# Test size threshold enforcement
|
||||
print('\n=== Size Threshold Test ===')
|
||||
small_text = 'small'
|
||||
large_text = 'x' * (DEFAULT_SIZE_THRESHOLD - 100) # Just under threshold
|
||||
|
||||
small_env, _ = smartsend(
|
||||
TEST_SUBJECT,
|
||||
[('small', small_text, 'text')],
|
||||
broker_url=TEST_BROKER_URL,
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
if small_env['payloads'][0]['transport'] == 'direct':
|
||||
print('✅ Small payload uses direct transport')
|
||||
else:
|
||||
print('❌ Small payload should use direct transport')
|
||||
passed = False
|
||||
|
||||
# Test that large text (> MAX_PAYLOAD_SIZE) raises error
|
||||
print('\n=== Max Payload Size Test ===')
|
||||
try:
|
||||
too_large_text = 'x' * (MAX_PAYLOAD_SIZE + 1000)
|
||||
large_env, _ = smartsend(
|
||||
TEST_SUBJECT,
|
||||
[('large', too_large_text, 'text')],
|
||||
broker_url=TEST_BROKER_URL,
|
||||
is_publish=False
|
||||
)
|
||||
print('❌ Should have raised MemoryError for payload exceeding MAX_PAYLOAD_SIZE')
|
||||
passed = False
|
||||
except MemoryError as e:
|
||||
print(f'✅ Correctly raised MemoryError: {e}')
|
||||
except Exception as e:
|
||||
print(f'❌ Unexpected error: {type(e).__name__}: {e}')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test()
|
||||
@@ -1,184 +0,0 @@
|
||||
"""
|
||||
Python Binary Receiver Test
|
||||
Tests the smartreceive function with binary/image/audio/video/table payloads
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import base64
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge import smartreceive, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
async def run_test():
|
||||
print('=== Python Binary Receiver Test ===\n')
|
||||
|
||||
# Create mock NATS message with binary payloads
|
||||
image_data = bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]) # PNG header
|
||||
audio_data = bytes([0x46, 0x4C, 0x41, 0x43, 0x00, 0x00, 0x00, 0x00]) # FLAC header
|
||||
video_data = bytes([0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70]) # MP4 header
|
||||
generic_binary = bytes([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE])
|
||||
|
||||
test_data = {
|
||||
'correlation_id': 'py-binary-receiver-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'msg_id': 'msg-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'timestamp': asyncio.get_event_loop().time().isoformat(),
|
||||
'send_to': '/test/binary',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'py-binary-test',
|
||||
'sender_id': 'sender-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'receiver_name': 'py-receiver',
|
||||
'receiver_id': 'receiver-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': 'payload-1',
|
||||
'dataname': 'image',
|
||||
'payload_type': 'image',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(image_data),
|
||||
'data': base64.b64encode(image_data).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(image_data)}
|
||||
},
|
||||
{
|
||||
'id': 'payload-2',
|
||||
'dataname': 'audio',
|
||||
'payload_type': 'audio',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(audio_data),
|
||||
'data': base64.b64encode(audio_data).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(audio_data)}
|
||||
},
|
||||
{
|
||||
'id': 'payload-3',
|
||||
'dataname': 'video',
|
||||
'payload_type': 'video',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(video_data),
|
||||
'data': base64.b64encode(video_data).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(video_data)}
|
||||
},
|
||||
{
|
||||
'id': 'payload-4',
|
||||
'dataname': 'binary',
|
||||
'payload_type': 'binary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(generic_binary),
|
||||
'data': base64.b64encode(generic_binary).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(generic_binary)}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_msg = {
|
||||
'payload': json.dumps(test_data)
|
||||
}
|
||||
|
||||
print('Mock Message Created:')
|
||||
print(f' Correlation ID: {test_data["correlation_id"]}')
|
||||
print(f' Payloads: {len(test_data["payloads"])}')
|
||||
print(f' Payload types: {", ".join(p["payload_type"] for p in test_data["payloads"])}\n')
|
||||
|
||||
try:
|
||||
# Receive and process the message
|
||||
print('Receiving and processing message...')
|
||||
env = await smartreceive(
|
||||
mock_msg,
|
||||
max_retries=3,
|
||||
base_delay=100,
|
||||
max_delay=1000
|
||||
)
|
||||
|
||||
print('\n=== Received Envelope ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate received data
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if not env.get('correlation_id'):
|
||||
print('❌ correlation_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ correlation_id present')
|
||||
|
||||
if len(env['payloads']) != 4:
|
||||
print(f'❌ Expected 4 payloads, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
# Expected data
|
||||
expected_data = [
|
||||
('image', image_data, 'image'),
|
||||
('audio', audio_data, 'audio'),
|
||||
('video', video_data, 'video'),
|
||||
('binary', generic_binary, 'binary')
|
||||
]
|
||||
|
||||
for i in range(len(env['payloads'])):
|
||||
payload = env['payloads'][i]
|
||||
expected = expected_data[i]
|
||||
|
||||
if payload[0] != expected[0]:
|
||||
print(f"❌ Payload {i + 1}: Expected dataname '{expected[0]}', got '{payload[0]}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct dataname')
|
||||
|
||||
if payload[2] != expected[2]:
|
||||
print(f"❌ Payload {i + 1}: Expected type '{expected[2]}', got '{payload[2]}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct type')
|
||||
|
||||
# Verify binary data integrity
|
||||
received_data = payload[1]
|
||||
if not isinstance(received_data, (bytes, bytearray)):
|
||||
print(f'❌ Payload {i + 1}: Expected bytes/bytearray, got {type(received_data)}')
|
||||
passed = False
|
||||
elif received_data != expected[1]:
|
||||
print(f'❌ Payload {i + 1}: Data mismatch')
|
||||
print(f' Expected: {expected[1]}')
|
||||
print(f' Got: {received_data}')
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Data correctly deserialized')
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(run_test())
|
||||
@@ -1,183 +0,0 @@
|
||||
"""
|
||||
Python Binary Sender Test
|
||||
Tests the smartsend function with binary/image/audio/video/table payloads
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import base64
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge import smartsend, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_SUBJECT = '/test/binary'
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
async def run_test():
|
||||
print('=== Python Binary Sender Test ===\n')
|
||||
|
||||
correlation_id = 'py-binary-test-' + str(asyncio.get_event_loop().time() * 1000000)
|
||||
print(f'Correlation ID: {correlation_id}')
|
||||
print(f'Subject: {TEST_SUBJECT}')
|
||||
print(f'Broker URL: {TEST_BROKER_URL}\n')
|
||||
|
||||
# Test data - binary data for different types
|
||||
image_data = bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]) # PNG header
|
||||
audio_data = bytes([0x46, 0x4C, 0x41, 0x43, 0x00, 0x00, 0x00, 0x00]) # FLAC header
|
||||
video_data = bytes([0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70]) # MP4 header
|
||||
generic_binary = bytes([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE])
|
||||
|
||||
# Test table data
|
||||
try:
|
||||
import pandas as pd
|
||||
table_data = pd.DataFrame({
|
||||
'id': [1, 2, 3, 4, 5],
|
||||
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
|
||||
'value': [10.5, 20.3, 30.1, 40.9, 50.7]
|
||||
})
|
||||
table_available = True
|
||||
except ImportError:
|
||||
table_available = False
|
||||
table_data = None
|
||||
|
||||
test_data = [
|
||||
('image', image_data, 'image'),
|
||||
('audio', audio_data, 'audio'),
|
||||
('video', video_data, 'video'),
|
||||
('binary', generic_binary, 'binary')
|
||||
]
|
||||
|
||||
if table_available:
|
||||
test_data.append(('table', table_data, 'table'))
|
||||
|
||||
try:
|
||||
# Send the message
|
||||
print('Sending binary payloads...')
|
||||
env, env_json_str = await smartsend(
|
||||
TEST_SUBJECT,
|
||||
test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id=correlation_id,
|
||||
msg_purpose='test',
|
||||
sender_name='py-binary-test',
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
print('\n=== Envelope Created ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Purpose: {env["msg_purpose"]}')
|
||||
print(f'Sender: {env["sender_name"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate envelope structure
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
expected_count = 5 if table_available else 4
|
||||
if len(env['payloads']) != expected_count:
|
||||
print(f'❌ Expected {expected_count} payloads, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
# Test each payload
|
||||
expected_datanames = ['image', 'audio', 'video', 'binary']
|
||||
expected_types = ['image', 'audio', 'video', 'binary']
|
||||
expected_data = [image_data, audio_data, video_data, generic_binary]
|
||||
|
||||
if table_available:
|
||||
expected_datanames.append('table')
|
||||
expected_types.append('table')
|
||||
|
||||
for i in range(len(env['payloads'])):
|
||||
payload = env['payloads'][i]
|
||||
|
||||
if payload['dataname'] != expected_datanames[i]:
|
||||
print(f"❌ Payload {i + 1}: Expected dataname '{expected_datanames[i]}', got '{payload['dataname']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct dataname')
|
||||
|
||||
if payload['payload_type'] != expected_types[i]:
|
||||
print(f"❌ Payload {i + 1}: Expected type '{expected_types[i]}', got '{payload['payload_type']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct type')
|
||||
|
||||
if payload['transport'] != 'direct':
|
||||
print(f"❌ Payload {i + 1}: Expected transport 'direct', got '{payload['transport']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct transport')
|
||||
|
||||
if payload['encoding'] != 'base64':
|
||||
print(f"❌ Payload {i + 1}: Expected encoding 'base64', got '{payload['encoding']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct encoding')
|
||||
|
||||
# Decode and verify the data
|
||||
decoded_data = base64.b64decode(payload['data'])
|
||||
|
||||
if i < len(expected_data):
|
||||
original_data = expected_data[i]
|
||||
if decoded_data != original_data:
|
||||
print(f'❌ Payload {i + 1}: Data integrity mismatch')
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Data integrity verified')
|
||||
else:
|
||||
# Table payload - just verify it's present
|
||||
print(f'✅ Payload {i + 1}: Table data present (size: {payload["size"]} bytes)')
|
||||
|
||||
print(f' Size: {payload["size"]} bytes\n')
|
||||
|
||||
# Test with larger binary data
|
||||
print('=== Large Binary Data Test ===')
|
||||
large_data = bytes([0xFF] * 10000) # 10KB of binary data
|
||||
large_test_data = [
|
||||
('large_binary', large_data, 'binary')
|
||||
]
|
||||
|
||||
large_env, _ = await smartsend(
|
||||
TEST_SUBJECT,
|
||||
large_test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id='large-' + correlation_id,
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
if len(large_env['payloads']) == 1 and large_env['payloads'][0]['size'] == 10000:
|
||||
print('✅ Large binary data handled correctly')
|
||||
else:
|
||||
print('❌ Large binary data handling failed')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(run_test())
|
||||
@@ -1,220 +0,0 @@
|
||||
"""
|
||||
Python Dictionary Receiver Test
|
||||
Tests the smartreceive function with dictionary payloads
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge import smartreceive, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
async def run_test():
|
||||
print('=== Python Dictionary Receiver Test ===\n')
|
||||
|
||||
# Create a mock NATS message with dictionary payloads
|
||||
import base64
|
||||
|
||||
simple_dict = {'key1': 'value1', 'key2': 'value2'}
|
||||
nested_dict = {'outer': {'inner': 'value', 'number': 42}}
|
||||
array_dict = {'items': [1, 2, 3, 'four', 'five']}
|
||||
mixed_dict = {'string': 'text', 'number': 123, 'boolean': True, 'null_val': None}
|
||||
|
||||
test_data = {
|
||||
'correlation_id': 'py-receiver-dict-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'msg_id': 'msg-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'timestamp': asyncio.get_event_loop().time().isoformat(),
|
||||
'send_to': '/test/dictionary',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'py-dict-test',
|
||||
'sender_id': 'sender-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'receiver_name': 'py-receiver',
|
||||
'receiver_id': 'receiver-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': 'payload-1',
|
||||
'dataname': 'simple_dict',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps(simple_dict).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps(simple_dict).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps(simple_dict).encode('utf8'))}
|
||||
},
|
||||
{
|
||||
'id': 'payload-2',
|
||||
'dataname': 'nested_dict',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps(nested_dict).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps(nested_dict).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps(nested_dict).encode('utf8'))}
|
||||
},
|
||||
{
|
||||
'id': 'payload-3',
|
||||
'dataname': 'array_dict',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps(array_dict).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps(array_dict).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps(array_dict).encode('utf8'))}
|
||||
},
|
||||
{
|
||||
'id': 'payload-4',
|
||||
'dataname': 'mixed_dict',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps(mixed_dict).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps(mixed_dict).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps(mixed_dict).encode('utf8'))}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_msg = {
|
||||
'payload': json.dumps(test_data)
|
||||
}
|
||||
|
||||
print('Mock Message Created:')
|
||||
print(f' Correlation ID: {test_data["correlation_id"]}')
|
||||
print(f' Payloads: {len(test_data["payloads"])}')
|
||||
print(f' Payload types: {", ".join(p["payload_type"] for p in test_data["payloads"])}\n')
|
||||
|
||||
try:
|
||||
# Receive and process the message
|
||||
print('Receiving and processing message...')
|
||||
env = await smartreceive(
|
||||
mock_msg,
|
||||
max_retries=3,
|
||||
base_delay=100,
|
||||
max_delay=1000
|
||||
)
|
||||
|
||||
print('\n=== Received Envelope ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate received data
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if not env.get('correlation_id'):
|
||||
print('❌ correlation_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ correlation_id present')
|
||||
|
||||
if len(env['payloads']) != 4:
|
||||
print(f'❌ Expected 4 payloads, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
# Expected data
|
||||
expected_data = [
|
||||
('simple_dict', simple_dict, 'dictionary'),
|
||||
('nested_dict', nested_dict, 'dictionary'),
|
||||
('array_dict', array_dict, 'dictionary'),
|
||||
('mixed_dict', mixed_dict, 'dictionary')
|
||||
]
|
||||
|
||||
for i in range(len(env['payloads'])):
|
||||
payload = env['payloads'][i]
|
||||
expected = expected_data[i]
|
||||
|
||||
if payload[0] != expected[0]:
|
||||
print(f"❌ Payload {i + 1}: Expected dataname '{expected[0]}', got '{payload[0]}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct dataname')
|
||||
|
||||
if payload[2] != expected[2]:
|
||||
print(f"❌ Payload {i + 1}: Expected type '{expected[2]}', got '{payload[2]}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct type')
|
||||
|
||||
data_match = json.dumps(payload[1], sort_keys=True) == json.dumps(expected[1], sort_keys=True)
|
||||
if not data_match:
|
||||
print(f'❌ Payload {i + 1}: Data mismatch')
|
||||
print(f' Expected: {json.dumps(expected[1], sort_keys=True)}')
|
||||
print(f' Got: {json.dumps(payload[1], sort_keys=True)}')
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Data correctly deserialized')
|
||||
|
||||
# Test round-trip with receive
|
||||
print('\n=== Round-trip Test ===')
|
||||
round_trip_data = {
|
||||
'correlation_id': 'roundtrip-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'msg_id': 'msg-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'timestamp': asyncio.get_event_loop().time().isoformat(),
|
||||
'send_to': '/test/dictionary',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'py-test',
|
||||
'sender_id': 'sender-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'receiver_name': 'py-receiver',
|
||||
'receiver_id': 'receiver-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': 'payload-rt',
|
||||
'dataname': 'roundtrip',
|
||||
'payload_type': 'dictionary',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(json.dumps({'test': 'data', 'nested': {'a': 1, 'b': 2}}).encode('utf8')),
|
||||
'data': base64.b64encode(json.dumps({'test': 'data', 'nested': {'a': 1, 'b': 2}}).encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(json.dumps({'test': 'data', 'nested': {'a': 1, 'b': 2}}).encode('utf8'))}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_rt_msg = {'payload': json.dumps(round_trip_data)}
|
||||
rt_env = await smartreceive(mock_rt_msg)
|
||||
|
||||
if rt_env['payloads'][0][0] == 'roundtrip' and rt_env['payloads'][0][2] == 'dictionary':
|
||||
print('✅ Round-trip test successful')
|
||||
else:
|
||||
print('❌ Round-trip test failed')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(run_test())
|
||||
@@ -1,172 +0,0 @@
|
||||
"""
|
||||
Python Dictionary Sender Test
|
||||
Tests the smartsend function with dictionary payloads
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge import smartsend, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_SUBJECT = '/test/dictionary'
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
async def run_test():
|
||||
print('=== Python Dictionary Sender Test ===\n')
|
||||
|
||||
correlation_id = 'py-dict-test-' + str(asyncio.get_event_loop().time() * 1000000)
|
||||
print(f'Correlation ID: {correlation_id}')
|
||||
print(f'Subject: {TEST_SUBJECT}')
|
||||
print(f'Broker URL: {TEST_BROKER_URL}\n')
|
||||
|
||||
# Test data - various dictionary structures
|
||||
test_data = [
|
||||
('simple_dict', {'key1': 'value1', 'key2': 'value2'}, 'dictionary'),
|
||||
('nested_dict', {'outer': {'inner': 'value', 'number': 42}}, 'dictionary'),
|
||||
('array_dict', {'items': [1, 2, 3, 'four', 'five']}, 'dictionary'),
|
||||
('mixed_dict', {'string': 'text', 'number': 123, 'boolean': True, 'null_val': None}, 'dictionary')
|
||||
]
|
||||
|
||||
try:
|
||||
# Send the message
|
||||
print('Sending dictionary payloads...')
|
||||
env, env_json_str = await smartsend(
|
||||
TEST_SUBJECT,
|
||||
test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id=correlation_id,
|
||||
msg_purpose='test',
|
||||
sender_name='py-dict-test',
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
print('\n=== Envelope Created ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Purpose: {env["msg_purpose"]}')
|
||||
print(f'Sender: {env["sender_name"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate envelope structure
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if len(env['payloads']) != 4:
|
||||
print(f'❌ Expected 4 payloads, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
# Test each payload
|
||||
expected_datanames = ['simple_dict', 'nested_dict', 'array_dict', 'mixed_dict']
|
||||
expected_types = ['dictionary', 'dictionary', 'dictionary', 'dictionary']
|
||||
|
||||
for i in range(len(env['payloads'])):
|
||||
payload = env['payloads'][i]
|
||||
|
||||
if payload['dataname'] != expected_datanames[i]:
|
||||
print(f"❌ Payload {i + 1}: Expected dataname '{expected_datanames[i]}', got '{payload['dataname']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct dataname')
|
||||
|
||||
if payload['payload_type'] != expected_types[i]:
|
||||
print(f"❌ Payload {i + 1}: Expected type '{expected_types[i]}', got '{payload['payload_type']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct type')
|
||||
|
||||
if payload['transport'] != 'direct':
|
||||
print(f"❌ Payload {i + 1}: Expected transport 'direct', got '{payload['transport']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct transport')
|
||||
|
||||
if payload['encoding'] != 'base64':
|
||||
print(f"❌ Payload {i + 1}: Expected encoding 'base64', got '{payload['encoding']}'")
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Correct encoding')
|
||||
|
||||
# Decode and verify the data
|
||||
import base64
|
||||
decoded_data = json.loads(base64.b64decode(payload['data']).decode('utf8'))
|
||||
original_data = test_data[i][1]
|
||||
|
||||
# Normalize for comparison (None vs null, True vs true, etc.)
|
||||
if json.dumps(decoded_data, sort_keys=True) != json.dumps(original_data, sort_keys=True):
|
||||
print(f'❌ Payload {i + 1}: Data integrity mismatch')
|
||||
print(f' Expected: {json.dumps(original_data)}')
|
||||
print(f' Got: {json.dumps(decoded_data)}')
|
||||
passed = False
|
||||
else:
|
||||
print(f'✅ Payload {i + 1}: Data integrity verified')
|
||||
|
||||
print(f' Size: {payload["size"]} bytes\n')
|
||||
|
||||
# Test round-trip serialization
|
||||
print('=== Round-trip Serialization Test ===')
|
||||
round_trip_data = [
|
||||
('roundtrip', {'test': 'data', 'numbers': [1, 2, 3], 'nested': {'a': 1, 'b': 2}}, 'dictionary')
|
||||
]
|
||||
|
||||
rt_env, _ = await smartsend(
|
||||
TEST_SUBJECT,
|
||||
round_trip_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id='roundtrip-' + correlation_id,
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
rt_payload = rt_env['payloads'][0]
|
||||
rt_decoded = json.loads(base64.b64decode(rt_payload['data']).decode('utf8'))
|
||||
|
||||
if json.dumps(rt_decoded, sort_keys=True) == json.dumps(round_trip_data[0][1], sort_keys=True):
|
||||
print('✅ Round-trip serialization successful')
|
||||
else:
|
||||
print('❌ Round-trip serialization failed')
|
||||
passed = False
|
||||
|
||||
# Test JSON string output
|
||||
print('\n=== JSON String Output Test ===')
|
||||
try:
|
||||
parsed = json.loads(env_json_str)
|
||||
if parsed['correlation_id'] == env['correlation_id'] and \
|
||||
len(parsed['payloads']) == len(env['payloads']):
|
||||
print('✅ JSON string is valid and matches envelope')
|
||||
else:
|
||||
print('❌ JSON string does not match envelope')
|
||||
passed = False
|
||||
except json.JSONDecodeError as e:
|
||||
print(f'❌ JSON string is invalid: {e}')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(run_test())
|
||||
@@ -1,167 +0,0 @@
|
||||
"""
|
||||
Python Table Sender Test
|
||||
Tests the smartsend function with table (Arrow IPC) payloads
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge import smartsend, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_SUBJECT = '/test/table'
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
async def run_test():
|
||||
print('=== Python Table Sender Test ===\n')
|
||||
|
||||
correlation_id = 'py-table-test-' + str(asyncio.get_event_loop().time() * 1000000)
|
||||
print(f'Correlation ID: {correlation_id}')
|
||||
print(f'Subject: {TEST_SUBJECT}')
|
||||
print(f'Broker URL: {TEST_BROKER_URL}\n')
|
||||
|
||||
# Test data - pandas DataFrame
|
||||
try:
|
||||
import pandas as pd
|
||||
table_data = pd.DataFrame({
|
||||
'id': [1, 2, 3, 4, 5],
|
||||
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
|
||||
'age': [30, 25, 35, 28, 32],
|
||||
'active': [True, False, True, True, False]
|
||||
})
|
||||
table_available = True
|
||||
except ImportError:
|
||||
print('❌ pandas not available - skipping table tests')
|
||||
sys.exit(0)
|
||||
|
||||
test_data = [
|
||||
('users_table', table_data, 'table')
|
||||
]
|
||||
|
||||
try:
|
||||
# Send the message
|
||||
print('Sending table payload...')
|
||||
env, env_json_str = await smartsend(
|
||||
TEST_SUBJECT,
|
||||
test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id=correlation_id,
|
||||
msg_purpose='test',
|
||||
sender_name='py-table-test',
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
print('\n=== Envelope Created ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Purpose: {env["msg_purpose"]}')
|
||||
print(f'Sender: {env["sender_name"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate envelope structure
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if len(env['payloads']) != 1:
|
||||
print(f'❌ Expected 1 payload, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
payload = env['payloads'][0]
|
||||
if payload['dataname'] != 'users_table':
|
||||
print(f"❌ Expected dataname 'users_table', got '{payload['dataname']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct dataname')
|
||||
|
||||
if payload['payload_type'] != 'table':
|
||||
print(f"❌ Expected payload_type 'table', got '{payload['payload_type']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct payload_type')
|
||||
|
||||
if payload['transport'] != 'direct':
|
||||
print(f"❌ Expected transport 'direct', got '{payload['transport']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct transport')
|
||||
|
||||
if payload['encoding'] != 'base64':
|
||||
print(f"❌ Expected encoding 'base64', got '{payload['encoding']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct encoding')
|
||||
|
||||
print(f'\nPayload size: {payload["size"]} bytes')
|
||||
|
||||
# Test with larger table
|
||||
print('\n=== Larger Table Test ===')
|
||||
large_table_data = pd.DataFrame({
|
||||
'id': range(100),
|
||||
'name': [f'User{i}' for i in range(100)],
|
||||
'age': [20 + (i % 50) for i in range(100)],
|
||||
'active': [i % 2 == 0 for i in range(100)]
|
||||
})
|
||||
|
||||
large_test_data = [
|
||||
('large_table', large_table_data, 'table')
|
||||
]
|
||||
|
||||
large_env, _ = await smartsend(
|
||||
TEST_SUBJECT,
|
||||
large_test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id='large-' + correlation_id,
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
if len(large_env['payloads']) == 1:
|
||||
print('✅ Large table handled correctly')
|
||||
print(f' Size: {large_env["payloads"][0]["size"]} bytes')
|
||||
else:
|
||||
print('❌ Large table handling failed')
|
||||
passed = False
|
||||
|
||||
# Test JSON string output
|
||||
print('\n=== JSON String Output Test ===')
|
||||
import json
|
||||
try:
|
||||
parsed = json.loads(env_json_str)
|
||||
if parsed['correlation_id'] == env['correlation_id'] and \
|
||||
len(parsed['payloads']) == len(env['payloads']):
|
||||
print('✅ JSON string is valid and matches envelope')
|
||||
else:
|
||||
print('❌ JSON string does not match envelope')
|
||||
passed = False
|
||||
except json.JSONDecodeError as e:
|
||||
print(f'❌ JSON string is invalid: {e}')
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(run_test())
|
||||
@@ -1,205 +0,0 @@
|
||||
"""
|
||||
Python Text Receiver Test
|
||||
Tests the smartreceive function with text payloads
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge import smartreceive, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
async def run_test():
|
||||
print('=== Python Text Receiver Test ===\n')
|
||||
|
||||
# Create a mock NATS message with text payload
|
||||
test_text = 'Hello, NATSBridge! This is a test message.'
|
||||
import base64
|
||||
|
||||
test_data = {
|
||||
'correlation_id': 'py-receiver-test-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'msg_id': 'msg-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'timestamp': asyncio.get_event_loop().time().isoformat(),
|
||||
'send_to': '/test/text',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'py-text-test',
|
||||
'sender_id': 'sender-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'receiver_name': 'py-receiver',
|
||||
'receiver_id': 'receiver-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': 'payload-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'dataname': 'message',
|
||||
'payload_type': 'text',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': len(test_text.encode('utf8')),
|
||||
'data': base64.b64encode(test_text.encode('utf8')).decode('ascii'),
|
||||
'metadata': {'payload_bytes': len(test_text.encode('utf8'))}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_msg = {
|
||||
'payload': json.dumps(test_data)
|
||||
}
|
||||
|
||||
print('Mock Message Created:')
|
||||
print(f' Correlation ID: {test_data["correlation_id"]}')
|
||||
print(f' Payloads: {len(test_data["payloads"])}')
|
||||
print(f' Payload dataname: {test_data["payloads"][0]["dataname"]}')
|
||||
print(f' Payload type: {test_data["payloads"][0]["payload_type"]}')
|
||||
print(f' Transport: {test_data["payloads"][0]["transport"]}\n')
|
||||
|
||||
try:
|
||||
# Receive and process the message
|
||||
print('Receiving and processing message...')
|
||||
env = await smartreceive(
|
||||
mock_msg,
|
||||
max_retries=3,
|
||||
base_delay=100,
|
||||
max_delay=1000
|
||||
)
|
||||
|
||||
print('\n=== Received Envelope ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate received data
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if not env.get('correlation_id'):
|
||||
print('❌ correlation_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ correlation_id present')
|
||||
|
||||
if len(env['payloads']) != 1:
|
||||
print(f'❌ Expected 1 payload, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
payload = env['payloads'][0]
|
||||
if payload[0] != 'message':
|
||||
print(f"❌ Expected dataname 'message', got '{payload[0]}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct dataname')
|
||||
|
||||
if payload[2] != 'text':
|
||||
print(f"❌ Expected type 'text', got '{payload[2]}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct type')
|
||||
|
||||
if payload[1] != test_text:
|
||||
print('❌ Data mismatch')
|
||||
print(f' Expected: {test_text}')
|
||||
print(f' Got: {payload[1]}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Data correctly deserialized')
|
||||
|
||||
# Test with multiple text payloads
|
||||
print('\n=== Multiple Text Payloads Test ===')
|
||||
multi_test_data = {
|
||||
'correlation_id': 'multi-receiver-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'msg_id': 'msg-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'timestamp': asyncio.get_event_loop().time().isoformat(),
|
||||
'send_to': '/test/text',
|
||||
'msg_purpose': 'test',
|
||||
'sender_name': 'py-text-test',
|
||||
'sender_id': 'sender-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'receiver_name': 'py-receiver',
|
||||
'receiver_id': 'receiver-' + str(asyncio.get_event_loop().time() * 1000000),
|
||||
'reply_to': '',
|
||||
'reply_to_msg_id': '',
|
||||
'broker_url': TEST_BROKER_URL,
|
||||
'metadata': {},
|
||||
'payloads': [
|
||||
{
|
||||
'id': 'payload-1',
|
||||
'dataname': 'msg1',
|
||||
'payload_type': 'text',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': 16,
|
||||
'data': base64.b64encode(b'First message').decode('ascii'),
|
||||
'metadata': {'payload_bytes': 16}
|
||||
},
|
||||
{
|
||||
'id': 'payload-2',
|
||||
'dataname': 'msg2',
|
||||
'payload_type': 'text',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': 16,
|
||||
'data': base64.b64encode(b'Second message').decode('ascii'),
|
||||
'metadata': {'payload_bytes': 16}
|
||||
},
|
||||
{
|
||||
'id': 'payload-3',
|
||||
'dataname': 'msg3',
|
||||
'payload_type': 'text',
|
||||
'transport': 'direct',
|
||||
'encoding': 'base64',
|
||||
'size': 16,
|
||||
'data': base64.b64encode(b'Third message').decode('ascii'),
|
||||
'metadata': {'payload_bytes': 16}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mock_multi_msg = {'payload': json.dumps(multi_test_data)}
|
||||
multi_env = await smartreceive(mock_multi_msg)
|
||||
|
||||
if len(multi_env['payloads']) == 3:
|
||||
print('✅ Multiple payloads handled correctly')
|
||||
|
||||
# Verify each payload
|
||||
expected_messages = ['First message', 'Second message', 'Third message']
|
||||
for i in range(3):
|
||||
if multi_env['payloads'][i][1] == expected_messages[i]:
|
||||
print(f'✅ Payload {i + 1} correctly deserialized')
|
||||
else:
|
||||
print(f'❌ Payload {i + 1} mismatch')
|
||||
passed = False
|
||||
else:
|
||||
print(f"❌ Expected 3 payloads, got {len(multi_env['payloads'])}")
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(run_test())
|
||||
@@ -1,164 +0,0 @@
|
||||
"""
|
||||
Python Text Sender Test
|
||||
Tests the smartsend function with text payloads
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from natsbridge import smartsend, DEFAULT_BROKER_URL, DEFAULT_FILESERVER_URL
|
||||
|
||||
TEST_SUBJECT = '/test/text'
|
||||
TEST_BROKER_URL = os.environ.get('NATS_URL', 'nats://localhost:4222')
|
||||
TEST_FILESERVER_URL = os.environ.get('FILESERVER_URL', 'http://localhost:8080')
|
||||
|
||||
|
||||
async def run_test():
|
||||
print('=== Python Text Sender Test ===\n')
|
||||
|
||||
correlation_id = 'py-text-test-' + str(asyncio.get_event_loop().time() * 1000000)
|
||||
print(f'Correlation ID: {correlation_id}')
|
||||
print(f'Subject: {TEST_SUBJECT}')
|
||||
print(f'Broker URL: {TEST_BROKER_URL}\n')
|
||||
|
||||
# Test data
|
||||
text_data = 'Hello, NATSBridge! This is a test message.'
|
||||
test_data = [
|
||||
('message', text_data, 'text')
|
||||
]
|
||||
|
||||
try:
|
||||
# Send the message
|
||||
print('Sending text payload...')
|
||||
env, env_json_str = await smartsend(
|
||||
TEST_SUBJECT,
|
||||
test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id=correlation_id,
|
||||
msg_purpose='test',
|
||||
sender_name='py-text-test',
|
||||
is_publish=False # Don't actually publish for this test
|
||||
)
|
||||
|
||||
print('\n=== Envelope Created ===')
|
||||
print(f'Correlation ID: {env["correlation_id"]}')
|
||||
print(f'Message ID: {env["msg_id"]}')
|
||||
print(f'Timestamp: {env["timestamp"]}')
|
||||
print(f'Subject: {env["send_to"]}')
|
||||
print(f'Purpose: {env["msg_purpose"]}')
|
||||
print(f'Sender: {env["sender_name"]}')
|
||||
print(f'Payloads: {len(env["payloads"])}\n')
|
||||
|
||||
# Validate envelope structure
|
||||
print('=== Validation ===')
|
||||
passed = True
|
||||
|
||||
if not env.get('correlation_id'):
|
||||
print('❌ correlation_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ correlation_id present')
|
||||
|
||||
if not env.get('msg_id'):
|
||||
print('❌ msg_id is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ msg_id present')
|
||||
|
||||
if not env.get('timestamp'):
|
||||
print('❌ timestamp is missing')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ timestamp present')
|
||||
|
||||
if len(env['payloads']) != 1:
|
||||
print(f'❌ Expected 1 payload, got {len(env["payloads"])}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct number of payloads')
|
||||
|
||||
payload = env['payloads'][0]
|
||||
if payload['dataname'] != 'message':
|
||||
print(f"❌ Expected dataname 'message', got '{payload['dataname']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct dataname')
|
||||
|
||||
if payload['payload_type'] != 'text':
|
||||
print(f"❌ Expected payload_type 'text', got '{payload['payload_type']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct payload_type')
|
||||
|
||||
if payload['transport'] != 'direct':
|
||||
print(f"❌ Expected transport 'direct', got '{payload['transport']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct transport')
|
||||
|
||||
if payload['encoding'] != 'base64':
|
||||
print(f"❌ Expected encoding 'base64', got '{payload['encoding']}'")
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Correct encoding')
|
||||
|
||||
# Decode and verify the data
|
||||
import base64
|
||||
decoded_data = base64.b64decode(payload['data']).decode('utf8')
|
||||
if decoded_data != text_data:
|
||||
print('❌ Decoded data mismatch')
|
||||
print(f' Expected: {text_data}')
|
||||
print(f' Got: {decoded_data}')
|
||||
passed = False
|
||||
else:
|
||||
print('✅ Data integrity verified')
|
||||
|
||||
print(f"\nPayload size: {payload['size']} bytes")
|
||||
print(f'Base64 data length: {len(payload["data"])} chars')
|
||||
|
||||
# Test with multiple text payloads
|
||||
print('\n=== Multiple Text Payloads Test ===')
|
||||
multi_test_data = [
|
||||
('msg1', 'First message', 'text'),
|
||||
('msg2', 'Second message', 'text'),
|
||||
('msg3', 'Third message', 'text')
|
||||
]
|
||||
|
||||
multi_env, _ = await smartsend(
|
||||
TEST_SUBJECT,
|
||||
multi_test_data,
|
||||
broker_url=TEST_BROKER_URL,
|
||||
fileserver_url=TEST_FILESERVER_URL,
|
||||
correlation_id='multi-test-' + correlation_id,
|
||||
is_publish=False
|
||||
)
|
||||
|
||||
if len(multi_env['payloads']) == 3:
|
||||
print('✅ Multiple payloads handled correctly')
|
||||
else:
|
||||
print(f"❌ Expected 3 payloads, got {len(multi_env['payloads'])}")
|
||||
passed = False
|
||||
|
||||
# Final result
|
||||
print('\n=== Test Result ===')
|
||||
if passed:
|
||||
print('✅ ALL TESTS PASSED')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('❌ SOME TESTS FAILED')
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Test failed with error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(run_test())
|
||||
Reference in New Issue
Block a user