From 64b741f9f3b316c3b7dcd7936615c97335af92fc Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 6 Sep 2019 13:32:44 +0200 Subject: [PATCH 01/22] First implementation pushed because of debugging purpose Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 160 ++++++++++++------ .../eclipse/hawkbit/amqp/BaseAmqpService.java | 9 + .../dmf/json/model/DmfTargetProperties.java | 37 ++++ .../repository/ControllerManagement.java | 17 ++ .../jpa/JpaControllerManagement.java | 140 +++++++++------ 5 files changed, 256 insertions(+), 107 deletions(-) create mode 100644 hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java 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 9c36c5d7ca..4a0a96ffd7 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 @@ -26,6 +26,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.DmfTargetProperties; import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; @@ -126,6 +127,10 @@ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate, @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue:dmf_receiver}", containerFactory = "listenerContainerFactory") public Message onMessage(final Message message, @Header(name = MessageHeaderKey.TYPE, required = false) final String type, + // TODO Ammar check whether i have to just add a new line but not + // @Header but @ RequestBody to get the whole payload and then check + // whether a name is specified to display it if specified = true, or + // is the RequestBody and so the payload in the "message" parameter? @Header(name = MessageHeaderKey.TENANT, required = false) final String tenant) { return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost()); } @@ -152,22 +157,43 @@ public Message onMessage(final Message message, final String type, final String try { final MessageType messageType = MessageType.valueOf(type); switch (messageType) { - case THING_CREATED: - setTenantSecurityContext(tenant); - registerTarget(message, virtualHost); - break; - case EVENT: - checkContentTypeJson(message); - setTenantSecurityContext(tenant); - handleIncomingEvent(message); - break; - case PING: - if (isCorrelationIdNotEmpty(message)) { - amqpMessageDispatcherService.sendPingReponseToDmfReceiver(message, tenant, virtualHost); - } - break; - default: - logAndThrowMessageError(message, "No handle method was found for the given message type."); + // TODO Ammar here the thing created message is received + case THING_CREATED : + // If never reassigned (so still null) then targetId will be + // the default targetName + String name = null; + // Check whether there is a message body, if so extract name + // TODO Ammar check what happens if there is a body BUT no + // name!? + // if (message.getBody() != null || message.getBody().length != 0) { + // if(message.getBody().toString().contains("name")){ + // if (message.toString().contains("name")){ + // if( message.getBodyContentAsString().contains("name")) + if (message.toString().contains("name")){ + checkContentTypeJson(message); + // Check whether name property set + final DmfTargetProperties targetProperties = convertMessage(message, DmfTargetProperties.class); + // if if-condition is false, then name will be null, and + // so later replaced with the targetId + if (targetProperties.getName() != null || targetProperties.getName().length() != 0) { + name = targetProperties.getName(); + } ; + } + setTenantSecurityContext(tenant); + registerTarget(message, virtualHost, name); + break; + case EVENT : + checkContentTypeJson(message); + setTenantSecurityContext(tenant); + handleIncomingEvent(message); + break; + case PING : + if (isCorrelationIdNotEmpty(message)) { + amqpMessageDispatcherService.sendPingReponseToDmfReceiver(message, tenant, virtualHost); + } + break; + default : + logAndThrowMessageError(message, "No handle method was found for the given message type."); } } catch (final IllegalArgumentException ex) { throw new AmqpRejectAndDontRequeueException("Invalid message!", ex); @@ -199,7 +225,9 @@ private static void setTenantSecurityContext(final String tenantId) { * @param ip * the ip of the target/thing */ - private void registerTarget(final Message message, final String virtualHost) { + // TODO Ammar write that param name can be null without problems to use per + // default the tgargetId as name + private void registerTarget(final Message message, final String virtualHost, final String name) { final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); final String replyTo = message.getMessageProperties().getReplyTo(); @@ -209,7 +237,11 @@ private void registerTarget(final Message message, final String virtualHost) { try { final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo); - final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); + // TODO Ammar here is where the target is created + // TODO Ammar overload the method + // "findOrRegisterTargetIfItDoesNotExist" by adding a additional one + // but with the name option + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, name); LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); } catch (EntityAlreadyExistsException e) { @@ -279,20 +311,36 @@ private Map> getSoftwareModulesWith */ private void handleIncomingEvent(final Message message) { switch (EventTopic.valueOf(getStringHeaderKey(message, MessageHeaderKey.TOPIC, "EventTopic is null"))) { - case UPDATE_ACTION_STATUS: - updateActionStatus(message); - break; - case UPDATE_ATTRIBUTES: - updateAttributes(message); - break; - default: - logAndThrowMessageError(message, "Got event without appropriate topic."); - break; + case UPDATE_ACTION_STATUS : + updateActionStatus(message); + break; + case UPDATE_ATTRIBUTES : + updateAttributes(message); + break; + default : + logAndThrowMessageError(message, "Got event without appropriate topic."); + break; } } + // TODO Ammar IN THIS METHOD "getUpdateMode()" IS CALLED AND THIS HANDELS + // THE OPTIONAL FIELD "mode" IN THE BODY, SO JUST USE THIS BEHAVIOR AND TRY + // WHETHER IT WORKS private void updateAttributes(final Message message) { + // TODO Ammar create class for "name" similar to this DmfAttributeUpdate + // and use similar logic + final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class); + final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); + + controllerManagement.updateControllerAttributes(thingId, attributeUpdate.getAttributes(), + getUpdateMode(attributeUpdate)); + } + + // TODO created by Ammar + private void updateAttributesWithName(final Message message) { + // TODO Ammar create class for "name" similar to this DmfAttributeUpdate + // and use similar logic final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class); final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); @@ -345,35 +393,35 @@ private static Status mapStatus(final Message message, final DmfActionUpdateStat final Action action) { Status status = null; switch (actionUpdateStatus.getActionStatus()) { - case DOWNLOAD: - status = Status.DOWNLOAD; - break; - case RETRIEVED: - status = Status.RETRIEVED; - break; - case RUNNING: - status = Status.RUNNING; - break; - case CANCELED: - status = Status.CANCELED; - break; - case FINISHED: - status = Status.FINISHED; - break; - case ERROR: - status = Status.ERROR; - break; - case WARNING: - status = Status.WARNING; - break; - case DOWNLOADED: - status = Status.DOWNLOADED; - break; - case CANCEL_REJECTED: - status = handleCancelRejectedState(message, action); - break; - default: - logAndThrowMessageError(message, "Status for action does not exisit."); + case DOWNLOAD : + status = Status.DOWNLOAD; + break; + case RETRIEVED : + status = Status.RETRIEVED; + break; + case RUNNING : + status = Status.RUNNING; + break; + case CANCELED : + status = Status.CANCELED; + break; + case FINISHED : + status = Status.FINISHED; + break; + case ERROR : + status = Status.ERROR; + break; + case WARNING : + status = Status.WARNING; + break; + case DOWNLOADED : + status = Status.DOWNLOADED; + break; + case CANCEL_REJECTED : + status = handleCancelRejectedState(message, action); + break; + default : + logAndThrowMessageError(message, "Status for action does not exisit."); } return status; 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..e4fdae1151 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 @@ -60,11 +60,20 @@ protected static void checkContentTypeJson(final Message message) { @SuppressWarnings("unchecked") public T convertMessage(@NotNull final Message message, final Class clazz) { checkMessageBody(message); + //TODO ??? how did they implement here, that "mode" is only optional?? message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME, clazz.getName()); return (T) rabbitTemplate.getMessageConverter().fromMessage(message); } + //TODO created by Ammar +/* public void isMessageBodyEmptyRename(@NotNull final Message message) { + checkMessageBody(message); + message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME, + clazz.getName()); + return (T) rabbitTemplate.getMessageConverter().fromMessage(message); + }*/ + protected MessageConverter getMessageConverter() { return rabbitTemplate.getMessageConverter(); } diff --git a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java new file mode 100644 index 0000000000..5f6a0630a9 --- /dev/null +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.dmf.json.model; + +import java.util.HashMap; +import java.util.Map; + +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 Update message. + */ +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class DmfTargetProperties { + + @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 712ce86378..5977d49118 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 @@ -207,6 +207,23 @@ Map> findTargetVisibleMetaDataBySoftwareModul @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address); + //TODO created by Ammar - adapt comment section + /** + * 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}. + * + * @param controllerId + * reference + * @param address + * the client IP address of the target, might be {@code null} + * @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. diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 83eea384f0..834bc0e352 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -386,6 +386,27 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi .orElseGet(() -> createTarget(controllerId, address)); } + @Override + @Transactional(isolation = Isolation.READ_COMMITTED) + @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + // TODO Ammar @Param name = name for the target to be created + public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address, String name) { + final Specification spec = (targetRoot, query, cb) -> cb + .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); + + return targetRepository.findOne(spec).map(target -> updateTargetStatus(target, address)) + .orElseGet(() -> createNewTarget(controllerId, address, name)); + } + + // TODO created by Ammar + private Target createNewTarget(final String controllerId, final URI address, final String name) { + // In case of a true expression, the targetId will be set as name + if (name == null || name.length() == 0) { + return createTarget(controllerId, address); + } + return createTarget(controllerId, address, name); + } + private Target createTarget(final String controllerId, final URI address) { final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(controllerId) @@ -398,6 +419,21 @@ private Target createTarget(final String controllerId, final URI address) { return result; } + // TODO created by Ammar to create Target in case optional name -> so we + // have an overloaded method "createTarget()" + private Target createTarget(final String controllerId, final URI address, final String name) { + + final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() + .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(name) + .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) + .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); + + afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher() + .publishEvent(new TargetPollEvent(result, eventPublisherHolder.getApplicationId()))); + + return result; + } + /** * Flush the update queue by means to persisting * {@link Target#getLastTargetQuery()}. @@ -519,7 +555,7 @@ private boolean isStoreEager(final JpaTarget toUpdate, final URI address) { @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action addCancelActionStatus(final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; @@ -532,20 +568,20 @@ public Action addCancelActionStatus(final ActionStatusCreate c) { final JpaActionStatus actionStatus = create.build(); switch (actionStatus.getStatus()) { - case CANCELED: - case FINISHED: - handleFinishedCancelation(actionStatus, action); - break; - case ERROR: - case CANCEL_REJECTED: - // Cancellation rejected. Back to running. - action.setStatus(Status.RUNNING); - break; - default: - // information status entry - check for a potential DOS attack - assertActionStatusQuota(action); - assertActionStatusMessageQuota(actionStatus); - break; + case CANCELED : + case FINISHED : + handleFinishedCancelation(actionStatus, action); + break; + case ERROR : + case CANCEL_REJECTED : + // Cancellation rejected. Back to running. + action.setStatus(Status.RUNNING); + break; + default : + // information status entry - check for a potential DOS attack + assertActionStatusQuota(action); + assertActionStatusMessageQuota(actionStatus); + break; } actionStatus.setAction(actionRepository.save(action)); @@ -570,7 +606,7 @@ private void handleFinishedCancelation(final JpaActionStatus actionStatus, final @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action addUpdateActionStatus(final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); @@ -622,19 +658,19 @@ private Action handleAddUpdateActionStatus(final JpaActionStatus actionStatus, f assertActionStatusMessageQuota(actionStatus); switch (actionStatus.getStatus()) { - case ERROR: - final JpaTarget target = (JpaTarget) action.getTarget(); - target.setUpdateStatus(TargetUpdateStatus.ERROR); - handleErrorOnAction(action, target); - break; - case FINISHED: - controllerId = handleFinishedAndStoreInTargetStatus(action); - break; - case DOWNLOADED: - controllerId = handleDownloadedActionStatus(action); - break; - default: - break; + case ERROR : + final JpaTarget target = (JpaTarget) action.getTarget(); + target.setUpdateStatus(TargetUpdateStatus.ERROR); + handleErrorOnAction(action, target); + break; + case FINISHED : + controllerId = handleFinishedAndStoreInTargetStatus(action); + break; + case DOWNLOADED : + controllerId = handleDownloadedActionStatus(action); + break; + default : + break; } actionStatus.setAction(action); @@ -720,7 +756,7 @@ private String handleFinishedAndStoreInTargetStatus(final JpaAction action) { @Override @Transactional @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target updateControllerAttributes(final String controllerId, final Map data, final UpdateMode mode) { @@ -737,27 +773,29 @@ public Target updateControllerAttributes(final String controllerId, final Map controllerAttributes = target.getControllerAttributes(); - + // TODO Ammar so here it REALLY check and handles the "mode" from body, + // but what happens if no mode in Body? Looking in the next line, if no + // mode found the default "UpdateMode.MERGE" will be assigned final UpdateMode updateMode = mode != null ? mode : UpdateMode.MERGE; switch (updateMode) { - case REMOVE: - // remove the addressed attributes - data.keySet().forEach(controllerAttributes::remove); - break; - case REPLACE: - // clear the attributes before adding the new attributes - controllerAttributes.clear(); - copy(data, controllerAttributes); - target.setRequestControllerAttributes(false); - break; - case MERGE: - // just merge the attributes in - copy(data, controllerAttributes); - target.setRequestControllerAttributes(false); - break; - default: - // unknown update mode - throw new IllegalStateException("The update mode " + updateMode + " is not supported."); + case REMOVE : + // remove the addressed attributes + data.keySet().forEach(controllerAttributes::remove); + break; + case REPLACE : + // clear the attributes before adding the new attributes + controllerAttributes.clear(); + copy(data, controllerAttributes); + target.setRequestControllerAttributes(false); + break; + case MERGE : + // just merge the attributes in + copy(data, controllerAttributes); + target.setRequestControllerAttributes(false); + break; + default : + // unknown update mode + throw new IllegalStateException("The update mode " + updateMode + " is not supported."); } assertTargetAttributesQuota(target); @@ -798,7 +836,7 @@ private void assertTargetAttributesQuota(final JpaTarget target) { @Override @Transactional @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action registerRetrieved(final long actionId, final String message) { return handleRegisterRetrieved(actionId, message); } @@ -859,7 +897,7 @@ private Action handleRegisterRetrieved(final Long actionId, final String message @Override @Transactional @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public ActionStatus addInformationalActionStatus(final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); From 7bda7cca721dc5a165f4cf6fd3c834c308ac5b91 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Wed, 11 Sep 2019 18:28:47 +0200 Subject: [PATCH 02/22] Add name field and tests regarding name field functionality in THING_CREATED Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 98 +++++++++---------- .../eclipse/hawkbit/amqp/BaseAmqpService.java | 9 -- .../amqp/AmqpMessageHandlerServiceTest.java | 62 +++++++++++- .../dmf/json/model/DmfTargetProperties.java | 2 +- .../repository/ControllerManagement.java | 3 +- .../jpa/JpaControllerManagement.java | 7 -- 6 files changed, 113 insertions(+), 68 deletions(-) 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 4a0a96ffd7..a975757916 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 @@ -127,10 +127,6 @@ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate, @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue:dmf_receiver}", containerFactory = "listenerContainerFactory") public Message onMessage(final Message message, @Header(name = MessageHeaderKey.TYPE, required = false) final String type, - // TODO Ammar check whether i have to just add a new line but not - // @Header but @ RequestBody to get the whole payload and then check - // whether a name is specified to display it if specified = true, or - // is the RequestBody and so the payload in the "message" parameter? @Header(name = MessageHeaderKey.TENANT, required = false) final String tenant) { return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost()); } @@ -156,31 +152,29 @@ public Message onMessage(final Message message, final String type, final String final SecurityContext oldContext = SecurityContextHolder.getContext(); try { final MessageType messageType = MessageType.valueOf(type); + // If name never reassigned, so still null, then per default: + // targetName = targetId + String name = null; switch (messageType) { - // TODO Ammar here the thing created message is received case THING_CREATED : - // If never reassigned (so still null) then targetId will be - // the default targetName - String name = null; - // Check whether there is a message body, if so extract name - // TODO Ammar check what happens if there is a body BUT no - // name!? - // if (message.getBody() != null || message.getBody().length != 0) { - // if(message.getBody().toString().contains("name")){ - // if (message.toString().contains("name")){ - // if( message.getBodyContentAsString().contains("name")) - if (message.toString().contains("name")){ + if (message.toString().contains("name")) { checkContentTypeJson(message); // Check whether name property set final DmfTargetProperties targetProperties = convertMessage(message, DmfTargetProperties.class); - // if if-condition is false, then name will be null, and - // so later replaced with the targetId - if (targetProperties.getName() != null || targetProperties.getName().length() != 0) { + // Will be true if "name" properly in body and not just + // contained in some attributes + if (targetProperties.getName() != null && targetProperties.getName().length() != 0) { name = targetProperties.getName(); - } ; + setTenantSecurityContext(tenant); + registerTarget(message, virtualHost, name); + } else { + setTenantSecurityContext(tenant); + registerTarget(message, virtualHost); + } + } else { + setTenantSecurityContext(tenant); + registerTarget(message, virtualHost); } - setTenantSecurityContext(tenant); - registerTarget(message, virtualHost, name); break; case EVENT : checkContentTypeJson(message); @@ -218,15 +212,41 @@ private static void setTenantSecurityContext(final String tenantId) { } /** - * Method to create a new target or to find the target if it already exists. + * Method to register a new target. * - * @param targetID - * the ID of the target/thing - * @param ip - * the ip of the target/thing + * @param message + * the message that contains the target/thing + * @param virtualHost + */ + private void registerTarget(final Message message, final String virtualHost) { + final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); + final String replyTo = message.getMessageProperties().getReplyTo(); + + if (StringUtils.isEmpty(replyTo)) { + logAndThrowMessageError(message, "No ReplyTo was set for the createThing message."); + } + + try { + final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo); + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); + LOG.debug("Target {} reported online state.", thingId); + sendUpdateCommandToTarget(target); + } catch (EntityAlreadyExistsException e) { + throw new AmqpRejectAndDontRequeueException("Target already registered, message will be ignored!", e); + } + } + + /** + * Method to register a new target. + * + * @param message + * the message that contains the target/thing + * @param virtualHost + * the virtualHost of the target/thing + * @param name + * the name of the target/thing, can be null and would then be + * replaced by targetId */ - // TODO Ammar write that param name can be null without problems to use per - // default the tgargetId as name private void registerTarget(final Message message, final String virtualHost, final String name) { final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); final String replyTo = message.getMessageProperties().getReplyTo(); @@ -237,10 +257,6 @@ private void registerTarget(final Message message, final String virtualHost, fin try { final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo); - // TODO Ammar here is where the target is created - // TODO Ammar overload the method - // "findOrRegisterTargetIfItDoesNotExist" by adding a additional one - // but with the name option final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, name); LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); @@ -324,23 +340,7 @@ private void handleIncomingEvent(final Message message) { } - // TODO Ammar IN THIS METHOD "getUpdateMode()" IS CALLED AND THIS HANDELS - // THE OPTIONAL FIELD "mode" IN THE BODY, SO JUST USE THIS BEHAVIOR AND TRY - // WHETHER IT WORKS private void updateAttributes(final Message message) { - // TODO Ammar create class for "name" similar to this DmfAttributeUpdate - // and use similar logic - final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class); - final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); - - controllerManagement.updateControllerAttributes(thingId, attributeUpdate.getAttributes(), - getUpdateMode(attributeUpdate)); - } - - // TODO created by Ammar - private void updateAttributesWithName(final Message message) { - // TODO Ammar create class for "name" similar to this DmfAttributeUpdate - // and use similar logic final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class); final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); 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 e4fdae1151..84f9cfb273 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 @@ -60,20 +60,11 @@ protected static void checkContentTypeJson(final Message message) { @SuppressWarnings("unchecked") public T convertMessage(@NotNull final Message message, final Class clazz) { checkMessageBody(message); - //TODO ??? how did they implement here, that "mode" is only optional?? message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME, clazz.getName()); return (T) rabbitTemplate.getMessageConverter().fromMessage(message); } - //TODO created by Ammar -/* public void isMessageBodyEmptyRename(@NotNull final Message message) { - checkMessageBody(message); - message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME, - clazz.getName()); - return (T) rabbitTemplate.getMessageConverter().fromMessage(message); - }*/ - protected MessageConverter getMessageConverter() { return rabbitTemplate.getMessageConverter(); } 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 8fe0132cea..29f4184bb6 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 @@ -36,6 +36,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfActionUpdateStatus; import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate; import org.eclipse.hawkbit.dmf.json.model.DmfDownloadResponse; +import org.eclipse.hawkbit.dmf.json.model.DmfTargetProperties; import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ControllerManagement; @@ -135,8 +136,11 @@ public class AmqpMessageHandlerServiceTest { @Captor private ArgumentCaptor modeCaptor; + @Captor + private ArgumentCaptor targetNameCaptor; + @Before - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({"rawtypes", "unchecked"}) public void before() throws Exception { messageConverter = new Jackson2JsonMessageConverter(); when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter); @@ -193,6 +197,62 @@ public void createThing() { } + @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 MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); + messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); + final DmfTargetProperties targetProperties = new DmfTargetProperties(); + targetProperties.setName("NonDefaultTargetName"); + + final Message message = messageConverter.toMessage(targetProperties, messageProperties); + + final Target targetMock = mock(Target.class); + + final ArgumentCaptor targetIdCaptor = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor 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(message, 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("Attributes is not right").isEqualTo(targetProperties.getName()); + } + + @Test + @Description("Tests the creation of a target/thing without name but with body by calling the same method that incoming RabbitMQ messages would access.") + public void createThingWithBodyWithoutName() { + final String knownThingId = "3"; + final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); + messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); + final DmfAttributeUpdate attributeUpdate = new DmfAttributeUpdate(); + // put "fake" name in the attributes to also test this behaviour, name + // should still be default (=targetId) + attributeUpdate.getAttributes().put("name", "testValue1"); + + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, + messageProperties); + + final Target targetMock = mock(Target.class); + + final ArgumentCaptor targetIdCaptor = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor 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, "vHost"); + + assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); + assertThat(uriCaptor.getValue().toString()).as("Uri is not right").isEqualTo("amqp://vHost/MyTest"); + } + @Test @Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.") public void updateAttributes() { diff --git a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java index 5f6a0630a9..4cffa726b5 100644 --- a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** - * JSON representation of the Attribute Update message. + * JSON representation of the Attribute THING_CREATED message. */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) 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 5977d49118..16e521d31f 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 @@ -207,7 +207,6 @@ Map> findTargetVisibleMetaDataBySoftwareModul @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address); - //TODO created by Ammar - adapt comment section /** * Register new target in the repository (plug-and-play) and in case it * already exists updates {@link Target#getAddress()} and @@ -219,6 +218,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul * 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) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 834bc0e352..55b1d3f904 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -389,7 +389,6 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - // TODO Ammar @Param name = name for the target to be created public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address, String name) { final Specification spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); @@ -398,7 +397,6 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi .orElseGet(() -> createNewTarget(controllerId, address, name)); } - // TODO created by Ammar private Target createNewTarget(final String controllerId, final URI address, final String name) { // In case of a true expression, the targetId will be set as name if (name == null || name.length() == 0) { @@ -419,8 +417,6 @@ private Target createTarget(final String controllerId, final URI address) { return result; } - // TODO created by Ammar to create Target in case optional name -> so we - // have an overloaded method "createTarget()" private Target createTarget(final String controllerId, final URI address, final String name) { final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() @@ -773,9 +769,6 @@ public Target updateControllerAttributes(final String controllerId, final Map controllerAttributes = target.getControllerAttributes(); - // TODO Ammar so here it REALLY check and handles the "mode" from body, - // but what happens if no mode in Body? Looking in the next line, if no - // mode found the default "UpdateMode.MERGE" will be assigned final UpdateMode updateMode = mode != null ? mode : UpdateMode.MERGE; switch (updateMode) { case REMOVE : From 7c783088b9e44cb569515f87942fbb6bf3a8a1c5 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Thu, 12 Sep 2019 14:15:37 +0200 Subject: [PATCH 03/22] SonarQube realted changes in name field functionality in THING_CREATED Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 55 ++++++++++++------- 1 file changed, 34 insertions(+), 21 deletions(-) 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 a975757916..aabfa71f9a 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 @@ -152,29 +152,9 @@ public Message onMessage(final Message message, final String type, final String final SecurityContext oldContext = SecurityContextHolder.getContext(); try { final MessageType messageType = MessageType.valueOf(type); - // If name never reassigned, so still null, then per default: - // targetName = targetId - String name = null; switch (messageType) { case THING_CREATED : - if (message.toString().contains("name")) { - checkContentTypeJson(message); - // Check whether name property set - final DmfTargetProperties targetProperties = convertMessage(message, DmfTargetProperties.class); - // Will be true if "name" properly in body and not just - // contained in some attributes - if (targetProperties.getName() != null && targetProperties.getName().length() != 0) { - name = targetProperties.getName(); - setTenantSecurityContext(tenant); - registerTarget(message, virtualHost, name); - } else { - setTenantSecurityContext(tenant); - registerTarget(message, virtualHost); - } - } else { - setTenantSecurityContext(tenant); - registerTarget(message, virtualHost); - } + handleThingCreatedRequest(message, tenant, virtualHost); break; case EVENT : checkContentTypeJson(message); @@ -474,6 +454,39 @@ private T getConfigValue(final String key, final Class< .runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue()); } + private void handleThingCreatedRequest(Message message, String tenant, String virtualHost) { + if (message.toString().contains("name")) { + handleNameContainedRequest(message, tenant, virtualHost); + } else { + handleNoNameContainedRequest(message, tenant, virtualHost); + } + } + + private void handleNameContainedRequest(Message message, String tenant, String virtualHost) { + // If name never reassigned, so still null, then per default: + // targetName = targetId + String name = null; + + checkContentTypeJson(message); + // Check whether name property set + final DmfTargetProperties targetProperties = convertMessage(message, DmfTargetProperties.class); + // Will be true if "name" properly in body and not just + // contained in some attributes + if (targetProperties.getName() != null && targetProperties.getName().length() != 0) { + name = targetProperties.getName(); + setTenantSecurityContext(tenant); + registerTarget(message, virtualHost, name); + } else { + setTenantSecurityContext(tenant); + registerTarget(message, virtualHost); + } + } + + private void handleNoNameContainedRequest(Message message, String tenant, String virtualHost) { + setTenantSecurityContext(tenant); + registerTarget(message, virtualHost); + } + // for testing public void setControllerManagement(final ControllerManagement controllerManagement) { this.controllerManagement = controllerManagement; From 66d52fba4f13664c2012ec820478ed67cd044030 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Thu, 12 Sep 2019 20:10:17 +0200 Subject: [PATCH 04/22] Add name field and tests regarding name field functionality in UPDATE_ATTRIBUTES Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 5 +++ .../amqp/AmqpMessageHandlerServiceTest.java | 34 ++++++++++++++++++- .../dmf/json/model/DmfAttributeUpdate.java | 11 ++++++ .../repository/ControllerManagement.java | 18 ++++++++++ .../jpa/JpaControllerManagement.java | 16 +++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) 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 aabfa71f9a..2c2c730f8d 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 @@ -324,6 +324,11 @@ private void updateAttributes(final Message message) { final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class); final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); + //If new name provided in body, then change the name + if (attributeUpdate.getName() != null && attributeUpdate.getName().length() != 0) { + controllerManagement.updateControllerName(thingId, attributeUpdate.getName()); + } + controllerManagement.updateControllerAttributes(thingId, attributeUpdate.getAttributes(), getUpdateMode(attributeUpdate)); } 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 29f4184bb6..c6d41b16ee 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 @@ -222,7 +222,7 @@ public void createThingWithName() { 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("Attributes is not right").isEqualTo(targetProperties.getName()); + assertThat(targetNameCaptor.getValue()).as("Thing name is not right").isEqualTo(targetProperties.getName()); } @Test @@ -279,6 +279,38 @@ public void updateAttributes() { } + @Test + @Description("Tests the target attribute update with name update by calling the same method that incoming RabbitMQ messages would access.") + public void updateAttributesWithName() { + final String knownThingId = "1"; + final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); + messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); + messageProperties.setHeader(MessageHeaderKey.TOPIC, "UPDATE_ATTRIBUTES"); + final DmfAttributeUpdate attributeUpdate = new DmfAttributeUpdate(); + attributeUpdate.getAttributes().put("testKey1", "testValue1"); + attributeUpdate.getAttributes().put("testKey2", "testValue2"); + attributeUpdate.setName("UpdatedTargetName"); + + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, + messageProperties); + + final ArgumentCaptor targetNameCaptor = ArgumentCaptor.forClass(String.class); + + when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), + modeCaptor.capture())).thenReturn(null); + when(controllerManagementMock.updateControllerName(targetIdCaptor.capture(), targetNameCaptor.capture())) + .thenReturn(null); + + amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); + + // verify + assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); + assertThat(attributesCaptor.getValue()).as("Attributes is not right") + .isEqualTo(attributeUpdate.getAttributes()); + assertThat(targetNameCaptor.getValue()).as("Thing name is wrong").isEqualTo(attributeUpdate.getName()); + + } + @Test @Description("Verifies that the update mode is retrieved from the UPDATE_ATTRIBUTES message and passed to the controller management.") public void attributeUpdateModes() { 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..5b057069cd 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 @@ -29,6 +29,9 @@ public class DmfAttributeUpdate { @JsonProperty private DmfUpdateMode mode; + @JsonProperty + private String name; + public DmfUpdateMode getMode() { return mode; } @@ -41,4 +44,12 @@ public Map getAttributes() { return attributes; } + 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 16e521d31f..61e6e9ea1a 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 @@ -374,6 +374,24 @@ Map> findTargetVisibleMetaDataBySoftwareModul Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map attributes, UpdateMode mode); + /** + * Updates name of the controller according to the given name + * + * @param controllerId + * to update + * @param controllerName + * the update mode or null + * + * @return updated {@link Target} + * + * @throws EntityNotFoundException + * if target that has to be updated could not be found + * @throws QuotaExceededException + * if maximum number of attributes per target is exceeded + */ + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Target updateControllerName(final String controllerId, final String controllerName); + /** * Finds {@link Target} based on given controller ID returns found Target * without details, i.e. NO {@link Target#getTags()} and diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 55b1d3f904..e115cad26d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -795,6 +795,22 @@ public Target updateControllerAttributes(final String controllerId, final Map new EntityNotFoundException(Target.class, controllerId)); + + target.setName(controllerName); + + assertTargetAttributesQuota(target); + + return targetRepository.save(target); + } + private static boolean isAttributeEntryValid(final Map.Entry e) { return isAttributeKeyValid(e.getKey()) && isAttributeValueValid(e.getValue()); } From 22cf51c502f777cbbfa72f9311b1f493635f727e Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Mon, 16 Sep 2019 13:38:38 +0200 Subject: [PATCH 05/22] Adapt documentation due to name field in THING_CREATED and UPDATE_ATTRIBUTES Signed-off-by: Ammar Bikic --- docs/content/apis/dmf_api.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/content/apis/dmf_api.md b/docs/content/apis/dmf_api.md index 1c024fe3f2..4d86cc2310 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 per default is the thing ID. This property is optional. + ### UPDATE_ATTRIBUTES Message to update target attributes. This message can be send in response to a _REQUEST_ATTRIBUTES_UPDATE_ event, sent by hawkBit. @@ -88,10 +98,12 @@ Payload Template: "exampleKey1" : "exampleValue1", "exampleKey2" : "exampleValue2" }, + "name": "String", "mode": "String" } ``` +The "name" property specifies the name of the thing. This property is optional.
The "mode" property specifies the update mode that should be applied. This property is optional. Possible [mode](https://github.com/eclipse/hawkbit/tree/master/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfUpdateMode.java) values: Value | Description From 158f442cb503c594a8acfacd16694474860445ee Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Wed, 18 Sep 2019 21:57:47 +0200 Subject: [PATCH 06/22] Add integration tests regarding name field functionality in THING_CREATED Signed-off-by: Ammar Bikic --- .../jpa/ControllerManagementTest.java | 135 ++++++++++++++++++ .../repository/test/util/TestdataFactory.java | 16 +++ 2 files changed, 151 insertions(+) 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 5ff3f924a3..ea61619eae 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 @@ -515,6 +515,20 @@ public void findOrRegisterTargetIfItDoesNotExist() { assertThat(targetRepository.count()).as("Only 1 target should be registred").isEqualTo(1L); } + @Test + @Description("Register a controller with name which does not exist") + @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 2)}) + public void findOrRegisterTargetIfItDoesNotExistWithName() { + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); + assertThat(target).as("target should not be null").isNotNull(); + + final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); + assertThat(target.getId()).as("Target should be the equals").isEqualTo(sameTarget.getId()); + assertThat(target.getName()).as("Taget names should be equal").isEqualTo(sameTarget.getName()); + 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() { @@ -536,6 +550,27 @@ public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionForInvalidControl .as("register target with too long controllerId should fail"); } + @Test + @Description("Tries to register a target with an invalid controller id") + public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionForInvalidControllerIdParam() { + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST, "TestName")) + .as("register target with null as controllerId should fail"); + + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("", LOCALHOST, "TestName")) + .as("register target with empty controllerId should fail"); + + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST, "TestName")) + .as("register target with empty controllerId should fail"); + + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist( + RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST, "TestName")) + .as("register target with too long controllerId should fail"); + } + @Test @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " + "exception is rethrown after max retries") @@ -555,6 +590,25 @@ public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionAfterMaxRetries() } } + @Test + @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " + + "exception is rethrown after max retries") + public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionAfterMaxRetries() { + final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); + when(mockTargetRepository.findOne(any())).thenThrow(ConcurrencyFailureException.class); + ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); + + try { + controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); + fail("Expected an ConcurrencyFailureException to be thrown!"); + } catch (final ConcurrencyFailureException e) { + verify(mockTargetRepository, times(TX_RT_MAX)).findOne(any()); + } finally { + // revert + ((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository); + } + } + @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") @@ -582,6 +636,33 @@ public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRe } } + @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)}) + public void findOrRegisterTargetIfItDoesNotExistWithNameDoesNotThrowExceptionBeforeMaxRetries() { + + final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); + ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); + final Target target = testdataFactory.createTargetWithName("TestName"); + + when(mockTargetRepository.findOne(any())).thenThrow(ConcurrencyFailureException.class) + .thenThrow(ConcurrencyFailureException.class).thenReturn(Optional.of((JpaTarget) target)); + when(mockTargetRepository.save(any())).thenReturn(target); + + try { + final Target targetFromControllerManagement = controllerManagement + .findOrRegisterTargetIfItDoesNotExist(target.getControllerId(), LOCALHOST, "TestName"); + verify(mockTargetRepository, times(3)).findOne(any()); + verify(mockTargetRepository, times(1)).save(any()); + assertThat(target).isEqualTo(targetFromControllerManagement); + } finally { + // revert + ((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository); + } + } + @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") @@ -605,6 +686,29 @@ public void findOrRegisterTargetIfItDoesNotExistDoesntRetryWhenEntityAlreadyExis } } + @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") + public void findOrRegisterTargetIfItDoesNotExistWithNameDoesntRetryWhenEntityAlreadyExistsException() { + + final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); + ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); + + when(mockTargetRepository.findOne(any())).thenReturn(Optional.empty()); + when(mockTargetRepository.save(any())).thenThrow(EntityAlreadyExistsException.class); + + try { + controllerManagement.findOrRegisterTargetIfItDoesNotExist("1234", LOCALHOST, "TestName"); + fail("Expected an EntityAlreadyExistsException to be thrown!"); + } catch (final EntityAlreadyExistsException e) { + verify(mockTargetRepository, times(1)).findOne(any()); + verify(mockTargetRepository, times(1)).save(any()); + } finally { + // revert + ((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository); + } + } + @Test @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " + "rethrown") @@ -626,6 +730,27 @@ public void recoverFindOrRegisterTargetIfItDoesNotExistIsNotInvokedForOtherExcep } } + @Test + @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " + + "rethrown") + public void recoverFindOrRegisterTargetIfItDoesNotExistWithNameIsNotInvokedForOtherExceptions() { + + final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); + ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); + + when(mockTargetRepository.findOne(any())).thenThrow(RuntimeException.class); + + try { + controllerManagement.findOrRegisterTargetIfItDoesNotExist("aControllerId", LOCALHOST, "TestName"); + fail("Expected a RuntimeException to be thrown!"); + } catch (final RuntimeException e) { + verify(mockTargetRepository, times(1)).findOne(any()); + } finally { + // revert + ((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository); + } + } + @Test @Description("Verify that targetVisible metadata is returned from repository") @ExpectEvents({@Expect(type = DistributionSetCreatedEvent.class, count = 1), @@ -653,6 +778,16 @@ public void targetPollEventNotSendIfDisabled() { repositoryProperties.setPublishTargetPollEvent(true); } + @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)}) + public void targetPollEventNotSendIfDisabledWithName() { + repositoryProperties.setPublishTargetPollEvent(false); + controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); + repositoryProperties.setPublishTargetPollEvent(true); + } + @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), 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..32a2b233c2 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 @@ -629,6 +629,22 @@ public Target createTarget(final String controllerId) { return target; } + /** + * @param targetName + * name of the target + * @return persisted {@link Target} + */ + public Target createTargetWithName(final String targetName) { + final Target target = targetManagement.create(entityFactory.target().create().controllerId(DEFAULT_CONTROLLER_ID).name(targetName)); + 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} From 2d13ca8e04048fe4223e5b261e858f0be0ec601a Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Thu, 19 Sep 2019 13:45:45 +0200 Subject: [PATCH 07/22] Reformat after finding format bug regarding THING_CREATED Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 212 +++--- .../amqp/AmqpMessageHandlerServiceTest.java | 195 +++--- .../dmf/json/model/DmfAttributeUpdate.java | 15 +- .../dmf/json/model/DmfTargetProperties.java | 9 +- .../repository/ControllerManagement.java | 142 ++--- .../jpa/JpaControllerManagement.java | 324 ++++------ .../jpa/ControllerManagementTest.java | 542 +++++++--------- .../repository/test/util/TestdataFactory.java | 603 +++++++----------- 8 files changed, 822 insertions(+), 1220 deletions(-) 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 2c2c730f8d..209c55e8a1 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 @@ -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 @@ -63,11 +63,9 @@ import org.springframework.util.StringUtils; /** - * * {@link AmqpMessageHandlerService} handles all incoming target interaction * AMQP messages (e.g. create target, check for updates etc.) for the queue * which is configured for the property hawkbit.dmf.rabbitmq.receiverQueue. - * */ public class AmqpMessageHandlerService extends BaseAmqpService { @@ -85,19 +83,13 @@ public class AmqpMessageHandlerService extends BaseAmqpService { /** * Constructor. - * - * @param rabbitTemplate - * for converting messages - * @param amqpMessageDispatcherService - * to sending events to DMF client - * @param controllerManagement - * for target repo access - * @param entityFactory - * to create entities - * @param systemSecurityContext - * the system Security Context - * @param tenantConfigurationManagement - * the tenant configuration Management + * + * @param rabbitTemplate for converting messages + * @param amqpMessageDispatcherService to sending events to DMF client + * @param controllerManagement for target repo access + * @param entityFactory to create entities + * @param systemSecurityContext the system Security Context + * @param tenantConfigurationManagement the tenant configuration Management */ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate, final AmqpMessageDispatcherService amqpMessageDispatcherService, @@ -115,33 +107,24 @@ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate, /** * Method to handle all incoming DMF amqp messages. * - * @param message - * incoming message - * @param type - * the message type - * @param tenant - * the contentType of the message - * + * @param message incoming message + * @param type 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") - public Message onMessage(final Message message, - @Header(name = MessageHeaderKey.TYPE, required = false) final String type, + @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue:dmf_receiver}", containerFactory = "listenerContainerFactory") public Message onMessage( + final Message message, @Header(name = MessageHeaderKey.TYPE, required = false) final String type, @Header(name = MessageHeaderKey.TENANT, required = false) final String tenant) { return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost()); } /** * * Executed if a amqp message arrives. - * - * @param message - * the message - * @param type - * the type - * @param tenant - * the tenant - * @param virtualHost - * the virtual host + * + * @param message the message + * @param type the type + * @param tenant the tenant + * @param virtualHost the virtual host * @return the rpc message back to supplier. */ public Message onMessage(final Message message, final String type, final String tenant, final String virtualHost) { @@ -153,21 +136,21 @@ public Message onMessage(final Message message, final String type, final String try { final MessageType messageType = MessageType.valueOf(type); switch (messageType) { - case THING_CREATED : - handleThingCreatedRequest(message, tenant, virtualHost); - break; - case EVENT : - checkContentTypeJson(message); - setTenantSecurityContext(tenant); - handleIncomingEvent(message); - break; - case PING : - if (isCorrelationIdNotEmpty(message)) { - amqpMessageDispatcherService.sendPingReponseToDmfReceiver(message, tenant, virtualHost); - } - break; - default : - logAndThrowMessageError(message, "No handle method was found for the given message type."); + case THING_CREATED: + handleThingCreatedRequest(message, tenant, virtualHost); + break; + case EVENT: + checkContentTypeJson(message); + setTenantSecurityContext(tenant); + handleIncomingEvent(message); + break; + case PING: + if (isCorrelationIdNotEmpty(message)) { + amqpMessageDispatcherService.sendPingReponseToDmfReceiver(message, tenant, virtualHost); + } + break; + default: + logAndThrowMessageError(message, "No handle method was found for the given message type."); } } catch (final IllegalArgumentException ex) { throw new AmqpRejectAndDontRequeueException("Invalid message!", ex); @@ -194,8 +177,7 @@ private static void setTenantSecurityContext(final String tenantId) { /** * Method to register a new target. * - * @param message - * the message that contains the target/thing + * @param message the message that contains the target/thing * @param virtualHost */ private void registerTarget(final Message message, final String virtualHost) { @@ -219,13 +201,10 @@ private void registerTarget(final Message message, final String virtualHost) { /** * Method to register a new target. * - * @param message - * the message that contains the target/thing - * @param virtualHost - * the virtualHost of the target/thing - * @param name - * the name of the target/thing, can be null and would then be - * replaced by targetId + * @param message the message that contains the target/thing + * @param virtualHost the virtualHost of the target/thing + * @param name the name of the target/thing, can be null and would then be + * replaced by targetId */ private void registerTarget(final Message message, final String virtualHost, final String name) { final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); @@ -276,8 +255,9 @@ private void sendOldestActionToTarget(final Target target) { final Action action = actionOptional.get(); if (action.isCancelingOrCanceled()) { - amqpMessageDispatcherService.sendCancelMessageToTarget(target.getTenant(), target.getControllerId(), - action.getId(), target.getAddress()); + amqpMessageDispatcherService + .sendCancelMessageToTarget(target.getTenant(), target.getControllerId(), action.getId(), + target.getAddress()); } else { amqpMessageDispatcherService.sendUpdateMessageToTarget(new ActionProperties(action), action.getTarget(), getSoftwareModulesWithMetadata(action.getDistributionSet())); @@ -300,22 +280,20 @@ private Map> getSoftwareModulesWith /** * Method to handle the different topics to an event. * - * @param message - * the incoming event message. - * @param topic - * the topic of the event. + * @param message the incoming event message. + * @param topic the topic of the event. */ private void handleIncomingEvent(final Message message) { switch (EventTopic.valueOf(getStringHeaderKey(message, MessageHeaderKey.TOPIC, "EventTopic is null"))) { - case UPDATE_ACTION_STATUS : - updateActionStatus(message); - break; - case UPDATE_ATTRIBUTES : - updateAttributes(message); - break; - default : - logAndThrowMessageError(message, "Got event without appropriate topic."); - break; + case UPDATE_ACTION_STATUS: + updateActionStatus(message); + break; + case UPDATE_ATTRIBUTES: + updateAttributes(message); + break; + default: + logAndThrowMessageError(message, "Got event without appropriate topic."); + break; } } @@ -324,20 +302,19 @@ private void updateAttributes(final Message message) { final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class); final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); - //If new name provided in body, then change the name + // If new name provided in body, then change the name if (attributeUpdate.getName() != null && attributeUpdate.getName().length() != 0) { controllerManagement.updateControllerName(thingId, attributeUpdate.getName()); } - controllerManagement.updateControllerAttributes(thingId, attributeUpdate.getAttributes(), - getUpdateMode(attributeUpdate)); + controllerManagement + .updateControllerAttributes(thingId, attributeUpdate.getAttributes(), getUpdateMode(attributeUpdate)); } /** * Method to update the action status of an action through the event. * - * @param actionUpdateStatus - * the object form the ampq message + * @param actionUpdateStatus the object form the ampq message */ private void updateActionStatus(final Message message) { final DmfActionUpdateStatus actionUpdateStatus = convertMessage(message, DmfActionUpdateStatus.class); @@ -346,17 +323,17 @@ private void updateActionStatus(final Message message) { final List messages = actionUpdateStatus.getMessage(); if (isCorrelationIdNotEmpty(message)) { - messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "DMF message correlation-id " - + message.getMessageProperties().getCorrelationId()); + messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "DMF message correlation-id " + message + .getMessageProperties().getCorrelationId()); } final Status status = mapStatus(message, actionUpdateStatus, action); final ActionStatusCreate actionStatus = entityFactory.actionStatus().create(action.getId()).status(status) .messages(messages); - final Action updatedAction = (Status.CANCELED == status) - ? controllerManagement.addCancelActionStatus(actionStatus) - : controllerManagement.addUpdateActionStatus(actionStatus); + final Action updatedAction = (Status.CANCELED == status) ? + controllerManagement.addCancelActionStatus(actionStatus) : + controllerManagement.addUpdateActionStatus(actionStatus); if (shouldTargetProceed(updatedAction)) { sendUpdateCommandToTarget(action.getTarget()); @@ -373,40 +350,39 @@ private static boolean isCorrelationIdNotEmpty(final Message message) { // Exception squid:MethodCyclomaticComplexity - false positive, is a simple // mapping - @SuppressWarnings("squid:MethodCyclomaticComplexity") - private static Status mapStatus(final Message message, final DmfActionUpdateStatus actionUpdateStatus, - final Action action) { + @SuppressWarnings("squid:MethodCyclomaticComplexity") private static Status mapStatus(final Message message, + final DmfActionUpdateStatus actionUpdateStatus, final Action action) { Status status = null; switch (actionUpdateStatus.getActionStatus()) { - case DOWNLOAD : - status = Status.DOWNLOAD; - break; - case RETRIEVED : - status = Status.RETRIEVED; - break; - case RUNNING : - status = Status.RUNNING; - break; - case CANCELED : - status = Status.CANCELED; - break; - case FINISHED : - status = Status.FINISHED; - break; - case ERROR : - status = Status.ERROR; - break; - case WARNING : - status = Status.WARNING; - break; - case DOWNLOADED : - status = Status.DOWNLOADED; - break; - case CANCEL_REJECTED : - status = handleCancelRejectedState(message, action); - break; - default : - logAndThrowMessageError(message, "Status for action does not exisit."); + case DOWNLOAD: + status = Status.DOWNLOAD; + break; + case RETRIEVED: + status = Status.RETRIEVED; + break; + case RUNNING: + status = Status.RUNNING; + break; + case CANCELED: + status = Status.CANCELED; + break; + case FINISHED: + status = Status.FINISHED; + break; + case ERROR: + status = Status.ERROR; + break; + case WARNING: + status = Status.WARNING; + break; + case DOWNLOADED: + status = Status.DOWNLOADED; + break; + case CANCEL_REJECTED: + status = handleCancelRejectedState(message, action); + break; + default: + logAndThrowMessageError(message, "Status for action does not exisit."); } return status; @@ -423,8 +399,8 @@ private static Status handleCancelRejectedState(final Message message, final Act // Exception squid:S3655 - logAndThrowMessageError throws exception, i.e. // get will not be called - @SuppressWarnings("squid:S3655") - private Action checkActionExist(final Message message, final DmfActionUpdateStatus actionUpdateStatus) { + @SuppressWarnings("squid:S3655") private Action checkActionExist(final Message message, + final DmfActionUpdateStatus actionUpdateStatus) { final Long actionId = actionUpdateStatus.getActionId(); LOG.debug("Target notifies intermediate about action {} with status {}.", actionId, 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 c6d41b16ee..2154689b9b 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 @@ -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 @@ -78,10 +78,7 @@ import io.qameta.allure.Feature; import io.qameta.allure.Story; -@RunWith(MockitoJUnitRunner.class) -@Feature("Component Tests - Device Management Federation API") -@Story("AmqpMessage Handler Service Test") -public class AmqpMessageHandlerServiceTest { +@RunWith(MockitoJUnitRunner.class) @Feature("Component Tests - Device Management Federation API") @Story("AmqpMessage Handler Service Test") public class AmqpMessageHandlerServiceTest { private static final String SHA1 = "12345"; private static final String TENANT = "DEFAULT"; @@ -94,54 +91,37 @@ public class AmqpMessageHandlerServiceTest { private MessageConverter messageConverter; - @Mock - private AmqpMessageDispatcherService amqpMessageDispatcherServiceMock; + @Mock private AmqpMessageDispatcherService amqpMessageDispatcherServiceMock; - @Mock - private ControllerManagement controllerManagementMock; + @Mock private ControllerManagement controllerManagementMock; - @Mock - private EntityFactory entityFactoryMock; + @Mock private EntityFactory entityFactoryMock; - @Mock - private ArtifactManagement artifactManagementMock; + @Mock private ArtifactManagement artifactManagementMock; - @Mock - private TenantConfigurationManagement tenantConfigurationManagement; + @Mock private TenantConfigurationManagement tenantConfigurationManagement; - @Mock - private AmqpControllerAuthentication authenticationManagerMock; + @Mock private AmqpControllerAuthentication authenticationManagerMock; - @Mock - private ArtifactRepository artifactRepositoryMock; + @Mock private ArtifactRepository artifactRepositoryMock; - @Mock - private DownloadIdCache downloadIdCache; + @Mock private DownloadIdCache downloadIdCache; - @Mock - private HostnameResolver hostnameResolverMock; + @Mock private HostnameResolver hostnameResolverMock; - @Mock - private RabbitTemplate rabbitTemplate; + @Mock private RabbitTemplate rabbitTemplate; - @Mock - private TenantAware tenantAwareMock; + @Mock private TenantAware tenantAwareMock; - @Captor - private ArgumentCaptor> attributesCaptor; + @Captor private ArgumentCaptor> attributesCaptor; - @Captor - private ArgumentCaptor targetIdCaptor; + @Captor private ArgumentCaptor targetIdCaptor; - @Captor - private ArgumentCaptor modeCaptor; + @Captor private ArgumentCaptor modeCaptor; - @Captor - private ArgumentCaptor targetNameCaptor; + @Captor private ArgumentCaptor targetNameCaptor; - @Before - @SuppressWarnings({"rawtypes", "unchecked"}) - public void before() throws Exception { + @Before @SuppressWarnings({ "rawtypes", "unchecked" }) public void before() throws Exception { messageConverter = new Jackson2JsonMessageConverter(); when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter); when(artifactManagementMock.findFirstBySHA1(SHA1)).thenReturn(Optional.empty()); @@ -160,9 +140,7 @@ public void before() throws Exception { controllerManagementMock, tenantAwareMock); } - @Test - @Description("Tests not allowed content-type in message") - public void wrongContentType() { + @Test @Description("Tests not allowed content-type in message") public void wrongContentType() { final MessageProperties messageProperties = new MessageProperties(); messageProperties.setContentType("xml"); final Message message = new Message(new byte[0], messageProperties); @@ -173,9 +151,7 @@ public void wrongContentType() { } } - @Test - @Description("Tests the creation of a target/thing by calling the same method that incoming RabbitMQ messages would access.") - public void createThing() { + @Test @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"); @@ -185,8 +161,9 @@ public void createThing() { final ArgumentCaptor targetIdCaptor = ArgumentCaptor.forClass(String.class); final ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); - when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), - uriCaptor.capture())).thenReturn(targetMock); + when(controllerManagementMock + .findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), uriCaptor.capture())) + .thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); @@ -197,9 +174,7 @@ public void createThing() { } - @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() { + @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 MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -214,8 +189,9 @@ public void createThingWithName() { final ArgumentCaptor 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 + .findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), uriCaptor.capture(), + targetNameCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); @@ -225,9 +201,7 @@ public void createThingWithName() { assertThat(targetNameCaptor.getValue()).as("Thing name is not right").isEqualTo(targetProperties.getName()); } - @Test - @Description("Tests the creation of a target/thing without name but with body by calling the same method that incoming RabbitMQ messages would access.") - public void createThingWithBodyWithoutName() { + @Test @Description("Tests the creation of a target/thing without name but with body by calling the same method that incoming RabbitMQ messages would access.") public void createThingWithBodyWithoutName() { final String knownThingId = "3"; final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -236,15 +210,16 @@ public void createThingWithBodyWithoutName() { // should still be default (=targetId) attributeUpdate.getAttributes().put("name", "testValue1"); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(attributeUpdate, messageProperties); final Target targetMock = mock(Target.class); final ArgumentCaptor targetIdCaptor = ArgumentCaptor.forClass(String.class); final ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); - when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), - uriCaptor.capture())).thenReturn(targetMock); + when(controllerManagementMock + .findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), uriCaptor.capture())) + .thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); @@ -253,9 +228,7 @@ public void createThingWithBodyWithoutName() { assertThat(uriCaptor.getValue().toString()).as("Uri is not right").isEqualTo("amqp://vHost/MyTest"); } - @Test - @Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.") - public void updateAttributes() { + @Test @Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.") public void updateAttributes() { final String knownThingId = "1"; final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -264,11 +237,12 @@ public void updateAttributes() { attributeUpdate.getAttributes().put("testKey1", "testValue1"); attributeUpdate.getAttributes().put("testKey2", "testValue2"); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(attributeUpdate, messageProperties); - when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), - modeCaptor.capture())).thenReturn(null); + when(controllerManagementMock + .updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), modeCaptor.capture())) + .thenReturn(null); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); @@ -279,9 +253,7 @@ public void updateAttributes() { } - @Test - @Description("Tests the target attribute update with name update by calling the same method that incoming RabbitMQ messages would access.") - public void updateAttributesWithName() { + @Test @Description("Tests the target attribute update with name update by calling the same method that incoming RabbitMQ messages would access.") public void updateAttributesWithName() { final String knownThingId = "1"; final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -291,13 +263,14 @@ public void updateAttributesWithName() { attributeUpdate.getAttributes().put("testKey2", "testValue2"); attributeUpdate.setName("UpdatedTargetName"); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(attributeUpdate, messageProperties); final ArgumentCaptor targetNameCaptor = ArgumentCaptor.forClass(String.class); - when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), - modeCaptor.capture())).thenReturn(null); + when(controllerManagementMock + .updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), modeCaptor.capture())) + .thenReturn(null); when(controllerManagementMock.updateControllerName(targetIdCaptor.capture(), targetNameCaptor.capture())) .thenReturn(null); @@ -311,9 +284,7 @@ public void updateAttributesWithName() { } - @Test - @Description("Verifies that the update mode is retrieved from the UPDATE_ATTRIBUTES message and passed to the controller management.") - public void attributeUpdateModes() { + @Test @Description("Verifies that the update mode is retrieved from the UPDATE_ATTRIBUTES message and passed to the controller management.") public void attributeUpdateModes() { final String knownThingId = "1"; final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -322,8 +293,9 @@ public void attributeUpdateModes() { attributeUpdate.getAttributes().put("testKey1", "testValue1"); attributeUpdate.getAttributes().put("testKey2", "testValue2"); - when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), - modeCaptor.capture())).thenReturn(null); + when(controllerManagementMock + .updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), modeCaptor.capture())) + .thenReturn(null); // send a message which does not specify a update mode Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, messageProperties); @@ -355,9 +327,7 @@ public void attributeUpdateModes() { } - @Test - @Description("Tests the creation of a thing without a 'reply to' header in message.") - public void createThingWitoutReplyTo() { + @Test @Description("Tests the creation of a thing without a 'reply to' header in message.") public void createThingWitoutReplyTo() { final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED, null); messageProperties.setHeader(MessageHeaderKey.THING_ID, "1"); final Message message = messageConverter.toMessage("", messageProperties); @@ -371,9 +341,7 @@ public void createThingWitoutReplyTo() { } - @Test - @Description("Tests the creation of a target/thing without a thingID by calling the same method that incoming RabbitMQ messages would access.") - public void createThingWithoutID() { + @Test @Description("Tests the creation of a target/thing without a thingID by calling the same method that incoming RabbitMQ messages would access.") public void createThingWithoutID() { final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); final Message message = messageConverter.toMessage(new byte[0], messageProperties); try { @@ -384,9 +352,7 @@ public void createThingWithoutID() { } } - @Test - @Description("Tests the call of the same method that incoming RabbitMQ messages would access with an unknown message type.") - public void unknownMessageType() { + @Test @Description("Tests the call of the same method that incoming RabbitMQ messages would access with an unknown message type.") public void unknownMessageType() { final String type = "bumlux"; final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); messageProperties.setHeader(MessageHeaderKey.THING_ID, ""); @@ -400,9 +366,7 @@ public void unknownMessageType() { } } - @Test - @Description("Tests a invalid message without event topic") - public void invalidEventTopic() { + @Test @Description("Tests a invalid message without event topic") public void invalidEventTopic() { final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); final Message message = new Message(new byte[0], messageProperties); try { @@ -428,15 +392,13 @@ public void invalidEventTopic() { } - @Test - @Description("Tests the update of an action of a target without a exist action id") - public void updateActionStatusWithoutActionId() { + @Test @Description("Tests the update of an action of a target without a exist action id") public void updateActionStatusWithoutActionId() { when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.empty()); final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); final DmfActionUpdateStatus actionUpdateStatus = new DmfActionUpdateStatus(1L, DmfActionStatus.DOWNLOAD); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(actionUpdateStatus, messageProperties); try { amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); @@ -446,16 +408,14 @@ public void updateActionStatusWithoutActionId() { } } - @Test - @Description("Tests the update of an action of a target without a exist action id") - public void updateActionStatusWithoutExistActionId() { + @Test @Description("Tests the update of an action of a target without a exist action id") public void updateActionStatusWithoutExistActionId() { final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.empty()); final DmfActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(DmfActionStatus.DOWNLOAD); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(actionUpdateStatus, messageProperties); try { amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); @@ -466,14 +426,12 @@ public void updateActionStatusWithoutExistActionId() { } - @Test - @Description("Tests that an download request is denied for an artifact which does not exists") - public void authenticationRequestDeniedForArtifactWhichDoesNotExists() { + @Test @Description("Tests that an download request is denied for an artifact which does not exists") public void authenticationRequestDeniedForArtifactWhichDoesNotExists() { final MessageProperties messageProperties = createMessageProperties(null); final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, FileResource.createFileResourceBySha1("12345")); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(securityToken, messageProperties); // test final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message); @@ -485,14 +443,12 @@ public void authenticationRequestDeniedForArtifactWhichDoesNotExists() { .isEqualTo(HttpStatus.NOT_FOUND.value()); } - @Test - @Description("Tests that an download request is denied for an artifact which is not assigned to the requested target") - public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() { + @Test @Description("Tests that an download request is denied for an artifact which is not assigned to the requested target") public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() { final MessageProperties messageProperties = createMessageProperties(null); final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, FileResource.createFileResourceBySha1("12345")); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(securityToken, messageProperties); final Artifact localArtifactMock = mock(Artifact.class); when(artifactManagementMock.findFirstBySHA1(anyString())).thenReturn(Optional.of(localArtifactMock)); @@ -507,14 +463,13 @@ public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() { .isEqualTo(HttpStatus.NOT_FOUND.value()); } - @Test - @Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target") - public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() throws MalformedURLException { + @Test @Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target") public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() + throws MalformedURLException { final MessageProperties messageProperties = createMessageProperties(null); final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, FileResource.createFileResourceBySha1("12345")); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(securityToken, messageProperties); // mock final Artifact localArtifactMock = mock(Artifact.class); @@ -542,9 +497,7 @@ public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarge .startsWith("http://localhost/api/v1/downloadserver/downloadId/"); } - @Test - @Description("Tests TODO") - public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException { + @Test @Description("Tests TODO") public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException { // Mock final Action action = createActionWithTarget(22L, Status.FINISHED); @@ -561,8 +514,8 @@ public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); final DmfActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(DmfActionStatus.FINISHED, 23L); - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, - messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter() + .toMessage(actionUpdateStatus, messageProperties); // test amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); @@ -570,8 +523,8 @@ public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException final ArgumentCaptor actionPropertiesCaptor = ArgumentCaptor.forClass(ActionProperties.class); final ArgumentCaptor targetCaptor = ArgumentCaptor.forClass(Target.class); - verify(amqpMessageDispatcherServiceMock, times(1)).sendUpdateMessageToTarget(actionPropertiesCaptor.capture(), - targetCaptor.capture(), any(Map.class)); + verify(amqpMessageDispatcherServiceMock, times(1)) + .sendUpdateMessageToTarget(actionPropertiesCaptor.capture(), targetCaptor.capture(), any(Map.class)); final ActionProperties actionProperties = actionPropertiesCaptor.getValue(); assertThat(actionProperties).isNotNull(); assertThat(actionProperties.getTenant()).as("event has tenant").isEqualTo("DEFAULT"); 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 5b057069cd..bd2b8f8556 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 @@ -19,18 +19,13 @@ /** * JSON representation of the Attribute Update message. */ -@JsonInclude(Include.NON_NULL) -@JsonIgnoreProperties(ignoreUnknown = true) -public class DmfAttributeUpdate { +@JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class DmfAttributeUpdate { - @JsonProperty - private final Map attributes = new HashMap<>(); + @JsonProperty private final Map attributes = new HashMap<>(); - @JsonProperty - private DmfUpdateMode mode; + @JsonProperty private DmfUpdateMode mode; - @JsonProperty - private String name; + @JsonProperty private String name; public DmfUpdateMode getMode() { return mode; diff --git a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java index 4cffa726b5..fb58c08ab5 100644 --- a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.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 @@ -19,12 +19,9 @@ /** * JSON representation of the Attribute THING_CREATED message. */ -@JsonInclude(Include.NON_NULL) -@JsonIgnoreProperties(ignoreUnknown = true) -public class DmfTargetProperties { +@JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class DmfTargetProperties { - @JsonProperty - private String name; + @JsonProperty private String name; public String getName() { return 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 61e6e9ea1a..a9969847bd 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 @@ -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 @@ -48,14 +48,14 @@ public interface ControllerManagement { /** * 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 @@ -64,43 +64,41 @@ public interface ControllerManagement { * @throws ConstraintViolationException * if fields are not filled as specified. Check * {@link ActionStatusCreate} for field constraints. - * + * */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Action addCancelActionStatus(@NotNull @Valid ActionStatusCreate create); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Action addCancelActionStatus( + @NotNull @Valid ActionStatusCreate create); /** * Retrieves assigned {@link SoftwareModule} of a target. - * + * * @param moduleId * of the {@link SoftwareModule} * @return {@link SoftwareModule} identified by ID */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Optional getSoftwareModule(long moduleId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Optional getSoftwareModule(long moduleId); /** * Retrieves {@link SoftwareModuleMetadata} where * {@link SoftwareModuleMetadata#isTargetVisible()}. - * + * * @param moduleId * of the {@link SoftwareModule} * @return list of {@link SoftwareModuleMetadata} with maximum size of * {@link RepositoryConstants#MAX_META_DATA_COUNT} */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Map> findTargetVisibleMetaDataBySoftwareModuleId( + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Map> findTargetVisibleMetaDataBySoftwareModuleId( @NotNull Collection moduleId); /** * Simple addition of a new {@link ActionStatus} entry to the {@link Action} * . No state changes. - * + * * @param create * to add to the action - * + * * @return created {@link ActionStatus} entity - * + * * @throws QuotaExceededException * if more than the allowed number of status entries or messages * per entry are inserted @@ -110,8 +108,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul * if fields are not filled as specified. Check * {@link ActionStatusCreate} for field constraints. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - ActionStatus addInformationalActionStatus(@NotNull @Valid ActionStatusCreate create); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) ActionStatus addInformationalActionStatus( + @NotNull @Valid ActionStatusCreate create); /** * Adds an {@link ActionStatus} entry for an update {@link Action} including @@ -132,13 +130,13 @@ Map> findTargetVisibleMetaDataBySoftwareModul * if fields are not filled as specified. Check * {@link ActionStatusCreate} for field constraints. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Action addUpdateActionStatus(@NotNull @Valid ActionStatusCreate create); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Action addUpdateActionStatus( + @NotNull @Valid ActionStatusCreate create); /** * Retrieves oldest {@link Action} that is active and assigned to a * {@link Target}. - * + * * For performance reasons this method does not throw * {@link EntityNotFoundException} in case target with given controlelrId * does not exist but will return an {@link Optional#empty()} instead. @@ -146,23 +144,23 @@ Map> findTargetVisibleMetaDataBySoftwareModul * @param controllerId * identifies the target to retrieve the actions from * @return a list of actions assigned to given target which are active - * + * */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Optional findOldestActiveActionByTarget(@NotEmpty String controllerId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Optional findOldestActiveActionByTarget( + @NotEmpty String controllerId); /** * Retrieves all active actions which are assigned to the target with the * given controller ID. - * + * * @param pageable * pagination parameter * @param controllerId * of the target * @return the requested {@link Page} with {@link Action}s */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Page findActiveActionsByTarget(@NotNull Pageable pageable, @NotEmpty String controllerId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Page findActiveActionsByTarget( + @NotNull Pageable pageable, @NotEmpty String controllerId); /** * Get the {@link Action} entity for given actionId with all lazy @@ -172,8 +170,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul * to be id of the action * @return the corresponding {@link Action} */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Optional findActionWithDetails(long actionId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Optional findActionWithDetails(long actionId); /** * Retrieves all the {@link ActionStatus} entries of the given @@ -184,12 +181,12 @@ Map> findTargetVisibleMetaDataBySoftwareModul * @param actionId * to be filtered on * @return the corresponding {@link Page} of {@link ActionStatus} - * + * * @throws EntityNotFoundException * if action with given ID does not exist */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Page findActionStatusByAction(@NotNull Pageable pageReq, long actionId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Page findActionStatusByAction( + @NotNull Pageable pageReq, long actionId); /** * Register new target in the repository (plug-and-play) and in case it @@ -204,8 +201,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul * the client IP address of the target, might be {@code null} * @return target reference */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Target findOrRegisterTargetIfItDoesNotExist( + @NotEmpty String controllerId, @NotNull URI address); /** * Register new target in the repository (plug-and-play) and in case it @@ -222,8 +219,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul * the name of the target * @return target reference */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address, String name); + @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 @@ -235,13 +232,13 @@ Map> findTargetVisibleMetaDataBySoftwareModul * of the the {@link SoftwareModule} that should be assigned to * the target * @return last {@link Action} for given combination - * + * * @throws EntityNotFoundException * if target with given ID does not exist * */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Optional getActionForDownloadByTargetAndSoftwareModule(@NotEmpty String controllerId, long moduleId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Optional getActionForDownloadByTargetAndSoftwareModule( + @NotEmpty String controllerId, long moduleId); /** * Returns configured polling interval at which the controller polls hawkBit @@ -249,16 +246,14 @@ Map> findTargetVisibleMetaDataBySoftwareModul * * @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - String getPollingTime(); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) String getPollingTime(); /** * Returns the configured minimum polling interval. * * @return current {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - String getMinPollingTime(); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) String getMinPollingTime(); /** * Returns the count to be used for reducing polling interval while calling @@ -267,8 +262,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul * @return configured value of * {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - int getMaintenanceWindowPollCount(); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) int getMaintenanceWindowPollCount(); /** * Returns polling time based on the maintenance window for an action. @@ -286,8 +280,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul * * @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - String getPollingTimeForAction(long actionId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) String getPollingTimeForAction(long actionId); /** * Checks if a given target has currently or has even been assigned to the @@ -295,7 +288,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul * 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 @@ -304,12 +297,12 @@ Map> findTargetVisibleMetaDataBySoftwareModul * @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 */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - boolean hasTargetArtifactAssigned(@NotEmpty String controllerId, @NotEmpty String sha1Hash); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) boolean hasTargetArtifactAssigned(@NotEmpty String controllerId, + @NotEmpty String sha1Hash); /** * Checks if a given target has currently or has even been assigned to the @@ -317,7 +310,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul * 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 @@ -326,12 +319,12 @@ Map> findTargetVisibleMetaDataBySoftwareModul * @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 */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - boolean hasTargetArtifactAssigned(long targetId, @NotEmpty String sha1Hash); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) boolean hasTargetArtifactAssigned(long targetId, + @NotEmpty String sha1Hash); /** * Registers retrieved status for given {@link Target} and {@link Action} if @@ -343,12 +336,11 @@ Map> findTargetVisibleMetaDataBySoftwareModul * for the status * @return the update action in case the status has been changed to * {@link Status#RETRIEVED} - * + * * @throws EntityNotFoundException * if action with given ID does not exist */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Action registerRetrieved(long actionId, String message); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Action registerRetrieved(long actionId, String message); /** * Updates attributes of the controller according to the given @@ -370,9 +362,8 @@ Map> findTargetVisibleMetaDataBySoftwareModul * @throws InvalidTargetAttributeException * if attributes violate constraints */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map attributes, - UpdateMode mode); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Target updateControllerAttributes(@NotEmpty String controllerId, + @NotNull Map attributes, UpdateMode mode); /** * Updates name of the controller according to the given name @@ -389,8 +380,8 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map getByControllerId(@NotEmpty String controllerId); + + SpringEvalExpressions.IS_SYSTEM_CODE) Optional getByControllerId(@NotEmpty String controllerId); /** * Finds {@link Target} based on given ID returns found Target without @@ -417,8 +407,7 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map get(long targetId); + + SpringEvalExpressions.IS_SYSTEM_CODE) Optional get(long targetId); /** * Retrieves the specified number of messages from action history of the @@ -444,8 +433,8 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map getActionHistoryMessages(long actionId, int messageCount); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) List getActionHistoryMessages(long actionId, + int messageCount); /** * Cancels given {@link Action} for this {@link Target}. However, it might @@ -463,28 +452,27 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map getActiveActionsByExternalRef(@NotNull List externalRefs); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) List getActiveActionsByExternalRef( + @NotNull List externalRefs); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index e115cad26d..44623e34b8 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.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 @@ -107,54 +107,38 @@ * JPA based {@link ControllerManagement} implementation. * */ -@Transactional(readOnly = true) -@Validated -public class JpaControllerManagement implements ControllerManagement { +@Transactional(readOnly = true) @Validated public class JpaControllerManagement implements ControllerManagement { private static final Logger LOG = LoggerFactory.getLogger(JpaControllerManagement.class); private final BlockingDeque queue; - @Autowired - private EntityManager entityManager; + @Autowired private EntityManager entityManager; - @Autowired - private ActionRepository actionRepository; + @Autowired private ActionRepository actionRepository; - @Autowired - private TargetRepository targetRepository; + @Autowired private TargetRepository targetRepository; - @Autowired - private SoftwareModuleRepository softwareModuleRepository; + @Autowired private SoftwareModuleRepository softwareModuleRepository; - @Autowired - private ActionStatusRepository actionStatusRepository; + @Autowired private ActionStatusRepository actionStatusRepository; - @Autowired - private QuotaManagement quotaManagement; + @Autowired private QuotaManagement quotaManagement; - @Autowired - private TenantConfigurationManagement tenantConfigurationManagement; + @Autowired private TenantConfigurationManagement tenantConfigurationManagement; - @Autowired - private SystemSecurityContext systemSecurityContext; + @Autowired private SystemSecurityContext systemSecurityContext; - @Autowired - private EntityFactory entityFactory; + @Autowired private EntityFactory entityFactory; - @Autowired - private EventPublisherHolder eventPublisherHolder; + @Autowired private EventPublisherHolder eventPublisherHolder; - @Autowired - private AfterTransactionCommitExecutor afterCommit; + @Autowired private AfterTransactionCommitExecutor afterCommit; - @Autowired - private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; + @Autowired private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; - @Autowired - private PlatformTransactionManager txManager; + @Autowired private PlatformTransactionManager txManager; - @Autowired - private TenantAware tenantAware; + @Autowired private TenantAware tenantAware; private final RepositoryProperties repositoryProperties; @@ -162,9 +146,9 @@ public class JpaControllerManagement implements ControllerManagement { final RepositoryProperties repositoryProperties) { if (!repositoryProperties.isEagerPollPersistence()) { - executorService.scheduleWithFixedDelay(this::flushUpdateQueue, - repositoryProperties.getPollPersistenceFlushTime(), - repositoryProperties.getPollPersistenceFlushTime(), TimeUnit.MILLISECONDS); + executorService + .scheduleWithFixedDelay(this::flushUpdateQueue, repositoryProperties.getPollPersistenceFlushTime(), + repositoryProperties.getPollPersistenceFlushTime(), TimeUnit.MILLISECONDS); queue = new LinkedBlockingDeque<>(repositoryProperties.getPollPersistenceQueueSize()); } else { @@ -174,8 +158,7 @@ public class JpaControllerManagement implements ControllerManagement { this.repositoryProperties = repositoryProperties; } - @Override - public String getPollingTime() { + @Override public String getPollingTime() { return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); } @@ -185,8 +168,7 @@ public String getPollingTime() { * * @return current {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. */ - @Override - public String getMinPollingTime() { + @Override public String getMinPollingTime() { return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement .getConfigurationValue(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL, String.class).getValue()); } @@ -198,14 +180,12 @@ public String getMinPollingTime() { * @return configured value of * {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}. */ - @Override - public int getMaintenanceWindowPollCount() { + @Override public int getMaintenanceWindowPollCount() { return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement .getConfigurationValue(TenantConfigurationKey.MAINTENANCE_WINDOW_POLL_COUNT, Integer.class).getValue()); } - @Override - public String getPollingTimeForAction(final long actionId) { + @Override public String getPollingTimeForAction(final long actionId) { final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId); @@ -300,8 +280,7 @@ String timeToNextEvent(final int eventCount, final ZonedDateTime timerResetTime) } } - @Override - public Optional getActionForDownloadByTargetAndSoftwareModule(final String controllerId, + @Override public Optional getActionForDownloadByTargetAndSoftwareModule(final String controllerId, final long moduleId) { throwExceptionIfTargetDoesNotExist(controllerId); throwExceptionIfSoftwareModuleDoesNotExist(moduleId); @@ -333,52 +312,44 @@ private void throwExceptionIfSoftwareModuleDoesNotExist(final Long moduleId) { } } - @Override - public boolean hasTargetArtifactAssigned(final String controllerId, final String sha1Hash) { + @Override public boolean hasTargetArtifactAssigned(final String controllerId, final String sha1Hash) { throwExceptionIfTargetDoesNotExist(controllerId); return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(controllerId, sha1Hash)) > 0; } - @Override - public boolean hasTargetArtifactAssigned(final long targetId, final String sha1Hash) { + @Override public boolean hasTargetArtifactAssigned(final long targetId, final String sha1Hash) { throwExceptionIfTargetDoesNotExist(targetId); return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(targetId, sha1Hash)) > 0; } - @Override - public Optional findOldestActiveActionByTarget(final String controllerId) { + @Override public Optional findOldestActiveActionByTarget(final String controllerId) { if (!actionRepository.activeActionExistsForControllerId(controllerId)) { return Optional.empty(); } // used in favorite to findFirstByTargetAndActiveOrderByIdAsc due to // DATAJPA-841 issue. - return actionRepository.findFirstByTargetControllerIdAndActive(new Sort(Direction.ASC, "id"), controllerId, - true); + return actionRepository + .findFirstByTargetControllerIdAndActive(new Sort(Direction.ASC, "id"), controllerId, true); } - @Override - public Page findActiveActionsByTarget(final Pageable pageable, final String controllerId) { + @Override public Page findActiveActionsByTarget(final Pageable pageable, final String controllerId) { if (!actionRepository.activeActionExistsForControllerId(controllerId)) { return Page.empty(); } return actionRepository.findByActiveAndTarget(pageable, controllerId, true); } - @Override - public Optional findActionWithDetails(final long actionId) { + @Override public Optional findActionWithDetails(final long actionId) { return actionRepository.getById(actionId); } - @Override - public List getActiveActionsByExternalRef(@NotNull final List externalRefs) { + @Override public List getActiveActionsByExternalRef(@NotNull final List externalRefs) { return actionRepository.findByExternalRefInAndActive(externalRefs, true); } - @Override - @Transactional(isolation = Isolation.READ_COMMITTED) - @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address) { + @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target findOrRegisterTargetIfItDoesNotExist( + final String controllerId, final URI address) { final Specification spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); @@ -386,10 +357,8 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi .orElseGet(() -> createTarget(controllerId, address)); } - @Override - @Transactional(isolation = Isolation.READ_COMMITTED) - @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address, String name) { + @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target findOrRegisterTargetIfItDoesNotExist( + final String controllerId, final URI address, String name) { final Specification spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); @@ -406,10 +375,11 @@ private Target createNewTarget(final String controllerId, final URI address, fin } private Target createTarget(final String controllerId, final URI address) { - final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() - .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(controllerId) - .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) - .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); + final Target result = targetRepository + .save((JpaTarget) entityFactory.target().create().controllerId(controllerId) + .description("Plug and Play target: " + controllerId).name(controllerId) + .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) + .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher() .publishEvent(new TargetPollEvent(result, eventPublisherHolder.getApplicationId()))); @@ -419,10 +389,11 @@ private Target createTarget(final String controllerId, final URI address) { private Target createTarget(final String controllerId, final URI address, final String name) { - final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() - .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(name) - .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) - .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); + final Target result = targetRepository + .save((JpaTarget) entityFactory.target().create().controllerId(controllerId) + .description("Plug and Play target: " + controllerId).name(name) + .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) + .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher() .publishEvent(new TargetPollEvent(result, eventPublisherHolder.getApplicationId()))); @@ -468,9 +439,9 @@ private void flushUpdateQueue() { private Void updateLastTargetQueries(final String tenant, final List polls) { LOG.debug("Persist {} targetqueries.", polls.size()); - final List> pollChunks = Lists.partition( - polls.stream().map(TargetPoll::getControllerId).collect(Collectors.toList()), - Constants.MAX_ENTRIES_IN_STATEMENT); + final List> pollChunks = Lists + .partition(polls.stream().map(TargetPoll::getControllerId).collect(Collectors.toList()), + Constants.MAX_ENTRIES_IN_STATEMENT); pollChunks.forEach(chunk -> { setLastTargetQuery(tenant, System.currentTimeMillis(), chunk); @@ -548,11 +519,9 @@ private boolean isStoreEager(final JpaTarget toUpdate, final URI address) { } } - @Override - @Transactional(isolation = Isolation.READ_COMMITTED) - @Retryable(include = { - ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Action addCancelActionStatus(final ActionStatusCreate c) { + @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action addCancelActionStatus( + final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); @@ -564,20 +533,20 @@ public Action addCancelActionStatus(final ActionStatusCreate c) { final JpaActionStatus actionStatus = create.build(); switch (actionStatus.getStatus()) { - case CANCELED : - case FINISHED : - handleFinishedCancelation(actionStatus, action); - break; - case ERROR : - case CANCEL_REJECTED : - // Cancellation rejected. Back to running. - action.setStatus(Status.RUNNING); - break; - default : - // information status entry - check for a potential DOS attack - assertActionStatusQuota(action); - assertActionStatusMessageQuota(actionStatus); - break; + case CANCELED: + case FINISHED: + handleFinishedCancelation(actionStatus, action); + break; + case ERROR: + case CANCEL_REJECTED: + // Cancellation rejected. Back to running. + action.setStatus(Status.RUNNING); + break; + default: + // information status entry - check for a potential DOS attack + assertActionStatusQuota(action); + assertActionStatusMessageQuota(actionStatus); + break; } actionStatus.setAction(actionRepository.save(action)); @@ -599,11 +568,9 @@ private void handleFinishedCancelation(final JpaActionStatus actionStatus, final DeploymentHelper.successCancellation(action, actionRepository, targetRepository); } - @Override - @Transactional(isolation = Isolation.READ_COMMITTED) - @Retryable(include = { - ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Action addUpdateActionStatus(final ActionStatusCreate c) { + @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action addUpdateActionStatus( + final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); final JpaActionStatus actionStatus = create.build(); @@ -626,11 +593,11 @@ public Action addUpdateActionStatus(final ActionStatusCreate c) { */ private boolean isUpdatingActionStatusAllowed(final JpaAction action, final JpaActionStatus actionStatus) { - final boolean isIntermediateFeedback = (FINISHED != actionStatus.getStatus()) - && (Status.ERROR != actionStatus.getStatus()); + final boolean isIntermediateFeedback = + (FINISHED != actionStatus.getStatus()) && (Status.ERROR != actionStatus.getStatus()); - final boolean isAllowedByRepositoryConfiguration = !repositoryProperties.isRejectActionStatusForClosedAction() - && isIntermediateFeedback; + final boolean isAllowedByRepositoryConfiguration = + !repositoryProperties.isRejectActionStatusForClosedAction() && isIntermediateFeedback; final boolean isAllowedForDownloadOnlyActions = isDownloadOnly(action) && !isIntermediateFeedback; @@ -654,19 +621,19 @@ private Action handleAddUpdateActionStatus(final JpaActionStatus actionStatus, f assertActionStatusMessageQuota(actionStatus); switch (actionStatus.getStatus()) { - case ERROR : - final JpaTarget target = (JpaTarget) action.getTarget(); - target.setUpdateStatus(TargetUpdateStatus.ERROR); - handleErrorOnAction(action, target); - break; - case FINISHED : - controllerId = handleFinishedAndStoreInTargetStatus(action); - break; - case DOWNLOADED : - controllerId = handleDownloadedActionStatus(action); - break; - default : - break; + case ERROR: + final JpaTarget target = (JpaTarget) action.getTarget(); + target.setUpdateStatus(TargetUpdateStatus.ERROR); + handleErrorOnAction(action, target); + break; + case FINISHED: + controllerId = handleFinishedAndStoreInTargetStatus(action); + break; + case DOWNLOADED: + controllerId = handleDownloadedActionStatus(action); + break; + default: + break; } actionStatus.setAction(action); @@ -700,8 +667,8 @@ private void requestControllerAttributes(final String controllerId) { target.setRequestControllerAttributes(true); - eventPublisherHolder.getEventPublisher() - .publishEvent(new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(), + eventPublisherHolder.getEventPublisher().publishEvent( + new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(), target.getControllerId(), target.getAddress() != null ? target.getAddress().toString() : null, JpaTarget.class.getName(), eventPublisherHolder.getApplicationId())); } @@ -738,8 +705,8 @@ private String handleFinishedAndStoreInTargetStatus(final JpaAction action) { // check if the assigned set is equal to the installed set (not // necessarily the case as another update might be pending already). - if (target.getAssignedDistributionSet() != null - && target.getAssignedDistributionSet().getId().equals(target.getInstalledDistributionSet().getId())) { + if (target.getAssignedDistributionSet() != null && target.getAssignedDistributionSet().getId() + .equals(target.getInstalledDistributionSet().getId())) { target.setUpdateStatus(TargetUpdateStatus.IN_SYNC); } @@ -749,12 +716,9 @@ private String handleFinishedAndStoreInTargetStatus(final JpaAction action) { return target.getControllerId(); } - @Override - @Transactional - @Retryable(include = { - ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Target updateControllerAttributes(final String controllerId, final Map data, - final UpdateMode mode) { + @Override @Transactional @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target updateControllerAttributes( + final String controllerId, final Map data, final UpdateMode mode) { /* * Constraints on attribute keys & values are not validated by @@ -771,35 +735,33 @@ public Target updateControllerAttributes(final String controllerId, final Map controllerAttributes = target.getControllerAttributes(); final UpdateMode updateMode = mode != null ? mode : UpdateMode.MERGE; switch (updateMode) { - case REMOVE : - // remove the addressed attributes - data.keySet().forEach(controllerAttributes::remove); - break; - case REPLACE : - // clear the attributes before adding the new attributes - controllerAttributes.clear(); - copy(data, controllerAttributes); - target.setRequestControllerAttributes(false); - break; - case MERGE : - // just merge the attributes in - copy(data, controllerAttributes); - target.setRequestControllerAttributes(false); - break; - default : - // unknown update mode - throw new IllegalStateException("The update mode " + updateMode + " is not supported."); + case REMOVE: + // remove the addressed attributes + data.keySet().forEach(controllerAttributes::remove); + break; + case REPLACE: + // clear the attributes before adding the new attributes + controllerAttributes.clear(); + copy(data, controllerAttributes); + target.setRequestControllerAttributes(false); + break; + case MERGE: + // just merge the attributes in + copy(data, controllerAttributes); + target.setRequestControllerAttributes(false); + break; + default: + // unknown update mode + throw new IllegalStateException("The update mode " + updateMode + " is not supported."); } assertTargetAttributesQuota(target); return targetRepository.save(target); } - @Override - @Transactional - @Retryable(include = { - ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Target updateControllerName(final String controllerId, final String controllerName) { + @Override @Transactional @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target updateControllerName( + final String controllerId, final String controllerName) { final JpaTarget target = (JpaTarget) targetRepository.findByControllerId(controllerId) .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); @@ -842,11 +804,9 @@ private void assertTargetAttributesQuota(final JpaTarget target) { Target.class.getSimpleName(), null); } - @Override - @Transactional - @Retryable(include = { - ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Action registerRetrieved(final long actionId, final String message) { + @Override @Transactional @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action registerRetrieved( + final long actionId, final String message) { return handleRegisterRetrieved(actionId, message); } @@ -903,11 +863,9 @@ private Action handleRegisterRetrieved(final Long actionId, final String message return action; } - @Override - @Transactional - @Retryable(include = { - ConcurrencyFailureException.class}, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public ActionStatus addInformationalActionStatus(final ActionStatusCreate c) { + @Override @Transactional @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public ActionStatus addInformationalActionStatus( + final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); final JpaActionStatus statusMessage = create.build(); @@ -924,18 +882,15 @@ private JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) { .orElseThrow(() -> new EntityNotFoundException(Action.class, actionId)); } - @Override - public Optional getByControllerId(final String controllerId) { + @Override public Optional getByControllerId(final String controllerId) { return targetRepository.findByControllerId(controllerId); } - @Override - public Optional get(final long targetId) { + @Override public Optional get(final long targetId) { return targetRepository.findById(targetId).map(t -> (Target) t); } - @Override - public Page findActionStatusByAction(final Pageable pageReq, final long actionId) { + @Override public Page findActionStatusByAction(final Pageable pageReq, final long actionId) { if (!actionRepository.existsById(actionId)) { throw new EntityNotFoundException(Action.class, actionId); } @@ -943,8 +898,7 @@ public Page findActionStatusByAction(final Pageable pageReq, final return actionStatusRepository.findByActionId(pageReq, actionId); } - @Override - public List getActionHistoryMessages(final long actionId, final int messageCount) { + @Override public List getActionHistoryMessages(final long actionId, final int messageCount) { // Just return empty list in case messageCount is zero. if (messageCount == 0) { return Collections.emptyList(); @@ -952,9 +906,9 @@ public List getActionHistoryMessages(final long actionId, final int mess // For negative and large value of messageCount, limit the number of // messages. - final int limit = messageCount < 0 || messageCount >= RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT - ? RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT - : messageCount; + final int limit = messageCount < 0 || messageCount >= RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT ? + RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT : + messageCount; final PageRequest pageable = PageRequest.of(0, limit, new Sort(Direction.DESC, "occurredAt")); final Page messages = actionStatusRepository.findMessagesByActionIdAndMessageNotLike(pageable, actionId, @@ -966,19 +920,16 @@ public List getActionHistoryMessages(final long actionId, final int mess return messages.getContent(); } - @Override - public Optional getSoftwareModule(final long id) { + @Override public Optional getSoftwareModule(final long id) { return softwareModuleRepository.findById(id).map(s -> (SoftwareModule) s); } - @Override - public Map> findTargetVisibleMetaDataBySoftwareModuleId( + @Override public Map> findTargetVisibleMetaDataBySoftwareModuleId( final Collection moduleId) { return softwareModuleMetadataRepository .findBySoftwareModuleIdInAndTargetVisible(PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), - moduleId, true) - .getContent().stream().collect(Collectors.groupingBy(o -> (Long) o[0], + moduleId, true).getContent().stream().collect(Collectors.groupingBy(o -> (Long) o[0], Collectors.mapping(o -> (SoftwareModuleMetadata) o[1], Collectors.toList()))); } @@ -1000,8 +951,7 @@ public String getControllerId() { return controllerId; } - @Override - public int hashCode() { + @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (controllerId == null ? 0 : controllerId.hashCode()); @@ -1009,8 +959,7 @@ public int hashCode() { return result; } - @Override - public boolean equals(final Object obj) { + @Override public boolean equals(final Object obj) { if (this == obj) { return true; } @@ -1057,10 +1006,8 @@ public boolean equals(final Object obj) { * @throws EntityNotFoundException * if action with given actionId does not exist. */ - @Override - @Modifying - @Transactional(isolation = Isolation.READ_COMMITTED) - public Action cancelAction(final long actionId) { + @Override @Modifying @Transactional(isolation = Isolation.READ_COMMITTED) public Action cancelAction( + final long actionId) { LOG.debug("cancelAction({})", actionId); final JpaAction action = actionRepository.findById(actionId) @@ -1087,8 +1034,7 @@ public Action cancelAction(final long actionId) { } } - @Override - public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) { + @Override public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) { actionRepository.updateExternalRef(actionId, externalRef); } 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 ea61619eae..0d6d512c1f 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 @@ -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 @@ -82,27 +82,24 @@ import io.qameta.allure.Step; import io.qameta.allure.Story; -@Feature("Component Tests - Repository") -@Story("Controller Management") -public class ControllerManagementTest extends AbstractJpaIntegrationTest { +@Feature("Component Tests - Repository") @Story("Controller Management") public class ControllerManagementTest + extends AbstractJpaIntegrationTest { - @Autowired - private RepositoryProperties repositoryProperties; + @Autowired private RepositoryProperties repositoryProperties; - @Test - @Description("Verifies that management get access react as specfied 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)}) - public void nonExistingEntityAccessReturnsNotPresent() { + @Test @Description( + "Verifies that management get access react as specfied 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) }) public void nonExistingEntityAccessReturnsNotPresent() { final Target target = testdataFactory.createTarget(); final SoftwareModule module = testdataFactory.createSoftwareModuleOs(); assertThat(controllerManagement.findActionWithDetails(NOT_EXIST_IDL)).isNotPresent(); assertThat(controllerManagement.getByControllerId(NOT_EXIST_ID)).isNotPresent(); assertThat(controllerManagement.get(NOT_EXIST_IDL)).isNotPresent(); - assertThat(controllerManagement.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), - module.getId())).isNotPresent(); + assertThat(controllerManagement + .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module.getId())) + .isNotPresent(); assertThat(controllerManagement.findOldestActiveActionByTarget(NOT_EXIST_ID)).isNotPresent(); @@ -110,12 +107,11 @@ public void nonExistingEntityAccessReturnsNotPresent() { assertThat(controllerManagement.hasTargetArtifactAssigned(target.getId(), "XXX")).isFalse(); } - @Test - @Description("Verifies that management queries react as specfied on calls for non existing entities " - + " by means of throwing EntityNotFoundException.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 1)}) - public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws URISyntaxException { + @Test @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") @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(); @@ -129,7 +125,7 @@ public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.FINISHED)), "Action"); verifyThrownExceptionBy(() -> controllerManagement - .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), NOT_EXIST_IDL), + .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), NOT_EXIST_IDL), "SoftwareModule"); verifyThrownExceptionBy( @@ -147,16 +143,14 @@ public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws () -> controllerManagement.updateControllerAttributes(NOT_EXIST_ID, Maps.newHashMap(), null), "Target"); } - @Test - @Description("Controller confirms successfull update with FINISHED status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Controller confirms successfull update with FINISHED status.") @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)}) - public void controllerConfirmsUpdateWithFinished() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmsUpdateWithFinished() { final Long actionId = createTargetAndAssignDs(); simulateIntermediateStatusOnUpdate(actionId); @@ -170,45 +164,39 @@ public void controllerConfirmsUpdateWithFinished() { assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(7); } - @Test - @Description("Controller confirmation failes with invalid messages.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Controller confirmation failes with invalid messages.") @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)}) - public void controllerConfirmationFailsWithInvalidMessages() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmationFailsWithInvalidMessages() { final Long actionId = createTargetAndAssignDs(); simulateIntermediateStatusOnUpdate(actionId); - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus() - .create(actionId).status(Action.Status.FINISHED).message(INVALID_TEXT_HTML))) - .as("set invalid description text should not be created"); + assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> controllerManagement + .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED) + .message(INVALID_TEXT_HTML))).as("set invalid description text should not be created"); - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> controllerManagement.addUpdateActionStatus( - entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED) - .messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML)))) + assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> controllerManagement + .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED) + .messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML)))) .as("set invalid description text should not be created"); assertThat(actionStatusRepository.count()).isEqualTo(6); assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(6); } - @Test - @Description("Controller confirms successfull update with FINISHED status on a action that is on canceling. " - + "Reason: The decission to ignore the cancellation is in fact up to the controller.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Controller confirms successfull update with FINISHED status on a action that is on canceling. " + + "Reason: The decission to ignore the cancellation is in fact up to the controller.") @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)}) - public void controllerConfirmsUpdateWithFinishedAndIgnorsCancellationWithThat() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmsUpdateWithFinishedAndIgnorsCancellationWithThat() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -221,14 +209,12 @@ public void controllerConfirmsUpdateWithFinishedAndIgnorsCancellationWithThat() assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(3); } - @Test - @Description("Update server rejects cancelation feedback if action is not in CANCELING state.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Update server rejects cancelation feedback if action is not in CANCELING state.") @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)}) - public void cancellationFeedbackRejectedIfActionIsNotInCanceling() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void cancellationFeedbackRejectedIfActionIsNotInCanceling() { final Long actionId = createTargetAndAssignDs(); try { @@ -247,16 +233,14 @@ public void cancellationFeedbackRejectedIfActionIsNotInCanceling() { } - @Test - @Description("Controller confirms action cancelation with FINISHED status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Controller confirms action cancelation with FINISHED status.") @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)}) - public void controllerConfirmsActionCancelationWithFinished() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmsActionCancelationWithFinished() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -274,16 +258,14 @@ public void controllerConfirmsActionCancelationWithFinished() { assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(8); } - @Test - @Description("Controller confirms action cancelation with FINISHED status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Controller confirms action cancelation with FINISHED status.") @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)}) - public void controllerConfirmsActionCancelationWithCanceled() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerConfirmsActionCancelationWithCanceled() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -301,17 +283,16 @@ public void controllerConfirmsActionCancelationWithCanceled() { assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(8); } - @Test - @Description("Controller rejects action cancelation 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), + @Test @Description( + "Controller rejects action cancelation 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), @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)}) - public void controllerRejectsActionCancelationWithReject() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerRejectsActionCancelationWithReject() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -329,17 +310,16 @@ public void controllerRejectsActionCancelationWithReject() { assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(8); } - @Test - @Description("Controller rejects action cancelation 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), + @Test @Description( + "Controller rejects action cancelation 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), @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)}) - public void controllerRejectsActionCancelationWithError() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerRejectsActionCancelationWithError() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -357,8 +337,7 @@ public void controllerRejectsActionCancelationWithError() { assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(8); } - @Step - private Long createTargetAndAssignDs() { + @Step private Long createTargetAndAssignDs() { final Long dsId = testdataFactory.createDistributionSet().getId(); testdataFactory.createTarget(); assignDistributionSet(dsId, DEFAULT_CONTROLLER_ID); @@ -368,8 +347,7 @@ private Long createTargetAndAssignDs() { return deploymentManagement.findActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID).getContent().get(0).getId(); } - @Step - private Long createAndAssignDsAsDownloadOnly(final String dsName, final String defaultControllerId) { + @Step private Long createAndAssignDsAsDownloadOnly(final String dsName, final String defaultControllerId) { final Long dsId = testdataFactory.createDistributionSet(dsName).getId(); assignDistributionSet(dsId, defaultControllerId, DOWNLOAD_ONLY); assertThat(targetManagement.getByControllerID(defaultControllerId).get().getUpdateStatus()) @@ -381,8 +359,7 @@ private Long createAndAssignDsAsDownloadOnly(final String dsName, final String d return id; } - @Step - private Long assignDs(final Long dsId, final String defaultControllerId, final Action.ActionType actionType) { + @Step private Long assignDs(final Long dsId, final String defaultControllerId, final Action.ActionType actionType) { assignDistributionSet(dsId, defaultControllerId, actionType); assertThat(targetManagement.getByControllerID(defaultControllerId).get().getUpdateStatus()) .isEqualTo(TargetUpdateStatus.PENDING); @@ -393,8 +370,7 @@ private Long assignDs(final Long dsId, final String defaultControllerId, final A return id; } - @Step - private void simulateIntermediateStatusOnCancellation(final Long actionId) { + @Step private void simulateIntermediateStatusOnCancellation(final Long actionId) { controllerManagement .addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING)); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING, @@ -421,8 +397,7 @@ private void simulateIntermediateStatusOnCancellation(final Long actionId) { Action.Status.WARNING, true); } - @Step - private void simulateIntermediateStatusOnUpdate(final Long actionId) { + @Step private void simulateIntermediateStatusOnUpdate(final Long actionId) { controllerManagement .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING)); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, @@ -466,16 +441,15 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @Test - @Description("Verifies that assignement 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), + @Test @Description( + "Verifies that assignement 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), @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)}) - public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() { + @Expect(type = SoftwareModuleUpdatedEvent.class, count = 2) }) public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() { final int artifactSize = 5 * 1024; final byte[] random = RandomUtils.nextBytes(artifactSize); @@ -492,21 +466,19 @@ public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() { assertThat( controllerManagement.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact.getSha1Hash())) - .isFalse(); + .isFalse(); savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId())); assertThat( controllerManagement.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact.getSha1Hash())) - .isTrue(); + .isTrue(); assertThat( controllerManagement.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact2.getSha1Hash())) - .isTrue(); + .isTrue(); } - @Test - @Description("Register a controller which does not exist") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetPollEvent.class, count = 2)}) - public void findOrRegisterTargetIfItDoesNotExist() { + @Test @Description("Register a controller which does not exist") @ExpectEvents({ + @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 2) }) public void findOrRegisterTargetIfItDoesNotExist() { final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); assertThat(target).as("target should not be null").isNotNull(); @@ -515,23 +487,20 @@ public void findOrRegisterTargetIfItDoesNotExist() { assertThat(targetRepository.count()).as("Only 1 target should be registred").isEqualTo(1L); } - @Test - @Description("Register a controller with name which does not exist") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetPollEvent.class, count = 2)}) - public void findOrRegisterTargetIfItDoesNotExistWithName() { + @Test @Description("Register a controller with name which does not exist") @ExpectEvents({ + @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 2) }) public void findOrRegisterTargetIfItDoesNotExistWithName() { final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); assertThat(target).as("target should not be null").isNotNull(); - final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); + final Target sameTarget = controllerManagement + .findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); assertThat(target.getId()).as("Target should be the equals").isEqualTo(sameTarget.getId()); assertThat(target.getName()).as("Taget names should be equal").isEqualTo(sameTarget.getName()); 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() { + @Test @Description("Tries to register a target with an invalid controller id") public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionForInvalidControllerIdParam() { assertThatExceptionOfType(ConstraintViolationException.class) .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST)) .as("register target with null as controllerId should fail"); @@ -544,17 +513,15 @@ public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionForInvalidControl .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST)) .as("register target with empty controllerId should fail"); - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist( + assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> controllerManagement + .findOrRegisterTargetIfItDoesNotExist( RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST)) .as("register target with too long controllerId should fail"); } - @Test - @Description("Tries to register a target with an invalid controller id") - public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionForInvalidControllerIdParam() { - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST, "TestName")) + @Test @Description("Tries to register a target with an invalid controller id") public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionForInvalidControllerIdParam() { + assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy( + () -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST, "TestName")) .as("register target with null as controllerId should fail"); assertThatExceptionOfType(ConstraintViolationException.class) @@ -565,16 +532,14 @@ public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionForInvali .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST, "TestName")) .as("register target with empty controllerId should fail"); - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist( + assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> controllerManagement + .findOrRegisterTargetIfItDoesNotExist( RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST, "TestName")) .as("register target with too long controllerId should fail"); } - @Test - @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " - + "exception is rethrown after max retries") - public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionAfterMaxRetries() { + @Test @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " + + "exception is rethrown after max retries") public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionAfterMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); when(mockTargetRepository.findOne(any())).thenThrow(ConcurrencyFailureException.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -590,10 +555,8 @@ public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionAfterMaxRetries() } } - @Test - @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " - + "exception is rethrown after max retries") - public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionAfterMaxRetries() { + @Test @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " + + "exception is rethrown after max retries") public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionAfterMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); when(mockTargetRepository.findOne(any())).thenThrow(ConcurrencyFailureException.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -609,12 +572,10 @@ public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionAfterMaxR } } - @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)}) - public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRetries() { + @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) }) public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -636,12 +597,10 @@ public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRe } } - @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)}) - public void findOrRegisterTargetIfItDoesNotExistWithNameDoesNotThrowExceptionBeforeMaxRetries() { + @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) }) public void findOrRegisterTargetIfItDoesNotExistWithNameDoesNotThrowExceptionBeforeMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -663,10 +622,8 @@ public void findOrRegisterTargetIfItDoesNotExistWithNameDoesNotThrowExceptionBef } } - @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") - public void findOrRegisterTargetIfItDoesNotExistDoesntRetryWhenEntityAlreadyExistsException() { + @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") public void findOrRegisterTargetIfItDoesNotExistDoesntRetryWhenEntityAlreadyExistsException() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -686,10 +643,8 @@ public void findOrRegisterTargetIfItDoesNotExistDoesntRetryWhenEntityAlreadyExis } } - @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") - public void findOrRegisterTargetIfItDoesNotExistWithNameDoesntRetryWhenEntityAlreadyExistsException() { + @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") public void findOrRegisterTargetIfItDoesNotExistWithNameDoesntRetryWhenEntityAlreadyExistsException() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -709,10 +664,8 @@ public void findOrRegisterTargetIfItDoesNotExistWithNameDoesntRetryWhenEntityAlr } } - @Test - @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " - + "rethrown") - public void recoverFindOrRegisterTargetIfItDoesNotExistIsNotInvokedForOtherExceptions() { + @Test @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " + + "rethrown") public void recoverFindOrRegisterTargetIfItDoesNotExistIsNotInvokedForOtherExceptions() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -730,10 +683,8 @@ public void recoverFindOrRegisterTargetIfItDoesNotExistIsNotInvokedForOtherExcep } } - @Test - @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " - + "rethrown") - public void recoverFindOrRegisterTargetIfItDoesNotExistWithNameIsNotInvokedForOtherExceptions() { + @Test @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " + + "rethrown") public void recoverFindOrRegisterTargetIfItDoesNotExistWithNameIsNotInvokedForOtherExceptions() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -751,12 +702,10 @@ public void recoverFindOrRegisterTargetIfItDoesNotExistWithNameIsNotInvokedForOt } } - @Test - @Description("Verify that targetVisible metadata is returned from repository") - @ExpectEvents({@Expect(type = DistributionSetCreatedEvent.class, count = 1), + @Test @Description("Verify that targetVisible metadata is returned from repository") @ExpectEvents({ + @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = SoftwareModuleCreatedEvent.class, count = 3), - @Expect(type = SoftwareModuleUpdatedEvent.class, count = 6)}) - public void findTargetVisibleMetaDataBySoftwareModuleId() { + @Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) }) public void findTargetVisibleMetaDataBySoftwareModuleId() { final DistributionSet set = testdataFactory.createDistributionSet(); testdataFactory.addSoftwareModuleMetadata(set); @@ -768,35 +717,29 @@ public void findTargetVisibleMetaDataBySoftwareModuleId() { result.entrySet().forEach(entry -> assertThat(entry.getValue()).hasSize(1)); } - @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)}) - public void targetPollEventNotSendIfDisabled() { + @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) }) public void targetPollEventNotSendIfDisabled() { repositoryProperties.setPublishTargetPollEvent(false); controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); repositoryProperties.setPublishTargetPollEvent(true); } - @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)}) - public void targetPollEventNotSendIfDisabledWithName() { + @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) }) public void targetPollEventNotSendIfDisabledWithName() { repositoryProperties.setPublishTargetPollEvent(false); controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); repositoryProperties.setPublishTargetPollEvent(true); } - @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), + @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), @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)}) - public void tryToFinishWithErrorUpdateProcessMoreThanOnce() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void tryToFinishWithErrorUpdateProcessMoreThanOnce() { final Long actionId = createTargetAndAssignDs(); // test and verify @@ -834,16 +777,14 @@ public void tryToFinishWithErrorUpdateProcessMoreThanOnce() { } - @Test - @Description("Controller trys to finish an update process after it has been finished by an FINISHED action status.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Controller trys to finish an update process after it has been finished by an FINISHED action status.") @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)}) - public void tryToFinishUpdateProcessMoreThanOnce() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void tryToFinishUpdateProcessMoreThanOnce() { final Long actionId = prepareFinishedUpdate().getId(); // try with disabled late feedback @@ -870,17 +811,15 @@ public void tryToFinishUpdateProcessMoreThanOnce() { } - @Test - @Description("Controller trys 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), + @Test @Description( + "Controller trys 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), @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)}) - public void sendUpdatesForFinishUpdateProcessDropedIfDisabled() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void sendUpdatesForFinishUpdateProcessDropedIfDisabled() { repositoryProperties.setRejectActionStatusForClosedAction(true); final Action action = prepareFinishedUpdate(); @@ -897,17 +836,15 @@ public void sendUpdatesForFinishUpdateProcessDropedIfDisabled() { .isEqualTo(3); } - @Test - @Description("Controller trys 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), + @Test @Description( + "Controller trys 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), @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)}) - public void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { repositoryProperties.setRejectActionStatusForClosedAction(false); Action action = prepareFinishedUpdate(); @@ -924,11 +861,10 @@ public void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { .isEqualTo(4); } - @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)}) - public void updateTargetAttributes() throws Exception { + @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) }) public void updateTargetAttributes() + throws Exception { final String controllerId = "test123"; final Target target = testdataFactory.createTarget(controllerId); @@ -947,8 +883,7 @@ public void updateTargetAttributes() throws Exception { assertThat(targetVerify.getLastModifiedAt()).isEqualTo(target.getLastModifiedAt()); } - @Step - private void addAttributeAndVerify(final String controllerId) { + @Step private void addAttributeAndVerify(final String controllerId) { final Map testData = Maps.newHashMapWithExpectedSize(1); testData.put("test1", "testdata1"); controllerManagement.updateControllerAttributes(controllerId, testData, null); @@ -957,8 +892,7 @@ private void addAttributeAndVerify(final String controllerId) { .isEqualTo(testData); } - @Step - private void addSecondAttributeAndVerify(final String controllerId) { + @Step private void addSecondAttributeAndVerify(final String controllerId) { final Map testData = Maps.newHashMapWithExpectedSize(2); testData.put("test2", "testdata20"); controllerManagement.updateControllerAttributes(controllerId, testData, null); @@ -968,8 +902,7 @@ private void addSecondAttributeAndVerify(final String controllerId) { .isEqualTo(testData); } - @Step - private void updateAttributeAndVerify(final String controllerId) { + @Step private void updateAttributeAndVerify(final String controllerId) { final Map testData = Maps.newHashMapWithExpectedSize(2); testData.put("test1", "testdata12"); @@ -980,11 +913,9 @@ private void updateAttributeAndVerify(final String controllerId) { .isEqualTo(testData); } - @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)}) - public void updateTargetAttributesWithDifferentUpdateModes() { + @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) }) public void updateTargetAttributesWithDifferentUpdateModes() { final String controllerId = "testCtrl"; testdataFactory.createTarget(controllerId); @@ -1003,8 +934,7 @@ public void updateTargetAttributesWithDifferentUpdateModes() { } - @Step - private void updateTargetAttributesWithUpdateModeRemove(final String controllerId) { + @Step private void updateTargetAttributesWithUpdateModeRemove(final String controllerId) { final int previousSize = targetManagement.getControllerAttributes(controllerId).size(); @@ -1021,8 +951,7 @@ private void updateTargetAttributesWithUpdateModeRemove(final String controllerI } - @Step - private void updateTargetAttributesWithUpdateModeMerge(final String controllerId) { + @Step private void updateTargetAttributesWithUpdateModeMerge(final String controllerId) { // get the current attributes final HashMap attributes = new HashMap<>( targetManagement.getControllerAttributes(controllerId)); @@ -1041,8 +970,7 @@ private void updateTargetAttributesWithUpdateModeMerge(final String controllerId attributes.keySet().forEach(assertThat(updatedAttributes)::containsKey); } - @Step - private void updateTargetAttributesWithUpdateModeReplace(final String controllerId) { + @Step private void updateTargetAttributesWithUpdateModeReplace(final String controllerId) { // get the current attributes final HashMap attributes = new HashMap<>( @@ -1063,8 +991,7 @@ private void updateTargetAttributesWithUpdateModeReplace(final String controller attributes.entrySet().forEach(assertThat(updatedAttributes)::doesNotContain); } - @Step - private void updateTargetAttributesWithoutUpdateMode(final String controllerId) { + @Step private void updateTargetAttributesWithoutUpdateMode(final String controllerId) { // set the initial attributes final Map attributes = new HashMap<>(); @@ -1078,11 +1005,10 @@ private void updateTargetAttributesWithoutUpdateMode(final String controllerId) assertThat(updatedAttributes).containsAllEntriesOf(attributes); } - @Test - @Description("Ensures that target attribute update fails if quota hits.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 2)}) - public void updateTargetAttributesFailsIfTooManyEntries() throws Exception { + @Test @Description("Ensures that target attribute update fails if quota hits.") @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(); testdataFactory.createTarget(controllerId); @@ -1124,9 +1050,7 @@ private void writeAttributes(final String controllerId, final int allowedAttribu controllerManagement.updateControllerAttributes(controllerId, testData, null); } - @Test - @Description("Checks if invalid values of attribute-key and attribute-value are handled correctly") - public void updateTargetAttributesFailsForInvalidAttributes() { + @Test @Description("Checks if invalid values of attribute-key and attribute-value are handled correctly") public void updateTargetAttributesFailsForInvalidAttributes() { final String keyTooLong = generateRandomStringWithLength(Target.CONTROLLER_ATTRIBUTE_KEY_SIZE + 1); final String keyValid = generateRandomStringWithLength(Target.CONTROLLER_ATTRIBUTE_KEY_SIZE); final String valueTooLong = generateRandomStringWithLength(Target.CONTROLLER_ATTRIBUTE_VALUE_SIZE + 1); @@ -1136,35 +1060,29 @@ public void updateTargetAttributesFailsForInvalidAttributes() { final String controllerId = "targetId123"; testdataFactory.createTarget(controllerId); - assertThatExceptionOfType(InvalidTargetAttributeException.class) - .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, - Collections.singletonMap(keyTooLong, valueValid), null)) + assertThatExceptionOfType(InvalidTargetAttributeException.class).isThrownBy(() -> controllerManagement + .updateControllerAttributes(controllerId, Collections.singletonMap(keyTooLong, valueValid), null)) .as("Attribute with key too long should not be created"); - assertThatExceptionOfType(InvalidTargetAttributeException.class) - .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, - Collections.singletonMap(keyTooLong, valueTooLong), null)) + assertThatExceptionOfType(InvalidTargetAttributeException.class).isThrownBy(() -> controllerManagement + .updateControllerAttributes(controllerId, Collections.singletonMap(keyTooLong, valueTooLong), null)) .as("Attribute with key too long and value too long should not be created"); - assertThatExceptionOfType(InvalidTargetAttributeException.class) - .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, - Collections.singletonMap(keyValid, valueTooLong), null)) + assertThatExceptionOfType(InvalidTargetAttributeException.class).isThrownBy(() -> controllerManagement + .updateControllerAttributes(controllerId, Collections.singletonMap(keyValid, valueTooLong), null)) .as("Attribute with value too long should not be created"); - assertThatExceptionOfType(InvalidTargetAttributeException.class) - .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, - Collections.singletonMap(keyNull, valueValid), null)) + assertThatExceptionOfType(InvalidTargetAttributeException.class).isThrownBy(() -> controllerManagement + .updateControllerAttributes(controllerId, Collections.singletonMap(keyNull, valueValid), null)) .as("Attribute with key NULL should not be created"); } - @Test - @Description("Controller providing status entries fails if providing more than permitted by quota.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Controller providing status entries fails if providing more than permitted by quota.") @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)}) - public void controllerProvidesIntermediateFeedbackFailsIfQuotaHit() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerProvidesIntermediateFeedbackFailsIfQuotaHit() { final int allowStatusEntries = 10; final Long actionId = createTargetAndAssignDs(); @@ -1184,18 +1102,18 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { } } - @Test - @Description("Test to verify the storage and retrieval of action history.") - public void findMessagesByActionStatusId() { + @Test @Description("Test to verify the storage and retrieval of action history.") public void findMessagesByActionStatusId() { final DistributionSet testDs = testdataFactory.createDistributionSet("1"); final List testTarget = testdataFactory.createTargets(1); final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget)); - controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId) - .status(Action.Status.RUNNING).messages(Lists.newArrayList("proceeding message 1"))); - controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId) - .status(Action.Status.RUNNING).messages(Lists.newArrayList("proceeding message 2"))); + controllerManagement.addUpdateActionStatus( + entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING) + .messages(Lists.newArrayList("proceeding message 1"))); + controllerManagement.addUpdateActionStatus( + entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING) + .messages(Lists.newArrayList("proceeding message 2"))); final List messages = controllerManagement.getActionHistoryMessages(actionId, 2); @@ -1205,50 +1123,50 @@ public void findMessagesByActionStatusId() { assertThat(messages.get(1)).as("Message of action-status").isEqualTo("proceeding message 1"); } - @Test - @Description("Verifies that the quota specifying the maximum number of status entries per action is enforced.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 2), + @Test @Description("Verifies that the quota specifying the maximum number of status entries per action is enforced.") @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)}) - public void addActionStatusUpdatesUntilQuotaIsExceeded() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 6) }) public void addActionStatusUpdatesUntilQuotaIsExceeded() { // any distribution set assignment causes 1 status entity to be created final int maxStatusEntries = quotaManagement.getMaxStatusEntriesPerAction() - 1; // test for informational status - final Long actionId1 = getFirstAssignedActionId(assignDistributionSet( - testdataFactory.createDistributionSet("ds1"), testdataFactory.createTargets(1, "t1"))); + final Long actionId1 = getFirstAssignedActionId( + assignDistributionSet(testdataFactory.createDistributionSet("ds1"), + testdataFactory.createTargets(1, "t1"))); assertThat(actionId1).isNotNull(); for (int i = 0; i < maxStatusEntries; ++i) { - controllerManagement.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1) - .status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis())); + controllerManagement.addInformationalActionStatus( + entityFactory.actionStatus().create(actionId1).status(Status.WARNING).message("Msg " + i) + .occurredAt(System.currentTimeMillis())); } assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement .addInformationalActionStatus(entityFactory.actionStatus().create(actionId1).status(Status.WARNING))); // test for update status (and mixed case) - final Long actionId2 = getFirstAssignedActionId(assignDistributionSet( - testdataFactory.createDistributionSet("ds2"), testdataFactory.createTargets(1, "t2"))); + final Long actionId2 = getFirstAssignedActionId( + assignDistributionSet(testdataFactory.createDistributionSet("ds2"), + testdataFactory.createTargets(1, "t2"))); assertThat(actionId2).isNotEqualTo(actionId1); for (int i = 0; i < maxStatusEntries; ++i) { - controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId2) - .status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis())); + controllerManagement.addUpdateActionStatus( + entityFactory.actionStatus().create(actionId2).status(Status.WARNING).message("Msg " + i) + .occurredAt(System.currentTimeMillis())); } assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement .addInformationalActionStatus(entityFactory.actionStatus().create(actionId2).status(Status.WARNING))); } - @Test - @Description("Verifies that the quota specifying the maximum number of messages per action status is enforced.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Verifies that the quota specifying the maximum number of messages per action status is enforced.") @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)}) - public void createActionStatusWithTooManyMessages() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void createActionStatusWithTooManyMessages() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); @@ -1263,20 +1181,18 @@ public void createActionStatusWithTooManyMessages() { entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))).isNotNull(); messages.add("msg"); - assertThatExceptionOfType(QuotaExceededException.class) - .isThrownBy(() -> controllerManagement.addInformationalActionStatus( + assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement + .addInformationalActionStatus( entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))); } - @Test - @Description("Verifies that a DOWNLOAD_ONLY action is not marked complete when the controller reports DOWNLOAD") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Verifies that a DOWNLOAD_ONLY action is not marked complete when the controller reports DOWNLOAD") @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)}) - public void controllerReportsDownloadForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerReportsDownloadForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); assertThat(actionId).isNotNull(); @@ -1290,16 +1206,14 @@ public void controllerReportsDownloadForDownloadOnlyAction() { assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(true); } - @Test - @Description("Verifies that a DOWNLOAD_ONLY action is marked complete once the controller reports DOWNLOADED") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Verifies that a DOWNLOAD_ONLY action is marked complete once the controller reports DOWNLOADED") @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)}) - public void controllerReportsDownloadedForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerReportsDownloadedForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); assertThat(actionId).isNotNull(); @@ -1313,16 +1227,14 @@ public void controllerReportsDownloadedForDownloadOnlyAction() { assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); } - @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), + @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), @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)}) - public void controllerReportsActionFinishedForDownloadOnlyActionThatIsNotActive() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerReportsActionFinishedForDownloadOnlyActionThatIsNotActive() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); assertThat(actionId).isNotNull(); @@ -1336,16 +1248,14 @@ public void controllerReportsActionFinishedForDownloadOnlyActionThatIsNotActive( assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); } - @Test - @Description("Verifies that multiple DOWNLOADED events for a DOWNLOAD_ONLY action are handled.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Verifies that multiple DOWNLOADED events for a DOWNLOAD_ONLY action are handled.") @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)}) - public void controllerReportsMultipleDownloadedForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void controllerReportsMultipleDownloadedForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); assertThat(actionId).isNotNull(); @@ -1360,17 +1270,15 @@ public void controllerReportsMultipleDownloadedForDownloadOnlyAction() { assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); } - @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), + @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), @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)}) - public void quotaExceptionWhencontrollerReportsTooManyDownloadedMessagesForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void quotaExceptionWhencontrollerReportsTooManyDownloadedMessagesForDownloadOnlyAction() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); @@ -1380,16 +1288,14 @@ public void quotaExceptionWhencontrollerReportsTooManyDownloadedMessagesForDownl .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))); } - @Test - @Description("Verifies that quota is enforced for UpdateActionStatus events for DOWNLOAD_ONLY assignments.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Verifies that quota is enforced for UpdateActionStatus events for DOWNLOAD_ONLY assignments.") @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)}) - public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); @@ -1417,14 +1323,12 @@ public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusM } } - @Test - @Description("Verifies that quota is enforced for UpdateActionStatus events for FORCED assignments.") - @ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1), + @Test @Description("Verifies that quota is enforced for UpdateActionStatus events for FORCED assignments.") @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)}) - public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForForced() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForForced() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); final Long actionId = createTargetAndAssignDs(); assertThat(actionId).isNotNull(); @@ -1451,9 +1355,7 @@ public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusM } } - @Test - @Description("Verify that the attaching externalRef to an action is propery stored") - public void updatedExternalRefOnActionIsReallyUpdated() { + @Test @Description("Verify that the attaching externalRef to an action is propery stored") public void updatedExternalRefOnActionIsReallyUpdated() { final List allExternalRef = new ArrayList<>(); final List allActionId = new ArrayList<>(); final int numberOfActions = 3; @@ -1463,8 +1365,9 @@ public void updatedExternalRefOnActionIsReallyUpdated() { final String knownExternalref = "externalRefId" + i; testdataFactory.createTarget(knownControllerId); - final DistributionSetAssignmentResult assignmentResult = deploymentManagement.assignDistributionSet( - knownDistributionSet.getId(), ActionType.FORCED, 0, Collections.singleton(knownControllerId)); + final DistributionSetAssignmentResult assignmentResult = deploymentManagement + .assignDistributionSet(knownDistributionSet.getId(), ActionType.FORCED, 0, + Collections.singleton(knownControllerId)); final Long actionId = getFirstAssignedActionId(assignmentResult); controllerManagement.updateActionExternalRef(actionId, knownExternalref); @@ -1479,9 +1382,7 @@ public void updatedExternalRefOnActionIsReallyUpdated() { } } - @Test - @Description("Verify that a null externalRef cannot be assigned to an action") - public void externalRefCannotBeNull() { + @Test @Description("Verify that a null externalRef cannot be assigned to an action") public void externalRefCannotBeNull() { try { controllerManagement.updateActionExternalRef(1L, null); fail("No ConstraintViolationException thrown when a null externalRef was set on an action"); @@ -1489,17 +1390,16 @@ 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), + @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), @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)}) - public void targetCanAlwaysReportFinishedOrErrorAfterActionIsClosedForDownloadOnlyAssignments() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 12) }) public void targetCanAlwaysReportFinishedOrErrorAfterActionIsClosedForDownloadOnlyAssignments() { testdataFactory.createTarget(); @@ -1530,8 +1430,7 @@ public void targetCanAlwaysReportFinishedOrErrorAfterActionIsClosedForDownloadOn assertThat(actionStatusRepository.count()).isEqualTo(12L); } - @Step - private void finishDownloadOnlyUpdateAndSendUpdateActionStatus(final Long actionId, final Status status) { + @Step private void finishDownloadOnlyUpdateAndSendUpdateActionStatus(final Long actionId, final Status status) { // finishing action controllerManagement .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)); @@ -1540,17 +1439,14 @@ private void finishDownloadOnlyUpdateAndSendUpdateActionStatus(final Long action assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); } - @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), + @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), @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)}) - public void controllerReportsFinishedForOldDownloadOnlyActionAfterSuccessfulForcedAssignment() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 6) }) public void controllerReportsFinishedForOldDownloadOnlyActionAfterSuccessfulForcedAssignment() { testdataFactory.createTarget(); final DistributionSet downloadOnlyDs = testdataFactory.createDistributionSet("downloadOnlyDs1"); @@ -1578,8 +1474,8 @@ public void controllerReportsFinishedForOldDownloadOnlyActionAfterSuccessfulForc assertNoActiveActionsExistsForControllerId(DEFAULT_CONTROLLER_ID); } - @Step - private void addUpdateActionStatus(final Long actionId, final String controllerId, final Status actionStatus) { + @Step private void addUpdateActionStatus(final Long actionId, final String controllerId, + final Status actionStatus) { controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(actionStatus)); assertActionStatus(actionId, controllerId, TargetUpdateStatus.IN_SYNC, actionStatus, actionStatus, false); } 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 32a2b233c2..1b1e663c0e 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 @@ -122,52 +122,38 @@ public class TestdataFactory { */ public static final String SM_TYPE_APP = "application"; - @Autowired - private ControllerManagement controllerManagament; + @Autowired private ControllerManagement controllerManagament; - @Autowired - private SoftwareModuleManagement softwareModuleManagement; + @Autowired private SoftwareModuleManagement softwareModuleManagement; - @Autowired - private SoftwareModuleTypeManagement softwareModuleTypeManagement; + @Autowired private SoftwareModuleTypeManagement softwareModuleTypeManagement; - @Autowired - private DistributionSetManagement distributionSetManagement; + @Autowired private DistributionSetManagement distributionSetManagement; - @Autowired - private DistributionSetTypeManagement distributionSetTypeManagement; + @Autowired private DistributionSetTypeManagement distributionSetTypeManagement; - @Autowired - private TargetManagement targetManagement; + @Autowired private TargetManagement targetManagement; - @Autowired - private DeploymentManagement deploymentManagement; + @Autowired private DeploymentManagement deploymentManagement; - @Autowired - private TargetTagManagement targetTagManagement; + @Autowired private TargetTagManagement targetTagManagement; - @Autowired - private DistributionSetTagManagement distributionSetTagManagement; + @Autowired private DistributionSetTagManagement distributionSetTagManagement; - @Autowired - private EntityFactory entityFactory; + @Autowired private EntityFactory entityFactory; - @Autowired - private ArtifactManagement artifactManagement; + @Autowired private ArtifactManagement artifactManagement; - @Autowired - private RolloutManagement rolloutManagement; + @Autowired private RolloutManagement rolloutManagement; /** * 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 DistributionSet#isRequiredMigrationStep()} false. - * - * @param prefix - * for {@link SoftwareModule}s and {@link DistributionSet}s name, - * vendor and description. - * + * + * @param prefix for {@link SoftwareModule}s and {@link DistributionSet}s name, + * vendor and description. * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix) { @@ -179,7 +165,7 @@ public DistributionSet createDistributionSet(final String prefix) { * {@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() { @@ -191,10 +177,8 @@ public DistributionSet createDistributionSet() { * {@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 modules of {@link DistributionSet#getModules()} * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final Collection modules) { @@ -206,13 +190,10 @@ public DistributionSet createDistributionSet(final Collection mo * {@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. - * + * + * @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) { @@ -223,13 +204,10 @@ 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}. - * - * @param prefix - * for {@link SoftwareModule}s and {@link DistributionSet}s name, - * vendor and description. - * @param isRequiredMigrationStep - * for {@link DistributionSet#isRequiredMigrationStep()} - * + * + * @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) { @@ -241,13 +219,10 @@ public DistributionSet createDistributionSet(final String prefix, final boolean * {@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()} - * + * + * @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) { @@ -258,17 +233,13 @@ 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}. - * - * @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. - * @param isRequiredMigrationStep - * for {@link DistributionSet#isRequiredMigrationStep()} - * + * + * @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. + * @param isRequiredMigrationStep for {@link DistributionSet#isRequiredMigrationStep()} * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final String version, @@ -287,79 +258,71 @@ public DistributionSet createDistributionSet(final String prefix, final String v .name(prefix + " Firmware").version(version + "." + new SecureRandom().nextInt(100)) .description(LOREM.words(20)).vendor(prefix + " vendor Limited Inc, California")); - return distributionSetManagement.create( - entityFactory.distributionSet().create().name(prefix != null && prefix.length() > 0 ? prefix : "DS") - .version(version).description(LOREM.words(10)).type(findOrCreateDefaultTestDsType()) - .modules(Arrays.asList(osMod.getId(), runtimeMod.getId(), appMod.getId())) - .requiredMigrationStep(isRequiredMigrationStep)); + return distributionSetManagement.create(entityFactory.distributionSet().create() + .name(prefix != null && prefix.length() > 0 ? prefix : "DS").version(version) + .description(LOREM.words(10)).type(findOrCreateDefaultTestDsType()) + .modules(Arrays.asList(osMod.getId(), runtimeMod.getId(), appMod.getId())) + .requiredMigrationStep(isRequiredMigrationStep)); } /** * Adds {@link SoftwareModuleMetadata} to every module of given * {@link DistributionSet}. - * + *

* {@link #VISIBLE_SM_MD_VALUE}, {@link #VISIBLE_SM_MD_KEY} with * {@link SoftwareModuleMetadata#isTargetVisible()} and * {@link #INVISIBLE_SM_MD_KEY}, {@link #INVISIBLE_SM_MD_VALUE} without * {@link SoftwareModuleMetadata#isTargetVisible()} - * - * @param set - * to add metadata to + * + * @param set to add metadata to */ public void addSoftwareModuleMetadata(final DistributionSet set) { set.getModules().forEach(this::addTestModuleMetadata); } private void addTestModuleMetadata(final SoftwareModule module) { - softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(module.getId()) - .key(VISIBLE_SM_MD_KEY).value(VISIBLE_SM_MD_VALUE).targetVisible(true)); - softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(module.getId()) - .key(INVISIBLE_SM_MD_KEY).value(INVISIBLE_SM_MD_VALUE).targetVisible(false)); + softwareModuleManagement.createMetaData( + entityFactory.softwareModuleMetadata().create(module.getId()).key(VISIBLE_SM_MD_KEY) + .value(VISIBLE_SM_MD_VALUE).targetVisible(true)); + softwareModuleManagement.createMetaData( + entityFactory.softwareModuleMetadata().create(module.getId()).key(INVISIBLE_SM_MD_KEY) + .value(INVISIBLE_SM_MD_VALUE).targetVisible(false)); } /** * 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. - * @param isRequiredMigrationStep - * for {@link DistributionSet#isRequiredMigrationStep()} - * @param modules - * for {@link DistributionSet#getModules()} - * + * + * @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. + * @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, final boolean isRequiredMigrationStep, final Collection modules) { - return distributionSetManagement.create( - entityFactory.distributionSet().create().name(prefix != null && prefix.length() > 0 ? prefix : "DS") - .version(version).description(LOREM.words(10)).type(findOrCreateDefaultTestDsType()) - .modules(modules.stream().map(SoftwareModule::getId).collect(Collectors.toList())) - .requiredMigrationStep(isRequiredMigrationStep)); + return distributionSetManagement.create(entityFactory.distributionSet().create() + .name(prefix != null && prefix.length() > 0 ? prefix : "DS").version(version) + .description(LOREM.words(10)).type(findOrCreateDefaultTestDsType()) + .modules(modules.stream().map(SoftwareModule::getId).collect(Collectors.toList())) + .requiredMigrationStep(isRequiredMigrationStep)); } /** * Creates {@link DistributionSet} in repository including three * {@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.updat - * @param tags - * {@link DistributionSet#getTags()} - * + * + * @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.updat + * @param tags {@link DistributionSet#getTags()} * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final String version, @@ -379,10 +342,8 @@ public DistributionSet createDistributionSet(final String prefix, final String v * , {@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 - * + * + * @param number of {@link DistributionSet}s to create * @return {@link List} of {@link DistributionSet} entities */ public List createDistributionSets(final int number) { @@ -393,9 +354,8 @@ public List createDistributionSets(final int number) { /** * Create a list of {@link DistributionSet}s without modules, i.e. * incomplete. - * - * @param number - * of {@link DistributionSet}s to create + * + * @param number of {@link DistributionSet}s to create * @return {@link List} of {@link DistributionSet} entities */ public List createDistributionSetsWithoutModules(final int number) { @@ -416,13 +376,10 @@ public List createDistributionSetsWithoutModules(final int numb * , {@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 - * + * + * @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 +396,9 @@ 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()} - * + * + * @param name {@link DistributionSet#getName()} + * @param version {@link DistributionSet#getVersion()} * @return {@link DistributionSet} entity */ public DistributionSet createDistributionSetWithNoSoftwareModules(final String name, final String version) { @@ -456,10 +410,8 @@ public DistributionSet createDistributionSetWithNoSoftwareModules(final String n /** * Creates {@link Artifact}s for given {@link SoftwareModule} with a small * text payload. - * - * @param moduleId - * the {@link Artifact}s belong to. - * + * + * @param moduleId the {@link Artifact}s belong to. * @return {@link Artifact} entity. */ public List createArtifacts(final Long moduleId) { @@ -475,16 +427,10 @@ public List createArtifacts(final Long moduleId) { /** * 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 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) { @@ -497,33 +443,25 @@ public Artifact createArtifact(final String artifactData, final Long moduleId, f * 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 - * + * @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) { + 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)); + .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. - * - * @param typeKey - * of the {@link SoftwareModuleType} - * + * + * @param typeKey of the {@link SoftwareModuleType} * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModule(final String typeKey) { @@ -535,8 +473,7 @@ public SoftwareModule createSoftwareModule(final String typeKey) { * {@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() { @@ -548,11 +485,8 @@ public SoftwareModule createSoftwareModuleApp() { * {@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 - * - * + * + * @param prefix added to name and version * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModuleApp(final String prefix) { @@ -564,8 +498,7 @@ public SoftwareModule createSoftwareModuleApp(final String prefix) { * {@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() { @@ -577,11 +510,8 @@ public SoftwareModule createSoftwareModuleOs() { * {@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 - * - * + * + * @param prefix added to name and version * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModuleOs(final String prefix) { @@ -592,18 +522,16 @@ 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. - * - * @param typeKey - * of the {@link SoftwareModuleType} - * @param prefix - * added to name and version - * + * + * @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) { - return softwareModuleManagement.create(entityFactory.softwareModule().create() - .type(findOrCreateSoftwareModuleType(typeKey)).name(prefix + typeKey).version(prefix + DEFAULT_VERSION) - .description(LOREM.words(10)).vendor(DEFAULT_VENDOR)); + return softwareModuleManagement + .create(entityFactory.softwareModule().create().type(findOrCreateSoftwareModuleType(typeKey)) + .name(prefix + typeKey).version(prefix + DEFAULT_VERSION).description(LOREM.words(10)) + .vendor(DEFAULT_VENDOR)); } /** @@ -614,8 +542,7 @@ public Target createTarget() { } /** - * @param controllerId - * of the target + * @param controllerId of the target * @return persisted {@link Target} */ public Target createTarget(final String controllerId) { @@ -630,12 +557,12 @@ public Target createTarget(final String controllerId) { } /** - * @param targetName - * name of the target + * @param targetName name of the target * @return persisted {@link Target} */ public Target createTargetWithName(final String targetName) { - final Target target = targetManagement.create(entityFactory.target().create().controllerId(DEFAULT_CONTROLLER_ID).name(targetName)); + final Target target = targetManagement + .create(entityFactory.target().create().controllerId(DEFAULT_CONTROLLER_ID).name(targetName)); assertThat(target.getCreatedBy()).isNotNull(); assertThat(target.getCreatedAt()).isNotNull(); assertThat(target.getLastModifiedBy()).isNotNull(); @@ -651,21 +578,22 @@ public Target createTargetWithName(final String targetName) { * , {@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. - * + * * @return persisted {@link DistributionSet}. */ public DistributionSet createUpdatedDistributionSet() { DistributionSet set = createDistributionSet(""); - set = distributionSetManagement.update( - entityFactory.distributionSet().update(set.getId()).description("Updated " + DEFAULT_DESCRIPTION)); + set = distributionSetManagement.update(entityFactory.distributionSet().update(set.getId()) + .description("Updated " + DEFAULT_DESCRIPTION)); - set.getModules().forEach(module -> softwareModuleManagement.update( - entityFactory.softwareModule().update(module.getId()).description("Updated " + DEFAULT_DESCRIPTION))); + set.getModules().forEach(module -> softwareModuleManagement + .update(entityFactory.softwareModule().update(module.getId()) + .description("Updated " + DEFAULT_DESCRIPTION))); // load also lazy stuff return distributionSetManagement.getWithDetails(set.getId()).get(); @@ -673,8 +601,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<>(); @@ -690,40 +618,32 @@ public DistributionSetType findOrCreateDefaultTestDsType() { /** * Creates {@link DistributionSetType} in repository. - * - * @param dsTypeKey - * {@link DistributionSetType#getKey()} - * @param dsTypeName - * {@link DistributionSetType#getName()} - * + * + * @param dsTypeKey {@link DistributionSetType#getKey()} + * @param dsTypeName {@link DistributionSetType#getName()} * @return persisted {@link DistributionSetType} */ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName) { - return distributionSetTypeManagement.getByKey(dsTypeKey) - .orElseGet(() -> distributionSetTypeManagement.create(entityFactory.distributionSetType().create() - .key(dsTypeKey).name(dsTypeName).description(LOREM.words(10)).colour("black"))); + return distributionSetTypeManagement.getByKey(dsTypeKey).orElseGet(() -> distributionSetTypeManagement + .create(entityFactory.distributionSetType().create().key(dsTypeKey).name(dsTypeName) + .description(LOREM.words(10)).colour("black"))); } /** * 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 - * {@link DistributionSetType#getName()} - * @param mandatory - * {@link DistributionSetType#getMandatoryModuleTypes()} - * @param optional - * {@link DistributionSetType#getOptionalModuleTypes()} - * + * + * @param dsTypeKey {@link DistributionSetType#getKey()} + * @param dsTypeName {@link DistributionSetType#getName()} + * @param mandatory {@link DistributionSetType#getMandatoryModuleTypes()} + * @param optional {@link DistributionSetType#getOptionalModuleTypes()} * @return persisted {@link DistributionSetType} */ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName, final Collection mandatory, final Collection optional) { - return distributionSetTypeManagement.getByKey(dsTypeKey) - .orElseGet(() -> distributionSetTypeManagement.create(entityFactory.distributionSetType().create() - .key(dsTypeKey).name(dsTypeName).description(LOREM.words(10)).colour("black") + return distributionSetTypeManagement.getByKey(dsTypeKey).orElseGet(() -> distributionSetTypeManagement + .create(entityFactory.distributionSetType().create().key(dsTypeKey).name(dsTypeName) + .description(LOREM.words(10)).colour("black") .optional(optional.stream().map(SoftwareModuleType::getId).collect(Collectors.toList())) .mandatory(mandatory.stream().map(SoftwareModuleType::getId).collect(Collectors.toList())))); } @@ -732,10 +652,8 @@ 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. - * - * @param key - * {@link SoftwareModuleType#getKey()} - * + * + * @param key {@link SoftwareModuleType#getKey()} * @return persisted {@link SoftwareModuleType} */ public SoftwareModuleType findOrCreateSoftwareModuleType(final String key) { @@ -745,55 +663,41 @@ 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()} - * + * + * @param key {@link SoftwareModuleType#getKey()} + * @param maxAssignments {@link SoftwareModuleType#getMaxAssignments()} * @return persisted {@link SoftwareModuleType} */ public SoftwareModuleType findOrCreateSoftwareModuleType(final String key, final int maxAssignments) { - return softwareModuleTypeManagement.getByKey(key) - .orElseGet(() -> softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create() - .key(key).name(key).description(LOREM.words(10)).maxAssignments(maxAssignments))); + return softwareModuleTypeManagement.getByKey(key).orElseGet(() -> softwareModuleTypeManagement + .create(entityFactory.softwareModuleType().create().key(key).name(key).description(LOREM.words(10)) + .maxAssignments(maxAssignments))); } /** * Creates a {@link DistributionSet}. * - * @param name - * {@link DistributionSet#getName()} - * @param version - * {@link DistributionSet#getVersion()} - * @param type - * {@link DistributionSet#getType()} - * @param modules - * {@link DistributionSet#getModules()} - * + * @param name {@link DistributionSet#getName()} + * @param version {@link DistributionSet#getVersion()} + * @param type {@link DistributionSet#getType()} + * @param modules {@link DistributionSet#getModules()} * @return the created {@link DistributionSet} */ public DistributionSet createDistributionSet(final String name, final String version, final DistributionSetType type, final Collection modules) { - return distributionSetManagement.create( - entityFactory.distributionSet().create().name(name).version(version).description(LOREM.words(10)) - .type(type).modules(modules.stream().map(SoftwareModule::getId).collect(Collectors.toList()))); + return distributionSetManagement.create(entityFactory.distributionSet().create().name(name).version(version) + .description(LOREM.words(10)).type(type) + .modules(modules.stream().map(SoftwareModule::getId).collect(Collectors.toList()))); } /** * Generates {@link DistributionSet} object without persisting it. * - * @param name - * {@link DistributionSet#getName()} - * @param version - * {@link DistributionSet#getVersion()} - * @param type - * {@link DistributionSet#getType()} - * @param modules - * {@link DistributionSet#getModules()} - * @param requiredMigrationStep - * {@link DistributionSet#isRequiredMigrationStep()} - * + * @param name {@link DistributionSet#getName()} + * @param version {@link DistributionSet#getVersion()} + * @param type {@link DistributionSet#getType()} + * @param modules {@link DistributionSet#getModules()} + * @param requiredMigrationStep {@link DistributionSet#isRequiredMigrationStep()} * @return the created {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name, final String version, @@ -807,15 +711,10 @@ public DistributionSet generateDistributionSet(final String name, final String v /** * Generates {@link DistributionSet} object without persisting it. * - * @param name - * {@link DistributionSet#getName()} - * @param version - * {@link DistributionSet#getVersion()} - * @param type - * {@link DistributionSet#getType()} - * @param modules - * {@link DistributionSet#getModules()} - * + * @param name {@link DistributionSet#getName()} + * @param version {@link DistributionSet#getVersion()} + * @param type {@link DistributionSet#getType()} + * @param modules {@link DistributionSet#getModules()} * @return the created {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name, final String version, @@ -826,9 +725,7 @@ public DistributionSet generateDistributionSet(final String name, final String v /** * builder method for generating a {@link DistributionSet}. * - * @param name - * {@link DistributionSet#getName()} - * + * @param name {@link DistributionSet#getName()} * @return the generated {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name) { @@ -840,10 +737,8 @@ public DistributionSet generateDistributionSet(final String name) { * 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 - * + * + * @param number of {@link Target}s to create * @return {@link List} of {@link Target} entities */ public List createTargets(final int number) { @@ -859,13 +754,10 @@ 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 - * of {@link Target}s to generate - * @param controllerIdPrefix - * for {@link Target#getControllerId()} generation. + * + * @param start value for the controllerId suffix + * @param numberOfTargets of {@link Target}s to generate + * @param controllerIdPrefix for {@link Target#getControllerId()} generation. * @return list of {@link Target} objects */ private List generateTargets(final int start, final int numberOfTargets, final String controllerIdPrefix) { @@ -881,11 +773,9 @@ 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. - * - * @param numberOfTargets - * of {@link Target}s to generate - * @param controllerIdPrefix - * for {@link Target#getControllerId()} generation. + * + * @param numberOfTargets of {@link Target}s to generate + * @param controllerIdPrefix for {@link Target#getControllerId()} generation. * @return list of {@link Target} objects */ public List generateTargets(final int numberOfTargets, final String controllerIdPrefix) { @@ -895,10 +785,8 @@ public List generateTargets(final int numberOfTargets, final String cont /** * builds a set of {@link Target} fixtures from the given parameters. * - * @param numberOfTargets - * number of targets to create - * @param prefix - * prefix used for the controller ID and description + * @param numberOfTargets number of targets to create + * @param prefix prefix used for the controller ID and description * @return set of {@link Target} */ public List createTargets(final int numberOfTargets, final String prefix) { @@ -908,43 +796,33 @@ public List createTargets(final int numberOfTargets, final String prefix /** * builds a set of {@link Target} fixtures from the given parameters. * - * @param numberOfTargets - * number of targets to create - * @param controllerIdPrefix - * prefix used for the controller ID - * @param descriptionPrefix - * prefix used for the description + * @param numberOfTargets number of targets to create + * @param controllerIdPrefix prefix used for the controller ID + * @param descriptionPrefix prefix used for the description * @return set of {@link Target} */ public List createTargets(final int numberOfTargets, final String controllerIdPrefix, final String descriptionPrefix) { - return targetManagement.create(IntStream.range(0, numberOfTargets) - .mapToObj(i -> entityFactory.target().create() - .controllerId(String.format("%s-%05d", controllerIdPrefix, i)) - .description(descriptionPrefix + i)) - .collect(Collectors.toList())); + return targetManagement.create(IntStream.range(0, numberOfTargets).mapToObj( + i -> entityFactory.target().create().controllerId(String.format("%s-%05d", controllerIdPrefix, i)) + .description(descriptionPrefix + i)).collect(Collectors.toList())); } /** * builds a set of {@link Target} fixtures from the given parameters. * - * @param numberOfTargets - * number of targets to create - * @param controllerIdPrefix - * prefix used for the controller ID - * @param descriptionPrefix - * prefix used for the description - * @param lastTargetQuery - * last time the target polled + * @param numberOfTargets number of targets to create + * @param controllerIdPrefix prefix used for the controller ID + * @param descriptionPrefix prefix used for the description + * @param lastTargetQuery last time the target polled * @return set of {@link Target} */ public List createTargets(final int numberOfTargets, final String controllerIdPrefix, final String descriptionPrefix, final Long lastTargetQuery) { - return targetManagement.create(IntStream.range(0, numberOfTargets) - .mapToObj(i -> entityFactory.target().create() - .controllerId(String.format("%s-%05d", controllerIdPrefix, i)) + return targetManagement.create(IntStream.range(0, numberOfTargets).mapToObj( + i -> entityFactory.target().create().controllerId(String.format("%s-%05d", controllerIdPrefix, i)) .description(descriptionPrefix + i).lastTargetQuery(lastTargetQuery)) .collect(Collectors.toList())); } @@ -952,10 +830,8 @@ public List createTargets(final int numberOfTargets, final String contro /** * Create a set of {@link TargetTag}s. * - * @param number - * number of {@link TargetTag}. to be created - * @param tagPrefix - * prefix for the {@link TargetTag#getName()} + * @param number number of {@link TargetTag}. to be created + * @param tagPrefix prefix for the {@link TargetTag#getName()} * @return the created set of {@link TargetTag}s */ public List createTargetTags(final int number, final String tagPrefix) { @@ -971,10 +847,8 @@ public List createTargetTags(final int number, final String tagPrefix /** * Creates {@link DistributionSetTag}s in repository. - * - * @param number - * of {@link DistributionSetTag}s - * + * + * @param number of {@link DistributionSetTag}s * @return the persisted {@link DistributionSetTag}s */ public List createDistributionSetTags(final int number) { @@ -998,14 +872,10 @@ private Action sendUpdateActionStatusToTarget(final Status status, final Action /** * 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 - * + * + * @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, @@ -1016,14 +886,10 @@ public List sendUpdateActionStatusToTargets(final Collection tar /** * 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 - * + * + * @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, @@ -1041,48 +907,34 @@ public List sendUpdateActionStatusToTargets(final Collection tar /** * Creates rollout based on given parameters. - * - * @param rolloutName - * of the {@link Rollout} - * @param rolloutDescription - * of the {@link Rollout} - * @param groupSize - * of the {@link Rollout} - * @param filterQuery - * to identify the {@link Target}s - * @param distributionSet - * to assign - * @param successCondition - * to switch to next group - * @param errorCondition - * to switch to next group + * + * @param rolloutName of the {@link Rollout} + * @param rolloutDescription of the {@link Rollout} + * @param groupSize of the {@link Rollout} + * @param filterQuery to identify the {@link Target}s + * @param distributionSet to assign + * @param successCondition to switch to next group + * @param errorCondition to switch to next group * @return created {@link Rollout} */ 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); } /** * Creates rollout based on given parameters. * - * @param rolloutName - * of the {@link Rollout} - * @param rolloutDescription - * of the {@link Rollout} - * @param groupSize - * of the {@link Rollout} - * @param filterQuery - * to identify the {@link Target}s - * @param distributionSet - * to assign - * @param successCondition - * to switch to next group - * @param errorCondition - * to switch to next group - * @param actionType - * the type of the Rollout + * @param rolloutName of the {@link Rollout} + * @param rolloutDescription of the {@link Rollout} + * @param groupSize of the {@link Rollout} + * @param filterQuery to identify the {@link Target}s + * @param distributionSet to assign + * @param successCondition to switch to next group + * @param errorCondition to switch to next group + * @param actionType the type of the Rollout * @return created {@link Rollout} */ public Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, @@ -1093,9 +945,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(); @@ -1106,10 +959,9 @@ 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 + * + * @param prefix for rollouts name, description, + * {@link Target#getControllerId()} filter * @return created {@link Rollout} */ public Rollout createRollout(final String prefix) { @@ -1121,10 +973,9 @@ public Rollout createRollout(final String prefix) { /** * 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 + * + * @param prefix for rollouts name, description, + * {@link Target#getControllerId()} filter * @return created {@link Rollout} */ public Rollout createSoftDeletedRollout(final String prefix) { From a843035585b760f5698e368cd8c3b9058937d357 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Thu, 19 Sep 2019 15:48:18 +0200 Subject: [PATCH 08/22] Reformat after finding the real format bug regarding THING_CREATED Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 97 +-- .../amqp/AmqpMessageHandlerServiceTest.java | 193 +++--- .../dmf/json/model/DmfAttributeUpdate.java | 13 +- .../dmf/json/model/DmfTargetProperties.java | 7 +- .../repository/ControllerManagement.java | 253 ++++---- .../jpa/JpaControllerManagement.java | 282 ++++---- .../jpa/ControllerManagementTest.java | 546 +++++++++------- .../repository/test/util/TestdataFactory.java | 614 ++++++++++-------- 8 files changed, 1172 insertions(+), 833 deletions(-) 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 209c55e8a1..ba7811dcdc 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 @@ -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 @@ -84,12 +84,18 @@ public class AmqpMessageHandlerService extends BaseAmqpService { /** * Constructor. * - * @param rabbitTemplate for converting messages - * @param amqpMessageDispatcherService to sending events to DMF client - * @param controllerManagement for target repo access - * @param entityFactory to create entities - * @param systemSecurityContext the system Security Context - * @param tenantConfigurationManagement the tenant configuration Management + * @param rabbitTemplate + * for converting messages + * @param amqpMessageDispatcherService + * to sending events to DMF client + * @param controllerManagement + * for target repo access + * @param entityFactory + * to create entities + * @param systemSecurityContext + * the system Security Context + * @param tenantConfigurationManagement + * the tenant configuration Management */ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate, final AmqpMessageDispatcherService amqpMessageDispatcherService, @@ -107,13 +113,17 @@ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate, /** * Method to handle all incoming DMF amqp messages. * - * @param message incoming message - * @param type the message type - * @param tenant the contentType of the message + * @param message + * incoming message + * @param type + * 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") public Message onMessage( - final Message message, @Header(name = MessageHeaderKey.TYPE, required = false) final String type, + @RabbitListener(queues = "${hawkbit.dmf.rabbitmq.receiverQueue:dmf_receiver}", containerFactory = "listenerContainerFactory") + public Message onMessage(final Message message, + @Header(name = MessageHeaderKey.TYPE, required = false) final String type, @Header(name = MessageHeaderKey.TENANT, required = false) final String tenant) { return onMessage(message, type, tenant, getRabbitTemplate().getConnectionFactory().getVirtualHost()); } @@ -121,10 +131,14 @@ public AmqpMessageHandlerService(final RabbitTemplate rabbitTemplate, /** * * Executed if a amqp message arrives. * - * @param message the message - * @param type the type - * @param tenant the tenant - * @param virtualHost the virtual host + * @param message + * the message + * @param type + * the type + * @param tenant + * the tenant + * @param virtualHost + * the virtual host * @return the rpc message back to supplier. */ public Message onMessage(final Message message, final String type, final String tenant, final String virtualHost) { @@ -177,7 +191,8 @@ private static void setTenantSecurityContext(final String tenantId) { /** * Method to register a new target. * - * @param message the message that contains the target/thing + * @param message + * the message that contains the target/thing * @param virtualHost */ private void registerTarget(final Message message, final String virtualHost) { @@ -201,10 +216,13 @@ private void registerTarget(final Message message, final String virtualHost) { /** * Method to register a new target. * - * @param message the message that contains the target/thing - * @param virtualHost the virtualHost of the target/thing - * @param name the name of the target/thing, can be null and would then be - * replaced by targetId + * @param message + * the message that contains the target/thing + * @param virtualHost + * the virtualHost of the target/thing + * @param name + * the name of the target/thing, can be null and would then be + * replaced by targetId */ private void registerTarget(final Message message, final String virtualHost, final String name) { final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); @@ -255,9 +273,8 @@ private void sendOldestActionToTarget(final Target target) { final Action action = actionOptional.get(); if (action.isCancelingOrCanceled()) { - amqpMessageDispatcherService - .sendCancelMessageToTarget(target.getTenant(), target.getControllerId(), action.getId(), - target.getAddress()); + amqpMessageDispatcherService.sendCancelMessageToTarget(target.getTenant(), target.getControllerId(), + action.getId(), target.getAddress()); } else { amqpMessageDispatcherService.sendUpdateMessageToTarget(new ActionProperties(action), action.getTarget(), getSoftwareModulesWithMetadata(action.getDistributionSet())); @@ -280,8 +297,10 @@ private Map> getSoftwareModulesWith /** * Method to handle the different topics to an event. * - * @param message the incoming event message. - * @param topic the topic of the event. + * @param message + * the incoming event message. + * @param topic + * the topic of the event. */ private void handleIncomingEvent(final Message message) { switch (EventTopic.valueOf(getStringHeaderKey(message, MessageHeaderKey.TOPIC, "EventTopic is null"))) { @@ -307,14 +326,15 @@ private void updateAttributes(final Message message) { controllerManagement.updateControllerName(thingId, attributeUpdate.getName()); } - controllerManagement - .updateControllerAttributes(thingId, attributeUpdate.getAttributes(), getUpdateMode(attributeUpdate)); + controllerManagement.updateControllerAttributes(thingId, attributeUpdate.getAttributes(), + getUpdateMode(attributeUpdate)); } /** * Method to update the action status of an action through the event. * - * @param actionUpdateStatus the object form the ampq message + * @param actionUpdateStatus + * the object form the ampq message */ private void updateActionStatus(final Message message) { final DmfActionUpdateStatus actionUpdateStatus = convertMessage(message, DmfActionUpdateStatus.class); @@ -323,17 +343,17 @@ private void updateActionStatus(final Message message) { final List messages = actionUpdateStatus.getMessage(); if (isCorrelationIdNotEmpty(message)) { - messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "DMF message correlation-id " + message - .getMessageProperties().getCorrelationId()); + messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "DMF message correlation-id " + + message.getMessageProperties().getCorrelationId()); } final Status status = mapStatus(message, actionUpdateStatus, action); final ActionStatusCreate actionStatus = entityFactory.actionStatus().create(action.getId()).status(status) .messages(messages); - final Action updatedAction = (Status.CANCELED == status) ? - controllerManagement.addCancelActionStatus(actionStatus) : - controllerManagement.addUpdateActionStatus(actionStatus); + final Action updatedAction = (Status.CANCELED == status) + ? controllerManagement.addCancelActionStatus(actionStatus) + : controllerManagement.addUpdateActionStatus(actionStatus); if (shouldTargetProceed(updatedAction)) { sendUpdateCommandToTarget(action.getTarget()); @@ -350,8 +370,9 @@ private static boolean isCorrelationIdNotEmpty(final Message message) { // Exception squid:MethodCyclomaticComplexity - false positive, is a simple // mapping - @SuppressWarnings("squid:MethodCyclomaticComplexity") private static Status mapStatus(final Message message, - final DmfActionUpdateStatus actionUpdateStatus, final Action action) { + @SuppressWarnings("squid:MethodCyclomaticComplexity") + private static Status mapStatus(final Message message, final DmfActionUpdateStatus actionUpdateStatus, + final Action action) { Status status = null; switch (actionUpdateStatus.getActionStatus()) { case DOWNLOAD: @@ -399,8 +420,8 @@ private static Status handleCancelRejectedState(final Message message, final Act // Exception squid:S3655 - logAndThrowMessageError throws exception, i.e. // get will not be called - @SuppressWarnings("squid:S3655") private Action checkActionExist(final Message message, - final DmfActionUpdateStatus actionUpdateStatus) { + @SuppressWarnings("squid:S3655") + private Action checkActionExist(final Message message, final DmfActionUpdateStatus actionUpdateStatus) { final Long actionId = actionUpdateStatus.getActionId(); LOG.debug("Target notifies intermediate about action {} with status {}.", actionId, 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 2154689b9b..3c4c85ce76 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 @@ -78,7 +78,10 @@ import io.qameta.allure.Feature; import io.qameta.allure.Story; -@RunWith(MockitoJUnitRunner.class) @Feature("Component Tests - Device Management Federation API") @Story("AmqpMessage Handler Service Test") public class AmqpMessageHandlerServiceTest { +@RunWith(MockitoJUnitRunner.class) +@Feature("Component Tests - Device Management Federation API") +@Story("AmqpMessage Handler Service Test") +public class AmqpMessageHandlerServiceTest { private static final String SHA1 = "12345"; private static final String TENANT = "DEFAULT"; @@ -91,37 +94,54 @@ private MessageConverter messageConverter; - @Mock private AmqpMessageDispatcherService amqpMessageDispatcherServiceMock; + @Mock + private AmqpMessageDispatcherService amqpMessageDispatcherServiceMock; - @Mock private ControllerManagement controllerManagementMock; + @Mock + private ControllerManagement controllerManagementMock; - @Mock private EntityFactory entityFactoryMock; + @Mock + private EntityFactory entityFactoryMock; - @Mock private ArtifactManagement artifactManagementMock; + @Mock + private ArtifactManagement artifactManagementMock; - @Mock private TenantConfigurationManagement tenantConfigurationManagement; + @Mock + private TenantConfigurationManagement tenantConfigurationManagement; - @Mock private AmqpControllerAuthentication authenticationManagerMock; + @Mock + private AmqpControllerAuthentication authenticationManagerMock; - @Mock private ArtifactRepository artifactRepositoryMock; + @Mock + private ArtifactRepository artifactRepositoryMock; - @Mock private DownloadIdCache downloadIdCache; + @Mock + private DownloadIdCache downloadIdCache; - @Mock private HostnameResolver hostnameResolverMock; + @Mock + private HostnameResolver hostnameResolverMock; - @Mock private RabbitTemplate rabbitTemplate; + @Mock + private RabbitTemplate rabbitTemplate; - @Mock private TenantAware tenantAwareMock; + @Mock + private TenantAware tenantAwareMock; - @Captor private ArgumentCaptor> attributesCaptor; + @Captor + private ArgumentCaptor> attributesCaptor; - @Captor private ArgumentCaptor targetIdCaptor; + @Captor + private ArgumentCaptor targetIdCaptor; - @Captor private ArgumentCaptor modeCaptor; + @Captor + private ArgumentCaptor modeCaptor; - @Captor private ArgumentCaptor targetNameCaptor; + @Captor + private ArgumentCaptor targetNameCaptor; - @Before @SuppressWarnings({ "rawtypes", "unchecked" }) public void before() throws Exception { + @Before + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void before() throws Exception { messageConverter = new Jackson2JsonMessageConverter(); when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter); when(artifactManagementMock.findFirstBySHA1(SHA1)).thenReturn(Optional.empty()); @@ -140,7 +160,9 @@ controllerManagementMock, tenantAwareMock); } - @Test @Description("Tests not allowed content-type in message") public void wrongContentType() { + @Test + @Description("Tests not allowed content-type in message") + public void wrongContentType() { final MessageProperties messageProperties = new MessageProperties(); messageProperties.setContentType("xml"); final Message message = new Message(new byte[0], messageProperties); @@ -151,7 +173,9 @@ } } - @Test @Description("Tests the creation of a target/thing by calling the same method that incoming RabbitMQ messages would access.") public void createThing() { + @Test + @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"); @@ -161,9 +185,8 @@ final ArgumentCaptor targetIdCaptor = ArgumentCaptor.forClass(String.class); final ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); - when(controllerManagementMock - .findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), uriCaptor.capture())) - .thenReturn(targetMock); + when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), + uriCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); @@ -174,7 +197,9 @@ } - @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() { + @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 MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -189,9 +214,8 @@ final ArgumentCaptor 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.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), + uriCaptor.capture(), targetNameCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); @@ -201,7 +225,9 @@ assertThat(targetNameCaptor.getValue()).as("Thing name is not right").isEqualTo(targetProperties.getName()); } - @Test @Description("Tests the creation of a target/thing without name but with body by calling the same method that incoming RabbitMQ messages would access.") public void createThingWithBodyWithoutName() { + @Test + @Description("Tests the creation of a target/thing without name but with body by calling the same method that incoming RabbitMQ messages would access.") + public void createThingWithBodyWithoutName() { final String knownThingId = "3"; final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -210,16 +236,15 @@ // should still be default (=targetId) attributeUpdate.getAttributes().put("name", "testValue1"); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(attributeUpdate, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, + messageProperties); final Target targetMock = mock(Target.class); final ArgumentCaptor targetIdCaptor = ArgumentCaptor.forClass(String.class); final ArgumentCaptor uriCaptor = ArgumentCaptor.forClass(URI.class); - when(controllerManagementMock - .findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), uriCaptor.capture())) - .thenReturn(targetMock); + when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), + uriCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); @@ -228,7 +253,9 @@ assertThat(uriCaptor.getValue().toString()).as("Uri is not right").isEqualTo("amqp://vHost/MyTest"); } - @Test @Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.") public void updateAttributes() { + @Test + @Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.") + public void updateAttributes() { final String knownThingId = "1"; final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -237,12 +264,11 @@ attributeUpdate.getAttributes().put("testKey1", "testValue1"); attributeUpdate.getAttributes().put("testKey2", "testValue2"); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(attributeUpdate, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, + messageProperties); - when(controllerManagementMock - .updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), modeCaptor.capture())) - .thenReturn(null); + when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), + modeCaptor.capture())).thenReturn(null); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); @@ -253,7 +279,9 @@ } - @Test @Description("Tests the target attribute update with name update by calling the same method that incoming RabbitMQ messages would access.") public void updateAttributesWithName() { + @Test + @Description("Tests the target attribute update with name update by calling the same method that incoming RabbitMQ messages would access.") + public void updateAttributesWithName() { final String knownThingId = "1"; final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -263,14 +291,13 @@ attributeUpdate.getAttributes().put("testKey2", "testValue2"); attributeUpdate.setName("UpdatedTargetName"); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(attributeUpdate, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, + messageProperties); final ArgumentCaptor targetNameCaptor = ArgumentCaptor.forClass(String.class); - when(controllerManagementMock - .updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), modeCaptor.capture())) - .thenReturn(null); + when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), + modeCaptor.capture())).thenReturn(null); when(controllerManagementMock.updateControllerName(targetIdCaptor.capture(), targetNameCaptor.capture())) .thenReturn(null); @@ -284,7 +311,9 @@ } - @Test @Description("Verifies that the update mode is retrieved from the UPDATE_ATTRIBUTES message and passed to the controller management.") public void attributeUpdateModes() { + @Test + @Description("Verifies that the update mode is retrieved from the UPDATE_ATTRIBUTES message and passed to the controller management.") + public void attributeUpdateModes() { final String knownThingId = "1"; final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); @@ -293,9 +322,8 @@ attributeUpdate.getAttributes().put("testKey1", "testValue1"); attributeUpdate.getAttributes().put("testKey2", "testValue2"); - when(controllerManagementMock - .updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), modeCaptor.capture())) - .thenReturn(null); + when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), + modeCaptor.capture())).thenReturn(null); // send a message which does not specify a update mode Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, messageProperties); @@ -327,7 +355,9 @@ } - @Test @Description("Tests the creation of a thing without a 'reply to' header in message.") public void createThingWitoutReplyTo() { + @Test + @Description("Tests the creation of a thing without a 'reply to' header in message.") + public void createThingWitoutReplyTo() { final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED, null); messageProperties.setHeader(MessageHeaderKey.THING_ID, "1"); final Message message = messageConverter.toMessage("", messageProperties); @@ -341,7 +371,9 @@ } - @Test @Description("Tests the creation of a target/thing without a thingID by calling the same method that incoming RabbitMQ messages would access.") public void createThingWithoutID() { + @Test + @Description("Tests the creation of a target/thing without a thingID by calling the same method that incoming RabbitMQ messages would access.") + public void createThingWithoutID() { final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); final Message message = messageConverter.toMessage(new byte[0], messageProperties); try { @@ -352,7 +384,9 @@ } } - @Test @Description("Tests the call of the same method that incoming RabbitMQ messages would access with an unknown message type.") public void unknownMessageType() { + @Test + @Description("Tests the call of the same method that incoming RabbitMQ messages would access with an unknown message type.") + public void unknownMessageType() { final String type = "bumlux"; final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); messageProperties.setHeader(MessageHeaderKey.THING_ID, ""); @@ -366,7 +400,9 @@ } } - @Test @Description("Tests a invalid message without event topic") public void invalidEventTopic() { + @Test + @Description("Tests a invalid message without event topic") + public void invalidEventTopic() { final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); final Message message = new Message(new byte[0], messageProperties); try { @@ -392,13 +428,15 @@ } - @Test @Description("Tests the update of an action of a target without a exist action id") public void updateActionStatusWithoutActionId() { + @Test + @Description("Tests the update of an action of a target without a exist action id") + public void updateActionStatusWithoutActionId() { when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.empty()); final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); final DmfActionUpdateStatus actionUpdateStatus = new DmfActionUpdateStatus(1L, DmfActionStatus.DOWNLOAD); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(actionUpdateStatus, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, + messageProperties); try { amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); @@ -408,14 +446,16 @@ } } - @Test @Description("Tests the update of an action of a target without a exist action id") public void updateActionStatusWithoutExistActionId() { + @Test + @Description("Tests the update of an action of a target without a exist action id") + public void updateActionStatusWithoutExistActionId() { final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.empty()); final DmfActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(DmfActionStatus.DOWNLOAD); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(actionUpdateStatus, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, + messageProperties); try { amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); @@ -426,12 +466,14 @@ } - @Test @Description("Tests that an download request is denied for an artifact which does not exists") public void authenticationRequestDeniedForArtifactWhichDoesNotExists() { + @Test + @Description("Tests that an download request is denied for an artifact which does not exists") + public void authenticationRequestDeniedForArtifactWhichDoesNotExists() { final MessageProperties messageProperties = createMessageProperties(null); final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, FileResource.createFileResourceBySha1("12345")); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(securityToken, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, + messageProperties); // test final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message); @@ -443,12 +485,14 @@ .isEqualTo(HttpStatus.NOT_FOUND.value()); } - @Test @Description("Tests that an download request is denied for an artifact which is not assigned to the requested target") public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() { + @Test + @Description("Tests that an download request is denied for an artifact which is not assigned to the requested target") + public void authenticationRequestDeniedForArtifactWhichIsNotAssignedToTarget() { final MessageProperties messageProperties = createMessageProperties(null); final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, FileResource.createFileResourceBySha1("12345")); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(securityToken, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, + messageProperties); final Artifact localArtifactMock = mock(Artifact.class); when(artifactManagementMock.findFirstBySHA1(anyString())).thenReturn(Optional.of(localArtifactMock)); @@ -463,13 +507,14 @@ .isEqualTo(HttpStatus.NOT_FOUND.value()); } - @Test @Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target") public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() - throws MalformedURLException { + @Test + @Description("Tests that an download request is allowed for an artifact which exists and assigned to the requested target") + public void authenticationRequestAllowedForArtifactWhichExistsAndAssignedToTarget() throws MalformedURLException { final MessageProperties messageProperties = createMessageProperties(null); final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLLER_ID, TARGET_ID, FileResource.createFileResourceBySha1("12345")); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(securityToken, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, + messageProperties); // mock final Artifact localArtifactMock = mock(Artifact.class); @@ -497,7 +542,9 @@ .startsWith("http://localhost/api/v1/downloadserver/downloadId/"); } - @Test @Description("Tests TODO") public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException { + @Test + @Description("Tests TODO") + public void lookupNextUpdateActionAfterFinished() throws IllegalAccessException { // Mock final Action action = createActionWithTarget(22L, Status.FINISHED); @@ -514,8 +561,8 @@ final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); final DmfActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(DmfActionStatus.FINISHED, 23L); - final Message message = amqpMessageHandlerService.getMessageConverter() - .toMessage(actionUpdateStatus, messageProperties); + final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, + messageProperties); // test amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); @@ -523,8 +570,8 @@ final ArgumentCaptor actionPropertiesCaptor = ArgumentCaptor.forClass(ActionProperties.class); final ArgumentCaptor targetCaptor = ArgumentCaptor.forClass(Target.class); - verify(amqpMessageDispatcherServiceMock, times(1)) - .sendUpdateMessageToTarget(actionPropertiesCaptor.capture(), targetCaptor.capture(), any(Map.class)); + verify(amqpMessageDispatcherServiceMock, times(1)).sendUpdateMessageToTarget(actionPropertiesCaptor.capture(), + targetCaptor.capture(), any(Map.class)); final ActionProperties actionProperties = actionPropertiesCaptor.getValue(); assertThat(actionProperties).isNotNull(); assertThat(actionProperties.getTenant()).as("event has tenant").isEqualTo("DEFAULT"); 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 bd2b8f8556..b46bd44219 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 @@ -19,13 +19,18 @@ /** * JSON representation of the Attribute Update message. */ -@JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class DmfAttributeUpdate { +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class DmfAttributeUpdate { - @JsonProperty private final Map attributes = new HashMap<>(); + @JsonProperty + private final Map attributes = new HashMap<>(); - @JsonProperty private DmfUpdateMode mode; + @JsonProperty + private DmfUpdateMode mode; - @JsonProperty private String name; + @JsonProperty + private String name; public DmfUpdateMode getMode() { return mode; diff --git a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java index fb58c08ab5..baea65a181 100644 --- a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java @@ -19,9 +19,12 @@ /** * JSON representation of the Attribute THING_CREATED message. */ -@JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class DmfTargetProperties { +@JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class DmfTargetProperties { - @JsonProperty private String name; + @JsonProperty + private String name; public String getName() { return 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 a9969847bd..e6f81ddfbc 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 @@ -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 @@ -46,8 +46,8 @@ 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 @@ -57,8 +57,8 @@ public interface ControllerManagement { * 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 @@ -66,8 +66,8 @@ public interface ControllerManagement { * {@link ActionStatusCreate} for field constraints. * */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Action addCancelActionStatus( - @NotNull @Valid ActionStatusCreate create); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action addCancelActionStatus(@NotNull @Valid ActionStatusCreate create); /** * Retrieves assigned {@link SoftwareModule} of a target. @@ -76,7 +76,8 @@ public interface ControllerManagement { * of the {@link SoftwareModule} * @return {@link SoftwareModule} identified by ID */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Optional getSoftwareModule(long moduleId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Optional getSoftwareModule(long moduleId); /** * Retrieves {@link SoftwareModuleMetadata} where @@ -87,12 +88,13 @@ public interface ControllerManagement { * @return list of {@link SoftwareModuleMetadata} with maximum size of * {@link RepositoryConstants#MAX_META_DATA_COUNT} */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Map> findTargetVisibleMetaDataBySoftwareModuleId( + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Map> findTargetVisibleMetaDataBySoftwareModuleId( @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 @@ -100,16 +102,16 @@ public interface ControllerManagement { * @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 * if fields are not filled as specified. Check * {@link ActionStatusCreate} for field constraints. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) ActionStatus addInformationalActionStatus( - @NotNull @Valid ActionStatusCreate create); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + ActionStatus addInformationalActionStatus(@NotNull @Valid ActionStatusCreate create); /** * Adds an {@link ActionStatus} entry for an update {@link Action} including @@ -122,36 +124,36 @@ public interface ControllerManagement { * @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 * if fields are not filled as specified. Check * {@link ActionStatusCreate} for field constraints. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Action addUpdateActionStatus( - @NotNull @Valid ActionStatusCreate create); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action addUpdateActionStatus(@NotNull @Valid ActionStatusCreate create); /** * Retrieves oldest {@link Action} that is active and assigned to a * {@link Target}. * * For performance reasons this method does not throw - * {@link EntityNotFoundException} in case target with given controlelrId - * does not exist but will return an {@link Optional#empty()} instead. + * {@link EntityNotFoundException} in case target with given controlelrId does + * not exist but will return an {@link Optional#empty()} instead. * * @param controllerId * identifies the target to retrieve the actions from * @return a list of actions assigned to given target which are active * */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Optional findOldestActiveActionByTarget( - @NotEmpty String controllerId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + 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 @@ -159,22 +161,21 @@ public interface ControllerManagement { * of the target * @return the requested {@link Page} with {@link Action}s */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Page findActiveActionsByTarget( - @NotNull Pageable pageable, @NotEmpty String controllerId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + 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 * @return the corresponding {@link Action} */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Optional findActionWithDetails(long actionId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + 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 @@ -185,15 +186,14 @@ public interface ControllerManagement { * @throws EntityNotFoundException * if action with given ID does not exist */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Page findActionStatusByAction( - @NotNull Pageable pageReq, long actionId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + 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 @@ -201,15 +201,14 @@ public interface ControllerManagement { * the client IP address of the target, might be {@code null} * @return target reference */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Target findOrRegisterTargetIfItDoesNotExist( - @NotEmpty String controllerId, @NotNull URI address); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Target findOrRegisterTargetIfItDoesNotExist(@NotEmpty String controllerId, @NotNull URI address); /** - * 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 @@ -219,26 +218,26 @@ public interface ControllerManagement { * the name of the target * @return target reference */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Target findOrRegisterTargetIfItDoesNotExist( - @NotEmpty String controllerId, @NotNull URI address, String name); + @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. + * 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 * if target with given ID does not exist * */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Optional getActionForDownloadByTargetAndSoftwareModule( - @NotEmpty String controllerId, long moduleId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Optional getActionForDownloadByTargetAndSoftwareModule(@NotEmpty String controllerId, long moduleId); /** * Returns configured polling interval at which the controller polls hawkBit @@ -246,14 +245,16 @@ public interface ControllerManagement { * * @return current {@link TenantConfigurationKey#POLLING_TIME_INTERVAL}. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) String getPollingTime(); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + String getPollingTime(); /** * Returns the configured minimum polling interval. * * @return current {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) String getMinPollingTime(); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + String getMinPollingTime(); /** * Returns the count to be used for reducing polling interval while calling @@ -262,73 +263,75 @@ public interface ControllerManagement { * @return configured value of * {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) int getMaintenanceWindowPollCount(); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + 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}. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) String getPollingTimeForAction(long actionId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + 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 */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) boolean hasTargetArtifactAssigned(@NotEmpty String controllerId, - @NotEmpty String sha1Hash); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + 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 */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) boolean hasTargetArtifactAssigned(long targetId, - @NotEmpty String sha1Hash); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + 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 @@ -340,7 +343,8 @@ public interface ControllerManagement { * @throws EntityNotFoundException * if action with given ID does not exist */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Action registerRetrieved(long actionId, String message); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action registerRetrieved(long actionId, String message); /** * Updates attributes of the controller according to the given @@ -362,8 +366,9 @@ public interface ControllerManagement { * @throws InvalidTargetAttributeException * if attributes violate constraints */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Target updateControllerAttributes(@NotEmpty String controllerId, - @NotNull Map attributes, UpdateMode mode); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map attributes, + UpdateMode mode); /** * Updates name of the controller according to the given name @@ -372,16 +377,14 @@ public interface ControllerManagement { * to update * @param controllerName * the update mode or null - * * @return updated {@link Target} - * * @throws EntityNotFoundException * if target that has to be updated could not be found * @throws QuotaExceededException * if maximum number of attributes per target is exceeded */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Target updateControllerName(final String controllerId, - final String controllerName); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Target updateControllerName(final String controllerId, final String controllerName); /** * Finds {@link Target} based on given controller ID returns found Target @@ -394,12 +397,12 @@ public interface ControllerManagement { * @see Target#getControllerId() */ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) Optional getByControllerId(@NotEmpty String controllerId); + + SpringEvalExpressions.IS_SYSTEM_CODE) + Optional 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. @@ -407,24 +410,24 @@ public interface ControllerManagement { * @see Target#getId() */ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_SYSTEM_CODE) Optional get(long targetId); + + SpringEvalExpressions.IS_SYSTEM_CODE) + Optional 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 @@ -433,14 +436,14 @@ public interface ControllerManagement { * * @return action history. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) List getActionHistoryMessages(long actionId, - int messageCount); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + List 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 @@ -452,7 +455,8 @@ public interface ControllerManagement { * @throws EntityNotFoundException * if action with given actionId does not exist. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) Action cancelAction(long actionId); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + Action cancelAction(long actionId); /** * Updates given {@link Action} with its external id. @@ -462,17 +466,16 @@ public interface ControllerManagement { * @param externalRef * of the action */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) void updateActionExternalRef(long actionId, - @NotEmpty String externalRef); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + void updateActionExternalRef(long actionId, @NotEmpty String externalRef); /** - * Retrieves list of {@link Action}s which matches the provided - * externalRefs. + * Retrieves list of {@link Action}s which matches the provided externalRefs. * * @param externalRefs * for which the actions need to be fetched. * @return list of {@link Action}s matching the externalRefs. */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) List getActiveActionsByExternalRef( - @NotNull List externalRefs); + @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) + List getActiveActionsByExternalRef(@NotNull List externalRefs); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 44623e34b8..a14e10b8ae 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -107,38 +107,54 @@ * JPA based {@link ControllerManagement} implementation. * */ -@Transactional(readOnly = true) @Validated public class JpaControllerManagement implements ControllerManagement { +@Transactional(readOnly = true) +@Validated +public class JpaControllerManagement implements ControllerManagement { private static final Logger LOG = LoggerFactory.getLogger(JpaControllerManagement.class); private final BlockingDeque queue; - @Autowired private EntityManager entityManager; + @Autowired + private EntityManager entityManager; - @Autowired private ActionRepository actionRepository; + @Autowired + private ActionRepository actionRepository; - @Autowired private TargetRepository targetRepository; + @Autowired + private TargetRepository targetRepository; - @Autowired private SoftwareModuleRepository softwareModuleRepository; + @Autowired + private SoftwareModuleRepository softwareModuleRepository; - @Autowired private ActionStatusRepository actionStatusRepository; + @Autowired + private ActionStatusRepository actionStatusRepository; - @Autowired private QuotaManagement quotaManagement; + @Autowired + private QuotaManagement quotaManagement; - @Autowired private TenantConfigurationManagement tenantConfigurationManagement; + @Autowired + private TenantConfigurationManagement tenantConfigurationManagement; - @Autowired private SystemSecurityContext systemSecurityContext; + @Autowired + private SystemSecurityContext systemSecurityContext; - @Autowired private EntityFactory entityFactory; + @Autowired + private EntityFactory entityFactory; - @Autowired private EventPublisherHolder eventPublisherHolder; + @Autowired + private EventPublisherHolder eventPublisherHolder; - @Autowired private AfterTransactionCommitExecutor afterCommit; + @Autowired + private AfterTransactionCommitExecutor afterCommit; - @Autowired private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; + @Autowired + private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; - @Autowired private PlatformTransactionManager txManager; + @Autowired + private PlatformTransactionManager txManager; - @Autowired private TenantAware tenantAware; + @Autowired + private TenantAware tenantAware; private final RepositoryProperties repositoryProperties; @@ -146,9 +162,9 @@ final RepositoryProperties repositoryProperties) { if (!repositoryProperties.isEagerPollPersistence()) { - executorService - .scheduleWithFixedDelay(this::flushUpdateQueue, repositoryProperties.getPollPersistenceFlushTime(), - repositoryProperties.getPollPersistenceFlushTime(), TimeUnit.MILLISECONDS); + executorService.scheduleWithFixedDelay(this::flushUpdateQueue, + repositoryProperties.getPollPersistenceFlushTime(), + repositoryProperties.getPollPersistenceFlushTime(), TimeUnit.MILLISECONDS); queue = new LinkedBlockingDeque<>(repositoryProperties.getPollPersistenceQueueSize()); } else { @@ -158,7 +174,8 @@ this.repositoryProperties = repositoryProperties; } - @Override public String getPollingTime() { + @Override + public String getPollingTime() { return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); } @@ -168,7 +185,8 @@ * * @return current {@link TenantConfigurationKey#MIN_POLLING_TIME_INTERVAL}. */ - @Override public String getMinPollingTime() { + @Override + public String getMinPollingTime() { return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement .getConfigurationValue(TenantConfigurationKey.MIN_POLLING_TIME_INTERVAL, String.class).getValue()); } @@ -180,12 +198,14 @@ * @return configured value of * {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}. */ - @Override public int getMaintenanceWindowPollCount() { + @Override + public int getMaintenanceWindowPollCount() { return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement .getConfigurationValue(TenantConfigurationKey.MAINTENANCE_WINDOW_POLL_COUNT, Integer.class).getValue()); } - @Override public String getPollingTimeForAction(final long actionId) { + @Override + public String getPollingTimeForAction(final long actionId) { final JpaAction action = getActionAndThrowExceptionIfNotFound(actionId); @@ -218,11 +238,11 @@ private static class EventTimer { * Constructor. * * @param defaultEventInterval - * default timer value to use for interval between events. - * This puts an upper bound for the timer value + * default timer value to use for interval between events. This puts + * an upper bound for the timer value * @param minimumEventInterval - * for loading {@link DistributionSet#getModules()}. This - * puts a lower bound to the timer value + * for loading {@link DistributionSet#getModules()}. This puts a + * lower bound to the timer value * @param timerUnit * representing the unit of time to be used for timer. */ @@ -237,16 +257,15 @@ private static class EventTimer { } /** - * This method calculates the time interval until the next event based - * on the desired number of events before the time when interval is - * reset to default. The return value is bounded by - * {@link EventTimer#defaultEventInterval} and + * This method calculates the time interval until the next event based on the + * desired number of events before the time when interval is reset to default. + * The return value is bounded by {@link EventTimer#defaultEventInterval} and * {@link EventTimer#minimumEventInterval}. * * @param eventCount - * number of events desired until the interval is reset to - * default. This is not guaranteed as the interval between - * events cannot be less than the minimum interval + * number of events desired until the interval is reset to default. + * This is not guaranteed as the interval between events cannot be + * less than the minimum interval * @param timerResetTime * time when exponential forwarding should reset to default * @@ -280,7 +299,8 @@ String timeToNextEvent(final int eventCount, final ZonedDateTime timerResetTime) } } - @Override public Optional getActionForDownloadByTargetAndSoftwareModule(final String controllerId, + @Override + public Optional getActionForDownloadByTargetAndSoftwareModule(final String controllerId, final long moduleId) { throwExceptionIfTargetDoesNotExist(controllerId); throwExceptionIfSoftwareModuleDoesNotExist(moduleId); @@ -312,44 +332,52 @@ private void throwExceptionIfSoftwareModuleDoesNotExist(final Long moduleId) { } } - @Override public boolean hasTargetArtifactAssigned(final String controllerId, final String sha1Hash) { + @Override + public boolean hasTargetArtifactAssigned(final String controllerId, final String sha1Hash) { throwExceptionIfTargetDoesNotExist(controllerId); return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(controllerId, sha1Hash)) > 0; } - @Override public boolean hasTargetArtifactAssigned(final long targetId, final String sha1Hash) { + @Override + public boolean hasTargetArtifactAssigned(final long targetId, final String sha1Hash) { throwExceptionIfTargetDoesNotExist(targetId); return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(targetId, sha1Hash)) > 0; } - @Override public Optional findOldestActiveActionByTarget(final String controllerId) { + @Override + public Optional findOldestActiveActionByTarget(final String controllerId) { if (!actionRepository.activeActionExistsForControllerId(controllerId)) { return Optional.empty(); } // used in favorite to findFirstByTargetAndActiveOrderByIdAsc due to // DATAJPA-841 issue. - return actionRepository - .findFirstByTargetControllerIdAndActive(new Sort(Direction.ASC, "id"), controllerId, true); + return actionRepository.findFirstByTargetControllerIdAndActive(new Sort(Direction.ASC, "id"), controllerId, + true); } - @Override public Page findActiveActionsByTarget(final Pageable pageable, final String controllerId) { + @Override + public Page findActiveActionsByTarget(final Pageable pageable, final String controllerId) { if (!actionRepository.activeActionExistsForControllerId(controllerId)) { return Page.empty(); } return actionRepository.findByActiveAndTarget(pageable, controllerId, true); } - @Override public Optional findActionWithDetails(final long actionId) { + @Override + public Optional findActionWithDetails(final long actionId) { return actionRepository.getById(actionId); } - @Override public List getActiveActionsByExternalRef(@NotNull final List externalRefs) { + @Override + public List getActiveActionsByExternalRef(@NotNull final List externalRefs) { return actionRepository.findByExternalRefInAndActive(externalRefs, true); } - @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target findOrRegisterTargetIfItDoesNotExist( - final String controllerId, final URI address) { + @Override + @Transactional(isolation = Isolation.READ_COMMITTED) + @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address) { final Specification spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); @@ -357,8 +385,10 @@ private void throwExceptionIfSoftwareModuleDoesNotExist(final Long moduleId) { .orElseGet(() -> createTarget(controllerId, address)); } - @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target findOrRegisterTargetIfItDoesNotExist( - final String controllerId, final URI address, String name) { + @Override + @Transactional(isolation = Isolation.READ_COMMITTED) + @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address, String name) { final Specification spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); @@ -375,11 +405,10 @@ private Target createNewTarget(final String controllerId, final URI address, fin } private Target createTarget(final String controllerId, final URI address) { - final Target result = targetRepository - .save((JpaTarget) entityFactory.target().create().controllerId(controllerId) - .description("Plug and Play target: " + controllerId).name(controllerId) - .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) - .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); + final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() + .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(controllerId) + .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) + .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher() .publishEvent(new TargetPollEvent(result, eventPublisherHolder.getApplicationId()))); @@ -389,11 +418,10 @@ private Target createTarget(final String controllerId, final URI address) { private Target createTarget(final String controllerId, final URI address, final String name) { - final Target result = targetRepository - .save((JpaTarget) entityFactory.target().create().controllerId(controllerId) - .description("Plug and Play target: " + controllerId).name(name) - .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) - .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); + final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() + .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(name) + .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) + .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher() .publishEvent(new TargetPollEvent(result, eventPublisherHolder.getApplicationId()))); @@ -439,9 +467,9 @@ private void flushUpdateQueue() { private Void updateLastTargetQueries(final String tenant, final List polls) { LOG.debug("Persist {} targetqueries.", polls.size()); - final List> pollChunks = Lists - .partition(polls.stream().map(TargetPoll::getControllerId).collect(Collectors.toList()), - Constants.MAX_ENTRIES_IN_STATEMENT); + final List> pollChunks = Lists.partition( + polls.stream().map(TargetPoll::getControllerId).collect(Collectors.toList()), + Constants.MAX_ENTRIES_IN_STATEMENT); pollChunks.forEach(chunk -> { setLastTargetQuery(tenant, System.currentTimeMillis(), chunk); @@ -454,9 +482,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()); @@ -484,8 +511,8 @@ 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()} changes or the buffer queue is full. * */ private Target updateTargetStatus(final JpaTarget toUpdate, final URI address) { @@ -519,9 +546,11 @@ private boolean isStoreEager(final JpaTarget toUpdate, final URI address) { } } - @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action addCancelActionStatus( - final ActionStatusCreate c) { + @Override + @Transactional(isolation = Isolation.READ_COMMITTED) + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public Action addCancelActionStatus(final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); @@ -568,9 +597,11 @@ private void handleFinishedCancelation(final JpaActionStatus actionStatus, final DeploymentHelper.successCancellation(action, actionRepository, targetRepository); } - @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action addUpdateActionStatus( - final ActionStatusCreate c) { + @Override + @Transactional(isolation = Isolation.READ_COMMITTED) + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public Action addUpdateActionStatus(final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); final JpaActionStatus actionStatus = create.build(); @@ -588,16 +619,16 @@ private void handleFinishedCancelation(final JpaActionStatus actionStatus, final * 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) { - final boolean isIntermediateFeedback = - (FINISHED != actionStatus.getStatus()) && (Status.ERROR != actionStatus.getStatus()); + final boolean isIntermediateFeedback = (FINISHED != actionStatus.getStatus()) + && (Status.ERROR != actionStatus.getStatus()); - final boolean isAllowedByRepositoryConfiguration = - !repositoryProperties.isRejectActionStatusForClosedAction() && isIntermediateFeedback; + final boolean isAllowedByRepositoryConfiguration = !repositoryProperties.isRejectActionStatusForClosedAction() + && isIntermediateFeedback; final boolean isAllowedForDownloadOnlyActions = isDownloadOnly(action) && !isIntermediateFeedback; @@ -667,8 +698,8 @@ private void requestControllerAttributes(final String controllerId) { target.setRequestControllerAttributes(true); - eventPublisherHolder.getEventPublisher().publishEvent( - new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(), + eventPublisherHolder.getEventPublisher() + .publishEvent(new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(), target.getControllerId(), target.getAddress() != null ? target.getAddress().toString() : null, JpaTarget.class.getName(), eventPublisherHolder.getApplicationId())); } @@ -705,8 +736,8 @@ private String handleFinishedAndStoreInTargetStatus(final JpaAction action) { // check if the assigned set is equal to the installed set (not // necessarily the case as another update might be pending already). - if (target.getAssignedDistributionSet() != null && target.getAssignedDistributionSet().getId() - .equals(target.getInstalledDistributionSet().getId())) { + if (target.getAssignedDistributionSet() != null + && target.getAssignedDistributionSet().getId().equals(target.getInstalledDistributionSet().getId())) { target.setUpdateStatus(TargetUpdateStatus.IN_SYNC); } @@ -716,13 +747,16 @@ private String handleFinishedAndStoreInTargetStatus(final JpaAction action) { return target.getControllerId(); } - @Override @Transactional @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target updateControllerAttributes( - final String controllerId, final Map data, final UpdateMode mode) { + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public Target updateControllerAttributes(final String controllerId, final Map data, + final UpdateMode mode) { /* - * Constraints on attribute keys & values are not validated by - * EclipseLink. Hence, they are validated here. + * Constraints on attribute keys & values are not validated by EclipseLink. + * Hence, they are validated here. */ if (data.entrySet().stream().anyMatch(e -> !isAttributeEntryValid(e))) { throw new InvalidTargetAttributeException(); @@ -759,9 +793,11 @@ private String handleFinishedAndStoreInTargetStatus(final JpaAction action) { return targetRepository.save(target); } - @Override @Transactional @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target updateControllerName( - final String controllerId, final String controllerName) { + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public Target updateControllerName(final String controllerId, final String controllerName) { final JpaTarget target = (JpaTarget) targetRepository.findByControllerId(controllerId) .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)); @@ -804,15 +840,17 @@ private void assertTargetAttributesQuota(final JpaTarget target) { Target.class.getSimpleName(), null); } - @Override @Transactional @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Action registerRetrieved( - final long actionId, final String message) { + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public Action registerRetrieved(final long actionId, final String message) { return handleRegisterRetrieved(actionId, 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 @@ -863,9 +901,11 @@ private Action handleRegisterRetrieved(final Long actionId, final String message return action; } - @Override @Transactional @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public ActionStatus addInformationalActionStatus( - final ActionStatusCreate c) { + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public ActionStatus addInformationalActionStatus(final ActionStatusCreate c) { final JpaActionStatusCreate create = (JpaActionStatusCreate) c; final JpaAction action = getActionAndThrowExceptionIfNotFound(create.getActionId()); final JpaActionStatus statusMessage = create.build(); @@ -882,15 +922,18 @@ private JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) { .orElseThrow(() -> new EntityNotFoundException(Action.class, actionId)); } - @Override public Optional getByControllerId(final String controllerId) { + @Override + public Optional getByControllerId(final String controllerId) { return targetRepository.findByControllerId(controllerId); } - @Override public Optional get(final long targetId) { + @Override + public Optional get(final long targetId) { return targetRepository.findById(targetId).map(t -> (Target) t); } - @Override public Page findActionStatusByAction(final Pageable pageReq, final long actionId) { + @Override + public Page findActionStatusByAction(final Pageable pageReq, final long actionId) { if (!actionRepository.existsById(actionId)) { throw new EntityNotFoundException(Action.class, actionId); } @@ -898,7 +941,8 @@ private JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) { return actionStatusRepository.findByActionId(pageReq, actionId); } - @Override public List getActionHistoryMessages(final long actionId, final int messageCount) { + @Override + public List getActionHistoryMessages(final long actionId, final int messageCount) { // Just return empty list in case messageCount is zero. if (messageCount == 0) { return Collections.emptyList(); @@ -906,9 +950,9 @@ private JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) { // For negative and large value of messageCount, limit the number of // messages. - final int limit = messageCount < 0 || messageCount >= RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT ? - RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT : - messageCount; + final int limit = messageCount < 0 || messageCount >= RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT + ? RepositoryConstants.MAX_ACTION_HISTORY_MSG_COUNT + : messageCount; final PageRequest pageable = PageRequest.of(0, limit, new Sort(Direction.DESC, "occurredAt")); final Page messages = actionStatusRepository.findMessagesByActionIdAndMessageNotLike(pageable, actionId, @@ -920,16 +964,19 @@ private JpaAction getActionAndThrowExceptionIfNotFound(final Long actionId) { return messages.getContent(); } - @Override public Optional getSoftwareModule(final long id) { + @Override + public Optional getSoftwareModule(final long id) { return softwareModuleRepository.findById(id).map(s -> (SoftwareModule) s); } - @Override public Map> findTargetVisibleMetaDataBySoftwareModuleId( + @Override + public Map> findTargetVisibleMetaDataBySoftwareModuleId( final Collection moduleId) { return softwareModuleMetadataRepository .findBySoftwareModuleIdInAndTargetVisible(PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), - moduleId, true).getContent().stream().collect(Collectors.groupingBy(o -> (Long) o[0], + moduleId, true) + .getContent().stream().collect(Collectors.groupingBy(o -> (Long) o[0], Collectors.mapping(o -> (SoftwareModuleMetadata) o[1], Collectors.toList()))); } @@ -951,7 +998,8 @@ public String getControllerId() { return controllerId; } - @Override public int hashCode() { + @Override + public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (controllerId == null ? 0 : controllerId.hashCode()); @@ -959,7 +1007,8 @@ public String getControllerId() { return result; } - @Override public boolean equals(final Object obj) { + @Override + public boolean equals(final Object obj) { if (this == obj) { return true; } @@ -991,10 +1040,10 @@ public String getControllerId() { /** * Cancels given {@link Action} for this {@link Target}. The method will - * immediately add a {@link Status#CANCELED} status to the action. However, - * it might be possible that the controller will continue to work on the - * cancelation. The controller needs to acknowledge or reject the - * cancelation using {@link DdiRootController#postCancelActionFeedback}. + * immediately add a {@link Status#CANCELED} status to the action. However, it + * might be possible that the controller will continue to work on the + * cancelation. The controller needs to acknowledge or reject the cancelation + * using {@link DdiRootController#postCancelActionFeedback}. * * @param actionId * to be canceled @@ -1006,8 +1055,10 @@ public String getControllerId() { * @throws EntityNotFoundException * if action with given actionId does not exist. */ - @Override @Modifying @Transactional(isolation = Isolation.READ_COMMITTED) public Action cancelAction( - final long actionId) { + @Override + @Modifying + @Transactional(isolation = Isolation.READ_COMMITTED) + public Action cancelAction(final long actionId) { LOG.debug("cancelAction({})", actionId); final JpaAction action = actionRepository.findById(actionId) @@ -1034,7 +1085,8 @@ public String getControllerId() { } } - @Override public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) { + @Override + public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) { actionRepository.updateExternalRef(actionId, externalRef); } 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 0d6d512c1f..b09083cd19 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 @@ -82,24 +82,27 @@ import io.qameta.allure.Step; import io.qameta.allure.Story; -@Feature("Component Tests - Repository") @Story("Controller Management") public class ControllerManagementTest - extends AbstractJpaIntegrationTest { - - @Autowired private RepositoryProperties repositoryProperties; - - @Test @Description( - "Verifies that management get access react as specfied 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) }) public void nonExistingEntityAccessReturnsNotPresent() { +@Feature("Component Tests - Repository") +@Story("Controller Management") +public class ControllerManagementTest extends AbstractJpaIntegrationTest { + + @Autowired + private RepositoryProperties repositoryProperties; + + @Test + @Description("Verifies that management get access react as specfied 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) }) + public void nonExistingEntityAccessReturnsNotPresent() { final Target target = testdataFactory.createTarget(); final SoftwareModule module = testdataFactory.createSoftwareModuleOs(); assertThat(controllerManagement.findActionWithDetails(NOT_EXIST_IDL)).isNotPresent(); assertThat(controllerManagement.getByControllerId(NOT_EXIST_ID)).isNotPresent(); assertThat(controllerManagement.get(NOT_EXIST_IDL)).isNotPresent(); - assertThat(controllerManagement - .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module.getId())) - .isNotPresent(); + assertThat(controllerManagement.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), + module.getId())).isNotPresent(); assertThat(controllerManagement.findOldestActiveActionByTarget(NOT_EXIST_ID)).isNotPresent(); @@ -107,11 +110,12 @@ assertThat(controllerManagement.hasTargetArtifactAssigned(target.getId(), "XXX")).isFalse(); } - @Test @Description("Verifies that management queries react as specfied on calls for non existing entities " - + " by means of throwing EntityNotFoundException.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) }) public void entityQueriesReferringToNotExistingEntitiesThrowsException() - throws URISyntaxException { + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @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(); @@ -125,7 +129,7 @@ entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.FINISHED)), "Action"); verifyThrownExceptionBy(() -> controllerManagement - .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), NOT_EXIST_IDL), + .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), NOT_EXIST_IDL), "SoftwareModule"); verifyThrownExceptionBy( @@ -143,14 +147,16 @@ () -> controllerManagement.updateControllerAttributes(NOT_EXIST_ID, Maps.newHashMap(), null), "Target"); } - @Test @Description("Controller confirms successfull update with FINISHED status.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Controller confirms successfull update with FINISHED status.") + @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) }) public void controllerConfirmsUpdateWithFinished() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerConfirmsUpdateWithFinished() { final Long actionId = createTargetAndAssignDs(); simulateIntermediateStatusOnUpdate(actionId); @@ -164,39 +170,45 @@ assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(7); } - @Test @Description("Controller confirmation failes with invalid messages.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Controller confirmation failes with invalid messages.") + @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) }) public void controllerConfirmationFailsWithInvalidMessages() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerConfirmationFailsWithInvalidMessages() { final Long actionId = createTargetAndAssignDs(); simulateIntermediateStatusOnUpdate(actionId); - assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> controllerManagement - .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED) - .message(INVALID_TEXT_HTML))).as("set invalid description text should not be created"); + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy(() -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus() + .create(actionId).status(Action.Status.FINISHED).message(INVALID_TEXT_HTML))) + .as("set invalid description text should not be created"); - assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> controllerManagement - .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED) - .messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML)))) + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy(() -> controllerManagement.addUpdateActionStatus( + entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED) + .messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML)))) .as("set invalid description text should not be created"); assertThat(actionStatusRepository.count()).isEqualTo(6); assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(6); } - @Test @Description("Controller confirms successfull update with FINISHED status on a action that is on canceling. " - + "Reason: The decission to ignore the cancellation is in fact up to the controller.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Controller confirms successfull update with FINISHED status on a action that is on canceling. " + + "Reason: The decission to ignore the cancellation is in fact up to the controller.") + @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) }) public void controllerConfirmsUpdateWithFinishedAndIgnorsCancellationWithThat() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerConfirmsUpdateWithFinishedAndIgnorsCancellationWithThat() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -209,12 +221,14 @@ assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(3); } - @Test @Description("Update server rejects cancelation feedback if action is not in CANCELING state.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Update server rejects cancelation feedback if action is not in CANCELING state.") + @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) }) public void cancellationFeedbackRejectedIfActionIsNotInCanceling() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void cancellationFeedbackRejectedIfActionIsNotInCanceling() { final Long actionId = createTargetAndAssignDs(); try { @@ -233,14 +247,16 @@ } - @Test @Description("Controller confirms action cancelation with FINISHED status.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Controller confirms action cancelation with FINISHED status.") + @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) }) public void controllerConfirmsActionCancelationWithFinished() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerConfirmsActionCancelationWithFinished() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -258,14 +274,16 @@ assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(8); } - @Test @Description("Controller confirms action cancelation with FINISHED status.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Controller confirms action cancelation with FINISHED status.") + @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) }) public void controllerConfirmsActionCancelationWithCanceled() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerConfirmsActionCancelationWithCanceled() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -283,16 +301,17 @@ assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(8); } - @Test @Description( - "Controller rejects action cancelation 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), + @Test + @Description("Controller rejects action cancelation 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), @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) }) public void controllerRejectsActionCancelationWithReject() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerRejectsActionCancelationWithReject() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -310,16 +329,17 @@ assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(8); } - @Test @Description( - "Controller rejects action cancelation 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), + @Test + @Description("Controller rejects action cancelation 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), @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) }) public void controllerRejectsActionCancelationWithError() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerRejectsActionCancelationWithError() { final Long actionId = createTargetAndAssignDs(); deploymentManagement.cancelAction(actionId); @@ -337,7 +357,8 @@ assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(8); } - @Step private Long createTargetAndAssignDs() { + @Step + private Long createTargetAndAssignDs() { final Long dsId = testdataFactory.createDistributionSet().getId(); testdataFactory.createTarget(); assignDistributionSet(dsId, DEFAULT_CONTROLLER_ID); @@ -347,7 +368,8 @@ return deploymentManagement.findActiveActionsByTarget(PAGE, DEFAULT_CONTROLLER_ID).getContent().get(0).getId(); } - @Step private Long createAndAssignDsAsDownloadOnly(final String dsName, final String defaultControllerId) { + @Step + private Long createAndAssignDsAsDownloadOnly(final String dsName, final String defaultControllerId) { final Long dsId = testdataFactory.createDistributionSet(dsName).getId(); assignDistributionSet(dsId, defaultControllerId, DOWNLOAD_ONLY); assertThat(targetManagement.getByControllerID(defaultControllerId).get().getUpdateStatus()) @@ -359,7 +381,8 @@ return id; } - @Step private Long assignDs(final Long dsId, final String defaultControllerId, final Action.ActionType actionType) { + @Step + private Long assignDs(final Long dsId, final String defaultControllerId, final Action.ActionType actionType) { assignDistributionSet(dsId, defaultControllerId, actionType); assertThat(targetManagement.getByControllerID(defaultControllerId).get().getUpdateStatus()) .isEqualTo(TargetUpdateStatus.PENDING); @@ -370,7 +393,8 @@ return id; } - @Step private void simulateIntermediateStatusOnCancellation(final Long actionId) { + @Step + private void simulateIntermediateStatusOnCancellation(final Long actionId) { controllerManagement .addCancelActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING)); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.CANCELING, @@ -397,7 +421,8 @@ Action.Status.WARNING, true); } - @Step private void simulateIntermediateStatusOnUpdate(final Long actionId) { + @Step + private void simulateIntermediateStatusOnUpdate(final Long actionId) { controllerManagement .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING)); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, @@ -441,15 +466,16 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @Test @Description( - "Verifies that assignement 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), + @Test + @Description("Verifies that assignement 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), @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) }) public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() { + @Expect(type = SoftwareModuleUpdatedEvent.class, count = 2) }) + public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() { final int artifactSize = 5 * 1024; final byte[] random = RandomUtils.nextBytes(artifactSize); @@ -466,19 +492,21 @@ private void assertActionStatus(final Long actionId, final String controllerId, assertThat( controllerManagement.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact.getSha1Hash())) - .isFalse(); + .isFalse(); savedTarget = getFirstAssignedTarget(assignDistributionSet(ds.getId(), savedTarget.getControllerId())); assertThat( controllerManagement.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact.getSha1Hash())) - .isTrue(); + .isTrue(); assertThat( controllerManagement.hasTargetArtifactAssigned(savedTarget.getControllerId(), artifact2.getSha1Hash())) - .isTrue(); + .isTrue(); } - @Test @Description("Register a controller which does not exist") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetPollEvent.class, count = 2) }) public void findOrRegisterTargetIfItDoesNotExist() { + @Test + @Description("Register a controller which does not exist") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 2) }) + public void findOrRegisterTargetIfItDoesNotExist() { final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); assertThat(target).as("target should not be null").isNotNull(); @@ -487,20 +515,24 @@ private void assertActionStatus(final Long actionId, final String controllerId, assertThat(targetRepository.count()).as("Only 1 target should be registred").isEqualTo(1L); } - @Test @Description("Register a controller with name which does not exist") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetPollEvent.class, count = 2) }) public void findOrRegisterTargetIfItDoesNotExistWithName() { + @Test + @Description("Register a controller with name which does not exist") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 2) }) + public void findOrRegisterTargetIfItDoesNotExistWithName() { final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); assertThat(target).as("target should not be null").isNotNull(); - final Target sameTarget = controllerManagement - .findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); + final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, + "TestName"); assertThat(target.getId()).as("Target should be the equals").isEqualTo(sameTarget.getId()); assertThat(target.getName()).as("Taget names should be equal").isEqualTo(sameTarget.getName()); 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() { + @Test + @Description("Tries to register a target with an invalid controller id") + public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionForInvalidControllerIdParam() { assertThatExceptionOfType(ConstraintViolationException.class) .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST)) .as("register target with null as controllerId should fail"); @@ -513,15 +545,18 @@ private void assertActionStatus(final Long actionId, final String controllerId, .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST)) .as("register target with empty controllerId should fail"); - assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> controllerManagement - .findOrRegisterTargetIfItDoesNotExist( + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist( RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST)) .as("register target with too long controllerId should fail"); } - @Test @Description("Tries to register a target with an invalid controller id") public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionForInvalidControllerIdParam() { - assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy( - () -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST, "TestName")) + @Test + @Description("Tries to register a target with an invalid controller id") + public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionForInvalidControllerIdParam() { + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy( + () -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST, "TestName")) .as("register target with null as controllerId should fail"); assertThatExceptionOfType(ConstraintViolationException.class) @@ -532,14 +567,16 @@ private void assertActionStatus(final Long actionId, final String controllerId, .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST, "TestName")) .as("register target with empty controllerId should fail"); - assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> controllerManagement - .findOrRegisterTargetIfItDoesNotExist( + assertThatExceptionOfType(ConstraintViolationException.class) + .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist( RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST, "TestName")) .as("register target with too long controllerId should fail"); } - @Test @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " - + "exception is rethrown after max retries") public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionAfterMaxRetries() { + @Test + @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " + + "exception is rethrown after max retries") + public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionAfterMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); when(mockTargetRepository.findOne(any())).thenThrow(ConcurrencyFailureException.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -555,8 +592,10 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @Test @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " - + "exception is rethrown after max retries") public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionAfterMaxRetries() { + @Test + @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " + + "exception is rethrown after max retries") + public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionAfterMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); when(mockTargetRepository.findOne(any())).thenThrow(ConcurrencyFailureException.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -572,10 +611,12 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @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) }) public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRetries() { + @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) }) + public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -597,10 +638,12 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @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) }) public void findOrRegisterTargetIfItDoesNotExistWithNameDoesNotThrowExceptionBeforeMaxRetries() { + @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) }) + public void findOrRegisterTargetIfItDoesNotExistWithNameDoesNotThrowExceptionBeforeMaxRetries() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -622,8 +665,10 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @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") public void findOrRegisterTargetIfItDoesNotExistDoesntRetryWhenEntityAlreadyExistsException() { + @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") + public void findOrRegisterTargetIfItDoesNotExistDoesntRetryWhenEntityAlreadyExistsException() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -643,8 +688,10 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @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") public void findOrRegisterTargetIfItDoesNotExistWithNameDoesntRetryWhenEntityAlreadyExistsException() { + @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") + public void findOrRegisterTargetIfItDoesNotExistWithNameDoesntRetryWhenEntityAlreadyExistsException() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -664,8 +711,10 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @Test @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " - + "rethrown") public void recoverFindOrRegisterTargetIfItDoesNotExistIsNotInvokedForOtherExceptions() { + @Test + @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " + + "rethrown") + public void recoverFindOrRegisterTargetIfItDoesNotExistIsNotInvokedForOtherExceptions() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -683,8 +732,10 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @Test @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " - + "rethrown") public void recoverFindOrRegisterTargetIfItDoesNotExistWithNameIsNotInvokedForOtherExceptions() { + @Test + @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " + + "rethrown") + public void recoverFindOrRegisterTargetIfItDoesNotExistWithNameIsNotInvokedForOtherExceptions() { final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); @@ -702,10 +753,12 @@ private void assertActionStatus(final Long actionId, final String controllerId, } } - @Test @Description("Verify that targetVisible metadata is returned from repository") @ExpectEvents({ - @Expect(type = DistributionSetCreatedEvent.class, count = 1), + @Test + @Description("Verify that targetVisible metadata is returned from repository") + @ExpectEvents({ @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = SoftwareModuleCreatedEvent.class, count = 3), - @Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) }) public void findTargetVisibleMetaDataBySoftwareModuleId() { + @Expect(type = SoftwareModuleUpdatedEvent.class, count = 6) }) + public void findTargetVisibleMetaDataBySoftwareModuleId() { final DistributionSet set = testdataFactory.createDistributionSet(); testdataFactory.addSoftwareModuleMetadata(set); @@ -717,29 +770,35 @@ private void assertActionStatus(final Long actionId, final String controllerId, result.entrySet().forEach(entry -> assertThat(entry.getValue()).hasSize(1)); } - @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) }) public void targetPollEventNotSendIfDisabled() { + @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) }) + public void targetPollEventNotSendIfDisabled() { repositoryProperties.setPublishTargetPollEvent(false); controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); repositoryProperties.setPublishTargetPollEvent(true); } - @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) }) public void targetPollEventNotSendIfDisabledWithName() { + @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) }) + public void targetPollEventNotSendIfDisabledWithName() { repositoryProperties.setPublishTargetPollEvent(false); controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); repositoryProperties.setPublishTargetPollEvent(true); } - @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), + @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), @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) }) public void tryToFinishWithErrorUpdateProcessMoreThanOnce() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void tryToFinishWithErrorUpdateProcessMoreThanOnce() { final Long actionId = createTargetAndAssignDs(); // test and verify @@ -777,14 +836,16 @@ private void assertActionStatus(final Long actionId, final String controllerId, } - @Test @Description("Controller trys to finish an update process after it has been finished by an FINISHED action status.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Controller trys to finish an update process after it has been finished by an FINISHED action status.") + @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) }) public void tryToFinishUpdateProcessMoreThanOnce() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void tryToFinishUpdateProcessMoreThanOnce() { final Long actionId = prepareFinishedUpdate().getId(); // try with disabled late feedback @@ -811,15 +872,17 @@ private void assertActionStatus(final Long actionId, final String controllerId, } - @Test @Description( - "Controller trys 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), + @Test + @Description("Controller trys 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), @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) }) public void sendUpdatesForFinishUpdateProcessDropedIfDisabled() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void sendUpdatesForFinishUpdateProcessDropedIfDisabled() { repositoryProperties.setRejectActionStatusForClosedAction(true); final Action action = prepareFinishedUpdate(); @@ -836,15 +899,17 @@ private void assertActionStatus(final Long actionId, final String controllerId, .isEqualTo(3); } - @Test @Description( - "Controller trys 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), + @Test + @Description("Controller trys 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), @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) }) public void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { repositoryProperties.setRejectActionStatusForClosedAction(false); Action action = prepareFinishedUpdate(); @@ -861,10 +926,11 @@ private void assertActionStatus(final Long actionId, final String controllerId, .isEqualTo(4); } - @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) }) public void updateTargetAttributes() - throws Exception { + @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) }) + public void updateTargetAttributes() throws Exception { final String controllerId = "test123"; final Target target = testdataFactory.createTarget(controllerId); @@ -883,7 +949,8 @@ private void assertActionStatus(final Long actionId, final String controllerId, assertThat(targetVerify.getLastModifiedAt()).isEqualTo(target.getLastModifiedAt()); } - @Step private void addAttributeAndVerify(final String controllerId) { + @Step + private void addAttributeAndVerify(final String controllerId) { final Map testData = Maps.newHashMapWithExpectedSize(1); testData.put("test1", "testdata1"); controllerManagement.updateControllerAttributes(controllerId, testData, null); @@ -892,7 +959,8 @@ private void assertActionStatus(final Long actionId, final String controllerId, .isEqualTo(testData); } - @Step private void addSecondAttributeAndVerify(final String controllerId) { + @Step + private void addSecondAttributeAndVerify(final String controllerId) { final Map testData = Maps.newHashMapWithExpectedSize(2); testData.put("test2", "testdata20"); controllerManagement.updateControllerAttributes(controllerId, testData, null); @@ -902,7 +970,8 @@ private void assertActionStatus(final Long actionId, final String controllerId, .isEqualTo(testData); } - @Step private void updateAttributeAndVerify(final String controllerId) { + @Step + private void updateAttributeAndVerify(final String controllerId) { final Map testData = Maps.newHashMapWithExpectedSize(2); testData.put("test1", "testdata12"); @@ -913,9 +982,11 @@ private void assertActionStatus(final Long actionId, final String controllerId, .isEqualTo(testData); } - @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) }) public void updateTargetAttributesWithDifferentUpdateModes() { + @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) }) + public void updateTargetAttributesWithDifferentUpdateModes() { final String controllerId = "testCtrl"; testdataFactory.createTarget(controllerId); @@ -934,7 +1005,8 @@ private void assertActionStatus(final Long actionId, final String controllerId, } - @Step private void updateTargetAttributesWithUpdateModeRemove(final String controllerId) { + @Step + private void updateTargetAttributesWithUpdateModeRemove(final String controllerId) { final int previousSize = targetManagement.getControllerAttributes(controllerId).size(); @@ -951,7 +1023,8 @@ private void assertActionStatus(final Long actionId, final String controllerId, } - @Step private void updateTargetAttributesWithUpdateModeMerge(final String controllerId) { + @Step + private void updateTargetAttributesWithUpdateModeMerge(final String controllerId) { // get the current attributes final HashMap attributes = new HashMap<>( targetManagement.getControllerAttributes(controllerId)); @@ -970,7 +1043,8 @@ private void assertActionStatus(final Long actionId, final String controllerId, attributes.keySet().forEach(assertThat(updatedAttributes)::containsKey); } - @Step private void updateTargetAttributesWithUpdateModeReplace(final String controllerId) { + @Step + private void updateTargetAttributesWithUpdateModeReplace(final String controllerId) { // get the current attributes final HashMap attributes = new HashMap<>( @@ -991,7 +1065,8 @@ private void assertActionStatus(final Long actionId, final String controllerId, attributes.entrySet().forEach(assertThat(updatedAttributes)::doesNotContain); } - @Step private void updateTargetAttributesWithoutUpdateMode(final String controllerId) { + @Step + private void updateTargetAttributesWithoutUpdateMode(final String controllerId) { // set the initial attributes final Map attributes = new HashMap<>(); @@ -1005,10 +1080,11 @@ private void assertActionStatus(final Long actionId, final String controllerId, assertThat(updatedAttributes).containsAllEntriesOf(attributes); } - @Test @Description("Ensures that target attribute update fails if quota hits.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 2) }) public void updateTargetAttributesFailsIfTooManyEntries() - throws Exception { + @Test + @Description("Ensures that target attribute update fails if quota hits.") + @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(); testdataFactory.createTarget(controllerId); @@ -1050,7 +1126,9 @@ private void writeAttributes(final String controllerId, final int allowedAttribu controllerManagement.updateControllerAttributes(controllerId, testData, null); } - @Test @Description("Checks if invalid values of attribute-key and attribute-value are handled correctly") public void updateTargetAttributesFailsForInvalidAttributes() { + @Test + @Description("Checks if invalid values of attribute-key and attribute-value are handled correctly") + public void updateTargetAttributesFailsForInvalidAttributes() { final String keyTooLong = generateRandomStringWithLength(Target.CONTROLLER_ATTRIBUTE_KEY_SIZE + 1); final String keyValid = generateRandomStringWithLength(Target.CONTROLLER_ATTRIBUTE_KEY_SIZE); final String valueTooLong = generateRandomStringWithLength(Target.CONTROLLER_ATTRIBUTE_VALUE_SIZE + 1); @@ -1060,29 +1138,35 @@ private void writeAttributes(final String controllerId, final int allowedAttribu final String controllerId = "targetId123"; testdataFactory.createTarget(controllerId); - assertThatExceptionOfType(InvalidTargetAttributeException.class).isThrownBy(() -> controllerManagement - .updateControllerAttributes(controllerId, Collections.singletonMap(keyTooLong, valueValid), null)) + assertThatExceptionOfType(InvalidTargetAttributeException.class) + .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, + Collections.singletonMap(keyTooLong, valueValid), null)) .as("Attribute with key too long should not be created"); - assertThatExceptionOfType(InvalidTargetAttributeException.class).isThrownBy(() -> controllerManagement - .updateControllerAttributes(controllerId, Collections.singletonMap(keyTooLong, valueTooLong), null)) + assertThatExceptionOfType(InvalidTargetAttributeException.class) + .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, + Collections.singletonMap(keyTooLong, valueTooLong), null)) .as("Attribute with key too long and value too long should not be created"); - assertThatExceptionOfType(InvalidTargetAttributeException.class).isThrownBy(() -> controllerManagement - .updateControllerAttributes(controllerId, Collections.singletonMap(keyValid, valueTooLong), null)) + assertThatExceptionOfType(InvalidTargetAttributeException.class) + .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, + Collections.singletonMap(keyValid, valueTooLong), null)) .as("Attribute with value too long should not be created"); - assertThatExceptionOfType(InvalidTargetAttributeException.class).isThrownBy(() -> controllerManagement - .updateControllerAttributes(controllerId, Collections.singletonMap(keyNull, valueValid), null)) + assertThatExceptionOfType(InvalidTargetAttributeException.class) + .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, + Collections.singletonMap(keyNull, valueValid), null)) .as("Attribute with key NULL should not be created"); } - @Test @Description("Controller providing status entries fails if providing more than permitted by quota.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Controller providing status entries fails if providing more than permitted by quota.") + @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) }) public void controllerProvidesIntermediateFeedbackFailsIfQuotaHit() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerProvidesIntermediateFeedbackFailsIfQuotaHit() { final int allowStatusEntries = 10; final Long actionId = createTargetAndAssignDs(); @@ -1102,18 +1186,18 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { } } - @Test @Description("Test to verify the storage and retrieval of action history.") public void findMessagesByActionStatusId() { + @Test + @Description("Test to verify the storage and retrieval of action history.") + public void findMessagesByActionStatusId() { final DistributionSet testDs = testdataFactory.createDistributionSet("1"); final List testTarget = testdataFactory.createTargets(1); final Long actionId = getFirstAssignedActionId(assignDistributionSet(testDs, testTarget)); - controllerManagement.addUpdateActionStatus( - entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING) - .messages(Lists.newArrayList("proceeding message 1"))); - controllerManagement.addUpdateActionStatus( - entityFactory.actionStatus().create(actionId).status(Action.Status.RUNNING) - .messages(Lists.newArrayList("proceeding message 2"))); + controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId) + .status(Action.Status.RUNNING).messages(Lists.newArrayList("proceeding message 1"))); + controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId) + .status(Action.Status.RUNNING).messages(Lists.newArrayList("proceeding message 2"))); final List messages = controllerManagement.getActionHistoryMessages(actionId, 2); @@ -1123,50 +1207,50 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { assertThat(messages.get(1)).as("Message of action-status").isEqualTo("proceeding message 1"); } - @Test @Description("Verifies that the quota specifying the maximum number of status entries per action is enforced.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 2), + @Test + @Description("Verifies that the quota specifying the maximum number of status entries per action is enforced.") + @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) }) public void addActionStatusUpdatesUntilQuotaIsExceeded() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 6) }) + public void addActionStatusUpdatesUntilQuotaIsExceeded() { // any distribution set assignment causes 1 status entity to be created final int maxStatusEntries = quotaManagement.getMaxStatusEntriesPerAction() - 1; // test for informational status - final Long actionId1 = getFirstAssignedActionId( - assignDistributionSet(testdataFactory.createDistributionSet("ds1"), - testdataFactory.createTargets(1, "t1"))); + final Long actionId1 = getFirstAssignedActionId(assignDistributionSet( + testdataFactory.createDistributionSet("ds1"), testdataFactory.createTargets(1, "t1"))); assertThat(actionId1).isNotNull(); for (int i = 0; i < maxStatusEntries; ++i) { - controllerManagement.addInformationalActionStatus( - entityFactory.actionStatus().create(actionId1).status(Status.WARNING).message("Msg " + i) - .occurredAt(System.currentTimeMillis())); + controllerManagement.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1) + .status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis())); } assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement .addInformationalActionStatus(entityFactory.actionStatus().create(actionId1).status(Status.WARNING))); // test for update status (and mixed case) - final Long actionId2 = getFirstAssignedActionId( - assignDistributionSet(testdataFactory.createDistributionSet("ds2"), - testdataFactory.createTargets(1, "t2"))); + final Long actionId2 = getFirstAssignedActionId(assignDistributionSet( + testdataFactory.createDistributionSet("ds2"), testdataFactory.createTargets(1, "t2"))); assertThat(actionId2).isNotEqualTo(actionId1); for (int i = 0; i < maxStatusEntries; ++i) { - controllerManagement.addUpdateActionStatus( - entityFactory.actionStatus().create(actionId2).status(Status.WARNING).message("Msg " + i) - .occurredAt(System.currentTimeMillis())); + controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId2) + .status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis())); } assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement .addInformationalActionStatus(entityFactory.actionStatus().create(actionId2).status(Status.WARNING))); } - @Test @Description("Verifies that the quota specifying the maximum number of messages per action status is enforced.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Verifies that the quota specifying the maximum number of messages per action status is enforced.") + @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) }) public void createActionStatusWithTooManyMessages() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void createActionStatusWithTooManyMessages() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); @@ -1181,18 +1265,20 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))).isNotNull(); messages.add("msg"); - assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement - .addInformationalActionStatus( + assertThatExceptionOfType(QuotaExceededException.class) + .isThrownBy(() -> controllerManagement.addInformationalActionStatus( entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))); } - @Test @Description("Verifies that a DOWNLOAD_ONLY action is not marked complete when the controller reports DOWNLOAD") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Verifies that a DOWNLOAD_ONLY action is not marked complete when the controller reports DOWNLOAD") + @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) }) public void controllerReportsDownloadForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerReportsDownloadForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); assertThat(actionId).isNotNull(); @@ -1206,14 +1292,16 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(true); } - @Test @Description("Verifies that a DOWNLOAD_ONLY action is marked complete once the controller reports DOWNLOADED") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Verifies that a DOWNLOAD_ONLY action is marked complete once the controller reports DOWNLOADED") + @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) }) public void controllerReportsDownloadedForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerReportsDownloadedForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); assertThat(actionId).isNotNull(); @@ -1227,14 +1315,16 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); } - @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), + @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), @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) }) public void controllerReportsActionFinishedForDownloadOnlyActionThatIsNotActive() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerReportsActionFinishedForDownloadOnlyActionThatIsNotActive() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); assertThat(actionId).isNotNull(); @@ -1248,14 +1338,16 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); } - @Test @Description("Verifies that multiple DOWNLOADED events for a DOWNLOAD_ONLY action are handled.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Verifies that multiple DOWNLOADED events for a DOWNLOAD_ONLY action are handled.") + @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) }) public void controllerReportsMultipleDownloadedForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void controllerReportsMultipleDownloadedForDownloadOnlyAction() { testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); assertThat(actionId).isNotNull(); @@ -1270,15 +1362,17 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); } - @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), + @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), @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) }) public void quotaExceptionWhencontrollerReportsTooManyDownloadedMessagesForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void quotaExceptionWhencontrollerReportsTooManyDownloadedMessagesForDownloadOnlyAction() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); @@ -1288,14 +1382,16 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))); } - @Test @Description("Verifies that quota is enforced for UpdateActionStatus events for DOWNLOAD_ONLY assignments.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Verifies that quota is enforced for UpdateActionStatus events for DOWNLOAD_ONLY assignments.") + @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) }) public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); testdataFactory.createTarget(); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); @@ -1323,12 +1419,14 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { } } - @Test @Description("Verifies that quota is enforced for UpdateActionStatus events for FORCED assignments.") @ExpectEvents({ - @Expect(type = TargetCreatedEvent.class, count = 1), + @Test + @Description("Verifies that quota is enforced for UpdateActionStatus events for FORCED assignments.") + @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) }) public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForForced() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForForced() { final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); final Long actionId = createTargetAndAssignDs(); assertThat(actionId).isNotNull(); @@ -1355,7 +1453,9 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { } } - @Test @Description("Verify that the attaching externalRef to an action is propery stored") public void updatedExternalRefOnActionIsReallyUpdated() { + @Test + @Description("Verify that the attaching externalRef to an action is propery stored") + public void updatedExternalRefOnActionIsReallyUpdated() { final List allExternalRef = new ArrayList<>(); final List allActionId = new ArrayList<>(); final int numberOfActions = 3; @@ -1365,9 +1465,8 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { final String knownExternalref = "externalRefId" + i; testdataFactory.createTarget(knownControllerId); - final DistributionSetAssignmentResult assignmentResult = deploymentManagement - .assignDistributionSet(knownDistributionSet.getId(), ActionType.FORCED, 0, - Collections.singleton(knownControllerId)); + final DistributionSetAssignmentResult assignmentResult = deploymentManagement.assignDistributionSet( + knownDistributionSet.getId(), ActionType.FORCED, 0, Collections.singleton(knownControllerId)); final Long actionId = getFirstAssignedActionId(assignmentResult); controllerManagement.updateActionExternalRef(actionId, knownExternalref); @@ -1382,7 +1481,9 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { } } - @Test @Description("Verify that a null externalRef cannot be assigned to an action") public void externalRefCannotBeNull() { + @Test + @Description("Verify that a null externalRef cannot be assigned to an action") + public void externalRefCannotBeNull() { try { controllerManagement.updateActionExternalRef(1L, null); fail("No ConstraintViolationException thrown when a null externalRef was set on an action"); @@ -1390,16 +1491,17 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { } } - @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), + @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), @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) }) public void targetCanAlwaysReportFinishedOrErrorAfterActionIsClosedForDownloadOnlyAssignments() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 12) }) + public void targetCanAlwaysReportFinishedOrErrorAfterActionIsClosedForDownloadOnlyAssignments() { testdataFactory.createTarget(); @@ -1430,7 +1532,8 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { assertThat(actionStatusRepository.count()).isEqualTo(12L); } - @Step private void finishDownloadOnlyUpdateAndSendUpdateActionStatus(final Long actionId, final Status status) { + @Step + private void finishDownloadOnlyUpdateAndSendUpdateActionStatus(final Long actionId, final Status status) { // finishing action controllerManagement .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)); @@ -1439,14 +1542,17 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { assertThat(actionRepository.activeActionExistsForControllerId(DEFAULT_CONTROLLER_ID)).isEqualTo(false); } - @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), + @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), @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) }) public void controllerReportsFinishedForOldDownloadOnlyActionAfterSuccessfulForcedAssignment() { + @Expect(type = SoftwareModuleCreatedEvent.class, count = 6) }) + public void controllerReportsFinishedForOldDownloadOnlyActionAfterSuccessfulForcedAssignment() { testdataFactory.createTarget(); final DistributionSet downloadOnlyDs = testdataFactory.createDistributionSet("downloadOnlyDs1"); @@ -1474,8 +1580,8 @@ private void writeStatus(final Long actionId, final int allowedStatusEntries) { assertNoActiveActionsExistsForControllerId(DEFAULT_CONTROLLER_ID); } - @Step private void addUpdateActionStatus(final Long actionId, final String controllerId, - final Status actionStatus) { + @Step + private void addUpdateActionStatus(final Long actionId, final String controllerId, final Status actionStatus) { controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(actionStatus)); assertActionStatus(actionId, controllerId, TargetUpdateStatus.IN_SYNC, actionStatus, actionStatus, false); } 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 1b1e663c0e..10524f3f97 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 @@ -117,43 +117,56 @@ 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"; - @Autowired private ControllerManagement controllerManagament; + @Autowired + private ControllerManagement controllerManagament; - @Autowired private SoftwareModuleManagement softwareModuleManagement; + @Autowired + private SoftwareModuleManagement softwareModuleManagement; - @Autowired private SoftwareModuleTypeManagement softwareModuleTypeManagement; + @Autowired + private SoftwareModuleTypeManagement softwareModuleTypeManagement; - @Autowired private DistributionSetManagement distributionSetManagement; + @Autowired + private DistributionSetManagement distributionSetManagement; - @Autowired private DistributionSetTypeManagement distributionSetTypeManagement; + @Autowired + private DistributionSetTypeManagement distributionSetTypeManagement; - @Autowired private TargetManagement targetManagement; + @Autowired + private TargetManagement targetManagement; - @Autowired private DeploymentManagement deploymentManagement; + @Autowired + private DeploymentManagement deploymentManagement; - @Autowired private TargetTagManagement targetTagManagement; + @Autowired + private TargetTagManagement targetTagManagement; - @Autowired private DistributionSetTagManagement distributionSetTagManagement; + @Autowired + private DistributionSetTagManagement distributionSetTagManagement; - @Autowired private EntityFactory entityFactory; + @Autowired + private EntityFactory entityFactory; - @Autowired private ArtifactManagement artifactManagement; + @Autowired + private ArtifactManagement artifactManagement; - @Autowired private RolloutManagement rolloutManagement; + @Autowired + private RolloutManagement rolloutManagement; /** * 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 prefix + * for {@link SoftwareModule}s and {@link DistributionSet}s name, + * vendor and description. * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix) { @@ -162,8 +175,8 @@ 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. @@ -174,11 +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()} + * @param modules + * of {@link DistributionSet#getModules()} * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final Collection modules) { @@ -187,13 +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. + * @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) { @@ -202,12 +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()} + * @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) { @@ -216,13 +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()} + * @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) { @@ -231,15 +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}. - * - * @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. - * @param isRequiredMigrationStep for {@link DistributionSet#isRequiredMigrationStep()} + * {@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. + * @param isRequiredMigrationStep + * for {@link DistributionSet#isRequiredMigrationStep()} * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final String version, @@ -258,11 +280,11 @@ public DistributionSet createDistributionSet(final String prefix, final String v .name(prefix + " Firmware").version(version + "." + new SecureRandom().nextInt(100)) .description(LOREM.words(20)).vendor(prefix + " vendor Limited Inc, California")); - return distributionSetManagement.create(entityFactory.distributionSet().create() - .name(prefix != null && prefix.length() > 0 ? prefix : "DS").version(version) - .description(LOREM.words(10)).type(findOrCreateDefaultTestDsType()) - .modules(Arrays.asList(osMod.getId(), runtimeMod.getId(), appMod.getId())) - .requiredMigrationStep(isRequiredMigrationStep)); + return distributionSetManagement.create( + entityFactory.distributionSet().create().name(prefix != null && prefix.length() > 0 ? prefix : "DS") + .version(version).description(LOREM.words(10)).type(findOrCreateDefaultTestDsType()) + .modules(Arrays.asList(osMod.getId(), runtimeMod.getId(), appMod.getId())) + .requiredMigrationStep(isRequiredMigrationStep)); } /** @@ -274,55 +296,60 @@ public DistributionSet createDistributionSet(final String prefix, final String v * {@link #INVISIBLE_SM_MD_KEY}, {@link #INVISIBLE_SM_MD_VALUE} without * {@link SoftwareModuleMetadata#isTargetVisible()} * - * @param set to add metadata to + * @param set + * to add metadata to */ public void addSoftwareModuleMetadata(final DistributionSet set) { set.getModules().forEach(this::addTestModuleMetadata); } private void addTestModuleMetadata(final SoftwareModule module) { - softwareModuleManagement.createMetaData( - entityFactory.softwareModuleMetadata().create(module.getId()).key(VISIBLE_SM_MD_KEY) - .value(VISIBLE_SM_MD_VALUE).targetVisible(true)); - softwareModuleManagement.createMetaData( - entityFactory.softwareModuleMetadata().create(module.getId()).key(INVISIBLE_SM_MD_KEY) - .value(INVISIBLE_SM_MD_VALUE).targetVisible(false)); + softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(module.getId()) + .key(VISIBLE_SM_MD_KEY).value(VISIBLE_SM_MD_VALUE).targetVisible(true)); + softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(module.getId()) + .key(INVISIBLE_SM_MD_KEY).value(INVISIBLE_SM_MD_VALUE).targetVisible(false)); } /** * 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. - * @param isRequiredMigrationStep for {@link DistributionSet#isRequiredMigrationStep()} - * @param modules for {@link DistributionSet#getModules()} + * @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. + * @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, final boolean isRequiredMigrationStep, final Collection modules) { - return distributionSetManagement.create(entityFactory.distributionSet().create() - .name(prefix != null && prefix.length() > 0 ? prefix : "DS").version(version) - .description(LOREM.words(10)).type(findOrCreateDefaultTestDsType()) - .modules(modules.stream().map(SoftwareModule::getId).collect(Collectors.toList())) - .requiredMigrationStep(isRequiredMigrationStep)); + return distributionSetManagement.create( + entityFactory.distributionSet().create().name(prefix != null && prefix.length() > 0 ? prefix : "DS") + .version(version).description(LOREM.words(10)).type(findOrCreateDefaultTestDsType()) + .modules(modules.stream().map(SoftwareModule::getId).collect(Collectors.toList())) + .requiredMigrationStep(isRequiredMigrationStep)); } /** * Creates {@link DistributionSet} in repository including three - * {@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.updat - * @param tags {@link DistributionSet#getTags()} + * {@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.updat + * @param tags + * {@link DistributionSet#getTags()} * @return {@link DistributionSet} entity. */ public DistributionSet createDistributionSet(final String prefix, final String version, @@ -338,12 +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 + * @param number + * of {@link DistributionSet}s to create * @return {@link List} of {@link DistributionSet} entities */ public List createDistributionSets(final int number) { @@ -352,10 +380,10 @@ 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 + * @param number + * of {@link DistributionSet}s to create * @return {@link List} of {@link DistributionSet} entities */ public List createDistributionSetsWithoutModules(final int number) { @@ -372,14 +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 + * @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) { @@ -397,8 +427,10 @@ public List createDistributionSets(final String prefix, final i * {@link #DEFAULT_DESCRIPTION} and * {@link DistributionSet#isRequiredMigrationStep()} false. * - * @param name {@link DistributionSet#getName()} - * @param version {@link DistributionSet#getVersion()} + * @param name + * {@link DistributionSet#getName()} + * @param version + * {@link DistributionSet#getVersion()} * @return {@link DistributionSet} entity */ public DistributionSet createDistributionSetWithNoSoftwareModules(final String name, final String version) { @@ -408,10 +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. + * @param moduleId + * the {@link Artifact}s belong to. * @return {@link Artifact} entity. */ public List createArtifacts(final Long moduleId) { @@ -425,12 +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. + * @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) { @@ -440,28 +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 + * @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)); + 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} + * @param typeKey + * of the {@link SoftwareModuleType} * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModule(final String typeKey) { @@ -469,10 +509,9 @@ 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}. */ @@ -481,12 +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 + * @param prefix + * added to name and version * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModuleApp(final String prefix) { @@ -494,10 +533,9 @@ 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}. */ @@ -506,12 +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 + * @param prefix + * added to name and version * @return persisted {@link SoftwareModule}. */ public SoftwareModule createSoftwareModuleOs(final String prefix) { @@ -520,18 +558,19 @@ 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 + * @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) { - return softwareModuleManagement - .create(entityFactory.softwareModule().create().type(findOrCreateSoftwareModuleType(typeKey)) - .name(prefix + typeKey).version(prefix + DEFAULT_VERSION).description(LOREM.words(10)) - .vendor(DEFAULT_VENDOR)); + return softwareModuleManagement.create(entityFactory.softwareModule().create() + .type(findOrCreateSoftwareModuleType(typeKey)).name(prefix + typeKey).version(prefix + DEFAULT_VERSION) + .description(LOREM.words(10)).vendor(DEFAULT_VENDOR)); } /** @@ -542,7 +581,8 @@ public Target createTarget() { } /** - * @param controllerId of the target + * @param controllerId + * of the target * @return persisted {@link Target} */ public Target createTarget(final String controllerId) { @@ -557,7 +597,8 @@ public Target createTarget(final String controllerId) { } /** - * @param targetName name of the target + * @param targetName + * name of the target * @return persisted {@link Target} */ public Target createTargetWithName(final String targetName) { @@ -574,26 +615,24 @@ public Target createTargetWithName(final String targetName) { /** * 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() { DistributionSet set = createDistributionSet(""); - set = distributionSetManagement.update(entityFactory.distributionSet().update(set.getId()) - .description("Updated " + DEFAULT_DESCRIPTION)); + set = distributionSetManagement.update( + entityFactory.distributionSet().update(set.getId()).description("Updated " + DEFAULT_DESCRIPTION)); - set.getModules().forEach(module -> softwareModuleManagement - .update(entityFactory.softwareModule().update(module.getId()) - .description("Updated " + DEFAULT_DESCRIPTION))); + set.getModules().forEach(module -> softwareModuleManagement.update( + entityFactory.softwareModule().update(module.getId()).description("Updated " + DEFAULT_DESCRIPTION))); // load also lazy stuff return distributionSetManagement.getWithDetails(set.getId()).get(); @@ -601,8 +640,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<>(); @@ -619,41 +658,48 @@ public DistributionSetType findOrCreateDefaultTestDsType() { /** * Creates {@link DistributionSetType} in repository. * - * @param dsTypeKey {@link DistributionSetType#getKey()} - * @param dsTypeName {@link DistributionSetType#getName()} + * @param dsTypeKey + * {@link DistributionSetType#getKey()} + * @param dsTypeName + * {@link DistributionSetType#getName()} * @return persisted {@link DistributionSetType} */ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName) { - return distributionSetTypeManagement.getByKey(dsTypeKey).orElseGet(() -> distributionSetTypeManagement - .create(entityFactory.distributionSetType().create().key(dsTypeKey).name(dsTypeName) - .description(LOREM.words(10)).colour("black"))); + return distributionSetTypeManagement.getByKey(dsTypeKey) + .orElseGet(() -> distributionSetTypeManagement.create(entityFactory.distributionSetType().create() + .key(dsTypeKey).name(dsTypeName).description(LOREM.words(10)).colour("black"))); } /** * 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 {@link DistributionSetType#getName()} - * @param mandatory {@link DistributionSetType#getMandatoryModuleTypes()} - * @param optional {@link DistributionSetType#getOptionalModuleTypes()} + * @param dsTypeKey + * {@link DistributionSetType#getKey()} + * @param dsTypeName + * {@link DistributionSetType#getName()} + * @param mandatory + * {@link DistributionSetType#getMandatoryModuleTypes()} + * @param optional + * {@link DistributionSetType#getOptionalModuleTypes()} * @return persisted {@link DistributionSetType} */ public DistributionSetType findOrCreateDistributionSetType(final String dsTypeKey, final String dsTypeName, final Collection mandatory, final Collection optional) { - return distributionSetTypeManagement.getByKey(dsTypeKey).orElseGet(() -> distributionSetTypeManagement - .create(entityFactory.distributionSetType().create().key(dsTypeKey).name(dsTypeName) - .description(LOREM.words(10)).colour("black") + return distributionSetTypeManagement.getByKey(dsTypeKey) + .orElseGet(() -> distributionSetTypeManagement.create(entityFactory.distributionSetType().create() + .key(dsTypeKey).name(dsTypeName).description(LOREM.words(10)).colour("black") .optional(optional.stream().map(SoftwareModuleType::getId).collect(Collectors.toList())) .mandatory(mandatory.stream().map(SoftwareModuleType::getId).collect(Collectors.toList())))); } /** * 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()} + * @param key + * {@link SoftwareModuleType#getKey()} * @return persisted {@link SoftwareModuleType} */ public SoftwareModuleType findOrCreateSoftwareModuleType(final String key) { @@ -664,40 +710,51 @@ 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()} + * @param key + * {@link SoftwareModuleType#getKey()} + * @param maxAssignments + * {@link SoftwareModuleType#getMaxAssignments()} * @return persisted {@link SoftwareModuleType} */ public SoftwareModuleType findOrCreateSoftwareModuleType(final String key, final int maxAssignments) { - return softwareModuleTypeManagement.getByKey(key).orElseGet(() -> softwareModuleTypeManagement - .create(entityFactory.softwareModuleType().create().key(key).name(key).description(LOREM.words(10)) - .maxAssignments(maxAssignments))); + return softwareModuleTypeManagement.getByKey(key) + .orElseGet(() -> softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create() + .key(key).name(key).description(LOREM.words(10)).maxAssignments(maxAssignments))); } /** * Creates a {@link DistributionSet}. * - * @param name {@link DistributionSet#getName()} - * @param version {@link DistributionSet#getVersion()} - * @param type {@link DistributionSet#getType()} - * @param modules {@link DistributionSet#getModules()} + * @param name + * {@link DistributionSet#getName()} + * @param version + * {@link DistributionSet#getVersion()} + * @param type + * {@link DistributionSet#getType()} + * @param modules + * {@link DistributionSet#getModules()} * @return the created {@link DistributionSet} */ public DistributionSet createDistributionSet(final String name, final String version, final DistributionSetType type, final Collection modules) { - return distributionSetManagement.create(entityFactory.distributionSet().create().name(name).version(version) - .description(LOREM.words(10)).type(type) - .modules(modules.stream().map(SoftwareModule::getId).collect(Collectors.toList()))); + return distributionSetManagement.create( + entityFactory.distributionSet().create().name(name).version(version).description(LOREM.words(10)) + .type(type).modules(modules.stream().map(SoftwareModule::getId).collect(Collectors.toList()))); } /** * Generates {@link DistributionSet} object without persisting it. * - * @param name {@link DistributionSet#getName()} - * @param version {@link DistributionSet#getVersion()} - * @param type {@link DistributionSet#getType()} - * @param modules {@link DistributionSet#getModules()} - * @param requiredMigrationStep {@link DistributionSet#isRequiredMigrationStep()} + * @param name + * {@link DistributionSet#getName()} + * @param version + * {@link DistributionSet#getVersion()} + * @param type + * {@link DistributionSet#getType()} + * @param modules + * {@link DistributionSet#getModules()} + * @param requiredMigrationStep + * {@link DistributionSet#isRequiredMigrationStep()} * @return the created {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name, final String version, @@ -711,10 +768,14 @@ public DistributionSet generateDistributionSet(final String name, final String v /** * Generates {@link DistributionSet} object without persisting it. * - * @param name {@link DistributionSet#getName()} - * @param version {@link DistributionSet#getVersion()} - * @param type {@link DistributionSet#getType()} - * @param modules {@link DistributionSet#getModules()} + * @param name + * {@link DistributionSet#getName()} + * @param version + * {@link DistributionSet#getVersion()} + * @param type + * {@link DistributionSet#getType()} + * @param modules + * {@link DistributionSet#getModules()} * @return the created {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name, final String version, @@ -725,7 +786,8 @@ public DistributionSet generateDistributionSet(final String name, final String v /** * builder method for generating a {@link DistributionSet}. * - * @param name {@link DistributionSet#getName()} + * @param name + * {@link DistributionSet#getName()} * @return the generated {@link DistributionSet} */ public DistributionSet generateDistributionSet(final String name) { @@ -734,11 +796,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 + * @param number + * of {@link Target}s to create * @return {@link List} of {@link Target} entities */ public List createTargets(final int number) { @@ -755,9 +817,12 @@ 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 of {@link Target}s to generate - * @param controllerIdPrefix for {@link Target#getControllerId()} generation. + * @param start + * value for the controllerId suffix + * @param numberOfTargets + * of {@link Target}s to generate + * @param controllerIdPrefix + * for {@link Target#getControllerId()} generation. * @return list of {@link Target} objects */ private List generateTargets(final int start, final int numberOfTargets, final String controllerIdPrefix) { @@ -771,11 +836,12 @@ 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 for {@link Target#getControllerId()} generation. + * @param numberOfTargets + * of {@link Target}s to generate + * @param controllerIdPrefix + * for {@link Target#getControllerId()} generation. * @return list of {@link Target} objects */ public List generateTargets(final int numberOfTargets, final String controllerIdPrefix) { @@ -785,8 +851,10 @@ public List generateTargets(final int numberOfTargets, final String cont /** * builds a set of {@link Target} fixtures from the given parameters. * - * @param numberOfTargets number of targets to create - * @param prefix prefix used for the controller ID and description + * @param numberOfTargets + * number of targets to create + * @param prefix + * prefix used for the controller ID and description * @return set of {@link Target} */ public List createTargets(final int numberOfTargets, final String prefix) { @@ -796,33 +864,43 @@ public List createTargets(final int numberOfTargets, final String prefix /** * builds a set of {@link Target} fixtures from the given parameters. * - * @param numberOfTargets number of targets to create - * @param controllerIdPrefix prefix used for the controller ID - * @param descriptionPrefix prefix used for the description + * @param numberOfTargets + * number of targets to create + * @param controllerIdPrefix + * prefix used for the controller ID + * @param descriptionPrefix + * prefix used for the description * @return set of {@link Target} */ public List createTargets(final int numberOfTargets, final String controllerIdPrefix, final String descriptionPrefix) { - return targetManagement.create(IntStream.range(0, numberOfTargets).mapToObj( - i -> entityFactory.target().create().controllerId(String.format("%s-%05d", controllerIdPrefix, i)) - .description(descriptionPrefix + i)).collect(Collectors.toList())); + return targetManagement.create(IntStream.range(0, numberOfTargets) + .mapToObj(i -> entityFactory.target().create() + .controllerId(String.format("%s-%05d", controllerIdPrefix, i)) + .description(descriptionPrefix + i)) + .collect(Collectors.toList())); } /** * builds a set of {@link Target} fixtures from the given parameters. * - * @param numberOfTargets number of targets to create - * @param controllerIdPrefix prefix used for the controller ID - * @param descriptionPrefix prefix used for the description - * @param lastTargetQuery last time the target polled + * @param numberOfTargets + * number of targets to create + * @param controllerIdPrefix + * prefix used for the controller ID + * @param descriptionPrefix + * prefix used for the description + * @param lastTargetQuery + * last time the target polled * @return set of {@link Target} */ public List createTargets(final int numberOfTargets, final String controllerIdPrefix, final String descriptionPrefix, final Long lastTargetQuery) { - return targetManagement.create(IntStream.range(0, numberOfTargets).mapToObj( - i -> entityFactory.target().create().controllerId(String.format("%s-%05d", controllerIdPrefix, i)) + return targetManagement.create(IntStream.range(0, numberOfTargets) + .mapToObj(i -> entityFactory.target().create() + .controllerId(String.format("%s-%05d", controllerIdPrefix, i)) .description(descriptionPrefix + i).lastTargetQuery(lastTargetQuery)) .collect(Collectors.toList())); } @@ -830,8 +908,10 @@ public List createTargets(final int numberOfTargets, final String contro /** * Create a set of {@link TargetTag}s. * - * @param number number of {@link TargetTag}. to be created - * @param tagPrefix prefix for the {@link TargetTag#getName()} + * @param number + * number of {@link TargetTag}. to be created + * @param tagPrefix + * prefix for the {@link TargetTag#getName()} * @return the created set of {@link TargetTag}s */ public List createTargetTags(final int number, final String tagPrefix) { @@ -848,7 +928,8 @@ public List createTargetTags(final int number, final String tagPrefix /** * Creates {@link DistributionSetTag}s in repository. * - * @param number of {@link DistributionSetTag}s + * @param number + * of {@link DistributionSetTag}s * @return the persisted {@link DistributionSetTag}s */ public List createDistributionSetTags(final int number) { @@ -870,12 +951,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 + * @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, @@ -884,12 +967,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 + * @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, @@ -908,13 +993,20 @@ public List sendUpdateActionStatusToTargets(final Collection tar /** * Creates rollout based on given parameters. * - * @param rolloutName of the {@link Rollout} - * @param rolloutDescription of the {@link Rollout} - * @param groupSize of the {@link Rollout} - * @param filterQuery to identify the {@link Target}s - * @param distributionSet to assign - * @param successCondition to switch to next group - * @param errorCondition to switch to next group + * @param rolloutName + * of the {@link Rollout} + * @param rolloutDescription + * of the {@link Rollout} + * @param groupSize + * of the {@link Rollout} + * @param filterQuery + * to identify the {@link Target}s + * @param distributionSet + * to assign + * @param successCondition + * to switch to next group + * @param errorCondition + * to switch to next group * @return created {@link Rollout} */ public Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, @@ -927,14 +1019,22 @@ public Rollout createRolloutByVariables(final String rolloutName, final String r /** * Creates rollout based on given parameters. * - * @param rolloutName of the {@link Rollout} - * @param rolloutDescription of the {@link Rollout} - * @param groupSize of the {@link Rollout} - * @param filterQuery to identify the {@link Target}s - * @param distributionSet to assign - * @param successCondition to switch to next group - * @param errorCondition to switch to next group - * @param actionType the type of the Rollout + * @param rolloutName + * of the {@link Rollout} + * @param rolloutDescription + * of the {@link Rollout} + * @param groupSize + * of the {@link Rollout} + * @param filterQuery + * to identify the {@link Target}s + * @param distributionSet + * to assign + * @param successCondition + * to switch to next group + * @param errorCondition + * to switch to next group + * @param actionType + * the type of the Rollout * @return created {@link Rollout} */ public Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, @@ -945,10 +1045,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(); @@ -960,8 +1060,9 @@ 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 + * @param prefix + * for rollouts name, description, {@link Target#getControllerId()} + * filter * @return created {@link Rollout} */ public Rollout createRollout(final String prefix) { @@ -971,11 +1072,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 + * @param prefix + * for rollouts name, description, {@link Target#getControllerId()} + * filter * @return created {@link Rollout} */ public Rollout createSoftDeletedRollout(final String prefix) { From 40a799857af6c02f7c485c69ad685a39fec1a7a2 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 20 Sep 2019 16:21:54 +0200 Subject: [PATCH 09/22] Reformat regarding THING_CREATED Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerServiceTest.java | 2 +- .../dmf/json/model/DmfAttributeUpdate.java | 2 +- .../dmf/json/model/DmfTargetProperties.java | 5 +-- .../jpa/JpaControllerManagement.java | 36 ++++--------------- .../jpa/ControllerManagementTest.java | 2 +- .../repository/test/util/TestdataFactory.java | 6 ++-- 6 files changed, 13 insertions(+), 40 deletions(-) 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 3c4c85ce76..e38c7852b3 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 @@ -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/DmfAttributeUpdate.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfAttributeUpdate.java index b46bd44219..0b36269971 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/DmfTargetProperties.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java index baea65a181..873c2234ef 100644 --- a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.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 @@ -8,9 +8,6 @@ */ package org.eclipse.hawkbit.dmf.json.model; -import java.util.HashMap; -import java.util.Map; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index a14e10b8ae..8743f7e662 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.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 @@ -19,12 +19,7 @@ import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalUnit; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ScheduledExecutorService; @@ -39,14 +34,7 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import org.eclipse.hawkbit.repository.ControllerManagement; -import org.eclipse.hawkbit.repository.EntityFactory; -import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper; -import org.eclipse.hawkbit.repository.QuotaManagement; -import org.eclipse.hawkbit.repository.RepositoryConstants; -import org.eclipse.hawkbit.repository.RepositoryProperties; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.repository.UpdateMode; +import org.eclipse.hawkbit.repository.*; import org.eclipse.hawkbit.repository.builder.ActionStatusCreate; import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent; import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent; @@ -58,24 +46,12 @@ import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.repository.jpa.model.JpaAction; -import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; -import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_; -import org.eclipse.hawkbit.repository.jpa.model.JpaAction_; -import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; -import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; -import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; +import org.eclipse.hawkbit.repository.jpa.model.*; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; -import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.*; import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionStatus; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -388,7 +364,7 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address, String name) { + public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address, final String name) { final Specification spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); 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 b09083cd19..300c060017 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 @@ -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-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 10524f3f97..9e82ea56dc 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 @@ -290,7 +290,7 @@ public DistributionSet createDistributionSet(final String prefix, final String v /** * Adds {@link SoftwareModuleMetadata} to every module of given * {@link DistributionSet}. - *

+ * * {@link #VISIBLE_SM_MD_VALUE}, {@link #VISIBLE_SM_MD_KEY} with * {@link SoftwareModuleMetadata#isTargetVisible()} and * {@link #INVISIBLE_SM_MD_KEY}, {@link #INVISIBLE_SM_MD_VALUE} without @@ -619,7 +619,7 @@ public Target createTargetWithName(final String targetName) { * {@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. From 90a74c21dab5d14aac5d26bd32eed0f07bfc66df Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 20 Sep 2019 18:57:50 +0200 Subject: [PATCH 10/22] Use constant in THING_CREATED Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 38 +++++++------------ 1 file changed, 13 insertions(+), 25 deletions(-) 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 ba7811dcdc..7628fc151a 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 @@ -13,12 +13,7 @@ import java.io.Serializable; import java.net.URI; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; @@ -30,20 +25,11 @@ import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.repository.ControllerManagement; -import org.eclipse.hawkbit.repository.EntityFactory; -import org.eclipse.hawkbit.repository.RepositoryConstants; -import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.repository.UpdateMode; +import org.eclipse.hawkbit.repository.*; import org.eclipse.hawkbit.repository.builder.ActionStatusCreate; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.*; import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.model.ActionProperties; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.util.IpUtil; import org.slf4j.Logger; @@ -81,6 +67,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService { private final SystemSecurityContext systemSecurityContext; + private static final String THING_ID_NULL = "ThingId is null"; + /** * Constructor. * @@ -196,7 +184,7 @@ private static void setTenantSecurityContext(final String tenantId) { * @param virtualHost */ private void registerTarget(final Message message, final String virtualHost) { - final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); + final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL); final String replyTo = message.getMessageProperties().getReplyTo(); if (StringUtils.isEmpty(replyTo)) { @@ -208,7 +196,7 @@ private void registerTarget(final Message message, final String virtualHost) { final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); - } catch (EntityAlreadyExistsException e) { + } catch (final EntityAlreadyExistsException e) { throw new AmqpRejectAndDontRequeueException("Target already registered, message will be ignored!", e); } } @@ -225,7 +213,7 @@ private void registerTarget(final Message message, final String virtualHost) { * replaced by targetId */ private void registerTarget(final Message message, final String virtualHost, final String name) { - final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); + final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL); final String replyTo = message.getMessageProperties().getReplyTo(); if (StringUtils.isEmpty(replyTo)) { @@ -237,7 +225,7 @@ private void registerTarget(final Message message, final String virtualHost, fin final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, name); LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); - } catch (EntityAlreadyExistsException e) { + } catch (final EntityAlreadyExistsException e) { throw new AmqpRejectAndDontRequeueException("Target already registered, message will be ignored!", e); } } @@ -319,7 +307,7 @@ private void handleIncomingEvent(final Message message) { private void updateAttributes(final Message message) { final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class); - final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); + final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL); // If new name provided in body, then change the name if (attributeUpdate.getName() != null && attributeUpdate.getName().length() != 0) { @@ -456,7 +444,7 @@ private T getConfigValue(final String key, final Class< .runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue()); } - private void handleThingCreatedRequest(Message message, String tenant, String virtualHost) { + private void handleThingCreatedRequest(final Message message, final String tenant, final String virtualHost) { if (message.toString().contains("name")) { handleNameContainedRequest(message, tenant, virtualHost); } else { @@ -464,7 +452,7 @@ private void handleThingCreatedRequest(Message message, String tenant, String vi } } - private void handleNameContainedRequest(Message message, String tenant, String virtualHost) { + private void handleNameContainedRequest(final Message message, final String tenant, final String virtualHost) { // If name never reassigned, so still null, then per default: // targetName = targetId String name = null; @@ -484,7 +472,7 @@ private void handleNameContainedRequest(Message message, String tenant, String v } } - private void handleNoNameContainedRequest(Message message, String tenant, String virtualHost) { + private void handleNoNameContainedRequest(final Message message, final String tenant, final String virtualHost) { setTenantSecurityContext(tenant); registerTarget(message, virtualHost); } From 1d82766665ad34e667453cdc5567de914c9d6011 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 20 Sep 2019 19:17:45 +0200 Subject: [PATCH 11/22] Format in THING_CREATED Signed-off-by: Ammar Bikic --- .../jpa/JpaControllerManagement.java | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 8743f7e662..70e2023935 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -19,7 +19,12 @@ import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalUnit; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ScheduledExecutorService; @@ -34,7 +39,14 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import org.eclipse.hawkbit.repository.*; +import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper; +import org.eclipse.hawkbit.repository.QuotaManagement; +import org.eclipse.hawkbit.repository.RepositoryConstants; +import org.eclipse.hawkbit.repository.RepositoryProperties; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.builder.ActionStatusCreate; import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent; import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent; @@ -46,12 +58,24 @@ import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.repository.jpa.model.*; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; +import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_; +import org.eclipse.hawkbit.repository.jpa.model.JpaAction_; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; +import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; -import org.eclipse.hawkbit.repository.model.*; +import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionStatus; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; @@ -364,7 +388,8 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address, final String name) { + public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address, + final String name) { final Specification spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); From 617859390d80e19aad9438720e4d65542daeb6ac Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 27 Sep 2019 17:50:32 +0200 Subject: [PATCH 12/22] Resolving peer review comments regarding THING_CREATED Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 86 +++++-------------- .../amqp/AmqpMessageHandlerServiceTest.java | 8 +- ...getProperties.java => DmfCreateThing.java} | 2 +- .../repository/ControllerManagement.java | 4 +- .../jpa/JpaControllerManagement.java | 23 ++--- 5 files changed, 36 insertions(+), 87 deletions(-) rename hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/{DmfTargetProperties.java => DmfCreateThing.java} (96%) 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 7628fc151a..e89942e671 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 @@ -21,7 +21,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.DmfTargetProperties; +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; @@ -139,7 +139,8 @@ public Message onMessage(final Message message, final String type, final String final MessageType messageType = MessageType.valueOf(type); switch (messageType) { case THING_CREATED: - handleThingCreatedRequest(message, tenant, virtualHost); + setTenantSecurityContext(tenant); + registerTarget(message, virtualHost); break; case EVENT: checkContentTypeJson(message); @@ -182,10 +183,13 @@ private static void setTenantSecurityContext(final String tenantId) { * @param message * the message that contains the target/thing * @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); final String replyTo = message.getMessageProperties().getReplyTo(); + String name = null; + final Target target; if (StringUtils.isEmpty(replyTo)) { logAndThrowMessageError(message, "No ReplyTo was set for the createThing message."); @@ -193,36 +197,21 @@ private void registerTarget(final Message message, final String virtualHost) { try { final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo); - final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); - LOG.debug("Target {} reported online state.", thingId); - sendUpdateCommandToTarget(target); - } catch (final EntityAlreadyExistsException e) { - throw new AmqpRejectAndDontRequeueException("Target already registered, message will be ignored!", e); - } - } - - /** - * Method to register a new target. - * - * @param message - * the message that contains the target/thing - * @param virtualHost - * the virtualHost of the target/thing - * @param name - * the name of the target/thing, can be null and would then be - * replaced by targetId - */ - private void registerTarget(final Message message, final String virtualHost, final String name) { - final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL); - final String replyTo = message.getMessageProperties().getReplyTo(); - - if (StringUtils.isEmpty(replyTo)) { - logAndThrowMessageError(message, "No ReplyTo was set for the createThing message."); - } - - try { - final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo); - final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, name); + if (message.toString().contains("name")) { + checkContentTypeJson(message); + // Check whether name property set + final DmfCreateThing targetProperties = convertMessage(message, DmfCreateThing.class); + // Will be true if "name" properly in body and not just contained in some + // attributes + if (targetProperties.getName() != null && targetProperties.getName().length() != 0) { + name = targetProperties.getName(); + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, name); + } else { + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); + } + } else { + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); + } LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); } catch (final EntityAlreadyExistsException e) { @@ -444,39 +433,6 @@ private T getConfigValue(final String key, final Class< .runAsSystem(() -> tenantConfigurationManagement.getConfigurationValue(key, valueType).getValue()); } - private void handleThingCreatedRequest(final Message message, final String tenant, final String virtualHost) { - if (message.toString().contains("name")) { - handleNameContainedRequest(message, tenant, virtualHost); - } else { - handleNoNameContainedRequest(message, tenant, virtualHost); - } - } - - private void handleNameContainedRequest(final Message message, final String tenant, final String virtualHost) { - // If name never reassigned, so still null, then per default: - // targetName = targetId - String name = null; - - checkContentTypeJson(message); - // Check whether name property set - final DmfTargetProperties targetProperties = convertMessage(message, DmfTargetProperties.class); - // Will be true if "name" properly in body and not just - // contained in some attributes - if (targetProperties.getName() != null && targetProperties.getName().length() != 0) { - name = targetProperties.getName(); - setTenantSecurityContext(tenant); - registerTarget(message, virtualHost, name); - } else { - setTenantSecurityContext(tenant); - registerTarget(message, virtualHost); - } - } - - private void handleNoNameContainedRequest(final Message message, final String tenant, final String virtualHost) { - setTenantSecurityContext(tenant); - registerTarget(message, virtualHost); - } - // for testing public void setControllerManagement(final ControllerManagement controllerManagement) { this.controllerManagement = controllerManagement; 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 e38c7852b3..5ab69d2cb4 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 @@ -14,6 +14,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -36,7 +37,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfActionUpdateStatus; import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate; import org.eclipse.hawkbit.dmf.json.model.DmfDownloadResponse; -import org.eclipse.hawkbit.dmf.json.model.DmfTargetProperties; +import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing; import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ControllerManagement; @@ -203,7 +204,7 @@ public void createThingWithName() { final String knownThingId = "2"; final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); - final DmfTargetProperties targetProperties = new DmfTargetProperties(); + final DmfCreateThing targetProperties = new DmfCreateThing(); targetProperties.setName("NonDefaultTargetName"); final Message message = messageConverter.toMessage(targetProperties, messageProperties); @@ -298,8 +299,7 @@ public void updateAttributesWithName() { when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), modeCaptor.capture())).thenReturn(null); - when(controllerManagementMock.updateControllerName(targetIdCaptor.capture(), targetNameCaptor.capture())) - .thenReturn(null); + doNothing().when(controllerManagementMock).updateControllerName(targetIdCaptor.capture(), targetNameCaptor.capture()); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); diff --git a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfCreateThing.java similarity index 96% rename from hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java rename to hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfCreateThing.java index 873c2234ef..46e6bdc7d3 100644 --- a/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfTargetProperties.java +++ b/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfCreateThing.java @@ -18,7 +18,7 @@ */ @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class DmfTargetProperties { +public class DmfCreateThing { @JsonProperty private String 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 e6f81ddfbc..b9e3c2c8b1 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 @@ -377,14 +377,14 @@ Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Mapnull - * @return updated {@link Target} + * @return void * @throws EntityNotFoundException * if target that has to be updated could not be found * @throws QuotaExceededException * if maximum number of attributes per target is exceeded */ @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - Target updateControllerName(final String controllerId, final String controllerName); + void updateControllerName(final String controllerId, final String controllerName); /** * Finds {@link Target} based on given controller ID returns found Target diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 70e2023935..c484e88dc6 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -394,20 +394,16 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); return targetRepository.findOne(spec).map(target -> updateTargetStatus(target, address)) - .orElseGet(() -> createNewTarget(controllerId, address, name)); + .orElseGet(() -> createTargetWithName(controllerId, address, name)); } - private Target createNewTarget(final String controllerId, final URI address, final String name) { + private Target createTargetWithName(final String controllerId, final URI address, final String name) { // In case of a true expression, the targetId will be set as name if (name == null || name.length() == 0) { return createTarget(controllerId, address); } - return createTarget(controllerId, address, name); - } - - private Target createTarget(final String controllerId, final URI address) { 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(name) .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); @@ -417,10 +413,9 @@ private Target createTarget(final String controllerId, final URI address) { return result; } - private Target createTarget(final String controllerId, final URI address, final String name) { - + private Target createTarget(final String controllerId, final URI address) { final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() - .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(name) + .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(controllerId) .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); @@ -798,16 +793,14 @@ public Target updateControllerAttributes(final String controllerId, final Map new EntityNotFoundException(Target.class, controllerId)); target.setName(controllerName); - assertTargetAttributesQuota(target); - - return targetRepository.save(target); + targetRepository.save(target); } private static boolean isAttributeEntryValid(final Map.Entry e) { @@ -1043,7 +1036,7 @@ public boolean equals(final Object obj) { * Cancels given {@link Action} for this {@link Target}. The method will * immediately add a {@link Status#CANCELED} status to the action. However, it * might be possible that the controller will continue to work on the - * cancelation. The controller needs to acknowledge or reject the cancelation + * cancellation. The controller needs to acknowledge or reject the cancelation * using {@link DdiRootController#postCancelActionFeedback}. * * @param actionId From 6d5aaca904dbf4dfc784faf77b0804bca0915dfa Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 27 Sep 2019 18:10:48 +0200 Subject: [PATCH 13/22] Resolving peer review comments (organize imports) regarding THING_CREATED Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 20 ++++++++++++++++--- .../repository/test/util/TestdataFactory.java | 13 ++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) 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 e89942e671..43d7f564c4 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 @@ -13,7 +13,12 @@ import java.io.Serializable; import java.net.URI; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; @@ -25,11 +30,20 @@ import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.repository.*; +import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.RepositoryConstants; +import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.builder.ActionStatusCreate; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.model.*; +import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.model.ActionProperties; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.util.IpUtil; import org.slf4j.Logger; 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 9e82ea56dc..2a7cb1d5bc 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 @@ -587,12 +587,7 @@ public Target createTarget() { */ public Target createTarget(final String controllerId) { final Target target = targetManagement.create(entityFactory.target().create().controllerId(controllerId)); - assertThat(target.getCreatedBy()).isNotNull(); - assertThat(target.getCreatedAt()).isNotNull(); - assertThat(target.getLastModifiedBy()).isNotNull(); - assertThat(target.getLastModifiedAt()).isNotNull(); - - assertThat(target.getUpdateStatus()).isEqualTo(TargetUpdateStatus.UNKNOWN); + assertTargetProperlyCreated(target); return target; } @@ -604,13 +599,17 @@ public Target createTarget(final String controllerId) { public Target createTargetWithName(final String targetName) { final Target target = targetManagement .create(entityFactory.target().create().controllerId(DEFAULT_CONTROLLER_ID).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; } /** From 6a8ff7917d46ce065d6e2957bb2f6f607c2f41cd Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 27 Sep 2019 18:33:50 +0200 Subject: [PATCH 14/22] Refactoring regarding THING_CREATED Signed-off-by: Ammar Bikic --- .../org/eclipse/hawkbit/amqp/AmqpMessageHandlerService.java | 5 +++-- .../org/eclipse/hawkbit/dmf/json/model/DmfCreateThing.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) 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 43d7f564c4..97136629cd 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; @@ -217,7 +218,7 @@ private void registerTarget(final Message message, final String virtualHost) { final DmfCreateThing targetProperties = convertMessage(message, DmfCreateThing.class); // Will be true if "name" properly in body and not just contained in some // attributes - if (targetProperties.getName() != null && targetProperties.getName().length() != 0) { + if (hasText(targetProperties.getName())) { name = targetProperties.getName(); target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, name); } else { @@ -313,7 +314,7 @@ private void updateAttributes(final Message message) { final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL); // If new name provided in body, then change the name - if (attributeUpdate.getName() != null && attributeUpdate.getName().length() != 0) { + if (hasText(attributeUpdate.getName())) { controllerManagement.updateControllerName(thingId, attributeUpdate.getName()); } 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 index 46e6bdc7d3..4e6d84c5e4 100644 --- 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 @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * 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 From 92bced075e68b638e6a9b806e664c0763609610d Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Tue, 1 Oct 2019 14:26:53 +0200 Subject: [PATCH 15/22] Refactoring due to peer review Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerServiceTest.java | 2 -- .../jpa/JpaControllerManagement.java | 28 +++++-------------- 2 files changed, 7 insertions(+), 23 deletions(-) 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 5ab69d2cb4..27c340cd2c 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 @@ -295,8 +295,6 @@ public void updateAttributesWithName() { final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, messageProperties); - final ArgumentCaptor targetNameCaptor = ArgumentCaptor.forClass(String.class); - when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), modeCaptor.capture())).thenReturn(null); doNothing().when(controllerManagementMock).updateControllerName(targetIdCaptor.capture(), targetNameCaptor.capture()); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index c484e88dc6..f7d67eee5b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -13,6 +13,7 @@ import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED; import static org.eclipse.hawkbit.repository.model.Target.CONTROLLER_ATTRIBUTE_KEY_SIZE; import static org.eclipse.hawkbit.repository.model.Target.CONTROLLER_ATTRIBUTE_VALUE_SIZE; +import static org.flywaydb.core.internal.util.StringUtils.hasText; import java.net.URI; import java.time.Duration; @@ -378,11 +379,8 @@ public List getActiveActionsByExternalRef(@NotNull final List ex @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address) { - final Specification spec = (targetRoot, query, cb) -> cb - .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); - - return targetRepository.findOne(spec).map(target -> updateTargetStatus(target, address)) - .orElseGet(() -> createTarget(controllerId, address)); + String name = controllerId; + return findOrRegisterTargetIfItDoesNotExist (controllerId, address, name); } @Override @@ -394,13 +392,13 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); return targetRepository.findOne(spec).map(target -> updateTargetStatus(target, address)) - .orElseGet(() -> createTargetWithName(controllerId, address, name)); + .orElseGet(() -> createTarget(controllerId, address, name)); } - private Target createTargetWithName(final String controllerId, final URI address, final String name) { + private Target createTarget(final String controllerId, final URI address, String name) { // In case of a true expression, the targetId will be set as name - if (name == null || name.length() == 0) { - return createTarget(controllerId, address); + if (!hasText(name)) { + name = controllerId; } final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(name) @@ -413,18 +411,6 @@ private Target createTargetWithName(final String controllerId, final URI address return result; } - private Target createTarget(final String controllerId, final URI address) { - final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() - .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(controllerId) - .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) - .address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build()); - - afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher() - .publishEvent(new TargetPollEvent(result, eventPublisherHolder.getApplicationId()))); - - return result; - } - /** * Flush the update queue by means to persisting * {@link Target#getLastTargetQuery()}. From 10dad685a5da33553da42e182faa5b7f2765b826 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Wed, 2 Oct 2019 15:15:24 +0200 Subject: [PATCH 16/22] Refactoring due to peer review Signed-off-by: Ammar Bikic --- .../hawkbit/repository/jpa/JpaControllerManagement.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index f7d67eee5b..7235ff2fa3 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -13,7 +13,6 @@ import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED; import static org.eclipse.hawkbit.repository.model.Target.CONTROLLER_ATTRIBUTE_KEY_SIZE; import static org.eclipse.hawkbit.repository.model.Target.CONTROLLER_ATTRIBUTE_VALUE_SIZE; -import static org.flywaydb.core.internal.util.StringUtils.hasText; import java.net.URI; import java.time.Duration; @@ -81,6 +80,7 @@ import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; +import org.flywaydb.core.internal.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -397,7 +397,7 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi private Target createTarget(final String controllerId, final URI address, String name) { // In case of a true expression, the targetId will be set as name - if (!hasText(name)) { + if (!StringUtils.hasText(name)) { name = controllerId; } final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() From d9e014c989471a273280bde5f91fe91b6ef9831f Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Tue, 8 Oct 2019 19:32:57 +0200 Subject: [PATCH 17/22] Excluding UPDATE_ATTRIBUTES changes and provide functionality of updating the name property in THING_CREATED message Signed-off-by: Ammar Bikic --- docs/content/apis/dmf_api.md | 2 - .../amqp/AmqpMessageHandlerService.java | 7 +-- .../amqp/AmqpMessageHandlerServiceTest.java | 43 +++------------ .../repository/ControllerManagement.java | 16 ------ .../jpa/JpaControllerManagement.java | 53 ++++++++++--------- .../jpa/ControllerManagementTest.java | 22 ++++++++ 6 files changed, 58 insertions(+), 85 deletions(-) diff --git a/docs/content/apis/dmf_api.md b/docs/content/apis/dmf_api.md index 4d86cc2310..99a21b7840 100644 --- a/docs/content/apis/dmf_api.md +++ b/docs/content/apis/dmf_api.md @@ -98,12 +98,10 @@ Payload Template: "exampleKey1" : "exampleValue1", "exampleKey2" : "exampleValue2" }, - "name": "String", "mode": "String" } ``` -The "name" property specifies the name of the thing. This property is optional.
The "mode" property specifies the update mode that should be applied. This property is optional. Possible [mode](https://github.com/eclipse/hawkbit/tree/master/hawkbit-dmf/hawkbit-dmf-api/src/main/java/org/eclipse/hawkbit/dmf/json/model/DmfUpdateMode.java) values: Value | Description 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 97136629cd..b05460a659 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 @@ -311,12 +311,7 @@ private void handleIncomingEvent(final Message message) { private void updateAttributes(final Message message) { final DmfAttributeUpdate attributeUpdate = convertMessage(message, DmfAttributeUpdate.class); - final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, THING_ID_NULL); - - // If new name provided in body, then change the name - if (hasText(attributeUpdate.getName())) { - controllerManagement.updateControllerName(thingId, attributeUpdate.getName()); - } + final String thingId = getStringHeaderKey(message, MessageHeaderKey.THING_ID, "ThingId is null"); controllerManagement.updateControllerAttributes(thingId, attributeUpdate.getAttributes(), getUpdateMode(attributeUpdate)); 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 27c340cd2c..834bbd1529 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 @@ -14,7 +14,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -27,6 +26,8 @@ import java.util.Map; import java.util.Optional; +import ch.qos.logback.core.net.SyslogOutputStream; +import net.bytebuddy.asm.Advice; import org.eclipse.hawkbit.api.HostnameResolver; import org.eclipse.hawkbit.artifact.repository.ArtifactRepository; import org.eclipse.hawkbit.cache.DownloadIdCache; @@ -36,8 +37,8 @@ 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.DmfDownloadResponse; 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; import org.eclipse.hawkbit.repository.ControllerManagement; @@ -46,6 +47,7 @@ import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder; import org.eclipse.hawkbit.repository.builder.ActionStatusCreate; +import org.eclipse.hawkbit.repository.jpa.TargetRepository; import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; @@ -73,6 +75,7 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import io.qameta.allure.Description; @@ -113,8 +116,8 @@ public class AmqpMessageHandlerServiceTest { @Mock private AmqpControllerAuthentication authenticationManagerMock; - @Mock - private ArtifactRepository artifactRepositoryMock; + @Autowired + TargetRepository targetRepository; @Mock private DownloadIdCache downloadIdCache; @@ -137,9 +140,6 @@ public class AmqpMessageHandlerServiceTest { @Captor private ArgumentCaptor modeCaptor; - @Captor - private ArgumentCaptor targetNameCaptor; - @Before @SuppressWarnings({ "rawtypes", "unchecked" }) public void before() throws Exception { @@ -280,35 +280,6 @@ public void updateAttributes() { } - @Test - @Description("Tests the target attribute update with name update by calling the same method that incoming RabbitMQ messages would access.") - public void updateAttributesWithName() { - final String knownThingId = "1"; - final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); - messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); - messageProperties.setHeader(MessageHeaderKey.TOPIC, "UPDATE_ATTRIBUTES"); - final DmfAttributeUpdate attributeUpdate = new DmfAttributeUpdate(); - attributeUpdate.getAttributes().put("testKey1", "testValue1"); - attributeUpdate.getAttributes().put("testKey2", "testValue2"); - attributeUpdate.setName("UpdatedTargetName"); - - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, - messageProperties); - - when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), - modeCaptor.capture())).thenReturn(null); - doNothing().when(controllerManagementMock).updateControllerName(targetIdCaptor.capture(), targetNameCaptor.capture()); - - amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost"); - - // verify - assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); - assertThat(attributesCaptor.getValue()).as("Attributes is not right") - .isEqualTo(attributeUpdate.getAttributes()); - assertThat(targetNameCaptor.getValue()).as("Thing name is wrong").isEqualTo(attributeUpdate.getName()); - - } - @Test @Description("Verifies that the update mode is retrieved from the UPDATE_ATTRIBUTES message and passed to the controller management.") public void attributeUpdateModes() { 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 b9e3c2c8b1..fc17f55305 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 @@ -370,22 +370,6 @@ Map> findTargetVisibleMetaDataBySoftwareModul Target updateControllerAttributes(@NotEmpty String controllerId, @NotNull Map attributes, UpdateMode mode); - /** - * Updates name of the controller according to the given name - * - * @param controllerId - * to update - * @param controllerName - * the update mode or null - * @return void - * @throws EntityNotFoundException - * if target that has to be updated could not be found - * @throws QuotaExceededException - * if maximum number of attributes per target is exceeded - */ - @PreAuthorize(SpringEvalExpressions.IS_CONTROLLER) - void updateControllerName(final String controllerId, final String controllerName); - /** * Finds {@link Target} based on given controller ID returns found Target * without details, i.e. NO {@link Target#getTags()} and diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 7235ff2fa3..289561d0c9 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -80,7 +80,6 @@ import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; -import org.flywaydb.core.internal.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -98,6 +97,7 @@ import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallback; +import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import com.google.common.collect.Lists; @@ -379,8 +379,8 @@ public List getActiveActionsByExternalRef(@NotNull final List ex @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address) { - String name = controllerId; - return findOrRegisterTargetIfItDoesNotExist (controllerId, address, name); + String name = controllerId; + return findOrRegisterTargetIfItDoesNotExist(controllerId, address, name); } @Override @@ -391,14 +391,14 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi final Specification spec = (targetRoot, query, cb) -> cb .equal(targetRoot.get(JpaTarget_.controllerId), controllerId); - return targetRepository.findOne(spec).map(target -> updateTargetStatus(target, 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, String name) { + private Target createTarget(final String controllerId, final URI address, String name) { // In case of a true expression, the targetId will be set as name if (!StringUtils.hasText(name)) { - name = controllerId; + name = controllerId; } final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(name) @@ -497,16 +497,22 @@ private static String formatQueryInStatementParams(final Collection para * {@link Target#getUpdateStatus()} changes or the buffer queue is full. * */ - private Target updateTargetStatus(final JpaTarget toUpdate, final URI address) { - boolean storeEager = isStoreEager(toUpdate, address); + private Target updateTarget(final JpaTarget toUpdate, final URI address, final String name) { + boolean adressStoreEager = isStoreEager(toUpdate, address); + boolean nameStoreEager = isNameStoreEager(toUpdate, name); if (TargetUpdateStatus.UNKNOWN == toUpdate.getUpdateStatus()) { toUpdate.setUpdateStatus(TargetUpdateStatus.REGISTERED); - storeEager = true; + adressStoreEager = true; } - if (storeEager || !queue.offer(new TargetPoll(toUpdate))) { - toUpdate.setAddress(address.toString()); + if (adressStoreEager || nameStoreEager || !queue.offer(new TargetPoll(toUpdate))) { + if (adressStoreEager) { + toUpdate.setAddress(address.toString()); + } + if (nameStoreEager) { + toUpdate.setName(name); + } toUpdate.setLastTargetQuery(System.currentTimeMillis()); afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher() @@ -528,6 +534,17 @@ private boolean isStoreEager(final JpaTarget toUpdate, final URI address) { } } + private boolean isNameStoreEager(final JpaTarget toUpdate, final String name) { + if (toUpdate.getName() == null) { + return true; + // avoid overwriting once configured name with default (controller id) + } else if (!name.equals(toUpdate.getControllerId())) { + return !toUpdate.getName().equals(name); + } else { + return false; + } + } + @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = { @@ -775,20 +792,6 @@ public Target updateControllerAttributes(final String controllerId, final Map new EntityNotFoundException(Target.class, controllerId)); - - target.setName(controllerName); - - targetRepository.save(target); - } - private static boolean isAttributeEntryValid(final Map.Entry e) { return isAttributeKeyValid(e.getKey()) && isAttributeValueValid(e.getValue()); } 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 300c060017..fc14f45bf1 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 @@ -638,6 +638,28 @@ public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRe } } + @Test + @Description("Register a controller which does not exist, then update the controller twice, first time by preventing 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, when a ConcurrencyFailureException is raised, the " + "exception is not rethrown when the max retries are not yet reached") From 105fb024a6ea7a2fabbad274c1b6c40b7b163728 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Thu, 10 Oct 2019 20:38:54 +0200 Subject: [PATCH 18/22] Refactoring due to peer review Signed-off-by: Ammar Bikic --- docs/content/apis/dmf_api.md | 2 +- .../amqp/AmqpMessageHandlerService.java | 35 +++-- .../amqp/AmqpMessageHandlerServiceTest.java | 61 ++------ .../dmf/json/model/DmfAttributeUpdate.java | 11 -- .../repository/ControllerManagement.java | 2 +- .../jpa/JpaControllerManagement.java | 62 +++----- .../jpa/ControllerManagementTest.java | 137 +----------------- 7 files changed, 62 insertions(+), 248 deletions(-) diff --git a/docs/content/apis/dmf_api.md b/docs/content/apis/dmf_api.md index 99a21b7840..1079587725 100644 --- a/docs/content/apis/dmf_api.md +++ b/docs/content/apis/dmf_api.md @@ -66,7 +66,7 @@ Payload Template (optional): } ``` -The "name" property specifies the name of the thing, which per default is the thing ID. This property is optional. +The "name" property specifies the name of the thing, which by default is the thing ID. This property is optional. ### UPDATE_ATTRIBUTES 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 b05460a659..a2e115c7b2 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 @@ -193,18 +193,18 @@ private static void setTenantSecurityContext(final String tenantId) { } /** - * Method to register a new target. + * 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 message - * the message that contains the target/thing + * 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); final String replyTo = message.getMessageProperties().getReplyTo(); - String name = null; - final Target target; if (StringUtils.isEmpty(replyTo)) { logAndThrowMessageError(message, "No ReplyTo was set for the createThing message."); @@ -212,28 +212,27 @@ private void registerTarget(final Message message, final String virtualHost) { try { final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo); - if (message.toString().contains("name")) { - checkContentTypeJson(message); - // Check whether name property set - final DmfCreateThing targetProperties = convertMessage(message, DmfCreateThing.class); - // Will be true if "name" properly in body and not just contained in some - // attributes - if (hasText(targetProperties.getName())) { - name = targetProperties.getName(); - target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, name); - } else { - target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); - } - } else { + final Target target; + if (!isMessageBodyEmpty(message)) { target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); + } else { + checkContentTypeJson(message); + final DmfCreateThing createThing = convertMessage(message, DmfCreateThing.class); + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, + createThing.getName()); } LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); } catch (final EntityAlreadyExistsException e) { - throw new AmqpRejectAndDontRequeueException("Target already registered, message will be ignored!", e); + throw new AmqpRejectAndDontRequeueException( + "Tried to register previously registered target, message will be ignored!", e); } } + protected static boolean isMessageBodyEmpty(final Message message) { + return message.getBody() == null || message.getBody().length == 0; + } + private void sendUpdateCommandToTarget(final Target target) { if (isMultiAssignmentsEnabled()) { sendCurrentActionsAsMultiActionToTarget(target); 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 834bbd1529..3c761d8d65 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 @@ -26,10 +26,7 @@ import java.util.Map; import java.util.Optional; -import ch.qos.logback.core.net.SyslogOutputStream; -import net.bytebuddy.asm.Advice; import org.eclipse.hawkbit.api.HostnameResolver; -import org.eclipse.hawkbit.artifact.repository.ArtifactRepository; import org.eclipse.hawkbit.cache.DownloadIdCache; import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; @@ -47,7 +44,6 @@ import org.eclipse.hawkbit.repository.UpdateMode; import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder; import org.eclipse.hawkbit.repository.builder.ActionStatusCreate; -import org.eclipse.hawkbit.repository.jpa.TargetRepository; import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; @@ -75,7 +71,6 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.amqp.support.converter.MessageConverter; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import io.qameta.allure.Description; @@ -116,9 +111,6 @@ public class AmqpMessageHandlerServiceTest { @Mock private AmqpControllerAuthentication authenticationManagerMock; - @Autowired - TargetRepository targetRepository; - @Mock private DownloadIdCache downloadIdCache; @@ -137,6 +129,9 @@ public class AmqpMessageHandlerServiceTest { @Captor private ArgumentCaptor targetIdCaptor; + @Captor + private ArgumentCaptor uriCaptor; + @Captor private ArgumentCaptor modeCaptor; @@ -178,14 +173,12 @@ 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 Message message = messageConverter.toMessage(new byte[0], getThingCreatedMessageProperties(knownThingId)); 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()); @@ -202,17 +195,15 @@ public void createThing() { @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 MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); - messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); final DmfCreateThing targetProperties = new DmfCreateThing(); targetProperties.setName("NonDefaultTargetName"); - final Message message = messageConverter.toMessage(targetProperties, messageProperties); + final Message message = messageConverter.toMessage(targetProperties, getThingCreatedMessageProperties(knownThingId)); 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); final ArgumentCaptor targetNameCaptor = ArgumentCaptor.forClass(String.class); when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), @@ -226,34 +217,6 @@ public void createThingWithName() { assertThat(targetNameCaptor.getValue()).as("Thing name is not right").isEqualTo(targetProperties.getName()); } - @Test - @Description("Tests the creation of a target/thing without name but with body by calling the same method that incoming RabbitMQ messages would access.") - public void createThingWithBodyWithoutName() { - final String knownThingId = "3"; - final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); - messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); - final DmfAttributeUpdate attributeUpdate = new DmfAttributeUpdate(); - // put "fake" name in the attributes to also test this behaviour, name - // should still be default (=targetId) - attributeUpdate.getAttributes().put("name", "testValue1"); - - final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, - messageProperties); - - final Target targetMock = mock(Target.class); - - final ArgumentCaptor targetIdCaptor = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor 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, "vHost"); - - assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); - assertThat(uriCaptor.getValue().toString()).as("Uri is not right").isEqualTo("amqp://vHost/MyTest"); - } - @Test @Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.") public void updateAttributes() { @@ -602,4 +565,10 @@ private void initalizeSecurityTokenGenerator() throws IllegalAccessException { } } } + + private MessageProperties getThingCreatedMessageProperties (String thingId){ + final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); + messageProperties.setHeader(MessageHeaderKey.THING_ID, thingId); + return 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 0b36269971..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 @@ -29,9 +29,6 @@ public class DmfAttributeUpdate { @JsonProperty private DmfUpdateMode mode; - @JsonProperty - private String name; - public DmfUpdateMode getMode() { return mode; } @@ -44,12 +41,4 @@ public Map getAttributes() { return attributes; } - 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 fc17f55305..7891367054 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 @@ -207,7 +207,7 @@ Map> findTargetVisibleMetaDataBySoftwareModul /** * 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 Target#getLastTargetQuery()} and {@link Target#getName()} and switches if * {@link TargetUpdateStatus#UNKNOWN} to {@link TargetUpdateStatus#REGISTERED}. * * @param controllerId diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 289561d0c9..5549df5023 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -379,8 +379,7 @@ public List getActiveActionsByExternalRef(@NotNull final List ex @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address) { - String name = controllerId; - return findOrRegisterTargetIfItDoesNotExist(controllerId, address, name); + return findOrRegisterTargetIfItDoesNotExist(controllerId, address, null); } @Override @@ -396,12 +395,9 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi } private Target createTarget(final String controllerId, final URI address, String name) { - // In case of a true expression, the targetId will be set as name - if (!StringUtils.hasText(name)) { - name = controllerId; - } + final Target result = targetRepository.save((JpaTarget) entityFactory.target().create() - .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(name) + .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()); @@ -494,55 +490,39 @@ 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. + * {@link Target#getUpdateStatus()} or {@link Target#getName()} changes or the buffer queue is full. * */ private Target updateTarget(final JpaTarget toUpdate, final URI address, final String name) { - boolean adressStoreEager = isStoreEager(toUpdate, address); - boolean nameStoreEager = isNameStoreEager(toUpdate, name); - - if (TargetUpdateStatus.UNKNOWN == toUpdate.getUpdateStatus()) { - toUpdate.setUpdateStatus(TargetUpdateStatus.REGISTERED); - adressStoreEager = true; - } - - if (adressStoreEager || nameStoreEager || !queue.offer(new TargetPoll(toUpdate))) { - if (adressStoreEager) { + if (isStoreEager(toUpdate, address, name) || !queue.offer(new TargetPoll(toUpdate))) { + if (isAddressChanged(toUpdate.getAddress(), address)) { toUpdate.setAddress(address.toString()); } - if (nameStoreEager) { + 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 isNameStoreEager(final JpaTarget toUpdate, final String name) { - if (toUpdate.getName() == null) { - return true; - // avoid overwriting once configured name with default (controller id) - } else if (!name.equals(toUpdate.getControllerId())) { - return !toUpdate.getName().equals(name); - } else { - return false; - } + 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 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 fc14f45bf1..cf1a3d9c36 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 @@ -505,7 +505,7 @@ public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() { @Test @Description("Register a controller which does not exist") @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetPollEvent.class, count = 2) }) + @Expect(type = TargetPollEvent.class, count = 2)}) public void findOrRegisterTargetIfItDoesNotExist() { final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); assertThat(target).as("target should not be null").isNotNull(); @@ -516,17 +516,16 @@ public void findOrRegisterTargetIfItDoesNotExist() { } @Test - @Description("Register a controller with name which does not exist") + @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 = TargetPollEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 1) }) public void findOrRegisterTargetIfItDoesNotExistWithName() { final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); - assertThat(target).as("target should not be null").isNotNull(); - - final Target sameTarget = 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 equal").isEqualTo(sameTarget.getName()); + 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); } @@ -551,28 +550,6 @@ public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionForInvalidControl .as("register target with too long controllerId should fail"); } - @Test - @Description("Tries to register a target with an invalid controller id") - public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionForInvalidControllerIdParam() { - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy( - () -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST, "TestName")) - .as("register target with null as controllerId should fail"); - - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("", LOCALHOST, "TestName")) - .as("register target with empty controllerId should fail"); - - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST, "TestName")) - .as("register target with empty controllerId should fail"); - - assertThatExceptionOfType(ConstraintViolationException.class) - .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist( - RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST, "TestName")) - .as("register target with too long controllerId should fail"); - } - @Test @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " + "exception is rethrown after max retries") @@ -592,25 +569,6 @@ public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionAfterMaxRetries() } } - @Test - @Description("Register a controller which does not exist, when a ConcurrencyFailureException is raised, the " - + "exception is rethrown after max retries") - public void findOrRegisterTargetIfItDoesNotExistWithNameThrowsExceptionAfterMaxRetries() { - final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); - when(mockTargetRepository.findOne(any())).thenThrow(ConcurrencyFailureException.class); - ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); - - try { - controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); - fail("Expected an ConcurrencyFailureException to be thrown!"); - } catch (final ConcurrencyFailureException e) { - verify(mockTargetRepository, times(TX_RT_MAX)).findOne(any()); - } finally { - // revert - ((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository); - } - } - @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") @@ -660,33 +618,6 @@ public void findOrRegisterTargetIfItDoesNotExistDoesUpdateNameOnExistingTargetPr assertThat(secondTimeUpdatedTarget.getName()).isEqualTo(targetName); } - @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) }) - public void findOrRegisterTargetIfItDoesNotExistWithNameDoesNotThrowExceptionBeforeMaxRetries() { - - final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); - ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); - final Target target = testdataFactory.createTargetWithName("TestName"); - - when(mockTargetRepository.findOne(any())).thenThrow(ConcurrencyFailureException.class) - .thenThrow(ConcurrencyFailureException.class).thenReturn(Optional.of((JpaTarget) target)); - when(mockTargetRepository.save(any())).thenReturn(target); - - try { - final Target targetFromControllerManagement = controllerManagement - .findOrRegisterTargetIfItDoesNotExist(target.getControllerId(), LOCALHOST, "TestName"); - verify(mockTargetRepository, times(3)).findOne(any()); - verify(mockTargetRepository, times(1)).save(any()); - assertThat(target).isEqualTo(targetFromControllerManagement); - } finally { - // revert - ((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository); - } - } - @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") @@ -710,29 +641,6 @@ public void findOrRegisterTargetIfItDoesNotExistDoesntRetryWhenEntityAlreadyExis } } - @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") - public void findOrRegisterTargetIfItDoesNotExistWithNameDoesntRetryWhenEntityAlreadyExistsException() { - - final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); - ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); - - when(mockTargetRepository.findOne(any())).thenReturn(Optional.empty()); - when(mockTargetRepository.save(any())).thenThrow(EntityAlreadyExistsException.class); - - try { - controllerManagement.findOrRegisterTargetIfItDoesNotExist("1234", LOCALHOST, "TestName"); - fail("Expected an EntityAlreadyExistsException to be thrown!"); - } catch (final EntityAlreadyExistsException e) { - verify(mockTargetRepository, times(1)).findOne(any()); - verify(mockTargetRepository, times(1)).save(any()); - } finally { - // revert - ((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository); - } - } - @Test @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " + "rethrown") @@ -754,27 +662,6 @@ public void recoverFindOrRegisterTargetIfItDoesNotExistIsNotInvokedForOtherExcep } } - @Test - @Description("Retry is aborted when an unchecked exception is thrown and the exception should also be " - + "rethrown") - public void recoverFindOrRegisterTargetIfItDoesNotExistWithNameIsNotInvokedForOtherExceptions() { - - final TargetRepository mockTargetRepository = Mockito.mock(TargetRepository.class); - ((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository); - - when(mockTargetRepository.findOne(any())).thenThrow(RuntimeException.class); - - try { - controllerManagement.findOrRegisterTargetIfItDoesNotExist("aControllerId", LOCALHOST, "TestName"); - fail("Expected a RuntimeException to be thrown!"); - } catch (final RuntimeException e) { - verify(mockTargetRepository, times(1)).findOne(any()); - } finally { - // revert - ((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository); - } - } - @Test @Description("Verify that targetVisible metadata is returned from repository") @ExpectEvents({ @Expect(type = DistributionSetCreatedEvent.class, count = 1), @@ -802,16 +689,6 @@ public void targetPollEventNotSendIfDisabled() { repositoryProperties.setPublishTargetPollEvent(true); } - @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) }) - public void targetPollEventNotSendIfDisabledWithName() { - repositoryProperties.setPublishTargetPollEvent(false); - controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST, "TestName"); - repositoryProperties.setPublishTargetPollEvent(true); - } - @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), From 910c45352e367bc338d0dba5776c559abd77b683 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 11 Oct 2019 17:43:20 +0200 Subject: [PATCH 19/22] Refactoring due to peer review Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 21 +++++++++++----- .../eclipse/hawkbit/amqp/BaseAmqpService.java | 2 +- .../amqp/AmqpMessageHandlerServiceTest.java | 25 ++++++++++++++----- .../repository/test/util/TestdataFactory.java | 12 ++++----- 4 files changed, 41 insertions(+), 19 deletions(-) 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 a2e115c7b2..d19cae7aa0 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 @@ -53,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 +85,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService { private static final String THING_ID_NULL = "ThingId is null"; + private static final String EMPTY_MESSAGE_BODY = "\"\""; + /** * Constructor. * @@ -213,13 +216,17 @@ private void registerTarget(final Message message, final String virtualHost) { try { final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo); final Target target; - if (!isMessageBodyEmpty(message)) { + if (isOptionalMessageBodyEmpty(message)) { target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); } else { checkContentTypeJson(message); - final DmfCreateThing createThing = convertMessage(message, DmfCreateThing.class); - target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, - createThing.getName()); + try { + final DmfCreateThing createThing = convertMessage(message, DmfCreateThing.class); + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, createThing.getName()); + } catch (final MessageConversionException e){ + throw new AmqpRejectAndDontRequeueException( + "Tried to register target with wrong body, message will be ignored!", e); + } } LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); @@ -229,8 +236,10 @@ private void registerTarget(final Message message, final String virtualHost) { } } - protected static boolean isMessageBodyEmpty(final Message message) { - return message.getBody() == null || message.getBody().length == 0; + 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) { 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 3c761d8d65..a2d0c7c4e0 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 @@ -173,7 +173,6 @@ 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 Message message = messageConverter.toMessage(new byte[0], getThingCreatedMessageProperties(knownThingId)); final Target targetMock = mock(Target.class); @@ -183,7 +182,7 @@ public void createThing() { uriCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); - amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); + amqpMessageHandlerService.onMessage(createMessage(new byte[0], getThingCreatedMessageProperties(knownThingId)), MessageType.THING_CREATED.name(), TENANT, "vHost"); // verify assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); @@ -198,8 +197,6 @@ public void createThingWithName() { final DmfCreateThing targetProperties = new DmfCreateThing(); targetProperties.setName("NonDefaultTargetName"); - final Message message = messageConverter.toMessage(targetProperties, getThingCreatedMessageProperties(knownThingId)); - final Target targetMock = mock(Target.class); targetIdCaptor = ArgumentCaptor.forClass(String.class); @@ -210,13 +207,25 @@ public void createThingWithName() { uriCaptor.capture(), targetNameCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); - amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, "vHost"); + 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"; + + try { + amqpMessageHandlerService.onMessage(createMessage("Not allowed Body".getBytes(), getThingCreatedMessageProperties(knownThingId)), MessageType.THING_CREATED.name(), TENANT, "vHost"); + fail("AmqpRejectAndDontRequeueException was excepeted due to wrong body"); + } catch (final AmqpRejectAndDontRequeueException e) { + } + } + @Test @Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.") public void updateAttributes() { @@ -566,9 +575,13 @@ private void initalizeSecurityTokenGenerator() throws IllegalAccessException { } } - private MessageProperties getThingCreatedMessageProperties (String thingId){ + 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-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 2a7cb1d5bc..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 @@ -586,24 +586,24 @@ public Target createTarget() { * @return persisted {@link Target} */ public Target createTarget(final String controllerId) { - final Target target = targetManagement.create(entityFactory.target().create().controllerId(controllerId)); - assertTargetProperlyCreated(target); - return target; + return createTarget(controllerId, controllerId); } /** + * @param controllerId + * of the target * @param targetName * name of the target * @return persisted {@link Target} */ - public Target createTargetWithName(final String targetName) { + public Target createTarget(final String controllerId, final String targetName) { final Target target = targetManagement - .create(entityFactory.target().create().controllerId(DEFAULT_CONTROLLER_ID).name(targetName)); + .create(entityFactory.target().create().controllerId(controllerId).name(targetName)); assertTargetProperlyCreated(target); return target; } - private void assertTargetProperlyCreated (Target target){ + private void assertTargetProperlyCreated(Target target) { assertThat(target.getCreatedBy()).isNotNull(); assertThat(target.getCreatedAt()).isNotNull(); assertThat(target.getLastModifiedBy()).isNotNull(); From c7ba85c241c0f7026886b4321c0944b8cb098d66 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Fri, 11 Oct 2019 20:23:34 +0200 Subject: [PATCH 20/22] Fix SonarQube finding Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerService.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) 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 d19cae7aa0..3e1b65ebcf 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 @@ -220,13 +220,9 @@ private void registerTarget(final Message message, final String virtualHost) { target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); } else { checkContentTypeJson(message); - try { - final DmfCreateThing createThing = convertMessage(message, DmfCreateThing.class); - target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, createThing.getName()); - } catch (final MessageConversionException e){ - throw new AmqpRejectAndDontRequeueException( - "Tried to register target with wrong body, message will be ignored!", e); - } + + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, tryConvertThingCreatedMessage(message).getName()); + } LOG.debug("Target {} reported online state.", thingId); sendUpdateCommandToTarget(target); @@ -236,6 +232,15 @@ private void registerTarget(final Message message, final String virtualHost) { } } + private DmfCreateThing tryConvertThingCreatedMessage (Message message){ + try { + return convertMessage(message, DmfCreateThing.class); + } catch (final MessageConversionException e){ + throw new AmqpRejectAndDontRequeueException( + "Tried to register target with wrong body, 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 From a4f4fc9fda9ba37fb2afa8c02897aec67d1a77b0 Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Mon, 14 Oct 2019 17:31:27 +0200 Subject: [PATCH 21/22] Merge master into current branch Signed-off-by: Ammar Bikic --- .../amqp/AmqpMessageHandlerServiceTest.java | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) 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 9525843609..943189bf4f 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 @@ -83,8 +83,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"; @@ -189,11 +189,13 @@ public void createThing() { uriCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOldestActiveActionByTarget(any())).thenReturn(Optional.empty()); - amqpMessageHandlerService.onMessage(createMessage(new byte[0], getThingCreatedMessageProperties(knownThingId)), 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 @@ -213,7 +215,9 @@ public void createThingWithName() { 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"); + 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"); @@ -225,11 +229,11 @@ public void createThingWithName() { public void createThingWithWrongBody() { final String knownThingId = "3"; - try { - amqpMessageHandlerService.onMessage(createMessage("Not allowed Body".getBytes(), getThingCreatedMessageProperties(knownThingId)), MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST); - fail("AmqpRejectAndDontRequeueException was excepeted due to wrong body"); - } catch (final AmqpRejectAndDontRequeueException e) { - } + assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) + .as("AmqpRejectAndDontRequeueException was excepeted due to wrong body") + .isThrownBy(() -> amqpMessageHandlerService.onMessage( + createMessage("Not allowed Body".getBytes(), getThingCreatedMessageProperties(knownThingId)), + MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST)); } @Test @@ -345,15 +349,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) @@ -569,12 +571,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); } @@ -591,14 +593,13 @@ public void deleteThingWithoutThingId() { 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){ + private Message createMessage(Object object, MessageProperties messageProperties) { return messageConverter.toMessage(object, messageProperties); } } From 0ef709070e10a2a68da80e978016eaeff45e837e Mon Sep 17 00:00:00 2001 From: Ammar Bikic Date: Wed, 16 Oct 2019 15:29:09 +0200 Subject: [PATCH 22/22] Fix peer review findings Signed-off-by: Ammar Bikic --- .../hawkbit/amqp/AmqpMessageHandlerService.java | 11 +---------- .../hawkbit/amqp/AmqpMessageHandlerServiceTest.java | 5 +++-- .../repository/jpa/ControllerManagementTest.java | 2 +- 3 files changed, 5 insertions(+), 13 deletions(-) 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 7a9ab71132..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 @@ -227,7 +227,7 @@ private void registerTarget(final Message message, final String virtualHost) { } else { checkContentTypeJson(message); - target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, tryConvertThingCreatedMessage(message).getName()); + target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, convertMessage(message, DmfCreateThing.class).getName()); } LOG.debug("Target {} reported online state.", thingId); @@ -238,15 +238,6 @@ private void registerTarget(final Message message, final String virtualHost) { } } - private DmfCreateThing tryConvertThingCreatedMessage (Message message){ - try { - return convertMessage(message, DmfCreateThing.class); - } catch (final MessageConversionException e){ - throw new AmqpRejectAndDontRequeueException( - "Tried to register target with wrong body, 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 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 943189bf4f..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 @@ -71,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; @@ -229,8 +230,8 @@ public void createThingWithName() { public void createThingWithWrongBody() { final String knownThingId = "3"; - assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) - .as("AmqpRejectAndDontRequeueException was excepeted due to wrong body") + 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)); 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 647231d4dc..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 @@ -595,7 +595,7 @@ public void findOrRegisterTargetIfItDoesNotExistDoesNotThrowExceptionBeforeMaxRe } @Test - @Description("Register a controller which does not exist, then update the controller twice, first time by preventing a name property and second time without a new name") + @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)})