From 9afa0793150cfcf988b34285cd555d5a5ace7682 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Thu, 15 Dec 2016 11:39:10 +0200 Subject: [PATCH 01/12] gatling-mqtt skeleton impl --- pom.xml | 26 +++++++++++++ tools/pom.xml | 25 ++++++++++++- .../client/tools/MqttStressTestClient.java | 5 ++- .../client/tools/MqttStressTestTool.java | 5 ++- .../thingsboard/client/tools/RestClient.java | 7 ++-- .../client/tools/ResultAccumulator.java | 5 ++- .../main/shell/install-local-gatling-mqtt.sh | 25 +++++++++++++ .../client/tools/MqttSimulation.scala | 37 +++++++++++++++++++ 8 files changed, 128 insertions(+), 7 deletions(-) create mode 100755 tools/src/main/shell/install-local-gatling-mqtt.sh create mode 100644 tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala diff --git a/pom.xml b/pom.xml index fc0bbd088c..06e9821187 100755 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,10 @@ 2.19.1 3.0.2 2.6.1 + 2.2.3 + 1.0.0 + 2.2.1 + 3.2.2 @@ -281,6 +285,16 @@ + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin.version} + + + io.gatling + gatling-maven-plugin + ${gatling-plugin.version} + @@ -689,6 +703,18 @@ springfox-swagger2 ${springfox-swagger.version} + + io.gatling.highcharts + gatling-charts-highcharts + ${gatling.version} + test + + + com.github.mnogu + gatling-mqtt + ${gatling-mqtt.version} + test + diff --git a/tools/pom.xml b/tools/pom.xml index d78c4cad85..904ca91c26 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -78,6 +78,29 @@ mockito-all test - + + io.gatling.highcharts + gatling-charts-highcharts + test + + + com.github.mnogu + gatling-mqtt + test + + + + + + net.alchim31.maven + scala-maven-plugin + + + io.gatling + gatling-maven-plugin + ${gatling-plugin.version} + + + diff --git a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java index b0ddf73952..66970a9150 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java +++ b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java @@ -1,4 +1,4 @@ -package org.thingsboard.client.tools; /** +/** * Copyright © 2016 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,6 +13,9 @@ package org.thingsboard.client.tools; /** * See the License for the specific language governing permissions and * limitations under the License. */ + +package org.thingsboard.client.tools; + import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.*; diff --git a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java index 900d81fa7d..7852c09197 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java +++ b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java @@ -1,4 +1,4 @@ -package org.thingsboard.client.tools; /** +/** * Copyright © 2016 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,6 +13,9 @@ package org.thingsboard.client.tools; /** * See the License for the specific language governing permissions and * limitations under the License. */ + +package org.thingsboard.client.tools; + import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.security.DeviceCredentials; diff --git a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java index 8eda7b68d9..f30164f4b3 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java +++ b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java @@ -1,4 +1,4 @@ -package org.thingsboard.client.tools; /** +/** * Copyright © 2016 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,10 +13,11 @@ package org.thingsboard.client.tools; /** * See the License for the specific language governing permissions and * limitations under the License. */ + +package org.thingsboard.client.tools; + import com.fasterxml.jackson.databind.JsonNode; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpRequest; import org.springframework.http.ResponseEntity; import org.springframework.http.client.ClientHttpRequestExecution; diff --git a/tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java b/tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java index 5bba82a8e6..197a45b7de 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java +++ b/tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java @@ -1,4 +1,4 @@ -package org.thingsboard.client.tools; /** +/** * Copyright © 2016 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,6 +13,9 @@ package org.thingsboard.client.tools; /** * See the License for the specific language governing permissions and * limitations under the License. */ + +package org.thingsboard.client.tools; + import lombok.extern.slf4j.Slf4j; import java.util.concurrent.atomic.AtomicInteger; diff --git a/tools/src/main/shell/install-local-gatling-mqtt.sh b/tools/src/main/shell/install-local-gatling-mqtt.sh new file mode 100755 index 0000000000..fb500ff081 --- /dev/null +++ b/tools/src/main/shell/install-local-gatling-mqtt.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Copyright © 2016 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. +# + +git clone https://github.com/mnogu/gatling-mqtt.git /tmp/gatling-mqtt +cd /tmp/gatling-mqtt + +sbt assembly + +cd /tmp/gatling-mqtt/target/scala-2.11 + +mvn install:install-file -Dfile=gatling-mqtt-assembly-0.1.0-SNAPSHOT.jar -DgroupId=com.github.mnogu -DartifactId=gatling-mqtt -Dversion=1.0.0 -Dpackaging=jar \ No newline at end of file diff --git a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala new file mode 100644 index 0000000000..6ac17d74fa --- /dev/null +++ b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala @@ -0,0 +1,37 @@ +/** + * Copyright © 2016 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.client.tools + +import io.gatling.core.Predef._ +import org.fusesource.mqtt.client.QoS +import scala.concurrent.duration._ + +import com.github.mnogu.gatling.mqtt.Predef._ + +class MqttSimulation extends Simulation { + val mqttConf = mqtt + .host("tcp://localhost:1883") + .userName("A1_TEST_TOKEN") + + val scn = scenario("MQTT Test") + .exec(mqtt("request") + .publish("v1/devices/me/telemetry", "{\"key1\":\"value1\", \"key2\":\"value2\"}", QoS.AT_LEAST_ONCE, retain = false)) + + setUp( + scn + .inject(constantUsersPerSec(2) during(5 seconds))) + .protocols(mqttConf) +} \ No newline at end of file From ea9c8d2b61815fbef152d96cf619609b95916956 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Thu, 15 Dec 2016 16:15:27 +0200 Subject: [PATCH 02/12] small fix --- tools/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/pom.xml b/tools/pom.xml index 904ca91c26..552260be58 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -99,7 +99,6 @@ io.gatling gatling-maven-plugin - ${gatling-plugin.version} From 21d632744c04fdb6c82187ff22ecc2afe655f579 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Thu, 15 Dec 2016 16:20:56 +0200 Subject: [PATCH 03/12] Merge branch 'master' of https://github.com/thingsboard/thingsboard into gatling-mqtt # Conflicts: # tools/pom.xml # tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java --- tools/pom.xml | 224 +++++++++++++++++++++++++------------------------- 1 file changed, 112 insertions(+), 112 deletions(-) diff --git a/tools/pom.xml b/tools/pom.xml index 614ebd7d4d..c1b3cc0bac 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -17,121 +17,121 @@ --> - 4.0.0 - + 4.0.0 + + org.thingsboard + 1.0.1-SNAPSHOT + thingsboard + org.thingsboard - 1.0.1-SNAPSHOT - thingsboard - - org.thingsboard - tools - jar + tools + jar - Thingsboard Server Tools - http://thingsboard.org + Thingsboard Server Tools + http://thingsboard.org - - UTF-8 - ${basedir}/.. - + + UTF-8 + ${basedir}/.. + - - - org.thingsboard.common - data - - - org.springframework.boot - spring-boot-starter-web - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - - - org.slf4j - slf4j-api - - - org.slf4j - log4j-over-slf4j - - - ch.qos.logback - logback-core - - - ch.qos.logback - logback-classic - - - org.springframework - spring-test - - - junit - junit - test - - - org.mockito - mockito-all - test - - - io.gatling.highcharts - gatling-charts-highcharts - test - - - com.github.mnogu - gatling-mqtt - test - - + + + org.thingsboard.common + data + + + org.springframework.boot + spring-boot-starter-web + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + org.slf4j + slf4j-api + + + org.slf4j + log4j-over-slf4j + + + ch.qos.logback + logback-core + + + ch.qos.logback + logback-classic + + + org.springframework + spring-test + + + junit + junit + test + + + org.mockito + mockito-all + test + + + io.gatling.highcharts + gatling-charts-highcharts + test + + + com.github.mnogu + gatling-mqtt + test + + - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - - org.thingsboard.client.tools.MqttStressTestTool - - - - - - - - - net.alchim31.maven - scala-maven-plugin - - - io.gatling - gatling-maven-plugin - - - + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + org.thingsboard.client.tools.MqttStressTestTool + + + + + + + + + net.alchim31.maven + scala-maven-plugin + + + io.gatling + gatling-maven-plugin + + + From 4e5bb26cafe069b50a81dee0547667e9ccf029aa Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Thu, 15 Dec 2016 17:25:31 +0200 Subject: [PATCH 04/12] read from file --- .../client/tools/MqttStressTestTool.java | 25 ++++++++++++ .../client/tools/MqttSimulation.scala | 39 ++++++++++--------- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java index 08e5cfe6d3..05075ba9de 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java +++ b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java @@ -22,7 +22,12 @@ import org.eclipse.paho.client.mqttv3.IMqttToken; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.security.DeviceCredentials; +import java.io.BufferedWriter; +import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -58,16 +63,20 @@ public class MqttStressTestTool { List clients = new ArrayList<>(); List connectTokens = new ArrayList<>(); + List deviceCredentialsIds = new ArrayList<>(); for (int i = 0; i < params.getDeviceCount(); i++) { Device device = restClient.createDevice("Device " + UUID.randomUUID()); DeviceCredentials credentials = restClient.getCredentials(device.getId()); String[] mqttUrls = params.getMqttUrls(); String mqttURL = mqttUrls[i % mqttUrls.length]; MqttStressTestClient client = new MqttStressTestClient(results, mqttURL, credentials.getCredentialsId()); + deviceCredentialsIds.add(credentials.getCredentialsId()); connectTokens.add(client.connect()); clients.add(client); } + dumpDeviceCredentialsIdsToTmpFile(deviceCredentialsIds); + for (IMqttToken tokens : connectTokens) { tokens.waitForCompletion(); } @@ -114,4 +123,20 @@ public class MqttStressTestTool { scheduler.shutdownNow(); } + private static void dumpDeviceCredentialsIdsToTmpFile(List deviceCredentialsIds) throws IOException { + Path path = Paths.get("/tmp/mqtt.csv"); + try (BufferedWriter writer = Files.newBufferedWriter(path)) { + writer.write("deviceCredentialsId"); + writer.write('\n'); + deviceCredentialsIds.forEach((deviceCredentialsId) -> { + try { + writer.write(deviceCredentialsId); + writer.write('\n'); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + } + } diff --git a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala index 6ac17d74fa..d82ed5b7d4 100644 --- a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala +++ b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala @@ -1,18 +1,18 @@ /** - * Copyright © 2016 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. - */ + * Copyright © 2016 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.client.tools import io.gatling.core.Predef._ @@ -22,16 +22,19 @@ import scala.concurrent.duration._ import com.github.mnogu.gatling.mqtt.Predef._ class MqttSimulation extends Simulation { + val mqttConf = mqtt .host("tcp://localhost:1883") - .userName("A1_TEST_TOKEN") + .userName("${deviceCredentialsId}") val scn = scenario("MQTT Test") + .feed(csv("/tmp/mqtt.csv").circular) .exec(mqtt("request") .publish("v1/devices/me/telemetry", "{\"key1\":\"value1\", \"key2\":\"value2\"}", QoS.AT_LEAST_ONCE, retain = false)) setUp( - scn - .inject(constantUsersPerSec(2) during(5 seconds))) - .protocols(mqttConf) + scn + .inject(constantUsersPerSec(1000) during (5 seconds)) + ).protocols(mqttConf) + } \ No newline at end of file From d4b88f802a0bd0d9adfcfd4b5cfb7df6049c614c Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Wed, 4 Jan 2017 17:41:16 +0200 Subject: [PATCH 05/12] added connect-publish scenario --- docker/thingsboard/run_thingsboard.sh | 2 +- .../thingsboard/client/tools/TestParams.java | 2 +- .../client/tools/MqttSimulation.scala | 30 ++++++++++++++++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/docker/thingsboard/run_thingsboard.sh b/docker/thingsboard/run_thingsboard.sh index c41e53eb08..920d4ecb06 100755 --- a/docker/thingsboard/run_thingsboard.sh +++ b/docker/thingsboard/run_thingsboard.sh @@ -32,7 +32,7 @@ do done # Copying env variables into conf files -printenv | while read x; do echo export $x; done >> /usr/share/thingsboard/conf/thingsboard.conf +printenv | awk -F "=" '{print "export " $1 "='\''" $2 "'\''"}' >> /usr/share/thingsboard/conf/thingsboard.conf cat /usr/share/thingsboard/conf/thingsboard.conf diff --git a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java index eb1328b61e..1286f5efd9 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java +++ b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java @@ -27,7 +27,7 @@ public class TestParams { static final String TEST_PROPERTIES = "test.properties"; static final long DEFAULT_TEST_DURATION = TimeUnit.MINUTES.toMillis(1); static final long DEFAULT_TEST_INTERVAL = TimeUnit.MILLISECONDS.toMillis(100); - static final int DEFAULT_DEVICE_COUNT = 100; + static final int DEFAULT_DEVICE_COUNT = 25; static final String DEFAULT_REST_URL = "http://localhost:8080"; static final String DEFAULT_MQTT_URLS = "tcp://localhost:1883"; static final String DEFAULT_USERNAME = "tenant@thingsboard.org"; diff --git a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala index d82ed5b7d4..6002ede4bc 100644 --- a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala +++ b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala @@ -1,3 +1,18 @@ +/** + * Copyright © 2016 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. + */ /** * Copyright © 2016 The Thingsboard Authors * @@ -27,14 +42,21 @@ class MqttSimulation extends Simulation { .host("tcp://localhost:1883") .userName("${deviceCredentialsId}") - val scn = scenario("MQTT Test") - .feed(csv("/tmp/mqtt.csv").circular) - .exec(mqtt("request") + val connect = exec(mqtt("connect") + .connect()) + + val publish = repeat(400) { + exec(mqtt("publish") .publish("v1/devices/me/telemetry", "{\"key1\":\"value1\", \"key2\":\"value2\"}", QoS.AT_LEAST_ONCE, retain = false)) + } + + val scn = scenario("Scenario Name") + .feed(csv("/tmp/mqtt.csv").circular) + .exec(connect, publish) setUp( scn - .inject(constantUsersPerSec(1000) during (5 seconds)) + .inject(constantUsersPerSec(25) during (1 seconds)) ).protocols(mqttConf) } \ No newline at end of file From 595e1cc2c136f624ddf2309f5e0ee66e8290f5a9 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Thu, 5 Jan 2017 13:19:10 +0200 Subject: [PATCH 06/12] Performance improvements --- application/src/main/resources/actor-system.conf | 14 +++++++------- application/src/main/resources/thingsboard.yml | 2 +- .../org/thingsboard/client/tools/TestParams.java | 4 ++-- tools/src/main/resources/logback.xml | 1 + .../thingsboard/client/tools/MqttSimulation.scala | 8 ++++---- .../transport/mqtt/MqttTransportService.java | 1 - 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/application/src/main/resources/actor-system.conf b/application/src/main/resources/actor-system.conf index 7bd80ab95d..cceaf964af 100644 --- a/application/src/main/resources/actor-system.conf +++ b/application/src/main/resources/actor-system.conf @@ -29,9 +29,9 @@ app-dispatcher { executor = "fork-join-executor" fork-join-executor { # Min number of threads to cap factor-based parallelism number to - parallelism-min = 2 + parallelism-min = 1 # Max number of threads to cap factor-based parallelism number to - parallelism-max = 12 + parallelism-max = 1 # The parallelism factor is used to determine thread pool size using the # following formula: ceil(available processors * factor). Resulting size @@ -54,7 +54,7 @@ rpc-dispatcher { # Min number of threads to cap factor-based parallelism number to parallelism-min = 2 # Max number of threads to cap factor-based parallelism number to - parallelism-max = 12 + parallelism-max = 8 # The parallelism factor is used to determine thread pool size using the # following formula: ceil(available processors * factor). Resulting size @@ -82,7 +82,7 @@ core-dispatcher { # The parallelism factor is used to determine thread pool size using the # following formula: ceil(available processors * factor). Resulting size # is then bounded by the parallelism-min and parallelism-max values. - parallelism-factor = 1.0 + parallelism-factor = 0.25 } # How long time the dispatcher will wait for new actors until it shuts down shutdown-timeout = 1s @@ -105,7 +105,7 @@ rule-dispatcher { # The parallelism factor is used to determine thread pool size using the # following formula: ceil(available processors * factor). Resulting size # is then bounded by the parallelism-min and parallelism-max values. - parallelism-factor = 1.0 + parallelism-factor = 0.25 } # How long time the dispatcher will wait for new actors until it shuts down shutdown-timeout = 1s @@ -128,7 +128,7 @@ plugin-dispatcher { # The parallelism factor is used to determine thread pool size using the # following formula: ceil(available processors * factor). Resulting size # is then bounded by the parallelism-min and parallelism-max values. - parallelism-factor = 1.0 + parallelism-factor = 0.25 } # How long time the dispatcher will wait for new actors until it shuts down shutdown-timeout = 1s @@ -152,7 +152,7 @@ session-dispatcher { # The parallelism factor is used to determine thread pool size using the # following formula: ceil(available processors * factor). Resulting size # is then bounded by the parallelism-min and parallelism-max values. - parallelism-factor = 1.0 + parallelism-factor = 0.25 } # How long time the dispatcher will wait for new actors until it shuts down shutdown-timeout = 1s diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 2b42bdd67f..9eb3205c73 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -167,7 +167,7 @@ actors: # Cache parameters cache: # Enable/disable cache functionality. - enabled: "${CACHE_ENABLED:true}" + enabled: "${CACHE_ENABLED:false}" device_credentials: # Default time to store device credentials in cache, in seconds time_to_live: "${CACHE_DEVICE_CREDENTIAL_TTL:3600}" diff --git a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java index 1286f5efd9..f6ffb46f02 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java +++ b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java @@ -25,9 +25,9 @@ import java.util.concurrent.TimeUnit; @Slf4j public class TestParams { static final String TEST_PROPERTIES = "test.properties"; - static final long DEFAULT_TEST_DURATION = TimeUnit.MINUTES.toMillis(1); + static final long DEFAULT_TEST_DURATION = TimeUnit.SECONDS.toMillis(1); static final long DEFAULT_TEST_INTERVAL = TimeUnit.MILLISECONDS.toMillis(100); - static final int DEFAULT_DEVICE_COUNT = 25; + static final int DEFAULT_DEVICE_COUNT = 2000; static final String DEFAULT_REST_URL = "http://localhost:8080"; static final String DEFAULT_MQTT_URLS = "tcp://localhost:1883"; static final String DEFAULT_USERNAME = "tenant@thingsboard.org"; diff --git a/tools/src/main/resources/logback.xml b/tools/src/main/resources/logback.xml index 11973fa644..d3d16abed1 100644 --- a/tools/src/main/resources/logback.xml +++ b/tools/src/main/resources/logback.xml @@ -25,6 +25,7 @@ + diff --git a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala index 6002ede4bc..80732f57b6 100644 --- a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala +++ b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala @@ -45,18 +45,18 @@ class MqttSimulation extends Simulation { val connect = exec(mqtt("connect") .connect()) - val publish = repeat(400) { + val publish = repeat(600) { exec(mqtt("publish") - .publish("v1/devices/me/telemetry", "{\"key1\":\"value1\", \"key2\":\"value2\"}", QoS.AT_LEAST_ONCE, retain = false)) + .publish("v1/devices/me/telemetry", "{\"temperature\":\"42\"}", QoS.AT_LEAST_ONCE, retain = false)).pause(100 milliseconds) } val scn = scenario("Scenario Name") - .feed(csv("/tmp/mqtt.csv").circular) + .feed(csv("/tmp/mqtt.csv")) .exec(connect, publish) setUp( scn - .inject(constantUsersPerSec(25) during (1 seconds)) + .inject(constantUsersPerSec(1500) during (1 seconds)) ).protocols(mqttConf) } \ No newline at end of file diff --git a/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportService.java b/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportService.java index e8569cf5ef..02f6b40f7f 100644 --- a/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportService.java +++ b/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportService.java @@ -76,7 +76,6 @@ public class MqttTransportService { @PostConstruct public void init() throws Exception { - ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); log.info("Starting MQTT transport..."); log.info("Lookup MQTT transport adaptor {}", adaptorName); this.adaptor = (MqttTransportAdaptor) appContext.getBean(adaptorName); From ee6c0a0d7812e2c96364d15b54d4a7f1a5376e74 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Fri, 6 Jan 2017 16:48:04 +0200 Subject: [PATCH 07/12] added creation of devices --- .../client/tools/MqttStressTestTool.java | 107 ++++++++---------- .../thingsboard/client/tools/TestParams.java | 4 +- tools/src/main/resources/test.properties | 4 +- .../client/tools/MqttSimulation.scala | 37 +++--- 4 files changed, 70 insertions(+), 82 deletions(-) diff --git a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java index 05075ba9de..ce637fdea0 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java +++ b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java @@ -22,16 +22,15 @@ import org.eclipse.paho.client.mqttv3.IMqttToken; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.security.DeviceCredentials; -import java.io.BufferedWriter; -import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /** @@ -40,11 +39,15 @@ import java.util.concurrent.atomic.AtomicLong; @Slf4j public class MqttStressTestTool { + private static byte[] data = "{\"longKey\":73}".getBytes(StandardCharsets.UTF_8); + private static ResultAccumulator results = new ResultAccumulator(); + private static List clients = new ArrayList<>(); + private static List connectTokens = new ArrayList<>(); + public static void main(String[] args) throws Exception { TestParams params = new TestParams(); ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10); - if (params.getDuration() % params.getIterationInterval() != 0) { throw new IllegalArgumentException("Test Duration % Iteration Interval != 0"); } @@ -53,41 +56,7 @@ public class MqttStressTestTool { throw new IllegalArgumentException("Iteration Interval % Device Count != 0"); } - ResultAccumulator results = new ResultAccumulator(); - - AtomicLong value = new AtomicLong(Long.MAX_VALUE); - log.info("value: {} ", value.incrementAndGet()); - - RestClient restClient = new RestClient(params.getRestApiUrl()); - restClient.login(params.getUsername(), params.getPassword()); - - List clients = new ArrayList<>(); - List connectTokens = new ArrayList<>(); - List deviceCredentialsIds = new ArrayList<>(); - for (int i = 0; i < params.getDeviceCount(); i++) { - Device device = restClient.createDevice("Device " + UUID.randomUUID()); - DeviceCredentials credentials = restClient.getCredentials(device.getId()); - String[] mqttUrls = params.getMqttUrls(); - String mqttURL = mqttUrls[i % mqttUrls.length]; - MqttStressTestClient client = new MqttStressTestClient(results, mqttURL, credentials.getCredentialsId()); - deviceCredentialsIds.add(credentials.getCredentialsId()); - connectTokens.add(client.connect()); - clients.add(client); - } - - dumpDeviceCredentialsIdsToTmpFile(deviceCredentialsIds); - - for (IMqttToken tokens : connectTokens) { - tokens.waitForCompletion(); - } - - byte[] data = "{\"longKey\":73}".getBytes(StandardCharsets.UTF_8); - - for (MqttStressTestClient client : clients) { - client.warmUp(data); - } - - Thread.sleep(1000); + createDevices(params); long startTime = System.currentTimeMillis(); int iterationsCount = (int) (params.getDuration() / params.getIterationInterval()); @@ -123,20 +92,44 @@ public class MqttStressTestTool { scheduler.shutdownNow(); } - private static void dumpDeviceCredentialsIdsToTmpFile(List deviceCredentialsIds) throws IOException { - Path path = Paths.get("/tmp/mqtt.csv"); - try (BufferedWriter writer = Files.newBufferedWriter(path)) { - writer.write("deviceCredentialsId"); - writer.write('\n'); - deviceCredentialsIds.forEach((deviceCredentialsId) -> { - try { - writer.write(deviceCredentialsId); - writer.write('\n'); - } catch (IOException e) { - e.printStackTrace(); - } - }); - } - } + /** + * Returns list of device credential IDs + * + * @param params + * @return + * @throws Exception + */ + public static List createDevices(TestParams params) throws Exception { + AtomicLong value = new AtomicLong(Long.MAX_VALUE); + log.info("value: {} ", value.incrementAndGet()); + RestClient restClient = new RestClient(params.getRestApiUrl()); + restClient.login(params.getUsername(), params.getPassword()); + + List deviceCredentialsIds = new ArrayList<>(); + for (int i = 0; i < params.getDeviceCount(); i++) { + Device device = restClient.createDevice("Device " + UUID.randomUUID()); + DeviceCredentials credentials = restClient.getCredentials(device.getId()); + String[] mqttUrls = params.getMqttUrls(); + String mqttURL = mqttUrls[i % mqttUrls.length]; + MqttStressTestClient client = new MqttStressTestClient(results, mqttURL, credentials.getCredentialsId()); + + deviceCredentialsIds.add(credentials.getCredentialsId()); + + connectTokens.add(client.connect()); + clients.add(client); + } + + for (IMqttToken tokens : connectTokens) { + tokens.waitForCompletion(); + } + + for (MqttStressTestClient client : clients) { + client.warmUp(data); + } + + Thread.sleep(1000); + + return deviceCredentialsIds; + } } diff --git a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java index 1286f5efd9..88618f518e 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java +++ b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import java.io.FileInputStream; import java.io.IOException; +import java.net.URL; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -36,8 +37,9 @@ public class TestParams { private Properties params = new Properties(); public TestParams() throws IOException { + URL location = TestParams.class.getProtectionDomain().getCodeSource().getLocation(); try { - params.load(new FileInputStream(TEST_PROPERTIES)); + params.load(new FileInputStream(location.getFile() + TEST_PROPERTIES)); } catch (Exception e) { log.warn("Failed to read " + TEST_PROPERTIES); } diff --git a/tools/src/main/resources/test.properties b/tools/src/main/resources/test.properties index 6e9ed89cf9..d55c1fc205 100644 --- a/tools/src/main/resources/test.properties +++ b/tools/src/main/resources/test.properties @@ -1,5 +1,5 @@ restUrl=http://localhost:8080 mqttUrls=tcp://localhost:1883 -deviceCount=1 +deviceCount=100 durationMs=60000 -iterationIntervalMs=1000 +iterationIntervalMs=1000 \ No newline at end of file diff --git a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala index 6002ede4bc..0d92b74f10 100644 --- a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala +++ b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala @@ -13,50 +13,43 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * Copyright © 2016 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.client.tools +import com.github.mnogu.gatling.mqtt.Predef._ import io.gatling.core.Predef._ import org.fusesource.mqtt.client.QoS +import scala.collection.JavaConverters._ + import scala.concurrent.duration._ -import com.github.mnogu.gatling.mqtt.Predef._ - class MqttSimulation extends Simulation { + val testParams = new TestParams() + + val deviceCredentialsIds: Array[String] = MqttStressTestTool.createDevices(testParams).asScala.toArray + val mqttConf = mqtt .host("tcp://localhost:1883") .userName("${deviceCredentialsId}") val connect = exec(mqtt("connect") - .connect()) + .connect()) - val publish = repeat(400) { + val publish = repeat(100) { exec(mqtt("publish") .publish("v1/devices/me/telemetry", "{\"key1\":\"value1\", \"key2\":\"value2\"}", QoS.AT_LEAST_ONCE, retain = false)) + .pause(100 milliseconds) } + val deviceCredentialsIdsFeeder = deviceCredentialsIds.map( x => {Map("deviceCredentialsId" -> x)}) + val scn = scenario("Scenario Name") - .feed(csv("/tmp/mqtt.csv").circular) + .feed(deviceCredentialsIdsFeeder) .exec(connect, publish) setUp( - scn - .inject(constantUsersPerSec(25) during (1 seconds)) + scn + .inject(constantUsersPerSec(testParams.getDeviceCount) during (1 seconds)) ).protocols(mqttConf) } \ No newline at end of file From 95f5b3b19d4f3568d15148e562287602d0615d97 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Fri, 6 Jan 2017 16:58:12 +0200 Subject: [PATCH 08/12] fixed file path --- .../src/main/java/org/thingsboard/client/tools/TestParams.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java index 2391422f12..d157621d23 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java +++ b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java @@ -37,9 +37,8 @@ public class TestParams { private Properties params = new Properties(); public TestParams() throws IOException { - URL location = TestParams.class.getProtectionDomain().getCodeSource().getLocation(); try { - params.load(new FileInputStream(location.getFile() + TEST_PROPERTIES)); + params.load(TestParams.class.getClassLoader().getResourceAsStream(TEST_PROPERTIES)); } catch (Exception e) { log.warn("Failed to read " + TEST_PROPERTIES); } From 625be4a83b7382252424f7851a8fb1a38f954410 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Fri, 6 Jan 2017 16:59:14 +0200 Subject: [PATCH 09/12] removed unused file --- .../main/shell/install-local-gatling-mqtt.sh | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100755 tools/src/main/shell/install-local-gatling-mqtt.sh diff --git a/tools/src/main/shell/install-local-gatling-mqtt.sh b/tools/src/main/shell/install-local-gatling-mqtt.sh deleted file mode 100755 index fb500ff081..0000000000 --- a/tools/src/main/shell/install-local-gatling-mqtt.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# -# Copyright © 2016 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. -# - -git clone https://github.com/mnogu/gatling-mqtt.git /tmp/gatling-mqtt -cd /tmp/gatling-mqtt - -sbt assembly - -cd /tmp/gatling-mqtt/target/scala-2.11 - -mvn install:install-file -Dfile=gatling-mqtt-assembly-0.1.0-SNAPSHOT.jar -DgroupId=com.github.mnogu -DartifactId=gatling-mqtt -Dversion=1.0.0 -Dpackaging=jar \ No newline at end of file From 1a66a840b80105ec53fd9c3e41671b958f2f775d Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Wed, 11 Jan 2017 17:58:08 +0200 Subject: [PATCH 10/12] moved stress tests to different repo --- pom.xml | 26 ---- tools/pom.xml | 63 -------- .../client/tools/MqttStressTestClient.java | 99 ------------- .../client/tools/MqttStressTestTool.java | 135 ------------------ .../thingsboard/client/tools/RestClient.java | 77 ---------- .../client/tools/ResultAccumulator.java | 88 ------------ .../thingsboard/client/tools/TestParams.java | 74 ---------- tools/src/main/resources/logback.xml | 35 ----- tools/src/main/resources/test.properties | 5 - .../client/tools/MqttSimulation.scala | 55 ------- 10 files changed, 657 deletions(-) delete mode 100644 tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java delete mode 100644 tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java delete mode 100644 tools/src/main/java/org/thingsboard/client/tools/RestClient.java delete mode 100644 tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java delete mode 100644 tools/src/main/java/org/thingsboard/client/tools/TestParams.java delete mode 100644 tools/src/main/resources/logback.xml delete mode 100644 tools/src/main/resources/test.properties delete mode 100644 tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala diff --git a/pom.xml b/pom.xml index e9900f3571..442caef8ee 100755 --- a/pom.xml +++ b/pom.xml @@ -69,10 +69,6 @@ 2.19.1 3.0.2 2.6.1 - 2.2.3 - 1.0.0 - 2.2.1 - 3.2.2 @@ -285,16 +281,6 @@ - - net.alchim31.maven - scala-maven-plugin - ${scala-maven-plugin.version} - - - io.gatling - gatling-maven-plugin - ${gatling-plugin.version} - @@ -703,18 +689,6 @@ springfox-swagger2 ${springfox-swagger.version} - - io.gatling.highcharts - gatling-charts-highcharts - ${gatling.version} - test - - - com.github.mnogu - gatling-mqtt - ${gatling-mqtt.version} - test - diff --git a/tools/pom.xml b/tools/pom.xml index 46549fc07c..2c978f0662 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -35,61 +35,6 @@ ${basedir}/.. - - - org.thingsboard.common - data - - - org.springframework.boot - spring-boot-starter-web - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - - - org.slf4j - slf4j-api - - - org.slf4j - log4j-over-slf4j - - - ch.qos.logback - logback-core - - - ch.qos.logback - logback-classic - - - org.springframework - spring-test - - - junit - junit - test - - - org.mockito - mockito-all - test - - - io.gatling.highcharts - gatling-charts-highcharts - test - - - com.github.mnogu - gatling-mqtt - test - - - @@ -124,14 +69,6 @@ - - net.alchim31.maven - scala-maven-plugin - - - io.gatling - gatling-maven-plugin - diff --git a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java deleted file mode 100644 index 3b6fca98da..0000000000 --- a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright © 2016-2017 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.client.tools; - -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.*; -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; - -/** - * @author Andrew Shvayka - */ -@Slf4j -public class MqttStressTestClient { - - @Getter - private final String deviceToken; - @Getter - private final String clientId; - private final MqttClientPersistence persistence; - private final MqttAsyncClient client; - private final ResultAccumulator results; - - public MqttStressTestClient(ResultAccumulator results, String brokerUri, String deviceToken) throws MqttException { - this.results = results; - this.clientId = MqttAsyncClient.generateClientId(); - this.deviceToken = deviceToken; - this.persistence = new MemoryPersistence(); - this.client = new MqttAsyncClient(brokerUri, clientId, persistence); - } - - public IMqttToken connect() throws MqttException { - MqttConnectOptions options = new MqttConnectOptions(); - options.setUserName(deviceToken); - return client.connect(options, null, new IMqttActionListener() { - @Override - public void onSuccess(IMqttToken iMqttToken) { - log.info("OnSuccess"); - } - - @Override - public void onFailure(IMqttToken iMqttToken, Throwable e) { - log.info("OnFailure", e); - } - }); - } - - public void disconnect() throws MqttException { - client.disconnect(); - } - - - - public void warmUp(byte[] data) throws MqttException { - MqttMessage msg = new MqttMessage(data); - client.publish("v1/devices/me/telemetry", msg, null, new IMqttActionListener() { - @Override - public void onSuccess(IMqttToken asyncActionToken) { - } - - @Override - public void onFailure(IMqttToken asyncActionToken, Throwable exception) { - } - }).waitForCompletion(); - } - - - public void publishTelemetry(byte[] data) throws MqttException { - long sendTime = System.currentTimeMillis(); - MqttMessage msg = new MqttMessage(data); - client.publish("v1/devices/me/telemetry", msg, null, new IMqttActionListener() { - @Override - public void onSuccess(IMqttToken asyncActionToken) { - long ackTime = System.currentTimeMillis(); - results.onResult(true, ackTime - sendTime); - } - - @Override - public void onFailure(IMqttToken asyncActionToken, Throwable exception) { - long failTime = System.currentTimeMillis(); - results.onResult(false, failTime - sendTime); - } - }); - } -} diff --git a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java b/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java deleted file mode 100644 index b957f138a3..0000000000 --- a/tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright © 2016-2017 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.client.tools; - -import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.IMqttToken; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.security.DeviceCredentials; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -/** - * @author Andrew Shvayka - */ -@Slf4j -public class MqttStressTestTool { - - private static byte[] data = "{\"longKey\":73}".getBytes(StandardCharsets.UTF_8); - private static ResultAccumulator results = new ResultAccumulator(); - private static List clients = new ArrayList<>(); - private static List connectTokens = new ArrayList<>(); - - public static void main(String[] args) throws Exception { - TestParams params = new TestParams(); - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10); - - if (params.getDuration() % params.getIterationInterval() != 0) { - throw new IllegalArgumentException("Test Duration % Iteration Interval != 0"); - } - - if ((params.getIterationInterval() * 1000) % params.getDeviceCount() != 0) { - throw new IllegalArgumentException("Iteration Interval % Device Count != 0"); - } - - createDevices(params); - - long startTime = System.currentTimeMillis(); - int iterationsCount = (int) (params.getDuration() / params.getIterationInterval()); - int subIterationMicroSeconds = (int) ((params.getIterationInterval() * 1000) / params.getDeviceCount()); - - List> iterationFutures = new ArrayList<>(); - for (int i = 0; i < iterationsCount; i++) { - long delay = i * params.getIterationInterval(); - iterationFutures.add(scheduler.schedule((Callable) () -> { - long sleepMicroSeconds = 0L; - for (MqttStressTestClient client : clients) { - client.publishTelemetry(data); - sleepMicroSeconds += subIterationMicroSeconds; - if (sleepMicroSeconds > 1000) { - Thread.sleep(sleepMicroSeconds / 1000); - sleepMicroSeconds = sleepMicroSeconds % 1000; - } - } - return null; - }, delay, TimeUnit.MILLISECONDS)); - } - - for (ScheduledFuture future : iterationFutures) { - future.get(); - } - - Thread.sleep(1000); - - for (MqttStressTestClient client : clients) { - client.disconnect(); - } - log.info("Results: {} took {}ms", results, System.currentTimeMillis() - startTime); - scheduler.shutdownNow(); - } - - /** - * Returns list of device credential IDs - * - * @param params - * @return - * @throws Exception - */ - public static List createDevices(TestParams params) throws Exception { - AtomicLong value = new AtomicLong(Long.MAX_VALUE); - log.info("value: {} ", value.incrementAndGet()); - - RestClient restClient = new RestClient(params.getRestApiUrl()); - restClient.login(params.getUsername(), params.getPassword()); - - List deviceCredentialsIds = new ArrayList<>(); - for (int i = 0; i < params.getDeviceCount(); i++) { - Device device = restClient.createDevice("Device " + UUID.randomUUID()); - DeviceCredentials credentials = restClient.getCredentials(device.getId()); - String[] mqttUrls = params.getMqttUrls(); - String mqttURL = mqttUrls[i % mqttUrls.length]; - MqttStressTestClient client = new MqttStressTestClient(results, mqttURL, credentials.getCredentialsId()); - - deviceCredentialsIds.add(credentials.getCredentialsId()); - - connectTokens.add(client.connect()); - clients.add(client); - } - - for (IMqttToken tokens : connectTokens) { - tokens.waitForCompletion(); - } - - for (MqttStressTestClient client : clients) { - client.warmUp(data); - } - - Thread.sleep(1000); - - return deviceCredentialsIds; - } -} diff --git a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java deleted file mode 100644 index cb1b5fb890..0000000000 --- a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright © 2016-2017 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.client.tools; - -import com.fasterxml.jackson.databind.JsonNode; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpRequest; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.http.client.support.HttpRequestWrapper; -import org.springframework.web.client.RestTemplate; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.security.DeviceCredentials; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * @author Andrew Shvayka - */ -@RequiredArgsConstructor -public class RestClient implements ClientHttpRequestInterceptor { - private static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; - private final RestTemplate restTemplate = new RestTemplate(); - private String token; - private final String baseURL; - - public void login(String username, String password) { - Map loginRequest = new HashMap<>(); - loginRequest.put("username", username); - loginRequest.put("password", password); - ResponseEntity tokenInfo = restTemplate.postForEntity(baseURL + "/api/auth/login", loginRequest, JsonNode.class); - this.token = tokenInfo.getBody().get("token").asText(); - restTemplate.setInterceptors(Collections.singletonList(this)); - } - - public Device createDevice(String name) { - Device device = new Device(); - device.setName(name); - return restTemplate.postForEntity(baseURL + "/api/device", device, Device.class).getBody(); - } - - public DeviceCredentials getCredentials(DeviceId id) { - return restTemplate.getForEntity(baseURL + "/api/device/" + id.getId().toString() + "/credentials", DeviceCredentials.class).getBody(); - } - - public RestTemplate getRestTemplate() { - return restTemplate; - } - - @Override - public ClientHttpResponse intercept(HttpRequest request, byte[] bytes, ClientHttpRequestExecution execution) throws IOException { - HttpRequest wrapper = new HttpRequestWrapper(request); - wrapper.getHeaders().set(JWT_TOKEN_HEADER_PARAM, "Bearer " + token); - return execution.execute(wrapper, bytes); - } - -} diff --git a/tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java b/tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java deleted file mode 100644 index 2530ed13ff..0000000000 --- a/tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright © 2016-2017 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.client.tools; - -import lombok.extern.slf4j.Slf4j; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * @author Andrew Shvayka - */ -@Slf4j -public class ResultAccumulator { - - private AtomicLong minTime = new AtomicLong(Long.MAX_VALUE); - private AtomicLong maxTime = new AtomicLong(Long.MIN_VALUE); - private AtomicLong timeSpentCount = new AtomicLong(); - private AtomicInteger successCount = new AtomicInteger(); - private AtomicInteger errorCount = new AtomicInteger(); - - public void onResult(boolean success, long timeSpent) { - if (success) { - successCount.incrementAndGet(); - } else { - errorCount.incrementAndGet(); - } - timeSpentCount.addAndGet(timeSpent); - - while (!setMax(timeSpent)) ; - while (!setMin(timeSpent)) ; - } - - private boolean setMax(long timeSpent) { - long curMax = maxTime.get(); - long newMax = Math.max(curMax, timeSpent); - return maxTime.compareAndSet(curMax, newMax); - } - - private boolean setMin(long timeSpent) { - long curMin = minTime.get(); - long newMin = Math.min(curMin, timeSpent); - return minTime.compareAndSet(curMin, newMin); - } - - - public int getSuccessCount() { - return successCount.get(); - } - - public int getErrorCount() { - return errorCount.get(); - } - - public long getTimeSpent() { - return timeSpentCount.get(); - } - - public double getAvgTimeSpent() { - return ((double) getTimeSpent()) / (getSuccessCount() + getErrorCount()); - } - - @Override - public String toString() { - return "Result {" + - "successCount=" + getSuccessCount() + - ", errorCount=" + getErrorCount() + - ", totalTime=" + getTimeSpent() + - ", avgTime=" + getAvgTimeSpent() + - ", minTime=" + minTime.get() + - ", maxTime=" + maxTime.get() + - '}'; - } -} diff --git a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java b/tools/src/main/java/org/thingsboard/client/tools/TestParams.java deleted file mode 100644 index 24b860d9c1..0000000000 --- a/tools/src/main/java/org/thingsboard/client/tools/TestParams.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright © 2016-2017 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.client.tools; - -import lombok.extern.slf4j.Slf4j; - -import java.io.FileInputStream; -import java.io.IOException; -import java.net.URL; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - -@Slf4j -public class TestParams { - static final String TEST_PROPERTIES = "test.properties"; - static final long DEFAULT_TEST_DURATION = TimeUnit.SECONDS.toMillis(1); - static final long DEFAULT_TEST_INTERVAL = TimeUnit.MILLISECONDS.toMillis(100); - static final int DEFAULT_DEVICE_COUNT = 2000; - static final String DEFAULT_REST_URL = "http://localhost:8080"; - static final String DEFAULT_MQTT_URLS = "tcp://localhost:1883"; - static final String DEFAULT_USERNAME = "tenant@thingsboard.org"; - static final String DEFAULT_PASSWORD = "tenant"; - - private Properties params = new Properties(); - - public TestParams() throws IOException { - try { - params.load(TestParams.class.getClassLoader().getResourceAsStream(TEST_PROPERTIES)); - } catch (Exception e) { - log.warn("Failed to read " + TEST_PROPERTIES); - } - } - - public long getDuration() { - return Long.valueOf(params.getProperty("durationMs", Long.toString(DEFAULT_TEST_DURATION))); - } - - public long getIterationInterval() { - return Long.valueOf(params.getProperty("iterationIntervalMs", Long.toString(DEFAULT_TEST_INTERVAL))); - } - - public int getDeviceCount() { - return Integer.valueOf(params.getProperty("deviceCount", Integer.toString(DEFAULT_DEVICE_COUNT))); - } - - public String getRestApiUrl() { - return params.getProperty("restUrl", DEFAULT_REST_URL); - } - - public String[] getMqttUrls() { - return params.getProperty("mqttUrls", DEFAULT_MQTT_URLS).split(","); - } - - public String getUsername() { - return params.getProperty("username", DEFAULT_USERNAME); - } - - public String getPassword() { - return params.getProperty("password", DEFAULT_PASSWORD); - } -} diff --git a/tools/src/main/resources/logback.xml b/tools/src/main/resources/logback.xml deleted file mode 100644 index 518f474e4e..0000000000 --- a/tools/src/main/resources/logback.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - \ No newline at end of file diff --git a/tools/src/main/resources/test.properties b/tools/src/main/resources/test.properties deleted file mode 100644 index d55c1fc205..0000000000 --- a/tools/src/main/resources/test.properties +++ /dev/null @@ -1,5 +0,0 @@ -restUrl=http://localhost:8080 -mqttUrls=tcp://localhost:1883 -deviceCount=100 -durationMs=60000 -iterationIntervalMs=1000 \ No newline at end of file diff --git a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala b/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala deleted file mode 100644 index 0d92b74f10..0000000000 --- a/tools/src/test/scala/org/thingsboard/client/tools/MqttSimulation.scala +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright © 2016 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.client.tools - -import com.github.mnogu.gatling.mqtt.Predef._ -import io.gatling.core.Predef._ -import org.fusesource.mqtt.client.QoS -import scala.collection.JavaConverters._ - -import scala.concurrent.duration._ - -class MqttSimulation extends Simulation { - - val testParams = new TestParams() - - val deviceCredentialsIds: Array[String] = MqttStressTestTool.createDevices(testParams).asScala.toArray - - val mqttConf = mqtt - .host("tcp://localhost:1883") - .userName("${deviceCredentialsId}") - - val connect = exec(mqtt("connect") - .connect()) - - val publish = repeat(100) { - exec(mqtt("publish") - .publish("v1/devices/me/telemetry", "{\"key1\":\"value1\", \"key2\":\"value2\"}", QoS.AT_LEAST_ONCE, retain = false)) - .pause(100 milliseconds) - } - - val deviceCredentialsIdsFeeder = deviceCredentialsIds.map( x => {Map("deviceCredentialsId" -> x)}) - - val scn = scenario("Scenario Name") - .feed(deviceCredentialsIdsFeeder) - .exec(connect, publish) - - setUp( - scn - .inject(constantUsersPerSec(testParams.getDeviceCount) during (1 seconds)) - ).protocols(mqttConf) - -} \ No newline at end of file From 4dfe05865d7d363c9bdce41b9ca00a3f08753722 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Wed, 11 Jan 2017 19:02:56 +0200 Subject: [PATCH 11/12] added restclient to tools --- tools/pom.xml | 24 ++++++ .../thingsboard/client/tools/RestClient.java | 76 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 tools/src/main/java/org/thingsboard/client/tools/RestClient.java diff --git a/tools/pom.xml b/tools/pom.xml index 2c978f0662..a576d60022 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -35,6 +35,30 @@ ${basedir}/.. + + + org.thingsboard.common + data + ${project.version} + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + ${paho.client.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + diff --git a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java new file mode 100644 index 0000000000..e3e1793f30 --- /dev/null +++ b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java @@ -0,0 +1,76 @@ +/** + * Copyright © 2016-2017 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.client.tools; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpRequest; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.support.HttpRequestWrapper; +import org.springframework.web.client.RestTemplate; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.security.DeviceCredentials; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Andrew Shvayka + */ +@RequiredArgsConstructor +public class RestClient implements ClientHttpRequestInterceptor { + private static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; + private final RestTemplate restTemplate = new RestTemplate(); + private String token; + private final String baseURL; + + public void login(String username, String password) { + Map loginRequest = new HashMap<>(); + loginRequest.put("username", username); + loginRequest.put("password", password); + ResponseEntity tokenInfo = restTemplate.postForEntity(baseURL + "/api/auth/login", loginRequest, JsonNode.class); + this.token = tokenInfo.getBody().get("token").asText(); + restTemplate.setInterceptors(Collections.singletonList(this)); + } + + public Device createDevice(String name) { + Device device = new Device(); + device.setName(name); + return restTemplate.postForEntity(baseURL + "/api/device", device, Device.class).getBody(); + } + + public DeviceCredentials getCredentials(DeviceId id) { + return restTemplate.getForEntity(baseURL + "/api/device/" + id.getId().toString() + "/credentials", DeviceCredentials.class).getBody(); + } + + public RestTemplate getRestTemplate() { + return restTemplate; + } + + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] bytes, ClientHttpRequestExecution execution) throws IOException { + HttpRequest wrapper = new HttpRequestWrapper(request); + wrapper.getHeaders().set(JWT_TOKEN_HEADER_PARAM, "Bearer " + token); + return execution.execute(wrapper, bytes); + } + +} From 9721755d23352bf6ff665af57296ec3c0b5b3532 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Wed, 11 Jan 2017 19:06:50 +0200 Subject: [PATCH 12/12] fixed dependencies --- tools/pom.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tools/pom.xml b/tools/pom.xml index a576d60022..cbea684450 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -39,23 +39,14 @@ org.thingsboard.common data - ${project.version} org.springframework.boot spring-boot-starter-web - ${spring-boot.version} org.eclipse.paho org.eclipse.paho.client.mqttv3 - ${paho.client.version} - - - org.projectlombok - lombok - ${lombok.version} - provided