From 1b34519f2bdd7c870c4cca62907c2db2187672c2 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 30 Sep 2024 10:16:08 +0300 Subject: [PATCH 01/40] Updated unsupported Node.js dependencies from version 16.20.2 to 18.20.4 LTS --- msa/js-executor/pom.xml | 2 +- msa/web-ui/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index e123790066..c16cf662ec 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -71,7 +71,7 @@ install-node-and-yarn - v16.20.2 + v18.20.4 v1.22.17 diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index f2e626c7c1..0625dee9e7 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -80,7 +80,7 @@ install-node-and-yarn - v16.20.2 + v18.20.4 v1.22.17 From 4d2ac77c4adbab62f69fe8e394af4980cf43c032 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Wed, 16 Oct 2024 10:17:58 +0300 Subject: [PATCH 02/40] fixed upgrade --- .../engine/metadata/TbGetTelemetryNode.java | 37 ++++++++++++++----- .../metadata/TbGetTelemetryNodeTest.java | 32 ++++++++++++++++ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java index 2b5190563d..3a6f1dd9c4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java @@ -52,7 +52,7 @@ import java.util.stream.Collectors; @RuleNode(type = ComponentType.ENRICHMENT, name = "originator telemetry", configClazz = TbGetTelemetryNodeConfiguration.class, - version = 1, + version = 2, nodeDescription = "Adds message originator telemetry for selected time range into message metadata", nodeDetails = "Useful when you need to get telemetry data set from the message originator for a specific time range " + "instead of fetching just the latest telemetry or if you need to get the closest telemetry to the fetch interval start or end. " + @@ -232,21 +232,21 @@ public class TbGetTelemetryNode implements TbNode { public TbPair upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException { boolean hasChanges = false; switch (fromVersion) { - case 0 -> { + case 0: { if (oldConfiguration.hasNonNull("fetchMode")) { String fetchMode = oldConfiguration.get("fetchMode").asText(); switch (fetchMode) { - case "FIRST": + case "FIRST" -> { ((ObjectNode) oldConfiguration).put("orderBy", Direction.ASC.name()); ((ObjectNode) oldConfiguration).put("aggregation", Aggregation.NONE.name()); hasChanges = true; - break; - case "LAST": + } + case "LAST" -> { ((ObjectNode) oldConfiguration).put("orderBy", Direction.DESC.name()); ((ObjectNode) oldConfiguration).put("aggregation", Aggregation.NONE.name()); hasChanges = true; - break; - case "ALL": + } + case "ALL" -> { if (oldConfiguration.has("orderBy") && (oldConfiguration.get("orderBy").isNull() || oldConfiguration.get("orderBy").asText().isEmpty())) { ((ObjectNode) oldConfiguration).put("orderBy", Direction.ASC.name()); @@ -257,16 +257,33 @@ public class TbGetTelemetryNode implements TbNode { ((ObjectNode) oldConfiguration).put("aggregation", Aggregation.NONE.name()); hasChanges = true; } - break; - default: + } + default -> { ((ObjectNode) oldConfiguration).put("fetchMode", FetchMode.LAST.name()); ((ObjectNode) oldConfiguration).put("orderBy", Direction.DESC.name()); ((ObjectNode) oldConfiguration).put("aggregation", Aggregation.NONE.name()); hasChanges = true; - break; + } } } } + case 1: { + if (!oldConfiguration.hasNonNull("limit")) { + ((ObjectNode) oldConfiguration).put("limit", 1000); + hasChanges = true; + } + if (oldConfiguration.has("fetchMode") && oldConfiguration.get("fetchMode").asText().equals("ALL")) { + if (!oldConfiguration.hasNonNull("aggregation")) { + ((ObjectNode) oldConfiguration).put("aggregation", Aggregation.NONE.name()); + hasChanges = true; + } + if (!oldConfiguration.hasNonNull("orderBy")) { + ((ObjectNode) oldConfiguration).put("orderBy", Direction.ASC.name()); + hasChanges = true; + } + } + break; + } } return new TbPair<>(hasChanges, oldConfiguration); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeTest.java index f2d4a41fbc..87f273df93 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeTest.java @@ -637,6 +637,38 @@ public class TbGetTelemetryNodeTest extends AbstractRuleNodeUpgradeTest { "endInterval": 1, "endIntervalTimeUnit": "MINUTES" } + """), + // config for version 0 (fetchMode is 'ALL' and limit, aggregation and orderBy do not exist) + Arguments.of(0, + """ + { + "latestTsKeyNames": ["key"], + "fetchMode": "ALL", + "useMetadataIntervalPatterns": false, + "startIntervalPattern": "", + "endIntervalPattern": "", + "startInterval": 2, + "startIntervalTimeUnit": "MINUTES", + "endInterval": 1, + "endIntervalTimeUnit": "MINUTES" + } + """, + true, + """ + { + "latestTsKeyNames": ["key"], + "aggregation": "NONE", + "fetchMode": "ALL", + "orderBy": "ASC", + "limit": 1000, + "useMetadataIntervalPatterns": false, + "startIntervalPattern": "", + "endIntervalPattern": "", + "startInterval": 2, + "startIntervalTimeUnit": "MINUTES", + "endInterval": 1, + "endIntervalTimeUnit": "MINUTES" + } """) ); } From 4bd0697ea67ed31b4c52ff5a930f9c76f778c8ac Mon Sep 17 00:00:00 2001 From: mpetrov Date: Thu, 17 Oct 2024 18:34:41 +0300 Subject: [PATCH 03/40] Fixed remote shell request spam on exit --- .../main/data/json/system/widget_types/rpc_remote_shell.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_types/rpc_remote_shell.json b/application/src/main/data/json/system/widget_types/rpc_remote_shell.json index 91d2a64788..47f0472f2d 100644 --- a/application/src/main/data/json/system/widget_types/rpc_remote_shell.json +++ b/application/src/main/data/json/system/widget_types/rpc_remote_shell.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "
", "templateCss": ".cmd .cursor.blink {\n -webkit-animation-name: terminal-underline;\n -moz-animation-name: terminal-underline;\n -ms-animation-name: terminal-underline;\n animation-name: terminal-underline;\n}\n.terminal .inverted, .cmd .inverted {\n border-bottom-color: #aaa;\n}\n", - "controllerScript": "var requestTimeout = 500;\nvar commandStatusPollingInterval = 200;\n\nvar welcome = 'Welcome to ThingsBoard RPC remote shell.\\n';\n\nvar terminal, rpcEnabled, simulated, deviceName, cwd;\nvar commandExecuting = false;\n\nself.onInit = function() {\n var subscription = self.ctx.defaultSubscription;\n rpcEnabled = subscription.rpcEnabled;\n if (subscription.targetEntityName && subscription.targetEntityName.length) {\n deviceName = subscription.targetEntityName;\n } else {\n deviceName = 'Simulated';\n simulated = true;\n }\n if (self.ctx.settings.requestTimeout) {\n requestTimeout = self.ctx.settings.requestTimeout;\n }\n\n terminal = $('#device-terminal', self.ctx.$container).terminal(\n function (command) {\n if (command && command.trim().length) {\n try {\n if (simulated) {\n this.echo(command);\n } else {\n sendCommand(this, command);\n }\n } catch(e) {\n this.error(e + '');\n }\n } else {\n this.echo('');\n }\n }, {\n greetings: false,\n enabled: rpcEnabled,\n prompt: rpcEnabled ? currentPrompt : '',\n name: 'shell',\n pauseEvents: false,\n keydown: function (e, term) {\n if ((e.which == 67 || e.which == 68) && e.ctrlKey) { // CTRL+C || CTRL+D\n if (commandExecuting) {\n terminateCommand(term);\n return false;\n }\n }\n },\n onInit: initTerm\n }\n );\n};\n\nfunction initTerm(terminal) {\n terminal.echo(welcome);\n if (!rpcEnabled) {\n terminal.error('Target device is not set!\\n');\n } else {\n terminal.echo('Current target device for RPC terminal: [[b;#fff;]' + deviceName + ']\\n');\n if (!simulated) {\n terminal.pause();\n getTermInfo(terminal, function (remoteTermInfo) {\n if (remoteTermInfo) {\n terminal.echo('Remote platform info:');\n if (remoteTermInfo.platform) {\n terminal.echo('OS: [[b;#fff;]' + remoteTermInfo.platform + ']');\n } else {\n terminal.echo('OS: [[;#f00;]Unknown]');\n }\n if (remoteTermInfo.release) {\n terminal.echo('OS release: [[b;#fff;]' + remoteTermInfo.release + ']');\n } else {\n terminal.echo('OS release: [[;#f00;]Unknown]');\n }\n terminal.echo('\\r');\n } else {\n terminal.echo('[[;#f00;]Unable to get remote platform info.\\nDevice is not responding.]\\n');\n }\n terminal.resume();\n });\n }\n }\n}\n\nfunction currentPrompt(callback) {\n if (cwd) {\n callback('[[b;#2196f3;]' + deviceName + ']: [[b;#8bc34a;]' + cwd + ']> ');\n } else {\n callback('[[b;#8bc34a;]' + deviceName + ']> ');\n }\n}\n\nfunction getTermInfo(terminal, callback) {\n self.ctx.controlApi.sendTwoWayCommand('getTermInfo', null, requestTimeout).subscribe(\n function(response) {\n let termInfo;\n if (typeof response === 'string') {\n try {\n termInfo = JSON.parse(response);\n } catch (e) {\n terminal.error('Error parsing response: ' + e);\n callback(null);\n return;\n }\n } else {\n termInfo = response;\n }\n if (termInfo && termInfo.cwd) {\n cwd = termInfo.cwd;\n }\n if (callback) {\n callback(termInfo);\n }\n },\n function() {\n if (callback) {\n callback(null);\n }\n }\n );\n}\n\nfunction sendCommand(terminal, command) {\n terminal.pause();\n var sendCommandRequest = {\n command: command,\n cwd: cwd\n };\n self.ctx.controlApi.sendTwoWayCommand('sendCommand', sendCommandRequest, requestTimeout).subscribe(\n function (responseBody) {\n if (responseBody && responseBody.ok) {\n commandExecuting = true;\n setTimeout(pollCommandStatus.bind(null, terminal), commandStatusPollingInterval);\n } else {\n var error = responseBody ? responseBody.error : 'Unhandled error.';\n terminal.error(error);\n terminal.resume();\n }\n },\n function () {\n onRpcError(terminal);\n }\n );\n}\n\nfunction terminateCommand(terminal) {\n self.ctx.controlApi.sendTwoWayCommand('terminateCommand', null, requestTimeout).subscribe(\n function (responseBody) {\n if (!responseBody.ok) {\n commandExecuting = false;\n terminal.error(responseBody.error);\n terminal.resume();\n }\n },\n function () {\n onRpcError(terminal);\n }\n );\n}\n\nfunction onRpcError(terminal) {\n var errorText = self.ctx.defaultSubscription.rpcErrorText;\n terminal.error(errorText);\n terminal.resume();\n}\n\nfunction pollCommandStatus(terminal) {\n self.ctx.controlApi.sendTwoWayCommand('getCommandStatus', null, requestTimeout).subscribe(\n function (commandStatusResponse) {\n for (var i = 0; i < commandStatusResponse.data.length; i++) {\n var dataElement = commandStatusResponse.data[i];\n if (dataElement.stdout) {\n terminal.echo(dataElement.stdout);\n }\n if (dataElement.stderr) {\n terminal.error(dataElement.stderr);\n }\n }\n if (commandStatusResponse.done) {\n commandExecuting = false;\n cwd = commandStatusResponse.cwd;\n terminal.resume();\n } else {\n var interval = commandStatusPollingInterval;\n if (!commandStatusResponse.data.length) {\n interval *= 5;\n }\n setTimeout(pollCommandStatus.bind(null, terminal), interval);\n }\n },\n function () {\n commandExecuting = false;\n onRpcError(terminal);\n }\n );\n}\n\nself.onResize = function () {\n if (terminal) {\n terminal.resize(self.ctx.width, self.ctx.height);\n }\n};\n\nself.onDestroy = function() {\n};", + "controllerScript": "var requestTimeout = 500;\nvar commandStatusPollingInterval = 200;\n\nvar welcome = 'Welcome to ThingsBoard RPC remote shell.\\n';\n\nvar terminal, rpcEnabled, simulated, deviceName, cwd;\nvar commandExecuting = false;\n\nself.onInit = function() {\n var subscription = self.ctx.defaultSubscription;\n rpcEnabled = subscription.rpcEnabled;\n if (subscription.targetEntityName && subscription.targetEntityName.length) {\n deviceName = subscription.targetEntityName;\n } else {\n deviceName = 'Simulated';\n simulated = true;\n }\n if (self.ctx.settings.requestTimeout) {\n requestTimeout = self.ctx.settings.requestTimeout;\n }\n\n terminal = $('#device-terminal', self.ctx.$container).terminal(\n function (command) {\n if (command && command.trim().length) {\n try {\n if (command.trim() === 'exit') {\n if (!simulated) {\n self.ctx.controlApi.sendTwoWayCommand('sendCommand', {\n command: 'exit',\n cwd: cwd\n }, requestTimeout).subscribe();\n }\n this.disable();\n return;\n }\n if (simulated) {\n this.echo(command);\n } else {\n sendCommand(this, command);\n }\n } catch(e) {\n this.error(e + '');\n }\n } else {\n this.echo('');\n }\n }, {\n greetings: false,\n enabled: rpcEnabled,\n prompt: rpcEnabled ? currentPrompt : '',\n name: 'shell',\n pauseEvents: false,\n keydown: function (e, term) {\n if ((e.which == 67 || e.which == 68) && e.ctrlKey) { // CTRL+C || CTRL+D\n if (commandExecuting) {\n terminateCommand(term);\n return false;\n }\n }\n },\n onInit: initTerm\n }\n );\n};\n\nfunction initTerm(terminal) {\n terminal.echo(welcome);\n if (!rpcEnabled) {\n terminal.error('Target device is not set!\\n');\n } else {\n terminal.echo('Current target device for RPC terminal: [[b;#fff;]' + deviceName + ']\\n');\n if (!simulated) {\n terminal.pause();\n getTermInfo(terminal, function (remoteTermInfo) {\n if (remoteTermInfo) {\n terminal.echo('Remote platform info:');\n if (remoteTermInfo.platform) {\n terminal.echo('OS: [[b;#fff;]' + remoteTermInfo.platform + ']');\n } else {\n terminal.echo('OS: [[;#f00;]Unknown]');\n }\n if (remoteTermInfo.release) {\n terminal.echo('OS release: [[b;#fff;]' + remoteTermInfo.release + ']');\n } else {\n terminal.echo('OS release: [[;#f00;]Unknown]');\n }\n terminal.echo('\\r');\n } else {\n terminal.echo('[[;#f00;]Unable to get remote platform info.\\nDevice is not responding.]\\n');\n }\n terminal.resume();\n });\n }\n }\n}\n\nfunction currentPrompt(callback) {\n if (cwd) {\n callback('[[b;#2196f3;]' + deviceName + ']: [[b;#8bc34a;]' + cwd + ']> ');\n } else {\n callback('[[b;#8bc34a;]' + deviceName + ']> ');\n }\n}\n\nfunction getTermInfo(terminal, callback) {\n self.ctx.controlApi.sendTwoWayCommand('getTermInfo', null, requestTimeout).subscribe(\n function(response) {\n let termInfo;\n if (typeof response === 'string') {\n try {\n termInfo = JSON.parse(response);\n } catch (e) {\n terminal.error('Error parsing response: ' + e);\n callback(null);\n return;\n }\n } else {\n termInfo = response;\n }\n if (termInfo && termInfo.cwd) {\n cwd = termInfo.cwd;\n }\n if (callback) {\n callback(termInfo);\n }\n },\n function() {\n if (callback) {\n callback(null);\n }\n }\n );\n}\n\nfunction sendCommand(terminal, command) {\n terminal.pause();\n var sendCommandRequest = {\n command: command,\n cwd: cwd\n };\n self.ctx.controlApi.sendTwoWayCommand('sendCommand', sendCommandRequest, requestTimeout).subscribe(\n function (responseBody) {\n if (responseBody && responseBody.ok) {\n commandExecuting = true;\n setTimeout(pollCommandStatus.bind(null, terminal), commandStatusPollingInterval);\n } else {\n var error = responseBody ? responseBody.error : 'Unhandled error.';\n terminal.error(error);\n terminal.resume();\n }\n },\n function () {\n onRpcError(terminal);\n }\n );\n}\n\nfunction terminateCommand(terminal) {\n self.ctx.controlApi.sendTwoWayCommand('terminateCommand', null, requestTimeout).subscribe(\n function (responseBody) {\n if (!responseBody.ok) {\n commandExecuting = false;\n terminal.error(responseBody.error);\n terminal.resume();\n }\n },\n function () {\n onRpcError(terminal);\n }\n );\n}\n\nfunction onRpcError(terminal) {\n var errorText = self.ctx.defaultSubscription.rpcErrorText;\n terminal.error(errorText);\n terminal.resume();\n}\n\nfunction pollCommandStatus(terminal) {\n self.ctx.controlApi.sendTwoWayCommand('getCommandStatus', null, requestTimeout).subscribe(\n function (commandStatusResponse) {\n for (var i = 0; i < commandStatusResponse.data.length; i++) {\n var dataElement = commandStatusResponse.data[i];\n if (dataElement.stdout) {\n terminal.echo(dataElement.stdout);\n }\n if (dataElement.stderr) {\n terminal.error(dataElement.stderr);\n }\n }\n if (commandStatusResponse.done) {\n commandExecuting = false;\n cwd = commandStatusResponse.cwd;\n terminal.resume();\n } else {\n var interval = commandStatusPollingInterval;\n if (!commandStatusResponse.data.length) {\n interval *= 5;\n }\n setTimeout(pollCommandStatus.bind(null, terminal), interval);\n }\n },\n function () {\n commandExecuting = false;\n onRpcError(terminal);\n }\n );\n}\n\nself.onResize = function () {\n if (terminal) {\n terminal.resize(self.ctx.width, self.ctx.height);\n }\n};\n\nself.onDestroy = function() {\n};", "settingsSchema": "", "dataKeySettingsSchema": "{}\n", "settingsDirective": "tb-rpc-shell-widget-settings", From 0d9e8261e0ab7a77afea43784cb209ff0fb92968 Mon Sep 17 00:00:00 2001 From: d2eight Date: Thu, 24 Oct 2024 20:34:26 +0300 Subject: [PATCH 04/40] Adding outline appearance to the country input --- .../shared/components/country-autocomplete.component.html | 2 +- .../app/shared/components/country-autocomplete.component.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/shared/components/country-autocomplete.component.html b/ui-ngx/src/app/shared/components/country-autocomplete.component.html index eadf630dcd..c99ac037b2 100644 --- a/ui-ngx/src/app/shared/components/country-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/country-autocomplete.component.html @@ -15,7 +15,7 @@ limitations under the License. --> - + {{ labelText }} Date: Thu, 31 Oct 2024 16:51:00 +0200 Subject: [PATCH 05/40] Fixed sizing for codeblocks --- .../home/components/event/event-content-dialog.component.ts | 4 ++-- .../lib/home-page/getting-started-widget.component.scss | 2 +- ui-ngx/src/app/shared/components/markdown.component.scss | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/event/event-content-dialog.component.ts b/ui-ngx/src/app/modules/home/components/event/event-content-dialog.component.ts index 65b5be9b75..fb7b026914 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-content-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-content-dialog.component.ts @@ -139,14 +139,14 @@ export class EventContentDialogComponent extends DialogComponent 0) { const lines = content.split('\n'); - newHeight = 16 * lines.length + 16; + newHeight = 18 * lines.length + 16; let maxLineLength = 0; lines.forEach((row) => { const line = row.replace(/\t/g, ' ').replace(/\n/g, ''); const lineLength = line.length; maxLineLength = Math.max(maxLineLength, lineLength); }); - newWidth = 8 * maxLineLength + 16; + newWidth = 10 * maxLineLength + 16; } // newHeight = Math.min(400, newHeight); this.renderer.setStyle(editorElement, 'minHeight', newHeight.toString() + 'px'); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss index 65eaf66c54..3e34cbdcd9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss @@ -118,7 +118,7 @@ padding: 0; pre[class*=language-] { margin: 0; - padding: 9px 38px 9px 16px; + padding: 10px 38px 10px 16px; background: rgba(0, 0, 0, 0.03); border-radius: 6px; border: none; diff --git a/ui-ngx/src/app/shared/components/markdown.component.scss b/ui-ngx/src/app/shared/components/markdown.component.scss index 0c5e310e07..c47a78011b 100644 --- a/ui-ngx/src/app/shared/components/markdown.component.scss +++ b/ui-ngx/src/app/shared/components/markdown.component.scss @@ -370,7 +370,7 @@ } &.line-numbers { - padding-left: 66px; + padding: 10px 16px 10px 66px; & > code { span.line-numbers-rows { From 9ec8617433405f482cb136718249714266b81679 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Thu, 31 Oct 2024 16:51:28 +0200 Subject: [PATCH 06/40] Revert "Fixed sizing for codeblocks" This reverts commit 6d004fe2dc52c69e8f30a9717f5db0aa788898a2. --- .../home/components/event/event-content-dialog.component.ts | 4 ++-- .../lib/home-page/getting-started-widget.component.scss | 2 +- ui-ngx/src/app/shared/components/markdown.component.scss | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/event/event-content-dialog.component.ts b/ui-ngx/src/app/modules/home/components/event/event-content-dialog.component.ts index fb7b026914..65b5be9b75 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-content-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-content-dialog.component.ts @@ -139,14 +139,14 @@ export class EventContentDialogComponent extends DialogComponent 0) { const lines = content.split('\n'); - newHeight = 18 * lines.length + 16; + newHeight = 16 * lines.length + 16; let maxLineLength = 0; lines.forEach((row) => { const line = row.replace(/\t/g, ' ').replace(/\n/g, ''); const lineLength = line.length; maxLineLength = Math.max(maxLineLength, lineLength); }); - newWidth = 10 * maxLineLength + 16; + newWidth = 8 * maxLineLength + 16; } // newHeight = Math.min(400, newHeight); this.renderer.setStyle(editorElement, 'minHeight', newHeight.toString() + 'px'); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss index 3e34cbdcd9..65eaf66c54 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss @@ -118,7 +118,7 @@ padding: 0; pre[class*=language-] { margin: 0; - padding: 10px 38px 10px 16px; + padding: 9px 38px 9px 16px; background: rgba(0, 0, 0, 0.03); border-radius: 6px; border: none; diff --git a/ui-ngx/src/app/shared/components/markdown.component.scss b/ui-ngx/src/app/shared/components/markdown.component.scss index c47a78011b..0c5e310e07 100644 --- a/ui-ngx/src/app/shared/components/markdown.component.scss +++ b/ui-ngx/src/app/shared/components/markdown.component.scss @@ -370,7 +370,7 @@ } &.line-numbers { - padding: 10px 16px 10px 66px; + padding-left: 66px; & > code { span.line-numbers-rows { From 9a1c03ac5df3902796a7257fcf68524fae320ee6 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Thu, 31 Oct 2024 18:05:37 +0200 Subject: [PATCH 07/40] Updated autocomplete for AssetService --- .../models/ace/service-completion.models.ts | 102 ++++++++++-------- 1 file changed, 60 insertions(+), 42 deletions(-) diff --git a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts index 5efc428194..709d670e6b 100644 --- a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts +++ b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts @@ -102,6 +102,10 @@ export const customDialogComponentHref = 'Resource info'; +export const bulkImportResultHref = 'Bulk import result'; + +export const bulkImportRequestHref = 'Bulk import request'; + export const pageLinkArg: FunctionArg = { name: 'pageLink', type: 'PageLink', @@ -366,27 +370,6 @@ export const serviceCompletions: TbEditorCompletions = { meta: 'service', type: 'AssetService', children: { - getTenantAssetInfos: { - description: 'Get tenant assets', - meta: 'function', - args: [ - pageLinkArg, - {name: 'type', type: 'string', optional: true, description: 'Asset type'}, - requestConfigArg - ], - return: observablePageDataReturnType(assetInfoHref) - }, - getCustomerAssetInfos: { - description: 'Get customer assets', - meta: 'function', - args: [ - {name: 'customerId', type: 'string', description: 'Id of the customer'}, - pageLinkArg, - {name: 'type', type: 'string', optional: true, description: 'Asset type'}, - requestConfigArg - ], - return: observablePageDataReturnType(assetInfoHref) - }, getAsset: { description: 'Get asset by id', meta: 'function', @@ -414,53 +397,80 @@ export const serviceCompletions: TbEditorCompletions = { ], return: observableReturnType(assetInfoHref) }, - saveAsset: { - description: 'Save asset', + getTenantAssets: { + description: 'Get assets for the tenant, filtered by type if provided', meta: 'function', args: [ - {name: 'asset', type: assetHref, description: 'Asset object to save'}, + pageLinkArg, + { name: 'type', type: 'string', description: 'Optional asset type filter' }, requestConfigArg ], - return: observableReturnType(assetHref) + return: observablePageDataReturnType(assetHref) }, - deleteAsset: { - description: 'Delete asset by id', + getCustomerAssets: { + description: 'Get assets for a specific customer, filtered by type if provided', meta: 'function', args: [ - {name: 'assetId', type: 'string', description: 'Id of the asset'}, + { name: 'customerId', type: 'string', description: 'Customer ID' }, + pageLinkArg, + { name: 'type', type: 'string', description: 'Optional asset type filter' }, requestConfigArg ], - return: observableVoid() + return: observablePageDataReturnType(assetHref) }, - getAssetTypes: { - description: 'Get all available assets types', + getUserAssets: { + description: 'Get assets associated with the user, filtered by type if provided', meta: 'function', args: [ + pageLinkArg, + { name: 'type', type: 'string', description: 'Optional asset type filter' }, requestConfigArg ], - return: observableArrayReturnType('EntitySubtype') + return: observablePageDataReturnType(assetHref) }, - makeAssetPublic: { - description: 'Make asset public (available from public dashboard)', + getAllAssetInfos: { + description: 'Get all asset information with optional customer inclusion', meta: 'function', args: [ - {name: 'assetId', type: 'string', description: 'Id of the asset'}, + { name: 'includeCustomers', type: 'boolean', description: 'Whether to include customers in the result' }, + pageLinkArg, + { name: 'assetProfileId', type: 'string', description: 'Optional asset profile ID' }, requestConfigArg ], - return: observableReturnType(assetHref) + return: observablePageDataReturnType(assetInfoHref) }, - assignAssetToCustomer: { - description: 'Assign asset to specific customer', + getCustomerAssetInfos: { + description: 'Get customer asset information with optional customer inclusion', meta: 'function', args: [ - {name: 'customerId', type: 'string', description: 'Id of the customer'}, - {name: 'assetId', type: 'string', description: 'Id of the asset'}, + { name: 'includeCustomers', type: 'boolean', description: 'Whether to include customers in the result' }, + { name: 'customerId', type: 'string', description: 'Customer ID' }, + pageLinkArg, + { name: 'assetProfileId', type: 'string', description: 'Optional asset profile ID' }, + requestConfigArg + ], + return: observablePageDataReturnType(assetInfoHref) + }, + bulkImportAssets: { + description: 'Bulk import assets with provided entities data', + meta: 'function', + args: [ + { name: 'entitiesData', type: bulkImportRequestHref, description: 'Data for bulk importing assets' }, + requestConfigArg + ], + return: observableReturnType(bulkImportResultHref) + }, + saveAsset: { + description: 'Save asset', + meta: 'function', + args: [ + {name: 'asset', type: assetHref, description: 'Asset object to save'}, requestConfigArg ], return: observableReturnType(assetHref) }, - unassignAssetFromCustomer: { - description: 'Unassign asset from any customer', + deleteAsset: { + description: 'Delete asset by id', meta: 'function', args: [ {name: 'assetId', type: 'string', description: 'Id of the asset'}, @@ -468,6 +478,14 @@ export const serviceCompletions: TbEditorCompletions = { ], return: observableVoid() }, + getAssetTypes: { + description: 'Get all available assets types', + meta: 'function', + args: [ + requestConfigArg + ], + return: observableArrayReturnType('EntitySubtype') + }, findByQuery: { description: 'Find assets by search query', meta: 'function', From bcbd115a19183876ee055df2ad491d86ee344280 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 31 Oct 2024 18:32:38 +0200 Subject: [PATCH 08/40] Queue providers deprecation: update message and yml description --- .../thingsboard/server/service/update/DeprecationService.java | 3 ++- application/src/main/resources/thingsboard.yml | 4 +++- .../server/dao/notification/DefaultNotifications.java | 3 ++- msa/vc-executor/src/main/resources/tb-vc-executor.yml | 4 +++- transport/coap/src/main/resources/tb-coap-transport.yml | 4 +++- transport/http/src/main/resources/tb-http-transport.yml | 4 +++- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 4 +++- transport/mqtt/src/main/resources/tb-mqtt-transport.yml | 4 +++- transport/snmp/src/main/resources/tb-snmp-transport.yml | 4 +++- 9 files changed, 25 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/update/DeprecationService.java b/application/src/main/java/org/thingsboard/server/service/update/DeprecationService.java index ddb8080bcd..d4109ff420 100644 --- a/application/src/main/java/org/thingsboard/server/service/update/DeprecationService.java +++ b/application/src/main/java/org/thingsboard/server/service/update/DeprecationService.java @@ -55,7 +55,8 @@ public class DeprecationService { } } - log.warn("WARNING: {} queue type is deprecated and will be removed in ThingsBoard 4.0. Please migrate to Apache Kafka", queueTypeName); + log.warn("WARNING: Starting with ThingsBoard 4.0, {} will no longer be supported as a message queue for microservices. " + + "Please migrate to Apache Kafka. This change will not impact any rule nodes", queueTypeName); notificationCenter.sendGeneralWebNotification(TenantId.SYS_TENANT_ID, new SystemAdministratorsFilter(), DefaultNotifications.queueTypeDeprecation.toTemplate(), new GeneralNotificationInfo(Map.of( "queueType", queueTypeName diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index e9c8668958..8ff3bfb10e 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1439,7 +1439,9 @@ swagger: # Queue configuration parameters queue: - type: "${TB_QUEUE_TYPE:in-memory}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) + # in-memory or kafka (Apache Kafka). The following queue types are deprecated and will no longer be supported in ThingsBoard 4.0: + # aws-sqs (AWS SQS), pubsub (PubSub), service-bus (Azure Service Bus), rabbitmq (RabbitMQ) + type: "${TB_QUEUE_TYPE:in-memory}" prefix: "${TB_QUEUE_PREFIX:}" # Global queue prefix. If specified, prefix is added before default topic name: 'prefix.default_topic_name'. Prefix is applied to all topics (and consumer groups for kafka). in_memory: stats: diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java index 65a5763c5a..9b747766c9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java @@ -376,7 +376,8 @@ public class DefaultNotifications { .name("Queue type deprecation") .type(NotificationType.GENERAL) .subject("WARNING: ${queueType} deprecation") - .text("${queueType} queue type is deprecated and will be removed in ThingsBoard 4.0. Please migrate to Apache Kafka") + .text("Starting with ThingsBoard 4.0, ${queueType} will no longer be supported as a message queue for microservices. " + + "Please migrate to Apache Kafka. This change will not impact any rule nodes.") .icon("warning").color(RED_COLOR) .build(); diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index a55a0e73dc..6b79f2d101 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -47,7 +47,9 @@ zk: # Queue configuration parameters queue: - type: "${TB_QUEUE_TYPE:kafka}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) + # kafka (Apache Kafka). The following queue types are deprecated and will no longer be supported in ThingsBoard 4.0: + # aws-sqs (AWS SQS), pubsub (PubSub), service-bus (Azure Service Bus), rabbitmq (RabbitMQ) + type: "${TB_QUEUE_TYPE:kafka}" prefix: "${TB_QUEUE_PREFIX:}" # Global queue prefix. If specified, prefix is added before default topic name: 'prefix.default_topic_name'. Prefix is applied to all topics (and consumer groups for kafka). in_memory: stats: diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index f2ea0c1685..2c1c0550e1 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -232,7 +232,9 @@ coap: # Queue configuration parameters queue: - type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) + # kafka (Apache Kafka). The following queue types are deprecated and will no longer be supported in ThingsBoard 4.0: + # aws-sqs (AWS SQS), pubsub (PubSub), service-bus (Azure Service Bus), rabbitmq (RabbitMQ) + type: "${TB_QUEUE_TYPE:kafka}" prefix: "${TB_QUEUE_PREFIX:}" # Global queue prefix. If specified, prefix is added before default topic name: 'prefix.default_topic_name'. Prefix is applied to all topics (and consumer groups for kafka). kafka: # Kafka Bootstrap Servers diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 527715b8ca..3c28c6ddf6 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -202,7 +202,9 @@ transport: # Queue configuration parameters queue: - type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) + # kafka (Apache Kafka). The following queue types are deprecated and will no longer be supported in ThingsBoard 4.0: + # aws-sqs (AWS SQS), pubsub (PubSub), service-bus (Azure Service Bus), rabbitmq (RabbitMQ) + type: "${TB_QUEUE_TYPE:kafka}" prefix: "${TB_QUEUE_PREFIX:}" # Global queue prefix. If specified, prefix is added before default topic name: 'prefix.default_topic_name'. Prefix is applied to all topics (and consumer groups for kafka) . kafka: # Kafka Bootstrap Servers diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index bf6a159106..bafe77ee92 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -302,7 +302,9 @@ transport: # Queue configuration properties queue: - type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) + # kafka (Apache Kafka). The following queue types are deprecated and will no longer be supported in ThingsBoard 4.0: + # aws-sqs (AWS SQS), pubsub (PubSub), service-bus (Azure Service Bus), rabbitmq (RabbitMQ) + type: "${TB_QUEUE_TYPE:kafka}" prefix: "${TB_QUEUE_PREFIX:}" # Global queue prefix. If specified, prefix is added before default topic name: 'prefix.default_topic_name'. Prefix is applied to all topics (and consumer groups for kafka). kafka: # Kafka Bootstrap Servers diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index c9fd10a99d..51a2c173a7 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -235,7 +235,9 @@ transport: # Queue configuration parameters queue: - type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) + # kafka (Apache Kafka). The following queue types are deprecated and will no longer be supported in ThingsBoard 4.0: + # aws-sqs (AWS SQS), pubsub (PubSub), service-bus (Azure Service Bus), rabbitmq (RabbitMQ) + type: "${TB_QUEUE_TYPE:kafka}" prefix: "${TB_QUEUE_PREFIX:}" # Global queue prefix. If specified, prefix is added before default topic name: 'prefix.default_topic_name'. Prefix is applied to all topics (and consumer groups for kafka). kafka: # Kafka Bootstrap Servers diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 85a125b351..df222fe09f 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -181,7 +181,9 @@ transport: # Queue configuration parameters queue: - type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) + # kafka (Apache Kafka). The following queue types are deprecated and will no longer be supported in ThingsBoard 4.0: + # aws-sqs (AWS SQS), pubsub (PubSub), service-bus (Azure Service Bus), rabbitmq (RabbitMQ) + type: "${TB_QUEUE_TYPE:kafka}" prefix: "${TB_QUEUE_PREFIX:}" # Global queue prefix. If specified, prefix is added before default topic name: 'prefix.default_topic_name'. Prefix is applied to all topics (and consumer groups for kafka). kafka: # Kafka Bootstrap Servers From ba171900a9db305a801907f20f5192af7b5d79cc Mon Sep 17 00:00:00 2001 From: mpetrov Date: Fri, 1 Nov 2024 12:32:43 +0200 Subject: [PATCH 09/40] Revert "Updated autocomplete for AssetService" This reverts commit 9a1c03ac5df3902796a7257fcf68524fae320ee6. --- .../models/ace/service-completion.models.ts | 102 ++++++++---------- 1 file changed, 42 insertions(+), 60 deletions(-) diff --git a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts index 709d670e6b..5efc428194 100644 --- a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts +++ b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts @@ -102,10 +102,6 @@ export const customDialogComponentHref = 'Resource info'; -export const bulkImportResultHref = 'Bulk import result'; - -export const bulkImportRequestHref = 'Bulk import request'; - export const pageLinkArg: FunctionArg = { name: 'pageLink', type: 'PageLink', @@ -370,6 +366,27 @@ export const serviceCompletions: TbEditorCompletions = { meta: 'service', type: 'AssetService', children: { + getTenantAssetInfos: { + description: 'Get tenant assets', + meta: 'function', + args: [ + pageLinkArg, + {name: 'type', type: 'string', optional: true, description: 'Asset type'}, + requestConfigArg + ], + return: observablePageDataReturnType(assetInfoHref) + }, + getCustomerAssetInfos: { + description: 'Get customer assets', + meta: 'function', + args: [ + {name: 'customerId', type: 'string', description: 'Id of the customer'}, + pageLinkArg, + {name: 'type', type: 'string', optional: true, description: 'Asset type'}, + requestConfigArg + ], + return: observablePageDataReturnType(assetInfoHref) + }, getAsset: { description: 'Get asset by id', meta: 'function', @@ -397,80 +414,53 @@ export const serviceCompletions: TbEditorCompletions = { ], return: observableReturnType(assetInfoHref) }, - getTenantAssets: { - description: 'Get assets for the tenant, filtered by type if provided', - meta: 'function', - args: [ - pageLinkArg, - { name: 'type', type: 'string', description: 'Optional asset type filter' }, - requestConfigArg - ], - return: observablePageDataReturnType(assetHref) - }, - getCustomerAssets: { - description: 'Get assets for a specific customer, filtered by type if provided', - meta: 'function', - args: [ - { name: 'customerId', type: 'string', description: 'Customer ID' }, - pageLinkArg, - { name: 'type', type: 'string', description: 'Optional asset type filter' }, - requestConfigArg - ], - return: observablePageDataReturnType(assetHref) - }, - getUserAssets: { - description: 'Get assets associated with the user, filtered by type if provided', + saveAsset: { + description: 'Save asset', meta: 'function', args: [ - pageLinkArg, - { name: 'type', type: 'string', description: 'Optional asset type filter' }, + {name: 'asset', type: assetHref, description: 'Asset object to save'}, requestConfigArg ], - return: observablePageDataReturnType(assetHref) + return: observableReturnType(assetHref) }, - getAllAssetInfos: { - description: 'Get all asset information with optional customer inclusion', + deleteAsset: { + description: 'Delete asset by id', meta: 'function', args: [ - { name: 'includeCustomers', type: 'boolean', description: 'Whether to include customers in the result' }, - pageLinkArg, - { name: 'assetProfileId', type: 'string', description: 'Optional asset profile ID' }, + {name: 'assetId', type: 'string', description: 'Id of the asset'}, requestConfigArg ], - return: observablePageDataReturnType(assetInfoHref) + return: observableVoid() }, - getCustomerAssetInfos: { - description: 'Get customer asset information with optional customer inclusion', + getAssetTypes: { + description: 'Get all available assets types', meta: 'function', args: [ - { name: 'includeCustomers', type: 'boolean', description: 'Whether to include customers in the result' }, - { name: 'customerId', type: 'string', description: 'Customer ID' }, - pageLinkArg, - { name: 'assetProfileId', type: 'string', description: 'Optional asset profile ID' }, requestConfigArg ], - return: observablePageDataReturnType(assetInfoHref) + return: observableArrayReturnType('EntitySubtype') }, - bulkImportAssets: { - description: 'Bulk import assets with provided entities data', + makeAssetPublic: { + description: 'Make asset public (available from public dashboard)', meta: 'function', args: [ - { name: 'entitiesData', type: bulkImportRequestHref, description: 'Data for bulk importing assets' }, + {name: 'assetId', type: 'string', description: 'Id of the asset'}, requestConfigArg ], - return: observableReturnType(bulkImportResultHref) + return: observableReturnType(assetHref) }, - saveAsset: { - description: 'Save asset', + assignAssetToCustomer: { + description: 'Assign asset to specific customer', meta: 'function', args: [ - {name: 'asset', type: assetHref, description: 'Asset object to save'}, + {name: 'customerId', type: 'string', description: 'Id of the customer'}, + {name: 'assetId', type: 'string', description: 'Id of the asset'}, requestConfigArg ], return: observableReturnType(assetHref) }, - deleteAsset: { - description: 'Delete asset by id', + unassignAssetFromCustomer: { + description: 'Unassign asset from any customer', meta: 'function', args: [ {name: 'assetId', type: 'string', description: 'Id of the asset'}, @@ -478,14 +468,6 @@ export const serviceCompletions: TbEditorCompletions = { ], return: observableVoid() }, - getAssetTypes: { - description: 'Get all available assets types', - meta: 'function', - args: [ - requestConfigArg - ], - return: observableArrayReturnType('EntitySubtype') - }, findByQuery: { description: 'Find assets by search query', meta: 'function', From fa110b4c613710a40eb6d0370de0193f2d6980bd Mon Sep 17 00:00:00 2001 From: mpetrov Date: Fri, 1 Nov 2024 12:33:15 +0200 Subject: [PATCH 10/40] Updated autocomplete for AssetService refactoring --- .../models/ace/service-completion.models.ts | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts index 5efc428194..17e05427a1 100644 --- a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts +++ b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts @@ -102,6 +102,10 @@ export const customDialogComponentHref = 'Resource info'; +export const bulkImportResultHref = 'Bulk import result'; + +export const bulkImportRequestHref = 'Bulk import request'; + export const pageLinkArg: FunctionArg = { name: 'pageLink', type: 'PageLink', @@ -387,6 +391,67 @@ export const serviceCompletions: TbEditorCompletions = { ], return: observablePageDataReturnType(assetInfoHref) }, + getTenantAssetInfosByAssetProfileId: { + description: 'Get tenant asset infos by asset profile ID', + meta: 'function', + args: [ + pageLinkArg, + { name: 'assetProfileId', type: 'string', optional: true, description: 'ID of the asset profile' }, + requestConfigArg + ], + return: observablePageDataReturnType(assetInfoHref) + }, + getCustomerAssetInfosByAssetProfileId: { + description: 'Get customer asset infos by asset profile ID', + meta: 'function', + args: [ + { name: 'customerId', type: 'string', description: 'ID of the customer' }, + pageLinkArg, + { name: 'assetProfileId', type: 'string', optional: true, description: 'ID of the asset profile' }, + requestConfigArg + ], + return: observablePageDataReturnType(assetInfoHref) + }, + assignAssetToEdge: { + description: 'Assign an asset to an edge', + meta: 'function', + args: [ + { name: 'edgeId', type: 'string', description: 'ID of the edge' }, + { name: 'assetId', type: 'string', description: 'ID of the asset' }, + requestConfigArg + ], + return: observableReturnType(assetHref) + }, + unassignAssetFromEdge: { + description: 'Unassign an asset from an edge', + meta: 'function', + args: [ + { name: 'edgeId', type: 'string', description: 'ID of the edge' }, + { name: 'assetId', type: 'string', description: 'ID of the asset' }, + requestConfigArg + ], + return: observableVoid() + }, + getEdgeAssets: { + description: 'Get assets assigned to an edge', + meta: 'function', + args: [ + { name: 'edgeId', type: 'string', description: 'ID of the edge' }, + pageLinkArg, + { name: 'type', type: 'string', optional: true, description: 'Asset type' }, + requestConfigArg + ], + return: observablePageDataReturnType(assetInfoHref) + }, + bulkImportAssets: { + description: 'Bulk import assets with provided entities data', + meta: 'function', + args: [ + { name: 'entitiesData', type: bulkImportRequestHref, description: 'Data for bulk importing assets' }, + requestConfigArg + ], + return: observableReturnType(bulkImportResultHref) + }, getAsset: { description: 'Get asset by id', meta: 'function', From 37f4dc7cb24e52da0d06209e6ca21a6f7aa99eae Mon Sep 17 00:00:00 2001 From: d2eight Date: Fri, 1 Nov 2024 19:43:31 +0200 Subject: [PATCH 11/40] Fix of the action bug --- .../home/components/widget/widget-container.component.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index ed1f089454..f6679d0c94 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -38,6 +38,7 @@ [class]="{'tb-widget-actions-absolute': !(widget.showWidgetTitlePanel && !widgetComponent.widgetContext?.embedTitlePanel && (widget.showTitle||widget.hasAggregation))}" (mousedown)="$event.stopPropagation()"> From 637fe2a258856172e2aaa2fd86cde14a57a55478 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 11 Nov 2024 22:15:23 +0100 Subject: [PATCH 35/40] Used debugFailures and debugAll params instead of DebugStrategies --- .../rule_chains/edge_root_rule_chain.json | 27 +- .../device_profile/rule_chain_template.json | 21 +- .../tenant/rule_chains/root_rule_chain.json | 30 ++- .../main/data/upgrade/3.8.1/schema_update.sql | 6 +- .../actors/ruleChain/DefaultTbContext.java | 17 +- .../RuleChainActorMessageProcessor.java | 9 +- .../RuleNodeActorMessageProcessor.java | 3 +- .../BaseRuleChainMetadataConstructor.java | 5 +- .../actors/rule/DefaultTbContextTest.java | 251 +++++++----------- .../server/edge/AbstractEdgeTest.java | 6 +- .../server/edge/RuleChainEdgeTest.java | 3 +- ...AbstractRuleEngineFlowIntegrationTest.java | 11 +- ...actRuleEngineLifecycleIntegrationTest.java | 3 +- .../housekeeper/HousekeeperServiceTest.java | 5 +- .../sync/ie/ExportImportServiceSqlTest.java | 9 +- .../service/sync/vc/VersionControlTest.java | 9 +- .../common/data/rule/DebugStrategy.java | 70 ----- .../server/common/data/rule/RuleNode.java | 19 +- .../common/data/rule/RuleNodeDebugUtil.java | 45 ++++ .../DefaultTenantProfileConfiguration.java | 5 +- common/edge-api/src/main/proto/edge.proto | 11 +- .../server/dao/model/ModelConstants.java | 3 +- .../server/dao/model/sql/RuleNodeEntity.java | 20 +- .../server/dao/rule/BaseRuleChainService.java | 21 +- .../main/resources/sql/schema-entities.sql | 4 +- .../src/main/resources/root_rule_chain.json | 54 ++-- .../resources/MqttRuleNodeTestMetadata.json | 9 +- .../RpcResponseRuleChainMetadata.json | 9 +- 28 files changed, 326 insertions(+), 359 deletions(-) delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/DebugStrategy.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeDebugUtil.java diff --git a/application/src/main/data/json/edge/rule_chains/edge_root_rule_chain.json b/application/src/main/data/json/edge/rule_chains/edge_root_rule_chain.json index 04a5f52f4e..05dff1678f 100644 --- a/application/src/main/data/json/edge/rule_chains/edge_root_rule_chain.json +++ b/application/src/main/data/json/edge/rule_chains/edge_root_rule_chain.json @@ -20,7 +20,8 @@ }, "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", "name": "Device Profile Node", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "persistAlarmRulesState": false, "fetchAlarmRulesStateOnStart": false @@ -34,7 +35,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "Save Timeseries", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "defaultTTL": 0 }, @@ -47,7 +49,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", "name": "Save Client Attributes", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configurationVersion": 2, "configuration": { "scope": "CLIENT_SCOPE", @@ -64,7 +67,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", "name": "Message Type Switch", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "version": 0 }, @@ -77,7 +81,8 @@ }, "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log RPC from Device", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -92,7 +97,8 @@ }, "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log Other", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -107,7 +113,8 @@ }, "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", "name": "RPC Call Request", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "timeoutInSeconds": 60 }, @@ -120,7 +127,8 @@ }, "type": "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode", "name": "Push to cloud", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "scope": "SERVER_SCOPE" }, @@ -133,7 +141,8 @@ }, "type": "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode", "name": "Push to cloud", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "scope": "SERVER_SCOPE" }, diff --git a/application/src/main/data/json/tenant/device_profile/rule_chain_template.json b/application/src/main/data/json/tenant/device_profile/rule_chain_template.json index b005331862..3e265591de 100644 --- a/application/src/main/data/json/tenant/device_profile/rule_chain_template.json +++ b/application/src/main/data/json/tenant/device_profile/rule_chain_template.json @@ -19,7 +19,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "Save Timeseries", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "defaultTTL": 0 } @@ -31,7 +32,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", "name": "Save Client Attributes", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configurationVersion": 2, "configuration": { "scope": "CLIENT_SCOPE", @@ -47,7 +49,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", "name": "Message Type Switch", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "version": 0 } @@ -59,7 +62,8 @@ }, "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log RPC from Device", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -73,7 +77,8 @@ }, "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log Other", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -87,7 +92,8 @@ }, "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", "name": "RPC Call Request", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "timeoutInSeconds": 60 } @@ -100,7 +106,8 @@ }, "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", "name": "Device Profile Node", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "configuration": { "persistAlarmRulesState": false, "fetchAlarmRulesStateOnStart": false diff --git a/application/src/main/data/json/tenant/rule_chains/root_rule_chain.json b/application/src/main/data/json/tenant/rule_chains/root_rule_chain.json index 3b9898d0b1..4a799cf957 100644 --- a/application/src/main/data/json/tenant/rule_chains/root_rule_chain.json +++ b/application/src/main/data/json/tenant/rule_chains/root_rule_chain.json @@ -18,7 +18,9 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "Save Timeseries", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, + "debugAllUntil": 0, "configuration": { "defaultTTL": 0 } @@ -30,7 +32,9 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", "name": "Save Client Attributes", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, + "debugAllUntil": 0, "configurationVersion": 2, "configuration": { "scope": "CLIENT_SCOPE", @@ -46,7 +50,9 @@ }, "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", "name": "Message Type Switch", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, + "debugAllUntil": 0, "configuration": { "version": 0 } @@ -58,7 +64,9 @@ }, "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log RPC from Device", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, + "debugAllUntil": 0, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -72,7 +80,9 @@ }, "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log Other", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, + "debugAllUntil": 0, "configuration": { "scriptLang": "TBEL", "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);", @@ -86,7 +96,9 @@ }, "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", "name": "RPC Call Request", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, + "debugAllUntil": 0, "configuration": { "timeoutInSeconds": 60 } @@ -99,7 +111,9 @@ }, "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", "name": "Device Profile Node", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, + "debugAllUntil": 0, "configuration": { "persistAlarmRulesState": false, "fetchAlarmRulesStateOnStart": false @@ -140,4 +154,4 @@ ], "ruleChainConnections": null } -} \ No newline at end of file +} diff --git a/application/src/main/data/upgrade/3.8.1/schema_update.sql b/application/src/main/data/upgrade/3.8.1/schema_update.sql index dab9505d36..cbe0e6103a 100644 --- a/application/src/main/data/upgrade/3.8.1/schema_update.sql +++ b/application/src/main/data/upgrade/3.8.1/schema_update.sql @@ -28,9 +28,9 @@ UPDATE tb_user SET additional_info = (additional_info::jsonb - 'lastLoginTs' - ' -- UPDATE RULE NODE DEBUG MODE TO DEBUG STRATEGY START ALTER TABLE rule_node - ADD COLUMN IF NOT EXISTS debug_strategy varchar(32) DEFAULT 'DISABLED'; + ADD COLUMN IF NOT EXISTS debug_failures boolean DEFAULT false; ALTER TABLE rule_node - ADD COLUMN IF NOT EXISTS last_update_ts bigint NOT NULL DEFAULT extract(epoch from now()) * 1000; + ADD COLUMN IF NOT EXISTS debug_all_until bigint NOT NULL DEFAULT 0; DO $$ BEGIN @@ -38,7 +38,7 @@ $$ FROM information_schema.columns WHERE table_name = 'rule_node' AND column_name = 'debug_mode') THEN UPDATE rule_node - SET debug_strategy = CASE WHEN debug_mode = true THEN 'ALL_EVENTS' ELSE 'DISABLED' END; + SET debug_all_until = CASE WHEN debug_mode = true THEN extract(epoch from now() + 3600) * 1000 ELSE 0 END; ALTER TABLE rule_node DROP COLUMN debug_mode; END IF; diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 119d1d2900..000c260769 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -63,8 +63,8 @@ import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.common.data.rule.RuleNodeDebugUtil; import org.thingsboard.server.common.data.rule.RuleNodeState; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbActorMsg; @@ -1002,22 +1002,11 @@ public class DefaultTbContext implements TbContext { private void persistDebugOutput(TbMsg msg, Set relationTypes, Throwable error, String failureMessage) { RuleNode ruleNode = nodeCtx.getSelf(); - DebugStrategy debugStrategy = ruleNode.getDebugStrategy(); - if (debugStrategy.shouldPersistDebugOutputForAllEvents(ruleNode.getLastUpdateTs(), msg.getTs(), getMaxRuleNodeDebugDurationMinutes())) { + if (RuleNodeDebugUtil.isDebugAllAvailable(ruleNode)) { relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(getTenantId(), ruleNode.getId(), msg, relationType, error, failureMessage)); - } else if (debugStrategy.shouldPersistDebugForFailureEvent(relationTypes)) { + } else if (RuleNodeDebugUtil.isDebugFailuresAvailable(ruleNode, relationTypes)) { mainCtx.persistDebugOutput(getTenantId(), ruleNode.getId(), msg, TbNodeConnectionType.FAILURE, error, failureMessage); } } - private int getMaxRuleNodeDebugDurationMinutes() { - if (nodeCtx.getSelf().getDebugStrategy().isHasDuration()) { - var configuration = mainCtx.getTenantProfileCache() - .get(getTenantId()).getProfileData().getConfiguration(); - int systemMaxRuleNodeDebugModeDurationMinutes = mainCtx.getMaxRuleNodeDebugModeDurationMinutes(); - return configuration.getMaxRuleNodeDebugModeDurationMinutes(systemMaxRuleNodeDebugModeDurationMinutes); - } - return 0; - } - } diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java index 01caa50860..636ea3fd07 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.common.data.rule.RuleNodeDebugUtil; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.plugin.RuleNodeUpdatedMsg; @@ -255,13 +256,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor connections) { + void givenDebugFailuresEventsAndConnections_whenTellNext_thenVerifyDebugOutputPersisted(Set connections) { // GIVEN var callbackMock = mock(TbMsgCallback.class); var msg = getTbMsgWithCallback(callbackMock); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ONLY_FAILURE_EVENTS); + ruleNode.setDebugFailures(true); + ruleNode.setDebugAllUntil(0); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); @@ -169,7 +166,7 @@ class DefaultTbContextTest { checkTellNextCommonLogic(callbackMock, connections, msg); } - private static Stream> givenDebugStrategyOnlyFailureEventsAndConnections_whenTellNext_thenVerifyDebugOutputPersisted() { + private static Stream> givenDebugFailuresEventsAndConnections_whenTellNext_thenVerifyDebugOutputPersisted() { return Stream.of( Collections.singleton(TbNodeConnectionType.FAILURE), Set.of(TbNodeConnectionType.FAILURE, TbNodeConnectionType.SUCCESS) @@ -178,13 +175,14 @@ class DefaultTbContextTest { @MethodSource @ParameterizedTest - void givenDebugStrategyDisabledAndConnections_whenTellNext_thenVerifyDebugOutputNotPersisted(Set connections) { + void givenDebugDisabledAndConnections_whenTellNext_thenVerifyDebugOutputNotPersisted(Set connections) { // GIVEN var callbackMock = mock(TbMsgCallback.class); var msg = getTbMsgWithCallback(callbackMock); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.DISABLED); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(0); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); @@ -198,7 +196,7 @@ class DefaultTbContextTest { checkTellNextCommonLogic(callbackMock, connections, msg); } - private static Stream> givenDebugStrategyDisabledAndConnections_whenTellNext_thenVerifyDebugOutputNotPersisted() { + private static Stream> givenDebugDisabledAndConnections_whenTellNext_thenVerifyDebugOutputNotPersisted() { return Stream.of( Collections.singleton(TbNodeConnectionType.FAILURE), Collections.singleton(TbNodeConnectionType.SUCCESS), @@ -208,18 +206,17 @@ class DefaultTbContextTest { @MethodSource @ParameterizedTest - void givenDebugStrategyAllEventsAndConnection_whenTellNext_thenVerifyDebugOutputPersisted(String connection) { + void givenDebugAllEventsAndConnection_whenTellNext_thenVerifyDebugOutputPersisted(String connection) { // GIVEN var callbackMock = mock(TbMsgCallback.class); var msg = getTbMsgWithCallback(callbackMock); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); - ruleNode.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(getUntilTime()); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN defaultTbContext.tellNext(msg, connection); @@ -227,30 +224,27 @@ class DefaultTbContextTest { // THEN then(nodeCtxMock).should().getChainActor(); then(nodeCtxMock).shouldHaveNoMoreInteractions(); - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); then(mainCtxMock).should().persistDebugOutput(TENANT_ID, RULE_NODE_ID, msg, connection, null, null); then(mainCtxMock).shouldHaveNoMoreInteractions(); checkTellNextCommonLogic(callbackMock, connection, msg); } - private static Stream givenDebugStrategyAllEventsAndConnection_whenTellNext_thenVerifyDebugOutputPersisted() { + private static Stream givenDebugAllEventsAndConnection_whenTellNext_thenVerifyDebugOutputPersisted() { return failureAndSuccessConnection(); } @Test - public void givenDebugStrategyAllEventsAndFailureAndSuccessConnection_whenTellNext_thenVerifyDebugOutputPersistedForAllEvents() { + public void givenDebugAllEventsAndFailureAndSuccessConnection_whenTellNext_thenVerifyDebugOutputPersistedForAllEvents() { // GIVEN var callbackMock = mock(TbMsgCallback.class); var msg = getTbMsgWithCallback(callbackMock); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); - ruleNode.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(getUntilTime()); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN Set connections = failureAndSuccessConnection().collect(Collectors.toSet()); @@ -259,8 +253,6 @@ class DefaultTbContextTest { // THEN then(nodeCtxMock).should().getChainActor(); then(nodeCtxMock).shouldHaveNoMoreInteractions(); - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); var nodeConnectionsCaptor = ArgumentCaptor.forClass(String.class); int wantedNumberOfInvocations = connections.size(); then(mainCtxMock).should(times(wantedNumberOfInvocations)).persistDebugOutput(eq(TENANT_ID), eq(RULE_NODE_ID), eq(msg), nodeConnectionsCaptor.capture(), nullable(Throwable.class), nullable(String.class)); @@ -272,18 +264,17 @@ class DefaultTbContextTest { @MethodSource @ParameterizedTest - void givenDebugStrategyAllThenOnlyFailureEventsAndConnection_whenTellNext_thenVerifyDebugOutputPersisted(String connection) { + void givenDebugAllThenOnlyFailureEventsAndConnection_whenTellNext_thenVerifyDebugOutputPersisted(String connection) { // GIVEN var callbackMock = mock(TbMsgCallback.class); var msg = getTbMsgWithCallback(callbackMock); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); - ruleNode.setDebugStrategy(DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(getUntilTime()); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN defaultTbContext.tellNext(msg, connection); @@ -291,30 +282,27 @@ class DefaultTbContextTest { // THEN then(nodeCtxMock).should().getChainActor(); then(nodeCtxMock).shouldHaveNoMoreInteractions(); - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); then(mainCtxMock).should().persistDebugOutput(TENANT_ID, RULE_NODE_ID, msg, connection, null, null); then(mainCtxMock).shouldHaveNoMoreInteractions(); checkTellNextCommonLogic(callbackMock, connection, msg); } - private static Stream givenDebugStrategyAllThenOnlyFailureEventsAndConnection_whenTellNext_thenVerifyDebugOutputPersisted() { + private static Stream givenDebugAllThenOnlyFailureEventsAndConnection_whenTellNext_thenVerifyDebugOutputPersisted() { return failureAndSuccessConnection(); } @Test - public void givenDebugStrategyAllThenOnlyEventsAndFailureAndSuccessConnection_whenTellNext_thenVerifyDebugOutputPersistedForAllEvents() { + public void givenDebugAllThenOnlyEventsAndFailureAndSuccessConnection_whenTellNext_thenVerifyDebugOutputPersistedForAllEvents() { // GIVEN var callbackMock = mock(TbMsgCallback.class); var msg = getTbMsgWithCallback(callbackMock); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); - ruleNode.setDebugStrategy(DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS); + ruleNode.setDebugFailures(true); + ruleNode.setDebugAllUntil(getUntilTime()); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN Set connections = failureAndSuccessConnection().collect(Collectors.toSet()); @@ -323,8 +311,6 @@ class DefaultTbContextTest { // THEN then(nodeCtxMock).should().getChainActor(); then(nodeCtxMock).shouldHaveNoMoreInteractions(); - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); var nodeConnectionsCaptor = ArgumentCaptor.forClass(String.class); int wantedNumberOfInvocations = connections.size(); then(mainCtxMock).should(times(wantedNumberOfInvocations)).persistDebugOutput(eq(TENANT_ID), eq(RULE_NODE_ID), eq(msg), nodeConnectionsCaptor.capture(), nullable(Throwable.class), nullable(String.class)); @@ -339,12 +325,12 @@ class DefaultTbContextTest { } @Test - public void givenDebugStrategyOnlyFailureEventsAndFailureConnection_whenOutput_thenVerifyDebugOutputPersisted() { + public void givenDebugFailuresEventsAndFailureConnection_whenOutput_thenVerifyDebugOutputPersisted() { // GIVEN var msgMock = mock(TbMsg.class); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ONLY_FAILURE_EVENTS); + ruleNode.setDebugFailures(true); given(msgMock.popFormStack()).willReturn(new TbMsgProcessingStackItem(RULE_CHAIN_ID, RULE_NODE_ID)); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); @@ -361,12 +347,12 @@ class DefaultTbContextTest { } @Test - public void givenDebugStrategyOnlyFailureEventsAndSuccessConnection_whenOutput_thenVerifyDebugOutputNotPersisted() { + public void givenDebugFailuresEventsAndSuccessConnection_whenOutput_thenVerifyDebugOutputNotPersisted() { // GIVEN var msgMock = mock(TbMsg.class); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ONLY_FAILURE_EVENTS); + ruleNode.setDebugFailures(true); given(msgMock.popFormStack()).willReturn(new TbMsgProcessingStackItem(RULE_CHAIN_ID, RULE_NODE_ID)); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); @@ -382,12 +368,13 @@ class DefaultTbContextTest { @ParameterizedTest @ValueSource(strings = {TbNodeConnectionType.SUCCESS, TbNodeConnectionType.FAILURE}) - void givenDebugStrategyDisabled_whenOutput_thenVerifyDebugOutputNotPersisted(String nodeConnection) { + void givenDebugDisabled_whenOutput_thenVerifyDebugOutputNotPersisted(String nodeConnection) { // GIVEN var msgMock = mock(TbMsg.class); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.DISABLED); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(0); given(msgMock.popFormStack()).willReturn(new TbMsgProcessingStackItem(RULE_CHAIN_ID, RULE_NODE_ID)); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); @@ -403,25 +390,23 @@ class DefaultTbContextTest { @ParameterizedTest @ValueSource(strings = {TbNodeConnectionType.SUCCESS, TbNodeConnectionType.FAILURE}) - void givenDebugStrategyAllEvents_whenOutput_thenVerifyDebugOutputPersisted(String nodeConnection) { + void givenDebugAllEvents_whenOutput_thenVerifyDebugOutputPersisted(String nodeConnection) { // GIVEN var msgMock = mock(TbMsg.class); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(getUntilTime()); given(msgMock.popFormStack()).willReturn(new TbMsgProcessingStackItem(RULE_CHAIN_ID, RULE_NODE_ID)); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN defaultTbContext.output(msgMock, nodeConnection); // THEN checkOutputCommonLogic(msgMock, nodeConnection); - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); then(mainCtxMock).should().persistDebugOutput(TENANT_ID, RULE_NODE_ID, msgMock, nodeConnection, null, null); then(mainCtxMock).shouldHaveNoMoreInteractions(); then(nodeCtxMock).shouldHaveNoMoreInteractions(); @@ -429,25 +414,23 @@ class DefaultTbContextTest { @ParameterizedTest @ValueSource(strings = {TbNodeConnectionType.SUCCESS, TbNodeConnectionType.FAILURE}) - void givenDebugStrategyAllThenOnlyFailureEvents_whenOutput_thenVerifyDebugOutputPersisted(String nodeConnection) { + void givenDebugAllThenOnlyFailureEvents_whenOutput_thenVerifyDebugOutputPersisted(String nodeConnection) { // GIVEN var msgMock = mock(TbMsg.class); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(getUntilTime()); given(msgMock.popFormStack()).willReturn(new TbMsgProcessingStackItem(RULE_CHAIN_ID, RULE_NODE_ID)); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN defaultTbContext.output(msgMock, nodeConnection); // THEN checkOutputCommonLogic(msgMock, nodeConnection); - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); then(mainCtxMock).should().persistDebugOutput(TENANT_ID, RULE_NODE_ID, msgMock, nodeConnection, null, null); then(mainCtxMock).shouldHaveNoMoreInteractions(); then(nodeCtxMock).shouldHaveNoMoreInteractions(); @@ -459,7 +442,8 @@ class DefaultTbContextTest { var msgMock = mock(TbMsg.class); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.DISABLED); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(0); given(msgMock.popFormStack()).willReturn(null); TbMsgCallback callbackMock = mock(TbMsgCallback.class); given(msgMock.getCallback()).willReturn(callbackMock); @@ -476,19 +460,18 @@ class DefaultTbContextTest { } @Test - public void givenEmptyStackAndDebugStrategyAllEvents_whenOutput_thenVerifyMsgAckAndDebugOutputPersisted() { + public void givenEmptyStackAndDebugAllEvents_whenOutput_thenVerifyMsgAckAndDebugOutputPersisted() { // GIVEN var msgMock = mock(TbMsg.class); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ALL_EVENTS); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(getUntilTime()); given(msgMock.popFormStack()).willReturn(null); TbMsgCallback callbackMock = mock(TbMsgCallback.class); given(msgMock.getCallback()).willReturn(callbackMock); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN defaultTbContext.output(msgMock, TbNodeConnectionType.SUCCESS); @@ -502,19 +485,18 @@ class DefaultTbContextTest { } @Test - public void givenEmptyStackAndDebugStrategyAllThenOnlyFailureEvents_whenOutput_thenVerifyMsgAckAndDebugOutputPersisted() { + public void givenEmptyStackAndDebugAllThenOnlyFailureEvents_whenOutput_thenVerifyMsgAckAndDebugOutputPersisted() { // GIVEN var msgMock = mock(TbMsg.class); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); + ruleNode.setDebugFailures(true); + ruleNode.setDebugAllUntil(getUntilTime()); given(msgMock.popFormStack()).willReturn(null); TbMsgCallback callbackMock = mock(TbMsgCallback.class); given(msgMock.getCallback()).willReturn(callbackMock); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN defaultTbContext.output(msgMock, TbNodeConnectionType.SUCCESS); @@ -528,13 +510,13 @@ class DefaultTbContextTest { } @Test - public void givenDebugStrategyOnlyFailureEvents_whenEnqueueForTellFailure_thenVerifyDebugOutputPersisted() { + public void givenDebugFailuresEvents_whenEnqueueForTellFailure_thenVerifyDebugOutputPersisted() { // GIVEN var msg = getTbMsgWithQueueName(); var tpi = new TopicPartitionInfo(DataConstants.MAIN_QUEUE_TOPIC, TENANT_ID, 0, true); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ONLY_FAILURE_EVENTS); + ruleNode.setDebugFailures(true); var tbClusterServiceMock = mock(TbClusterService.class); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); @@ -561,13 +543,14 @@ class DefaultTbContextTest { } @Test - public void givenDebugStrategyDisabled_whenEnqueueForTellFailure_thenVerifyDebugOutputNotPersisted() { + public void givenDebugDisabled_whenEnqueueForTellFailure_thenVerifyDebugOutputNotPersisted() { // GIVEN var msg = getTbMsgWithQueueName(); var tpi = new TopicPartitionInfo(DataConstants.MAIN_QUEUE_TOPIC, TENANT_ID, 0, true); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.DISABLED); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(0); var tbClusterServiceMock = mock(TbClusterService.class); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); @@ -588,21 +571,20 @@ class DefaultTbContextTest { } @Test - public void givenDebugStrategyAllEvents_whenEnqueueForTellFailure_thenVerifyDebugOutputPersisted() { + public void givenDebugAllEvents_whenEnqueueForTellFailure_thenVerifyDebugOutputPersisted() { // GIVEN var msg = getTbMsgWithQueueName(); var tpi = new TopicPartitionInfo(DataConstants.MAIN_QUEUE_TOPIC, TENANT_ID, 0, true); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ALL_EVENTS); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(getUntilTime()); var tbClusterServiceMock = mock(TbClusterService.class); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(mainCtxMock.resolve(any(ServiceType.class), anyString(), any(TenantId.class), any(EntityId.class))).willReturn(tpi); given(mainCtxMock.getClusterService()).willReturn(tbClusterServiceMock); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN defaultTbContext.enqueueForTellFailure(msg, EXCEPTION); @@ -618,8 +600,6 @@ class DefaultTbContextTest { .ignoringFields("id", "ctx") .isEqualTo(expectedTbMsg); then(mainCtxMock).should().getClusterService(); - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); then(mainCtxMock).shouldHaveNoMoreInteractions(); then(tbClusterServiceMock).shouldHaveNoMoreInteractions(); } @@ -655,23 +635,20 @@ class DefaultTbContextTest { @MethodSource @ParameterizedTest - void givenDebugStrategyOptions_whenEnqueueForTellNext_thenVerifyDebugOutputPersistedOnlyForAllEventsDebugStrategy(DebugStrategy debugStrategy, String connectionType) { + void givenDebugOptions_whenEnqueueForTellNext_thenVerifyDebugOutputPersistedOnlyForDebugAll(boolean debugFailures, long debugAllUntil, String connectionType) { // GIVEN var msg = getTbMsgWithQueueName(); var tpi = new TopicPartitionInfo(DataConstants.MAIN_QUEUE_TOPIC, TENANT_ID, 0, true); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(debugStrategy); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); + ruleNode.setDebugFailures(debugFailures); + ruleNode.setDebugAllUntil(debugAllUntil); var tbClusterServiceMock = mock(TbClusterService.class); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(mainCtxMock.resolve(any(ServiceType.class), anyString(), any(TenantId.class), any(EntityId.class))).willReturn(tpi); given(mainCtxMock.getClusterService()).willReturn(tbClusterServiceMock); - if (DebugStrategy.ALL_EVENTS.equals(debugStrategy) || DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS.equals(debugStrategy)) { - mockGetMaxRuleNodeDebugModeDurationMinutes(); - } // WHEN defaultTbContext.enqueueForTellNext(msg, connectionType); @@ -697,9 +674,7 @@ class DefaultTbContextTest { assertThat(simpleTbQueueCallback).isNotNull(); simpleTbQueueCallback.onSuccess(null); - if (DebugStrategy.ALL_EVENTS.equals(debugStrategy) || DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS.equals(debugStrategy)) { - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); + if (debugAllUntil > 0) { ArgumentCaptor tbMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); then(mainCtxMock).should().persistDebugOutput(eq(TENANT_ID), eq(RULE_NODE_ID), tbMsgCaptor.capture(), eq(connectionType), isNull(), isNull()); TbMsg actualTbMsg = tbMsgCaptor.getValue(); @@ -714,24 +689,21 @@ class DefaultTbContextTest { @MethodSource @ParameterizedTest - void givenDebugStrategyOptions_whenEnqueue_thenVerifyDebugOutputPersistedOnlyForAllEventsDebugStrategy(DebugStrategy debugStrategy) { + void givenDebugOptions_whenEnqueue_thenVerifyDebugOutputPersistedOnlyForDebugAll(boolean debugFailures, long debugAllUntil) { // GIVEN var msg = getTbMsgWithQueueName(); var tpi = new TopicPartitionInfo(DataConstants.MAIN_QUEUE_TOPIC, TENANT_ID, 0, true); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setQueueName(DataConstants.MAIN_QUEUE_NAME); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(debugStrategy); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); + ruleNode.setDebugFailures(debugFailures); + ruleNode.setDebugAllUntil(debugAllUntil); var tbClusterServiceMock = mock(TbClusterService.class); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(mainCtxMock.resolve(any(ServiceType.class), anyString(), any(TenantId.class), any(EntityId.class))).willReturn(tpi); given(mainCtxMock.getClusterService()).willReturn(tbClusterServiceMock); - if (DebugStrategy.ALL_EVENTS.equals(debugStrategy) || DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS.equals(debugStrategy)) { - mockGetMaxRuleNodeDebugModeDurationMinutes(); - } Consumer onFailure = mock(Consumer.class); Runnable onSuccess = mock(Runnable.class); @@ -760,9 +732,7 @@ class DefaultTbContextTest { assertThat(simpleTbQueueCallback).isNotNull(); simpleTbQueueCallback.onSuccess(null); - if (debugStrategy.isHasDuration()) { - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); + if (debugAllUntil > 0) { then(mainCtxMock).should().persistDebugOutput(eq(TENANT_ID), eq(RULE_NODE_ID), eq(msg), eq(TbNodeConnectionType.TO_ROOT_RULE_CHAIN), nullable(Throwable.class), nullable(String.class)); } then(mainCtxMock).should().getClusterService(); @@ -771,12 +741,13 @@ class DefaultTbContextTest { } @Test - public void givenDebugStrategyOnlyFailures_whenTellFailure_thenVerifyDebugOutputPersisted() { + public void givenDebugFailuress_whenTellFailure_thenVerifyDebugOutputPersisted() { // GIVEN var msg = getTbMsg(); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ONLY_FAILURE_EVENTS); + ruleNode.setDebugFailures(true); + ruleNode.setDebugAllUntil(0); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); @@ -801,12 +772,13 @@ class DefaultTbContextTest { } @Test - public void givenDebugStrategyDisabled_whenTellFailure_thenVerifyDebugOutputNotPersisted() { + public void givenDebugDisabled_whenTellFailure_thenVerifyDebugOutputNotPersisted() { // GIVEN var msg = getTbMsg(); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.DISABLED); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(0); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); @@ -829,17 +801,16 @@ class DefaultTbContextTest { } @Test - public void givenDebugStrategyAllEvents_whenTellFailure_thenVerifyDebugOutputPersisted() { + public void givenDebugAllEvents_whenTellFailure_thenVerifyDebugOutputPersisted() { // GIVEN var msg = getTbMsg(); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setDebugStrategy(DebugStrategy.ALL_EVENTS); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); + ruleNode.setDebugFailures(false); + ruleNode.setDebugAllUntil(getUntilTime()); given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); - mockGetMaxRuleNodeDebugModeDurationMinutes(); // WHEN defaultTbContext.tellFailure(msg, EXCEPTION); @@ -856,15 +827,14 @@ class DefaultTbContextTest { then(chainActorMock).shouldHaveNoMoreInteractions(); then(nodeCtxMock).should().getChainActor(); then(mainCtxMock).should().persistDebugOutput(TENANT_ID, RULE_NODE_ID, msg, TbNodeConnectionType.FAILURE, EXCEPTION, null); - then(mainCtxMock).should().getTenantProfileCache(); - then(mainCtxMock).should().getMaxRuleNodeDebugModeDurationMinutes(); then(mainCtxMock).shouldHaveNoMoreInteractions(); then(nodeCtxMock).shouldHaveNoMoreInteractions(); } @MethodSource @ParameterizedTest - void givenDebugStrategyAndConnectionAndPersistedResultOptions_whenTellNext_thenVerifyDebugOutputPersistence(DebugStrategy debugStrategy, + void givenDebugFailuresAndDebugAllAndConnectionAndPersistedResultOptions_whenTellNext_thenVerifyDebugOutputPersistence(boolean debugFailures, + long debugAllUntil, String connection, boolean shouldPersist, boolean shouldPersistAfterDurationTime) { @@ -873,16 +843,13 @@ class DefaultTbContextTest { var msg = getTbMsgWithCallback(callbackMock); var ruleNode = new RuleNode(RULE_NODE_ID); ruleNode.setRuleChainId(RULE_CHAIN_ID); - ruleNode.setLastUpdateTs(System.currentTimeMillis()); - ruleNode.setDebugStrategy(debugStrategy); + ruleNode.setDebugFailures(debugFailures); + ruleNode.setDebugAllUntil(debugAllUntil); if (shouldPersist) { given(nodeCtxMock.getTenantId()).willReturn(TENANT_ID); } given(nodeCtxMock.getSelf()).willReturn(ruleNode); given(nodeCtxMock.getChainActor()).willReturn(chainActorMock); - if (debugStrategy.isHasDuration()) { - mockGetMaxRuleNodeDebugModeDurationMinutes(); - } // WHEN defaultTbContext.tellNext(msg, connection); @@ -894,9 +861,7 @@ class DefaultTbContextTest { // GIVEN Mockito.clearInvocations(mainCtxMock); - if (debugStrategy.isHasDuration()) { - mockGetMaxRuleNodeDebugModeDurationMinutes(0); - } + ruleNode.setDebugAllUntil(0); // WHEN defaultTbContext.tellNext(msg, connection); @@ -956,34 +921,34 @@ class DefaultTbContextTest { simpleTbQueueCallback.onSuccess(null); } - private static Stream givenDebugStrategyOptions_whenEnqueueForTellNext_thenVerifyDebugOutputPersistedOnlyForAllEventsDebugStrategy() { + private static Stream givenDebugOptions_whenEnqueueForTellNext_thenVerifyDebugOutputPersistedOnlyForDebugAll() { return Stream.of( - Arguments.of(DebugStrategy.ALL_EVENTS, TbNodeConnectionType.OTHER), - Arguments.of(DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS, TbNodeConnectionType.OTHER), - Arguments.of(DebugStrategy.ONLY_FAILURE_EVENTS, TbNodeConnectionType.TRUE), - Arguments.of(DebugStrategy.DISABLED, TbNodeConnectionType.FALSE) + Arguments.of(false, getUntilTime(), TbNodeConnectionType.OTHER), + Arguments.of(true, getUntilTime(), TbNodeConnectionType.OTHER), + Arguments.of(true, 0, TbNodeConnectionType.TRUE), + Arguments.of(false, 0, TbNodeConnectionType.FALSE) ); } - private static Stream givenDebugStrategyOptions_whenEnqueue_thenVerifyDebugOutputPersistedOnlyForAllEventsDebugStrategy() { + private static Stream givenDebugOptions_whenEnqueue_thenVerifyDebugOutputPersistedOnlyForDebugAll() { return Stream.of( - Arguments.of(DebugStrategy.ALL_EVENTS), - Arguments.of(DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS), - Arguments.of(DebugStrategy.ONLY_FAILURE_EVENTS), - Arguments.of(DebugStrategy.DISABLED) + Arguments.of(false, getUntilTime()), + Arguments.of(true, getUntilTime()), + Arguments.of(true, 0), + Arguments.of(false, 0) ); } - private static Stream givenDebugStrategyAndConnectionAndPersistedResultOptions_whenTellNext_thenVerifyDebugOutputPersistence() { + private static Stream givenDebugFailuresAndDebugAllAndConnectionAndPersistedResultOptions_whenTellNext_thenVerifyDebugOutputPersistence() { return Stream.of( - Arguments.of(DebugStrategy.ALL_EVENTS, TbNodeConnectionType.SUCCESS, true, false), - Arguments.of(DebugStrategy.ALL_EVENTS, TbNodeConnectionType.FAILURE, true, false), - Arguments.of(DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS, TbNodeConnectionType.SUCCESS, true, false), - Arguments.of(DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS, TbNodeConnectionType.FAILURE, true, true), - Arguments.of(DebugStrategy.ONLY_FAILURE_EVENTS, TbNodeConnectionType.SUCCESS, false, false), - Arguments.of(DebugStrategy.ONLY_FAILURE_EVENTS, TbNodeConnectionType.FAILURE, true, true), - Arguments.of(DebugStrategy.DISABLED, TbNodeConnectionType.SUCCESS, false, false), - Arguments.of(DebugStrategy.DISABLED, TbNodeConnectionType.FAILURE, false, false) + Arguments.of(false, getUntilTime(), TbNodeConnectionType.SUCCESS, true, false), + Arguments.of(false, getUntilTime(), TbNodeConnectionType.FAILURE, true, false), + Arguments.of(true, getUntilTime(), TbNodeConnectionType.SUCCESS, true, false), + Arguments.of(true, getUntilTime(), TbNodeConnectionType.FAILURE, true, true), + Arguments.of(true, 0, TbNodeConnectionType.SUCCESS, false, false), + Arguments.of(true, 0, TbNodeConnectionType.FAILURE, true, true), + Arguments.of(false, 0, TbNodeConnectionType.SUCCESS, false, false), + Arguments.of(false, 0, TbNodeConnectionType.FAILURE, false, false) ); } @@ -999,21 +964,11 @@ class DefaultTbContextTest { return TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TENANT_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); } - private void mockGetMaxRuleNodeDebugModeDurationMinutes() { - mockGetMaxRuleNodeDebugModeDurationMinutes(15); + private static long getUntilTime() { + return getUntilTime(15); } - private void mockGetMaxRuleNodeDebugModeDurationMinutes(int maxRuleNodeDebugModeDurationMinutes) { - var tbTenantProfileCacheMock = mock(TbTenantProfileCache.class); - var tenantProfileMock = mock(TenantProfile.class); - var tenantProfileDataMock = mock(TenantProfileData.class); - var tenantProfileConfigurationMock = mock(TenantProfileConfiguration.class); - - given(mainCtxMock.getTenantProfileCache()).willReturn(tbTenantProfileCacheMock); - given(tbTenantProfileCacheMock.get(TENANT_ID)).willReturn(tenantProfileMock); - given(tenantProfileMock.getProfileData()).willReturn(tenantProfileDataMock); - given(tenantProfileDataMock.getConfiguration()).willReturn(tenantProfileConfigurationMock); - given(tenantProfileConfigurationMock.getMaxRuleNodeDebugModeDurationMinutes(anyInt())).willReturn(maxRuleNodeDebugModeDurationMinutes); + private static long getUntilTime(int maxRuleNodeDebugModeDurationMinutes) { + return System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(maxRuleNodeDebugModeDurationMinutes); } - } diff --git a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java index a09ca1d148..3220620dfd 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -71,7 +71,6 @@ import org.thingsboard.server.common.data.query.EntityKeyValueType; import org.thingsboard.server.common.data.query.FilterPredicateValue; import org.thingsboard.server.common.data.query.NumericFilterPredicate; import org.thingsboard.server.common.data.queue.Queue; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; @@ -164,7 +163,8 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { } private RuleChainId getEdgeRootRuleChainId() throws Exception { - return doGetTypedWithPageLink("/api/ruleChains?type={type}&", new TypeReference>() {}, + return doGetTypedWithPageLink("/api/ruleChains?type={type}&", new TypeReference>() { + }, new PageLink(100, 0, "Edge Root Rule Chain"), "EDGE") .getData().get(0).getId(); @@ -208,7 +208,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { protected void updateRootRuleChainMetadata() throws Exception { RuleChainId rootRuleChainId = getEdgeRootRuleChainId(); RuleChainMetaData rootRuleChainMetadata = doGet("/api/ruleChain/" + rootRuleChainId.getId().toString() + "/metadata", RuleChainMetaData.class); - rootRuleChainMetadata.getNodes().forEach(n -> n.setDebugStrategy(DebugStrategy.ALL_EVENTS)); + rootRuleChainMetadata.getNodes().forEach(n -> n.setDebugAll(true)); doPost("/api/ruleChain/metadata", rootRuleChainMetadata, RuleChainMetaData.class); } diff --git a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java index 2dc2bd42f3..224c21ffc5 100644 --- a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java @@ -23,7 +23,6 @@ import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; import org.thingsboard.rule.engine.util.TbMsgSource; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.RuleChainId; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; @@ -229,7 +228,7 @@ public class RuleChainEdgeTest extends AbstractEdgeTest { // update metadata for root rule chain edgeImitator.expectMessageAmount(1); - metaData.getNodes().forEach(n -> n.setDebugStrategy(DebugStrategy.ALL_EVENTS)); + metaData.getNodes().forEach(n -> n.setDebugAll(true)); doPost("/api/ruleChain/metadata", metaData, RuleChainMetaData.class); Assert.assertTrue(edgeImitator.waitForMessages()); ruleChainUpdateMsgOpt = edgeImitator.findMessageByType(RuleChainUpdateMsg.class); diff --git a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java index 3af4c012e0..0798ff8fdb 100644 --- a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java @@ -43,7 +43,6 @@ import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.NodeConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; @@ -143,7 +142,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule ruleNode1.setName("Simple Rule Node 1"); ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode1.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode1.setDebugAll(true); TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); configuration1.setFetchTo(TbMsgSource.METADATA); configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1")); @@ -153,7 +152,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode2.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode2.setDebugAll(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setFetchTo(TbMsgSource.METADATA); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); @@ -249,7 +248,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule ruleNode1.setName("Simple Rule Node 1"); ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode1.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode1.setDebugAll(true); TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); configuration1.setFetchTo(TbMsgSource.METADATA); configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1")); @@ -258,7 +257,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule RuleNode ruleNode12 = new RuleNode(); ruleNode12.setName("Simple Rule Node 1"); ruleNode12.setType(org.thingsboard.rule.engine.flow.TbRuleChainInputNode.class.getName()); - ruleNode12.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode12.setDebugAll(true); TbRuleChainInputNodeConfiguration configuration12 = new TbRuleChainInputNodeConfiguration(); configuration12.setRuleChainId(secondaryRuleChain.getId().getId().toString()); ruleNode12.setConfiguration(JacksonUtil.valueToTree(configuration12)); @@ -283,7 +282,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode2.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode2.setDebugAll(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setFetchTo(TbMsgSource.METADATA); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); diff --git a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java index dd148748ca..efc817f6d2 100644 --- a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java @@ -36,7 +36,6 @@ import org.thingsboard.server.common.data.event.EventType; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.msg.TbMsgType; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleNode; @@ -98,7 +97,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac ruleNode.setName("Simple Rule Node"); ruleNode.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode.setDebugAll(true); TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration(); configuration.setFetchTo(TbMsgSource.METADATA); configuration.setServerAttributeNames(Collections.singletonList("serverAttributeKey")); diff --git a/application/src/test/java/org/thingsboard/server/service/housekeeper/HousekeeperServiceTest.java b/application/src/test/java/org/thingsboard/server/service/housekeeper/HousekeeperServiceTest.java index 752624fa51..a3a2b55c76 100644 --- a/application/src/test/java/org/thingsboard/server/service/housekeeper/HousekeeperServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/housekeeper/HousekeeperServiceTest.java @@ -58,7 +58,6 @@ import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; @@ -463,7 +462,7 @@ public class HousekeeperServiceTest extends AbstractControllerTest { ruleNode1.setName("Simple Rule Node 1"); ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode1.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode1.setDebugAll(true); TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1")); ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration1)); @@ -472,7 +471,7 @@ public class HousekeeperServiceTest extends AbstractControllerTest { ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode2.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode2.setDebugAll(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2)); diff --git a/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java b/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java index 06bc670804..fdbf6b1e68 100644 --- a/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java @@ -65,7 +65,6 @@ import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; @@ -472,7 +471,7 @@ public class ExportImportServiceSqlTest extends AbstractControllerTest { RuleNode ruleNode1 = new RuleNode(); ruleNode1.setName("Generator 1"); ruleNode1.setType(TbMsgGeneratorNode.class.getName()); - ruleNode1.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode1.setDebugAllUntil(System.currentTimeMillis()); TbMsgGeneratorNodeConfiguration configuration1 = new TbMsgGeneratorNodeConfiguration(); configuration1.setOriginatorType(originatorId.getEntityType()); configuration1.setOriginatorId(originatorId.getId().toString()); @@ -482,7 +481,7 @@ public class ExportImportServiceSqlTest extends AbstractControllerTest { ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode2.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode2.setDebugAllUntil(System.currentTimeMillis()); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2)); @@ -511,7 +510,7 @@ public class ExportImportServiceSqlTest extends AbstractControllerTest { ruleNode1.setName("Simple Rule Node 1"); ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode1.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode1.setDebugAllUntil(System.currentTimeMillis()); TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1")); ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration1)); @@ -520,7 +519,7 @@ public class ExportImportServiceSqlTest extends AbstractControllerTest { ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode2.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode2.setDebugAllUntil(System.currentTimeMillis()); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2)); diff --git a/application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java b/application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java index 21f6363f5f..194aaee8e0 100644 --- a/application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java @@ -65,7 +65,6 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; @@ -871,7 +870,7 @@ public class VersionControlTest extends AbstractControllerTest { RuleNode ruleNode1 = new RuleNode(); ruleNode1.setName("Generator 1"); ruleNode1.setType(TbMsgGeneratorNode.class.getName()); - ruleNode1.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode1.setDebugAll(true); TbMsgGeneratorNodeConfiguration configuration1 = new TbMsgGeneratorNodeConfiguration(); configuration1.setOriginatorType(originatorId.getEntityType()); configuration1.setOriginatorId(originatorId.getId().toString()); @@ -881,7 +880,7 @@ public class VersionControlTest extends AbstractControllerTest { ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode2.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode2.setDebugAll(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2)); @@ -909,7 +908,7 @@ public class VersionControlTest extends AbstractControllerTest { ruleNode1.setName("Simple Rule Node 1"); ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode1.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode1.setDebugAll(true); TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1")); ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration1)); @@ -918,7 +917,7 @@ public class VersionControlTest extends AbstractControllerTest { ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); - ruleNode2.setDebugStrategy(DebugStrategy.ALL_EVENTS); + ruleNode2.setDebugAll(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration2)); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/DebugStrategy.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/DebugStrategy.java deleted file mode 100644 index a065c9065f..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/DebugStrategy.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright © 2016-2024 The Thingsboard Authors - * - * 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. - */ -package org.thingsboard.server.common.data.rule; - -import lombok.Getter; -import org.thingsboard.server.common.data.msg.TbNodeConnectionType; - -import java.util.Set; -import java.util.concurrent.TimeUnit; - -@Getter -public enum DebugStrategy { - DISABLED(0, false), - ALL_EVENTS(1, true), - ALL_THEN_ONLY_FAILURE_EVENTS(2, true), - ONLY_FAILURE_EVENTS(3, false); - - private final int protoNumber; - private final boolean hasDuration; - - DebugStrategy(int protoNumber, boolean hasDuration) { - this.protoNumber = protoNumber; - this.hasDuration = hasDuration; - } - - public boolean shouldPersistDebugInput(long lastUpdateTs, long msgTs, int debugModeDurationMinutes) { - return isAllEventsStrategyAndMsgTsWithinDebugDuration(lastUpdateTs, msgTs, debugModeDurationMinutes); - } - - public boolean shouldPersistDebugOutputForAllEvents(long lastUpdateTs, long msgTs, int debugModeDurationMinutes) { - return this.isAllEventsStrategyAndMsgTsWithinDebugDuration(lastUpdateTs, msgTs, debugModeDurationMinutes); - } - - public boolean shouldPersistDebugForFailureEvent(Set nodeConnections) { - return isFailureStrategy() && nodeConnections.contains(TbNodeConnectionType.FAILURE); - } - - public boolean shouldPersistDebugForFailureEvent(String nodeConnection) { - return isFailureStrategy() && TbNodeConnectionType.FAILURE.equals(nodeConnection); - } - - private boolean isFailureStrategy() { - return DebugStrategy.ONLY_FAILURE_EVENTS.equals(this) || DebugStrategy.ALL_THEN_ONLY_FAILURE_EVENTS.equals(this); - } - - private boolean isAllEventsStrategyAndMsgTsWithinDebugDuration(long lastUpdateTs, long msgTs, int debugModeDurationMinutes) { - return this.hasDuration && isMsgTsWithinDebugDuration(lastUpdateTs, msgTs, debugModeDurationMinutes); - } - - private boolean isMsgTsWithinDebugDuration(long lastUpdateTs, long msgCreationTs, int debugModeDurationMinutes) { - if (debugModeDurationMinutes <= 0) { - return true; - } - return msgCreationTs < lastUpdateTs + TimeUnit.MINUTES.toMillis(debugModeDurationMinutes); - } - -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java index 35601afe02..bbc244676c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java @@ -47,10 +47,12 @@ public class RuleNode extends BaseDataWithAdditionalInfo implements @Length(fieldName = "name") @Schema(description = "User defined name of the rule node. Used on UI and for logging. ", example = "Process sensor reading") private String name; - @Schema(description = "Timestamp of the last rule node update.") - private long lastUpdateTs; - @Schema(description = "Debug strategy. ", example = "ALL_EVENTS") - private DebugStrategy debugStrategy; + @Schema(description = "Debug failures. ", example = "false") + private boolean debugFailures; + @Schema(description = "Debug All. Used as a trigger for updating debugAllUntil.", example = "false") + private boolean debugAll; + @Schema(description = "Timestamp of the end time for the processing debug events.") + private long debugAllUntil; @Schema(description = "Enable/disable singleton mode. ", example = "false") private boolean singletonMode; @Schema(description = "Queue name. ", example = "Main") @@ -77,8 +79,9 @@ public class RuleNode extends BaseDataWithAdditionalInfo implements this.ruleChainId = ruleNode.getRuleChainId(); this.type = ruleNode.getType(); this.name = ruleNode.getName(); - this.lastUpdateTs = ruleNode.getLastUpdateTs(); - this.debugStrategy = ruleNode.getDebugStrategy(); + this.debugFailures = ruleNode.isDebugFailures(); + this.debugAll = ruleNode.isDebugAll(); + this.debugAllUntil = ruleNode.getDebugAllUntil(); this.singletonMode = ruleNode.isSingletonMode(); this.setConfiguration(ruleNode.getConfiguration()); this.externalId = ruleNode.getExternalId(); @@ -89,10 +92,6 @@ public class RuleNode extends BaseDataWithAdditionalInfo implements return name; } - public DebugStrategy getDebugStrategy() { - return debugStrategy == null ? DebugStrategy.DISABLED : debugStrategy; - } - public JsonNode getConfiguration() { return BaseDataWithAdditionalInfo.getJson(() -> configuration, () -> configurationBytes); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeDebugUtil.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeDebugUtil.java new file mode 100644 index 0000000000..c6a3b495c8 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeDebugUtil.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * 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. + */ +package org.thingsboard.server.common.data.rule; + +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; + +import java.util.Set; + +public final class RuleNodeDebugUtil { + private RuleNodeDebugUtil() {} + + public static boolean isDebugAllAvailable(RuleNode ruleNode) { + return ruleNode.getDebugAllUntil() > System.currentTimeMillis(); + } + + public static boolean isDebugAvailable(RuleNode ruleNode, String nodeConnection) { + return isDebugAllAvailable(ruleNode) || ruleNode.isDebugFailures() && TbNodeConnectionType.FAILURE.equals(nodeConnection); + } + + public static boolean isDebugFailuresAvailable(RuleNode ruleNode, Set nodeConnections) { + return isDebugFailuresAvailable(ruleNode) && nodeConnections.contains(TbNodeConnectionType.FAILURE); + } + + public static boolean isDebugFailuresAvailable(RuleNode ruleNode, String nodeConnection) { + return isDebugFailuresAvailable(ruleNode) && TbNodeConnectionType.FAILURE.equals(nodeConnection); + } + + public static boolean isDebugFailuresAvailable(RuleNode ruleNode) { + return ruleNode.isDebugFailures() || isDebugAllAvailable(ruleNode); + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index ff5c0ea426..1b36578a77 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java @@ -205,6 +205,9 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @Override public int getMaxRuleNodeDebugModeDurationMinutes(int systemMaxRuleNodeDebugModeDurationMinutes) { - return Math.min(systemMaxRuleNodeDebugModeDurationMinutes, maxRuleNodeDebugDurationMinutes); + if (maxRuleNodeDebugDurationMinutes > 0) { + return Math.min(systemMaxRuleNodeDebugModeDurationMinutes, maxRuleNodeDebugDurationMinutes); + } + return systemMaxRuleNodeDebugModeDurationMinutes; } } diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index 167e160648..379ea3b77b 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -162,13 +162,6 @@ message RuleChainMetadataUpdateMsg { string entity = 8; } -enum DebugStrategy { - DISABLED = 0; - ALL_EVENTS = 1; - ALL_THEN_ONLY_FAILURE_EVENTS = 2; - ONLY_FAILURE_EVENTS = 3; -} - message RuleNodeProto { option deprecated = true; int64 idMSB = 1; @@ -180,8 +173,8 @@ message RuleNodeProto { string additionalInfo = 7; bool singletonMode = 8; int32 configurationVersion = 9; - int64 lastUpdateTs = 10; - DebugStrategy debugStrategy = 11; + bool debugFailures = 10; + int64 debugAllUntil = 11; } message NodeConnectionInfoProto { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 4311bfa11d..fc987218cf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -398,7 +398,8 @@ public class ModelConstants { public static final String EVENT_MESSAGE_COLUMN_NAME = "e_message"; public static final String DEBUG_MODE = "debug_mode"; - public static final String DEBUG_STRATEGY = "debug_strategy"; + public static final String DEBUG_FAILURES = "debug_failures"; + public static final String DEBUG__ALL_UNTIL = "debug_all_until"; public static final String SINGLETON_MODE = "singleton_mode"; public static final String QUEUE_NAME = "queue_name"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeEntity.java index 278fde0d6d..d1efb19061 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeEntity.java @@ -19,14 +19,11 @@ import com.fasterxml.jackson.databind.JsonNode; import jakarta.persistence.Column; import jakarta.persistence.Convert; import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.Table; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.model.BaseSqlEntity; @@ -61,12 +58,11 @@ public class RuleNodeEntity extends BaseSqlEntity { @Column(name = ModelConstants.ADDITIONAL_INFO_PROPERTY) private JsonNode additionalInfo; - @Column(name = ModelConstants.LAST_UPDATE_TS_COLUMN) - private long lastUpdateTs; + @Column(name = ModelConstants.DEBUG_FAILURES) + private boolean debugFailures; - @Enumerated(EnumType.STRING) - @Column(name = ModelConstants.DEBUG_STRATEGY) - private DebugStrategy debugStrategy; + @Column(name = ModelConstants.DEBUG__ALL_UNTIL) + private long debugAllUntil; @Column(name = ModelConstants.SINGLETON_MODE) private boolean singletonMode; @@ -90,8 +86,8 @@ public class RuleNodeEntity extends BaseSqlEntity { } this.type = ruleNode.getType(); this.name = ruleNode.getName(); - this.lastUpdateTs = ruleNode.getLastUpdateTs(); - this.debugStrategy = ruleNode.getDebugStrategy(); + this.debugFailures = ruleNode.isDebugFailures(); + this.debugAllUntil = ruleNode.getDebugAllUntil(); this.singletonMode = ruleNode.isSingletonMode(); this.queueName = ruleNode.getQueueName(); this.configurationVersion = ruleNode.getConfigurationVersion(); @@ -111,8 +107,8 @@ public class RuleNodeEntity extends BaseSqlEntity { } ruleNode.setType(type); ruleNode.setName(name); - ruleNode.setLastUpdateTs(lastUpdateTs); - ruleNode.setDebugStrategy(debugStrategy); + ruleNode.setDebugFailures(debugFailures); + ruleNode.setDebugAllUntil(debugAllUntil); ruleNode.setSingletonMode(singletonMode); ruleNode.setQueueName(queueName); ruleNode.setConfigurationVersion(configurationVersion); diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index f141ef627e..74375b1c78 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -24,6 +24,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; @@ -44,7 +45,6 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.plugin.ComponentClusteringMode; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; -import org.thingsboard.server.common.data.rule.DebugStrategy; import org.thingsboard.server.common.data.rule.NodeConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; @@ -66,6 +66,8 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.service.validator.RuleChainDataValidator; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; +import org.thingsboard.server.dao.util.TimeUtils; import java.util.ArrayList; import java.util.Collection; @@ -77,6 +79,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; @@ -110,6 +113,12 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Autowired private DataValidator ruleChainValidator; + @Autowired + private TbTenantProfileCache tbTenantProfileCache; + + @Value("${actors.rule.node.max_debug_mode_duration:60}") + private int maxRuleNodeDebugModeDurationMinutes; + @Override @Transactional public RuleChain saveRuleChain(RuleChain ruleChain) { @@ -215,11 +224,16 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } RuleChainId ruleChainId = ruleChain.getId(); if (nodes != null) { - long lastUpdateTs = System.currentTimeMillis(); + long now = System.currentTimeMillis(); for (RuleNode node : toAddOrUpdate) { node.setRuleChainId(ruleChainId); node = ruleNodeUpdater.apply(node); - node.setLastUpdateTs(lastUpdateTs); + + if (node.isDebugAll()) { + int debugDuration = tbTenantProfileCache.get(tenantId).getDefaultProfileConfiguration().getMaxRuleNodeDebugModeDurationMinutes(maxRuleNodeDebugModeDurationMinutes); + node.setDebugAllUntil(now + TimeUnit.MINUTES.toMillis(debugDuration)); + } + RuleChainDataValidator.validateRuleNode(node); RuleNode savedNode = ruleNodeDao.save(tenantId, node); relations.add(new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(), @@ -264,7 +278,6 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC layout.remove("description"); layout.remove("ruleChainNodeId"); targetNode.setAdditionalInfo(layout); - targetNode.setDebugStrategy(DebugStrategy.DISABLED); targetNode = ruleNodeDao.save(tenantId, targetNode); EntityRelation sourceRuleChainToRuleNode = new EntityRelation(); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index c5f459773a..9e766392fc 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -181,8 +181,8 @@ CREATE TABLE IF NOT EXISTS rule_node ( configuration varchar(10000000), type varchar(255), name varchar(255), - last_update_ts bigint NOT NULL, - debug_strategy varchar(32) DEFAULT 'DISABLED', + debug_failures boolean, + debug_all_until bigint NOT NULL, singleton_mode boolean, queue_name varchar(255), external_id uuid diff --git a/monitoring/src/main/resources/root_rule_chain.json b/monitoring/src/main/resources/root_rule_chain.json index 1da16c9b09..9e057490aa 100644 --- a/monitoring/src/main/resources/root_rule_chain.json +++ b/monitoring/src/main/resources/root_rule_chain.json @@ -20,7 +20,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "Save Timeseries", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -35,7 +36,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", "name": "Save Attributes", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 1, "configuration": { @@ -53,7 +55,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", "name": "Message Type Switch", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -68,7 +71,8 @@ }, "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log RPC from Device", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -85,7 +89,8 @@ }, "type": "org.thingsboard.rule.engine.action.TbLogNode", "name": "Log Other", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -102,7 +107,8 @@ }, "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", "name": "RPC Call Request", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -117,7 +123,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbOriginatorTypeFilterNode", "name": "Is Entity Group", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -134,7 +141,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode", "name": "Post attributes or RPC request", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -152,7 +160,8 @@ }, "type": "org.thingsboard.rule.engine.transform.TbDuplicateMsgToGroupNode", "name": "Duplicate To Group Entities", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -169,7 +178,8 @@ }, "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", "name": "Device Profile Node", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -186,7 +196,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbJsFilterNode", "name": "Test JS script", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -204,7 +215,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbJsFilterNode", "name": "Test TBEL script", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -222,7 +234,8 @@ }, "type": "org.thingsboard.rule.engine.transform.TbTransformMsgNode", "name": "Add arrival timestamp", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -240,7 +253,8 @@ }, "type": "org.thingsboard.rule.engine.transform.TbTransformMsgNode", "name": "Calculate additional latencies", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -258,7 +272,8 @@ }, "type": "org.thingsboard.rule.engine.transform.TbChangeOriginatorNode", "name": "To latencies asset", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -287,7 +302,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "Save Timeseries", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -303,7 +319,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbCheckMessageNode", "name": "Has testData", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -323,7 +340,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "Save Timeseries with TTL", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "singletonMode": false, "configurationVersion": 0, "configuration": { diff --git a/msa/black-box-tests/src/test/resources/MqttRuleNodeTestMetadata.json b/msa/black-box-tests/src/test/resources/MqttRuleNodeTestMetadata.json index dc6a394a39..e6c93cffe1 100644 --- a/msa/black-box-tests/src/test/resources/MqttRuleNodeTestMetadata.json +++ b/msa/black-box-tests/src/test/resources/MqttRuleNodeTestMetadata.json @@ -9,7 +9,8 @@ }, "type": "org.thingsboard.rule.engine.mqtt.TbMqttNode", "name": "test mqtt", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "singletonMode": true, "queueName": "HighPriority", "configurationVersion": 0, @@ -36,7 +37,8 @@ }, "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", "name": "save timeseries", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "singletonMode": false, "configurationVersion": 0, "configuration": { @@ -54,7 +56,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", "name": "switch", - "debugStrategy": "DISABLED", + "debugFailures": false, + "debugAll": false, "singletonMode": false, "configurationVersion": 0, "configuration": { diff --git a/msa/black-box-tests/src/test/resources/RpcResponseRuleChainMetadata.json b/msa/black-box-tests/src/test/resources/RpcResponseRuleChainMetadata.json index 31eb3149f3..ddb9f8bec1 100644 --- a/msa/black-box-tests/src/test/resources/RpcResponseRuleChainMetadata.json +++ b/msa/black-box-tests/src/test/resources/RpcResponseRuleChainMetadata.json @@ -8,7 +8,8 @@ }, "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", "name": "msgTypeSwitch", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "configuration": { "version": 0 } @@ -20,7 +21,8 @@ }, "type": "org.thingsboard.rule.engine.transform.TbTransformMsgNode", "name": "formResponse", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "configuration": { "jsScript": "if (msg.method == \"getResponse\") {\n return {msg: {\"response\": \"requestReceived\"}, metadata: metadata, msgType: msgType};\n}\n\nreturn {msg: msg, metadata: metadata, msgType: msgType};" } @@ -32,7 +34,8 @@ }, "type": "org.thingsboard.rule.engine.rpc.TbSendRPCReplyNode", "name": "rpcReply", - "debugStrategy": "ALL_EVENTS", + "debugFailures": false, + "debugAll": true, "configuration": { "requestIdMetaDataAttribute": "requestId" } From 7495861080350353d6bc66c6c7cde4f982d0b2a3 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 12 Nov 2024 09:46:20 +0100 Subject: [PATCH 36/40] added validation for the debugAllUntil --- .../thingsboard/server/dao/rule/BaseRuleChainService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 74375b1c78..94eb1ad283 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -229,9 +229,13 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC node.setRuleChainId(ruleChainId); node = ruleNodeUpdater.apply(node); + int debugDuration = tbTenantProfileCache.get(tenantId).getDefaultProfileConfiguration().getMaxRuleNodeDebugModeDurationMinutes(maxRuleNodeDebugModeDurationMinutes); + long debugUntil = now + TimeUnit.MINUTES.toMillis(debugDuration); + if (node.isDebugAll()) { - int debugDuration = tbTenantProfileCache.get(tenantId).getDefaultProfileConfiguration().getMaxRuleNodeDebugModeDurationMinutes(maxRuleNodeDebugModeDurationMinutes); - node.setDebugAllUntil(now + TimeUnit.MINUTES.toMillis(debugDuration)); + node.setDebugAllUntil(debugUntil); + } else if (node.getDebugAllUntil() > debugUntil) { + throw new DataValidationException("Unable to update 'debugAllUntil' property. To reset the debug duration, please modify the 'debugAll' property instead."); } RuleChainDataValidator.validateRuleNode(node); From 78decec8da3893e3320cf529768508b821fa149b Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 12 Nov 2024 10:35:34 +0100 Subject: [PATCH 37/40] fixed default rule-chains creation --- .../org/thingsboard/server/service/install/InstallScripts.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java index 115208bc47..75c0c0873c 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java +++ b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java @@ -202,7 +202,7 @@ public class InstallScripts { ruleChain = ruleChainService.saveRuleChain(ruleChain, false); ruleChainMetaData.setRuleChainId(ruleChain.getId()); - ruleChainService.saveRuleChainMetaData(TenantId.SYS_TENANT_ID, ruleChainMetaData, Function.identity(), false); + ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData, Function.identity(), false); return ruleChain; } From cf377b00830f485506416ee333da430796e7373d Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 12 Nov 2024 11:04:42 +0100 Subject: [PATCH 38/40] fixed circular references --- .../org/thingsboard/server/dao/rule/BaseRuleChainService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 94eb1ad283..52f28db5db 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -25,6 +25,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; @@ -114,6 +115,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC private DataValidator ruleChainValidator; @Autowired + @Lazy private TbTenantProfileCache tbTenantProfileCache; @Value("${actors.rule.node.max_debug_mode_duration:60}") From f54e1882bfd8a12716cf1444ae6c8343700a450c Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 13 Nov 2024 13:56:46 +0100 Subject: [PATCH 39/40] Refactored due to common use of debug mode configuration --- .../server/actors/ActorSystemContext.java | 4 +- .../actors/ruleChain/DefaultTbContext.java | 6 +-- .../RuleChainActorMessageProcessor.java | 4 +- .../RuleNodeActorMessageProcessor.java | 8 ++-- .../controller/SystemInfoController.java | 6 +-- .../tenant/TenantMsgConstructorV1.java | 2 +- .../src/main/resources/thingsboard.yml | 5 +++ .../server/common/data/HasDebugMode.java | 33 ++++++++++++++ .../server/common/data/SystemParams.java | 2 +- .../server/common/data/rule/RuleNode.java | 3 +- .../common/data/rule/RuleNodeDebugUtil.java | 45 ------------------- .../DefaultTenantProfileConfiguration.java | 10 ++--- .../profile/TenantProfileConfiguration.java | 2 +- .../common/util/DebugModeUtil.java | 43 ++++++++++++++++++ .../server/dao/rule/BaseRuleChainService.java | 7 ++- 15 files changed, 108 insertions(+), 72 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/HasDebugMode.java delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeDebugUtil.java create mode 100644 common/util/src/main/java/org/thingsboard/common/util/DebugModeUtil.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 2920fa400a..e2a6f452c5 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -577,9 +577,9 @@ public class ActorSystemContext { @Getter private boolean externalNodeForceAck; - @Value("${actors.rule.node.max_debug_mode_duration:60}") + @Value("${debug_mode.max_duration:60}") @Getter - private int maxRuleNodeDebugModeDurationMinutes; + private int maxDebugModeDurationMinutes; @Value("${state.rule.node.deviceState.rateLimit:1:1,30:60,60:3600}") @Getter diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 000c260769..27c6dd19b7 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -64,7 +64,7 @@ import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleNode; -import org.thingsboard.server.common.data.rule.RuleNodeDebugUtil; +import org.thingsboard.common.util.DebugModeUtil; import org.thingsboard.server.common.data.rule.RuleNodeState; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbActorMsg; @@ -1002,9 +1002,9 @@ public class DefaultTbContext implements TbContext { private void persistDebugOutput(TbMsg msg, Set relationTypes, Throwable error, String failureMessage) { RuleNode ruleNode = nodeCtx.getSelf(); - if (RuleNodeDebugUtil.isDebugAllAvailable(ruleNode)) { + if (DebugModeUtil.isDebugAllAvailable(ruleNode)) { relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(getTenantId(), ruleNode.getId(), msg, relationType, error, failureMessage)); - } else if (RuleNodeDebugUtil.isDebugFailuresAvailable(ruleNode, relationTypes)) { + } else if (DebugModeUtil.isDebugFailuresAvailable(ruleNode, relationTypes)) { mainCtx.persistDebugOutput(getTenantId(), ruleNode.getId(), msg, TbNodeConnectionType.FAILURE, error, failureMessage); } } diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java index 636ea3fd07..460da228c3 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; -import org.thingsboard.server.common.data.rule.RuleNodeDebugUtil; +import org.thingsboard.common.util.DebugModeUtil; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.plugin.RuleNodeUpdatedMsg; @@ -256,7 +256,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor implements HasName { +public class RuleNode extends BaseDataWithAdditionalInfo implements HasName, HasDebugMode { private static final long serialVersionUID = -5656679015121235465L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeDebugUtil.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeDebugUtil.java deleted file mode 100644 index c6a3b495c8..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNodeDebugUtil.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright © 2016-2024 The Thingsboard Authors - * - * 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. - */ -package org.thingsboard.server.common.data.rule; - -import org.thingsboard.server.common.data.msg.TbNodeConnectionType; - -import java.util.Set; - -public final class RuleNodeDebugUtil { - private RuleNodeDebugUtil() {} - - public static boolean isDebugAllAvailable(RuleNode ruleNode) { - return ruleNode.getDebugAllUntil() > System.currentTimeMillis(); - } - - public static boolean isDebugAvailable(RuleNode ruleNode, String nodeConnection) { - return isDebugAllAvailable(ruleNode) || ruleNode.isDebugFailures() && TbNodeConnectionType.FAILURE.equals(nodeConnection); - } - - public static boolean isDebugFailuresAvailable(RuleNode ruleNode, Set nodeConnections) { - return isDebugFailuresAvailable(ruleNode) && nodeConnections.contains(TbNodeConnectionType.FAILURE); - } - - public static boolean isDebugFailuresAvailable(RuleNode ruleNode, String nodeConnection) { - return isDebugFailuresAvailable(ruleNode) && TbNodeConnectionType.FAILURE.equals(nodeConnection); - } - - public static boolean isDebugFailuresAvailable(RuleNode ruleNode) { - return ruleNode.isDebugFailures() || isDebugAllAvailable(ruleNode); - } - -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index 1b36578a77..540dafdd4a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java @@ -95,7 +95,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @Schema(example = "50") private int maxRuleNodeExecutionsPerMessage; @Schema(example = "15") - private int maxRuleNodeDebugDurationMinutes; + private int maxDebugDurationMinutes; @Schema(example = "0") private long maxEmails; @Schema(example = "true") @@ -204,10 +204,10 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura } @Override - public int getMaxRuleNodeDebugModeDurationMinutes(int systemMaxRuleNodeDebugModeDurationMinutes) { - if (maxRuleNodeDebugDurationMinutes > 0) { - return Math.min(systemMaxRuleNodeDebugModeDurationMinutes, maxRuleNodeDebugDurationMinutes); + public int getMaxDebugModeDurationMinutes(int systemMaxDebugModeDurationMinutes) { + if (maxDebugDurationMinutes > 0) { + return Math.min(systemMaxDebugModeDurationMinutes, maxDebugDurationMinutes); } - return systemMaxRuleNodeDebugModeDurationMinutes; + return systemMaxDebugModeDurationMinutes; } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java index af36a15c4f..12d66e5178 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/TenantProfileConfiguration.java @@ -52,6 +52,6 @@ public interface TenantProfileConfiguration extends Serializable { int getMaxRuleNodeExecsPerMessage(); @JsonIgnore - int getMaxRuleNodeDebugModeDurationMinutes(int systemMaxRuleNodeDebugModeDurationMinutes); + int getMaxDebugModeDurationMinutes(int systemMaxDebugModeDurationMinutes); } diff --git a/common/util/src/main/java/org/thingsboard/common/util/DebugModeUtil.java b/common/util/src/main/java/org/thingsboard/common/util/DebugModeUtil.java new file mode 100644 index 0000000000..0f4213f989 --- /dev/null +++ b/common/util/src/main/java/org/thingsboard/common/util/DebugModeUtil.java @@ -0,0 +1,43 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * 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. + */ +package org.thingsboard.common.util; + +import org.thingsboard.server.common.data.HasDebugMode; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; + +import java.util.Set; + +public final class DebugModeUtil { + private DebugModeUtil() { + } + + public static boolean isDebugAllAvailable(HasDebugMode debugMode) { + return debugMode.getDebugAllUntil() > System.currentTimeMillis(); + } + + public static boolean isDebugAvailable(HasDebugMode debugMode, String nodeConnection) { + return isDebugAllAvailable(debugMode) || debugMode.isDebugFailures() && TbNodeConnectionType.FAILURE.equals(nodeConnection); + } + + public static boolean isDebugFailuresAvailable(HasDebugMode debugMode, Set nodeConnections) { + return isDebugFailuresAvailable(debugMode) && nodeConnections.contains(TbNodeConnectionType.FAILURE); + } + + private static boolean isDebugFailuresAvailable(HasDebugMode debugMode) { + return debugMode.isDebugFailures() || isDebugAllAvailable(debugMode); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 52f28db5db..046a5532c4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -68,7 +68,6 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.service.validator.RuleChainDataValidator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.util.TimeUtils; import java.util.ArrayList; import java.util.Collection; @@ -118,8 +117,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Lazy private TbTenantProfileCache tbTenantProfileCache; - @Value("${actors.rule.node.max_debug_mode_duration:60}") - private int maxRuleNodeDebugModeDurationMinutes; + @Value("${debug_mode.max_duration:60}") + private int maxDebugModeDurationMinutes; @Override @Transactional @@ -231,7 +230,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC node.setRuleChainId(ruleChainId); node = ruleNodeUpdater.apply(node); - int debugDuration = tbTenantProfileCache.get(tenantId).getDefaultProfileConfiguration().getMaxRuleNodeDebugModeDurationMinutes(maxRuleNodeDebugModeDurationMinutes); + int debugDuration = tbTenantProfileCache.get(tenantId).getDefaultProfileConfiguration().getMaxDebugModeDurationMinutes(maxDebugModeDurationMinutes); long debugUntil = now + TimeUnit.MINUTES.toMillis(debugDuration); if (node.isDebugAll()) { From 2addd492669fb2b7b1e0d83746f76e2fc7dbe0ab Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 13 Nov 2024 14:30:19 +0100 Subject: [PATCH 40/40] minor refactoring --- .../server/controller/TenantProfileController.java | 2 +- .../edge/rpc/constructor/tenant/TenantMsgConstructorV1.java | 2 +- .../tenant/profile/DefaultTenantProfileConfiguration.java | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index 85660b5914..258014d6fe 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -151,7 +151,7 @@ public class TenantProfileController extends BaseController { " \"maxJSExecutions\": 5000000,\n" + " \"maxDPStorageDays\": 0,\n" + " \"maxRuleNodeExecutionsPerMessage\": 50,\n" + - " \"maxRuleNodeDebugDurationMinutes\": 15,\n" + + " \"maxDebugModeDurationMinutes\": 15,\n" + " \"maxEmails\": 0,\n" + " \"maxSms\": 0,\n" + " \"maxCreatedAlarms\": 1000,\n" + diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV1.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV1.java index 4db6a41084..a9accf572d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV1.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV1.java @@ -88,7 +88,7 @@ public class TenantMsgConstructorV1 implements TenantMsgConstructor { configuration.setMaxTransportDataPoints(0); configuration.setRuleEngineExceptionsTtlDays(0); configuration.setMaxRuleNodeExecutionsPerMessage(0); - configuration.setMaxDebugDurationMinutes(0); + configuration.setMaxDebugModeDurationMinutes(0); tenantProfileData.setConfiguration(configuration); tenantProfile.setProfileData(tenantProfileData); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index 540dafdd4a..40606a9959 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java @@ -95,7 +95,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @Schema(example = "50") private int maxRuleNodeExecutionsPerMessage; @Schema(example = "15") - private int maxDebugDurationMinutes; + private int maxDebugModeDurationMinutes; @Schema(example = "0") private long maxEmails; @Schema(example = "true") @@ -205,8 +205,8 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @Override public int getMaxDebugModeDurationMinutes(int systemMaxDebugModeDurationMinutes) { - if (maxDebugDurationMinutes > 0) { - return Math.min(systemMaxDebugModeDurationMinutes, maxDebugDurationMinutes); + if (maxDebugModeDurationMinutes > 0) { + return Math.min(systemMaxDebugModeDurationMinutes, maxDebugModeDurationMinutes); } return systemMaxDebugModeDurationMinutes; }