node-red-contrib-aedes 0.15.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/nodejs.yml +1 -1
- package/CHANGELOG.md +14 -0
- package/README.md +11 -3
- package/aedes.html +44 -19
- package/aedes.js +412 -210
- package/locales/de/aedes.html +110 -0
- package/locales/de/aedes.json +54 -0
- package/locales/en-US/aedes.html +103 -12
- package/locales/en-US/aedes.json +15 -2
- package/package.json +6 -4
- package/test/aedes_last_will_spec.js +25 -48
- package/test/aedes_persist_spec.js +777 -0
- package/test/aedes_qos_spec.js +76 -77
- package/test/aedes_retain_spec.js +62 -189
- package/test/aedes_spec.js +257 -67
- package/test/aedes_ws_spec.js +107 -38
- package/test/test-utils.js +17 -0
- package/docs/DEV-SETUP.md +0 -86
- package/docs/MIGRATION-PLAN-0.51-TO-1.0.md +0 -349
- package/docs/MIGRATION-PLAN-NODE-RED-4.md +0 -107
package/test/aedes_spec.js
CHANGED
|
@@ -4,6 +4,8 @@ const helper = require('node-red-node-test-helper');
|
|
|
4
4
|
const aedesNode = require('../aedes.js');
|
|
5
5
|
const mqttNode = require('../node_modules/node-red/node_modules/@node-red/nodes/core/network/10-mqtt.js');
|
|
6
6
|
const mqtt = require('mqtt');
|
|
7
|
+
const should = require('should');
|
|
8
|
+
const { logError } = require('./test-utils');
|
|
7
9
|
|
|
8
10
|
const credentialsOK = { n1: { username: 'test', password: 'test' }, b1: { user: 'test', password: 'test' } };
|
|
9
11
|
const credentialsMissing = { n1: { username: 'test', password: 'test' }, b1: { user: 'test' } };
|
|
@@ -68,10 +70,13 @@ describe('Aedes Broker TCP tests', function () {
|
|
|
68
70
|
}
|
|
69
71
|
],
|
|
70
72
|
function () {
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
const n1 = helper.getNode('n1');
|
|
74
|
+
n1._initPromise.then(function () {
|
|
75
|
+
const n2 = helper.getNode('n2');
|
|
76
|
+
n2.on('input', function (msg) {
|
|
77
|
+
msg.should.have.property('topic', 'clientReady');
|
|
78
|
+
done();
|
|
79
|
+
});
|
|
75
80
|
});
|
|
76
81
|
});
|
|
77
82
|
});
|
|
@@ -108,10 +113,13 @@ describe('Aedes Broker TCP tests', function () {
|
|
|
108
113
|
|
|
109
114
|
helper.load([aedesNode, mqttNode], flow, credentialsMissing,
|
|
110
115
|
function () {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
const n1 = helper.getNode('n1');
|
|
117
|
+
n1._initPromise.then(function () {
|
|
118
|
+
const n2 = helper.getNode('n2');
|
|
119
|
+
n2.on('input', function (msg) {
|
|
120
|
+
msg.should.have.property('topic', 'clientError');
|
|
121
|
+
done();
|
|
122
|
+
});
|
|
115
123
|
});
|
|
116
124
|
});
|
|
117
125
|
});
|
|
@@ -148,10 +156,13 @@ describe('Aedes Broker TCP tests', function () {
|
|
|
148
156
|
|
|
149
157
|
helper.load([aedesNode, mqttNode], flow, credentialsOK,
|
|
150
158
|
function () {
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
159
|
+
const n1 = helper.getNode('n1');
|
|
160
|
+
n1._initPromise.then(function () {
|
|
161
|
+
const n2 = helper.getNode('n2');
|
|
162
|
+
n2.on('input', function (msg) {
|
|
163
|
+
msg.should.have.property('topic', 'clientReady');
|
|
164
|
+
done();
|
|
165
|
+
});
|
|
155
166
|
});
|
|
156
167
|
});
|
|
157
168
|
});
|
|
@@ -198,17 +209,20 @@ describe('Aedes Broker TCP tests', function () {
|
|
|
198
209
|
}
|
|
199
210
|
],
|
|
200
211
|
function () {
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
+
const n1 = helper.getNode('n1');
|
|
213
|
+
n1._initPromise.then(function () {
|
|
214
|
+
const n2 = helper.getNode('n2');
|
|
215
|
+
const n3 = helper.getNode('n3');
|
|
216
|
+
const n5 = helper.getNode('n5');
|
|
217
|
+
n2.on('input', function (msg) {
|
|
218
|
+
if (msg.topic === 'subscribe') {
|
|
219
|
+
n3.receive({ payload: 'test' });
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
n5.on('input', function (msg) {
|
|
223
|
+
msg.should.have.property('topic', 'test1883');
|
|
224
|
+
done();
|
|
225
|
+
});
|
|
212
226
|
});
|
|
213
227
|
});
|
|
214
228
|
});
|
|
@@ -267,22 +281,26 @@ describe('Aedes Broker TCP tests', function () {
|
|
|
267
281
|
}
|
|
268
282
|
],
|
|
269
283
|
function () {
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
284
|
+
const n1 = helper.getNode('n1');
|
|
285
|
+
const n11 = helper.getNode('n11');
|
|
286
|
+
Promise.all([n1._initPromise, n11._initPromise]).then(function () {
|
|
287
|
+
let i = 0;
|
|
288
|
+
const n2 = helper.getNode('n2');
|
|
289
|
+
n2.on('input', function (msg) {
|
|
290
|
+
msg.should.have.property('topic', 'clientReady');
|
|
291
|
+
i++;
|
|
292
|
+
if (i === 2) {
|
|
293
|
+
done();
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
const n12 = helper.getNode('n12');
|
|
297
|
+
n12.on('input', function (msg) {
|
|
298
|
+
msg.should.have.property('topic', 'clientReady');
|
|
299
|
+
i++;
|
|
300
|
+
if (i === 2) {
|
|
301
|
+
done();
|
|
302
|
+
}
|
|
303
|
+
});
|
|
286
304
|
});
|
|
287
305
|
});
|
|
288
306
|
});
|
|
@@ -334,18 +352,19 @@ describe('Aedes Broker TCP tests', function () {
|
|
|
334
352
|
type: 'helper'
|
|
335
353
|
}];
|
|
336
354
|
helper.load(aedesNode, flow, function () {
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
355
|
+
const n1 = helper.getNode('n1');
|
|
356
|
+
n1._initPromise.then(function () {
|
|
357
|
+
const client = mqtt.connect('mqtt://localhost:1883', { clientId: 'client', resubscribe: false, reconnectPeriod: -1 });
|
|
358
|
+
client.on('error', logError);
|
|
359
|
+
client.on('connect', function () {
|
|
360
|
+
// console.log('External client connected');
|
|
361
|
+
});
|
|
362
|
+
const n2 = helper.getNode('n2');
|
|
363
|
+
n2.on('input', function (msg) {
|
|
364
|
+
msg.should.have.property('topic', 'clientReady');
|
|
365
|
+
client.end(function () {
|
|
366
|
+
done();
|
|
367
|
+
});
|
|
349
368
|
});
|
|
350
369
|
});
|
|
351
370
|
});
|
|
@@ -387,27 +406,198 @@ describe('Aedes Broker TCP tests', function () {
|
|
|
387
406
|
}
|
|
388
407
|
];
|
|
389
408
|
helper.load([aedesNode, mqttNode], flow, function () {
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
409
|
+
const n1 = helper.getNode('n1');
|
|
410
|
+
n1._initPromise.then(function () {
|
|
411
|
+
const client = mqtt.connect('mqtt://localhost:1883', { clientId: 'client', resubscribe: false, reconnectPeriod: -1 });
|
|
412
|
+
client.on('error', logError);
|
|
413
|
+
client.on('connect', function () {
|
|
414
|
+
// console.log('External client connected');
|
|
415
|
+
});
|
|
416
|
+
const n2 = helper.getNode('n2');
|
|
417
|
+
const n5 = helper.getNode('n5');
|
|
418
|
+
n2.on('input', function (msg) {
|
|
419
|
+
if (msg.topic === 'subscribe') {
|
|
420
|
+
client.publish('test1883', 'test');
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
n5.on('input', function (msg) {
|
|
424
|
+
// console.log(msg);
|
|
425
|
+
msg.should.have.property('topic', 'test1883');
|
|
426
|
+
client.end(function () {
|
|
427
|
+
done();
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it('should handle initialization failure gracefully', function (done) {
|
|
435
|
+
this.timeout(10000);
|
|
436
|
+
const net = require('net');
|
|
437
|
+
// Occupy port 1887 to force an EADDRINUSE
|
|
438
|
+
const blocker = net.createServer();
|
|
439
|
+
blocker.listen(1887, function () {
|
|
440
|
+
const flow = [{
|
|
441
|
+
id: 'n1',
|
|
442
|
+
type: 'aedes broker',
|
|
443
|
+
mqtt_port: '1887',
|
|
444
|
+
name: 'Aedes 1887',
|
|
445
|
+
wires: [[], []]
|
|
446
|
+
}];
|
|
447
|
+
helper.load(aedesNode, flow, function () {
|
|
448
|
+
const n1 = helper.getNode('n1');
|
|
449
|
+
n1._initPromise.then(function () {
|
|
450
|
+
// Init succeeded but server.listen should have fired an error
|
|
451
|
+
blocker.close(function () {
|
|
452
|
+
done();
|
|
453
|
+
});
|
|
454
|
+
}).catch(function () {
|
|
455
|
+
// Expected to fail
|
|
456
|
+
blocker.close(function () {
|
|
457
|
+
done();
|
|
458
|
+
});
|
|
459
|
+
});
|
|
393
460
|
});
|
|
394
|
-
|
|
395
|
-
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('should emit clientDisconnect when a client disconnects', function (done) {
|
|
465
|
+
this.timeout(10000);
|
|
466
|
+
const flow = [
|
|
467
|
+
{
|
|
468
|
+
id: 'n1',
|
|
469
|
+
type: 'aedes broker',
|
|
470
|
+
mqtt_port: '1883',
|
|
471
|
+
name: 'Aedes 1883',
|
|
472
|
+
wires: [['n2'], []]
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
id: 'n2',
|
|
476
|
+
type: 'helper'
|
|
477
|
+
}
|
|
478
|
+
];
|
|
479
|
+
helper.load(aedesNode, flow, function () {
|
|
480
|
+
const n1 = helper.getNode('n1');
|
|
481
|
+
n1._initPromise.then(function () {
|
|
482
|
+
const client = mqtt.connect('mqtt://localhost:1883', {
|
|
483
|
+
clientId: 'client-disconnect-test',
|
|
484
|
+
resubscribe: false,
|
|
485
|
+
reconnectPeriod: -1
|
|
486
|
+
});
|
|
487
|
+
const n2 = helper.getNode('n2');
|
|
488
|
+
n2.on('input', function (msg) {
|
|
489
|
+
if (msg.topic === 'clientReady') {
|
|
490
|
+
client.end();
|
|
491
|
+
} else if (msg.topic === 'clientDisconnect') {
|
|
492
|
+
should(msg.payload.client.id).equal('client-disconnect-test');
|
|
493
|
+
done();
|
|
494
|
+
}
|
|
495
|
+
});
|
|
396
496
|
});
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it('should emit keepaliveTimeout when a client stops responding', function (done) {
|
|
501
|
+
this.timeout(10000);
|
|
502
|
+
const flow = [
|
|
503
|
+
{
|
|
504
|
+
id: 'n1',
|
|
505
|
+
type: 'aedes broker',
|
|
506
|
+
mqtt_port: '1883',
|
|
507
|
+
name: 'Aedes 1883',
|
|
508
|
+
wires: [['n2'], []]
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
id: 'n2',
|
|
512
|
+
type: 'helper'
|
|
513
|
+
}
|
|
514
|
+
];
|
|
515
|
+
helper.load(aedesNode, flow, function () {
|
|
516
|
+
const n1 = helper.getNode('n1');
|
|
517
|
+
n1._initPromise.then(function () {
|
|
518
|
+
const net = require('net');
|
|
519
|
+
const socket = net.createConnection({ port: 1883 }, function () {
|
|
520
|
+
// Send a minimal MQTT CONNECT packet with keepalive=1 second
|
|
521
|
+
const connectPacket = Buffer.from([
|
|
522
|
+
0x10, // CONNECT packet type
|
|
523
|
+
0x11, // Remaining length: 17
|
|
524
|
+
0x00, 0x04, // Protocol name length
|
|
525
|
+
0x4D, 0x51, 0x54, 0x54, // "MQTT"
|
|
526
|
+
0x04, // Protocol level 4 (MQTT 3.1.1)
|
|
527
|
+
0x02, // Connect flags (clean session)
|
|
528
|
+
0x00, 0x01, // Keep alive: 1 second
|
|
529
|
+
0x00, 0x05, // Client ID length: 5
|
|
530
|
+
0x6B, 0x61, 0x74, 0x65, 0x73 // "kates"
|
|
531
|
+
]);
|
|
532
|
+
socket.write(connectPacket);
|
|
533
|
+
// Do not send any more data — keepalive will expire
|
|
534
|
+
});
|
|
535
|
+
const n2 = helper.getNode('n2');
|
|
536
|
+
n2.on('input', function (msg) {
|
|
537
|
+
if (msg.topic === 'keepaliveTimeout') {
|
|
538
|
+
should(msg.payload.client.id).equal('kates');
|
|
539
|
+
socket.destroy();
|
|
540
|
+
done();
|
|
541
|
+
}
|
|
542
|
+
});
|
|
403
543
|
});
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
it('should emit published messages on the 2nd output', function (done) {
|
|
548
|
+
this.timeout(10000);
|
|
549
|
+
const flow = [
|
|
550
|
+
{
|
|
551
|
+
id: 'n1',
|
|
552
|
+
type: 'aedes broker',
|
|
553
|
+
mqtt_port: '1883',
|
|
554
|
+
name: 'Aedes 1883',
|
|
555
|
+
wires: [[], ['n2']]
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
id: 'n2',
|
|
559
|
+
type: 'helper'
|
|
560
|
+
}
|
|
561
|
+
];
|
|
562
|
+
helper.load(aedesNode, flow, function () {
|
|
563
|
+
const n1 = helper.getNode('n1');
|
|
564
|
+
n1._initPromise.then(function () {
|
|
565
|
+
const client = mqtt.connect('mqtt://localhost:1883', {
|
|
566
|
+
clientId: 'publish-test',
|
|
567
|
+
resubscribe: false,
|
|
568
|
+
reconnectPeriod: -1
|
|
569
|
+
});
|
|
570
|
+
client.on('connect', function () {
|
|
571
|
+
client.publish('testTopic', 'testPayload');
|
|
572
|
+
});
|
|
573
|
+
const n2 = helper.getNode('n2');
|
|
574
|
+
n2.on('input', function (msg) {
|
|
575
|
+
if (msg.payload.packet && msg.payload.packet.topic === 'testTopic') {
|
|
576
|
+
should(msg.topic).equal('publish');
|
|
577
|
+
should(msg.payload.packet.payload.toString()).equal('testPayload');
|
|
578
|
+
client.end(function () {
|
|
579
|
+
done();
|
|
580
|
+
});
|
|
581
|
+
}
|
|
409
582
|
});
|
|
410
583
|
});
|
|
411
584
|
});
|
|
412
585
|
});
|
|
586
|
+
|
|
587
|
+
it('should handle close during initialization', function (done) {
|
|
588
|
+
this.timeout(10000);
|
|
589
|
+
const flow = [{
|
|
590
|
+
id: 'n1',
|
|
591
|
+
type: 'aedes broker',
|
|
592
|
+
mqtt_port: '1888',
|
|
593
|
+
name: 'Aedes 1888',
|
|
594
|
+
wires: [[], []]
|
|
595
|
+
}];
|
|
596
|
+
helper.load(aedesNode, flow, function () {
|
|
597
|
+
// Immediately unload before init completes
|
|
598
|
+
helper.unload().then(function () {
|
|
599
|
+
done();
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
});
|
|
413
603
|
});
|
package/test/aedes_ws_spec.js
CHANGED
|
@@ -4,6 +4,7 @@ const helper = require('node-red-node-test-helper');
|
|
|
4
4
|
const aedesNode = require('../aedes.js');
|
|
5
5
|
const mqttNode = require('../node_modules/node-red/node_modules/@node-red/nodes/core/network/10-mqtt.js');
|
|
6
6
|
const mqtt = require('mqtt');
|
|
7
|
+
const { logError } = require('./test-utils');
|
|
7
8
|
|
|
8
9
|
helper.init(require.resolve('node-red'));
|
|
9
10
|
|
|
@@ -17,6 +18,43 @@ describe('Aedes Broker Websocket tests', function () {
|
|
|
17
18
|
});
|
|
18
19
|
});
|
|
19
20
|
|
|
21
|
+
it('should connect an external ws mqtt client', function (done) {
|
|
22
|
+
this.timeout(10000);
|
|
23
|
+
const flow = [
|
|
24
|
+
{
|
|
25
|
+
id: 'n1',
|
|
26
|
+
type: 'aedes broker',
|
|
27
|
+
mqtt_port: '1883',
|
|
28
|
+
mqtt_ws_port: '8080',
|
|
29
|
+
name: 'Aedes 1883',
|
|
30
|
+
wires: [['n2'], []]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'n2',
|
|
34
|
+
type: 'helper'
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
helper.load(aedesNode, flow, function () {
|
|
38
|
+
const n1 = helper.getNode('n1');
|
|
39
|
+
n1._initPromise.then(function () {
|
|
40
|
+
const client = mqtt.connect('ws://localhost:8080', {
|
|
41
|
+
clientId: 'ws-client',
|
|
42
|
+
resubscribe: false,
|
|
43
|
+
reconnectPeriod: -1
|
|
44
|
+
});
|
|
45
|
+
client.on('error', logError);
|
|
46
|
+
const n2 = helper.getNode('n2');
|
|
47
|
+
n2.on('input', function (msg) {
|
|
48
|
+
if (msg.topic === 'clientReady') {
|
|
49
|
+
client.end(function () {
|
|
50
|
+
done();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
20
58
|
it('should not throw an exception with 2 servers on the same ws port', function (done) {
|
|
21
59
|
this.timeout(10000); // have to wait for the inject with delay of two seconds
|
|
22
60
|
|
|
@@ -50,6 +88,35 @@ describe('Aedes Broker Websocket tests', function () {
|
|
|
50
88
|
});
|
|
51
89
|
});
|
|
52
90
|
|
|
91
|
+
it('should set error status when ws port is already in use', function (done) {
|
|
92
|
+
this.timeout(10000);
|
|
93
|
+
const net = require('net');
|
|
94
|
+
const blocker = net.createServer();
|
|
95
|
+
blocker.listen(8081, function () {
|
|
96
|
+
const flow = [{
|
|
97
|
+
id: 'n1',
|
|
98
|
+
type: 'aedes broker',
|
|
99
|
+
mqtt_port: '1883',
|
|
100
|
+
mqtt_ws_port: '8081',
|
|
101
|
+
name: 'Aedes WS Error',
|
|
102
|
+
wires: [[], []]
|
|
103
|
+
}];
|
|
104
|
+
helper.load(aedesNode, flow, function () {
|
|
105
|
+
const n1 = helper.getNode('n1');
|
|
106
|
+
n1.on('call:status', function (call) {
|
|
107
|
+
if (call.args[0].fill === 'red') {
|
|
108
|
+
call.args[0].should.have.property('fill', 'red');
|
|
109
|
+
call.args[0].should.have.property('shape', 'ring');
|
|
110
|
+
call.args[0].should.have.property('text', 'aedes-mqtt-broker.status.error');
|
|
111
|
+
blocker.close(function () {
|
|
112
|
+
done();
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
53
120
|
it('a subscriber should receive a message from an external ws publisher', function (done) {
|
|
54
121
|
this.timeout(10000); // have to wait for the inject with delay of 10 seconds
|
|
55
122
|
const flow = [
|
|
@@ -87,25 +154,26 @@ describe('Aedes Broker Websocket tests', function () {
|
|
|
87
154
|
}
|
|
88
155
|
];
|
|
89
156
|
helper.load([aedesNode, mqttNode], flow, function () {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
157
|
+
const n1 = helper.getNode('n1');
|
|
158
|
+
n1._initPromise.then(function () {
|
|
159
|
+
const client = mqtt.connect('ws://localhost:8080', { clientId: 'client', resubscribe: false, reconnectPeriod: -1 });
|
|
160
|
+
client.on('error', logError);
|
|
161
|
+
client.on('connect', function () {
|
|
162
|
+
// console.log('External client connected');
|
|
163
|
+
});
|
|
164
|
+
const n2 = helper.getNode('n2');
|
|
165
|
+
const n5 = helper.getNode('n5');
|
|
166
|
+
n2.on('input', function (msg) {
|
|
167
|
+
if (msg.topic === 'subscribe') {
|
|
168
|
+
client.publish('test1883', 'test');
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
n5.on('input', function (msg) {
|
|
172
|
+
// console.log(msg);
|
|
173
|
+
msg.should.have.property('topic', 'test1883');
|
|
174
|
+
client.end(function () {
|
|
175
|
+
done();
|
|
176
|
+
});
|
|
109
177
|
});
|
|
110
178
|
});
|
|
111
179
|
});
|
|
@@ -150,25 +218,26 @@ describe('Aedes Broker Websocket tests', function () {
|
|
|
150
218
|
];
|
|
151
219
|
|
|
152
220
|
helper.load([aedesNode, mqttNode], flow, function () {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
221
|
+
const n1 = helper.getNode('n1');
|
|
222
|
+
n1._initPromise.then(function () {
|
|
223
|
+
const client = mqtt.connect(helper.url().replace(/http/, 'ws') + '/mqtt', { clientId: 'client', resubscribe: false, reconnectPeriod: -1 });
|
|
224
|
+
client.on('error', logError);
|
|
225
|
+
client.on('connect', function () {
|
|
226
|
+
// console.log('External client connected');
|
|
227
|
+
});
|
|
228
|
+
const n2 = helper.getNode('n2');
|
|
229
|
+
const n5 = helper.getNode('n5');
|
|
230
|
+
n2.on('input', function (msg) {
|
|
231
|
+
if (msg.topic === 'subscribe') {
|
|
232
|
+
client.publish('test1883', 'test');
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
n5.on('input', function (msg) {
|
|
236
|
+
// console.log(msg);
|
|
237
|
+
msg.should.have.property('topic', 'test1883');
|
|
238
|
+
client.end(function () {
|
|
239
|
+
done();
|
|
240
|
+
});
|
|
172
241
|
});
|
|
173
242
|
});
|
|
174
243
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Logs detailed error information including AggregateError support.
|
|
5
|
+
* Useful for debugging Node-RED and MQTT client errors in tests.
|
|
6
|
+
*/
|
|
7
|
+
function logError (err) {
|
|
8
|
+
if (err instanceof AggregateError) {
|
|
9
|
+
console.error('AggregateError:', err.message);
|
|
10
|
+
console.error('Name:', err.name);
|
|
11
|
+
console.error('Errors:', err.errors);
|
|
12
|
+
} else {
|
|
13
|
+
console.error('Error:', err.message || err.toString());
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = { logError };
|
package/docs/DEV-SETUP.md
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# Developer Setup Note
|
|
2
|
-
|
|
3
|
-
After every `npm install` or `npm update`, re-link Node-RED:
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
sudo npm link node-red
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
`npm install` resets the `node_modules` directory and removes the symlink created by `npm link`. Without re-linking, the test helper cannot find Node-RED and tests will fail.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Backporting a fix to a legacy branch
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
# 1. Stash any WIP on current branch
|
|
17
|
-
git stash push -m "WIP before backport"
|
|
18
|
-
|
|
19
|
-
# 2. Switch to the legacy branch
|
|
20
|
-
git checkout v0.15.x # or: git checkout v11
|
|
21
|
-
|
|
22
|
-
# 3. Cherry-pick the fix commit from the source branch
|
|
23
|
-
git cherry-pick <commit-hash> # resolve conflicts if any
|
|
24
|
-
|
|
25
|
-
# 4. Run tests
|
|
26
|
-
npm test
|
|
27
|
-
|
|
28
|
-
# 5. Bump patch version and commit
|
|
29
|
-
npm run patch # bumps version in package.json (no git tag)
|
|
30
|
-
git add -A
|
|
31
|
-
git commit -m "Bump patch version"
|
|
32
|
-
|
|
33
|
-
# 6. Publish to npm (optional, with appropriate tag)
|
|
34
|
-
npm publish --tag <tag> # e.g. --tag legacy or --tag v11
|
|
35
|
-
|
|
36
|
-
# 7. Return to working branch and restore WIP
|
|
37
|
-
git checkout <working-branch>
|
|
38
|
-
git stash pop
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Notes:
|
|
42
|
-
- Find the commit hash with `git log --oneline <source-branch>`.
|
|
43
|
-
- If the cherry-pick has conflicts, resolve them, then `git cherry-pick --continue`.
|
|
44
|
-
- `npm run patch` runs `npm --no-git-tag-version version patch` — it bumps the patch version in `package.json` without creating a git tag.
|
|
45
|
-
- Use `--tag <tag>` with `npm publish` to avoid overwriting the `latest` tag on npm. Choose a tag that matches the branch (e.g. `legacy`, `v11`).
|
|
46
|
-
|
|
47
|
-
### Example: Backport Tasks 6 and 7.1
|
|
48
|
-
|
|
49
|
-
Each fix you want to backport needs its own separate commit on the source branch.
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# 1. Commit each fix separately on the source branch
|
|
53
|
-
git add aedes.js
|
|
54
|
-
git commit -m "Fix: add removed parameter to close handler" # Task 7.1
|
|
55
|
-
|
|
56
|
-
git add aedes.js
|
|
57
|
-
git commit -m "Fix: iterate subscribe/unsubscribe arrays" # Task 6
|
|
58
|
-
|
|
59
|
-
# 2. Find the commit hashes
|
|
60
|
-
git log --oneline migrate-aedes-v1
|
|
61
|
-
|
|
62
|
-
# 3. Backport to v0.15.x
|
|
63
|
-
git stash push -m "WIP before backport"
|
|
64
|
-
git checkout v0.15.x
|
|
65
|
-
git cherry-pick <Task-7.1-commit> # close handler: add removed parameter
|
|
66
|
-
git cherry-pick <Task-6-commit> # fix subscribe/unsubscribe event handlers
|
|
67
|
-
npm test
|
|
68
|
-
npm run patch
|
|
69
|
-
git add -A && git commit -m "Bump patch version"
|
|
70
|
-
npm publish --tag v0.15.x
|
|
71
|
-
git push origin v0.15.x
|
|
72
|
-
|
|
73
|
-
# 4. Backport to v11
|
|
74
|
-
git checkout v11
|
|
75
|
-
git cherry-pick <Task-7.1-commit> # close handler: add removed parameter
|
|
76
|
-
git cherry-pick <Task-6-commit> # fix subscribe/unsubscribe event handlers
|
|
77
|
-
npm test
|
|
78
|
-
npm run patch
|
|
79
|
-
git add -A && git commit -m "Bump patch version"
|
|
80
|
-
npm publish --tag v11
|
|
81
|
-
git push origin v11
|
|
82
|
-
|
|
83
|
-
# 5. Return to working branch
|
|
84
|
-
git checkout migrate-aedes-v1
|
|
85
|
-
git stash pop
|
|
86
|
-
```
|