thingsboard-memoizeit

Integration-tests subproject

10/16/2018 8:05:52 AM

Details

diff --git a/msa/integration-tests/pom.xml b/msa/integration-tests/pom.xml
new file mode 100644
index 0000000..a1c24f3
--- /dev/null
+++ b/msa/integration-tests/pom.xml
@@ -0,0 +1,98 @@
+<!--
+
+    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.
+
+-->
+<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>2.2.0-SNAPSHOT</version>
+        <artifactId>msa</artifactId>
+    </parent>
+    <groupId>org.thingsboard.msa</groupId>
+    <artifactId>integration-tests</artifactId>
+
+    <name>ThingsBoard Integration Tests</name>
+    <url>https://thingsboard.io</url>
+    <description>Project for ThingsBoard integration tests with using Docker</description>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <main.dir>${basedir}/../..</main.dir>
+        <integrationtests.skip>true</integrationtests.skip>
+        <testcontainers.version>1.9.1</testcontainers.version>
+        <java-websocket.version>1.3.9</java-websocket.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>testcontainers</artifactId>
+            <version>${testcontainers.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.java-websocket</groupId>
+            <artifactId>Java-WebSocket</artifactId>
+            <version>${java-websocket.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.takari.junit</groupId>
+            <artifactId>takari-cpsuite</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.thingsboard</groupId>
+            <artifactId>netty-mqtt</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.thingsboard</groupId>
+            <artifactId>tools</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <includes>
+                        <include>**/*TestSuite.java</include>
+                    </includes>
+                    <skipTests>${integrationtests.skip}</skipTests>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/msa/integration-tests/README.md b/msa/integration-tests/README.md
new file mode 100644
index 0000000..5ae6354
--- /dev/null
+++ b/msa/integration-tests/README.md
@@ -0,0 +1,18 @@
+
+## Integration tests execution
+To run the integration tests with using Docker, the local Docker images of Thingsboard's microservices should be built. <br />
+- 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:
+        
+        local-maven-build/tb-node
+        local-maven-build/tb-web-ui
+        local-maven-build/tb-web-ui 
+
+- Run the integration tests in the [msa/integration-tests](../integration-tests) directory:
+
+        mvn clean install -Dintegrationtests.skip=false
\ No newline at end of file
diff --git a/msa/integration-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java
new file mode 100644
index 0000000..ab7f101
--- /dev/null
+++ b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java
@@ -0,0 +1,112 @@
+/**
+ * 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.junit.*;
+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 java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public abstract class AbstractContainerTest {
+    protected static String httpUrl;
+    protected static String wsUrl;
+    protected static RestClient restClient;
+    protected ObjectMapper mapper = new ObjectMapper();
+
+    @BeforeClass
+    public static void before() {
+        httpUrl = "http://localhost:" + ContainerTestSuite.composeContainer.getServicePort("tb-web-ui1", ContainerTestSuite.EXPOSED_PORT);
+        wsUrl = "ws://localhost:" + ContainerTestSuite.composeContainer.getServicePort("tb-web-ui1", ContainerTestSuite.EXPOSED_PORT);
+        restClient = new RestClient(httpUrl);
+    }
+
+    protected Device createDevice(String name) {
+        return restClient.createDevice(name + RandomStringUtils.randomAlphanumeric(7), "DEFAULT");
+    }
+
+    protected WsClient subscribeToTelemetryWebSocket(DeviceId deviceId) throws URISyntaxException, InterruptedException {
+        WsClient mWs = new WsClient(new URI(wsUrl + "/api/ws/plugins/telemetry?token=" + restClient.getToken()));
+        mWs.connectBlocking(1, TimeUnit.SECONDS);
+
+        JsonObject tsSubCmd = new JsonObject();
+        tsSubCmd.addProperty("entityType", EntityType.DEVICE.name());
+        tsSubCmd.addProperty("entityId", deviceId.toString());
+        tsSubCmd.addProperty("scope", "LATEST_TELEMETRY");
+        tsSubCmd.addProperty("cmdId", new Random().nextInt(100));
+        tsSubCmd.addProperty("unsubscribe", false);
+        JsonArray wsTsSubCmds = new JsonArray();
+        wsTsSubCmds.add(tsSubCmd);
+        JsonObject wsRequest = new JsonObject();
+        wsRequest.add("tsSubCmds", wsTsSubCmds);
+        wsRequest.add("historyCmds", new JsonArray());
+        wsRequest.add("attrSubCmds", new JsonArray());
+        mWs.send(wsRequest.toString());
+        return mWs;
+    }
+
+    protected Map<String, Long> getExpectedLatestValues(long ts) {
+        return ImmutableMap.<String, Long>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<Object> list = wsTelemetryResponse.getDataValuesByKey(key);
+        return expectedTs.equals(list.get(0)) && expectedValue.equals(list.get(1));
+    }
+
+    protected boolean verify(WsTelemetryResponse wsTelemetryResponse, String key, String expectedValue) {
+        List<Object> list = wsTelemetryResponse.getDataValuesByKey(key);
+        return expectedValue.equals(list.get(1));
+    }
+
+    protected JsonObject createPayload(long ts) {
+        JsonObject values = createPayload();
+        JsonObject payload = new JsonObject();
+        payload.addProperty("ts", ts);
+        payload.add("values", values);
+        return payload;
+    }
+
+    protected JsonObject createPayload() {
+        JsonObject values = new JsonObject();
+        values.addProperty("stringKey", "value1");
+        values.addProperty("booleanKey", true);
+        values.addProperty("doubleKey", 42.0);
+        values.addProperty("longKey", 73L);
+
+        return values;
+    }
+
+}
diff --git a/msa/integration-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java
new file mode 100644
index 0000000..7cc0a0f
--- /dev/null
+++ b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java
@@ -0,0 +1,57 @@
+/**
+ * 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.connectivity;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.http.ResponseEntity;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.msa.AbstractContainerTest;
+import org.thingsboard.server.msa.WsClient;
+import org.thingsboard.server.msa.WsTelemetryResponse;
+
+import java.util.concurrent.TimeUnit;
+
+public class HttpClientTest extends AbstractContainerTest {
+
+    @Test
+    public void telemetryUpdate() throws Exception {
+        restClient.login("tenant@thingsboard.org", "tenant");
+
+        Device device = createDevice("http_");
+        DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId());
+
+        WsClient mWs = subscribeToTelemetryWebSocket(device.getId());
+        ResponseEntity deviceTelemetryResponse = restClient.getRestTemplate()
+                .postForEntity(httpUrl + "/api/v1/{credentialsId}/telemetry",
+                        mapper.readTree(createPayload().toString()),
+                        ResponseEntity.class,
+                        deviceCredentials.getCredentialsId());
+        Assert.assertTrue(deviceTelemetryResponse.getStatusCode().is2xxSuccessful());
+        TimeUnit.SECONDS.sleep(1);
+        WsTelemetryResponse actualLatestTelemetry = mapper.readValue(mWs.getLastMessage(), WsTelemetryResponse.class);
+
+        Assert.assertEquals(getExpectedLatestValues(123456789L).keySet(), actualLatestTelemetry.getLatestValues().keySet());
+
+        Assert.assertTrue(verify(actualLatestTelemetry, "booleanKey", Boolean.TRUE.toString()));
+        Assert.assertTrue(verify(actualLatestTelemetry, "stringKey", "value1"));
+        Assert.assertTrue(verify(actualLatestTelemetry, "doubleKey", Double.toString(42.0)));
+        Assert.assertTrue(verify(actualLatestTelemetry, "longKey", Long.toString(73)));
+
+        restClient.getRestTemplate().delete(httpUrl + "/api/device/" + device.getId());
+    }
+}
diff --git a/msa/integration-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java
new file mode 100644
index 0000000..4ad638e
--- /dev/null
+++ b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java
@@ -0,0 +1,111 @@
+/**
+ * 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.connectivity;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import lombok.Data;
+import org.junit.*;
+import org.thingsboard.mqtt.MqttClient;
+import org.thingsboard.mqtt.MqttClientConfig;
+import org.thingsboard.mqtt.MqttHandler;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.msa.AbstractContainerTest;
+import org.thingsboard.server.msa.WsClient;
+import org.thingsboard.server.msa.WsTelemetryResponse;
+
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.*;
+
+public class MqttClientTest extends AbstractContainerTest {
+
+    @Test
+    public void telemetryUpload() throws Exception {
+        restClient.login("tenant@thingsboard.org", "tenant");
+        Device device = createDevice("mqtt_");
+        DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId());
+
+        WsClient mWs = subscribeToTelemetryWebSocket(device.getId());
+        MqttClient mqttClient = getMqttClient(deviceCredentials);
+        mqttClient.publish("v1/devices/me/telemetry", Unpooled.wrappedBuffer(createPayload().toString().getBytes()));
+        TimeUnit.SECONDS.sleep(1);
+        WsTelemetryResponse actualLatestTelemetry = mapper.readValue(mWs.getLastMessage(), WsTelemetryResponse.class);
+
+        Assert.assertEquals(getExpectedLatestValues(123456789L).keySet(), actualLatestTelemetry.getLatestValues().keySet());
+
+        Assert.assertTrue(verify(actualLatestTelemetry, "booleanKey", Boolean.TRUE.toString()));
+        Assert.assertTrue(verify(actualLatestTelemetry, "stringKey", "value1"));
+        Assert.assertTrue(verify(actualLatestTelemetry, "doubleKey", Double.toString(42.0)));
+        Assert.assertTrue(verify(actualLatestTelemetry, "longKey", Long.toString(73)));
+
+        restClient.getRestTemplate().delete(httpUrl + "/api/device/" + device.getId());
+    }
+
+    @Test
+    public void telemetryUploadWithTs() throws Exception {
+        long ts = 1451649600512L;
+
+        restClient.login("tenant@thingsboard.org", "tenant");
+        Device device = createDevice("mqtt_");
+        DeviceCredentials deviceCredentials = restClient.getCredentials(device.getId());
+
+        WsClient mWs = subscribeToTelemetryWebSocket(device.getId());
+        MqttClient mqttClient = getMqttClient(deviceCredentials);
+        mqttClient.publish("v1/devices/me/telemetry", Unpooled.wrappedBuffer(createPayload(ts).toString().getBytes()));
+        TimeUnit.SECONDS.sleep(1);
+        WsTelemetryResponse actualLatestTelemetry = mapper.readValue(mWs.getLastMessage(), WsTelemetryResponse.class);
+
+        Assert.assertEquals(getExpectedLatestValues(ts), actualLatestTelemetry.getLatestValues());
+
+        Assert.assertTrue(verify(actualLatestTelemetry, "booleanKey", ts, Boolean.TRUE.toString()));
+        Assert.assertTrue(verify(actualLatestTelemetry, "stringKey", ts, "value1"));
+        Assert.assertTrue(verify(actualLatestTelemetry, "doubleKey", ts, Double.toString(42.0)));
+        Assert.assertTrue(verify(actualLatestTelemetry, "longKey", ts, Long.toString(73)));
+
+        restClient.getRestTemplate().delete(httpUrl + "/api/device/" + device.getId());
+    }
+
+    private MqttClient getMqttClient(DeviceCredentials deviceCredentials) throws InterruptedException {
+        MqttMessageListener queue = new MqttMessageListener();
+        MqttClientConfig clientConfig = new MqttClientConfig();
+        clientConfig.setClientId("MQTT client from test");
+        clientConfig.setUsername(deviceCredentials.getCredentialsId());
+        MqttClient mqttClient = MqttClient.create(clientConfig, queue);
+        mqttClient.connect("localhost", 1883).sync();
+        return mqttClient;
+    }
+
+    @Data
+    private class MqttMessageListener implements MqttHandler {
+        private final BlockingQueue<MqttEvent> events;
+
+        private MqttMessageListener() {
+            events = new ArrayBlockingQueue<>(100);
+        }
+
+        @Override
+        public void onMessage(String topic, ByteBuf message) {
+            events.add(new MqttEvent(topic, message.toString(StandardCharsets.UTF_8)));
+        }
+    }
+
+    @Data
+    private class MqttEvent {
+        private final String topic;
+        private final String message;
+    }
+}
diff --git a/msa/integration-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java
new file mode 100644
index 0000000..fd2de22
--- /dev/null
+++ b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java
@@ -0,0 +1,37 @@
+/**
+ * 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 org.junit.ClassRule;
+import org.junit.extensions.cpsuite.ClasspathSuite;
+import org.junit.runner.RunWith;
+import org.testcontainers.containers.DockerComposeContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+
+import java.io.File;
+
+@RunWith(ClasspathSuite.class)
+@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.msa.*"})
+public class ContainerTestSuite {
+    static final int EXPOSED_PORT = 8080;
+
+    @ClassRule
+    public static DockerComposeContainer composeContainer = new DockerComposeContainer(new File("./../docker/docker-compose.yml"))
+            .withPull(false)
+            .withLocalCompose(true)
+            .withTailChildContainers(true)
+            .withExposedService("tb-web-ui1", EXPOSED_PORT, Wait.forHttp("/login"));
+}
diff --git a/msa/integration-tests/src/test/java/org/thingsboard/server/msa/WsClient.java b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/WsClient.java
new file mode 100644
index 0000000..2f05eee
--- /dev/null
+++ b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/WsClient.java
@@ -0,0 +1,57 @@
+/**
+ * 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 org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+
+import java.net.URI;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+public class WsClient extends WebSocketClient {
+    private final BlockingQueue<String> events;
+    private String message;
+
+    public WsClient(URI serverUri) {
+        super(serverUri);
+        events = new ArrayBlockingQueue<>(100);
+    }
+
+    @Override
+    public void onOpen(ServerHandshake serverHandshake) {
+    }
+
+    @Override
+    public void onMessage(String message) {
+        events.add(message);
+        this.message = message;
+    }
+
+    @Override
+    public void onClose(int code, String reason, boolean remote) {
+        events.clear();
+    }
+
+    @Override
+    public void onError(Exception ex) {
+        ex.printStackTrace();
+    }
+
+    public String getLastMessage() {
+        return this.message;
+    }
+}
\ No newline at end of file
diff --git a/msa/integration-tests/src/test/java/org/thingsboard/server/msa/WsTelemetryResponse.java b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/WsTelemetryResponse.java
new file mode 100644
index 0000000..834c5d1
--- /dev/null
+++ b/msa/integration-tests/src/test/java/org/thingsboard/server/msa/WsTelemetryResponse.java
@@ -0,0 +1,40 @@
+/**
+ * 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 lombok.Data;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Data
+public class WsTelemetryResponse implements Serializable {
+    private int subscriptionId;
+    private int errorCode;
+    private String errorMsg;
+    private Map<String, List<List<Object>>> data;
+    private Map<String, Object> latestValues;
+
+    public List<Object> getDataValuesByKey(String key) {
+        return data.entrySet().stream()
+                .filter(e -> e.getKey().equals(key))
+                .flatMap(e -> e.getValue().stream().flatMap(Collection::stream))
+                .collect(Collectors.toList());
+    }
+}

msa/pom.xml 1(+1 -0)

diff --git a/msa/pom.xml b/msa/pom.xml
index 21ddb4d..dd4c365 100644
--- a/msa/pom.xml
+++ b/msa/pom.xml
@@ -40,6 +40,7 @@
         <module>js-executor</module>
         <module>web-ui</module>
         <module>tb-node</module>
+        <module>integration-tests</module>
     </modules>
 
     <build>