Create dmf test module (#493)

* Add DMF parent module + submodules

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Fix sonar issue

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Refactor Test Module 

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* - Fix tenant is empty
- Small refactoring

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Remove org.springframework.context.annotation.Description

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Configure rabbit test template

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Fix header

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* tenant should not be empty

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Increase time out

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Increase 3 to sec.

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Fix comments

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Add port 

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>

* Fix test config

Signed-off-by: SirWayne <dennis.melzer@bosch-si.com>
This commit is contained in:
Dennis Melzer
2017-04-26 10:36:21 +02:00
committed by GitHub
parent 574fda1101
commit f608f49db0
60 changed files with 472 additions and 288 deletions

View File

@@ -14,7 +14,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-parent</artifactId>
<artifactId>hawkbit-dmf-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-dmf-amqp</artifactId>
@@ -67,10 +67,18 @@
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- Optional -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-test</artifactId>
<artifactId>hawkbit-dmf-rabbitmq-test</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
@@ -84,42 +92,11 @@
<artifactId>mariadb-java-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-jpa</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>

View File

@@ -10,6 +10,8 @@ package org.eclipse.hawkbit.amqp;
import java.net.URI;
import javax.validation.constraints.NotNull;
import org.springframework.amqp.core.Message;
/**
@@ -27,7 +29,7 @@ public interface AmqpSenderService {
* @param replyTo
* the reply to uri
*/
void sendMessage(Message message, URI replyTo);
void sendMessage(@NotNull Message message, @NotNull URI replyTo);
/**
* Extract the exchange from the uri. Default implementation removes the

View File

@@ -14,10 +14,15 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.amqp.AmqpProperties;
import org.eclipse.hawkbit.amqp.DmfApiConfiguration;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken;
import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.rabbitmq.test.AbstractAmqpIntegrationTest;
import org.eclipse.hawkbit.rabbitmq.test.AmqpTestConfiguration;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -28,15 +33,20 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.context.annotation.Description;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - Device Management Federation API")
@Stories("Amqp Authentication Message Handler")
@SpringApplicationConfiguration(classes = { RepositoryApplicationConfiguration.class, AmqpTestConfiguration.class,
DmfApiConfiguration.class })
public class AmqpAuthenticationMessageHandlerIntegrationTest extends AbstractAmqpIntegrationTest {
private static final String TARGET_SECRUITY_TOKEN = "12345";
@@ -44,6 +54,9 @@ public class AmqpAuthenticationMessageHandlerIntegrationTest extends AbstractAmq
private static final String TENANT_EXIST = "DEFAULT";
private static final String TARGET = "NewDmfTarget";
@Autowired
private AmqpProperties amqpProperties;
@Before
public void testSetup() {
enableTargetTokenAuthentification();
@@ -55,6 +68,7 @@ public class AmqpAuthenticationMessageHandlerIntegrationTest extends AbstractAmq
final Message createAndSendMessage = getDmfClient()
.sendAndReceive(new Message("".getBytes(), new MessageProperties()));
assertThat(createAndSendMessage).isNull();
assertEmptyAuthenticationMessageCount();
}
@Test
@@ -62,6 +76,7 @@ public class AmqpAuthenticationMessageHandlerIntegrationTest extends AbstractAmq
public void securityTokenIsNull() {
final Message createAndSendMessage = sendAndReceiveAuthenticationMessage(null);
assertThat(createAndSendMessage).isNull();
assertEmptyAuthenticationMessageCount();
}
@Test
@@ -71,6 +86,7 @@ public class AmqpAuthenticationMessageHandlerIntegrationTest extends AbstractAmq
FileResource.createFileResourceBySha1(TARGET_SECRUITY_TOKEN));
final Message createAndSendMessage = sendAndReceiveAuthenticationMessage(securityToken);
assertThat(createAndSendMessage).isNull();
assertEmptyAuthenticationMessageCount();
}
@Test
@@ -440,4 +456,13 @@ public class AmqpAuthenticationMessageHandlerIntegrationTest extends AbstractAmq
return AmqpSettings.AUTHENTICATION_EXCHANGE;
}
private int getAuthenticationMessageCount() {
return Integer.parseInt(getRabbitAdmin().getQueueProperties(amqpProperties.getAuthenticationReceiverQueue())
.get(RabbitAdmin.QUEUE_MESSAGE_COUNT).toString());
}
private void assertEmptyAuthenticationMessageCount() {
assertThat(getAuthenticationMessageCount()).isEqualTo(0);
}
}

View File

@@ -16,6 +16,7 @@ import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.amqp.AmqpProperties;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
@@ -42,6 +43,8 @@ import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
@@ -51,6 +54,9 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("Amqp Message Handler Service")
public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegrationTest {
@Autowired
private AmqpProperties amqpProperties;
@Test
@Description("Tests register target")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 2),
@@ -71,7 +77,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
public void registerEmptyTarget() {
createAndSendTarget("", TENANT_EXIST);
assertAllTargetsCount(0);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@@ -81,7 +87,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
public void registerWhitespaceTarget() {
createAndSendTarget("Invalid Invalid", TENANT_EXIST);
assertAllTargetsCount(0);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@@ -91,7 +97,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
public void registerInvalidNullTargets() {
createAndSendTarget(null, TENANT_EXIST);
assertAllTargetsCount(0);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@@ -103,7 +109,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().setContentType("WrongContentType");
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -115,7 +121,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().setReplyTo(null);
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -127,7 +133,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().setReplyTo("");
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -139,7 +145,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().getHeaders().remove(MessageHeaderKey.THING_ID);
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -150,7 +156,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
final Message createTargetMessage = createTargetMessage(null, TENANT_EXIST);
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -162,7 +168,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().getHeaders().remove(MessageHeaderKey.TENANT);
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -173,7 +179,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
final Message createTargetMessage = createTargetMessage(REGISTER_TARGET, null);
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -184,7 +190,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
final Message createTargetMessage = createTargetMessage(REGISTER_TARGET, "");
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -195,7 +201,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
final Message createTargetMessage = createTargetMessage(REGISTER_TARGET, "TenantNotExist");
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertThat(systemManagement.findTenants()).hasSize(1);
}
@@ -207,7 +213,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().getHeaders().remove(MessageHeaderKey.TYPE);
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -219,7 +225,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().getHeaders().put(MessageHeaderKey.TYPE, null);
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -231,7 +237,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().getHeaders().put(MessageHeaderKey.TYPE, "");
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -243,7 +249,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
createTargetMessage.getMessageProperties().getHeaders().put(MessageHeaderKey.TYPE, "NotExist");
getDmfClient().send(createTargetMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
assertAllTargetsCount(0);
}
@@ -255,7 +261,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
eventMessage.getMessageProperties().getHeaders().put(MessageHeaderKey.TOPIC, null);
getDmfClient().send(eventMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -266,7 +272,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
eventMessage.getMessageProperties().getHeaders().put(MessageHeaderKey.TOPIC, "");
getDmfClient().send(eventMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -277,7 +283,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
eventMessage.getMessageProperties().getHeaders().put(MessageHeaderKey.TOPIC, "NotExist");
getDmfClient().send(eventMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -288,7 +294,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
eventMessage.getMessageProperties().getHeaders().remove(MessageHeaderKey.TOPIC);
getDmfClient().send(eventMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -297,7 +303,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
public void updateActionStatusWithNullContent() {
final Message eventMessage = createEventMessage(TENANT_EXIST, EventTopic.UPDATE_ACTION_STATUS, null);
getDmfClient().send(eventMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -306,7 +312,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
public void updateActionStatusWithEmptyContent() {
final Message eventMessage = createEventMessage(TENANT_EXIST, EventTopic.UPDATE_ACTION_STATUS, "");
getDmfClient().send(eventMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -316,7 +322,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
final Message eventMessage = createEventMessage(TENANT_EXIST, EventTopic.UPDATE_ACTION_STATUS,
"Invalid Content");
getDmfClient().send(eventMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -327,7 +333,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
final Message eventMessage = createEventMessage(TENANT_EXIST, EventTopic.UPDATE_ACTION_STATUS,
actionUpdateStatus);
getDmfClient().send(eventMessage);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -412,7 +418,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void cancelNotAllowActionStatus() {
registerTargetAndSendActionStatus(ActionStatus.CANCELED);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -479,7 +485,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
final Long actionNotExist = actionId + 1;
sendActionUpdateStatus(new ActionUpdateStatus(actionNotExist, ActionStatus.CANCELED));
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -492,7 +498,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void canceledRejectedNotAllowActionStatus() {
registerTargetAndSendActionStatus(ActionStatus.CANCEL_REJECTED);
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
@Test
@@ -551,7 +557,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
getDmfClient().send(createUpdateAttributesMessage);
// verify
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
final AttributeUpdate controllerAttributeEmpty = new AttributeUpdate();
assertUpdateAttributes(target, controllerAttributeEmpty.getAttributes());
}
@@ -575,7 +581,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
getDmfClient().send(createUpdateAttributesMessageWrongBody);
// verify
verifyDeadLetterMessages(1);
verifyOneDeadLetterMessage();
}
private Long registerTargetAndSendActionStatus(final ActionStatus sendActionStatus) {
@@ -630,4 +636,19 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
getDmfClient().send(updateMessage);
}
private int getAuthenticationMessageCount() {
return Integer.parseInt(getRabbitAdmin().getQueueProperties(amqpProperties.getReceiverQueue())
.get(RabbitAdmin.QUEUE_MESSAGE_COUNT).toString());
}
private void assertEmptyReceiverQueueCount() {
assertThat(getAuthenticationMessageCount()).isEqualTo(0);
}
private void verifyOneDeadLetterMessage() {
assertEmptyReceiverQueueCount();
createConditionFactory().until(() -> {
Mockito.verify(getDeadletterListener(), Mockito.times(1)).handleMessage(Mockito.any());
});
}
}

View File

@@ -16,7 +16,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import org.eclipse.hawkbit.AmqpTestConfiguration;
import org.eclipse.hawkbit.amqp.DmfApiConfiguration;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
@@ -26,6 +26,9 @@ import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest;
import org.eclipse.hawkbit.integration.listener.DeadletterListener;
import org.eclipse.hawkbit.integration.listener.ReplyToListener;
import org.eclipse.hawkbit.matcher.SoftwareModuleJsonMatcher;
import org.eclipse.hawkbit.rabbitmq.test.AbstractAmqpIntegrationTest;
import org.eclipse.hawkbit.rabbitmq.test.AmqpTestConfiguration;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.Target;
@@ -39,12 +42,15 @@ import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.test.RabbitListenerTestHarness;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
/**
*
* Common class for {@link AmqpMessageHandlerServiceIntegrationTest} and
* {@link AmqpMessageDispatcherServiceIntegrationTest}.
*/
@SpringApplicationConfiguration(classes = { RepositoryApplicationConfiguration.class, AmqpTestConfiguration.class,
DmfApiConfiguration.class, DmfTestConfiguration.class })
public abstract class AmqpServiceIntegrationTest extends AbstractAmqpIntegrationTest {
protected static final String TENANT_EXIST = "DEFAULT";
@@ -230,14 +236,14 @@ public abstract class AmqpServiceIntegrationTest extends AbstractAmqpIntegration
assertThat(target.getCreatedBy()).isEqualTo(createdBy);
assertThat(target.getUpdateStatus()).isEqualTo(updateStatus);
assertThat(target.getAddress()).isEqualTo(
IpUtil.createAmqpUri(connectionFactory.getVirtualHost(), AmqpTestConfiguration.REPLY_TO_EXCHANGE));
IpUtil.createAmqpUri(connectionFactory.getVirtualHost(), DmfTestConfiguration.REPLY_TO_EXCHANGE));
}
protected Message createTargetMessage(final String target, final String tenant) {
final MessageProperties messageProperties = createMessagePropertiesWithTenant(tenant);
messageProperties.getHeaders().put(MessageHeaderKey.THING_ID, target);
messageProperties.getHeaders().put(MessageHeaderKey.TYPE, MessageType.THING_CREATED.toString());
messageProperties.setReplyTo(AmqpTestConfiguration.REPLY_TO_EXCHANGE);
messageProperties.setReplyTo(DmfTestConfiguration.REPLY_TO_EXCHANGE);
return createMessage("", messageProperties);
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.integration;
import org.eclipse.hawkbit.integration.listener.DeadletterListener;
import org.eclipse.hawkbit.integration.listener.ReplyToListener;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.test.RabbitListenerTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* DMF Test configuration.
*/
@Configuration
@RabbitListenerTest
public class DmfTestConfiguration {
public static final String REPLY_TO_EXCHANGE = "reply.queue";
@Bean
DeadletterListener deadletterListener() {
return new DeadletterListener();
}
@Bean
ReplyToListener replyToListener() {
return new ReplyToListener();
}
@Bean
Queue replyToQueue() {
return new Queue(ReplyToListener.REPLY_TO_QUEUE, false, false, true);
}
@Bean
FanoutExchange replyToExchange() {
return new FanoutExchange(REPLY_TO_EXCHANGE, false, true);
}
@Bean
Binding bindQueueToReplyToExchange() {
return BindingBuilder.bind(replyToQueue()).to(replyToExchange());
}
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.integration.listener;
import org.eclipse.hawkbit.rabbitmq.test.listener.TestRabbitListener;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;

View File

@@ -13,22 +13,23 @@ import static org.junit.Assert.fail;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.hawkbit.AmqpTestConfiguration;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.rabbitmq.test.listener.TestRabbitListener;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
public class ReplyToListener implements TestRabbitListener {
public static final String LISTENER_ID = "replyto";
public static final String REPLY_TO_QUEUE = "reply_queue";
private final Map<EventTopic, Message> eventTopicMessages = new HashMap<>();
private final Map<String, Message> deleteMessages = new HashMap<>();
@Override
@RabbitListener(id = LISTENER_ID, queues = AmqpTestConfiguration.REPLY_TO_QUEUE)
@RabbitListener(id = LISTENER_ID, queues = REPLY_TO_QUEUE)
public void handleMessage(final Message message) {
final MessageType messageType = MessageType

View File

@@ -14,11 +14,11 @@
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-parent</artifactId>
<artifactId>hawkbit-dmf-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-dmf-api</artifactId>
<name>hawkBit :: Device Management Federation API</name>
<name>hawkBit :: DMF API</name>
<dependencies>
<dependency>

View File

@@ -0,0 +1,62 @@
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<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.eclipse.hawkbit</groupId>
<artifactId>hawkbit-dmf-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-dmf-rabbitmq-test</artifactId>
<name>hawkBit :: DMF RabbitMq Test module</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-dmf-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-junit</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-test</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -6,22 +6,24 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.integration;
package org.eclipse.hawkbit.rabbitmq.test;
import static java.util.concurrent.TimeUnit.SECONDS;
import org.eclipse.hawkbit.AmqpTestConfiguration;
import org.eclipse.hawkbit.amqp.DmfApiConfiguration;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.junit.BrokerRunning;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
@@ -29,8 +31,7 @@ import org.springframework.test.annotation.DirtiesContext.ClassMode;
import com.jayway.awaitility.Awaitility;
import com.jayway.awaitility.core.ConditionFactory;
@SpringApplicationConfiguration(classes = { RepositoryApplicationConfiguration.class, AmqpTestConfiguration.class,
DmfApiConfiguration.class })
@SpringApplicationConfiguration(classes = { RepositoryApplicationConfiguration.class, AmqpTestConfiguration.class })
// Dirty context is necessary to create a new vhost and recreate all necessary
// beans after every test class.
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
@@ -41,12 +42,16 @@ public abstract class AbstractAmqpIntegrationTest extends AbstractIntegrationTes
public BrokerRunning brokerRunning;
@Autowired
@Qualifier("dmfClient")
private ConnectionFactory connectionFactory;
@Autowired
private RabbitAdmin rabbitAdmin;
private RabbitTemplate dmfClient;
@Before
public void setup() {
dmfClient.setExchange(getExchange());
dmfClient = createDmfClient();
}
protected abstract String getExchange();
@@ -67,4 +72,30 @@ public abstract class AbstractAmqpIntegrationTest extends AbstractIntegrationTes
return getDmfClient().getMessageConverter().toMessage(payload, messageProperties);
}
protected int getQueueMessageCount(String queueName) {
return Integer
.parseInt(rabbitAdmin.getQueueProperties(queueName).get(RabbitAdmin.QUEUE_MESSAGE_COUNT).toString());
}
protected RabbitAdmin getRabbitAdmin() {
return rabbitAdmin;
}
private RabbitTemplate createDmfClient() {
final RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(new Jackson2JsonMessageConverter());
template.setReceiveTimeout(TimeUnit.SECONDS.toMillis(3));
template.setReplyTimeout(TimeUnit.SECONDS.toMillis(3));
template.setExchange(getExchange());
return template;
}
protected String getVirtualHost() {
return connectionFactory.getVirtualHost();
}
protected int getPort() {
return connectionFactory.getPort();
}
}

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit;
package org.eclipse.hawkbit.rabbitmq.test;
import java.net.MalformedURLException;
import java.net.URL;
@@ -15,29 +15,21 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.RabbitMqSetupService.AlivenessException;
import org.eclipse.hawkbit.amqp.AmqpProperties;
import org.eclipse.hawkbit.HawkbitServerProperties;
import org.eclipse.hawkbit.api.HostnameResolver;
import org.eclipse.hawkbit.integration.listener.DeadletterListener;
import org.eclipse.hawkbit.integration.listener.ReplyToListener;
import org.eclipse.hawkbit.rabbitmq.test.RabbitMqSetupService.AlivenessException;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.junit.BrokerRunning;
import org.springframework.amqp.rabbit.test.RabbitListenerTest;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@@ -49,22 +41,12 @@ import com.google.common.base.Throwables;
*
*/
@Configuration
@EnableConfigurationProperties({ AmqpProperties.class })
@RabbitListenerTest
public class AmqpTestConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(AmqpTestConfiguration.class);
public static final String REPLY_TO_EXCHANGE = "reply.queue";
public static final String REPLY_TO_QUEUE = "reply_queue";
/**
* @return the {@link SystemSecurityContext} singleton bean which make it
* accessible in beans which cannot access the service directly,
* e.g. JPA entities.
*/
@Bean
public SystemSecurityContextHolder systemSecurityContextHolder() {
SystemSecurityContextHolder systemSecurityContextHolder() {
return SystemSecurityContextHolder.getInstance();
}
@@ -73,33 +55,23 @@ public class AmqpTestConfiguration {
return new DelegatingSecurityContextExecutorService(Executors.newSingleThreadExecutor());
}
/**
* @return {@link TaskExecutor} for task execution
*/
@Bean
public TaskExecutor taskExecutor() {
TaskExecutor taskExecutor() {
return new ConcurrentTaskExecutor(asyncExecutor());
}
/**
* @return {@link ScheduledExecutorService} based on
* {@link #threadPoolTaskScheduler()}.
*/
@Bean
public ScheduledExecutorService scheduledExecutorService() {
ScheduledExecutorService scheduledExecutorService() {
return threadPoolTaskScheduler().getScheduledExecutor();
}
/**
* @return {@link ThreadPoolTaskScheduler} for scheduled operations.
*/
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
@Bean
public HostnameResolver hostnameResolver(final HawkbitServerProperties serverProperties) {
HostnameResolver hostnameResolver(final HawkbitServerProperties serverProperties) {
return () -> {
try {
return new URL(serverProperties.getUrl());
@@ -109,42 +81,8 @@ public class AmqpTestConfiguration {
};
}
@Bean(name = "dmfClient")
public RabbitTemplate dmfClient(ConnectionFactory connectionFactory) {
final RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(new Jackson2JsonMessageConverter());
template.setReceiveTimeout(TimeUnit.SECONDS.toMillis(5));
return template;
}
@Bean
public Queue replyToQueue() {
return new Queue(REPLY_TO_QUEUE, false, false, true);
}
@Bean
public FanoutExchange replyToExchange() {
return new FanoutExchange(REPLY_TO_EXCHANGE, false, true);
}
@Bean
public Binding bindQueueToReplyToExchange() {
return BindingBuilder.bind(replyToQueue()).to(replyToExchange());
}
@Bean
public DeadletterListener deadletterListener() {
return new DeadletterListener();
}
@Bean
public ReplyToListener replyToListener() {
return new ReplyToListener();
}
@Bean
public ConnectionFactory rabbitConnectionFactory(final RabbitMqSetupService rabbitmqSetupService)
throws AlivenessException {
ConnectionFactory rabbitConnectionFactory(final RabbitMqSetupService rabbitmqSetupService) {
final CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setHost(rabbitmqSetupService.getHostname());
factory.setPort(5672);
@@ -152,7 +90,9 @@ public class AmqpTestConfiguration {
factory.setPassword(rabbitmqSetupService.getPassword());
try {
factory.setVirtualHost(rabbitmqSetupService.createVirtualHost());
} catch (final Exception e) {
// All exception are catched. The BrokerRunning decide if the
// test should break or not
} catch (@SuppressWarnings("squid:S2221") final Exception e) {
Throwables.propagateIfInstanceOf(e, AlivenessException.class);
LOG.error("Cannot create virtual host {}", e.getMessage());
}
@@ -160,12 +100,22 @@ public class AmqpTestConfiguration {
}
@Bean
public RabbitMqSetupService rabbitmqSetupService(RabbitProperties properties) {
RabbitMqSetupService rabbitmqSetupService(RabbitProperties properties) {
return new RabbitMqSetupService(properties);
}
@Bean
public BrokerRunning brokerRunning(RabbitMqSetupService rabbitmqSetupService) {
@Primary
public RabbitTemplate rabbitTemplateForTest(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
rabbitTemplate.setReplyTimeout(TimeUnit.SECONDS.toMillis(3));
rabbitTemplate.setReceiveTimeout(TimeUnit.SECONDS.toMillis(3));
return rabbitTemplate;
}
@Bean
BrokerRunning brokerRunning(RabbitMqSetupService rabbitmqSetupService) {
final BrokerRunning brokerRunning = BrokerRunning.isRunning();
brokerRunning.setHostName(rabbitmqSetupService.getHostname());
brokerRunning.getConnectionFactory().setUsername(rabbitmqSetupService.getUsername());

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit;
package org.eclipse.hawkbit.rabbitmq.test;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
@@ -30,7 +30,12 @@ import com.rabbitmq.http.client.domain.UserPermissions;
*/
public class RabbitMqSetupService {
private static Client rabbitmqHttpClient;
private static final String GUEST = "guest";
private static final String DEFAULT_USER = GUEST;
private static final String DEFAULT_PASSWORD = GUEST;
private Client rabbitmqHttpClient;
private String virtualHost;
private final String hostname;
@@ -43,20 +48,20 @@ public class RabbitMqSetupService {
hostname = properties.getHost();
username = properties.getUsername();
if (StringUtils.isEmpty(username)) {
username = "guest";
username = DEFAULT_USER;
}
password = properties.getPassword();
if (StringUtils.isEmpty(password)) {
password = "guest";
password = DEFAULT_PASSWORD;
}
}
private Client getRabbitmqHttpClient() {
private synchronized Client getRabbitmqHttpClient() {
if (rabbitmqHttpClient == null) {
try {
rabbitmqHttpClient = new Client("http://" + getHostname() + ":15672/api/", getUsername(),
getPassword());
rabbitmqHttpClient = new Client(getHttpApiUrl(), getUsername(), getPassword());
} catch (MalformedURLException | URISyntaxException e) {
throw Throwables.propagate(e);
}
@@ -64,7 +69,12 @@ public class RabbitMqSetupService {
return rabbitmqHttpClient;
}
String createVirtualHost() throws JsonProcessingException, AlivenessException {
public String getHttpApiUrl() {
return "http://" + getHostname() + ":15672/api/";
}
@SuppressWarnings("squid:S1162")
public String createVirtualHost() throws JsonProcessingException {
if (!getRabbitmqHttpClient().alivenessTest("/")) {
throw new AlivenessException(getHostname());
@@ -77,7 +87,7 @@ public class RabbitMqSetupService {
}
@PreDestroy
void deleteVirtualHost() {
public void deleteVirtualHost() {
if (StringUtils.isEmpty(virtualHost)) {
return;
}
@@ -105,7 +115,7 @@ public class RabbitMqSetupService {
return permissions;
}
static class AlivenessException extends Exception {
static class AlivenessException extends RuntimeException {
private static final long serialVersionUID = 1L;
public AlivenessException(String hostname) {

View File

@@ -6,11 +6,18 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.integration.listener;
package org.eclipse.hawkbit.rabbitmq.test.listener;
import org.springframework.amqp.core.Message;
@FunctionalInterface
public interface TestRabbitListener {
/**
* handle incoming message
*
* @param message
* the message
*/
void handleMessage(Message message);
}

View File

@@ -0,0 +1,34 @@
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
-->
<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.eclipse.hawkbit</groupId>
<version>0.2.0-SNAPSHOT</version>
<artifactId>hawkbit-parent</artifactId>
</parent>
<artifactId>hawkbit-dmf-parent</artifactId>
<name>hawkBit :: Device Management Federation</name>
<packaging>pom</packaging>
<properties>
<jacoco.outputDir>${project.basedir}/../../target/</jacoco.outputDir>
</properties>
<modules>
<module>hawkbit-dmf-api</module>
<module>hawkbit-dmf-amqp</module>
<module>hawkbit-dmf-rabbitmq-test</module>
</modules>
</project>

View File

@@ -42,7 +42,6 @@ import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.context.annotation.Description;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
@@ -50,6 +49,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.jayway.jsonpath.JsonPath;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Step;
import ru.yandex.qatools.allure.annotations.Stories;

View File

@@ -22,8 +22,8 @@ import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Description;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;

View File

@@ -43,13 +43,13 @@ import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.eclipse.hawkbit.rest.util.SuccessCondition;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Description;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.http.MediaType;
import com.google.common.collect.Lists;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Step;
import ru.yandex.qatools.allure.annotations.Stories;

View File

@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
import org.eclipse.persistence.annotations.Multitenant;
import org.eclipse.persistence.annotations.MultitenantType;
import org.eclipse.persistence.annotations.TenantDiscriminatorColumn;
import org.hibernate.validator.constraints.NotEmpty;
/**
* Holder of the base attributes common to all tenant aware entities.
@@ -33,6 +34,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
@Column(name = "tenant", nullable = false, insertable = false, updatable = false, length = 40)
@Size(max = 40)
@NotEmpty
private String tenant;
/**

View File

@@ -24,6 +24,7 @@ import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.eclipse.hawkbit.repository.model.TenantMetaData;
import org.hibernate.validator.constraints.NotEmpty;
/**
* Tenant entity with meta data that is configured globally for the entire
@@ -45,6 +46,7 @@ public class JpaTenantMetaData extends AbstractJpaBaseEntity implements TenantMe
@Column(name = "tenant", nullable = false, updatable = false, length = 40)
@Size(max = 40)
@NotEmpty
private String tenant;
@OneToOne(fetch = FetchType.LAZY)

View File

@@ -15,9 +15,9 @@ import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import org.springframework.context.annotation.Description;
import org.springframework.security.core.GrantedAuthority;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;

View File

@@ -13,13 +13,13 @@ import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Description;
import com.google.gwt.core.client.GWT;
import com.google.gwtmockito.GwtMockitoTestRunner;
import com.vaadin.client.UIDL;
import com.vaadin.client.ui.dd.VDragEvent;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@@ -31,25 +31,25 @@ public class ItemIdClientCriterionTest {
@Test
@Description("Verifies that drag source is not valid for the configured id (strict mode)")
public void noMatchInStrictMode() {
ItemIdClientCriterion cut = new ItemIdClientCriterion();
final ItemIdClientCriterion cut = new ItemIdClientCriterion();
// prepare drag-event:
String testId = "thisId";
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(testId);
final String testId = "thisId";
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(testId);
// prepare configuration:
UIDL uidl = GWT.create(UIDL.class);
String configuredId = "component0";
String id = "this";
final UIDL uidl = GWT.create(UIDL.class);
final String configuredId = "component0";
final String id = "this";
when(uidl.getStringAttribute(configuredId)).thenReturn(id);
String configuredMode = "m";
String strictMode = "s";
final String configuredMode = "m";
final String strictMode = "s";
when(uidl.getStringAttribute(configuredMode)).thenReturn(strictMode);
String count = "c";
final String count = "c";
when(uidl.getIntAttribute(count)).thenReturn(1);
// act
boolean result = cut.accept(dragEvent, uidl);
final boolean result = cut.accept(dragEvent, uidl);
// verify that in strict mode: [thisId !equals this]
assertThat(result).as("Expected: [" + id + " !equals " + testId + "].").isFalse();
@@ -58,25 +58,25 @@ public class ItemIdClientCriterionTest {
@Test
@Description("Verifies that drag source is valid for the configured id (strict mode)")
public void matchInStrictMode() {
ItemIdClientCriterion cut = new ItemIdClientCriterion();
final ItemIdClientCriterion cut = new ItemIdClientCriterion();
// prepare drag-event:
String testId = "thisId";
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(testId);
final String testId = "thisId";
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(testId);
// prepare configuration:
UIDL uidl = GWT.create(UIDL.class);
String configuredId = "component0";
String id = "thisId";
final UIDL uidl = GWT.create(UIDL.class);
final String configuredId = "component0";
final String id = "thisId";
when(uidl.getStringAttribute(configuredId)).thenReturn(id);
String configuredMode = "m";
String strictMode = "s";
final String configuredMode = "m";
final String strictMode = "s";
when(uidl.getStringAttribute(configuredMode)).thenReturn(strictMode);
String count = "c";
final String count = "c";
when(uidl.getIntAttribute(count)).thenReturn(1);
// act
boolean result = cut.accept(dragEvent, uidl);
final boolean result = cut.accept(dragEvent, uidl);
// verify that in strict mode: [thisId equals thisId]
assertThat(result).as("Expected: [" + id + " equals " + testId + "].").isTrue();
@@ -85,25 +85,25 @@ public class ItemIdClientCriterionTest {
@Test
@Description("Verifies that drag source is not valid for the configured id (prefix mode)")
public void noMatchInPrefixMode() {
ItemIdClientCriterion cut = new ItemIdClientCriterion();
final ItemIdClientCriterion cut = new ItemIdClientCriterion();
// prepare drag-event:
String testId = "thisId";
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(testId);
final String testId = "thisId";
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(testId);
// prepare configuration:
UIDL uidl = GWT.create(UIDL.class);
String configuredId = "component0";
String prefix = "any";
final UIDL uidl = GWT.create(UIDL.class);
final String configuredId = "component0";
final String prefix = "any";
when(uidl.getStringAttribute(configuredId)).thenReturn(prefix);
String configuredMode = "m";
String prefixMode = "p";
final String configuredMode = "m";
final String prefixMode = "p";
when(uidl.getStringAttribute(configuredMode)).thenReturn(prefixMode);
String count = "c";
final String count = "c";
when(uidl.getIntAttribute(count)).thenReturn(1);
// act
boolean result = cut.accept(dragEvent, uidl);
final boolean result = cut.accept(dragEvent, uidl);
// verify that in strict mode: [thisId !startsWith any]
assertThat(result).as("Expected: [" + testId + " !startsWith " + prefix + "].").isFalse();
@@ -112,25 +112,25 @@ public class ItemIdClientCriterionTest {
@Test
@Description("Verifies that drag source is valid for the configured id (prefix mode)")
public void matchInPrefixMode() {
ItemIdClientCriterion cut = new ItemIdClientCriterion();
final ItemIdClientCriterion cut = new ItemIdClientCriterion();
// prepare drag-event:
String testId = "thisId";
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(testId);
final String testId = "thisId";
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(testId);
// prepare configuration:
UIDL uidl = GWT.create(UIDL.class);
String configuredId = "component0";
String prefix = "this";
final UIDL uidl = GWT.create(UIDL.class);
final String configuredId = "component0";
final String prefix = "this";
when(uidl.getStringAttribute(configuredId)).thenReturn(prefix);
String configuredMode = "m";
String prefixMode = "p";
final String configuredMode = "m";
final String prefixMode = "p";
when(uidl.getStringAttribute(configuredMode)).thenReturn(prefixMode);
String count = "c";
final String count = "c";
when(uidl.getIntAttribute(count)).thenReturn(1);
// act
boolean result = cut.accept(dragEvent, uidl);
final boolean result = cut.accept(dragEvent, uidl);
// verify that in strict mode: [thisId startsWith this]
assertThat(result).as("Expected: [" + testId + " startsWith " + prefix + "].").isTrue();

View File

@@ -20,7 +20,6 @@ import org.eclipse.hawkbit.ui.dd.client.criteria.ViewClientCriterion.ViewCriteri
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.context.annotation.Description;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
@@ -35,6 +34,7 @@ import com.vaadin.client.ui.VDragAndDropWrapper;
import com.vaadin.client.ui.VScrollTable;
import com.vaadin.client.ui.dd.VDragEvent;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@@ -47,11 +47,11 @@ public class ViewClientCriterionTest {
@Test
@Description("Verfies compilation of template strings.")
public void verifyCompiledTemplateStrings() {
ViewCriterionTemplates templates = GWT.create(ViewCriterionTemplates.class);
final ViewCriterionTemplates templates = GWT.create(ViewCriterionTemplates.class);
// compile templates
String multiSelectionStyle = templates.multiSelectionStyle("my-theme", "10").asString();
String notificationMsg = templates.notificationMsg("some-message").asString();
final String multiSelectionStyle = templates.multiSelectionStyle("my-theme", "10").asString();
final String notificationMsg = templates.notificationMsg("some-message").asString();
// assure compilation
assertThat(multiSelectionStyle).as("Expected: Compiled template string").isNotNull();
@@ -61,13 +61,13 @@ public class ViewClientCriterionTest {
@Test
@Description("Process serialized config for hiding the drop hints.")
public void processSerializedDropTargetHintsConfig() {
ViewClientCriterion cut = new ViewClientCriterion();
final ViewClientCriterion cut = new ViewClientCriterion();
// prepare configuration:
Document document = Document.get();
UIDL uidl = GWT.create(UIDL.class);
final Document document = Document.get();
final UIDL uidl = GWT.create(UIDL.class);
when(uidl.getIntAttribute("cdac")).thenReturn(3);
Element[] elements = new Element[3];
final Element[] elements = new Element[3];
for (int i = 0; i < 3; i++) {
when(uidl.getStringAttribute("dac" + String.valueOf(i))).thenReturn("itemId" + String.valueOf(i));
elements[i] = Mockito.mock(Element.class);
@@ -95,11 +95,11 @@ public class ViewClientCriterionTest {
@Test
@Description("Exception occures when processing serialized config for hiding the drop hints.")
public void exceptionWhenProcessingDropTargetHintsDataStructure() {
ViewClientCriterion cut = new ViewClientCriterion();
final ViewClientCriterion cut = new ViewClientCriterion();
// prepare configuration:
Document document = Document.get();
UIDL uidl = GWT.create(UIDL.class);
final Document document = Document.get();
final UIDL uidl = GWT.create(UIDL.class);
when(uidl.getIntAttribute("cdac")).thenReturn(2);
when(uidl.getStringAttribute("dac0")).thenReturn("no-problem");
when(uidl.getStringAttribute("dac1")).thenReturn("problem-bear");
@@ -114,7 +114,7 @@ public class ViewClientCriterionTest {
// cross-check that problem-bear was never invoked
verify(document, Mockito.never()).getElementById("problem-bear");
} catch (RuntimeException re) {
} catch (final RuntimeException re) {
fail("Exception is not re-thrown in order to continue with the loop");
} finally {
reset(Document.get());
@@ -124,12 +124,12 @@ public class ViewClientCriterionTest {
@Test
@Description("Check multi row drag decoration with non-table widget")
public void processMultiRowDragDecorationNonTable() {
ViewClientCriterion cut = new ViewClientCriterion();
final ViewClientCriterion cut = new ViewClientCriterion();
// prepare drag-event with non table widget:
VDragAndDropWrapper nonTable = Mockito.mock(VDragAndDropWrapper.class);
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent("thisId", nonTable);
Document document = Document.get();
final VDragAndDropWrapper nonTable = Mockito.mock(VDragAndDropWrapper.class);
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent("thisId", nonTable);
final Document document = Document.get();
// act
cut.setMultiRowDragDecoration(dragEvent);
@@ -141,18 +141,18 @@ public class ViewClientCriterionTest {
@Test
@Description("Check multi row drag decoration with single selection")
public void processMultiRowDragDecorationSingleSelection() {
ViewClientCriterion cut = new ViewClientCriterion();
final ViewClientCriterion cut = new ViewClientCriterion();
// prepare table
VScrollTable table = Mockito.spy(new VScrollTable());
final VScrollTable table = Mockito.spy(new VScrollTable());
table.selectedRowKeys.add("one");
// prepare drag-event with table widget:
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent("thisId", table);
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent("thisId", table);
// prepare document
Document document = Document.get();
Element ele = Mockito.mock(Element.class);
final Document document = Document.get();
final Element ele = Mockito.mock(Element.class);
when(document.getElementById(ViewClientCriterion.SP_DRAG_COUNT)).thenReturn(ele);
try {
@@ -172,21 +172,21 @@ public class ViewClientCriterionTest {
@Test
@Description("Check multi row drag decoration with a single item dragged while a multi selection is active in table")
public void processMultiRowDragDecorationMultiSelectionNotDragged() {
ViewClientCriterion cut = new ViewClientCriterion();
final ViewClientCriterion cut = new ViewClientCriterion();
// prepare table
VScrollTable table = Mockito.spy(new VScrollTable());
final VScrollTable table = Mockito.spy(new VScrollTable());
table.selectedRowKeys.add("one");
table.selectedRowKeys.add("two");
table.focusedRow = Mockito.mock(VScrollTable.VScrollTableBody.VScrollTableRow.class);
when(table.focusedRow.getKey()).thenReturn("another");
// prepare drag-event with table widget:
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent("thisId", table);
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent("thisId", table);
// prepare document
Document document = Document.get();
Element ele = Mockito.mock(Element.class);
final Document document = Document.get();
final Element ele = Mockito.mock(Element.class);
when(document.getElementById(ViewClientCriterion.SP_DRAG_COUNT)).thenReturn(ele);
try {
@@ -206,22 +206,22 @@ public class ViewClientCriterionTest {
@Test
@Description("Check multi row drag decoration with a valid multi selection")
public void processMultiRowDragDecorationMultiSelection() {
ViewClientCriterion cut = new ViewClientCriterion();
final ViewClientCriterion cut = new ViewClientCriterion();
// prepare table
VScrollTable table = Mockito.spy(new VScrollTable());
final VScrollTable table = Mockito.spy(new VScrollTable());
table.selectedRowKeys.add("one");
table.selectedRowKeys.add("two");
table.focusedRow = Mockito.mock(VScrollTable.VScrollTableBody.VScrollTableRow.class);
when(table.focusedRow.getKey()).thenReturn("one");
// prepare drag-event with table widget:
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent("thisId", table, "myTheme");
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent("thisId", table, "myTheme");
dragEvent.getTransferable().getDragSource().getConnection().getUIConnector();
// prepare document
Document document = Document.get();
StyleElement ele = Mockito.spy(StyleElement.class);
final Document document = Document.get();
final StyleElement ele = Mockito.spy(StyleElement.class);
when(ele.getTagName()).thenReturn(StyleElement.TAG);
when(document.getElementById(ViewClientCriterion.SP_DRAG_COUNT)).thenReturn(ele);

View File

@@ -17,7 +17,6 @@ import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.context.annotation.Description;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
@@ -28,6 +27,7 @@ import com.vaadin.client.ui.dd.VDragAndDropManager;
import com.vaadin.client.ui.dd.VDragEvent;
import com.vaadin.client.ui.dd.VDropHandler;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@@ -39,13 +39,13 @@ public class ViewComponentClientCriterionTest {
@Test
@Description("Process serialized data structure for preparing the drop targets to show.")
public void processSerializedDropTargetHintsDataStructure() {
ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
final ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
// prepare configuration:
Document document = Document.get();
UIDL uidl = GWT.create(UIDL.class);
final Document document = Document.get();
final UIDL uidl = GWT.create(UIDL.class);
when(uidl.getIntAttribute("cda")).thenReturn(3);
Element[] elements = new Element[3];
final Element[] elements = new Element[3];
for (int i = 0; i < 3; i++) {
when(uidl.getStringAttribute("da" + String.valueOf(i))).thenReturn("itemId" + String.valueOf(i));
elements[i] = Mockito.mock(Element.class);
@@ -69,11 +69,11 @@ public class ViewComponentClientCriterionTest {
@Test
@Description("Exception occures when processing serialized data structure for preparing the drop targets to show.")
public void exceptionWhenProcessingDropTargetHintsDataStructure() {
ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
final ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
// prepare configuration:
Document document = Document.get();
UIDL uidl = GWT.create(UIDL.class);
final Document document = Document.get();
final UIDL uidl = GWT.create(UIDL.class);
when(uidl.getIntAttribute("cda")).thenReturn(2);
when(uidl.getStringAttribute("da0")).thenReturn("no-problem");
when(uidl.getStringAttribute("da1")).thenReturn("problem-bear");
@@ -82,7 +82,7 @@ public class ViewComponentClientCriterionTest {
// act
try {
cut.showDropTargetHints(uidl);
} catch (RuntimeException re) {
} catch (final RuntimeException re) {
fail("Exception is not re-thrown in order to continue with the loop");
}
@@ -96,19 +96,19 @@ public class ViewComponentClientCriterionTest {
@Test
@Description("Verifies that drag source is valid for the configured prefix")
public void checkDragSourceWithValidId() {
ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
final ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
// prepare drag-event:
String prefix = "this";
String id = "thisId";
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(id);
final String prefix = "this";
final String id = "thisId";
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(id);
// prepare configuration:
UIDL uidl = GWT.create(UIDL.class);
final UIDL uidl = GWT.create(UIDL.class);
when(uidl.getStringAttribute("ds")).thenReturn(prefix);
// act
boolean result = cut.isValidDragSource(dragEvent, uidl);
final boolean result = cut.isValidDragSource(dragEvent, uidl);
// assure that drag source is valid: [thisId startsWith this]
assertThat(result).as("Expected: [" + id + " startsWith " + prefix + "].").isTrue();
@@ -117,19 +117,19 @@ public class ViewComponentClientCriterionTest {
@Test
@Description("Verifies that drag source is not valid for the configured prefix")
public void checkDragSourceWithInvalidId() {
ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
final ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
// prepare drag-event:
String prefix = "this";
String id = "notThis";
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(id);
final String prefix = "this";
final String id = "notThis";
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(id);
// prepare configuration:
UIDL uidl = GWT.create(UIDL.class);
final UIDL uidl = GWT.create(UIDL.class);
when(uidl.getStringAttribute("ds")).thenReturn(prefix);
// act
boolean result = cut.isValidDragSource(dragEvent, uidl);
final boolean result = cut.isValidDragSource(dragEvent, uidl);
// assure that drag source is valid: [thisId !startsWith this]
assertThat(result).as("Expected: [" + id + " !startsWith " + prefix + "].").isFalse();
@@ -139,23 +139,23 @@ public class ViewComponentClientCriterionTest {
@Description("An exception occures while the drag source is validated against the configured prefix")
public void exceptionWhenCheckingDragSource() {
ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
final ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
// prepare drag-event:
String prefix = "this";
String id = "notThis";
VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(id);
final String prefix = "this";
final String id = "notThis";
final VDragEvent dragEvent = CriterionTestHelper.createMockedVDragEvent(id);
doThrow(new RuntimeException()).when(dragEvent).getTransferable();
// prepare configuration:
UIDL uidl = GWT.create(UIDL.class);
final UIDL uidl = GWT.create(UIDL.class);
when(uidl.getStringAttribute("ds")).thenReturn(prefix);
// act
Boolean result = null;
try {
result = cut.isValidDragSource(dragEvent, uidl);
} catch (Exception ex) {
} catch (final Exception ex) {
fail("Exception is not re-thrown");
}
@@ -166,18 +166,18 @@ public class ViewComponentClientCriterionTest {
@Test
@Description("Successfully checks if the current drop location is in the list of valid drop targets")
public void successfulCheckValidDropTarget() {
ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
final ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
// prepare drag and drop manager:
String dtargetid = "dropTarget1Id";
VDropHandler dropHandler = CriterionTestHelper.createMockedVDropHandler(dtargetid);
final String dtargetid = "dropTarget1Id";
final VDropHandler dropHandler = CriterionTestHelper.createMockedVDropHandler(dtargetid);
when(VDragAndDropManager.get().getCurrentDropHandler()).thenReturn(dropHandler);
// prepare configuration:
UIDL uidl = createUidlWithThreeDropTargets();
final UIDL uidl = createUidlWithThreeDropTargets();
// act
boolean result = cut.isValidDropTarget(uidl);
final boolean result = cut.isValidDropTarget(uidl);
// assure drop target is valid: [dropTarget1Id startsWith dropTarget1]
assertThat(result).as("Expected: [" + dtargetid + " startsWith dropTarget1].").isTrue();
@@ -186,43 +186,42 @@ public class ViewComponentClientCriterionTest {
@Test
@Description("Failed check if the current drop location is in the list of valid drop targets")
public void failedCheckValidDropTarget() {
ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
final ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
// prepare drag and drop manager:
String dtargetid = "no-hit";
VDropHandler dropHandler = CriterionTestHelper.createMockedVDropHandler(dtargetid);
final String dtargetid = "no-hit";
final VDropHandler dropHandler = CriterionTestHelper.createMockedVDropHandler(dtargetid);
when(VDragAndDropManager.get().getCurrentDropHandler()).thenReturn(dropHandler);
// prepare configuration:
UIDL uidl = createUidlWithThreeDropTargets();
final UIDL uidl = createUidlWithThreeDropTargets();
// act
boolean result = cut.isValidDropTarget(uidl);
final boolean result = cut.isValidDropTarget(uidl);
// assure "no-hit" does not match [dropTarget0,dropTarget1,dropTarget2]
assertThat(result).as("Expected: [" + dtargetid + " does not match one of the list entries].")
.isFalse();
assertThat(result).as("Expected: [" + dtargetid + " does not match one of the list entries].").isFalse();
}
@Test
@Description("An exception occures while the current drop location is validated against the list of valid drop target prefixes")
public void exceptionWhenCheckingValidDropTarget() {
ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
final ViewComponentClientCriterion cut = new ViewComponentClientCriterion();
// prepare drag and drop manager:
String dtargetid = "no-hit";
VDropHandler dropHandler = CriterionTestHelper.createMockedVDropHandler(dtargetid);
final String dtargetid = "no-hit";
final VDropHandler dropHandler = CriterionTestHelper.createMockedVDropHandler(dtargetid);
when(VDragAndDropManager.get().getCurrentDropHandler()).thenReturn(dropHandler);
doThrow(new RuntimeException()).when(dropHandler).getConnector();
// prepare configuration:
UIDL uidl = createUidlWithThreeDropTargets();
final UIDL uidl = createUidlWithThreeDropTargets();
// act
Boolean result = null;
try {
result = cut.isValidDropTarget(uidl);
} catch (Exception ex) {
} catch (final Exception ex) {
fail("Exception is not re-thrown");
}
@@ -231,7 +230,7 @@ public class ViewComponentClientCriterionTest {
}
private UIDL createUidlWithThreeDropTargets() {
UIDL uidl = GWT.create(UIDL.class);
final UIDL uidl = GWT.create(UIDL.class);
when(uidl.getIntAttribute("cdt")).thenReturn(3);
for (int i = 0; i < 3; i++) {
when(uidl.getStringAttribute("dt" + String.valueOf(i))).thenReturn("dropTarget" + String.valueOf(i));

View File

@@ -39,8 +39,7 @@
<module>hawkbit-ddi-api</module>
<module>hawkbit-ddi-dl-api</module>
<module>hawkbit-ddi-resource</module>
<module>hawkbit-dmf-api</module>
<module>hawkbit-dmf-amqp</module>
<module>hawkbit-dmf-parent</module>
<module>hawkbit-repository</module>
<module>hawkbit-security-integration</module>
<module>hawkbit-http-security</module>