Optional controller attributes for THING_CREATED (#1154)

* added optional attributes payload to THING_CREATED DMF message

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added optional attributes unit test for THING_CREATED message handler

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* extended Target interface with getControllerAttributes method, extended DMF message handler integration tests

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* updated hawkbit docs

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* fixed review findings

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>
This commit is contained in:
Bondar Bogdan
2021-08-02 17:45:48 +02:00
committed by GitHub
parent ace2f00742
commit 98535c96b4
7 changed files with 307 additions and 118 deletions

View File

@@ -63,11 +63,19 @@ Payload Template (optional):
```json ```json
{ {
"name": "String" "name": "String",
"attributeUpdate": {
"attributes": {
"exampleKey1" : "exampleValue1",
"exampleKey2" : "exampleValue2"
},
"mode": "String"
}
} }
``` ```
The "name" property specifies the name of the thing, which by default is the thing ID. This property is optional. The "name" property specifies the name of the thing, which by default is the thing ID. This property is optional.<br />
The "attributeUpdate" property provides the attributes of the thing, for details see UPDATE_ATTRIBUTES message. This property is optional.
### THING_REMOVED ### THING_REMOVED
@@ -93,7 +101,7 @@ type=THING\_REMOVED <br /> tenant=default <br /> thingId=abc | content\_type=app
### UPDATE_ATTRIBUTES ### UPDATE_ATTRIBUTES
Message to update target attributes. This message can be send in response to a _REQUEST_ATTRIBUTES_UPDATE_ event, sent by hawkBit. Message to update target attributes. This message can be send in response to a REQUEST_ATTRIBUTES_UPDATE event, sent by hawkBit.
| Header | Description | Type | Mandatory | Header | Description | Type | Mandatory
|-----------------------------|----------------------------------|-------------------------------------|---------------- |-----------------------------|----------------------------------|-------------------------------------|----------------

View File

@@ -10,7 +10,6 @@ package org.eclipse.hawkbit.amqp;
import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT; import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUNT;
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED; import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
import static org.springframework.util.StringUtils.hasText;
import java.io.Serializable; import java.io.Serializable;
import java.net.URI; import java.net.URI;
@@ -53,7 +52,6 @@ import org.springframework.amqp.AmqpRejectAndDontRequeueException;
import org.springframework.amqp.core.Message; import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Header;
import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@@ -201,12 +199,12 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
} }
/** /**
* Method to create a new target or to find the target if it already exists and * Method to create a new target or to find the target if it already exists
* update its poll time, status and optionally its name. * and update its poll time, status and optionally its name and attributes.
* *
* @param message * @param message
* the message that contains replyTo property and optionally the name * the message that contains replyTo property and optionally the
* in body * name and attributes in body
* @param virtualHost * @param virtualHost
* the virtual host * the virtual host
*/ */
@@ -225,14 +223,22 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri); target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri);
} else { } else {
checkContentTypeJson(message); checkContentTypeJson(message);
final DmfCreateThing thingCreateBody = convertMessage(message, DmfCreateThing.class);
final DmfAttributeUpdate thingAttributeUpdateBody = thingCreateBody.getAttributeUpdate();
target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri, convertMessage(message, DmfCreateThing.class).getName()); target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(thingId, amqpUri,
thingCreateBody.getName());
if (thingAttributeUpdateBody != null) {
controllerManagement.updateControllerAttributes(thingId, thingAttributeUpdateBody.getAttributes(),
getUpdateMode(thingAttributeUpdateBody));
}
} }
LOG.debug("Target {} reported online state.", thingId); LOG.debug("Target {} reported online state.", thingId);
sendUpdateCommandToTarget(target); sendUpdateCommandToTarget(target);
} catch (final EntityAlreadyExistsException e) { } catch (final EntityAlreadyExistsException e) {
throw new AmqpRejectAndDontRequeueException("Tried to register previously registered target, message will be ignored!", e); throw new AmqpRejectAndDontRequeueException(
"Tried to register previously registered target, message will be ignored!", e);
} }
} }
@@ -251,8 +257,8 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
} }
private void sendCurrentActionsAsMultiActionToTarget(final Target target) { private void sendCurrentActionsAsMultiActionToTarget(final Target target) {
final List<Action> actions = controllerManagement final List<Action> actions = controllerManagement.findActiveActionsWithHighestWeight(target.getControllerId(),
.findActiveActionsWithHighestWeight(target.getControllerId(), MAX_ACTION_COUNT); MAX_ACTION_COUNT);
final Set<DistributionSet> distributionSets = actions.stream().map(Action::getDistributionSet) final Set<DistributionSet> distributionSets = actions.stream().map(Action::getDistributionSet)
.collect(Collectors.toSet()); .collect(Collectors.toSet());

View File

@@ -14,8 +14,8 @@ import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationPrope
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -79,6 +79,7 @@ import org.springframework.http.HttpStatus;
import io.qameta.allure.Description; import io.qameta.allure.Description;
import io.qameta.allure.Feature; import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story; import io.qameta.allure.Story;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@@ -143,6 +144,9 @@ public class AmqpMessageHandlerServiceTest {
@Captor @Captor
private ArgumentCaptor<String> targetIdCaptor; private ArgumentCaptor<String> targetIdCaptor;
@Captor
private ArgumentCaptor<String> targetNameCaptor;
@Captor @Captor
private ArgumentCaptor<URI> uriCaptor; private ArgumentCaptor<URI> uriCaptor;
@@ -185,50 +189,64 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests the creation of a target/thing by calling the same method that incoming RabbitMQ messages would access.") @Description("Tests the creation of a target/thing by calling the same method that incoming RabbitMQ messages would access.")
public void createThing() { public void createThing() {
final String knownThingId = "1"; final String knownThingId = "1";
final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED);
messageProperties.setHeader(MessageHeaderKey.THING_ID, "1"); processThingCreatedMessage(knownThingId, null);
final Message message = messageConverter.toMessage(new byte[0], messageProperties);
assertThingIdCapturedField(knownThingId);
assertReplyToCapturedField("MyTest");
}
@Step
private void processThingCreatedMessage(final String thingId, final DmfCreateThing payload) {
final MessageProperties messageProperties = getThingCreatedMessageProperties(thingId);
final Message message = createMessage(payload != null ? payload : new byte[0], messageProperties);
final Target targetMock = mock(Target.class); final Target targetMock = mock(Target.class);
if (payload == null) {
final ArgumentCaptor<String> targetIdCaptor = ArgumentCaptor.forClass(String.class); when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(),
final ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class); uriCaptor.capture())).thenReturn(targetMock);
when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), } else {
uriCaptor.capture())).thenReturn(targetMock); when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(),
uriCaptor.capture(), targetNameCaptor.capture())).thenReturn(targetMock);
if (payload.getAttributeUpdate() != null) {
when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(),
attributesCaptor.capture(), modeCaptor.capture())).thenReturn(null);
}
}
when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.empty()); when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.empty());
amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST);
}
// verify @Step
assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); private void assertThingIdCapturedField(final String thingId) {
assertThat(uriCaptor.getValue().toString()).as("Uri is not right") assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(thingId);
.isEqualTo("amqp://" + VIRTUAL_HOST + "/MyTest"); }
@Step
private void assertReplyToCapturedField(final String replyTo) {
assertThat(uriCaptor.getValue()).as("Uri is not right").hasToString("amqp://" + VIRTUAL_HOST + "/" + replyTo);
} }
@Test @Test
@Description("Tests the creation of a target/thing with specified name by calling the same method that incoming RabbitMQ messages would access.") @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() { public void createThingWithName() {
final String knownThingId = "2"; final String knownThingId = "2";
final DmfCreateThing targetProperties = new DmfCreateThing(); final String knownThingName = "NonDefaultTargetName";
targetProperties.setName("NonDefaultTargetName");
final Target targetMock = mock(Target.class); final DmfCreateThing payload = new DmfCreateThing();
payload.setName(knownThingName);
targetIdCaptor = ArgumentCaptor.forClass(String.class); processThingCreatedMessage(knownThingId, payload);
uriCaptor = ArgumentCaptor.forClass(URI.class);
final ArgumentCaptor<String> targetNameCaptor = ArgumentCaptor.forClass(String.class);
when(controllerManagementMock.findOrRegisterTargetIfItDoesNotExist(targetIdCaptor.capture(), assertThingIdCapturedField(knownThingId);
uriCaptor.capture(), targetNameCaptor.capture())).thenReturn(targetMock); assertReplyToCapturedField("MyTest");
when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.empty()); assertThingNameCapturedField(knownThingName);
}
amqpMessageHandlerService.onMessage( @Step
createMessage(targetProperties, getThingCreatedMessageProperties(knownThingId)), private void assertThingNameCapturedField(final String thingName) {
MessageType.THING_CREATED.name(), TENANT, "vHost"); assertThat(targetNameCaptor.getValue()).as("Thing name is wrong").isEqualTo(thingName);
assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId);
assertThat(uriCaptor.getValue().toString()).as("Uri is not right").isEqualTo("amqp://vHost/MyTest");
assertThat(targetNameCaptor.getValue()).as("Thing name is not right").isEqualTo(targetProperties.getName());
} }
@Test @Test
@@ -243,6 +261,58 @@ public class AmqpMessageHandlerServiceTest {
MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST)); MessageType.THING_CREATED.name(), TENANT, VIRTUAL_HOST));
} }
@Test
@Description("Tests the creation of a target/thing with specified attributes by calling the same method that incoming RabbitMQ messages would access.")
public void createThingWithAttributes() {
final String knownThingId = "4";
final DmfAttributeUpdate attributeUpdate = new DmfAttributeUpdate();
attributeUpdate.getAttributes().put("testKey1", "testValue1");
attributeUpdate.getAttributes().put("testKey2", "testValue2");
final DmfCreateThing payload = new DmfCreateThing();
payload.setAttributeUpdate(attributeUpdate);
processThingCreatedMessage(knownThingId, payload);
assertThingIdCapturedField(knownThingId);
assertReplyToCapturedField("MyTest");
assertThingAttributesCapturedField(attributeUpdate.getAttributes());
}
@Step
private void assertThingAttributesCapturedField(final Map<String, String> attributes) {
assertThat(attributesCaptor.getValue()).as("Attributes is not right").isEqualTo(attributes);
}
@Test
@Description("Tests the creation of a target/thing with specified name and attributes by calling the same method that incoming RabbitMQ messages would access.")
public void createThingWithNameAndAttributes() {
final String knownThingId = "5";
final String knownThingName = "NonDefaultTargetName";
final DmfAttributeUpdate attributeUpdate = new DmfAttributeUpdate();
attributeUpdate.getAttributes().put("testKey1", "testValue1");
attributeUpdate.getAttributes().put("testKey2", "testValue2");
attributeUpdate.setMode(DmfUpdateMode.REPLACE);
final DmfCreateThing payload = new DmfCreateThing();
payload.setName(knownThingName);
payload.setAttributeUpdate(attributeUpdate);
processThingCreatedMessage(knownThingId, payload);
assertThingIdCapturedField(knownThingId);
assertReplyToCapturedField("MyTest");
assertThingAttributesCapturedField(attributeUpdate.getAttributes());
assertThingAttributesModeCapturedField(UpdateMode.REPLACE);
}
@Step
private void assertThingAttributesModeCapturedField(final UpdateMode attributesUpdateMode) {
assertThat(modeCaptor.getValue()).as("Attributes update mode is not right").isEqualTo(attributesUpdateMode);
}
@Test @Test
@Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.") @Description("Tests the target attribute update by calling the same method that incoming RabbitMQ messages would access.")
public void updateAttributes() { public void updateAttributes() {
@@ -254,18 +324,15 @@ public class AmqpMessageHandlerServiceTest {
attributeUpdate.getAttributes().put("testKey1", "testValue1"); attributeUpdate.getAttributes().put("testKey1", "testValue1");
attributeUpdate.getAttributes().put("testKey2", "testValue2"); attributeUpdate.getAttributes().put("testKey2", "testValue2");
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, final Message message = createMessage(attributeUpdate, messageProperties);
messageProperties);
when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(), when(controllerManagementMock.updateControllerAttributes(targetIdCaptor.capture(), attributesCaptor.capture(),
modeCaptor.capture())).thenReturn(null); modeCaptor.capture())).thenReturn(null);
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
// verify assertThingIdCapturedField(knownThingId);
assertThat(targetIdCaptor.getValue()).as("Thing id is wrong").isEqualTo(knownThingId); assertThingAttributesCapturedField(attributeUpdate.getAttributes());
assertThat(attributesCaptor.getValue()).as("Attributes is not right")
.isEqualTo(attributeUpdate.getAttributes());
} }
@Test @Test
@@ -283,32 +350,32 @@ public class AmqpMessageHandlerServiceTest {
modeCaptor.capture())).thenReturn(null); modeCaptor.capture())).thenReturn(null);
// send a message which does not specify a update mode // send a message which does not specify a update mode
Message message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, messageProperties); Message message = createMessage(attributeUpdate, messageProperties);
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
// verify that NO fallback is made on the way to the controller // verify that NO fallback is made on the way to the controller
// management layer // management layer
assertThat(modeCaptor.getValue()).isNull(); assertThingAttributesModeCapturedField(null);
// send a message which specifies update mode MERGE // send a message which specifies update mode MERGE
attributeUpdate.setMode(DmfUpdateMode.MERGE); attributeUpdate.setMode(DmfUpdateMode.MERGE);
message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, messageProperties); message = createMessage(attributeUpdate, messageProperties);
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
// verify that the update mode is converted and forwarded as expected // verify that the update mode is converted and forwarded as expected
assertThat(modeCaptor.getValue()).isEqualTo(UpdateMode.MERGE); assertThingAttributesModeCapturedField(UpdateMode.MERGE);
// send a message which specifies update mode REPLACE // send a message which specifies update mode REPLACE
attributeUpdate.setMode(DmfUpdateMode.REPLACE); attributeUpdate.setMode(DmfUpdateMode.REPLACE);
message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, messageProperties); message = createMessage(attributeUpdate, messageProperties);
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
// verify that the update mode is converted and forwarded as expected // verify that the update mode is converted and forwarded as expected
assertThat(modeCaptor.getValue()).isEqualTo(UpdateMode.REPLACE); assertThingAttributesModeCapturedField(UpdateMode.REPLACE);
// send a message which specifies update mode REMOVE // send a message which specifies update mode REMOVE
attributeUpdate.setMode(DmfUpdateMode.REMOVE); attributeUpdate.setMode(DmfUpdateMode.REMOVE);
message = amqpMessageHandlerService.getMessageConverter().toMessage(attributeUpdate, messageProperties); message = createMessage(attributeUpdate, messageProperties);
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
// verify that the update mode is converted and forwarded as expected // verify that the update mode is converted and forwarded as expected
assertThat(modeCaptor.getValue()).isEqualTo(UpdateMode.REMOVE); assertThingAttributesModeCapturedField(UpdateMode.REMOVE);
} }
@Test @Test
@@ -316,7 +383,7 @@ public class AmqpMessageHandlerServiceTest {
public void createThingWithoutReplyTo() { public void createThingWithoutReplyTo() {
final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED, null); final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED, null);
messageProperties.setHeader(MessageHeaderKey.THING_ID, "1"); messageProperties.setHeader(MessageHeaderKey.THING_ID, "1");
final Message message = messageConverter.toMessage("", messageProperties); final Message message = createMessage("", messageProperties);
assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class)
.as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no replyTo header was set") .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no replyTo header was set")
@@ -328,7 +395,7 @@ public class AmqpMessageHandlerServiceTest {
@Description("Tests the creation of a target/thing without a thingID by calling the same method that incoming RabbitMQ messages would access.") @Description("Tests the creation of a target/thing without a thingID by calling the same method that incoming RabbitMQ messages would access.")
public void createThingWithoutID() { public void createThingWithoutID() {
final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED);
final Message message = messageConverter.toMessage(new byte[0], messageProperties); final Message message = createMessage(new byte[0], messageProperties);
assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class)
.as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no thingId was set") .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no thingId was set")
@@ -342,7 +409,7 @@ public class AmqpMessageHandlerServiceTest {
final String type = "bumlux"; final String type = "bumlux";
final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED);
messageProperties.setHeader(MessageHeaderKey.THING_ID, ""); messageProperties.setHeader(MessageHeaderKey.THING_ID, "");
final Message message = messageConverter.toMessage(new byte[0], messageProperties); final Message message = createMessage(new byte[0], messageProperties);
assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class)
.as(FAIL_MESSAGE_AMQP_REJECT_REASON + "due to unknown message type") .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "due to unknown message type")
@@ -378,8 +445,7 @@ public class AmqpMessageHandlerServiceTest {
final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT);
messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
final DmfActionUpdateStatus actionUpdateStatus = new DmfActionUpdateStatus(1L, DmfActionStatus.DOWNLOAD); final DmfActionUpdateStatus actionUpdateStatus = new DmfActionUpdateStatus(1L, DmfActionStatus.DOWNLOAD);
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, final Message message = createMessage(actionUpdateStatus, messageProperties);
messageProperties);
assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class)
.as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no action id was set") .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no action id was set")
@@ -395,8 +461,7 @@ public class AmqpMessageHandlerServiceTest {
when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.empty()); when(controllerManagementMock.findActionWithDetails(anyLong())).thenReturn(Optional.empty());
final DmfActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(DmfActionStatus.DOWNLOAD); final DmfActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(DmfActionStatus.DOWNLOAD);
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, final Message message = createMessage(actionUpdateStatus, messageProperties);
messageProperties);
assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class)
.as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no action id was set") .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no action id was set")
@@ -410,8 +475,7 @@ public class AmqpMessageHandlerServiceTest {
final MessageProperties messageProperties = createMessageProperties(null); final MessageProperties messageProperties = createMessageProperties(null);
final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID,
TARGET_ID, FileResource.createFileResourceBySha1("12345")); TARGET_ID, FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = createMessage(securityToken, messageProperties);
messageProperties);
// test // test
final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message); final Message onMessage = amqpAuthenticationMessageHandlerService.onAuthenticationRequest(message);
@@ -429,8 +493,7 @@ public class AmqpMessageHandlerServiceTest {
final MessageProperties messageProperties = createMessageProperties(null); final MessageProperties messageProperties = createMessageProperties(null);
final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID,
TARGET_ID, FileResource.createFileResourceBySha1("12345")); TARGET_ID, FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = createMessage(securityToken, messageProperties);
messageProperties);
final Artifact localArtifactMock = mock(Artifact.class); final Artifact localArtifactMock = mock(Artifact.class);
when(artifactManagementMock.findFirstBySHA1(anyString())).thenReturn(Optional.of(localArtifactMock)); when(artifactManagementMock.findFirstBySHA1(anyString())).thenReturn(Optional.of(localArtifactMock));
@@ -451,8 +514,7 @@ public class AmqpMessageHandlerServiceTest {
final MessageProperties messageProperties = createMessageProperties(null); final MessageProperties messageProperties = createMessageProperties(null);
final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID, final DmfTenantSecurityToken securityToken = new DmfTenantSecurityToken(TENANT, TENANT_ID, CONTROLLER_ID,
TARGET_ID, FileResource.createFileResourceBySha1("12345")); TARGET_ID, FileResource.createFileResourceBySha1("12345"));
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken, final Message message = createMessage(securityToken, messageProperties);
messageProperties);
// mock // mock
final Artifact localArtifactMock = mock(Artifact.class); final Artifact localArtifactMock = mock(Artifact.class);
@@ -494,14 +556,12 @@ public class AmqpMessageHandlerServiceTest {
when(create.status(any())).thenReturn(create); when(create.status(any())).thenReturn(create);
when(entityFactoryMock.actionStatus()).thenReturn(builder); when(entityFactoryMock.actionStatus()).thenReturn(builder);
// for the test the same action can be used // for the test the same action can be used
when(controllerManagementMock.findActiveActionWithHighestWeight(any())) when(controllerManagementMock.findActiveActionWithHighestWeight(any())).thenReturn(Optional.of(action));
.thenReturn(Optional.of(action));
final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT); final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT);
messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name()); messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
final DmfActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(DmfActionStatus.FINISHED, 23L); final DmfActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(DmfActionStatus.FINISHED, 23L);
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(actionUpdateStatus, final Message message = createMessage(actionUpdateStatus, messageProperties);
messageProperties);
// test // test
amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.EVENT.name(), TENANT, VIRTUAL_HOST);
@@ -579,7 +639,7 @@ public class AmqpMessageHandlerServiceTest {
final String knownThingId = "1"; final String knownThingId = "1";
final MessageProperties messageProperties = createMessageProperties(MessageType.THING_REMOVED); final MessageProperties messageProperties = createMessageProperties(MessageType.THING_REMOVED);
messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId); messageProperties.setHeader(MessageHeaderKey.THING_ID, knownThingId);
final Message message = messageConverter.toMessage(new byte[0], messageProperties); final Message message = createMessage(new byte[0], messageProperties);
// test // test
amqpMessageHandlerService.onMessage(message, MessageType.THING_REMOVED.name(), TENANT, VIRTUAL_HOST); amqpMessageHandlerService.onMessage(message, MessageType.THING_REMOVED.name(), TENANT, VIRTUAL_HOST);
@@ -593,7 +653,7 @@ public class AmqpMessageHandlerServiceTest {
public void deleteThingWithoutThingId() { public void deleteThingWithoutThingId() {
// prepare invalid message // prepare invalid message
final MessageProperties messageProperties = createMessageProperties(MessageType.THING_REMOVED); final MessageProperties messageProperties = createMessageProperties(MessageType.THING_REMOVED);
final Message message = messageConverter.toMessage(new byte[0], messageProperties); final Message message = createMessage(new byte[0], messageProperties);
assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class) assertThatExceptionOfType(AmqpRejectAndDontRequeueException.class)
.as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no thingId was set") .as(FAIL_MESSAGE_AMQP_REJECT_REASON + "since no thingId was set")
@@ -601,13 +661,13 @@ public class AmqpMessageHandlerServiceTest {
VIRTUAL_HOST)); VIRTUAL_HOST));
} }
private MessageProperties getThingCreatedMessageProperties(String thingId) { private MessageProperties getThingCreatedMessageProperties(final String thingId) {
final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED); final MessageProperties messageProperties = createMessageProperties(MessageType.THING_CREATED);
messageProperties.setHeader(MessageHeaderKey.THING_ID, thingId); messageProperties.setHeader(MessageHeaderKey.THING_ID, thingId);
return messageProperties; return messageProperties;
} }
private Message createMessage(Object object, MessageProperties messageProperties) { private Message createMessage(final Object object, final MessageProperties messageProperties) {
return messageConverter.toMessage(object, messageProperties); return messageConverter.toMessage(object, messageProperties);
} }
} }

View File

@@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@@ -28,6 +29,7 @@ import org.eclipse.hawkbit.dmf.json.model.DmfActionRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus; import org.eclipse.hawkbit.dmf.json.model.DmfActionStatus;
import org.eclipse.hawkbit.dmf.json.model.DmfActionUpdateStatus; import org.eclipse.hawkbit.dmf.json.model.DmfActionUpdateStatus;
import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate; import org.eclipse.hawkbit.dmf.json.model.DmfAttributeUpdate;
import org.eclipse.hawkbit.dmf.json.model.DmfCreateThing;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest; import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfMetadata; import org.eclipse.hawkbit.dmf.json.model.DmfMetadata;
import org.eclipse.hawkbit.integration.listener.DeadletterListener; import org.eclipse.hawkbit.integration.listener.DeadletterListener;
@@ -54,6 +56,9 @@ import org.springframework.amqp.rabbit.test.RabbitListenerTestHarness;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration; import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.util.CollectionUtils;
import com.cronutils.utils.StringUtils;
import io.qameta.allure.Step; import io.qameta.allure.Step;
@@ -92,7 +97,8 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
private <T> T waitUntilIsPresent(final Callable<Optional<T>> callable) { private <T> T waitUntilIsPresent(final Callable<Optional<T>> callable) {
createConditionFactory().until(() -> WithSpringAuthorityRule.runAsPrivileged(() -> callable.call().isPresent())); createConditionFactory()
.until(() -> WithSpringAuthorityRule.runAsPrivileged(() -> callable.call().isPresent()));
try { try {
return WithSpringAuthorityRule.runAsPrivileged(() -> callable.call().get()); return WithSpringAuthorityRule.runAsPrivileged(() -> callable.call().get());
@@ -188,7 +194,8 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
protected void assertDmfDownloadAndUpdateRequest(final DmfDownloadAndUpdateRequest request, protected void assertDmfDownloadAndUpdateRequest(final DmfDownloadAndUpdateRequest request,
final Set<SoftwareModule> softwareModules, final String controllerId) { final Set<SoftwareModule> softwareModules, final String controllerId) {
assertThat(softwareModules).is(new HamcrestCondition<>(SoftwareModuleJsonMatcher.containsExactly(request.getSoftwareModules()))); assertThat(softwareModules)
.is(new HamcrestCondition<>(SoftwareModuleJsonMatcher.containsExactly(request.getSoftwareModules())));
request.getSoftwareModules().forEach(dmfModule -> assertThat(dmfModule.getMetadata()).containsExactly( request.getSoftwareModules().forEach(dmfModule -> assertThat(dmfModule.getMetadata()).containsExactly(
new DmfMetadata(TestdataFactory.VISIBLE_SM_MD_KEY, TestdataFactory.VISIBLE_SM_MD_VALUE))); new DmfMetadata(TestdataFactory.VISIBLE_SM_MD_KEY, TestdataFactory.VISIBLE_SM_MD_VALUE)));
final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.getByControllerID(controllerId)); final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.getByControllerID(controllerId));
@@ -205,8 +212,13 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
assertAssignmentMessage(dsModules, controllerId, EventTopic.DOWNLOAD); assertAssignmentMessage(dsModules, controllerId, EventTopic.DOWNLOAD);
} }
protected void createAndSendThingCreated(final String target, final String tenant) { protected void createAndSendThingCreated(final String controllerId, final String tenant) {
final Message message = createTargetMessage(target, tenant); createAndSendThingCreated(controllerId, null, null, tenant);
}
protected void createAndSendThingCreated(final String controllerId, final String name,
final Map<String, String> attributes, final String tenant) {
final Message message = createTargetMessage(controllerId, name, attributes, tenant);
getDmfClient().send(message); getDmfClient().send(message);
} }
@@ -254,32 +266,50 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
registerAndAssertTargetWithExistingTenant(controllerId, 1); registerAndAssertTargetWithExistingTenant(controllerId, 1);
} }
protected void registerAndAssertTargetWithExistingTenant(final String target, protected void registerAndAssertTargetWithExistingTenant(final String controllerId,
final int existingTargetsAfterCreation) { final int existingTargetsAfterCreation) {
registerAndAssertTargetWithExistingTenant(controllerId, existingTargetsAfterCreation,
registerAndAssertTargetWithExistingTenant(target, existingTargetsAfterCreation, TargetUpdateStatus.REGISTERED, TargetUpdateStatus.REGISTERED, CREATED_BY);
CREATED_BY);
} }
protected void registerAndAssertTargetWithExistingTenant(final String target, protected void registerAndAssertTargetWithExistingTenant(final String controllerId,
final int existingTargetsAfterCreation, final TargetUpdateStatus expectedTargetStatus, final int existingTargetsAfterCreation, final TargetUpdateStatus expectedTargetStatus,
final String createdBy) { final String createdBy) {
createAndSendThingCreated(target, TENANT_EXIST); registerAndAssertTargetWithExistingTenant(controllerId, null, existingTargetsAfterCreation,
final Target registeredTarget = waitUntilIsPresent(() -> targetManagement.getByControllerID(target)); expectedTargetStatus, createdBy, null);
}
protected void registerAndAssertTargetWithExistingTenant(final String controllerId, final String name,
final int existingTargetsAfterCreation, final TargetUpdateStatus expectedTargetStatus,
final String createdBy, final Map<String, String> attributes) {
registerAndAssertTargetWithExistingTenant(controllerId, name, existingTargetsAfterCreation,
expectedTargetStatus, createdBy, attributes, () -> targetManagement.getByControllerID(controllerId));
}
private void registerAndAssertTargetWithExistingTenant(final String controllerId, final String name,
final int existingTargetsAfterCreation, final TargetUpdateStatus expectedTargetStatus,
final String createdBy, final Map<String, String> attributes,
final Callable<Optional<Target>> fetchTarget) {
createAndSendThingCreated(controllerId, name, attributes, TENANT_EXIST);
final Target registeredTarget = waitUntilIsPresent(fetchTarget::call);
assertAllTargetsCount(existingTargetsAfterCreation); assertAllTargetsCount(existingTargetsAfterCreation);
assertThat(registeredTarget).isNotNull(); assertThat(registeredTarget).isNotNull();
assertTarget(registeredTarget, expectedTargetStatus, createdBy); assertTarget(registeredTarget, name != null ? name : controllerId, expectedTargetStatus, createdBy,
attributes != null ? attributes : Collections.emptyMap());
} }
protected void registerSameTargetAndAssertBasedOnVersion(final String controllerId, protected void registerSameTargetAndAssertBasedOnVersion(final String controllerId,
final int existingTargetsAfterCreation, final TargetUpdateStatus expectedTargetStatus) { final int existingTargetsAfterCreation, final TargetUpdateStatus expectedTargetStatus) {
registerSameTargetAndAssertBasedOnVersion(controllerId, null, existingTargetsAfterCreation,
expectedTargetStatus, null);
}
protected void registerSameTargetAndAssertBasedOnVersion(final String controllerId, final String name,
final int existingTargetsAfterCreation, final TargetUpdateStatus expectedTargetStatus,
final Map<String, String> attributes) {
final int version = controllerManagement.getByControllerId(controllerId).get().getOptLockRevision(); final int version = controllerManagement.getByControllerId(controllerId).get().getOptLockRevision();
createAndSendThingCreated(controllerId, TENANT_EXIST); registerAndAssertTargetWithExistingTenant(controllerId, name, existingTargetsAfterCreation,
final Target registeredTarget = waitUntilIsPresent(() -> findTargetBasedOnNewVersion(controllerId, version)); expectedTargetStatus, CREATED_BY, attributes, () -> findTargetBasedOnNewVersion(controllerId, version));
assertAllTargetsCount(existingTargetsAfterCreation);
assertThat(registeredTarget).isNotNull();
assertThat(registeredTarget.getUpdateStatus()).isEqualTo(expectedTargetStatus);
} }
private Optional<Target> findTargetBasedOnNewVersion(final String controllerId, final int version) { private Optional<Target> findTargetBasedOnNewVersion(final String controllerId, final int version) {
@@ -290,23 +320,43 @@ public abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpInt
return Optional.empty(); return Optional.empty();
} }
private void assertTarget(final Target target, final TargetUpdateStatus updateStatus, final String createdBy) { private void assertTarget(final Target target, final String name, final TargetUpdateStatus updateStatus,
final String createdBy, final Map<String, String> attributes) {
assertThat(target.getTenant()).isEqualTo(TENANT_EXIST); assertThat(target.getTenant()).isEqualTo(TENANT_EXIST);
assertThat(target.getName()).isEqualTo(name);
assertThat(target.getDescription()).contains("Plug and Play"); assertThat(target.getDescription()).contains("Plug and Play");
assertThat(target.getDescription()).contains(target.getControllerId()); assertThat(target.getDescription()).contains(target.getControllerId());
assertThat(target.getCreatedBy()).isEqualTo(createdBy); assertThat(target.getCreatedBy()).isEqualTo(createdBy);
assertThat(target.getUpdateStatus()).isEqualTo(updateStatus); assertThat(target.getUpdateStatus()).isEqualTo(updateStatus);
assertThat(target.getAddress()).isEqualTo( assertThat(target.getAddress())
IpUtil.createAmqpUri(getVirtualHost(), DmfTestConfiguration.REPLY_TO_EXCHANGE)); .isEqualTo(IpUtil.createAmqpUri(getVirtualHost(), DmfTestConfiguration.REPLY_TO_EXCHANGE));
assertThat(targetManagement.getControllerAttributes(target.getControllerId())).isEqualTo(attributes);
} }
protected Message createTargetMessage(final String target, final String tenant) { protected Message createTargetMessage(final String controllerId, final String tenant) {
return createTargetMessage(controllerId, null, null, tenant);
}
protected Message createTargetMessage(final String controllerId, final String name,
final Map<String, String> attributes, final String tenant) {
final MessageProperties messageProperties = createMessagePropertiesWithTenant(tenant); final MessageProperties messageProperties = createMessagePropertiesWithTenant(tenant);
messageProperties.getHeaders().put(MessageHeaderKey.THING_ID, target); messageProperties.getHeaders().put(MessageHeaderKey.THING_ID, controllerId);
messageProperties.getHeaders().put(MessageHeaderKey.TYPE, MessageType.THING_CREATED.toString()); messageProperties.getHeaders().put(MessageHeaderKey.TYPE, MessageType.THING_CREATED.toString());
messageProperties.setReplyTo(DmfTestConfiguration.REPLY_TO_EXCHANGE); messageProperties.setReplyTo(DmfTestConfiguration.REPLY_TO_EXCHANGE);
return createMessage(null, messageProperties); DmfCreateThing payload = null;
if (!StringUtils.isEmpty(name) || !CollectionUtils.isEmpty(attributes)) {
payload = new DmfCreateThing();
payload.setName(name);
if (!CollectionUtils.isEmpty(attributes)) {
final DmfAttributeUpdate attributeUpdate = new DmfAttributeUpdate();
attributeUpdate.getAttributes().putAll(attributes);
payload.setAttributeUpdate(attributeUpdate);
}
}
return createMessage(payload, messageProperties);
} }
protected Message createPingMessage(final String correlationId, final String tenant) { protected Message createPingMessage(final String correlationId, final String tenant) {

View File

@@ -92,7 +92,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
assertPingReplyMessage(CORRELATION_ID); assertPingReplyMessage(CORRELATION_ID);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
} }
@Test @Test
@@ -107,7 +107,63 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
registerAndAssertTargetWithExistingTenant(target2, 2); registerAndAssertTargetWithExistingTenant(target2, 2);
registerSameTargetAndAssertBasedOnVersion(target2, 2, TargetUpdateStatus.REGISTERED); registerSameTargetAndAssertBasedOnVersion(target2, 2, TargetUpdateStatus.REGISTERED);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
}
@Test
@Description("Tests register target with name")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 2) })
public void registerTargetWithName() {
final String controllerId = TARGET_PREFIX + "registerTargetWithName";
final String name = "NonDefaultTargetName";
registerAndAssertTargetWithExistingTenant(controllerId, name, 1, TargetUpdateStatus.REGISTERED, CREATED_BY,
null);
registerSameTargetAndAssertBasedOnVersion(controllerId, name + "_updated", 1, TargetUpdateStatus.REGISTERED,
null);
Mockito.verifyNoInteractions(getDeadletterListener());
}
@Test
@Description("Tests register target with attributes")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetPollEvent.class, count = 2) })
public void registerTargetWithAttributes() {
final String controllerId = TARGET_PREFIX + "registerTargetWithAttributes";
final Map<String, String> attributes = new HashMap<>();
attributes.put("testKey1", "testValue1");
attributes.put("testKey2", "testValue2");
registerAndAssertTargetWithExistingTenant(controllerId, null, 1, TargetUpdateStatus.REGISTERED, CREATED_BY,
attributes);
attributes.put("testKey3", "testValue3");
registerSameTargetAndAssertBasedOnVersion(controllerId, null, 1, TargetUpdateStatus.REGISTERED, attributes);
Mockito.verifyNoInteractions(getDeadletterListener());
}
@Test
@Description("Tests register target with name and attributes")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 3), @Expect(type = TargetPollEvent.class, count = 2) })
public void registerTargetWithNameAndAttributes() {
final String controllerId = TARGET_PREFIX + "registerTargetWithAttributes";
final String name = "NonDefaultTargetName";
final Map<String, String> attributes = new HashMap<>();
attributes.put("testKey1", "testValue1");
attributes.put("testKey2", "testValue2");
registerAndAssertTargetWithExistingTenant(controllerId, name, 1, TargetUpdateStatus.REGISTERED, CREATED_BY,
attributes);
attributes.put("testKey3", "testValue3");
registerSameTargetAndAssertBasedOnVersion(controllerId, name + "_updated", 1, TargetUpdateStatus.REGISTERED,
attributes);
Mockito.verifyNoInteractions(getDeadletterListener());
} }
@Test @Test
@@ -510,7 +566,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
// verify // verify
assertDownloadAndInstallMessage(distributionSet.getModules(), controllerId); assertDownloadAndInstallMessage(distributionSet.getModules(), controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
} }
@Test @Test
@@ -537,7 +593,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
// verify // verify
assertDownloadMessage(distributionSet.getModules(), controllerId); assertDownloadMessage(distributionSet.getModules(), controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
} }
@Test @Test
@@ -564,7 +620,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
// verify // verify
assertDownloadAndInstallMessage(distributionSet.getModules(), controllerId); assertDownloadAndInstallMessage(distributionSet.getModules(), controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
} }
@Test @Test
@@ -592,7 +648,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
// verify // verify
assertCancelActionMessage(getFirstAssignedActionId(distributionSetAssignmentResult), controllerId); assertCancelActionMessage(getFirstAssignedActionId(distributionSetAssignmentResult), controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
} }
@Test @Test
@@ -836,15 +892,15 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
// verify // verify
final Message message = assertReplyMessageHeader(EventTopic.DOWNLOAD, controllerId); final Message message = assertReplyMessageHeader(EventTopic.DOWNLOAD, controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
// get actionId from Message // get actionId from Message
Long actionId = Long.parseLong(getJsonFieldFromBody(message.getBody(), "actionId")); final Long actionId = Long.parseLong(getJsonFieldFromBody(message.getBody(), "actionId"));
// Send DOWNLOADED message // Send DOWNLOADED message
createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.DOWNLOADED); createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.DOWNLOADED);
assertAction(actionId, 1, Status.RUNNING, Status.DOWNLOADED); assertAction(actionId, 1, Status.RUNNING, Status.DOWNLOADED);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), null); verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), null);
} }
@@ -868,22 +924,22 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
// verify // verify
final Message message = assertReplyMessageHeader(EventTopic.DOWNLOAD, controllerId); final Message message = assertReplyMessageHeader(EventTopic.DOWNLOAD, controllerId);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
// get actionId from Message // get actionId from Message
Long actionId = Long.parseLong(getJsonFieldFromBody(message.getBody(), "actionId")); final Long actionId = Long.parseLong(getJsonFieldFromBody(message.getBody(), "actionId"));
// Send DOWNLOADED message, should result in the action being closed // Send DOWNLOADED message, should result in the action being closed
createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.DOWNLOADED); createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.DOWNLOADED);
assertAction(actionId, 1, Status.RUNNING, Status.DOWNLOADED); assertAction(actionId, 1, Status.RUNNING, Status.DOWNLOADED);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), null); verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), null);
// Send FINISHED message // Send FINISHED message
createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.FINISHED); createAndSendActionStatusUpdateMessage(controllerId, actionId, DmfActionStatus.FINISHED);
assertAction(actionId, 2, Status.RUNNING, Status.DOWNLOADED, Status.FINISHED); assertAction(actionId, 2, Status.RUNNING, Status.DOWNLOADED, Status.FINISHED);
Mockito.verifyZeroInteractions(getDeadletterListener()); Mockito.verifyNoInteractions(getDeadletterListener());
verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), distributionSet.getId()); verifyAssignedDsAndInstalledDs(controllerId, distributionSet.getId(), distributionSet.getId());
} }
@@ -899,7 +955,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
final String controllerId = "dummy_target"; final String controllerId = "dummy_target";
try { try {
for (Class<? extends RuntimeException> exceptionClass : exceptionsThatShouldNotBeRequeued) { for (final Class<? extends RuntimeException> exceptionClass : exceptionsThatShouldNotBeRequeued) {
doThrow(exceptionClass).when(mockedControllerManagement) doThrow(exceptionClass).when(mockedControllerManagement)
.findOrRegisterTargetIfItDoesNotExist(eq(controllerId), any()); .findOrRegisterTargetIfItDoesNotExist(eq(controllerId), any());
@@ -998,7 +1054,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
} }
private void assertEmptyReceiverQueueCount() { private void assertEmptyReceiverQueueCount() {
assertThat(getAuthenticationMessageCount()).isEqualTo(0); assertThat(getAuthenticationMessageCount()).isZero();
} }
private void verifyOneDeadLetterMessage() { private void verifyOneDeadLetterMessage() {
@@ -1013,7 +1069,7 @@ public class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServic
} }
private static String getJsonFieldFromBody(final byte[] body, final String fieldName) throws IOException { private static String getJsonFieldFromBody(final byte[] body, final String fieldName) throws IOException {
ObjectMapper objectMapper = new ObjectMapper(); final ObjectMapper objectMapper = new ObjectMapper();
final ObjectNode node = objectMapper.readValue(new String(body, Charset.defaultCharset()), ObjectNode.class); final ObjectNode node = objectMapper.readValue(new String(body, Charset.defaultCharset()), ObjectNode.class);
assertThat(node.has(fieldName)).isTrue(); assertThat(node.has(fieldName)).isTrue();
return node.get(fieldName).asText(); return node.get(fieldName).asText();

View File

@@ -23,6 +23,9 @@ public class DmfCreateThing {
@JsonProperty @JsonProperty
private String name; private String name;
@JsonProperty
private DmfAttributeUpdate attributeUpdate;
public String getName() { public String getName() {
return name; return name;
} }
@@ -31,4 +34,11 @@ public class DmfCreateThing {
this.name = name; this.name = name;
} }
public DmfAttributeUpdate getAttributeUpdate() {
return attributeUpdate;
}
public void setAttributeUpdate(final DmfAttributeUpdate attributeUpdate) {
this.attributeUpdate = attributeUpdate;
}
} }

View File

@@ -98,5 +98,4 @@ public interface Target extends NamedEntity {
* {@link #getControllerAttributes()}. * {@link #getControllerAttributes()}.
*/ */
boolean isRequestControllerAttributes(); boolean isRequestControllerAttributes();
} }