Support user consent flow (#1293)

* Introduce user consent flow
* Add permissions to confirmation management
* rename from consent to confirmation
* Reformat code. Remove unused imports. Change and add permission checks when configuring auto-confirmation.
* Do not include null values for DDI confirmation base endpoint
* fix confirmation required checkbox id
* Remove unused import. Fix consume/produce type of new API's.
* Change term processing to proceeding when activating user consent flow
* Align formatting and extend integration test cases for DMF and DDI.
* Extend DMF test cases to consider auto-confirmation
* Refactor action management to fix problem of handling action status updates on closed actions.
* remove unsupported validation
* use new confirmation api for DMF. Extend test cases.,
* Remove unnecessary fields.
* Extend API documentation for DDI and MGMT API.
* adapt ddi api docs adoc file
* Fixed the duplicate migration version for db files
* fix method to support confirmation
* Fixed PR comments
* Addressed PR comments
* Fixed after merge compilation issue
* Fixed after merge compilation issue
* Fix failing tests in MgmtRolloutResourceTest
* Fixed the permissions issue reflected by integration tests
* Added back the missing line of code lost during merge
* Fix the failing test on Jenkins

Signed-off-by: Stanislav Trailov <stanislav.trailov@bosch.io>
Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>
Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io>
Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
Co-authored-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
This commit is contained in:
Michael Herdt
2023-01-25 12:11:05 +01:00
committed by GitHub
parent b919ceda5c
commit 21f1569881
208 changed files with 7830 additions and 831 deletions

View File

@@ -27,6 +27,7 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadResponse;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
@@ -117,6 +118,9 @@ public class AmqpControllerAuthenticationTest {
@Mock
private ControllerManagement controllerManagement;
@Mock
private ConfirmationManagement confirmationManagement;
@Mock
private DdiSecurityProperties securityProperties;
@@ -156,7 +160,7 @@ public class AmqpControllerAuthenticationTest {
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate,
mock(AmqpMessageDispatcherService.class), controllerManagement, new JpaEntityFactory(),
systemSecurityContext, tenantConfigurationManagementMock);
systemSecurityContext, tenantConfigurationManagementMock, confirmationManagement);
amqpAuthenticationMessageHandlerService = new AmqpAuthenticationMessageHandler(rabbitTemplate,
authenticationManager, artifactManagementMock, cacheMock, hostnameResolverMock, controllerManagement,

View File

@@ -36,16 +36,19 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
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.DmfAutoConfirmation;
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.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
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.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusBuilder;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
@@ -110,6 +113,9 @@ public class AmqpMessageHandlerServiceTest {
@Mock
private ControllerManagement controllerManagementMock;
@Mock
private ConfirmationManagement confirmationManagementMock;
@Mock
private EntityFactory entityFactoryMock;
@@ -146,6 +152,12 @@ public class AmqpMessageHandlerServiceTest {
@Captor
private ArgumentCaptor<String> targetIdCaptor;
@Captor
private ArgumentCaptor<String> initiatorCaptor;
@Captor
private ArgumentCaptor<String> remarkCaptor;
@Captor
private ArgumentCaptor<String> targetNameCaptor;
@@ -169,7 +181,8 @@ public class AmqpMessageHandlerServiceTest {
final SystemSecurityContext systemSecurityContext = new SystemSecurityContext(tenantAware);
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock,
controllerManagementMock, entityFactoryMock, systemSecurityContext, tenantConfigurationManagement);
controllerManagementMock, entityFactoryMock, systemSecurityContext, tenantConfigurationManagement,
confirmationManagementMock);
amqpAuthenticationMessageHandlerService = new AmqpAuthenticationMessageHandler(rabbitTemplate,
authenticationManagerMock, artifactManagementMock, downloadIdCache, hostnameResolverMock,
controllerManagementMock, tenantAwareMock);
@@ -230,6 +243,16 @@ public class AmqpMessageHandlerServiceTest {
assertThat(uriCaptor.getValue()).as("Uri is not right").hasToString("amqp://" + VIRTUAL_HOST + "/" + replyTo);
}
@Step
private void assertInitiatorCapturedField(final String initiator) {
assertThat(initiatorCaptor.getValue()).as("Initiator is wrong").isEqualTo(initiator);
}
@Step
private void assertRemarkCapturedField(final String remark) {
assertThat(remarkCaptor.getValue()).as("Remark is wrong").isEqualTo(remark);
}
@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() {
@@ -556,6 +579,7 @@ public class AmqpMessageHandlerServiceTest {
final ActionStatusCreate create = mock(ActionStatusCreate.class);
when(builder.create(22L)).thenReturn(create);
when(create.status(any())).thenReturn(create);
when(create.messages(any())).thenReturn(create);
when(entityFactoryMock.actionStatus()).thenReturn(builder);
// for the test the same action can be used
when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.of(action));
@@ -572,7 +596,7 @@ public class AmqpMessageHandlerServiceTest {
final ArgumentCaptor<Target> targetCaptor = ArgumentCaptor.forClass(Target.class);
verify(amqpMessageDispatcherServiceMock, times(1)).sendUpdateMessageToTarget(actionPropertiesCaptor.capture(),
targetCaptor.capture(), any(Map.class));
targetCaptor.capture(), any(Map.class));
final ActionProperties actionProperties = actionPropertiesCaptor.getValue();
assertThat(actionProperties).isNotNull();
assertThat(actionProperties.getTenant()).as("event has tenant").isEqualTo("DEFAULT");
@@ -616,6 +640,56 @@ public class AmqpMessageHandlerServiceTest {
.contains("Device reported status code: 12");
}
@Test
@Description("Tests activating auto-confirmation on a target.")
void setAutoConfirmationStateActive() {
final String knownThingId = "1";
final String initiator = "iAmTheInitiator";
final String remark = "remarkForTesting";
final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT);
messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId);
messageProperties.setHeader(MessageHeaderKey.TOPIC, "UPDATE_AUTO_CONFIRM");
final DmfAutoConfirmation autoConfirmation = new DmfAutoConfirmation();
autoConfirmation.setEnabled(true);
autoConfirmation.setInitiator(initiator);
autoConfirmation.setRemark(remark);
final Message message = createMessage(autoConfirmation, messageProperties);
when(controllerManagementMock.activateAutoConfirmation(targetIdCaptor.capture(), initiatorCaptor.capture(),
remarkCaptor.capture())).thenReturn(null);
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
verify(controllerManagementMock, times(0)).deactivateAutoConfirmation(anyString());
assertThingIdCapturedField(knownThingId);
assertInitiatorCapturedField(initiator);
assertRemarkCapturedField(remark);
}
@Test
@Description("Tests deactivating auto-confirmation on a target.")
void setAutoConfirmationStateDeactivated() {
final String knownThingId = "1";
final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT);
messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId);
messageProperties.setHeader(MessageHeaderKey.TOPIC, "UPDATE_AUTO_CONFIRM");
final DmfAutoConfirmation autoConfirmation = new DmfAutoConfirmation();
final Message message = createMessage(autoConfirmation, messageProperties);
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
verify(controllerManagementMock).deactivateAutoConfirmation(targetIdCaptor.capture());
verify(controllerManagementMock, times(0)).activateAutoConfirmation(anyString(), anyString(), anyString());
assertThingIdCapturedField(knownThingId);
}
private DmfActionUpdateStatus createActionUpdateStatus(final DmfActionStatus status) {
return createActionUpdateStatus(status, 2L);
}

View File

@@ -12,7 +12,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -31,6 +30,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfActionRequest;
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.DmfConfirmRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
@@ -129,7 +129,13 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
testdataFactory.addSoftwareModuleMetadata(distributionSet);
return registerTargetAndAssignDistributionSet(distributionSet.getId(), TargetUpdateStatus.REGISTERED,
distributionSet.getModules(), controllerId);
distributionSet.getModules(), controllerId);
}
protected DistributionSetAssignmentResult prepareDistributionSetAndAssign(final String controllerId) {
distributionSet = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
testdataFactory.addSoftwareModuleMetadata(distributionSet);
return assignDistributionSet(distributionSet.getId(), controllerId);
}
protected DistributionSetAssignmentResult registerTargetAndAssignDistributionSet(final Long assignDs,
@@ -138,7 +144,11 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
registerAndAssertTargetWithExistingTenant(controllerId, 1, expectedStatus, CREATED_BY);
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(assignDs, controllerId);
assertDownloadAndInstallMessage(expectedSoftwareModulesInMessage, controllerId);
if (isConfirmationFlowEnabled()) {
assertConfirmMessage(expectedSoftwareModulesInMessage, controllerId);
} else {
assertDownloadAndInstallMessage(expectedSoftwareModulesInMessage, controllerId);
}
return assignmentResult;
}
@@ -452,4 +462,24 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
softwareModules.forEach(dmfModule -> assertThat(dmfModule.getMetadata()).containsExactly(
new DmfMetadata(TestdataFactory.VISIBLE_SM_MD_KEY, TestdataFactory.VISIBLE_SM_MD_VALUE)));
}
protected void assertConfirmMessage(final Set<SoftwareModule> dsModules, final String controllerId) {
final Message replyMessage = assertReplyMessageHeader(EventTopic.CONFIRM, controllerId);
assertAllTargetsCount(1);
final DmfConfirmRequest confirmRequest = (DmfConfirmRequest) getDmfClient()
.getMessageConverter().fromMessage(replyMessage);
assertConfirmRequest(confirmRequest, dsModules, controllerId);
}
protected void assertConfirmRequest(final DmfConfirmRequest request, final Set<SoftwareModule> softwareModules,
final String controllerId) {
assertSoftwareModules(softwareModules, request.getSoftwareModules());
final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.getByControllerID(controllerId));
assertThat(updatedTarget).isNotNull();
assertThat(updatedTarget.getSecurityToken()).isEqualTo(request.getTargetSecurityToken());
}
}

View File

@@ -466,7 +466,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
private Rollout createAndStartRollout(final DistributionSet ds, final String filterQuery, final Integer weight) {
final Rollout rollout = testdataFactory.createRolloutByVariables(UUID.randomUUID().toString(), "", 1,
filterQuery, ds, "50", "5", ActionType.FORCED, weight);
filterQuery, ds, "50", "5", ActionType.FORCED, weight, false);
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
return rollout;
@@ -695,4 +695,28 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer
assertThat(tokens.contains(requestTarget.getTargetSecurityToken()));
});
}
@Test
@Description("Verify that a distribution assignment send a confirm message.")
@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),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void sendConfirmStatus() {
final String controllerId = TARGET_PREFIX + "sendConfirmStatus";
enableConfirmationFlow();
registerTargetAndAssignDistributionSet(controllerId);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING);
assertConfirmMessage(getDistributionSet().getModules(), controllerId);
assertEventMessageNotPresent(EventTopic.DOWNLOAD_AND_INSTALL);
}
protected void assertEventMessageNotPresent(final EventTopic eventTopic) {
assertThat(replyToListener.getLatestEventMessage(eventTopic)).isNull();
}
}

View File

@@ -47,6 +47,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.event.remote.entity.TenantConfigurationCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
@@ -966,6 +968,26 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
getDmfClient().send(updateMessage);
}
private void assertActionStatusList(final Long actionId, final int statusListCount,
final Status... expectedActionStates) {
createConditionFactory().await().untilAsserted(() -> {
try {
WithSpringAuthorityRule.runAsPrivileged(() -> {
final List<ActionStatus> actionStatusList = deploymentManagement
.findActionStatusByAction(PAGE, actionId).getContent();
assertThat(actionStatusList).hasSize(statusListCount);
final List<Status> status = actionStatusList.stream().map(ActionStatus::getStatus)
.collect(Collectors.toList());
assertThat(status).containsOnly(expectedActionStates);
return null;
});
} catch (final Exception e) {
throw new RuntimeException(e);
}
});
}
private int getAuthenticationMessageCount() {
return Integer
.parseInt(Objects.requireNonNull(getRabbitAdmin().getQueueProperties(amqpProperties.getReceiverQueue()))
@@ -993,4 +1015,142 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
assertThat(node.has("actionId")).isTrue();
return node.get("actionId").asText();
}
@Test
@Description("Register a target and send a update action status (confirmed). Verify if the updated action status is correct.")
@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 = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void confirmedActionStatus() {
enableConfirmationFlow();
final String controllerId = TARGET_PREFIX + "confirmedActionStatus";
final DistributionSetAssignmentResult assignmentResult = registerTargetAndAssignDistributionSet(controllerId);
final Long actionId = getFirstAssignedActionId(assignmentResult);
createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.CONFIRMED);
assertActionStatusList(actionId, 2, Status.WAIT_FOR_CONFIRMATION, Status.RUNNING);
// assert download and install message
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.CONFIRM, EventTopic.DOWNLOAD_AND_INSTALL);
assertDownloadAndInstallMessage(assignmentResult.getDistributionSet().getModules(), controllerId);
}
@Test
@Description("Verify the DMF confirmed feedback can be provided if confirmation flow is disabled")
@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 = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1),
@Expect(type = TenantConfigurationUpdatedEvent.class, count = 1) })
void verifyActionCanBeConfirmedOnDisabledConfirmationFlow() {
enableConfirmationFlow();
final String controllerId = TARGET_PREFIX + "confirmedActionStatus";
final DistributionSetAssignmentResult assignmentResult = registerTargetAndAssignDistributionSet(controllerId);
final Long actionId = getFirstAssignedActionId(assignmentResult);
// verify action status is in WAIT_FOR_CONFIRMATION
assertActionStatusList(actionId, 1, Status.WAIT_FOR_CONFIRMATION);
disableConfirmationFlow();
createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.CONFIRMED);
assertActionStatusList(actionId, 2, Status.WAIT_FOR_CONFIRMATION, Status.RUNNING);
// assert download and install message
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.CONFIRM, EventTopic.DOWNLOAD_AND_INSTALL);
assertDownloadAndInstallMessage(assignmentResult.getDistributionSet().getModules(), controllerId);
}
@Test
@Description("Verify the DMF confirmed feedback can be provided if confirmation flow is disabled")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 0),
@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),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1),
@Expect(type = TenantConfigurationUpdatedEvent.class, count = 1)})
void verifyActionCanBeDeniedOnDisabledConfirmationFlow() {
enableConfirmationFlow();
final String controllerId = TARGET_PREFIX + "confirmedActionStatus";
final DistributionSetAssignmentResult assignmentResult = registerTargetAndAssignDistributionSet(controllerId);
final Long actionId = getFirstAssignedActionId(assignmentResult);
// verify action status is in WAIT_FOR_CONFIRMATION
assertActionStatusList(actionId, 1, Status.WAIT_FOR_CONFIRMATION);
disableConfirmationFlow();
createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.DENIED);
assertActionStatusList(actionId, 2, Status.WAIT_FOR_CONFIRMATION);
}
@Test
@Description("Verify the DMF download and install message is send directly if auto-confirmation is active")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 0),
@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 = 2),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void verifyDownloadAndInstallDirectlySendOnAutoConfirmationEnabled() {
enableConfirmationFlow();
final String controllerId = TARGET_PREFIX + "confirmedActionStatus";
registerAndAssertTargetWithExistingTenant(controllerId);
confirmationManagement.activateAutoConfirmation(controllerId, null, null);
final DistributionSetAssignmentResult assignmentResult = prepareDistributionSetAndAssign(controllerId);
final Long actionId = getFirstAssignedActionId(assignmentResult);
// verify action status is in WAIT_FOR_CONFIRMATION
assertActionStatusList(actionId, 1, Status.WAIT_FOR_CONFIRMATION);
// assert download and install message
waitUntilEventMessagesAreDispatchedToTarget(EventTopic.DOWNLOAD_AND_INSTALL);
assertDownloadAndInstallMessage(assignmentResult.getDistributionSet().getModules(), controllerId);
}
@Test
@Description("Register a target and send a update action status (denied). Verify if the updated action status is correct.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class), @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),
@Expect(type = TenantConfigurationCreatedEvent.class, count = 1) })
void deniedActionStatus() {
enableConfirmationFlow();
final String controllerId = TARGET_PREFIX + "deniedActionStatus";
final DistributionSetAssignmentResult assignmentResult = registerTargetAndAssignDistributionSet(controllerId);
final Long actionId = getFirstAssignedActionId(assignmentResult);
assertActionStatusList(actionId, 1, Status.WAIT_FOR_CONFIRMATION);
createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.DENIED);
assertActionStatusList(actionId, 2, Status.WAIT_FOR_CONFIRMATION);
}
}