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:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ public class DmfActionUpdateStatus {
|
||||
@JsonProperty
|
||||
private List<String> message;
|
||||
|
||||
public DmfActionUpdateStatus(@JsonProperty(value = "actionId", required = true) Long actionId,
|
||||
@JsonProperty(value = "actionStatus", required = true) DmfActionStatus actionStatus) {
|
||||
public DmfActionUpdateStatus(@JsonProperty(value = "actionId", required = true) final Long actionId,
|
||||
@JsonProperty(value = "actionStatus", required = true) final DmfActionStatus actionStatus) {
|
||||
this.actionId = actionId;
|
||||
this.actionStatus = actionStatus;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user