diff --git a/node-red-node-wot/package-lock.json b/node-red-node-wot/package-lock.json index 61d5608..37cb19a 100644 --- a/node-red-node-wot/package-lock.json +++ b/node-red-node-wot/package-lock.json @@ -1,12 +1,12 @@ { "name": "@thingweb/node-red-node-wot", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@thingweb/node-red-node-wot", - "version": "1.0.0", + "version": "1.0.1", "license": "MIT", "dependencies": { "@node-wot/binding-coap": "0.8.12", @@ -18,7 +18,7 @@ "@node-wot/core": "0.8.12" }, "devDependencies": { - "@types/chai": "^4.3.11", + "@types/chai": "^4.3.12", "@types/chai-as-promised": "^7.1.8", "@types/mocha": "^10.0.6", "@types/node-red": "^1.3.4", diff --git a/node-red-node-wot/package.json b/node-red-node-wot/package.json index 68cad38..d94d03e 100644 --- a/node-red-node-wot/package.json +++ b/node-red-node-wot/package.json @@ -25,6 +25,7 @@ "wot-property": "dist/wot-property.js", "wot-action": "dist/wot-action.js", "wot-event": "dist/wot-event.js", + "wot-update-td": "dist/wot-update-td.js", "wot-server-config": "dist/wot-server-config.js", "wot-thing-config": "dist/wot-thing-config.js", "wot-server-end": "dist/wot-server-end.js", @@ -33,7 +34,7 @@ "wot-server-event": "dist/wot-server-event.js", "wot-server-td": "dist/wot-server-td.js" }, - "version":">=2.0.0" + "version": ">=2.0.0" }, "scripts": { "build": "npm run copy:src2dist && tsc", @@ -52,7 +53,7 @@ "@node-wot/core": "0.8.12" }, "devDependencies": { - "@types/chai": "^4.3.11", + "@types/chai": "^4.3.12", "@types/chai-as-promised": "^7.1.8", "@types/mocha": "^10.0.6", "@types/node-red": "^1.3.4", diff --git a/node-red-node-wot/src/wot-action.js b/node-red-node-wot/src/wot-action.js index 0714161..69ed103 100644 --- a/node-red-node-wot/src/wot-action.js +++ b/node-red-node-wot/src/wot-action.js @@ -4,6 +4,9 @@ module.exports = function (RED) { function invokeActionNode(config) { RED.nodes.createNode(this, config) let node = this + let consumedThing + + this.status({}) if (!config.thing) { this.status({ fill: "red", shape: "dot", text: "Error: Thing undefined" }) @@ -17,15 +20,26 @@ module.exports = function (RED) { return } + const thingNode = RED.nodes.getNode(config.thing) + thingNode.addUpdateTDListener(async (_consumedThing) => { + consumedThing = _consumedThing + }) + this.on("input", function (msg, send, done) { - RED.nodes.getNode(config.thing).consumedThing.then((consumedThing) => { - const uriVariables = config.uriVariables ? JSON.parse(config.uriVariables) : undefined - consumedThing - .invokeAction(config.action, msg.payload, { - uriVariables: uriVariables, - }) - .then(async (resp) => { - const payload = resp ? await resp.value() : "" + if (!consumedThing) { + node.error("[error] consumedThing is not defined.") + done("consumedThing is not defined.") + return + } + const uriVariables = config.uriVariables ? JSON.parse(config.uriVariables) : undefined + consumedThing + .invokeAction(config.action, msg.payload, { + uriVariables: uriVariables, + }) + .then(async (resp) => { + let payload + try { + payload = await resp.value() node.send({ payload: payload, topic: config.topic }) node.status({ fill: "green", @@ -33,17 +47,20 @@ module.exports = function (RED) { text: "invoked", }) done() + } catch (err) { + console.error(`[error] failed to get return value. err: `, err) + done(`[error] failed to get return value. err: ${err.toString()}`) + } + }) + .catch((err) => { + node.warn(err) + node.status({ + fill: "red", + shape: "ring", + text: err.message, }) - .catch((err) => { - node.warn(err) - node.status({ - fill: "red", - shape: "ring", - text: err.message, - }) - done(err) - }) - }) + done(err) + }) }) this.on("close", function (removed, done) { diff --git a/node-red-node-wot/src/wot-event.js b/node-red-node-wot/src/wot-event.js index 89a0f53..2900eca 100644 --- a/node-red-node-wot/src/wot-event.js +++ b/node-red-node-wot/src/wot-event.js @@ -4,8 +4,9 @@ module.exports = function (RED) { function subscribeEventNode(config) { RED.nodes.createNode(this, config) let node = this + let consumedThing + let subscription - this.subscription = undefined this.status({}) if (!config.thing) { @@ -16,95 +17,84 @@ module.exports = function (RED) { return } - RED.nodes - .getNode(config.thing) - .consumedThing.then(async (consumedThing) => { - let subscription - // Repeat until event subscription succeeds. - try { - while (true) { - subscription = await consumedThing - .subscribeEvent( - config.event, - async (resp) => { - if (resp) { - let payload - try { - payload = await resp.value() - } catch (err) { - node.error(`[error] failed to get event. err: ${err.toString()}`) - console.error(`[error] failed to get event. err: `, err) - } - node.send({ payload, topic: config.topic }) + const thingNode = RED.nodes.getNode(config.thing) + thingNode.addUpdateTDListener(async (_consumedThing) => { + if (subscription) { + // Stop if already subscribed + await subscription.stop() + } + consumedThing = _consumedThing + // Repeat until event subscription succeeds. + try { + while (true) { + subscription = await consumedThing + .subscribeEvent( + config.event, + async (resp) => { + if (resp) { + let payload + try { + payload = await resp.value() + } catch (err) { + node.error(`[error] failed to get event. err: ${err.toString()}`) + console.error(`[error] failed to get event. err: `, err) } - node.status({ - fill: "green", - shape: "dot", - text: "Subscribed", - }) - }, - (err) => { - console.error("[error] subscribe events.", err) - node.error(`[error] subscribe events. err: ${err.toString()}`) - node.status({ - fill: "red", - shape: "ring", - text: "Subscription error", - }) - }, - () => { - console.error("[warn] Subscription ended.") - node.warn("[warn] Subscription ended.") - node.status({}) - node.subscription = undefined + node.send({ payload, topic: config.topic }) } - ) - .catch((err) => { - console.warn("[warn] event subscribe error. try again. error: " + err) - }) - if (subscription) { - break - } - await (() => { - return new Promise((resolve) => { - setTimeout(() => { - resolve() - }, 500) - }) - })() + node.status({ + fill: "green", + shape: "dot", + text: "Subscribed", + }) + }, + (err) => { + console.error("[error] subscribe events.", err) + node.error(`[error] subscribe events. err: ${err.toString()}`) + node.status({ + fill: "red", + shape: "ring", + text: "Subscription error", + }) + }, + () => { + console.error("[warn] Subscription ended.") + node.warn("[warn] Subscription ended.") + node.status({}) + subscription = undefined + } + ) + .catch((err) => { + console.warn("[warn] event subscribe error. try again. error: " + err) + }) + if (subscription) { + break } - } catch (err) { - node.status({ - fill: "red", - shape: "ring", - text: "Subscription error", + await new Promise((resolve) => { + setTimeout(resolve, 500) }) - node.error(`[error] failed to subscribe events. error: ${err.toString()}`) } - node.subscription = subscription - - if (node.subscription) { - node.status({ - fill: "green", - shape: "dot", - text: "Subscribed", - }) - } - }) - .catch((err) => { + } catch (err) { node.status({ fill: "red", shape: "ring", text: "Subscription error", }) - node.error(`[error] Failed to create consumed thing for enents. err: ${err.toString()}`) - }) + node.error(`[error] failed to subscribe events. error: ${err.toString()}`) + } + + if (subscription) { + node.status({ + fill: "green", + shape: "dot", + text: "Subscribed", + }) + } + }) - this.on("close", function (removed, done) { - if (removed) { - // This node has been deleted - } else { - // This node is being restarted + this.on("close", async function (removed, done) { + if (subscription) { + // Stop if already subscribed + await subscription.stop() } done() }) diff --git a/node-red-node-wot/src/wot-property.js b/node-red-node-wot/src/wot-property.js index e35097d..7acda80 100644 --- a/node-red-node-wot/src/wot-property.js +++ b/node-red-node-wot/src/wot-property.js @@ -5,6 +5,7 @@ module.exports = function (RED) { RED.nodes.createNode(this, config) let node = this let consumedThing + let subscription this.status({}) @@ -20,16 +21,20 @@ module.exports = function (RED) { return } - RED.nodes.getNode(config.thing).consumedThing.then(async (thing) => { - consumedThing = thing + const thingNode = RED.nodes.getNode(config.thing) + thingNode.addUpdateTDListener(async (_consumedThing) => { + if (subscription) { + // Stop if already subscribed + await subscription.stop() + } + consumedThing = _consumedThing if (config.observe === false) { return } // Repeat until observeProperty succeeds. - let ob while (true) { try { - ob = await consumedThing.observeProperty( + subscription = await consumedThing.observeProperty( config.property, async (resp) => { let payload @@ -59,7 +64,7 @@ module.exports = function (RED) { text: "Observe error", }) } - if (ob) { + if (subscription) { node.status({ fill: "green", shape: "dot", @@ -113,11 +118,10 @@ module.exports = function (RED) { }) }) - node.on("close", function (removed, done) { - if (removed) { - // This node has been deleted - } else { - // This node is being restarted + node.on("close", async function (removed, done) { + if (subscription) { + // Stop if already subscribed + await subscription.stop() } done() }) @@ -127,6 +131,7 @@ module.exports = function (RED) { function writePropertyNode(config) { RED.nodes.createNode(this, config) let node = this + let consumedThing this.status({}) @@ -142,32 +147,49 @@ module.exports = function (RED) { return } - RED.nodes.getNode(config.thing).consumedThing.then((consumedThing) => { - node.on("input", function (msg, send, done) { - const uriVariables = config.uriVariables ? JSON.parse(config.uriVariables) : undefined - consumedThing - .writeProperty(config.property, msg.payload, { - uriVariables: uriVariables, - }) - .then((resp) => { - if (resp) node.send({ payload: resp, topic: config.topic }) - node.status({ - fill: "green", - shape: "dot", - text: "connected", - }) - done() + const thingNode = RED.nodes.getNode(config.thing) + thingNode.addUpdateTDListener(async (_consumedThing) => { + consumedThing = _consumedThing + }) + + node.on("input", function (msg, send, done) { + if (!consumedThing) { + node.error("[error] consumedThing is not defined.") + done("consumedThing is not defined.") + return + } + const uriVariables = config.uriVariables ? JSON.parse(config.uriVariables) : undefined + consumedThing + .writeProperty(config.property, msg.payload, { + uriVariables: uriVariables, + }) + .then((resp) => { + if (resp) node.send({ payload: resp, topic: config.topic }) + node.status({ + fill: "green", + shape: "dot", + text: "connected", }) - .catch((err) => { - node.warn(err) - node.status({ - fill: "red", - shape: "ring", - text: err.message, - }) - done(err) + done() + }) + .catch((err) => { + node.warn(err) + node.status({ + fill: "red", + shape: "ring", + text: err.message, }) - }) + done(err) + }) + }) + + this.on("close", function (removed, done) { + if (removed) { + // This node has been deleted + } else { + // This node is being restarted + } + done() }) } RED.nodes.registerType("write-property", writePropertyNode) diff --git a/node-red-node-wot/src/wot-server-td.ts b/node-red-node-wot/src/wot-server-td.ts index 3579fda..47002ff 100644 --- a/node-red-node-wot/src/wot-server-td.ts +++ b/node-red-node-wot/src/wot-server-td.ts @@ -5,8 +5,6 @@ module.exports = function (RED) { RED.nodes.createNode(this, config) const node = this this.status({ fill: "red", shape: "dot", text: "not prepared" }) - console.log("*** wot server td node: ", node) - console.log("*** wot server td config: ", config) node.setServientStatus = (running: boolean) => { if (running) { diff --git a/node-red-node-wot/src/wot-thing.js b/node-red-node-wot/src/wot-thing.js index 3e759cb..fe653ab 100644 --- a/node-red-node-wot/src/wot-thing.js +++ b/node-red-node-wot/src/wot-thing.js @@ -13,16 +13,22 @@ module.exports = function (RED) { function consumedThingNode(config) { RED.nodes.createNode(this, config) const node = this + let consumedThing + let tdListeners = [] - this.tdLink = config.tdLink - this.td = JSON.parse(config.td) + this.addUpdateTDListener = (listener) => { + tdListeners.push(listener) + if (consumedThing) { + listener(consumedThing) + } + } - this.consumedThing = new Promise((resolve, reject) => { + this.createConsumedThing = async (td) => { let servient = new Servient() if (config.basicAuth) { servient.addCredentials({ - [this.td.id]: { username: config.username.trim(), password: config.password }, + [td.id]: { username: config.username.trim(), password: config.password }, }) } @@ -47,16 +53,21 @@ module.exports = function (RED) { servient.addClientFactory(new ModbusClientFactory()) } - servient - .start() - .then((thingFactory) => { - let consumedThing = thingFactory.consume(this.td) - resolve(consumedThing) - }) - .catch((err) => { - node.error(`[error] failed to start servient. err: ${err.toString()}`) - reject(err) - }) + const thingFactory = await servient.start() + consumedThing = await thingFactory.consume(td) + tdListeners.forEach((listener) => { + listener(consumedThing) + }) + } + + const td = JSON.parse(config.td) + this.createConsumedThing(td).catch((err) => { + node.error(`[error] failed to start servient. err: ${err.toString()}`) + }) + + this.on("close", function (removed, done) { + tdListeners = [] + done() }) } RED.nodes.registerType("consumed-thing", consumedThingNode) diff --git a/node-red-node-wot/src/wot-update-td.html b/node-red-node-wot/src/wot-update-td.html new file mode 100644 index 0000000..ae04e7d --- /dev/null +++ b/node-red-node-wot/src/wot-update-td.html @@ -0,0 +1,58 @@ + + + + + diff --git a/node-red-node-wot/src/wot-update-td.js b/node-red-node-wot/src/wot-update-td.js new file mode 100644 index 0000000..e978173 --- /dev/null +++ b/node-red-node-wot/src/wot-update-td.js @@ -0,0 +1,51 @@ +"use strict" + +module.exports = function (RED) { + function UpdateTDNode(config) { + RED.nodes.createNode(this, config) + let node = this + + this.status({}) + + if (!config.thing) { + this.status({ fill: "red", shape: "dot", text: "Error: Thing undefined" }) + return + } else if (!config.tdSource) { + this.status({ + fill: "red", + shape: "dot", + text: "Error: Choose a td source", + }) + return + } + + const thingNode = RED.nodes.getNode(config.thing) + + this.on("input", async function (msg, send, done) { + let td + if (config.tdSource && config.tdSourceType) { + try { + td = await RED.util.evaluateNodeProperty(config.tdSource, config.tdSourceType, node, msg) + } catch (err) { + return done("cannot evaluate td source") + } + } + try { + await thingNode.createConsumedThing(td) + done() + } catch (err) { + done(err) + } + }) + + this.on("close", function (removed, done) { + if (removed) { + // This node has been deleted + } else { + // This node is being restarted + } + done() + }) + } + RED.nodes.registerType("update-td", UpdateTDNode) +} diff --git a/node-red-node-wot/test/server-td-test.ts b/node-red-node-wot/test/server-td-test.ts new file mode 100644 index 0000000..5062d56 --- /dev/null +++ b/node-red-node-wot/test/server-td-test.ts @@ -0,0 +1,125 @@ +/** + * test for server-td + */ +import "mocha" +import * as chai from "chai" +import chaiAsPromised from "chai-as-promised" +import helper from "node-red-node-test-helper" +import { startFlow, endFlow, getNodeAfterStartFlow } from "./util" + +helper.init(require.resolve("node-red")) + +chai.use(chaiAsPromised) +const assert = chai.assert + +/* + Flow Summary + [Server-side] + 1a. wot-server-event:id.serverevent01 (id.serverconfig01, id.thingconfig01') + 1b. wot-server-td:id.servertd01 (id.serverconfig01, id.thingconfig01') + 2b. helper:id.gettdhelper01 + */ +const targetFlow = [ + // Server-side + { + id: "id.serverevent01", + type: "wot-server-event", + name: "", + eventName: "testEvent", + eventDescription: "test event", + eventDataType: "string", + inParams_eventValueType: "msg", + inParams_eventValueConstValue: "payload", + woTServerConfig: "id.serverconfig01", + woTThingConfig: "id.thingconfig01", + wires: [], + }, + { + id: "id.servertd01", + type: "wot-server-td", + name: "", + outParams1_tdType: "msg", + outParams1_tdConstValue: "payload", + woTServerConfig: "id.serverconfig01", + woTThingConfig: "id.thingconfig01", + outputTDAfterServerStartFlag: true, + wires: [["id.gettdhelper01"]], + }, + { + id: "id.serverconfig01", + type: "wot-server-config", + name: "httpserver", + bindingType: "http", + bindingConfigType: "json", + bindingConfigConstValue: '{"port":8383}', + }, + { + id: "id.thingconfig01", + type: "wot-thing-config", + name: "thing01", + description: "thing01 for test", + }, + { id: "id.gettdhelper01", type: "helper" }, +] + +let eventContent = "test-content" + +describe("Tests for Server TD", function () { + this.timeout(15 * 1000) + before(async function () { + await startFlow(targetFlow, helper, 0) + }) + + after(async function () { + await endFlow("id.serverconfig01", helper) + }) + + beforeEach(function (done) { + done() + }) + + afterEach(function (done) { + done() + }) + + it("get td after server start", function (done) { + getNodeAfterStartFlow("id.gettdhelper01", helper).then((helperNode) => { + helperNode.removeAllListeners("input") + helperNode.on("input", function (msg) { + try { + //@ts-ignore + assert.equal(msg.payload?.title, "thing01") + done() + } catch (err) { + done(err) + } + }) + }) + }) + + it("get td by input", function (done) { + // wait for servient start + new Promise((resolve, reject) => { + setTimeout(resolve, 2000) + }).then(() => { + const helperNode = helper.getNode("id.gettdhelper01") + let sentFlg = false + helperNode.removeAllListeners("input") + helperNode.on("input", function (msg) { + try { + // check after send trigger or not + if (sentFlg) { + //@ts-ignore + assert.equal(msg.payload?.title, "thing01") + done() + } + } catch (err) { + done(err) + } + }) + const serverTDNode = helper.getNode("id.servertd01") + serverTDNode.receive({}) + sentFlg = true + }) + }) +}) diff --git a/node-red-node-wot/test/update-td-test.ts b/node-red-node-wot/test/update-td-test.ts new file mode 100644 index 0000000..001d998 --- /dev/null +++ b/node-red-node-wot/test/update-td-test.ts @@ -0,0 +1,226 @@ +/** + * test for update-td + */ +import "mocha" +import * as chai from "chai" +import chaiAsPromised from "chai-as-promised" +import helper from "node-red-node-test-helper" +import { startFlow, endFlow } from "./util" + +helper.init(require.resolve("node-red")) + +chai.use(chaiAsPromised) +const assert = chai.assert + +/* + Flow Summary + [Server-side] + 1a. wot-server-event:id.serverevent01 (id.serverconfig01, id.thingconfig01') + 1b. wot-server-event:id.serverevent02 (id.serverconfig02, id.thingconfig01') + [Client-side] + 1a. subscribe-event:id.subscribeevent01 (id.consumedthing01) + 2a. helper:id.subscribeeventhelper01 + 1b. update-td:id.updatetd01 (id.consumedthing01) + */ +const targetFlow = [ + // Server-side + { + id: "id.serverevent01", + type: "wot-server-event", + name: "", + eventName: "testEvent", + eventDescription: "test event", + eventDataType: "string", + inParams_eventValueType: "msg", + inParams_eventValueConstValue: "payload", + woTServerConfig: "id.serverconfig01", + woTThingConfig: "id.thingconfig01", + wires: [], + }, + { + id: "id.serverconfig01", + type: "wot-server-config", + name: "httpserver", + bindingType: "http", + bindingConfigType: "json", + bindingConfigConstValue: '{"port":8181}', + }, + { + id: "id.thingconfig01", + type: "wot-thing-config", + name: "thing01", + description: "thing01 for test", + }, + { + id: "id.serverevent02", + type: "wot-server-event", + name: "", + eventName: "testEvent", + eventDescription: "test event", + eventDataType: "string", + inParams_eventValueType: "msg", + inParams_eventValueConstValue: "payload", + woTServerConfig: "id.serverconfig02", + woTThingConfig: "id.thingconfig01", + wires: [], + }, + { + id: "id.serverconfig02", + type: "wot-server-config", + name: "httpserver", + bindingType: "http", + bindingConfigType: "json", + bindingConfigConstValue: '{"port":8282}', + }, + // Client-side + { + id: "id.subscribeevent01", + type: "subscribe-event", + name: "", + topic: "", + thing: "id.consumedthing01", + event: "testEvent", + uriVariables: "", + wires: [["id.subscribeeventhelper01"]], + }, + { id: "id.subscribeeventhelper01", type: "helper" }, + { + id: "id.consumedthing01", + type: "consumed-thing", + tdLink: "", + td: JSON.stringify({ + "@context": [ + "https://www.w3.org/2019/wot/td/v1", + "https://www.w3.org/2022/wot/td/v1.1", + { "@language": "en" }, + ], + "@type": "Thing", + title: "thing01", + securityDefinitions: { nosec: { scheme: "nosec" } }, + security: ["nosec"], + events: { + testEvent: { + description: "", + data: { type: "string" }, + forms: [ + { + href: "http://localhost:8181/thing01/events/testEvent", + contentType: "application/json", + subprotocol: "longpoll", + op: ["subscribeevent", "unsubscribeevent"], + }, + { + href: "http://localhost:8181/thing01/events/testEvent", + contentType: "application/cbor", + subprotocol: "longpoll", + op: ["subscribeevent", "unsubscribeevent"], + }, + ], + }, + }, + id: "urn:uuid:cf950521-8eaf-4e1c-9277-758930e47246", + description: "", + }), + http: true, + ws: false, + coap: false, + mqtt: false, + opcua: false, + modbus: false, + basicAuth: false, + username: "", + password: "", + }, + { + id: "id.updatetd01", + type: "update-td", + name: "", + thing: "id.consumedthing01", + tdSourceType: "msg", + tdSource: "payload", + wires: [], + }, +] + +describe("Tests for Update TD", function () { + this.timeout(15 * 1000) + before(async function () { + await startFlow(targetFlow, helper) + }) + + after(async function () { + await endFlow("id.serverconfig01", helper) + }) + + beforeEach(function (done) { + done() + }) + + afterEach(function (done) { + done() + }) + + it("update td", function (done) { + const clientHelperNode = helper.getNode("id.subscribeeventhelper01") + clientHelperNode.removeAllListeners("input") + let expectedEvent + clientHelperNode.on("input", function (msg) { + try { + assert.equal(msg.payload, expectedEvent) + if (expectedEvent === "event from server02") { + done() + } + } catch (err) { + done(err) + } + }) + const serverEventNode01 = helper.getNode("id.serverevent01") + const serverEventNode02 = helper.getNode("id.serverevent02") + expectedEvent = "event from server01" + serverEventNode01.receive({ payload: "event from server01" }) + serverEventNode02.receive({ payload: "event from server02" }) + new Promise((resolve) => setTimeout(resolve, 500)).then(() => { + const updateTDNode = helper.getNode("id.updatetd01") + updateTDNode.receive({ + payload: { + "@context": [ + "https://www.w3.org/2019/wot/td/v1", + "https://www.w3.org/2022/wot/td/v1.1", + { "@language": "en" }, + ], + "@type": "Thing", + title: "thing01", + securityDefinitions: { nosec: { scheme: "nosec" } }, + security: ["nosec"], + events: { + testEvent: { + description: "", + data: { type: "string" }, + forms: [ + { + href: "http://localhost:8282/thing01/events/testEvent", + contentType: "application/json", + subprotocol: "longpoll", + op: ["subscribeevent", "unsubscribeevent"], + }, + { + href: "http://localhost:8282/thing01/events/testEvent", + contentType: "application/cbor", + subprotocol: "longpoll", + op: ["subscribeevent", "unsubscribeevent"], + }, + ], + }, + }, + id: "urn:uuid:cf950521-8eaf-4e1c-9277-758930e47246", + description: "", + }, + }) + new Promise((resolve) => setTimeout(resolve, 500)).then(() => { + expectedEvent = "event from server02" + serverEventNode01.receive({ payload: "event from server01" }) + serverEventNode02.receive({ payload: "event from server02" }) + }) + }) + }) +}) diff --git a/node-red-node-wot/test/util.ts b/node-red-node-wot/test/util.ts index 09a40f6..0170b6c 100644 --- a/node-red-node-wot/test/util.ts +++ b/node-red-node-wot/test/util.ts @@ -6,10 +6,12 @@ const serverPropertyNode = require("../src/wot-server-property.ts") const serverActionNode = require("../src/wot-server-action.ts") const serverEventNode = require("../src/wot-server-event.ts") const serverEndNode = require("../src/wot-server-end.ts") +const serverTDNode = require("../src/wot-server-td.ts") const thingConfigNode = require("../src/wot-thing.js") const propertyNode = require("../src/wot-property.js") const actionNode = require("../src/wot-action.js") const eventNode = require("../src/wot-event.js") +const updateTDNode = require("../src/wot-update-td.js") const USE_NODES = [ serverConfigNode, @@ -18,28 +20,30 @@ const USE_NODES = [ serverActionNode, serverEventNode, serverEndNode, + serverTDNode, thingConfigNode, propertyNode, actionNode, eventNode, + updateTDNode, ] -const launchFlow = async (flow: any[], helper) => { +const launchFlow = async (flow: any[], helper, waitForServientStart = 2000) => { return new Promise((resolve, reject) => { helper.load(USE_NODES, flow, function () { // Wait for the servient to start. setTimeout(function () { resolve() - }, 2000) + }, waitForServientStart) }) }) } -export const startFlow = async (targetFlow, helper) => { +export const startFlow = async (targetFlow, helper, waitForServientStart = 2000) => { return new Promise((resolve, reject) => { helper.startServer(async function () { try { - await launchFlow(targetFlow, helper) + await launchFlow(targetFlow, helper, waitForServientStart) resolve() } catch (err) { reject(err) @@ -58,3 +62,17 @@ export const endFlow = async (id: string, helper) => { } }) } + +export const getNodeAfterStartFlow = async (id: string, helper, wait = 50, maxCount = 50) => { + for (let i = 0; i < maxCount; i++) { + let node = helper.getNode(id) + if (node) { + return node + } else { + await new Promise((resolve, reject) => { + setTimeout(resolve, wait) + }) + } + } + throw new Error("timeout for getting node") +}