diff --git a/msa/black-box-tests/README.md b/msa/black-box-tests/README.md
new file mode 100644
index 0000000000..c26d9c5fc6
--- /dev/null
+++ b/msa/black-box-tests/README.md
@@ -0,0 +1,21 @@
+
+## Black box tests execution
+To run the black box tests with using Docker, the local Docker images of Thingsboard's microservices should be built.
+- Build the local Docker images in the directory with the Thingsboard's main [pom.xml](./../../pom.xml):
+
+ mvn clean install -Ddockerfile.skip=false
+- Verify that the new local images were built:
+
+ docker image ls
+As result, in REPOSITORY column, next images should be present:
+
+ thingsboard/tb-coap-transport
+ thingsboard/tb-http-transport
+ thingsboard/tb-mqtt-transport
+ thingsboard/tb-node
+ thingsboard/tb-web-ui
+ thingsboard/tb-js-executor
+
+- Run the black box tests in the [msa/black-box-tests](../black-box-tests) directory:
+
+ mvn clean install -DblackBoxTests.skip=false
\ No newline at end of file
diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml
new file mode 100644
index 0000000000..2af4d2c14e
--- /dev/null
+++ b/msa/black-box-tests/pom.xml
@@ -0,0 +1,104 @@
+
+
+ 4.0.0
+
+
+ org.thingsboard
+ 2.2.0-SNAPSHOT
+ msa
+
+ org.thingsboard.msa
+ black-box-tests
+
+ ThingsBoard Black Box Tests
+ https://thingsboard.io
+ Project for ThingsBoard black box testing with using Docker
+
+
+ UTF-8
+ ${basedir}/../..
+ true
+ 1.9.1
+ 1.3.9
+ 4.5.6
+
+
+
+
+ org.testcontainers
+ testcontainers
+ ${testcontainers.version}
+
+
+ org.java-websocket
+ Java-WebSocket
+ ${java-websocket.version}
+
+
+ org.apache.httpcomponents
+ httpclient
+ ${httpclient.version}
+
+
+ io.takari.junit
+ takari-cpsuite
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ com.google.code.gson
+ gson
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ com.google.guava
+ guava
+
+
+ org.thingsboard
+ netty-mqtt
+
+
+ org.thingsboard
+ tools
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ **/*TestSuite.java
+
+ ${blackBoxTests.skip}
+
+
+
+
+
+
diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java
new file mode 100644
index 0000000000..5ebab780be
--- /dev/null
+++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java
@@ -0,0 +1,175 @@
+/**
+ * Copyright © 2016-2018 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.msa;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.SSLContexts;
+import org.junit.*;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.thingsboard.client.tools.RestClient;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.id.DeviceId;
+import org.thingsboard.server.msa.mapper.WsTelemetryResponse;
+
+import javax.net.ssl.*;
+import java.net.URI;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+@Slf4j
+public abstract class AbstractContainerTest {
+ protected static final String HTTPS_URL = "https://localhost";
+ protected static final String WSS_URL = "wss://localhost";
+ protected static RestClient restClient;
+ protected ObjectMapper mapper = new ObjectMapper();
+
+ @BeforeClass
+ public static void before() throws Exception {
+ restClient = new RestClient(HTTPS_URL);
+ restClient.getRestTemplate().setRequestFactory(getRequestFactoryForSelfSignedCert());
+ }
+
+ protected Device createDevice(String name) {
+ return restClient.createDevice(name + RandomStringUtils.randomAlphanumeric(7), "DEFAULT");
+ }
+
+ protected WsClient subscribeToWebSocket(DeviceId deviceId, String scope, CmdsType property) throws Exception {
+ WsClient wsClient = new WsClient(new URI(WSS_URL + "/api/ws/plugins/telemetry?token=" + restClient.getToken()));
+ SSLContextBuilder builder = SSLContexts.custom();
+ builder.loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true);
+ wsClient.setSocket(builder.build().getSocketFactory().createSocket());
+ wsClient.connectBlocking();
+
+ JsonObject cmdsObject = new JsonObject();
+ cmdsObject.addProperty("entityType", EntityType.DEVICE.name());
+ cmdsObject.addProperty("entityId", deviceId.toString());
+ cmdsObject.addProperty("scope", scope);
+ cmdsObject.addProperty("cmdId", new Random().nextInt(100));
+
+ JsonArray cmd = new JsonArray();
+ cmd.add(cmdsObject);
+ JsonObject wsRequest = new JsonObject();
+ wsRequest.add(property.toString(), cmd);
+ wsClient.send(wsRequest.toString());
+ return wsClient;
+ }
+
+ protected Map getExpectedLatestValues(long ts) {
+ return ImmutableMap.builder()
+ .put("booleanKey", ts)
+ .put("stringKey", ts)
+ .put("doubleKey", ts)
+ .put("longKey", ts)
+ .build();
+ }
+
+ protected boolean verify(WsTelemetryResponse wsTelemetryResponse, String key, Long expectedTs, String expectedValue) {
+ List