Browse Source

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
pull/30/head
volodymyr-babak 10 years ago
parent
commit
64dfb4a7f7
  1. 2
      application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
  2. 192
      tools/pom.xml
  3. 22
      tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java
  4. 86
      tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java
  5. 2
      tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java
  6. 73
      tools/src/main/java/org/thingsboard/client/tools/TestParams.java
  7. 34
      tools/src/main/resources/logback.xml
  8. 3
      tools/test.properties
  9. 16
      ui/package.json

2
application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java

@ -134,7 +134,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable()
http.headers().cacheControl().disable().frameOptions().disable()
.and()
.csrf().disable()
.exceptionHandling()

192
tools/pom.xml

@ -17,89 +17,121 @@
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>1.0.1-SNAPSHOT</version>
<artifactId>thingsboard</artifactId>
</parent>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<artifactId>tools</artifactId>
<packaging>jar</packaging>
<version>1.0.1-SNAPSHOT</version>
<artifactId>thingsboard</artifactId>
</parent>
<groupId>org.thingsboard</groupId>
<artifactId>tools</artifactId>
<packaging>jar</packaging>
<name>Thingsboard Server Tools</name>
<url>http://thingsboard.org</url>
<name>Thingsboard Server Tools</name>
<url>http://thingsboard.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<main.dir>${basedir}/..</main.dir>
</properties>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<main.dir>${basedir}/..</main.dir>
</properties>
<dependencies>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>data</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.gatling.highcharts</groupId>
<artifactId>gatling-charts-highcharts</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.mnogu</groupId>
<artifactId>gatling-mqtt</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>data</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.gatling.highcharts</groupId>
<artifactId>gatling-charts-highcharts</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.mnogu</groupId>
<artifactId>gatling-mqtt</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.gatling</groupId>
<artifactId>gatling-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>org.thingsboard.client.tools.MqttStressTestTool</Main-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.gatling</groupId>
<artifactId>gatling-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

22
tools/src/main/java/org/thingsboard/client/tools/MqttStressTestClient.java

@ -43,10 +43,10 @@ public class MqttStressTestClient {
this.client = new MqttAsyncClient(brokerUri, clientId, persistence);
}
public void connect() throws MqttException {
public IMqttToken connect() throws MqttException {
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(deviceToken);
client.connect(options, null, new IMqttActionListener() {
return client.connect(options, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken iMqttToken) {
log.info("OnSuccess");
@ -63,6 +63,22 @@ public class MqttStressTestClient {
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);
@ -70,14 +86,12 @@ public class MqttStressTestClient {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
long ackTime = System.currentTimeMillis();
// log.info("Delivery time: {}", ackTime - sendTime);
results.onResult(true, ackTime - sendTime);
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
long failTime = System.currentTimeMillis();
// log.info("Failure time: {}", failTime - sendTime);
results.onResult(false, failTime - sendTime);
}
});

86
tools/src/main/java/org/thingsboard/client/tools/MqttStressTestTool.java

@ -14,16 +14,19 @@
* 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.concurrent.TimeUnit;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
/**
@ -32,60 +35,83 @@ import java.util.concurrent.atomic.AtomicLong;
@Slf4j
public class MqttStressTestTool {
private static final long TEST_DURATION = TimeUnit.MINUTES.toMillis(1);
private static final long TEST_ITERATION = TimeUnit.MILLISECONDS.toMillis(100);
private static final long TEST_SUB_ITERATION = TimeUnit.MILLISECONDS.toMillis(2);
private static final int DEVICE_COUNT = 100;
private static final String BASE_URL = "http://localhost:8080";
private static final String[] MQTT_URLS = {"tcp://localhost:1883"};
// private static final String[] MQTT_URLS = {"tcp://localhost:1883", "tcp://localhost:1884", "tcp://localhost:1885"};
private static final String USERNAME = "tenant@thingsboard.org";
private static final String PASSWORD = "tenant";
public static void main(String[] args) throws Exception {
TestParams params = new TestParams();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
public static void main(String[] args) throws Exception {
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");
}
ResultAccumulator results = new ResultAccumulator();
AtomicLong value = new AtomicLong(Long.MAX_VALUE);
log.info("value: {} ", value.incrementAndGet());
RestClient restClient = new RestClient(BASE_URL);
restClient.login(USERNAME, PASSWORD);
RestClient restClient = new RestClient(params.getRestApiUrl());
restClient.login(params.getUsername(), params.getPassword());
List<MqttStressTestClient> clients = new ArrayList<>();
for (int i = 0; i < DEVICE_COUNT; i++) {
Device device = restClient.createDevice("Device " + i);
List<IMqttToken> connectTokens = new ArrayList<>();
for (int i = 0; i < params.getDeviceCount(); i++) {
Device device = restClient.createDevice("Device " + UUID.randomUUID());
DeviceCredentials credentials = restClient.getCredentials(device.getId());
String mqttURL = MQTT_URLS[i % MQTT_URLS.length];
String[] mqttUrls = params.getMqttUrls();
String mqttURL = mqttUrls[i % mqttUrls.length];
MqttStressTestClient client = new MqttStressTestClient(results, mqttURL, credentials.getCredentialsId());
client.connect();
connectTokens.add(client.connect());
clients.add(client);
}
Thread.sleep(1000);
for (IMqttToken tokens : connectTokens) {
tokens.waitForCompletion();
}
byte[] data = "{\"longKey\":73}".getBytes(StandardCharsets.UTF_8);
long startTime = System.currentTimeMillis();
int iterationsCount = (int) (TEST_DURATION / TEST_ITERATION);
int subIterationsCount = (int) (TEST_ITERATION / TEST_SUB_ITERATION);
if (clients.size() % subIterationsCount != 0) {
throw new IllegalArgumentException("Invalid parameter exception!");
for (MqttStressTestClient client : clients) {
client.warmUp(data);
}
Thread.sleep(1000);
long startTime = System.currentTimeMillis();
int iterationsCount = (int) (params.getDuration() / params.getIterationInterval());
int subIterationMicroSeconds = (int) ((params.getIterationInterval() * 1000) / params.getDeviceCount());
List<ScheduledFuture<Void>> iterationFutures = new ArrayList<>();
for (int i = 0; i < iterationsCount; i++) {
for (int j = 0; j < subIterationsCount; j++) {
int packSize = clients.size() / subIterationsCount;
for (int k = 0; k < packSize; k++) {
int clientIndex = packSize * j + k;
clients.get(clientIndex).publishTelemetry(data);
long delay = i * params.getIterationInterval();
iterationFutures.add(scheduler.schedule((Callable<Void>) () -> {
long sleepMicroSeconds = 0L;
for (MqttStressTestClient client : clients) {
client.publishTelemetry(data);
sleepMicroSeconds += subIterationMicroSeconds;
if (sleepMicroSeconds > 1000) {
Thread.sleep(sleepMicroSeconds / 1000);
sleepMicroSeconds = sleepMicroSeconds % 1000;
}
}
Thread.sleep(TEST_SUB_ITERATION);
}
return null;
}, delay, TimeUnit.MILLISECONDS));
}
for (ScheduledFuture<Void> future : iterationFutures) {
future.get();
}
Thread.sleep(1000);
for (MqttStressTestClient client : clients) {
client.disconnect();
}
log.info("Results: {} took {}ms", results, System.currentTimeMillis() - startTime);
scheduler.shutdownNow();
}
}

2
tools/src/main/java/org/thingsboard/client/tools/ResultAccumulator.java

@ -76,7 +76,7 @@ public class ResultAccumulator {
@Override
public String toString() {
return "org.thingsboard.client.tools.ResultAccumulator{" +
return "Result {" +
"successCount=" + getSuccessCount() +
", errorCount=" + getErrorCount() +
", totalTime=" + getTimeSpent() +

73
tools/src/main/java/org/thingsboard/client/tools/TestParams.java

@ -0,0 +1,73 @@
/**
* 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 lombok.extern.slf4j.Slf4j;
import java.io.FileInputStream;
import java.io.IOException;
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.MINUTES.toMillis(1);
static final long DEFAULT_TEST_INTERVAL = TimeUnit.MILLISECONDS.toMillis(100);
static final int DEFAULT_DEVICE_COUNT = 100;
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(new FileInputStream(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);
}
}

34
tools/src/main/resources/logback.xml

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
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.
-->
<!DOCTYPE configuration>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.thingsboard" level="INFO" />
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

3
tools/test.properties

@ -0,0 +1,3 @@
deviceCount=1000
durationMs=5000
iterationIntervalMs=250

16
ui/package.json

@ -15,12 +15,12 @@
},
"dependencies": {
"ace-builds": "^1.2.5",
"angular": "^1.5.8",
"angular-animate": "^1.5.8",
"angular-aria": "^1.5.8",
"angular": "1.5.8",
"angular-animate": "1.5.8",
"angular-aria": "1.5.8",
"angular-breadcrumb": "^0.4.1",
"angular-carousel": "^1.0.1",
"angular-cookies": "^1.5.8",
"angular-cookies": "1.5.8",
"angular-drag-and-drop-lists": "^1.4.0",
"angular-fullscreen": "git://github.com/fabiobiondi/angular-fullscreen.git#master",
"angular-gridster": "^0.13.14",
@ -29,11 +29,11 @@
"angular-material": "^1.1.1",
"angular-material-data-table": "^0.10.9",
"angular-material-icons": "^0.7.1",
"angular-messages": "^1.5.8",
"angular-route": "^1.5.8",
"angular-sanitize": "^1.5.8",
"angular-messages": "1.5.8",
"angular-route": "1.5.8",
"angular-sanitize": "1.5.8",
"angular-storage": "0.0.15",
"angular-touch": "^1.5.8",
"angular-touch": "1.5.8",
"angular-translate": "^2.12.1",
"angular-translate-handler-log": "^2.12.1",
"angular-translate-interpolation-messageformat": "^2.12.1",

Loading…
Cancel
Save