2017-09-20 11:30:07 +02:00
|
|
|
/**
|
|
|
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
**/
|
|
|
|
|
2018-04-24 16:01:49 +02:00
|
|
|
var should = require("should");
|
|
|
|
var sinon = require("sinon");
|
|
|
|
|
2018-08-20 17:17:24 +02:00
|
|
|
var NR_TEST_UTILS = require("nr-test-utils");
|
|
|
|
var comms = NR_TEST_UTILS.require("@node-red/runtime/lib/api/comms");
|
2020-12-02 10:25:10 +01:00
|
|
|
var events = NR_TEST_UTILS.require("@node-red/util/lib/events");
|
2018-04-24 16:01:49 +02:00
|
|
|
|
2018-04-23 13:35:21 +02:00
|
|
|
describe("runtime-api/comms", function() {
|
2018-04-24 16:01:49 +02:00
|
|
|
describe("listens for events", function() {
|
|
|
|
var messages = [];
|
|
|
|
var clientConnection = {
|
|
|
|
send: function(topic,data) {
|
|
|
|
messages.push({topic,data})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var eventHandlers = {};
|
|
|
|
before(function(done) {
|
2020-12-02 10:25:10 +01:00
|
|
|
sinon.stub(events,"removeListener", function() {})
|
|
|
|
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
|
2018-04-24 16:01:49 +02:00
|
|
|
comms.init({
|
|
|
|
log: {
|
|
|
|
trace: function(){}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
comms.addConnection({client: clientConnection}).then(done);
|
|
|
|
})
|
|
|
|
after(function(done) {
|
|
|
|
comms.removeConnection({client: clientConnection}).then(done);
|
2020-12-02 10:25:10 +01:00
|
|
|
events.removeListener.restore();
|
|
|
|
events.on.restore();
|
2018-04-24 16:01:49 +02:00
|
|
|
})
|
|
|
|
afterEach(function() {
|
|
|
|
messages = [];
|
|
|
|
})
|
|
|
|
|
|
|
|
it('runtime events',function(){
|
|
|
|
eventHandlers.should.have.property('runtime-event');
|
|
|
|
eventHandlers['runtime-event']({
|
|
|
|
id: "my-event",
|
|
|
|
payload: "my-payload"
|
|
|
|
})
|
|
|
|
messages.should.have.length(1);
|
|
|
|
messages[0].should.have.property("topic","notification/my-event");
|
|
|
|
messages[0].should.have.property("data","my-payload")
|
|
|
|
})
|
|
|
|
it('status events',function(){
|
|
|
|
eventHandlers.should.have.property('node-status');
|
|
|
|
eventHandlers['node-status']({
|
|
|
|
id: "my-event",
|
2019-03-04 11:23:10 +01:00
|
|
|
status: {text:"my-status",badProperty:"should be filtered"}
|
2018-04-24 16:01:49 +02:00
|
|
|
})
|
|
|
|
messages.should.have.length(1);
|
|
|
|
messages[0].should.have.property("topic","status/my-event");
|
2019-03-04 11:23:10 +01:00
|
|
|
messages[0].should.have.property("data");
|
|
|
|
messages[0].data.should.have.property("text","my-status");
|
|
|
|
messages[0].data.should.not.have.property("badProperty");
|
|
|
|
|
2018-04-24 16:01:49 +02:00
|
|
|
})
|
|
|
|
it('comms events',function(){
|
|
|
|
eventHandlers.should.have.property('runtime-event');
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-topic",
|
|
|
|
data: "my-payload"
|
|
|
|
})
|
|
|
|
messages.should.have.length(1);
|
|
|
|
messages[0].should.have.property("topic","my-topic");
|
|
|
|
messages[0].should.have.property("data","my-payload")
|
|
|
|
})
|
|
|
|
});
|
|
|
|
describe("manages connections", function() {
|
|
|
|
var eventHandlers = {};
|
|
|
|
var messages = [];
|
|
|
|
var clientConnection1 = {
|
|
|
|
send: function(topic,data) {
|
|
|
|
messages.push({topic,data})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var clientConnection2 = {
|
|
|
|
send: function(topic,data) {
|
|
|
|
messages.push({topic,data})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
before(function() {
|
2020-12-02 10:25:10 +01:00
|
|
|
sinon.stub(events,"removeListener", function() {})
|
|
|
|
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
|
2018-04-24 16:01:49 +02:00
|
|
|
comms.init({
|
|
|
|
log: {
|
|
|
|
trace: function(){}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
2020-12-02 10:25:10 +01:00
|
|
|
after(function() {
|
|
|
|
events.removeListener.restore();
|
|
|
|
events.on.restore();
|
|
|
|
})
|
2018-04-24 16:01:49 +02:00
|
|
|
afterEach(function(done) {
|
|
|
|
comms.removeConnection({client: clientConnection1}).then(function() {
|
|
|
|
comms.removeConnection({client: clientConnection2}).then(done);
|
|
|
|
});
|
|
|
|
messages = [];
|
|
|
|
})
|
|
|
|
it('adds new connections',function(done){
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-topic",
|
|
|
|
data: "my-payload"
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection1}).then(function() {
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-topic",
|
|
|
|
data: "my-payload"
|
|
|
|
})
|
|
|
|
messages.should.have.length(1);
|
|
|
|
comms.addConnection({client: clientConnection2}).then(function() {
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-topic",
|
|
|
|
data: "my-payload"
|
|
|
|
})
|
|
|
|
messages.should.have.length(3);
|
|
|
|
done();
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('removes connections',function(done){
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-topic",
|
|
|
|
data: "my-payload"
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection1}).then(function() {
|
|
|
|
comms.addConnection({client: clientConnection2}).then(function() {
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-topic",
|
|
|
|
data: "my-payload"
|
|
|
|
})
|
|
|
|
messages.should.have.length(2);
|
|
|
|
comms.removeConnection({client: clientConnection1}).then(function() {
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-topic",
|
|
|
|
data: "my-payload"
|
|
|
|
})
|
|
|
|
messages.should.have.length(3);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe("subscriptions", function() {
|
|
|
|
var messages = [];
|
|
|
|
var clientConnection = {
|
|
|
|
send: function(topic,data) {
|
|
|
|
messages.push({topic,data})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var clientConnection2 = {
|
|
|
|
send: function(topic,data) {
|
|
|
|
messages.push({topic,data})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var eventHandlers = {};
|
|
|
|
before(function() {
|
2020-12-02 10:25:10 +01:00
|
|
|
sinon.stub(events,"removeListener", function() {})
|
|
|
|
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
|
2018-04-24 16:01:49 +02:00
|
|
|
comms.init({
|
|
|
|
log: {
|
|
|
|
trace: function(){}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
2020-12-02 10:25:10 +01:00
|
|
|
after(function() {
|
|
|
|
events.removeListener.restore();
|
|
|
|
events.on.restore();
|
|
|
|
})
|
2018-04-24 16:01:49 +02:00
|
|
|
afterEach(function(done) {
|
|
|
|
messages = [];
|
|
|
|
comms.removeConnection({client: clientConnection}).then(done);
|
|
|
|
})
|
|
|
|
|
|
|
|
it('subscribe triggers retained messages',function(done){
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-event",
|
|
|
|
data: "my-payload",
|
|
|
|
retain: true
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection}).then(function() {
|
|
|
|
return comms.subscribe({client: clientConnection, topic: "my-event"}).then(function() {
|
|
|
|
messages.should.have.length(1);
|
|
|
|
messages[0].should.have.property("topic","my-event");
|
|
|
|
messages[0].should.have.property("data","my-payload");
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
}).catch(done);
|
|
|
|
})
|
2020-11-17 14:29:13 +01:00
|
|
|
it('retains non-blank status message',function(done){
|
|
|
|
eventHandlers['node-status']({
|
|
|
|
id: "node1234",
|
|
|
|
status: {text:"hello"}
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection}).then(function() {
|
|
|
|
return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() {
|
|
|
|
messages.should.have.length(1);
|
|
|
|
messages[0].should.have.property("topic","status/node1234");
|
|
|
|
messages[0].should.have.property("data",{text:"hello", fill: undefined, shape: undefined});
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
}).catch(done);
|
|
|
|
})
|
|
|
|
it('does not retain blank status message',function(done){
|
|
|
|
eventHandlers['node-status']({
|
|
|
|
id: "node1234",
|
|
|
|
status: {}
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection}).then(function() {
|
|
|
|
return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() {
|
|
|
|
messages.should.have.length(0);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
}).catch(done);
|
|
|
|
})
|
|
|
|
it('does not send blank status if first status',function(done){
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection}).then(function() {
|
|
|
|
return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() {
|
|
|
|
eventHandlers['node-status']({
|
|
|
|
id: "node5678",
|
|
|
|
status: {}
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
it('sends blank status if replacing retained',function(done){
|
|
|
|
eventHandlers['node-status']({
|
|
|
|
id: "node5678",
|
|
|
|
status: {text:"hello"}
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection}).then(function() {
|
|
|
|
return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() {
|
|
|
|
messages.should.have.length(1);
|
|
|
|
eventHandlers['node-status']({
|
|
|
|
id: "node5678",
|
|
|
|
status: {}
|
|
|
|
})
|
|
|
|
messages.should.have.length(2);
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('does not retain initial status blank message',function(done){
|
|
|
|
eventHandlers['node-status']({
|
|
|
|
id: "my-event",
|
|
|
|
status: {}
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection}).then(function() {
|
|
|
|
return comms.subscribe({client: clientConnection, topic: "my-event"}).then(function() {
|
|
|
|
messages.should.have.length(1);
|
|
|
|
messages[0].should.have.property("topic","my-event");
|
|
|
|
messages[0].should.have.property("data","my-payload");
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
}).catch(done);
|
|
|
|
})
|
|
|
|
|
2018-04-24 16:01:49 +02:00
|
|
|
it('retained messages get cleared',function(done) {
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-event",
|
|
|
|
data: "my-payload",
|
|
|
|
retain: true
|
|
|
|
})
|
|
|
|
messages.should.have.length(0);
|
|
|
|
comms.addConnection({client: clientConnection}).then(function() {
|
|
|
|
return comms.subscribe({client: clientConnection, topic: "my-event"}).then(function() {
|
|
|
|
messages.should.have.length(1);
|
|
|
|
messages[0].should.have.property("topic","my-event");
|
|
|
|
messages[0].should.have.property("data","my-payload");
|
|
|
|
// Now we have a retained message, clear it
|
|
|
|
eventHandlers['comms']({
|
|
|
|
topic: "my-event",
|
|
|
|
data: "my-payload-cleared"
|
|
|
|
});
|
|
|
|
messages.should.have.length(2);
|
|
|
|
messages[1].should.have.property("topic","my-event");
|
|
|
|
messages[1].should.have.property("data","my-payload-cleared");
|
|
|
|
// Now add a second client and subscribe - no message should arrive
|
|
|
|
return comms.addConnection({client: clientConnection2}).then(function() {
|
|
|
|
return comms.subscribe({client: clientConnection2, topic: "my-event"}).then(function() {
|
|
|
|
messages.should.have.length(2);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
})
|
|
|
|
|
2017-09-20 11:30:07 +02:00
|
|
|
});
|