mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add tests for MQTT v5 auto parsing hints
This commit is contained in:
parent
78f456911a
commit
8ba6a7436e
@ -4,6 +4,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const should = require("should");
|
const should = require("should");
|
||||||
const helper = require("node-red-node-test-helper");
|
const helper = require("node-red-node-test-helper");
|
||||||
|
const { doesNotThrow } = require("should");
|
||||||
const mqttNodes = require("nr-test-utils").require("@node-red/nodes/core/network/10-mqtt.js");
|
const mqttNodes = require("nr-test-utils").require("@node-red/nodes/core/network/10-mqtt.js");
|
||||||
const BROKER_HOST = process.env.MQTT_BROKER_SERVER || "localhost";
|
const BROKER_HOST = process.env.MQTT_BROKER_SERVER || "localhost";
|
||||||
const BROKER_PORT = process.env.MQTT_BROKER_PORT || 1883;
|
const BROKER_PORT = process.env.MQTT_BROKER_PORT || 1883;
|
||||||
@ -92,7 +93,21 @@ describe('MQTT Nodes', function () {
|
|||||||
options.expectMsg = Object.assign({}, options.sendMsg);
|
options.expectMsg = Object.assign({}, options.sendMsg);
|
||||||
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, { done: done });
|
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, { done: done });
|
||||||
});
|
});
|
||||||
itConditional('should send JSON and receive string (auto)', function (done) {
|
//Prior to V3, "auto" mode would only parse to string or buffer.
|
||||||
|
// itConditional('should send JSON and receive string (auto mode)', function (done) {
|
||||||
|
// if (skipTests) { return this.skip() }
|
||||||
|
// this.timeout = 2000;
|
||||||
|
// const options = {}
|
||||||
|
// options.sendMsg = {
|
||||||
|
// topic: nextTopic(),
|
||||||
|
// payload: '{"prop":"value1", "num":1}',
|
||||||
|
// qos: 1
|
||||||
|
// }
|
||||||
|
// options.expectMsg = Object.assign({}, options.sendMsg);
|
||||||
|
// testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, { done: done });
|
||||||
|
// })
|
||||||
|
//In V3, "auto" mode should try to parse JSON, then string and fall back to buffer
|
||||||
|
itConditional('should send JSON and receive object (auto mode)', function (done) {
|
||||||
if (skipTests) { return this.skip() }
|
if (skipTests) { return this.skip() }
|
||||||
this.timeout = 2000;
|
this.timeout = 2000;
|
||||||
const options = {}
|
const options = {}
|
||||||
@ -102,9 +117,22 @@ describe('MQTT Nodes', function () {
|
|||||||
qos: 1
|
qos: 1
|
||||||
}
|
}
|
||||||
options.expectMsg = Object.assign({}, options.sendMsg);
|
options.expectMsg = Object.assign({}, options.sendMsg);
|
||||||
|
options.expectMsg.payload = JSON.parse(options.sendMsg.payload);
|
||||||
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, { done: done });
|
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, { done: done });
|
||||||
})
|
})
|
||||||
itConditional('should send JSON and receive string (utf8)', function (done) {
|
itConditional('should send invalid JSON and receive string (auto mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(),
|
||||||
|
payload: '{prop:"value3", "num":3}'// send invalid JSON ...
|
||||||
|
}
|
||||||
|
options.expectMsg = Object.assign({}, options.sendMsg);//expect same payload
|
||||||
|
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, { done: done });
|
||||||
|
});
|
||||||
|
|
||||||
|
itConditional('should send JSON and receive string (utf8 mode)', function (done) {
|
||||||
if (skipTests) { return this.skip() }
|
if (skipTests) { return this.skip() }
|
||||||
this.timeout = 2000;
|
this.timeout = 2000;
|
||||||
const options = {}
|
const options = {}
|
||||||
@ -116,7 +144,7 @@ describe('MQTT Nodes', function () {
|
|||||||
options.expectMsg = Object.assign({}, options.sendMsg);
|
options.expectMsg = Object.assign({}, options.sendMsg);
|
||||||
testSendRecv({}, { datatype: "utf8", topicType: "static" }, {}, options, { done: done });
|
testSendRecv({}, { datatype: "utf8", topicType: "static" }, {}, options, { done: done });
|
||||||
});
|
});
|
||||||
itConditional('should send JSON and receive Object (json)', function (done) {
|
itConditional('should send JSON and receive Object (json mode)', function (done) {
|
||||||
if (skipTests) { return this.skip() }
|
if (skipTests) { return this.skip() }
|
||||||
this.timeout = 2000;
|
this.timeout = 2000;
|
||||||
const options = {}
|
const options = {}
|
||||||
@ -127,7 +155,31 @@ describe('MQTT Nodes', function () {
|
|||||||
options.expectMsg = Object.assign({}, options.sendMsg, { payload: { "prop": "value3", "num": 3 } });//expect an object
|
options.expectMsg = Object.assign({}, options.sendMsg, { payload: { "prop": "value3", "num": 3 } });//expect an object
|
||||||
testSendRecv({}, { datatype: "json", topicType: "static" }, {}, options, { done: done });
|
testSendRecv({}, { datatype: "json", topicType: "static" }, {}, options, { done: done });
|
||||||
});
|
});
|
||||||
itConditional('should send String and receive Buffer (buffer)', function (done) {
|
itConditional('should send invalid JSON and raise error (json mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(),
|
||||||
|
payload: '{prop:"value3", "num":3}', // send invalid JSON ...
|
||||||
|
}
|
||||||
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
|
hooks.afterLoad = (helperNode, mqttBroker, mqttIn, mqttOut) => {
|
||||||
|
helperNode.on("input", function (msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.a.property("error").type("object");
|
||||||
|
msg.error.should.have.a.property("source").type("object");
|
||||||
|
msg.error.source.should.have.a.property("id", mqttIn.id);
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done(err)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true; //handled
|
||||||
|
}
|
||||||
|
testSendRecv({}, { datatype: "json", topicType: "static" }, {}, options, hooks);
|
||||||
|
});
|
||||||
|
itConditional('should send String and receive Buffer (buffer mode)', function (done) {
|
||||||
if (skipTests) { return this.skip() }
|
if (skipTests) { return this.skip() }
|
||||||
this.timeout = 2000;
|
this.timeout = 2000;
|
||||||
const options = {}
|
const options = {}
|
||||||
@ -138,7 +190,7 @@ describe('MQTT Nodes', function () {
|
|||||||
options.expectMsg = Object.assign({}, options.sendMsg, { payload: Buffer.from(options.sendMsg.payload) });//expect Buffer.from(msg.payload)
|
options.expectMsg = Object.assign({}, options.sendMsg, { payload: Buffer.from(options.sendMsg.payload) });//expect Buffer.from(msg.payload)
|
||||||
testSendRecv({}, { datatype: "buffer", topicType: "static" }, {}, options, { done: done });
|
testSendRecv({}, { datatype: "buffer", topicType: "static" }, {}, options, { done: done });
|
||||||
});
|
});
|
||||||
itConditional('should send utf8 Buffer and receive String (auto)', function (done) {
|
itConditional('should send utf8 Buffer and receive String (auto mode)', function (done) {
|
||||||
if (skipTests) { return this.skip() }
|
if (skipTests) { return this.skip() }
|
||||||
this.timeout = 2000;
|
this.timeout = 2000;
|
||||||
const options = {}
|
const options = {}
|
||||||
@ -149,7 +201,7 @@ describe('MQTT Nodes', function () {
|
|||||||
options.expectMsg = Object.assign({}, options.sendMsg, { payload: "x y z" });//set expected payload to "x y z"
|
options.expectMsg = Object.assign({}, options.sendMsg, { payload: "x y z" });//set expected payload to "x y z"
|
||||||
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, { done: done });
|
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, { done: done });
|
||||||
});
|
});
|
||||||
itConditional('should send non utf8 Buffer and receive Buffer (auto)', function (done) {
|
itConditional('should send non utf8 Buffer and receive Buffer (auto mode)', function (done) {
|
||||||
if (skipTests) { return this.skip() }
|
if (skipTests) { return this.skip() }
|
||||||
this.timeout = 2000;
|
this.timeout = 2000;
|
||||||
const options = {}
|
const options = {}
|
||||||
@ -158,7 +210,7 @@ describe('MQTT Nodes', function () {
|
|||||||
topic: nextTopic(),
|
topic: nextTopic(),
|
||||||
payload: Buffer.from([0xC0, 0xC1, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF]) //non valid UTF8
|
payload: Buffer.from([0xC0, 0xC1, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF]) //non valid UTF8
|
||||||
}
|
}
|
||||||
options.expectMsg = Object.assign({}, options.sendMsg);
|
options.expectMsg = Object.assign({}, options.sendMsg, {payload: Buffer.from([0xC0, 0xC1, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF])});
|
||||||
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
testSendRecv({}, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
||||||
});
|
});
|
||||||
itConditional('should send/receive all v5 flags and settings', function (done) {
|
itConditional('should send/receive all v5 flags and settings', function (done) {
|
||||||
@ -168,16 +220,16 @@ describe('MQTT Nodes', function () {
|
|||||||
const options = {}
|
const options = {}
|
||||||
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
options.sendMsg = {
|
options.sendMsg = {
|
||||||
topic: t + "/command", payload: Buffer.from("v5"), qos: 1, retain: true,
|
topic: t + "/command", payload: Buffer.from('{"version":"v5"}'), qos: 1, retain: true,
|
||||||
responseTopic: t + "/response",
|
responseTopic: t + "/response",
|
||||||
userProperties: { prop1: "val1" },
|
userProperties: { prop1: "val1" },
|
||||||
contentType: "application/json",
|
contentType: "text/plain",
|
||||||
correlationData: Buffer.from([1, 2, 3]),
|
correlationData: Buffer.from([1, 2, 3]),
|
||||||
payloadFormatIndicator: true,
|
payloadFormatIndicator: true,
|
||||||
messageExpiryInterval: 2000,
|
messageExpiryInterval: 2000,
|
||||||
}
|
}
|
||||||
options.expectMsg = Object.assign({}, options.sendMsg);
|
options.expectMsg = Object.assign({}, options.sendMsg);
|
||||||
options.expectMsg.payload = options.expectMsg.payload.toString(); //auto mode + payloadFormatIndicator should make a string
|
options.expectMsg.payload = options.expectMsg.payload.toString(); //auto mode + payloadFormatIndicator + contentType: "text/plain" should make a string
|
||||||
delete options.expectMsg.payloadFormatIndicator; //Seems mqtt.js only publishes payloadFormatIndicator the will msg
|
delete options.expectMsg.payloadFormatIndicator; //Seems mqtt.js only publishes payloadFormatIndicator the will msg
|
||||||
const inOptions = {
|
const inOptions = {
|
||||||
datatype: "auto", topicType: "static",
|
datatype: "auto", topicType: "static",
|
||||||
@ -185,6 +237,98 @@ describe('MQTT Nodes', function () {
|
|||||||
}
|
}
|
||||||
testSendRecv({ protocolVersion: 5 }, inOptions, {}, options, hooks);
|
testSendRecv({ protocolVersion: 5 }, inOptions, {}, options, hooks);
|
||||||
});
|
});
|
||||||
|
itConditional('should send regular string with v5 media type "text/plain" and receive a string (auto mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(), payload: "abc", contentType: "text/plain"
|
||||||
|
}
|
||||||
|
options.expectMsg = Object.assign({}, options.sendMsg);
|
||||||
|
testSendRecv({ protocolVersion: 5 }, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
||||||
|
});
|
||||||
|
itConditional('should send JSON with v5 media type "text/plain" and receive a string (auto mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(), payload: '{"prop":"val"}', contentType: "text/plain"
|
||||||
|
}
|
||||||
|
options.expectMsg = Object.assign({}, options.sendMsg);
|
||||||
|
testSendRecv({ protocolVersion: 5 }, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
||||||
|
});
|
||||||
|
itConditional('should send JSON with v5 media type "application/json" and receive an object (auto mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(), payload: '{"prop":"val"}', contentType: "application/json",
|
||||||
|
}
|
||||||
|
options.expectMsg = Object.assign({}, options.sendMsg, { payload: JSON.parse(options.sendMsg.payload)});
|
||||||
|
testSendRecv({ protocolVersion: 5 }, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
||||||
|
});
|
||||||
|
itConditional('should send invalid JSON with v5 media type "application/json" and raise an error (auto mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(),
|
||||||
|
payload: '{prop:"value3", "num":3}', contentType: "application/json", // send invalid JSON ...
|
||||||
|
}
|
||||||
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
|
hooks.afterLoad = (helperNode, mqttBroker, mqttIn, mqttOut) => {
|
||||||
|
helperNode.on("input", function (msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.a.property("error").type("object");
|
||||||
|
msg.error.should.have.a.property("source").type("object");
|
||||||
|
msg.error.source.should.have.a.property("id", mqttIn.id);
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done(err)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true; //handled
|
||||||
|
}
|
||||||
|
testSendRecv({ protocolVersion: 5 }, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
||||||
|
});
|
||||||
|
|
||||||
|
itConditional('should send buffer with v5 media type "application/json" and receive an object (auto mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(), payload: Buffer.from([0x7b,0x22,0x70,0x72,0x6f,0x70,0x22,0x3a,0x22,0x76,0x61,0x6c,0x22,0x7d]), contentType: "application/json",
|
||||||
|
}
|
||||||
|
options.expectMsg = Object.assign({}, options.sendMsg, { payload: {"prop":"val"}});
|
||||||
|
testSendRecv({ protocolVersion: 5 }, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
||||||
|
});
|
||||||
|
itConditional('should send buffer with v5 media type "text/plain" and receive a string (auto mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(), payload: Buffer.from([0x7b,0x22,0x70,0x72,0x6f,0x70,0x22,0x3a,0x22,0x76,0x61,0x6c,0x22,0x7d]), contentType: "text/plain",
|
||||||
|
}
|
||||||
|
options.expectMsg = Object.assign({}, options.sendMsg, { payload: '{"prop":"val"}'});
|
||||||
|
testSendRecv({ protocolVersion: 5 }, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
||||||
|
});
|
||||||
|
itConditional('should send buffer with v5 media type "application/zip" and receive a buffer (auto mode)', function (done) {
|
||||||
|
if (skipTests) { return this.skip() }
|
||||||
|
this.timeout = 2000;
|
||||||
|
const options = {}
|
||||||
|
const hooks = { done: done, beforeLoad: null, afterLoad: null, afterConnect: null }
|
||||||
|
options.sendMsg = {
|
||||||
|
topic: nextTopic(), payload: Buffer.from([0x7b,0x22,0x70,0x72,0x6f,0x70,0x22,0x3a,0x22,0x76,0x61,0x6c,0x22,0x7d]), contentType: "application/zip",
|
||||||
|
}
|
||||||
|
options.expectMsg = Object.assign({}, options.sendMsg, { payload: Buffer.from([0x7b,0x22,0x70,0x72,0x6f,0x70,0x22,0x3a,0x22,0x76,0x61,0x6c,0x22,0x7d])});
|
||||||
|
testSendRecv({ protocolVersion: 5 }, { datatype: "auto", topicType: "static" }, {}, options, hooks);
|
||||||
|
});
|
||||||
|
|
||||||
itConditional('should subscribe dynamically via action', function (done) {
|
itConditional('should subscribe dynamically via action', function (done) {
|
||||||
if (skipTests) { return this.skip() }
|
if (skipTests) { return this.skip() }
|
||||||
this.timeout = 2000;
|
this.timeout = 2000;
|
||||||
@ -463,14 +607,16 @@ function buildBasicMQTTSendRecvFlow(brokerOptions, inOptions, outOptions) {
|
|||||||
const inNode = buildMQTTInNode(inOptions.id, inOptions.name, inOptions.broker || broker.id, inOptions.topic, inOptions, ["helper.node"]);
|
const inNode = buildMQTTInNode(inOptions.id, inOptions.name, inOptions.broker || broker.id, inOptions.topic, inOptions, ["helper.node"]);
|
||||||
const outNode = buildMQTTOutNode(outOptions.id, outOptions.name, outOptions.broker || broker.id, outOptions.topic, outOptions);
|
const outNode = buildMQTTOutNode(outOptions.id, outOptions.name, outOptions.broker || broker.id, outOptions.topic, outOptions);
|
||||||
const helper = buildNode("helper", "helper.node", "helper_node", {});
|
const helper = buildNode("helper", "helper.node", "helper_node", {});
|
||||||
|
const catchNode = buildNode("catch", "catch.node", "catch_node", {"scope": ["mqtt.in"]}, ["helper.node"]);
|
||||||
return {
|
return {
|
||||||
nodes: {
|
nodes: {
|
||||||
[broker.name]: broker,
|
[broker.name]: broker,
|
||||||
[inNode.name]: inNode,
|
[inNode.name]: inNode,
|
||||||
[outNode.name]: outNode,
|
[outNode.name]: outNode,
|
||||||
[helper.name]: helper,
|
[helper.name]: helper,
|
||||||
|
[catchNode.name]: catchNode,
|
||||||
},
|
},
|
||||||
flow: [broker, inNode, outNode, helper]
|
flow: [broker, inNode, outNode, helper, catchNode]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user