From af0f7ceb5a8970129b28e00e74dd00018c4581cc Mon Sep 17 00:00:00 2001 From: Ammar Bikic <47420151+AmmarBikic@users.noreply.github.com> Date: Thu, 24 Oct 2019 12:13:35 +0200 Subject: [PATCH] Feature add optional name to thing created (#888) * First implementation pushed because of debugging purpose Signed-off-by: Ammar Bikic * Add name field and tests regarding name field functionality in THING_CREATED Signed-off-by: Ammar Bikic * SonarQube realted changes in name field functionality in THING_CREATED Signed-off-by: Ammar Bikic * Add name field and tests regarding name field functionality in UPDATE_ATTRIBUTES Signed-off-by: Ammar Bikic * Adapt documentation due to name field in THING_CREATED and UPDATE_ATTRIBUTES Signed-off-by: Ammar Bikic * Add integration tests regarding name field functionality in THING_CREATED Signed-off-by: Ammar Bikic * Reformat after finding format bug regarding THING_CREATED Signed-off-by: Ammar Bikic * Reformat after finding the real format bug regarding THING_CREATED Signed-off-by: Ammar Bikic * Reformat regarding THING_CREATED Signed-off-by: Ammar Bikic * Use constant in THING_CREATED Signed-off-by: Ammar Bikic * Format in THING_CREATED Signed-off-by: Ammar Bikic * Resolving peer review comments regarding THING_CREATED Signed-off-by: Ammar Bikic * Resolving peer review comments (organize imports) regarding THING_CREATED Signed-off-by: Ammar Bikic * Refactoring regarding THING_CREATED Signed-off-by: Ammar Bikic * Refactoring due to peer review Signed-off-by: Ammar Bikic * Refactoring due to peer review Signed-off-by: Ammar Bikic * Excluding UPDATE_ATTRIBUTES changes and provide functionality of updating the name property in THING_CREATED message Signed-off-by: Ammar Bikic * Refactoring due to peer review Signed-off-by: Ammar Bikic * Refactoring due to peer review Signed-off-by: Ammar Bikic * Fix SonarQube finding Signed-off-by: Ammar Bikic * Merge master into current branch Signed-off-by: Ammar Bikic * Fix peer review findings Signed-off-by: Ammar Bikic --- docs/content/apis/dmf_api.md | 12 +- .../amqp/AmqpMessageHandlerService.java | 39 ++- .../eclipse/hawkbit/amqp/BaseAmqpService.java | 2 +- .../amqp/AmqpMessageHandlerServiceTest.java | 85 +++-- .../dmf/json/model/DmfAttributeUpdate.java | 2 +- .../dmf/json/model/DmfCreateThing.java | 34 ++ .../repository/ControllerManagement.java | 163 +++++----- .../jpa/JpaControllerManagement.java | 106 ++++--- .../jpa/ControllerManagementTest.java | 170 ++++++---- .../repository/test/util/TestdataFactory.java | 300 ++++++++---------- 10 files changed, 525 insertions(+), 388 deletions(-) create mode 100644 hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfCreateThing.java diff --git a/docs/content/apis/dmf_api.md b/docs/content/apis/dmf_api.md index 48c64f5805..98ade42c47 100644 --- a/docs/content/apis/dmf_api.md +++ b/docs/content/apis/dmf_api.md @@ -52,12 +52,22 @@ Message Properties | Description content_type | The content type of the payload | String | true reply_to | Exchange to reply to. The default is sp.direct.exchange which is bound to the sp_direct_queue | String | false -Example headers +Example headers and payload: Header | MessageProperties ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- type=THING\_CREATED
tenant=tenant123
thingId=abc
sender=Lwm2m | content\_type=application/json
reply_to (optional) =sp.connector.replyTo +Payload Template (optional): + +```json +{ + "name": "String" +} +``` + +The "name" property specifies the name of the thing, which by default is the thing ID. This property is optional. + ### THING_REMOVED diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java index 7bdbd8cddd..124d420b77 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java @@ -10,6 +10,7 @@ import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT; import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED; +import static org.springframework.util.StringUtils.hasText; import java.io.Serializable; import java.net.URI; @@ -26,6 +27,7 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageType; import org.eclipse.hawkbit.dmf.json.model.DmfActionUpdateStatus; import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate; +import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing; import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; @@ -51,6 +53,7 @@ import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.support.converter.MessageConversionException; import org.springframework.data.domain.PageRequest; import org.springframework.messaging.handler.annotation.Header; import org.springframework.security.authentication.AnonymousAuthenticationToken; @@ -84,6 +87,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService { private static final String THING_ID_NULL = "ThingId is null"; + private static final String EMPTY_MESSAGE_BODY = "\"\""; + /** * Constructor. * @@ -122,7 +127,6 @@ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate, * the message type * @param tenant * the contentType of the message - * * @return a message if no message is send back to sender */ @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue:dmf_receiver}", containerFactory = "listenerContainerFactory") @@ -198,12 +202,14 @@ private static void setTenantSecurityContext(final String tenantId) { } /** - * Method to create a new target or to find the target if it already exists. + * Method to create a new target or to find the target if it already exists and + * update its poll time, status and optionally its name. * - * @param targetID - * the ID of the target/thing - * @param ip - * the ip of the target/thing + * @param message + * the message that contains replyTo property and optionally the name + * in body + * @param virtualHost + * the virtual host */ private void registerTarget(final Message message, final String virtualHost) { final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL); @@ -215,14 +221,29 @@ private void registerTarget(final Message message, final String virtualHost) { try { final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo); - final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); + final Target target; + if (isOptionalMessageBodyEmpty(message)) { + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); + } else { + checkContentTypeJson(message); + + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, convertMessage(message, DmfCreateThing.class).getName()); + + } LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); - } catch (EntityAlreadyExistsException e) { - throw new AmqpRejectAndDontRequeueException("Target already registered, message will be ignored!", e); + } catch (final EntityAlreadyExistsException e) { + throw new AmqpRejectAndDontRequeueException( + "Tried to register previously registered target, message will be ignored!", e); } } + private static boolean isOptionalMessageBodyEmpty(final Message message) { + // empty byte array message body is serialized to double-quoted string + // by message converter and should also be considered as empty + return isMessageBodyEmpty(message) || EMPTY_MESSAGE_BODY.equals(new String(message.getBody())); + } + private void sendUpdateCommandToTarget(final Target target) { if (isMultiAssignmentsEnabled()) { sendCurrentActionsAsMultiActionToTarget(target); diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java index 84f9cfb273..ca27006c40 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java @@ -69,7 +69,7 @@ protected MessageConverter getMessageConverter() { return rabbitTemplate.getMessageConverter(); } - private static boolean isMessageBodyEmpty(final Message message) { + protected static boolean isMessageBodyEmpty(final Message message) { return message.getBody() == null || message.getBody().length == 0; } diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java index 723e4028cb..4485a0fe85 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageHandlerServiceTest.java @@ -35,6 +35,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus; import org.eclipse.hawkbit.dmf.json.model.DmfActionUpdateStatus; import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate; +import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing; import org.eclipse.hawkbit.dmf.json.model.DmfDownloadResponse; import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; import org.eclipse.hawkbit.repository.ArtifactManagement; @@ -70,6 +71,7 @@ import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConversionException; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.http.HttpStatus; @@ -82,8 +84,8 @@ @Story("AmqpMessage Handler Service Test") public class AmqpMessageHandlerServiceTest { - private static final String FAIL_MESSAGE_AMQP_REJECT_REASON = AmqpRejectAndDontRequeueException.class.getSimpleName() - + " was expected, "; + private static final String FAIL_MESSAGE_AMQP_REJECT_REASON = AmqpRejectAndDontRequeueException.class + .getSimpleName() + " was expected, "; private static final String SHA1 = "12345"; private static final String VIRTUAL_HOST = "vHost"; @@ -136,6 +138,9 @@ public class AmqpMessageHandlerServiceTest { @Captor private ArgumentCaptor targetIdCaptor; + @Captor + private ArgumentCaptor uriCaptor; + @Captor private ArgumentCaptor modeCaptor; @@ -176,23 +181,60 @@ public void wrongContentType() { @Description("Tests the creation of a target/thing by calling the same method that incoming RabbitMQ messages would access.") public void createThing() { final String knownThingId = "1"; - final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); - messageProperties.setHeader(MessageHeaderKey.THING_ID, "1"); - final Message message = messageConverter.toMessage(new byte[0], messageProperties); final Target targetMock = mock(Target.class); - final ArgumentCaptor targetIdCaptor = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); + targetIdCaptor = ArgumentCaptor.forClass(String.class); + uriCaptor = ArgumentCaptor.forClass(URI.class); when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), uriCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); - amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST); + amqpMessageHandlerService.onMessage(createMessage(new byte[0], getThingCreatedMessageProperties(knownThingId)), + MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST); // verify assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); - assertThat(uriCaptor.getValue().toString()).as("Uri is not right").isEqualTo("amqp://"+VIRTUAL_HOST+"/MyTest"); + assertThat(uriCaptor.getValue().toString()).as("Uri is not right") + .isEqualTo("amqp://" + VIRTUAL_HOST + "/MyTest"); + } + + @Test + @Description("Tests the creation of a target/thing with specified name by calling the same method that incoming RabbitMQ messages would access.") + public void createThingWithName() { + final String knownThingId = "2"; + final DmfCreateThing targetProperties = new DmfCreateThing(); + targetProperties.setName("NonDefaultTargetName"); + + final Target targetMock = mock(Target.class); + + targetIdCaptor = ArgumentCaptor.forClass(String.class); + uriCaptor = ArgumentCaptor.forClass(URI.class); + final ArgumentCaptor targetNameCaptor = ArgumentCaptor.forClass(String.class); + + when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), + uriCaptor.capture(), targetNameCaptor.capture())).thenReturn(targetMock); + when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); + + amqpMessageHandlerService.onMessage( + createMessage(targetProperties, getThingCreatedMessageProperties(knownThingId)), + MessageType.THING_CREATED.name(), TENANT, "vHost"); + + assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); + assertThat(uriCaptor.getValue().toString()).as("Uri is not right").isEqualTo("amqp://vHost/MyTest"); + assertThat(targetNameCaptor.getValue()).as("Thing name is not right").isEqualTo(targetProperties.getName()); + } + + @Test + @Description("Tests not allowed body in message") + public void createThingWithWrongBody() { + final String knownThingId = "3"; + + assertThatExceptionOfType(MessageConversionException.class) + .as("MessageConversionException was excepeted due to wrong body") + .isThrownBy(() -> amqpMessageHandlerService.onMessage( + createMessage("Not allowed Body".getBytes(), getThingCreatedMessageProperties(knownThingId)), + MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST)); } @Test @@ -308,15 +350,13 @@ public void invalidEventTopic() { final Message message = new Message(new byte[0], messageProperties); assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) - .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "due to unknown message type") - .isThrownBy(() -> amqpMessageHandlerService.onMessage(message, "unknownMessageType", TENANT, - VIRTUAL_HOST)); + .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "due to unknown message type").isThrownBy( + () -> amqpMessageHandlerService.onMessage(message, "unknownMessageType", TENANT, VIRTUAL_HOST)); messageProperties.setHeader(MessageHeaderKey.TOPIC, "wrongTopic"); assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) - .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "due to unknown topic") - .isThrownBy(() -> amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, - VIRTUAL_HOST)); + .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "due to unknown topic").isThrownBy(() -> amqpMessageHandlerService + .onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST)); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.CANCEL_DOWNLOAD.name()); assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) @@ -532,12 +572,12 @@ public void deleteThing() { final String knownThingId = "1"; final MessageProperties messageProperties = createMessageProperties(MessageType.THING_REMOVED); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); - final Message message = messageConverter.toMessage(new byte[0],messageProperties); + final Message message = messageConverter.toMessage(new byte[0], messageProperties); // test amqpMessageHandlerService.onMessage(message, MessageType.THING_REMOVED.name(), TENANT, VIRTUAL_HOST); - //verify + // verify verify(controllerManagementMock).deleteExistingTarget(knownThingId); } @@ -547,11 +587,20 @@ public void deleteThingWithoutThingId() { // prepare invalid message final MessageProperties messageProperties = createMessageProperties(MessageType.THING_REMOVED); final Message message = messageConverter.toMessage(new byte[0], messageProperties); - + assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no thingId was set") .isThrownBy(() -> amqpMessageHandlerService.onMessage(message, MessageType.THING_REMOVED.name(), TENANT, VIRTUAL_HOST)); } + private MessageProperties getThingCreatedMessageProperties(String thingId) { + final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); + messageProperties.setHeader(MessageHeaderKey.THING_ID, thingId); + return messageProperties; + } + + private Message createMessage(Object object, MessageProperties messageProperties) { + return messageConverter.toMessage(object, messageProperties); + } } diff --git a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfAttributeUpdate.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfAttributeUpdate.java index ea52dac756..9985384595 100644 --- a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfAttributeUpdate.java +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfAttributeUpdate.java @@ -1,6 +1,6 @@ /** * 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 diff --git a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfCreateThing.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfCreateThing.java new file mode 100644 index 0000000000..4e6d84c5e4 --- /dev/null +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfCreateThing.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2019 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.dmf.json.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * JSON representation of the Attribute THING_CREATED message. + */ +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class DmfCreateThing { + + @JsonProperty + private String name; + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java index 3a6d43dc20..d92d9b9a54 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java @@ -46,19 +46,19 @@ public interface ControllerManagement { /** - * Adds an {@link ActionStatus} for a cancel {@link Action} including - * potential state changes for the target and the {@link Action} itself. + * Adds an {@link ActionStatus} for a cancel {@link Action} including potential + * state changes for the target and the {@link Action} itself. * * @param create * to be added * @return the updated {@link Action} - * + * * @throws EntityAlreadyExistsException * if a given entity already exists * * @throws QuotaExceededException - * if more than the allowed number of status entries or messages - * per entry are inserted + * if more than the allowed number of status entries or messages per + * entry are inserted * @throws EntityNotFoundException * if given action does not exist * @throws ConstraintViolationException @@ -93,8 +93,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul @NotNull Collection moduleId); /** - * Simple addition of a new {@link ActionStatus} entry to the {@link Action} - * . No state changes. + * Simple addition of a new {@link ActionStatus} entry to the {@link Action} . + * No state changes. * * @param create * to add to the action @@ -102,8 +102,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul * @return created {@link ActionStatus} entity * * @throws QuotaExceededException - * if more than the allowed number of status entries or messages - * per entry are inserted + * if more than the allowed number of status entries or messages per + * entry are inserted * @throws EntityNotFoundException * if given action does not exist * @throws ConstraintViolationException @@ -124,8 +124,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul * @throws EntityAlreadyExistsException * if a given entity already exists * @throws QuotaExceededException - * if more than the allowed number of status entries or messages - * per entry are inserted + * if more than the allowed number of status entries or messages per + * entry are inserted * @throws EntityNotFoundException * if action status not exist * @throws ConstraintViolationException @@ -140,7 +140,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul * {@link Target}. * * For performance reasons this method does not throw - * {@link EntityNotFoundException} in case target with given controllerId + * {@link EntityNotFoundException} in case target with given controlelrId * does not exist but will return an {@link Optional#empty()} instead. * * @param controllerId @@ -152,8 +152,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul Optional findOldestActiveActionByTarget(@NotEmpty String controllerId); /** - * Retrieves all active actions which are assigned to the target with the - * given controller ID. + * Retrieves all active actions which are assigned to the target with the given + * controller ID. * * @param pageable * pagination parameter @@ -165,8 +165,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul Page findActiveActionsByTarget(@NotNull Pageable pageable, @NotEmpty String controllerId); /** - * Get the {@link Action} entity for given actionId with all lazy - * attributes. + * Get the {@link Action} entity for given actionId with all lazy attributes. * * @param actionId * to be id of the action @@ -176,8 +175,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul Optional findActionWithDetails(long actionId); /** - * Retrieves all the {@link ActionStatus} entries of the given - * {@link Action}. + * Retrieves all the {@link ActionStatus} entries of the given {@link Action}. * * @param pageReq * pagination parameter @@ -192,11 +190,10 @@ Map> findTargetVisibleMetaDataBySoftwareModul Page findActionStatusByAction(@NotNull Pageable pageReq, long actionId); /** - * Register new target in the repository (plug-and-play) and in case it - * already exists updates {@link Target#getAddress()} and + * Register new target in the repository (plug-and-play) and in case it already + * exists updates {@link Target#getAddress()} and * {@link Target#getLastTargetQuery()} and switches if - * {@link TargetUpdateStatus#UNKNOWN} to - * {@link TargetUpdateStatus#REGISTERED}. + * {@link TargetUpdateStatus#UNKNOWN} to {@link TargetUpdateStatus#REGISTERED}. * * @param controllerId * reference @@ -208,14 +205,31 @@ Map> findTargetVisibleMetaDataBySoftwareModul Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address); /** - * Retrieves last {@link Action} for a download of an artifact of given - * module and target if exists and is not canceled. + * Register new target in the repository (plug-and-play) and in case it already + * exists updates {@link Target#getAddress()} and + * {@link Target#getLastTargetQuery()} and {@link Target#getName()} and switches if + * {@link TargetUpdateStatus#UNKNOWN} to {@link TargetUpdateStatus#REGISTERED}. + * + * @param controllerId + * reference + * @param address + * the client IP address of the target, might be {@code null} + * @param name + * the name of the target + * @return target reference + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address, String name); + + /** + * Retrieves last {@link Action} for a download of an artifact of given module + * and target if exists and is not canceled. * * @param controllerId * to look for * @param moduleId - * of the the {@link SoftwareModule} that should be assigned to - * the target + * of the the {@link SoftwareModule} that should be assigned to the + * target * @return last {@link Action} for given combination * * @throws EntityNotFoundException @@ -253,18 +267,18 @@ Map> findTargetVisibleMetaDataBySoftwareModul int getMaintenanceWindowPollCount(); /** - * Returns polling time based on the maintenance window for an action. - * Server will reduce the polling interval as the start time for maintenance - * window approaches, so that at least these many attempts are made between - * current polling until start of maintenance window. Poll time keeps - * reducing with MinPollingTime as lower limit - * {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. After the start - * of maintenance window, it resets to default + * Returns polling time based on the maintenance window for an action. Server + * will reduce the polling interval as the start time for maintenance window + * approaches, so that at least these many attempts are made between current + * polling until start of maintenance window. Poll time keeps reducing with + * MinPollingTime as lower limit + * {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. After the start of + * maintenance window, it resets to default * {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}. * * @param actionId - * id the {@link Action} for which polling time is calculated - * based on it having maintenance window or not + * id the {@link Action} for which polling time is calculated based + * on it having maintenance window or not * * @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}. */ @@ -272,20 +286,20 @@ Map> findTargetVisibleMetaDataBySoftwareModul String getPollingTimeForAction(long actionId); /** - * Checks if a given target has currently or has even been assigned to the - * given artifact through the action history list. This can e.g. indicate if - * a target is allowed to download a given artifact because it has currently - * assigned or had ever been assigned to the target and so it's visible to a - * specific target e.g. for downloading. + * Checks if a given target has currently or has even been assigned to the given + * artifact through the action history list. This can e.g. indicate if a target + * is allowed to download a given artifact because it has currently assigned or + * had ever been assigned to the target and so it's visible to a specific target + * e.g. for downloading. * * @param controllerId * the ID of the target to check * @param sha1Hash * of the artifact to verify if the given target had even been * assigned to - * @return {@code true} if the given target has currently or had ever a - * relation to the given artifact through the action history, - * otherwise {@code false} + * @return {@code true} if the given target has currently or had ever a relation + * to the given artifact through the action history, otherwise + * {@code false} * * @throws EntityNotFoundException * if target with given ID does not exist @@ -294,20 +308,20 @@ Map> findTargetVisibleMetaDataBySoftwareModul boolean hasTargetArtifactAssigned(@NotEmpty String controllerId, @NotEmpty String sha1Hash); /** - * Checks if a given target has currently or has even been assigned to the - * given artifact through the action history list. This can e.g. indicate if - * a target is allowed to download a given artifact because it has currently - * assigned or had ever been assigned to the target and so it's visible to a - * specific target e.g. for downloading. + * Checks if a given target has currently or has even been assigned to the given + * artifact through the action history list. This can e.g. indicate if a target + * is allowed to download a given artifact because it has currently assigned or + * had ever been assigned to the target and so it's visible to a specific target + * e.g. for downloading. * * @param targetId * the ID of the target to check * @param sha1Hash * of the artifact to verify if the given target had even been * assigned to - * @return {@code true} if the given target has currently or had ever a - * relation to the given artifact through the action history, - * otherwise {@code false} + * @return {@code true} if the given target has currently or had ever a relation + * to the given artifact through the action history, otherwise + * {@code false} * * @throws EntityNotFoundException * if target with given ID does not exist @@ -316,8 +330,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul boolean hasTargetArtifactAssigned(long targetId, @NotEmpty String sha1Hash); /** - * Registers retrieved status for given {@link Target} and {@link Action} if - * it does not exist yet. + * Registers retrieved status for given {@link Target} and {@link Action} if it + * does not exist yet. * * @param actionId * to the handle status for @@ -371,9 +385,8 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map getByControllerId(@NotEmpty String controllerId); /** - * Finds {@link Target} based on given ID returns found Target without - * details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()} - * possible. + * Finds {@link Target} based on given ID returns found Target without details, + * i.e. NO {@link Target#getTags()} and {@link Target#getActions()} possible. * * @param targetId * to look for. @@ -385,21 +398,20 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map get(long targetId); /** - * Retrieves the specified number of messages from action history of the - * given {@link Action} based on messageCount. Regardless of the value of + * Retrieves the specified number of messages from action history of the given + * {@link Action} based on messageCount. Regardless of the value of * messageCount, in order to restrict resource utilisation by controllers, * maximum number of messages that are retrieved from database is limited by - * {@link RepositoryConstants#MAX_ACTION_HISTORY_MSG_COUNT}. messageCount - * less then zero, retrieves the maximum allowed number of action status - * messages from history; messageCount equal zero, does not retrieve any - * message; and messageCount larger then zero, retrieves the specified - * number of messages, limited by maximum allowed number. A controller sends - * the feedback for an {@link ActionStatus} as a list of messages; while - * returning the messages, even though the messages from multiple - * {@link ActionStatus} are retrieved in descending order by the reported - * time ({@link ActionStatus#getOccurredAt()}), i.e. latest ActionStatus - * first, the sub-ordering of messages from within single - * {@link ActionStatus} is unspecified. + * {@link RepositoryConstants#MAX_ACTION_HISTORY_MSG_COUNT}. messageCount less + * then zero, retrieves the maximum allowed number of action status messages + * from history; messageCount equal zero, does not retrieve any message; and + * messageCount larger then zero, retrieves the specified number of messages, + * limited by maximum allowed number. A controller sends the feedback for an + * {@link ActionStatus} as a list of messages; while returning the messages, + * even though the messages from multiple {@link ActionStatus} are retrieved in + * descending order by the reported time ({@link ActionStatus#getOccurredAt()}), + * i.e. latest ActionStatus first, the sub-ordering of messages from within + * single {@link ActionStatus} is unspecified. * * @param actionId * to be filtered on @@ -412,10 +424,10 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map getActionHistoryMessages(long actionId, int messageCount); /** - * Cancels given {@link Action} for this {@link Target}. However, it might - * be possible that the controller will continue to work on the - * cancellation. The controller needs to acknowledge or reject the - * cancellation using {@link DdiRootController#postCancelActionFeedback}. + * Cancels given {@link Action} for this {@link Target}. However, it might be + * possible that the controller will continue to work on the cancellation. The + * controller needs to acknowledge or reject the cancellation using + * {@link DdiRootController#postCancelActionFeedback}. * * @param actionId * to be canceled @@ -442,9 +454,8 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); - return targetRepository.findOne(spec).map(target -> updateTargetStatus(target, address)) - .orElseGet(() -> createTarget(controllerId, address)); + return targetRepository.findOne(spec).map(target -> updateTarget(target, address, name)) + .orElseGet(() -> createTarget(controllerId, address, name)); } - private Target createTarget(final String controllerId, final URI address) { + private Target createTarget(final String controllerId, final URI address, String name) { + final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() - .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(controllerId) + .controllerId(controllerId).description("Plug and Play target: " + controllerId).name((StringUtils.hasText(name) ? name : controllerId)) .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); @@ -458,9 +467,8 @@ private Void updateLastTargetQueries(final String tenant, final List /** * Sets {@link Target#getLastTargetQuery()} by native SQL in order to avoid - * raising opt lock revision as this update is not mission critical and in - * fact only written by {@link ControllerManagement}, i.e. the target - * itself. + * raising opt lock revision as this update is not mission critical and in fact + * only written by {@link ControllerManagement}, i.e. the target itself. */ private void setLastTargetQuery(final String tenant, final long currentTimeMillis, final List chunk) { final Map paramMapping = Maps.newHashMapWithExpectedSize(chunk.size()); @@ -488,39 +496,40 @@ private static String formatQueryInStatementParams(final Collection para } /** - * Stores target directly to DB in case either {@link Target#getAddress()} - * or {@link Target#getUpdateStatus()} changes or the buffer queue is full. + * Stores target directly to DB in case either {@link Target#getAddress()} or + * {@link Target#getUpdateStatus()} or {@link Target#getName()} changes or the buffer queue is full. * */ - private Target updateTargetStatus(final JpaTarget toUpdate, final URI address) { - boolean storeEager = isStoreEager(toUpdate, address); - - if (TargetUpdateStatus.UNKNOWN == toUpdate.getUpdateStatus()) { - toUpdate.setUpdateStatus(TargetUpdateStatus.REGISTERED); - storeEager = true; - } - - if (storeEager || !queue.offer(new TargetPoll(toUpdate))) { - toUpdate.setAddress(address.toString()); + private Target updateTarget(final JpaTarget toUpdate, final URI address, final String name) { + if (isStoreEager(toUpdate, address, name) || !queue.offer(new TargetPoll(toUpdate))) { + if (isAddressChanged(toUpdate.getAddress(), address)) { + toUpdate.setAddress(address.toString()); + } + if (isNameChanged(toUpdate.getName(), name)) { + toUpdate.setName(name); + } + if (isStatusUnknown(toUpdate.getUpdateStatus())) { + toUpdate.setUpdateStatus(TargetUpdateStatus.REGISTERED); + } toUpdate.setLastTargetQuery(System.currentTimeMillis()); - afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher() .publishEvent(new TargetPollEvent(toUpdate, eventPublisherHolder.getApplicationId()))); - return targetRepository.save(toUpdate); } - return toUpdate; } - - private boolean isStoreEager(final JpaTarget toUpdate, final URI address) { - if (repositoryProperties.isEagerPollPersistence()) { - return true; - } else if (toUpdate.getAddress() == null) { - return true; - } else { - return !toUpdate.getAddress().equals(address); - } + private boolean isStoreEager(final JpaTarget toUpdate, final URI address, final String name) { + return repositoryProperties.isEagerPollPersistence() || isAddressChanged(toUpdate.getAddress(), address) + || isNameChanged(toUpdate.getName(), name) || isStatusUnknown(toUpdate.getUpdateStatus()); + } + private boolean isAddressChanged(final URI addressToUpdate, final URI address) { + return addressToUpdate == null || !addressToUpdate.equals(address); + } + private boolean isNameChanged(final String nameToUpdate, final String name) { + return StringUtils.hasText(name) && !nameToUpdate.equals(name); + } + private boolean isStatusUnknown(final TargetUpdateStatus statusToUpdate) { + return TargetUpdateStatus.UNKNOWN == statusToUpdate; } @Override @@ -596,8 +605,8 @@ public Action addUpdateActionStatus(final ActionStatusCreate c) { * ActionStatus updates are allowed mainly if the action is active. If the * action is not active we accept further status updates if permitted so by * repository configuration. In this case, only the values: Status.ERROR and - * Status.FINISHED are allowed. In the case of a DOWNLOAD_ONLY action, we - * accept status updates only once. + * Status.FINISHED are allowed. In the case of a DOWNLOAD_ONLY action, we accept + * status updates only once. */ private boolean isUpdatingActionStatusAllowed(final JpaAction action, final JpaActionStatus actionStatus) { @@ -732,8 +741,8 @@ public Target updateControllerAttributes(final String controllerId, final Map !isAttributeEntryValid(e))) { throw new InvalidTargetAttributeException(); @@ -744,7 +753,6 @@ public Target updateControllerAttributes(final String controllerId, final Map controllerAttributes = target.getControllerAttributes(); - final UpdateMode updateMode = mode != null ? mode : UpdateMode.MERGE; switch (updateMode) { case REMOVE: @@ -811,8 +819,8 @@ public Action registerRetrieved(final long actionId, final String message) { } /** - * Registers retrieved status for given {@link Target} and {@link Action} if - * it does not exist yet. + * Registers retrieved status for given {@link Target} and {@link Action} if it + * does not exist yet. * * @param actionId * to the handle status for diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java index 082432e5f2..ebc7dc7d71 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java @@ -92,8 +92,8 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest { @Test @Description("Verifies that management get access react as specified on calls for non existing entities by means " + "of Optional not present.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 1)}) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) }) public void nonExistingEntityAccessReturnsNotPresent() { final Target target = testdataFactory.createTarget(); final SoftwareModule module = testdataFactory.createSoftwareModuleOs(); @@ -113,8 +113,8 @@ public void nonExistingEntityAccessReturnsNotPresent() { @Test @Description("Verifies that management queries react as specified on calls for non existing entities " + " by means of throwing EntityNotFoundException.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 1)}) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) }) public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws URISyntaxException { final Target target = testdataFactory.createTarget(); final SoftwareModule module = testdataFactory.createSoftwareModuleOs(); @@ -149,13 +149,13 @@ public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws @Test @Description("Controller confirms successful update with FINISHED status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAttributesRequestedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmsUpdateWithFinished() { final Long actionId = createTargetAndAssignDs(); @@ -172,11 +172,11 @@ public void controllerConfirmsUpdateWithFinished() { @Test @Description("Controller confirmation fails with invalid messages.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmationFailsWithInvalidMessages() { final Long actionId = createTargetAndAssignDs(); @@ -200,14 +200,14 @@ public void controllerConfirmationFailsWithInvalidMessages() { @Test @Description("Controller confirms successful update with FINISHED status on a action that is on canceling. " + "Reason: The decision to ignore the cancellation is in fact up to the controller.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2), @Expect(type = CancelTargetAssignmentEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAttributesRequestedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmsUpdateWithFinishedAndIgnoresCancellationWithThat() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -223,11 +223,11 @@ public void controllerConfirmsUpdateWithFinishedAndIgnoresCancellationWithThat() @Test @Description("Update server rejects cancellation feedback if action is not in CANCELING state.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void cancellationFeedbackRejectedIfActionIsNotInCanceling() { final Long actionId = createTargetAndAssignDs(); @@ -245,13 +245,13 @@ public void cancellationFeedbackRejectedIfActionIsNotInCanceling() { @Test @Description("Controller confirms action cancellation with FINISHED status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = CancelTargetAssignmentEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmsActionCancellationWithFinished() { final Long actionId = createTargetAndAssignDs(); @@ -272,13 +272,13 @@ public void controllerConfirmsActionCancellationWithFinished() { @Test @Description("Controller confirms action cancellation with FINISHED status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = CancelTargetAssignmentEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmsActionCancellationWithCanceled() { final Long actionId = createTargetAndAssignDs(); @@ -300,13 +300,13 @@ public void controllerConfirmsActionCancellationWithCanceled() { @Test @Description("Controller rejects action cancellation with CANCEL_REJECTED status. Action goes back to RUNNING status as it expects " + "that the controller will continue the original update.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = CancelTargetAssignmentEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerRejectsActionCancellationWithReject() { final Long actionId = createTargetAndAssignDs(); @@ -328,13 +328,13 @@ public void controllerRejectsActionCancellationWithReject() { @Test @Description("Controller rejects action cancellation with ERROR status. Action goes back to RUNNING status as it expects " + "that the controller will continue the original update.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = CancelTargetAssignmentEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerRejectsActionCancellationWithError() { final Long actionId = createTargetAndAssignDs(); @@ -465,12 +465,12 @@ private void assertActionStatus(final Long actionId, final String controllerId, @Test @Description("Verifies that assignment verification works based on SHA1 hash. By design it is not important which artifact " + "is actually used for the check as long as they have an identical binary, i.e. same SHA1 hash. ") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 2), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = SoftwareModuleCreatedEvent.class, count = 6), - @Expect(type = SoftwareModuleUpdatedEvent.class, count = 2)}) + @Expect(type = SoftwareModuleUpdatedEvent.class, count = 2) }) public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() { final int artifactSize = 5 * 1024; final byte[] random = RandomUtils.nextBytes(artifactSize); @@ -500,7 +500,7 @@ public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() { @Test @Description("Register a controller which does not exist") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 2)}) public void findOrRegisterTargetIfItDoesNotExist() { final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); @@ -511,6 +511,20 @@ public void findOrRegisterTargetIfItDoesNotExist() { assertThat(targetRepository.count()).as("Only 1 target should be registered").isEqualTo(1L); } + @Test + @Description("Register a controller with name which does not exist and update its name") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 1) }) + public void findOrRegisterTargetIfItDoesNotExistWithName() { + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); + final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, + "ChangedTestName"); + assertThat(target.getId()).as("Target should be the equals").isEqualTo(sameTarget.getId()); + assertThat(target.getName()).as("Taget names should be different").isNotEqualTo(sameTarget.getName()); + assertThat(sameTarget.getName()).as("Taget name should be changed").isEqualTo("ChangedTestName"); + assertThat(targetRepository.count()).as("Only 1 target should be registred").isEqualTo(1L); + } + @Test @Description("Tries to register a target with an invalid controller id") public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionForInvalidControllerIdParam() { @@ -556,8 +570,8 @@ public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionAfterMaxRetries() @Test @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " + "exception is not rethrown when the max retries are not yet reached") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetPollEvent.class, count = 1)}) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 1) }) public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); @@ -580,6 +594,28 @@ public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRe } } + @Test + @Description("Register a controller which does not exist, then update the controller twice, first time by providing a name property and second time without a new name") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 3) , + @Expect(type = TargetUpdatedEvent.class, count = 1)}) + public void findOrRegisterTargetIfItDoesNotExistDoesUpdateNameOnExistingTargetProperly() { + + String controllerId = "12345"; + String targetName = "UpdatedName"; + + final Target newTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST); + assertThat(newTarget.getName()).isEqualTo(controllerId); + + + Target firstTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST, targetName); + assertThat(firstTimeUpdatedTarget.getName()).isEqualTo(targetName); + + //Name should not change to default (name=targetId) if target is updated without new name provided + Target secondTimeUpdatedTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist(controllerId, LOCALHOST); + assertThat(secondTimeUpdatedTarget.getName()).isEqualTo(targetName); + } + @Test @Description("Register a controller which does not exist, if a EntityAlreadyExistsException is raised, the " + "exception is rethrown and no further retries will be attempted") @@ -629,9 +665,9 @@ public void recoverFindOrRegisterTargetIfItDoesNotExistIsNotInvokedForOtherExcep @Test @Description("Verify that targetVisible metadata is returned from repository") - @ExpectEvents({@Expect(type = DistributionSetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = SoftwareModuleCreatedEvent.class, count = 3), - @Expect(type = SoftwareModuleUpdatedEvent.class, count = 6)}) + @Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) }) public void findTargetVisibleMetaDataBySoftwareModuleId() { final DistributionSet set = testdataFactory.createDistributionSet(); testdataFactory.addSoftwareModuleMetadata(set); @@ -646,8 +682,8 @@ public void findTargetVisibleMetaDataBySoftwareModuleId() { @Test @Description("Verify that controller registration does not result in a TargetPollEvent if feature is disabled") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetPollEvent.class, count = 0)}) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 0) }) public void targetPollEventNotSendIfDisabled() { repositoryProperties.setPublishTargetPollEvent(false); controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); @@ -656,12 +692,12 @@ public void targetPollEventNotSendIfDisabled() { @Test @Description("Controller tries to finish an update process after it has been finished by an error action status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void tryToFinishWithErrorUpdateProcessMoreThanOnce() { final Long actionId = createTargetAndAssignDs(); @@ -702,13 +738,13 @@ public void tryToFinishWithErrorUpdateProcessMoreThanOnce() { @Test @Description("Controller tries to finish an update process after it has been finished by an FINISHED action status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAttributesRequestedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void tryToFinishUpdateProcessMoreThanOnce() { final Long actionId = prepareFinishedUpdate().getId(); @@ -739,13 +775,13 @@ public void tryToFinishUpdateProcessMoreThanOnce() { @Test @Description("Controller tries to send an update feedback after it has been finished which is reject as the repository is " + "configured to reject that.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAttributesRequestedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void sendUpdatesForFinishUpdateProcessDroppedIfDisabled() { repositoryProperties.setRejectActionStatusForClosedAction(true); @@ -766,13 +802,13 @@ public void sendUpdatesForFinishUpdateProcessDroppedIfDisabled() { @Test @Description("Controller tries to send an update feedback after it has been finished which is accepted as the repository is " + "configured to accept them.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAttributesRequestedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { repositoryProperties.setRejectActionStatusForClosedAction(false); @@ -792,8 +828,8 @@ public void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { @Test @Description("Ensures that target attribute update is reflected by the repository.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 3)}) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetUpdatedEvent.class, count = 3) }) public void updateTargetAttributes() throws Exception { final String controllerId = "test123"; final Target target = testdataFactory.createTarget(controllerId); @@ -848,8 +884,8 @@ private void updateAttributeAndVerify(final String controllerId) { @Test @Description("Ensures that target attributes can be updated using different update modes.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 4)}) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetUpdatedEvent.class, count = 4) }) public void updateTargetAttributesWithDifferentUpdateModes() { final String controllerId = "testCtrl"; @@ -946,8 +982,8 @@ private void updateTargetAttributesWithoutUpdateMode(final String controllerId) @Test @Description("Ensures that target attribute update fails if quota hits.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 2)}) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetUpdatedEvent.class, count = 2) }) public void updateTargetAttributesFailsIfTooManyEntries() throws Exception { final String controllerId = "test123"; final int allowedAttributes = quotaManagement.getMaxAttributeEntriesPerTarget(); @@ -1025,11 +1061,11 @@ public void updateTargetAttributesFailsForInvalidAttributes() { @Test @Description("Controller providing status entries fails if providing more than permitted by quota.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerProvidesIntermediateFeedbackFailsIfQuotaHit() { final int allowStatusEntries = 10; final Long actionId = createTargetAndAssignDs(); @@ -1073,11 +1109,11 @@ public void findMessagesByActionStatusId() { @Test @Description("Verifies that the quota specifying the maximum number of status entries per action is enforced.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 2), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 2), @Expect(type = DistributionSetCreatedEvent.class, count = 2), @Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 2), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 6)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 6) }) public void addActionStatusUpdatesUntilQuotaIsExceeded() { // any distribution set assignment causes 1 status entity to be created @@ -1109,11 +1145,11 @@ public void addActionStatusUpdatesUntilQuotaIsExceeded() { @Test @Description("Verifies that the quota specifying the maximum number of messages per action status is enforced.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void createActionStatusWithTooManyMessages() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); @@ -1137,11 +1173,11 @@ public void createActionStatusWithTooManyMessages() { @Test @Description("Verifies that a DOWNLOAD_ONLY action is not marked complete when the controller reports DOWNLOAD") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerReportsDownloadForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); @@ -1158,13 +1194,13 @@ public void controllerReportsDownloadForDownloadOnlyAction() { @Test @Description("Verifies that a DOWNLOAD_ONLY action is marked complete once the controller reports DOWNLOADED") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAttributesRequestedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerReportsDownloadedForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); @@ -1181,13 +1217,13 @@ public void controllerReportsDownloadedForDownloadOnlyAction() { @Test @Description("Verifies that a controller can report a FINISHED event for a DOWNLOAD_ONLY non-active action.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 3), @Expect(type = TargetAttributesRequestedEvent.class, count = 2), @Expect(type = ActionUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerReportsActionFinishedForDownloadOnlyActionThatIsNotActive() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); @@ -1204,13 +1240,13 @@ public void controllerReportsActionFinishedForDownloadOnlyActionThatIsNotActive( @Test @Description("Verifies that multiple DOWNLOADED events for a DOWNLOAD_ONLY action are handled.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAttributesRequestedEvent.class, count = 3), @Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerReportsMultipleDownloadedForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); @@ -1229,13 +1265,13 @@ public void controllerReportsMultipleDownloadedForDownloadOnlyAction() { @Test(expected = QuotaExceededException.class) @Description("Verifies that quota is asserted when a controller reports too many DOWNLOADED events for a " + "DOWNLOAD_ONLY action.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAttributesRequestedEvent.class, count = 9), @Expect(type = ActionUpdatedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void quotaExceptionWhencontrollerReportsTooManyDownloadedMessagesForDownloadOnlyAction() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); testdataFactory.createTarget(); @@ -1248,13 +1284,13 @@ public void quotaExceptionWhencontrollerReportsTooManyDownloadedMessagesForDownl @Test @Description("Verifies that quota is enforced for UpdateActionStatus events for DOWNLOAD_ONLY assignments.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetAttributesRequestedEvent.class, count = 9), @Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void quotaExceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); testdataFactory.createTarget(); @@ -1279,11 +1315,11 @@ public void quotaExceededExceptionWhenControllerReportsTooManyUpdateActionStatus @Test @Description("Verifies that quota is enforced for UpdateActionStatus events for FORCED assignments.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 3)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void quotaExceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForForced() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); final Long actionId = createTargetAndAssignDs(); @@ -1344,13 +1380,13 @@ public void externalRefCannotBeNull() { @Test @Description("Verifies that a target can report FINISHED/ERROR updates for DOWNLOAD_ONLY assignments regardless of " + "repositoryProperties.rejectActionStatusForClosedAction value.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 4), @Expect(type = ActionCreatedEvent.class, count = 4), @Expect(type = TargetUpdatedEvent.class, count = 12), @Expect(type = TargetAssignDistributionSetEvent.class, count = 4), @Expect(type = TargetAttributesRequestedEvent.class, count = 6), @Expect(type = ActionUpdatedEvent.class, count = 8), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 12)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 12) }) public void targetCanAlwaysReportFinishedOrErrorAfterActionIsClosedForDownloadOnlyAssignments() { testdataFactory.createTarget(); @@ -1395,13 +1431,13 @@ private void finishDownloadOnlyUpdateAndSendUpdateActionStatus(final Long action @Test @Description("Verifies that a controller can report a FINISHED event for a DOWNLOAD_ONLY action after having" + " installed an intermediate update.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 2), @Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 5), @Expect(type = TargetAttributesRequestedEvent.class, count = 3), @Expect(type = ActionUpdatedEvent.class, count = 3), @Expect(type = TargetAssignDistributionSetEvent.class, count = 2), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 6)}) + @Expect(type = SoftwareModuleCreatedEvent.class, count = 6) }) public void controllerReportsFinishedForOldDownloadOnlyActionAfterSuccessfulForcedAssignment() { testdataFactory.createTarget(); diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java index debc9d8df9..5d1a38a462 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java @@ -1,6 +1,6 @@ /** * 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 @@ -117,8 +117,8 @@ public class TestdataFactory { public static final String SM_TYPE_RT = "runtime"; /** - * Key of test "application" {@link SoftwareModuleType} : optional software - * in {@link #DS_TYPE_DEFAULT}. + * Key of test "application" {@link SoftwareModuleType} : optional software in + * {@link #DS_TYPE_DEFAULT}. */ public static final String SM_TYPE_APP = "application"; @@ -160,14 +160,13 @@ public class TestdataFactory { /** * Creates {@link DistributionSet} in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and * {@link DistributionSet#isRequiredMigrationStep()} false. - * + * * @param prefix * for {@link SoftwareModule}s and {@link DistributionSet}s name, * vendor and description. - * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix) { @@ -176,10 +175,10 @@ public DistributionSet createDistributionSet(final String prefix) { /** * Creates {@link DistributionSet} in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and * {@link DistributionSet#isRequiredMigrationStep()} false. - * + * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet() { @@ -188,13 +187,12 @@ public DistributionSet createDistributionSet() { /** * Creates {@link DistributionSet} in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and * {@link DistributionSet#isRequiredMigrationStep()} false. - * + * * @param modules * of {@link DistributionSet#getModules()} - * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final Collection modules) { @@ -203,16 +201,15 @@ public DistributionSet createDistributionSet(final Collection mo /** * Creates {@link DistributionSet} in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and * {@link DistributionSet#isRequiredMigrationStep()} false. - * + * * @param modules * of {@link DistributionSet#getModules()} * @param prefix * for {@link SoftwareModule}s and {@link DistributionSet}s name, * vendor and description. - * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final Collection modules, final String prefix) { @@ -221,15 +218,14 @@ public DistributionSet createDistributionSet(final Collection mo /** * Creates {@link DistributionSet} in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION}. - * + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION}. + * * @param prefix * for {@link SoftwareModule}s and {@link DistributionSet}s name, * vendor and description. * @param isRequiredMigrationStep * for {@link DistributionSet#isRequiredMigrationStep()} - * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final boolean isRequiredMigrationStep) { @@ -238,16 +234,15 @@ public DistributionSet createDistributionSet(final String prefix, final boolean /** * Creates {@link DistributionSet} in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} and * {@link DistributionSet#isRequiredMigrationStep()} false. - * + * * @param prefix * for {@link SoftwareModule}s and {@link DistributionSet}s name, * vendor and description. * @param tags * {@link DistributionSet#getTags()} - * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final Collection tags) { @@ -256,19 +251,17 @@ public DistributionSet createDistributionSet(final String prefix, final Collecti /** * Creates {@link DistributionSet} in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP}. - * + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP}. + * * @param prefix * for {@link SoftwareModule}s and {@link DistributionSet}s name, * vendor and description. * @param version * {@link DistributionSet#getVersion()} and - * {@link SoftwareModule#getVersion()} extended by a random - * number. + * {@link SoftwareModule#getVersion()} extended by a random number. * @param isRequiredMigrationStep * for {@link DistributionSet#isRequiredMigrationStep()} - * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final String version, @@ -302,7 +295,7 @@ public DistributionSet createDistributionSet(final String prefix, final String v * {@link SoftwareModuleMetadata#isTargetVisible()} and * {@link #INVISIBLE_SM_MD_KEY}, {@link #INVISIBLE_SM_MD_VALUE} without * {@link SoftwareModuleMetadata#isTargetVisible()} - * + * * @param set * to add metadata to */ @@ -320,19 +313,17 @@ private void addTestModuleMetadata(final SoftwareModule module) { /** * Creates {@link DistributionSet} in repository. - * + * * @param prefix * for {@link SoftwareModule}s and {@link DistributionSet}s name, * vendor and description. * @param version * {@link DistributionSet#getVersion()} and - * {@link SoftwareModule#getVersion()} extended by a random - * number. + * {@link SoftwareModule#getVersion()} extended by a random number. * @param isRequiredMigrationStep * for {@link DistributionSet#isRequiredMigrationStep()} * @param modules * for {@link DistributionSet#getModules()} - * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final String version, @@ -347,9 +338,9 @@ public DistributionSet createDistributionSet(final String prefix, final String v /** * Creates {@link DistributionSet} in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP}. - * + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP}. + * * @param prefix * for {@link SoftwareModule}s and {@link DistributionSet}s name, * vendor and description. @@ -359,7 +350,6 @@ public DistributionSet createDistributionSet(final String prefix, final String v * number.updat * @param tags * {@link DistributionSet#getTags()} - * * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final String version, @@ -375,14 +365,13 @@ public DistributionSet createDistributionSet(final String prefix, final String v /** * Creates {@link DistributionSet}s in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an - * iterative number and {@link DistributionSet#isRequiredMigrationStep()} + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an iterative + * number and {@link DistributionSet#isRequiredMigrationStep()} * false. - * + * * @param number * of {@link DistributionSet}s to create - * * @return {@link List} of {@link DistributionSet} entities */ public List createDistributionSets(final int number) { @@ -391,9 +380,8 @@ public List createDistributionSets(final int number) { } /** - * Create a list of {@link DistributionSet}s without modules, i.e. - * incomplete. - * + * Create a list of {@link DistributionSet}s without modules, i.e. incomplete. + * * @param number * of {@link DistributionSet}s to create * @return {@link List} of {@link DistributionSet} entities @@ -412,17 +400,16 @@ public List createDistributionSetsWithoutModules(final int numb /** * Creates {@link DistributionSet}s in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an - * iterative number and {@link DistributionSet#isRequiredMigrationStep()} + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an iterative + * number and {@link DistributionSet#isRequiredMigrationStep()} * false. - * + * * @param prefix * for {@link SoftwareModule}s and {@link DistributionSet}s name, * vendor and description. * @param number * of {@link DistributionSet}s to create - * * @return {@link List} of {@link DistributionSet} entities */ public List createDistributionSets(final String prefix, final int number) { @@ -439,12 +426,11 @@ public List createDistributionSets(final String prefix, final i * Creates {@link DistributionSet}s in repository with * {@link #DEFAULT_DESCRIPTION} and * {@link DistributionSet#isRequiredMigrationStep()} false. - * + * * @param name * {@link DistributionSet#getName()} * @param version * {@link DistributionSet#getVersion()} - * * @return {@link DistributionSet} entity */ public DistributionSet createDistributionSetWithNoSoftwareModules(final String name, final String version) { @@ -454,12 +440,11 @@ public DistributionSet createDistributionSetWithNoSoftwareModules(final String n } /** - * Creates {@link Artifact}s for given {@link SoftwareModule} with a small - * text payload. - * + * Creates {@link Artifact}s for given {@link SoftwareModule} with a small text + * payload. + * * @param moduleId * the {@link Artifact}s belong to. - * * @return {@link Artifact} entity. */ public List createArtifacts(final Long moduleId) { @@ -473,18 +458,15 @@ public List createArtifacts(final Long moduleId) { } /** - * Create an {@link Artifact} for given {@link SoftwareModule} with a small - * text payload. - * + * Create an {@link Artifact} for given {@link SoftwareModule} with a small text + * payload. + * * @param artifactData * the {@link Artifact} Inputstream - * * @param moduleId * the {@link Artifact} belongs to - * * @param filename * that was provided during upload. - * * @return {@link Artifact} entity. */ public Artifact createArtifact(final String artifactData, final Long moduleId, final String filename) { @@ -494,36 +476,32 @@ public Artifact createArtifact(final String artifactData, final Long moduleId, f } /** - * Create an {@link Artifact} for given {@link SoftwareModule} with a small - * text payload. + * Create an {@link Artifact} for given {@link SoftwareModule} with a small text + * payload. * * @param artifactData * the {@link Artifact} Inputstream - * * @param moduleId * the {@link Artifact} belongs to - * * @param filename * that was provided during upload. - * * @param fileSize * the file size - * * @return {@link Artifact} entity. */ - public Artifact createArtifact(final byte[] artifactData, final Long moduleId, final String filename, final int fileSize) { - return artifactManagement - .create(new ArtifactUpload(new ByteArrayInputStream(artifactData), moduleId, filename, false, fileSize)); + public Artifact createArtifact(final byte[] artifactData, final Long moduleId, final String filename, + final int fileSize) { + return artifactManagement.create( + new ArtifactUpload(new ByteArrayInputStream(artifactData), moduleId, filename, false, fileSize)); } /** * Creates {@link SoftwareModule} with {@link #DEFAULT_VENDOR} and - * {@link #DEFAULT_VERSION} and random generated - * {@link Target#getDescription()} in the repository. - * + * {@link #DEFAULT_VERSION} and random generated {@link Target#getDescription()} + * in the repository. + * * @param typeKey * of the {@link SoftwareModuleType} - * * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModule(final String typeKey) { @@ -531,12 +509,10 @@ public SoftwareModule createSoftwareModule(final String typeKey) { } /** - * Creates {@link SoftwareModule} of type - * {@value Constants#SMT_DEFAULT_APP_KEY} with {@link #DEFAULT_VENDOR} and - * {@link #DEFAULT_VERSION} and random generated - * {@link Target#getDescription()} in the repository. - * - * + * Creates {@link SoftwareModule} of type {@value Constants#SMT_DEFAULT_APP_KEY} + * with {@link #DEFAULT_VENDOR} and {@link #DEFAULT_VERSION} and random + * generated {@link Target#getDescription()} in the repository. + * * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModuleApp() { @@ -544,15 +520,12 @@ public SoftwareModule createSoftwareModuleApp() { } /** - * Creates {@link SoftwareModule} of type - * {@value Constants#SMT_DEFAULT_APP_KEY} with {@link #DEFAULT_VENDOR} and - * {@link #DEFAULT_VERSION} and random generated - * {@link Target#getDescription()} in the repository. - * + * Creates {@link SoftwareModule} of type {@value Constants#SMT_DEFAULT_APP_KEY} + * with {@link #DEFAULT_VENDOR} and {@link #DEFAULT_VERSION} and random + * generated {@link Target#getDescription()} in the repository. + * * @param prefix * added to name and version - * - * * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModuleApp(final String prefix) { @@ -560,12 +533,10 @@ public SoftwareModule createSoftwareModuleApp(final String prefix) { } /** - * Creates {@link SoftwareModule} of type - * {@value Constants#SMT_DEFAULT_OS_KEY} with {@link #DEFAULT_VENDOR} and - * {@link #DEFAULT_VERSION} and random generated - * {@link Target#getDescription()} in the repository. - * - * + * Creates {@link SoftwareModule} of type {@value Constants#SMT_DEFAULT_OS_KEY} + * with {@link #DEFAULT_VENDOR} and {@link #DEFAULT_VERSION} and random + * generated {@link Target#getDescription()} in the repository. + * * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModuleOs() { @@ -573,15 +544,12 @@ public SoftwareModule createSoftwareModuleOs() { } /** - * Creates {@link SoftwareModule} of type - * {@value Constants#SMT_DEFAULT_OS_KEY} with {@link #DEFAULT_VENDOR} and - * {@link #DEFAULT_VERSION} and random generated - * {@link Target#getDescription()} in the repository. - * + * Creates {@link SoftwareModule} of type {@value Constants#SMT_DEFAULT_OS_KEY} + * with {@link #DEFAULT_VENDOR} and {@link #DEFAULT_VERSION} and random + * generated {@link Target#getDescription()} in the repository. + * * @param prefix * added to name and version - * - * * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModuleOs(final String prefix) { @@ -590,14 +558,13 @@ public SoftwareModule createSoftwareModuleOs(final String prefix) { /** * Creates {@link SoftwareModule} with {@link #DEFAULT_VENDOR} and - * {@link #DEFAULT_VERSION} and random generated - * {@link Target#getDescription()} in the repository. - * + * {@link #DEFAULT_VERSION} and random generated {@link Target#getDescription()} + * in the repository. + * * @param typeKey * of the {@link SoftwareModuleType} * @param prefix * added to name and version - * * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModule(final String typeKey, final String prefix) { @@ -619,28 +586,43 @@ public Target createTarget() { * @return persisted {@link Target} */ public Target createTarget(final String controllerId) { - final Target target = targetManagement.create(entityFactory.target().create().controllerId(controllerId)); + return createTarget(controllerId, controllerId); + } + + /** + * @param controllerId + * of the target + * @param targetName + * name of the target + * @return persisted {@link Target} + */ + public Target createTarget(final String controllerId, final String targetName) { + final Target target = targetManagement + .create(entityFactory.target().create().controllerId(controllerId).name(targetName)); + assertTargetProperlyCreated(target); + return target; + } + + private void assertTargetProperlyCreated(Target target) { assertThat(target.getCreatedBy()).isNotNull(); assertThat(target.getCreatedAt()).isNotNull(); assertThat(target.getLastModifiedBy()).isNotNull(); assertThat(target.getLastModifiedAt()).isNotNull(); assertThat(target.getUpdateStatus()).isEqualTo(TargetUpdateStatus.UNKNOWN); - return target; } /** * Creates {@link DistributionSet}s in repository including three - * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} - * , {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an - * iterative number and {@link DistributionSet#isRequiredMigrationStep()} + * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} , + * {@link #SM_TYPE_APP} with {@link #DEFAULT_VERSION} followed by an iterative + * number and {@link DistributionSet#isRequiredMigrationStep()} * false. * * In addition it updates the created {@link DistributionSet}s and - * {@link SoftwareModule}s to ensure that - * {@link BaseEntity#getLastModifiedAt()} and - * {@link BaseEntity#getLastModifiedBy()} is filled. - * + * {@link SoftwareModule}s to ensure that {@link BaseEntity#getLastModifiedAt()} + * and {@link BaseEntity#getLastModifiedBy()} is filled. + * * @return persisted {@link DistributionSet}. */ public DistributionSet createUpdatedDistributionSet() { @@ -657,8 +639,8 @@ public DistributionSet createUpdatedDistributionSet() { /** * @return {@link DistributionSetType} with key {@link #DS_TYPE_DEFAULT} and - * {@link SoftwareModuleType}s {@link #SM_TYPE_OS}, - * {@link #SM_TYPE_RT} , {@link #SM_TYPE_APP}. + * {@link SoftwareModuleType}s {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} + * , {@link #SM_TYPE_APP}. */ public DistributionSetType findOrCreateDefaultTestDsType() { final List mand = new ArrayList<>(); @@ -674,12 +656,11 @@ public DistributionSetType findOrCreateDefaultTestDsType() { /** * Creates {@link DistributionSetType} in repository. - * + * * @param dsTypeKey * {@link DistributionSetType#getKey()} * @param dsTypeName * {@link DistributionSetType#getName()} - * * @return persisted {@link DistributionSetType} */ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName) { @@ -691,7 +672,7 @@ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKe /** * Finds {@link DistributionSetType} in repository with given * {@link DistributionSetType#getKey()} or creates if it does not exist yet. - * + * * @param dsTypeKey * {@link DistributionSetType#getKey()} * @param dsTypeName @@ -700,7 +681,6 @@ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKe * {@link DistributionSetType#getMandatoryModuleTypes()} * @param optional * {@link DistributionSetType#getOptionalModuleTypes()} - * * @return persisted {@link DistributionSetType} */ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName, @@ -714,12 +694,11 @@ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKe /** * Finds {@link SoftwareModuleType} in repository with given - * {@link SoftwareModuleType#getKey()} or creates if it does not exist yet - * with {@link SoftwareModuleType#getMaxAssignments()} = 1. - * + * {@link SoftwareModuleType#getKey()} or creates if it does not exist yet with + * {@link SoftwareModuleType#getMaxAssignments()} = 1. + * * @param key * {@link SoftwareModuleType#getKey()} - * * @return persisted {@link SoftwareModuleType} */ public SoftwareModuleType findOrCreateSoftwareModuleType(final String key) { @@ -729,12 +708,11 @@ public SoftwareModuleType findOrCreateSoftwareModuleType(final String key) { /** * Finds {@link SoftwareModuleType} in repository with given * {@link SoftwareModuleType#getKey()} or creates if it does not exist yet. - * + * * @param key * {@link SoftwareModuleType#getKey()} * @param maxAssignments * {@link SoftwareModuleType#getMaxAssignments()} - * * @return persisted {@link SoftwareModuleType} */ public SoftwareModuleType findOrCreateSoftwareModuleType(final String key, final int maxAssignments) { @@ -754,7 +732,6 @@ public SoftwareModuleType findOrCreateSoftwareModuleType(final String key, final * {@link DistributionSet#getType()} * @param modules * {@link DistributionSet#getModules()} - * * @return the created {@link DistributionSet} */ public DistributionSet createDistributionSet(final String name, final String version, @@ -777,7 +754,6 @@ public DistributionSet createDistributionSet(final String name, final String ver * {@link DistributionSet#getModules()} * @param requiredMigrationStep * {@link DistributionSet#isRequiredMigrationStep()} - * * @return the created {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name, final String version, @@ -799,7 +775,6 @@ public DistributionSet generateDistributionSet(final String name, final String v * {@link DistributionSet#getType()} * @param modules * {@link DistributionSet#getModules()} - * * @return the created {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name, final String version, @@ -812,7 +787,6 @@ public DistributionSet generateDistributionSet(final String name, final String v * * @param name * {@link DistributionSet#getName()} - * * @return the generated {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name) { @@ -821,13 +795,11 @@ public DistributionSet generateDistributionSet(final String name) { } /** - * Creates {@link Target}s in repository and with - * {@link #DEFAULT_CONTROLLER_ID} as prefix for - * {@link Target#getControllerId()}. - * + * Creates {@link Target}s in repository and with {@link #DEFAULT_CONTROLLER_ID} + * as prefix for {@link Target#getControllerId()}. + * * @param number * of {@link Target}s to create - * * @return {@link List} of {@link Target} entities */ public List createTargets(final int number) { @@ -843,7 +815,7 @@ public List createTargets(final int number) { /** * Builds {@link Target} objects with given prefix for * {@link Target#getControllerId()} followed by a number suffix. - * + * * @param start * value for the controllerId suffix * @param numberOfTargets @@ -863,9 +835,8 @@ private List generateTargets(final int start, final int numberOfTargets, /** * Builds {@link Target} objects with given prefix for - * {@link Target#getControllerId()} followed by a number suffix starting - * with 0. - * + * {@link Target#getControllerId()} followed by a number suffix starting with 0. + * * @param numberOfTargets * of {@link Target}s to generate * @param controllerIdPrefix @@ -955,10 +926,9 @@ public List createTargetTags(final int number, final String tagPrefix /** * Creates {@link DistributionSetTag}s in repository. - * + * * @param number * of {@link DistributionSetTag}s - * * @return the persisted {@link DistributionSetTag}s */ public List createDistributionSetTags(final int number) { @@ -980,16 +950,14 @@ private Action sendUpdateActionStatusToTarget(final Status status, final Action } /** - * Append {@link ActionStatus} to all {@link Action}s of given - * {@link Target}s. - * + * Append {@link ActionStatus} to all {@link Action}s of given {@link Target}s. + * * @param targets * to add {@link ActionStatus} * @param status * to add * @param message * to add - * * @return updated {@link Action}. */ public List sendUpdateActionStatusToTargets(final Collection targets, final Status status, @@ -998,16 +966,14 @@ public List sendUpdateActionStatusToTargets(final Collection tar } /** - * Append {@link ActionStatus} to all {@link Action}s of given - * {@link Target}s. - * + * Append {@link ActionStatus} to all {@link Action}s of given {@link Target}s. + * * @param targets * to add {@link ActionStatus} * @param status * to add * @param msgs * to add - * * @return updated {@link Action}. */ public List sendUpdateActionStatusToTargets(final Collection targets, final Status status, @@ -1025,7 +991,7 @@ public List sendUpdateActionStatusToTargets(final Collection tar /** * Creates rollout based on given parameters. - * + * * @param rolloutName * of the {@link Rollout} * @param rolloutDescription @@ -1045,7 +1011,8 @@ public List sendUpdateActionStatusToTargets(final Collection tar public Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, final int groupSize, final String filterQuery, final DistributionSet distributionSet, final String successCondition, final String errorCondition) { - return createRolloutByVariables(rolloutName, rolloutDescription, groupSize, filterQuery, distributionSet, successCondition, errorCondition, Action.ActionType.FORCED); + return createRolloutByVariables(rolloutName, rolloutDescription, groupSize, filterQuery, distributionSet, + successCondition, errorCondition, Action.ActionType.FORCED); } /** @@ -1077,9 +1044,10 @@ public Rollout createRolloutByVariables(final String rolloutName, final String r .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) .errorAction(RolloutGroupErrorAction.PAUSE, null).build(); - final Rollout rollout = rolloutManagement.create(entityFactory.rollout().create().name(rolloutName) - .description(rolloutDescription).targetFilterQuery(filterQuery).set(distributionSet) - .actionType(actionType), groupSize, conditions); + final Rollout rollout = rolloutManagement.create( + entityFactory.rollout().create().name(rolloutName).description(rolloutDescription) + .targetFilterQuery(filterQuery).set(distributionSet).actionType(actionType), + groupSize, conditions); // Run here, because Scheduler is disabled during tests rolloutManagement.handleRollouts(); @@ -1090,10 +1058,10 @@ public Rollout createRolloutByVariables(final String rolloutName, final String r /** * Create {@link Rollout} with a new {@link DistributionSet} and * {@link Target}s. - * + * * @param prefix - * for rollouts name, description, - * {@link Target#getControllerId()} filter + * for rollouts name, description, {@link Target#getControllerId()} + * filter * @return created {@link Rollout} */ public Rollout createRollout(final String prefix) { @@ -1103,12 +1071,12 @@ public Rollout createRollout(final String prefix) { } /** - * Create the soft deleted {@link Rollout} with a new - * {@link DistributionSet} and {@link Target}s. - * + * Create the soft deleted {@link Rollout} with a new {@link DistributionSet} + * and {@link Target}s. + * * @param prefix - * for rollouts name, description, - * {@link Target#getControllerId()} filter + * for rollouts name, description, {@link Target#getControllerId()} + * filter * @return created {@link Rollout} */ public Rollout createSoftDeletedRollout(final String prefix) {