node-red-contrib-aedes 0.15.1 → 1.1.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.
@@ -52,47 +52,50 @@ describe('Aedes Broker retain tests', function () {
52
52
  }
53
53
  ];
54
54
  helper.load([aedesNode, mqttNode], flow, function () {
55
- const client1 = mqtt.connect('mqtt://localhost:1883', { clientId: 'client1' });
56
- const client2 = mqtt.connect('mqtt://localhost:1883', { clientId: 'client2' });
57
- client1.on('error', function (err) {
58
- console.error('Error: ', err.toString());
59
- });
60
- client2.on('error', function (err) {
61
- console.error('Error: ', err.toString());
62
- });
63
- client1.on('connect', function () {
64
- // console.log('External client1 connected');
65
- client1.publish('test1883', 'test', { retain: true }, function () {
66
- // console.log('Published test');
67
- client2.subscribe('test1883', function (err, granted) {
68
- // console.log('Subscription successful ' + JSON.stringify(granted));
69
- if (err) {
70
- console.error('Error subscribing');
71
- done();
72
- }
55
+ const n1 = helper.getNode('n1');
56
+ n1._initPromise.then(function () {
57
+ const client1 = mqtt.connect('mqtt://localhost:1883', { clientId: 'client1' });
58
+ const client2 = mqtt.connect('mqtt://localhost:1883', { clientId: 'client2' });
59
+ client1.on('error', function (err) {
60
+ console.error('Error: ', err.toString());
61
+ });
62
+ client2.on('error', function (err) {
63
+ console.error('Error: ', err.toString());
64
+ });
65
+ client1.on('connect', function () {
66
+ // console.log('External client1 connected');
67
+ client1.publish('test1883', 'test', { retain: true }, function () {
68
+ // console.log('Published test');
69
+ client2.subscribe('test1883', function (err, granted) {
70
+ // console.log('Subscription successful ' + JSON.stringify(granted));
71
+ if (err) {
72
+ console.error('Error subscribing');
73
+ done();
74
+ }
75
+ });
73
76
  });
74
77
  });
75
- });
76
- client2.on('connect', function () {
77
- // console.log('External client2 connected');
78
- });
78
+ client2.on('connect', function () {
79
+ // console.log('External client2 connected');
80
+ });
79
81
 
80
- const n2 = helper.getNode('n2');
81
- n2.on('input', function (msg) {
82
- // console.log('Broker received message topic: ' + msg.topic + ', clientid: ' + msg.payload.client.id);
83
- if (msg.topic === 'subscribe') {
84
- // console.log('Client ' + msg.payload.client.id + ' subscribed ' + JSON.stringify(msg.payload.client.subscriptions));
85
- } else if (msg.topic === 'clientReady') {
86
- // console.log('Client ' + msg.payload.client.id + ' connected with clean ' + msg.payload.client.clean);
87
- }
88
- });
89
- client2.on('message', function (topic, message) {
90
- // console.log(message.toString());
91
- should(topic.toString()).equal('test1883');
92
- should(message.toString()).equal('test');
93
- client2.end(function () {
94
- client1.end(function () {
95
- done();
82
+ const n2 = helper.getNode('n2');
83
+ n2.on('input', function (msg) {
84
+ // console.log('Broker received message topic: ' + msg.topic + ', clientid: ' + msg.payload.client.id);
85
+ if (msg.topic === 'subscribe') {
86
+ // console.log('Client ' + msg.payload.client.id + ' subscribed ' + JSON.stringify(msg.payload.client.subscriptions));
87
+ } else if (msg.topic === 'clientReady') {
88
+ // console.log('Client ' + msg.payload.client.id + ' connected with clean ' + msg.payload.client.clean);
89
+ }
90
+ });
91
+ client2.on('message', function (topic, message) {
92
+ // console.log(message.toString());
93
+ should(topic.toString()).equal('test1883');
94
+ should(message.toString()).equal('test');
95
+ client2.end(function () {
96
+ client1.end(function () {
97
+ done();
98
+ });
96
99
  });
97
100
  });
98
101
  });
@@ -116,49 +119,52 @@ describe('Aedes Broker retain tests', function () {
116
119
  }
117
120
  ];
118
121
  helper.load([aedesNode, mqttNode], flow, function () {
119
- const client1 = mqtt.connect('mqtt://localhost:1883', { clientId: 'client1' });
120
- const client2 = mqtt.connect('mqtt://localhost:1883', { clientId: 'client2' });
121
- client1.on('error', function (err) {
122
- console.error('Error: ', err.toString());
123
- });
124
- client2.on('error', function (err) {
125
- console.error('Error: ', err.toString());
126
- });
127
- client2.on('connect', function () {
128
- // console.log('External client2 connected');
129
- });
130
- client1.on('connect', function () {
131
- // console.log('External client1 connected');
132
- client1.publish('test1883', 'test1', { retain: true }, function () {
133
- // console.log('Published test1');
134
- client1.publish('test1883', 'test2', { retain: true }, function () {
135
- // console.log('Published test2');
136
- client2.subscribe('test1883', function (err, granted) {
137
- // console.log('Subscription successful ' + JSON.stringify(granted));
138
- if (err) {
139
- console.error('Error subscribing');
140
- done();
141
- }
122
+ const n1 = helper.getNode('n1');
123
+ n1._initPromise.then(function () {
124
+ const client1 = mqtt.connect('mqtt://localhost:1883', { clientId: 'client1' });
125
+ const client2 = mqtt.connect('mqtt://localhost:1883', { clientId: 'client2' });
126
+ client1.on('error', function (err) {
127
+ console.error('Error: ', err.toString());
128
+ });
129
+ client2.on('error', function (err) {
130
+ console.error('Error: ', err.toString());
131
+ });
132
+ client2.on('connect', function () {
133
+ // console.log('External client2 connected');
134
+ });
135
+ client1.on('connect', function () {
136
+ // console.log('External client1 connected');
137
+ client1.publish('test1883', 'test1', { retain: true }, function () {
138
+ // console.log('Published test1');
139
+ client1.publish('test1883', 'test2', { retain: true }, function () {
140
+ // console.log('Published test2');
141
+ client2.subscribe('test1883', function (err, granted) {
142
+ // console.log('Subscription successful ' + JSON.stringify(granted));
143
+ if (err) {
144
+ console.error('Error subscribing');
145
+ done();
146
+ }
147
+ });
142
148
  });
143
149
  });
144
150
  });
145
- });
146
- const n2 = helper.getNode('n2');
147
- n2.on('input', function (msg) {
148
- // console.log('Broker received message topic: ' + msg.topic + ', clientid: ' + msg.payload.client.id);
149
- if (msg.topic === 'subscribe') {
150
- // console.log('Client ' + msg.payload.client.id + ' subscribed ' + JSON.stringify(msg.payload.client.subscriptions));
151
- } else if (msg.topic === 'clientReady') {
152
- // console.log('Client ' + msg.payload.client.id + ' connected with clean ' + msg.payload.client.clean);
153
- }
154
- });
155
- client2.on('message', function (topic, message) {
156
- // console.log(message.toString());
157
- should(topic.toString()).equal('test1883');
158
- should(message.toString()).equal('test2');
159
- client2.end(function () {
160
- client1.end(function () {
161
- done();
151
+ const n2 = helper.getNode('n2');
152
+ n2.on('input', function (msg) {
153
+ // console.log('Broker received message topic: ' + msg.topic + ', clientid: ' + msg.payload.client.id);
154
+ if (msg.topic === 'subscribe') {
155
+ // console.log('Client ' + msg.payload.client.id + ' subscribed ' + JSON.stringify(msg.payload.client.subscriptions));
156
+ } else if (msg.topic === 'clientReady') {
157
+ // console.log('Client ' + msg.payload.client.id + ' connected with clean ' + msg.payload.client.clean);
158
+ }
159
+ });
160
+ client2.on('message', function (topic, message) {
161
+ // console.log(message.toString());
162
+ should(topic.toString()).equal('test1883');
163
+ should(message.toString()).equal('test2');
164
+ client2.end(function () {
165
+ client1.end(function () {
166
+ done();
167
+ });
162
168
  });
163
169
  });
164
170
  });
@@ -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 should = require('should');
7
8
 
8
9
  const credentialsOK = { n1: { username: 'test', password: 'test' }, b1: { user: 'test', password: 'test' } };
9
10
  const credentialsMissing = { n1: { username: 'test', password: 'test' }, b1: { user: 'test' } };
@@ -68,10 +69,13 @@ describe('Aedes Broker TCP tests', function () {
68
69
  }
69
70
  ],
70
71
  function () {
71
- const n2 = helper.getNode('n2');
72
- n2.on('input', function (msg) {
73
- msg.should.have.property('topic', 'clientReady');
74
- done();
72
+ const n1 = helper.getNode('n1');
73
+ n1._initPromise.then(function () {
74
+ const n2 = helper.getNode('n2');
75
+ n2.on('input', function (msg) {
76
+ msg.should.have.property('topic', 'clientReady');
77
+ done();
78
+ });
75
79
  });
76
80
  });
77
81
  });
@@ -108,10 +112,13 @@ describe('Aedes Broker TCP tests', function () {
108
112
 
109
113
  helper.load([aedesNode, mqttNode], flow, credentialsMissing,
110
114
  function () {
111
- const n2 = helper.getNode('n2');
112
- n2.on('input', function (msg) {
113
- msg.should.have.property('topic', 'clientError');
114
- done();
115
+ const n1 = helper.getNode('n1');
116
+ n1._initPromise.then(function () {
117
+ const n2 = helper.getNode('n2');
118
+ n2.on('input', function (msg) {
119
+ msg.should.have.property('topic', 'clientError');
120
+ done();
121
+ });
115
122
  });
116
123
  });
117
124
  });
@@ -148,10 +155,13 @@ describe('Aedes Broker TCP tests', function () {
148
155
 
149
156
  helper.load([aedesNode, mqttNode], flow, credentialsOK,
150
157
  function () {
151
- const n2 = helper.getNode('n2');
152
- n2.on('input', function (msg) {
153
- msg.should.have.property('topic', 'clientReady');
154
- done();
158
+ const n1 = helper.getNode('n1');
159
+ n1._initPromise.then(function () {
160
+ const n2 = helper.getNode('n2');
161
+ n2.on('input', function (msg) {
162
+ msg.should.have.property('topic', 'clientReady');
163
+ done();
164
+ });
155
165
  });
156
166
  });
157
167
  });
@@ -198,17 +208,20 @@ describe('Aedes Broker TCP tests', function () {
198
208
  }
199
209
  ],
200
210
  function () {
201
- const n2 = helper.getNode('n2');
202
- const n3 = helper.getNode('n3');
203
- const n5 = helper.getNode('n5');
204
- n2.on('input', function (msg) {
205
- if (msg.topic === 'subscribe') {
206
- n3.receive({ payload: 'test' });
207
- }
208
- });
209
- n5.on('input', function (msg) {
210
- msg.should.have.property('topic', 'test1883');
211
- done();
211
+ const n1 = helper.getNode('n1');
212
+ n1._initPromise.then(function () {
213
+ const n2 = helper.getNode('n2');
214
+ const n3 = helper.getNode('n3');
215
+ const n5 = helper.getNode('n5');
216
+ n2.on('input', function (msg) {
217
+ if (msg.topic === 'subscribe') {
218
+ n3.receive({ payload: 'test' });
219
+ }
220
+ });
221
+ n5.on('input', function (msg) {
222
+ msg.should.have.property('topic', 'test1883');
223
+ done();
224
+ });
212
225
  });
213
226
  });
214
227
  });
@@ -267,22 +280,26 @@ describe('Aedes Broker TCP tests', function () {
267
280
  }
268
281
  ],
269
282
  function () {
270
- let i = 0;
271
- const n2 = helper.getNode('n2');
272
- n2.on('input', function (msg) {
273
- msg.should.have.property('topic', 'clientReady');
274
- i++;
275
- if (i === 2) {
276
- done();
277
- }
278
- });
279
- const n12 = helper.getNode('n12');
280
- n12.on('input', function (msg) {
281
- msg.should.have.property('topic', 'clientReady');
282
- i++;
283
- if (i === 2) {
284
- done();
285
- }
283
+ const n1 = helper.getNode('n1');
284
+ const n11 = helper.getNode('n11');
285
+ Promise.all([n1._initPromise, n11._initPromise]).then(function () {
286
+ let i = 0;
287
+ const n2 = helper.getNode('n2');
288
+ n2.on('input', function (msg) {
289
+ msg.should.have.property('topic', 'clientReady');
290
+ i++;
291
+ if (i === 2) {
292
+ done();
293
+ }
294
+ });
295
+ const n12 = helper.getNode('n12');
296
+ n12.on('input', function (msg) {
297
+ msg.should.have.property('topic', 'clientReady');
298
+ i++;
299
+ if (i === 2) {
300
+ done();
301
+ }
302
+ });
286
303
  });
287
304
  });
288
305
  });
@@ -334,18 +351,21 @@ describe('Aedes Broker TCP tests', function () {
334
351
  type: 'helper'
335
352
  }];
336
353
  helper.load(aedesNode, flow, function () {
337
- const client = mqtt.connect('mqtt://localhost:1883', { clientId: 'client', resubscribe: false, reconnectPeriod: -1 });
338
- client.on('error', function (err) {
339
- console.error('Error: ', err.toString());
340
- });
341
- client.on('connect', function () {
342
- // console.log('External client connected');
343
- });
344
- const n2 = helper.getNode('n2');
345
- n2.on('input', function (msg) {
346
- msg.should.have.property('topic', 'clientReady');
347
- client.end(function () {
348
- done();
354
+ const n1 = helper.getNode('n1');
355
+ n1._initPromise.then(function () {
356
+ const client = mqtt.connect('mqtt://localhost:1883', { clientId: 'client', resubscribe: false, reconnectPeriod: -1 });
357
+ client.on('error', function (err) {
358
+ console.error('Error: ', err.toString());
359
+ });
360
+ client.on('connect', function () {
361
+ // console.log('External client connected');
362
+ });
363
+ const n2 = helper.getNode('n2');
364
+ n2.on('input', function (msg) {
365
+ msg.should.have.property('topic', 'clientReady');
366
+ client.end(function () {
367
+ done();
368
+ });
349
369
  });
350
370
  });
351
371
  });
@@ -387,27 +407,200 @@ describe('Aedes Broker TCP tests', function () {
387
407
  }
388
408
  ];
389
409
  helper.load([aedesNode, mqttNode], flow, function () {
390
- const client = mqtt.connect('mqtt://localhost:1883', { clientId: 'client', resubscribe: false, reconnectPeriod: -1 });
391
- client.on('error', function (err) {
392
- console.error('Error: ', err.toString());
410
+ const n1 = helper.getNode('n1');
411
+ n1._initPromise.then(function () {
412
+ const client = mqtt.connect('mqtt://localhost:1883', { clientId: 'client', resubscribe: false, reconnectPeriod: -1 });
413
+ client.on('error', function (err) {
414
+ console.error('Error: ', err.toString());
415
+ });
416
+ client.on('connect', function () {
417
+ // console.log('External client connected');
418
+ });
419
+ const n2 = helper.getNode('n2');
420
+ const n5 = helper.getNode('n5');
421
+ n2.on('input', function (msg) {
422
+ if (msg.topic === 'subscribe') {
423
+ client.publish('test1883', 'test');
424
+ }
425
+ });
426
+ n5.on('input', function (msg) {
427
+ // console.log(msg);
428
+ msg.should.have.property('topic', 'test1883');
429
+ client.end(function () {
430
+ done();
431
+ });
432
+ });
393
433
  });
394
- client.on('connect', function () {
395
- // console.log('External client connected');
434
+ });
435
+ });
436
+
437
+ it('should handle initialization failure gracefully', function (done) {
438
+ this.timeout(10000);
439
+ const net = require('net');
440
+ // Occupy port 1887 to force an EADDRINUSE
441
+ const blocker = net.createServer();
442
+ blocker.listen(1887, function () {
443
+ const flow = [{
444
+ id: 'n1',
445
+ type: 'aedes broker',
446
+ mqtt_port: '1887',
447
+ name: 'Aedes 1887',
448
+ wires: [[], []]
449
+ }];
450
+ helper.load(aedesNode, flow, function () {
451
+ const n1 = helper.getNode('n1');
452
+ n1._initPromise.then(function () {
453
+ // Init succeeded but server.listen should have fired an error
454
+ blocker.close(function () {
455
+ done();
456
+ });
457
+ }).catch(function () {
458
+ // Expected to fail
459
+ blocker.close(function () {
460
+ done();
461
+ });
462
+ });
463
+ });
464
+ });
465
+ });
466
+
467
+ it('should emit clientDisconnect when a client disconnects', function (done) {
468
+ this.timeout(10000);
469
+ const flow = [
470
+ {
471
+ id: 'n1',
472
+ type: 'aedes broker',
473
+ mqtt_port: '1883',
474
+ name: 'Aedes 1883',
475
+ wires: [['n2'], []]
476
+ },
477
+ {
478
+ id: 'n2',
479
+ type: 'helper'
480
+ }
481
+ ];
482
+ helper.load(aedesNode, flow, function () {
483
+ const n1 = helper.getNode('n1');
484
+ n1._initPromise.then(function () {
485
+ const client = mqtt.connect('mqtt://localhost:1883', {
486
+ clientId: 'client-disconnect-test',
487
+ resubscribe: false,
488
+ reconnectPeriod: -1
489
+ });
490
+ const n2 = helper.getNode('n2');
491
+ n2.on('input', function (msg) {
492
+ if (msg.topic === 'clientReady') {
493
+ client.end();
494
+ } else if (msg.topic === 'clientDisconnect') {
495
+ should(msg.payload.client.id).equal('client-disconnect-test');
496
+ done();
497
+ }
498
+ });
396
499
  });
397
- const n2 = helper.getNode('n2');
398
- const n5 = helper.getNode('n5');
399
- n2.on('input', function (msg) {
400
- if (msg.topic === 'subscribe') {
401
- client.publish('test1883', 'test');
402
- }
500
+ });
501
+ });
502
+
503
+ it('should emit keepaliveTimeout when a client stops responding', function (done) {
504
+ this.timeout(10000);
505
+ const flow = [
506
+ {
507
+ id: 'n1',
508
+ type: 'aedes broker',
509
+ mqtt_port: '1883',
510
+ name: 'Aedes 1883',
511
+ wires: [['n2'], []]
512
+ },
513
+ {
514
+ id: 'n2',
515
+ type: 'helper'
516
+ }
517
+ ];
518
+ helper.load(aedesNode, flow, function () {
519
+ const n1 = helper.getNode('n1');
520
+ n1._initPromise.then(function () {
521
+ const net = require('net');
522
+ const socket = net.createConnection({ port: 1883 }, function () {
523
+ // Send a minimal MQTT CONNECT packet with keepalive=1 second
524
+ const connectPacket = Buffer.from([
525
+ 0x10, // CONNECT packet type
526
+ 0x11, // Remaining length: 17
527
+ 0x00, 0x04, // Protocol name length
528
+ 0x4D, 0x51, 0x54, 0x54, // "MQTT"
529
+ 0x04, // Protocol level 4 (MQTT 3.1.1)
530
+ 0x02, // Connect flags (clean session)
531
+ 0x00, 0x01, // Keep alive: 1 second
532
+ 0x00, 0x05, // Client ID length: 5
533
+ 0x6B, 0x61, 0x74, 0x65, 0x73 // "kates"
534
+ ]);
535
+ socket.write(connectPacket);
536
+ // Do not send any more data — keepalive will expire
537
+ });
538
+ const n2 = helper.getNode('n2');
539
+ n2.on('input', function (msg) {
540
+ if (msg.topic === 'keepaliveTimeout') {
541
+ should(msg.payload.client.id).equal('kates');
542
+ socket.destroy();
543
+ done();
544
+ }
545
+ });
403
546
  });
404
- n5.on('input', function (msg) {
405
- // console.log(msg);
406
- msg.should.have.property('topic', 'test1883');
407
- client.end(function () {
408
- done();
547
+ });
548
+ });
549
+
550
+ it('should emit published messages on the 2nd output', function (done) {
551
+ this.timeout(10000);
552
+ const flow = [
553
+ {
554
+ id: 'n1',
555
+ type: 'aedes broker',
556
+ mqtt_port: '1883',
557
+ name: 'Aedes 1883',
558
+ wires: [[], ['n2']]
559
+ },
560
+ {
561
+ id: 'n2',
562
+ type: 'helper'
563
+ }
564
+ ];
565
+ helper.load(aedesNode, flow, function () {
566
+ const n1 = helper.getNode('n1');
567
+ n1._initPromise.then(function () {
568
+ const client = mqtt.connect('mqtt://localhost:1883', {
569
+ clientId: 'publish-test',
570
+ resubscribe: false,
571
+ reconnectPeriod: -1
572
+ });
573
+ client.on('connect', function () {
574
+ client.publish('testTopic', 'testPayload');
575
+ });
576
+ const n2 = helper.getNode('n2');
577
+ n2.on('input', function (msg) {
578
+ if (msg.payload.packet && msg.payload.packet.topic === 'testTopic') {
579
+ should(msg.topic).equal('publish');
580
+ should(msg.payload.packet.payload.toString()).equal('testPayload');
581
+ client.end(function () {
582
+ done();
583
+ });
584
+ }
409
585
  });
410
586
  });
411
587
  });
412
588
  });
589
+
590
+ it('should handle close during initialization', function (done) {
591
+ this.timeout(10000);
592
+ const flow = [{
593
+ id: 'n1',
594
+ type: 'aedes broker',
595
+ mqtt_port: '1888',
596
+ name: 'Aedes 1888',
597
+ wires: [[], []]
598
+ }];
599
+ helper.load(aedesNode, flow, function () {
600
+ // Immediately unload before init completes
601
+ helper.unload().then(function () {
602
+ done();
603
+ });
604
+ });
605
+ });
413
606
  });