Request attribute update after deployment (#750)

Send attribute update request to ddi connected device after successful software update

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>
This commit is contained in:
Stefan Klotz
2018-10-25 17:12:41 +02:00
committed by Dominic Schabel
parent 93279c0803
commit f8e1a547b0
7 changed files with 232 additions and 95 deletions

View File

@@ -12,7 +12,9 @@ import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.Callable;
import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
@@ -30,6 +32,7 @@ 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.springframework.amqp.core.Message;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
@@ -53,7 +56,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
final String controllerId = TARGET_PREFIX + "sendDownloadAndInstallStatus";
registerTargetAndAssignDistributionSet(controllerId);
waitUntilTargetStatusIsPending(controllerId);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING);
assertDownloadAndInstallMessage(getDistributionSet().getModules(), controllerId);
}
@@ -75,7 +78,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
assignDistributionSetWithMaintenanceWindow(distributionSet.getId(), controllerId, getTestSchedule(2),
getTestDuration(10), getTestTimeZone());
waitUntilTargetStatusIsPending(controllerId);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING);
assertDownloadMessage(distributionSet.getModules(), controllerId);
}
@@ -97,7 +100,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
assignDistributionSetWithMaintenanceWindow(distributionSet.getId(), controllerId, getTestSchedule(-5),
getTestDuration(10), getTestTimeZone());
waitUntilTargetStatusIsPending(controllerId);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING);
assertDownloadAndInstallMessage(distributionSet.getModules(), controllerId);
}
@@ -122,7 +125,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
assertCancelActionMessage(assignmentResult.getActions().get(0), controllerId);
createAndSendTarget(controllerId, TENANT_EXIST);
waitUntilTargetStatusIsPending(controllerId);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING);
assertCancelActionMessage(assignmentResult.getActions().get(0), controllerId);
}
@@ -143,7 +146,7 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
final Long actionId = registerTargetAndCancelActionId(controllerId);
createAndSendTarget(controllerId, TENANT_EXIST);
waitUntilTargetStatusIsPending(controllerId);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING);
assertCancelActionMessage(actionId, controllerId);
}
@@ -159,11 +162,47 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AmqpServiceInte
assertDeleteMessage(controllerId);
}
private void waitUntilTargetStatusIsPending(final String controllerId) {
@Test
@Description("Verify that attribute update is requested after device successfully closed software update.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 2),
@Expect(type = ActionUpdatedEvent.class, count = 2), @Expect(type = ActionCreatedEvent.class, count = 2),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 4),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
public void attributeRequestAfterSuccessfulUpdate() {
final String controllerId = TARGET_PREFIX + "attributeUpdateRequest";
registerAndAssertTargetWithExistingTenant(controllerId);
final Target target = controllerManagement.getByControllerId(controllerId).get();
final DistributionSet distributionSet = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final long actionId1 = assignDistributionSet(distributionSet, target).getActions().get(0);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING);
final Message messageError = createActionStatusUpdateMessage(controllerId, TENANT_EXIST, actionId1,
DmfActionStatus.ERROR);
getDmfClient().send(messageError);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.ERROR);
assertRequestAttributesUpdateMessageAbsent();
final long actionId2 = assignDistributionSet(distributionSet, target).getActions().get(0);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING);
final Message messageFin = createActionStatusUpdateMessage(controllerId, TENANT_EXIST, actionId2,
DmfActionStatus.FINISHED);
getDmfClient().send(messageFin);
waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.IN_SYNC);
assertRequestAttributesUpdateMessage(controllerId);
}
private void waitUntilTargetHasStatus(final String controllerId, final TargetUpdateStatus status) {
waitUntil(() -> {
final Optional<Target> findTargetByControllerID = targetManagement.getByControllerID(controllerId);
return findTargetByControllerID.isPresent()
&& TargetUpdateStatus.PENDING.equals(findTargetByControllerID.get().getUpdateStatus());
&& status.equals(findTargetByControllerID.get().getUpdateStatus());
});
}

View File

@@ -27,6 +27,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate;
import org.eclipse.hawkbit.dmf.json.model.DmfUpdateMode;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
@@ -363,13 +364,14 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
}
@Test
@Description("Tests register target and cancel a assignment")
@Description("Tests register target and send finished message")
@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 finishActionStatus() {
final String controllerId = TARGET_PREFIX + "finishActionStatus";
@@ -805,7 +807,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
verifyNumberOfDeadLetterMessages(3);
}
private void sendUpdateAttributesMessageWithGivenAttributes(String target, String key, String value) {
private void sendUpdateAttributesMessageWithGivenAttributes(final String target, final String key, final String value) {
final DmfAttributeUpdate controllerAttribute = new DmfAttributeUpdate();
controllerAttribute.getAttributes().put(key, value);
final Message message = createUpdateAttributesMessage(target, TENANT_EXIST, controllerAttribute);
@@ -889,7 +891,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AmqpServiceIntegra
verifyNumberOfDeadLetterMessages(1);
}
private void verifyNumberOfDeadLetterMessages(int numberOfInvocations) {
private void verifyNumberOfDeadLetterMessages(final int numberOfInvocations) {
assertEmptyReceiverQueueCount();
createConditionFactory()
.until(() -> Mockito.verify(getDeadletterListener(), Mockito.times(numberOfInvocations)).handleMessage(Mockito.any()));

View File

@@ -23,6 +23,8 @@ import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
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.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
@@ -147,6 +149,14 @@ public abstract class AmqpServiceIntegrationTest extends AbstractAmqpIntegration
assertThat(headers.get(MessageHeaderKey.TYPE)).isEqualTo(MessageType.THING_DELETED.toString());
}
protected void assertRequestAttributesUpdateMessage(final String target) {
assertReplyMessageHeader(EventTopic.REQUEST_ATTRIBUTES_UPDATE, target);
}
protected void assertRequestAttributesUpdateMessageAbsent() {
assertThat(replyToListener.getEventTopicMessages()).doesNotContainKey(EventTopic.REQUEST_ATTRIBUTES_UPDATE);
}
protected void assertPingReplyMessage(final String correlationId) {
verifyReplyToListener();
@@ -302,6 +312,17 @@ public abstract class AmqpServiceIntegrationTest extends AbstractAmqpIntegration
return createMessage(null, messageProperties);
}
protected Message createActionStatusUpdateMessage(final String target, final String tenant, final long actionId,
final DmfActionStatus status) {
final MessageProperties messageProperties = createMessagePropertiesWithTenant(tenant);
messageProperties.getHeaders().put(MessageHeaderKey.THING_ID, target);
messageProperties.getHeaders().put(MessageHeaderKey.TYPE, MessageType.EVENT.toString());
messageProperties.getHeaders().put(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.toString());
final DmfActionUpdateStatus dmfActionUpdateStatus = new DmfActionUpdateStatus(actionId, status);
return createMessage(dmfActionUpdateStatus, messageProperties);
}
protected MessageProperties createMessagePropertiesWithTenant(final String tenant) {
final MessageProperties messageProperties = new MessageProperties();
messageProperties.getHeaders().put(MessageHeaderKey.TENANT, tenant);