Feature/type for multi actions (#986)

* Introduce different types of Multi Action Event to distinguish between an Assignment and a Cancel.
* Minimize the payload for the multiAction assignment and cancel event. Write tests for the MultiActionCancelEvent.
* Remove unused action status.
* Move list of actionIds to MultiActionEvent and declare it as abstract.
* Remove unused imports.

Signed-off-by: Michael Herdt <Michael.Herdt2@bosch-si.com>
This commit is contained in:
Michael Herdt
2020-09-25 13:12:42 +02:00
committed by GitHub
parent 1b92b653da
commit e82b9cee70
9 changed files with 291 additions and 102 deletions

View File

@@ -8,17 +8,6 @@
*/
package org.eclipse.hawkbit.amqp;
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.api.ApiType;
import org.eclipse.hawkbit.api.ArtifactUrl;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
@@ -66,6 +55,17 @@ import org.springframework.context.event.EventListener;
import org.springframework.data.domain.PageRequest;
import org.springframework.util.CollectionUtils;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
/**
* {@link AmqpMessageDispatcherService} create all outgoing AMQP messages and
* delegate the messages to a {@link AmqpMessageSenderService}.
@@ -104,8 +104,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
* @param targetManagement
* to access target information
* @param serviceMatcher
* to check in cluster case if the message is from the same
* cluster node
* to check in cluster case if the message is from the same cluster
* node
* @param distributionSetManagement
* to retrieve modules
*/
@@ -128,8 +128,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
/**
* Method to send a message to a RabbitMQ Exchange after the Distribution
* set has been assign to a Target.
* Method to send a message to a RabbitMQ Exchange after the Distribution set
* has been assign to a Target.
*
* @param assignedEvent
* the object to be send.
@@ -157,7 +157,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
/**
* Listener for Multi-Action events.
*
* @param e
* @param multiActionEvent
* the Multi-Action event to be processed
*/
@EventListener(classes = MultiActionEvent.class)
@@ -242,9 +242,9 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
/**
* 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
* 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.
*
@@ -260,8 +260,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
/**
* Determines the {@link EventTopic} for the given {@link Action}, depending
* on its action type.
* Determines the {@link EventTopic} for the given {@link Action}, depending on
* its action type.
*
* @param action
* to obtain the corresponding {@link EventTopic} for
@@ -276,8 +276,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
/**
* Method to send a message to a RabbitMQ Exchange after the assignment of
* the Distribution set to a Target has been canceled.
* Method to send a message to a RabbitMQ Exchange after the assignment of the
* Distribution set to a Target has been canceled.
*
* @param cancelEvent
* that is to be converted to a DMF message
@@ -300,12 +300,11 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
}
/**
* Method to send a message to a RabbitMQ Exchange after a Target was
* deleted.
* Method to send a message to a RabbitMQ Exchange after a Target was deleted.
*
* @param deleteEvent
* the TargetDeletedEvent which holds the necessary data for
* sending a target delete message.
* the TargetDeletedEvent which holds the necessary data for sending
* a target delete message.
*/
@EventListener(classes = TargetDeletedEvent.class)
protected void targetDelete(final TargetDeletedEvent deleteEvent) {
@@ -488,4 +487,4 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), module.getId()).getContent();
}
}
}

View File

@@ -8,23 +8,9 @@
*/
package org.eclipse.hawkbit.integration;
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;
import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.json.model.DmfActionRequest;
@@ -34,7 +20,8 @@ import org.eclipse.hawkbit.dmf.json.model.DmfMultiActionRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMultiActionRequest.DmfMultiActionElement;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.event.remote.MultiActionEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
@@ -66,9 +53,22 @@ 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 java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
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")
@@ -164,7 +164,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
@Test
@Description("If multi assignment is enabled multi-action messages are sent.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = MultiActionEvent.class, count = 2),
@Expect(type = MultiActionAssignEvent.class, count = 2),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = ActionUpdatedEvent.class, count = 0),
@@ -247,7 +247,8 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
@Test
@Description("Handle cancelation process of an action in multi assignment mode.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = MultiActionEvent.class, count = 3),
@Expect(type = MultiActionCancelEvent.class, count = 1),
@Expect(type = MultiActionAssignEvent.class, count = 2),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = ActionUpdatedEvent.class, count = 2),
@@ -278,7 +279,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
@Test
@Description("Handle finishing an action in multi assignment mode.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = MultiActionEvent.class, count = 2),
@Expect(type = MultiActionAssignEvent.class, count = 2),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
@@ -305,7 +306,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
@Test
@Description("If multi assignment is enabled assigning a DS multiple times creates a new action every time.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = MultiActionEvent.class, count = 2),
@Expect(type = MultiActionAssignEvent.class, count = 2),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = ActionUpdatedEvent.class, count = 0),
@@ -349,7 +350,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
@Test
@Description("If multi assignment is enabled multiple rollouts with the same DS lead to multiple actions.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = MultiActionEvent.class, count = 2),
@Expect(type = MultiActionAssignEvent.class, count = 2),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0),
@Expect(type = CancelTargetAssignmentEvent.class, count = 0),
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = ActionUpdatedEvent.class, count = 2),
@@ -380,7 +381,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
@Test
@Description("If multi assignment is enabled finishing one rollout does not affect other rollouts of the target.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = MultiActionEvent.class, count = 3), @Expect(type = ActionCreatedEvent.class, count = 3),
@Expect(type = MultiActionAssignEvent.class, count = 3), @Expect(type = ActionCreatedEvent.class, count = 3),
@Expect(type = ActionUpdatedEvent.class, count = 5),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),

View File

@@ -0,0 +1,47 @@
/**
* Copyright (c) 2020 Bosch.IO 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.repository.event.remote;
import org.eclipse.hawkbit.repository.model.Action;
import java.util.List;
/**
* Generic deployment event for the Multi-Assignments feature. The event extends
* the {@link MultiActionEvent} and holds a list of controller IDs to identify
* the targets which are affected by a deployment action and a list of
* actionIds containing the identifiers of the affected actions
* as payload. This event is only published in case of an assignment.
*/
public class MultiActionAssignEvent extends MultiActionEvent {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public MultiActionAssignEvent() {
// for serialization libs like jackson
}
/**
* Constructor.
*
* @param tenant
* tenant the event is scoped to
* @param applicationId
* the application id
* @param actions
* the actions of the deployment action
*/
public MultiActionAssignEvent(String tenant, String applicationId, List<Action> actions) {
super(tenant, applicationId, actions);
}
}

View File

@@ -0,0 +1,47 @@
/**
* Copyright (c) 2020 Bosch.IO 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.repository.event.remote;
import java.util.List;
import org.eclipse.hawkbit.repository.model.Action;
/**
* Generic deployment event for the Multi-Assignments feature. The event extends
* the {@link MultiActionEvent} and holds a list of controller IDs to identify
* the targets which are affected by a deployment action and a list of
* actionIds containing the identifiers of the affected actions
* as payload. This event is only published in case of an cancellation.
*/
public class MultiActionCancelEvent extends MultiActionEvent {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public MultiActionCancelEvent() {
// for serialization libs like jackson
}
/**
* Constructor.
*
* @param tenant
* tenant the event is scoped to
* @param applicationId
* the application id
* @param actions
* the actions to be canceled
*/
public MultiActionCancelEvent(String tenant, String applicationId, List<Action> actions) {
super(tenant, applicationId, actions);
}
}

View File

@@ -8,9 +8,14 @@
*/
package org.eclipse.hawkbit.repository.event.remote;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Target;
import org.springframework.hateoas.Identifiable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
/**
* Generic deployment event for the Multi-Assignments feature. The event payload
@@ -18,11 +23,12 @@ import java.util.List;
* a deployment action (e.g. a software assignment (update) or a cancellation of
* an update).
*/
public class MultiActionEvent extends RemoteTenantAwareEvent implements Iterable<String> {
public abstract class MultiActionEvent extends RemoteTenantAwareEvent implements Iterable<String> {
private static final long serialVersionUID = 1L;
private final List<String> controllerIds = new ArrayList<>();
private final List<Long> actionIds = new ArrayList<>();
/**
* Default constructor.
@@ -33,17 +39,18 @@ public class MultiActionEvent extends RemoteTenantAwareEvent implements Iterable
/**
* Constructor.
*
*
* @param tenant
* tenant the event is scoped to
* @param applicationId
* the application id
* @param controllerIds
* the controller IDs of the affected targets
* @param actions
* the actions involved
*/
public MultiActionEvent(final String tenant, final String applicationId, final List<String> controllerIds) {
public MultiActionEvent(String tenant, String applicationId, List<Action> actions) {
super(applicationId, tenant, applicationId);
this.controllerIds.addAll(controllerIds);
this.controllerIds.addAll(getControllerIdsFromActions(actions));
this.actionIds.addAll(getIdsFromActions(actions));
}
public List<String> getControllerIds() {
@@ -55,4 +62,17 @@ public class MultiActionEvent extends RemoteTenantAwareEvent implements Iterable
return controllerIds.iterator();
}
}
public List<Long> getActionIds() {
return actionIds;
}
private static List<String> getControllerIdsFromActions(final List<Action> actions) {
return actions.stream().map(Action::getTarget).map(Target::getControllerId).distinct()
.collect(Collectors.toList());
}
private static List<Long> getIdsFromActions(final List<Action> actions) {
return actions.stream().map(Identifiable::getId).collect(Collectors.toList());
}
}

View File

@@ -17,7 +17,8 @@ import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTagDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTypeDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.RolloutGroupDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent;
@@ -135,7 +136,8 @@ public class EventType {
TYPES.put(37, TargetAttributesRequestedEvent.class);
// deployment event for assignments and /or cancellations
TYPES.put(38, MultiActionEvent.class);
TYPES.put(38, MultiActionAssignEvent.class);
TYPES.put(39, MultiActionCancelEvent.class);
}
private int value;

View File

@@ -18,7 +18,8 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.event.remote.MultiActionEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
@@ -144,14 +145,14 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
void cancelAssignment(final JpaAction action) {
if (isMultiAssignmentsEnabled()) {
sendMultiActionEvent(action.getTarget());
sendMultiActionCancelEvent(action);
} else {
cancelAssignDistributionSetEvent(action.getTarget(), action.getId());
}
}
private void sendMultiActionEvent(final Target target) {
sendMultiActionEvent(target.getTenant(), Collections.singletonList(target.getControllerId()));
private void sendMultiActionCancelEvent(final Action action) {
sendMultiActionCancelEvent(action.getTenant(), Collections.singletonList(action));
}
private void sendDeploymentEvent(final List<Action> actions) {
@@ -160,8 +161,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
return;
}
final String tenant = filteredActions.get(0).getTenant();
sendMultiActionEvent(tenant, filteredActions.stream().map(action -> action.getTarget().getControllerId())
.collect(Collectors.toList()));
sendMultiActionAssignEvent(tenant, filteredActions);
}
private DistributionSetAssignmentResult sendDistributionSetAssignedEvent(
@@ -190,17 +190,31 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
}
/**
* Helper to fire a {@link MultiActionEvent}. This method may only be called
* if the Multi-Assignments feature is enabled.
*
* Helper to fire a {@link MultiActionCancelEvent}. This method may only be
* called if the Multi-Assignments feature is enabled.
*
* @param tenant
* the event is scoped to
* @param controllerIds
* of the targets the event refers to
* @param actions
* assigned to the targets
*/
private void sendMultiActionEvent(final String tenant, final List<String> controllerIds) {
private void sendMultiActionCancelEvent(final String tenant, final List<Action> actions) {
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
.publishEvent(new MultiActionEvent(tenant, eventPublisherHolder.getApplicationId(), controllerIds)));
.publishEvent(new MultiActionCancelEvent(tenant, eventPublisherHolder.getApplicationId(), actions)));
}
/**
* Helper to fire a {@link MultiActionAssignEvent}. This method may only be
* called if the Multi-Assignments feature is enabled.
*
* @param tenant
* the event is scoped to
* @param actions
* assigned to the targets
*/
private void sendMultiActionAssignEvent(final String tenant, final List<Action> actions) {
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
.publishEvent(new MultiActionAssignEvent(tenant, eventPublisherHolder.getApplicationId(), actions)));
}
private static Stream<Action> filterCancellations(final List<Action> actions) {

View File

@@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action;
@@ -33,22 +34,50 @@ public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
private static final String APPLICATION_ID_DEFAULT = "Node";
@Test
@Description("Verifies that a MultiActionEvent can be properly serialized and deserialized")
public void testMultiActionEvent() {
private Action createAction(final String controllerId) {
final JpaAction generateAction = new JpaAction();
generateAction.setActionType(ActionType.FORCED);
generateAction.setTarget(testdataFactory.createTarget(controllerId));
generateAction.setStatus(Status.RUNNING);
return generateAction;
}
@Test
@Description("Verifies that a testMultiActionAssignEvent can be properly serialized and deserialized")
public void testMultiActionAssignEvent() {
final List<String> controllerIds = Arrays.asList("id0", "id1", "id2", "id3",
"id4loooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnng");
final MultiActionEvent event = new MultiActionEvent(TENANT_DEFAULT, APPLICATION_ID_DEFAULT, controllerIds);
final List<Action> actions = controllerIds.stream().map(this::createAction).collect(Collectors.toList());
final MultiActionEvent remoteEventProtoStuff = createProtoStuffEvent(event);
assertThat(event).isEqualTo(remoteEventProtoStuff);
assertThat(remoteEventProtoStuff.getControllerIds()).containsExactlyElementsOf(controllerIds);
final MultiActionAssignEvent assignEvent = new MultiActionAssignEvent(TENANT_DEFAULT, APPLICATION_ID_DEFAULT,
actions);
final MultiActionEvent remoteEventJackson = createJacksonEvent(event);
assertThat(event).isEqualTo(remoteEventJackson);
assertThat(remoteEventJackson.getControllerIds()).containsExactlyElementsOf(controllerIds);
final MultiActionAssignEvent remoteAssignEventProtoStuff = createProtoStuffEvent(assignEvent);
assertThat(assignEvent).isEqualTo(remoteAssignEventProtoStuff);
assertThat(remoteAssignEventProtoStuff.getControllerIds()).containsExactlyElementsOf(controllerIds);
final MultiActionAssignEvent remoteAssignEventJackson = createJacksonEvent(assignEvent);
assertThat(assignEvent).isEqualTo(remoteAssignEventJackson);
assertThat(remoteAssignEventJackson.getControllerIds()).containsExactlyElementsOf(controllerIds);
}
@Test
@Description("Verifies that a MultiActionCancelEvent can be properly serialized and deserialized")
public void testMultiActionCancelEvent() {
final List<String> controllerIds = Arrays.asList("id0", "id1", "id2", "id3",
"id4loooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnng");
final List<Action> actions = controllerIds.stream().map(this::createAction).collect(Collectors.toList());
final MultiActionCancelEvent cancelEvent = new MultiActionCancelEvent(TENANT_DEFAULT, APPLICATION_ID_DEFAULT,
actions);
final MultiActionCancelEvent remoteCancelEventProtoStuff = createProtoStuffEvent(cancelEvent);
assertThat(cancelEvent).isEqualTo(remoteCancelEventProtoStuff);
assertThat(remoteCancelEventProtoStuff.getControllerIds()).containsExactlyElementsOf(controllerIds);
final MultiActionCancelEvent remoteCancelEventJackson = createJacksonEvent(cancelEvent);
assertThat(cancelEvent).isEqualTo(remoteCancelEventJackson);
assertThat(remoteCancelEventJackson.getControllerIds()).containsExactlyElementsOf(controllerIds);
}
@Test

View File

@@ -27,7 +27,8 @@ import javax.validation.ConstraintViolationException;
import org.assertj.core.api.Assertions;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.event.remote.MultiActionEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
@@ -561,7 +562,8 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetUpdatedEvent.class, count = 20), @Expect(type = ActionCreatedEvent.class, count = 20),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
@Expect(type = MultiActionEvent.class, count = 2),
@Expect(type = MultiActionAssignEvent.class, count = 2),
@Expect(type = MultiActionCancelEvent.class, count = 0),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0) })
public void previousAssignmentsAreNotCanceledInMultiAssignMode() {
enableMultiAssignments();
@@ -600,7 +602,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetUpdatedEvent.class, count = 4), @Expect(type = ActionCreatedEvent.class, count = 4),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
@Expect(type = MultiActionEvent.class, count = 1),
@Expect(type = MultiActionAssignEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0) })
public void multiassignmentInOneRequest() {
final List<Target> targets = testdataFactory.createTargets(2);
@@ -620,6 +622,36 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
});
}
@Test
@Description("Assign multiple DSs to multiple Targets in one request in multiAssignment mode and cancel each created action afterwards.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 4), @Expect(type = ActionCreatedEvent.class, count = 4),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
@Expect(type = MultiActionAssignEvent.class, count = 1),
@Expect(type = MultiActionCancelEvent.class, count = 4),
@Expect(type = ActionUpdatedEvent.class, count = 4),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 0) })
public void cancelMultiAssignmentActions() {
final List<Target> targets = testdataFactory.createTargets(2);
final List<DistributionSet> distributionSets = testdataFactory.createDistributionSets(2);
final List<DeploymentRequest> deploymentRequests = createAssignmentRequests(distributionSets, targets, 34);
enableMultiAssignments();
final List<DistributionSetAssignmentResult> results = deploymentManagement
.assignDistributionSets(deploymentRequests);
assertThat(getResultingActionCount(results)).isEqualTo(deploymentRequests.size());
final List<Long> dsIds = distributionSets.stream().map(DistributionSet::getId).collect(Collectors.toList());
targets.forEach(target -> {
actionRepository.findByTargetControllerId(PAGE, target.getControllerId()).forEach(action -> {
assertThat(action.getDistributionSet().getId()).isIn(dsIds);
deploymentManagement.cancelAction(action.getId());
});
});
}
protected List<DeploymentRequest> createAssignmentRequests(final Collection<DistributionSet> distributionSets,
final Collection<Target> targets, final int weight) {
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
@@ -689,7 +721,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 3), @Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = MultiActionEvent.class, count = 1) })
@Expect(type = MultiActionAssignEvent.class, count = 1) })
public void duplicateAssignmentsInRequestAreOnlyRemovedIfMultiassignmentDisabled() {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
@@ -767,7 +799,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = MultiActionEvent.class, count = 2) })
@Expect(type = MultiActionAssignEvent.class, count = 2) })
public void weightValidatedAndSaved() {
final String targetId = testdataFactory.createTarget().getControllerId();
final Long dsId = testdataFactory.createDistributionSet().getId();
@@ -794,8 +826,8 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
/**
* test a simple deployment by calling the
* {@link TargetRepository#assignDistributionSet(DistributionSet, Iterable)}
* and checking the active action and the action history of the targets.
* {@link TargetRepository#assignDistributionSet(DistributionSet, Iterable)} and
* checking the active action and the action history of the targets.
*
*/
@Test
@@ -1035,10 +1067,9 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
}
/**
* test the deletion of {@link DistributionSet}s including exception in case
* of {@link Target}s are assigned by
* {@link Target#getAssignedDistributionSet()} or
* {@link Target#getInstalledDistributionSet()}
* test the deletion of {@link DistributionSet}s including exception in case of
* {@link Target}s are assigned by {@link Target#getAssignedDistributionSet()}
* or {@link Target#getInstalledDistributionSet()}
*/
@Test
@Description("Deletes distribution set. Expected behaviour is that a soft delete is performed "
@@ -1306,8 +1337,8 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
* Helper methods that creates 2 lists of targets and a list of distribution
* sets.
* <p>
* <b>All created distribution sets are assigned to all targets of the
* target list deployedTargets.</b>
* <b>All created distribution sets are assigned to all targets of the target
* list deployedTargets.</b>
*
* @param undeployedTargetPrefix
* prefix to be used as target controller prefix
@@ -1316,8 +1347,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
* @param deployedTargetPrefix
* prefix to be used as target controller prefix
* @param noOfDeployedTargets
* number of targets to which the created distribution sets
* assigned
* number of targets to which the created distribution sets assigned
* @param noOfDistributionSets
* number of distribution sets
* @param distributionSetPrefix