Feature download only (#810)

* Added initial version of DOWNLOAD_ONLY
* Added DOWNLOAD_ONLY option to ActionTypeOptionGroupLayout
* Removed DOWNLOAD_ONLY checkbox, added Download Only UI option
* Mark actions that finished with DOWNLOADED as finished
* initial changes to realize downoadOnly in UI
* Changed method of disabling maintenanceWindow into smarter solution
* Added new icon for download only option
* Set DistributionSet as unassigned when DOWNLOAD_ONLY
* Enabled update action status for DOWNLOAD_ONLY after download
* Current state of abstraction task
* Assign DistributionSet to target if target installs it after downloading
* Abstracted class redundant methods
* Added tests
* Fixed Rollout finish status for DWONLOAD_ONLY Rollouts
* Added Rollout type json property in test documentation
* Added DOWNLOAD_ONLY test for target assignment
* Added event listener also to DistributionTable
* Fixed event listener problem
* Change column name to "Type" and added also DownloadOnly icon to that column.
* Cleanup
* Center aligned the icons in type column
* Fixed DistributionSet already assigned but not installed
* Rename download_only to downloadonly
* Further changes regarding center aligned the icons
* Fixed target assign status in Rollout view when download_only
* Fixed SonarQube issues
* Fixed SonarQube issues + code formatting
* Fixed Tests
* Marked squid:S128 as suppressed - irrelevant
* Adapting rollouts view by additional column (not finished by now)
* Putted type column on proper position
* Trying to display icons in new type column in rollouts view
* Added icon also for soft, icon might change -> just change
* createOptionGroup method in ActionTypeOptionGroupLayout class
* added first draft of type column in rollouts view
* increase visibility of sendUpdateMessageToTarget method
* Ground functionality of new type column in deployment view is now implemented
* Type column implementation in rollouts view is finished for now
* Rebased on master
* Fixed DurationControl change on ScheduleControl change.
* (Re)Added Soft deployment Icon
* Fixed SonarQube issues
* Fixed SonarQube issues
* Fixed failing test
* Fixes + added missing header
* Added message to the fail() instruction
* Fixed copyright header
* Apply suggestions from code review
* Fixed TotalTargetCountStatus.java
* Removed unused method from TotalTargetCountStatus.java
* add id to rollout create and update UI popup
* Added download_only tests for MgmtTargetResourceTest.java
* added missing header in TotalTargetCountStatusTest.java
* Rename because of newest changes
* added Download_Only dmf integration tests
* Renamed MgmtAction.forcedType to actionType
* renamed actionType to forceType for Mgmt API
* added missing javadocs for public methods
* Added Download Only support for AutoAssignment

Signed-off-by: Ahmed Sayed <ahmed.sayed@bosch-si.com>
Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>
This commit is contained in:
Ahmed Sayed
2019-04-17 12:27:23 +02:00
committed by Stefan Behl
parent 04b9abda3b
commit ed95ae6398
76 changed files with 1754 additions and 639 deletions

View File

@@ -133,7 +133,6 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService {
checkByTargetId(sha1Hash, secruityToken.getTargetId());
} else {
LOG.info("anonymous download no authentication check for artifact {}", sha1Hash);
return;
}
}

View File

@@ -270,6 +270,12 @@ public class AmqpConfiguration {
return new DefaultAmqpMessageSenderService(rabbitTemplate());
}
/**
* Create RabbitListenerContainerFactory bean if no listenerContainerFactory
* bean found
*
* @return RabbitListenerContainerFactory bean
*/
@Bean
@ConditionalOnMissingBean(name = "listenerContainerFactory")
public RabbitListenerContainerFactory<SimpleMessageListenerContainer> listenerContainerFactory(

View File

@@ -38,6 +38,8 @@ import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEv
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionProperties;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
@@ -143,28 +145,28 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), module.getId())
.getContent()));
targetManagement.getByControllerID(assignedEvent.getActions().keySet())
.forEach(target -> sendUpdateMessageToTarget(assignedEvent.getTenant(), target,
assignedEvent.getActions().get(target.getControllerId()), modules,
assignedEvent.isMaintenanceWindowAvailable()));
targetManagement.getByControllerID(assignedEvent.getActions().keySet()).forEach(
target -> sendUpdateMessageToTarget(assignedEvent.getActions().get(target.getControllerId()),
target, modules));
});
}
/**
* Method to get the type of event depending on whether the action has a
* valid maintenance window available or not based on defined maintenance
* schedule. In case of no maintenance schedule or if there is a valid
* window available, the topic {@link EventTopic#DOWNLOAD_AND_INSTALL} is
* Method to get the type of event depending on whether the action is a
* DOWNLOAD_ONLY action or if it has a valid maintenance window available
* or not based on defined maintenance schedule. In case of no maintenance
* schedule or if there is a valid window available, the topic {@link EventTopic#DOWNLOAD_AND_INSTALL} is
* returned else {@link EventTopic#DOWNLOAD} is returned.
*
* @param maintenanceWindowAvailable
* valid maintenance window or not.
* @param action
* current action properties.
*
* @return {@link EventTopic} to use for message.
*/
private static EventTopic getEventTypeForTarget(final boolean maintenanceWindowAvailable) {
return maintenanceWindowAvailable ? EventTopic.DOWNLOAD_AND_INSTALL : EventTopic.DOWNLOAD;
private static EventTopic getEventTypeForTarget(final ActionProperties action) {
return (Action.ActionType.DOWNLOAD_ONLY.equals(action.getActionType()) ||
!action.isMaintenanceWindowAvailable()) ? EventTopic.DOWNLOAD : EventTopic.DOWNLOAD_AND_INSTALL;
}
/**
@@ -206,8 +208,10 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
updateAttributesEvent.getTargetAddress());
}
protected void sendUpdateMessageToTarget(final String tenant, final Target target, final Long actionId,
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules, final boolean maintenanceWindowAvailable) {
protected void sendUpdateMessageToTarget(final ActionProperties action, final Target target,
final Map<SoftwareModule, List<SoftwareModuleMetadata>> modules) {
String tenant = action.getTenant();
final URI targetAdress = target.getAddress();
if (!IpUtil.isAmqpUri(targetAdress)) {
@@ -215,7 +219,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = new DmfDownloadAndUpdateRequest();
downloadAndUpdateRequest.setActionId(actionId);
downloadAndUpdateRequest.setActionId(action.getId());
final String targetSecurityToken = systemSecurityContext.runAsSystem(target::getSecurityToken);
downloadAndUpdateRequest.setTargetSecurityToken(targetSecurityToken);
@@ -227,8 +231,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
});
final Message message = getMessageConverter().toMessage(downloadAndUpdateRequest,
createConnectorMessagePropertiesEvent(tenant, target.getControllerId(),
getEventTypeForTarget(maintenanceWindowAvailable)));
createConnectorMessagePropertiesEvent(tenant, target.getControllerId(), getEventTypeForTarget(action)));
amqpSenderService.sendMessage(message, targetAdress);
}

View File

@@ -31,6 +31,7 @@ import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
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.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.Target;
@@ -218,8 +219,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
action.getDistributionSet().getModules().forEach(module -> modules.put(module, metadata.get(module.getId())));
amqpMessageDispatcherService.sendUpdateMessageToTarget(action.getTenant(), action.getTarget(), action.getId(),
modules, action.isMaintenanceWindowAvailable());
amqpMessageDispatcherService.sendUpdateMessageToTarget(new ActionProperties(action), action.getTarget(),
modules);
}
/**

View File

@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.amqp;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
@@ -46,6 +45,7 @@ import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
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.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
@@ -301,7 +301,7 @@ public class AmqpMessageHandlerServiceTest {
final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT);
final Message message = new Message(new byte[0], messageProperties);
try {
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost");
amqpMessageHandlerService.onMessage(message, "unknownMessageType", TENANT, "vHost");
fail("AmqpRejectAndDontRequeueException was excepeted due to unknown message type");
} catch (final AmqpRejectAndDontRequeueException e) {
}
@@ -462,19 +462,16 @@ public class AmqpMessageHandlerServiceTest {
// test
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, "vHost");
final ArgumentCaptor<String> tenantCaptor = ArgumentCaptor.forClass(String.class);
final ArgumentCaptor<ActionProperties> actionPropertiesCaptor = ArgumentCaptor.forClass(ActionProperties.class);
final ArgumentCaptor<Target> targetCaptor = ArgumentCaptor.forClass(Target.class);
final ArgumentCaptor<Long> actionIdCaptor = ArgumentCaptor.forClass(Long.class);
verify(amqpMessageDispatcherServiceMock, times(1)).sendUpdateMessageToTarget(tenantCaptor.capture(),
targetCaptor.capture(), actionIdCaptor.capture(), any(Map.class), anyBoolean());
final String tenant = tenantCaptor.getValue();
final String controllerId = targetCaptor.getValue().getControllerId();
final Long actionId = actionIdCaptor.getValue();
assertThat(tenant).as("event has tenant").isEqualTo("DEFAULT");
assertThat(controllerId).as("event has wrong controller id").isEqualTo("target1");
assertThat(actionId).as("event has wrong action id").isEqualTo(22L);
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");
assertThat(targetCaptor.getValue().getControllerId()).as("event has wrong controller id").isEqualTo("target1");
assertThat(actionProperties.getId()).as("event has wrong action id").isEqualTo(22L);
}
@@ -516,6 +513,7 @@ public class AmqpMessageHandlerServiceTest {
when(actionMock.getId()).thenReturn(targetId);
when(actionMock.getTenant()).thenReturn("DEFAULT");
when(actionMock.getTarget()).thenReturn(targetMock);
when(actionMock.getActionType()).thenReturn(Action.ActionType.SOFT);
when(targetMock.getControllerId()).thenReturn("target1");
return actionMock;
}

View File

@@ -34,6 +34,7 @@ import org.eclipse.hawkbit.matcher.SoftwareModuleJsonMatcher;
import org.eclipse.hawkbit.rabbitmq.test.AbstractAmqpIntegrationTest;
import org.eclipse.hawkbit.rabbitmq.test.AmqpTestConfiguration;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -235,7 +236,7 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
assertThat(targetManagement.count()).isEqualTo(expectedTargetsCount);
}
private Message assertReplyMessageHeader(final EventTopic eventTopic, final String controllerId) {
protected Message assertReplyMessageHeader(final EventTopic eventTopic, final String controllerId) {
verifyReplyToListener();
final Message replyMessage = replyToListener.getEventTopicMessages().get(eventTopic);
assertAllTargetsCount(1);
@@ -379,4 +380,16 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
return AmqpSettings.DMF_EXCHANGE;
}
@Step
protected DistributionSet createTargetAndDistributionSetAndAssign(final String controllerId,
final Action.ActionType actionType) {
registerAndAssertTargetWithExistingTenant(controllerId);
final DistributionSet distributionSet = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
testdataFactory.addSoftwareModuleMetadata(distributionSet);
assignDistributionSet(distributionSet.getId(), controllerId, actionType);
return distributionSet;
}
}

View File

@@ -8,10 +8,12 @@
*/
package org.eclipse.hawkbit.integration;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.Callable;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
@@ -25,6 +27,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedE
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.Target;
@@ -32,12 +35,18 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.amqp.core.Message;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.DOWNLOAD;
import static org.eclipse.hawkbit.dmf.amqp.api.MessageType.EVENT;
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
@Feature("Component Tests - Device Management Federation API")
@Story("Amqp Message Dispatcher Service")
public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpServiceIntegrationTest {
@@ -198,6 +207,37 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
assertRequestAttributesUpdateMessage(controllerId);
}
@Test
@Description("Tests the download_only assignment: asserts correct dmf Message topic, and assigned DS")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) })
public void downloadOnlyAssignmentSendsDownloadMessageTopic() {
final String controllerId = TARGET_PREFIX + "registerTargets_1";
final DistributionSet distributionSet = createTargetAndDistributionSetAndAssign(controllerId, DOWNLOAD_ONLY);
// verify
final Message message = assertReplyMessageHeader(EventTopic.DOWNLOAD, controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener());
assertThat(message).isNotNull();
final Map<String, Object> headers = message.getMessageProperties().getHeaders();
assertThat(headers).containsEntry("thingId", controllerId);
assertThat(headers).containsEntry("type", EVENT.toString());
assertThat(headers).containsEntry("topic", DOWNLOAD.toString());
final Optional<Target> target = controllerManagement.getByControllerId(controllerId);
assertThat(target).isPresent();
// verify the DS was assigned to the Target
final DistributionSet assignedDistributionSet = ((JpaTarget) target.get()).getAssignedDistributionSet();
assertThat(assignedDistributionSet.getId()).isEqualTo(distributionSet.getId());
}
private void waitUntilTargetHasStatus(final String controllerId, final TargetUpdateStatus status) {
waitUntil(() -> {
final Optional<Target> findTargetByControllerID = targetManagement.getByControllerID(controllerId);

View File

@@ -9,14 +9,20 @@
package org.eclipse.hawkbit.integration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.eclipse.hawkbit.amqp.AmqpProperties;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
@@ -37,6 +43,8 @@ import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedE
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -797,6 +805,99 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
verifyNumberOfDeadLetterMessages(3);
}
@Test
@Description("Tests the download_only assignment: tests the handling of a target reporting DOWNLOADED")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetPollEvent.class, count = 1) })
public void downloadOnlyAssignmentFinishesActionWhenTargetReportsDownloaded()
throws IOException {
// create target
final String controllerId = TARGET_PREFIX + "registerTargets_1";
final DistributionSet distributionSet = createTargetAndDistributionSetAndAssign(controllerId, DOWNLOAD_ONLY);
// verify
final Message message = assertReplyMessageHeader(EventTopic.DOWNLOAD, controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener());
// get actionId from Message
Long actionId = Long.parseLong(getJsonFieldFromBody(message.getBody(), "actionId"));
// Send DOWNLOADED message
sendActionUpdateStatus(new DmfActionUpdateStatus(actionId, DmfActionStatus.DOWNLOADED));
assertAction(actionId, 1, Status.RUNNING, Status.DOWNLOADED);
Mockito.verifyZeroInteractions(getDeadletterListener());
verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), null);
}
@Test
@Description("Tests the download_only assignment: tests the handling of a target reporting FINISHED")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetAttributesRequestedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 3),
@Expect(type = TargetPollEvent.class, count = 1) })
public void downloadOnlyAssignmentAllowsActionStatusUpdatesWhenTargetReportsFinishedAndUpdatesInstalledDS()
throws IOException {
// create target
final String controllerId = TARGET_PREFIX + "registerTargets_1";
final DistributionSet distributionSet = createTargetAndDistributionSetAndAssign(controllerId, DOWNLOAD_ONLY);
// verify
final Message message = assertReplyMessageHeader(EventTopic.DOWNLOAD, controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener());
// get actionId from Message
Long actionId = Long.parseLong(getJsonFieldFromBody(message.getBody(), "actionId"));
// Send DOWNLOADED message, should result in the action being closed
sendActionUpdateStatus(new DmfActionUpdateStatus(actionId, DmfActionStatus.DOWNLOADED));
assertAction(actionId, 1, Status.RUNNING, Status.DOWNLOADED);
Mockito.verifyZeroInteractions(getDeadletterListener());
verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), null);
// Send FINISHED message
sendActionUpdateStatus(new DmfActionUpdateStatus(actionId, DmfActionStatus.FINISHED));
assertAction(actionId, 2, Status.RUNNING, Status.DOWNLOADED, Status.FINISHED);
Mockito.verifyZeroInteractions(getDeadletterListener());
verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), distributionSet.getId());
}
@Step
private void verifyAssignedDsAndInstalledDs(final String controllerId, final Long assignedDsId,
final Long installedDsId) {
final Optional<Target> target = controllerManagement.getByControllerId(controllerId);
assertThat(target).isPresent();
// verify the DS was assigned to the Target
final DistributionSet assignedDistributionSet = ((JpaTarget) target.get()).getAssignedDistributionSet();
assertThat(assignedDsId).isNotNull();
assertThat(assignedDistributionSet.getId()).isEqualTo(assignedDsId);
// verify that the installed DS was not affected
final JpaDistributionSet installedDistributionSet = ((JpaTarget) target.get()).getInstalledDistributionSet();
if (installedDsId == null) {
assertThat(installedDistributionSet).isNull();
} else {
assertThat(installedDistributionSet.getId()).isEqualTo(installedDsId);
}
}
private void sendUpdateAttributesMessageWithGivenAttributes(final String target, final String key,
final String value) {
final DmfAttributeUpdate controllerAttribute = new DmfAttributeUpdate();
@@ -887,4 +988,11 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
createConditionFactory().untilAsserted(() -> Mockito
.verify(getDeadletterListener(), Mockito.times(numberOfInvocations)).handleMessage(Mockito.any()));
}
private static String getJsonFieldFromBody(final byte[] body, final String fieldName) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
final ObjectNode node = objectMapper.readValue(new String(body, Charset.defaultCharset()), ObjectNode.class);
assertThat(node.has(fieldName)).isTrue();
return node.get(fieldName).asText();
}
}