Feature Reset Target Attributes (#664)

* Enhance DDI putConfigData REST entry point with update mode

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* ControllerManagement unit tests for new target attribute update modes

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Added DdiRootControllerRestApi test for new update mode

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Enhance DMF UPDATE_ATTRIBUTES message with update mode

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Enhance DMF integration tests

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Enhance DMF integration tests

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Fix DMF integration tests

* Fix failing tests

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Fix failing tests

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Fix Sonar findings

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Javadoc improvements

Signed-off-by: stefbehl <stefan.behl@bosch-si.com>

* Fix codacy findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>
This commit is contained in:
Stefan Behl
2018-03-26 17:50:20 +02:00
committed by Kai Zimmermann
parent e700acc312
commit 607cf92a9e
19 changed files with 746 additions and 125 deletions

View File

@@ -38,6 +38,7 @@ import org.eclipse.hawkbit.repository.QuotaManagement;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
@@ -666,18 +667,41 @@ public class JpaControllerManagement implements ControllerManagement {
@Transactional
@Retryable(include = {
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Target updateControllerAttributes(final String controllerId, final Map<String, String> data) {
public Target updateControllerAttributes(final String controllerId, final Map<String, String> data,
final UpdateMode mode) {
final JpaTarget target = (JpaTarget) targetRepository.findByControllerId(controllerId)
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
target.getControllerAttributes().putAll(data);
// get the modifiable attribute map
final Map<String, String> controllerAttributes = target.getControllerAttributes();
if (target.getControllerAttributes().size() > quotaManagement.getMaxAttributeEntriesPerTarget()) {
throw new QuotaExceededException("Controller attribues", target.getControllerAttributes().size(),
quotaManagement.getMaxAttributeEntriesPerTarget());
final UpdateMode updateMode = mode != null ? mode : UpdateMode.MERGE;
switch (updateMode) {
case REMOVE:
// remove the addressed attributes
data.keySet().forEach(controllerAttributes::remove);
break;
case REPLACE:
// clear the attributes before adding the new attributes
controllerAttributes.clear();
controllerAttributes.putAll(data);
target.setRequestControllerAttributes(false);
break;
case MERGE:
// just merge the attributes in
controllerAttributes.putAll(data);
target.setRequestControllerAttributes(false);
break;
default:
// unknown update mode
throw new IllegalStateException("The update mode " + updateMode + " is not supported.");
}
target.setRequestControllerAttributes(false);
final int attributeCount = controllerAttributes.size();
if (attributeCount > quotaManagement.getMaxAttributeEntriesPerTarget()) {
throw new QuotaExceededException("Controller attributes", attributeCount,
quotaManagement.getMaxAttributeEntriesPerTarget());
}
return targetRepository.save(target);
}

View File

@@ -16,6 +16,7 @@ import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -24,6 +25,7 @@ import javax.validation.ConstraintViolationException;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.UpdateMode;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
@@ -121,8 +123,8 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
verifyThrownExceptionBy(() -> controllerManagement.registerRetrieved(NOT_EXIST_IDL, "test message"), "Action");
verifyThrownExceptionBy(() -> controllerManagement.updateControllerAttributes(NOT_EXIST_ID, Maps.newHashMap()),
"Target");
verifyThrownExceptionBy(
() -> controllerManagement.updateControllerAttributes(NOT_EXIST_ID, Maps.newHashMap(), null), "Target");
}
@Test
@@ -658,7 +660,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
private void addAttributeAndVerify(final String controllerId) {
final Map<String, String> testData = Maps.newHashMapWithExpectedSize(1);
testData.put("test1", "testdata1");
controllerManagement.updateControllerAttributes(controllerId, testData);
controllerManagement.updateControllerAttributes(controllerId, testData, null);
assertThat(targetManagement.getControllerAttributes(controllerId)).as("Controller Attributes are wrong")
.isEqualTo(testData);
@@ -668,7 +670,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
private void addSecondAttributeAndVerify(final String controllerId) {
final Map<String, String> testData = Maps.newHashMapWithExpectedSize(2);
testData.put("test2", "testdata20");
controllerManagement.updateControllerAttributes(controllerId, testData);
controllerManagement.updateControllerAttributes(controllerId, testData, null);
testData.put("test1", "testdata1");
assertThat(targetManagement.getControllerAttributes(controllerId)).as("Controller Attributes are wrong")
@@ -680,13 +682,111 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Map<String, String> testData = Maps.newHashMapWithExpectedSize(2);
testData.put("test1", "testdata12");
controllerManagement.updateControllerAttributes(controllerId, testData);
controllerManagement.updateControllerAttributes(controllerId, testData, null);
testData.put("test2", "testdata20");
assertThat(targetManagement.getControllerAttributes(controllerId)).as("Controller Attributes are wrong")
.isEqualTo(testData);
}
@Test
@Description("Ensures that target attributes can be updated using different update modes.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 4) })
public void updateTargetAttributesWithDifferentUpdateModes() {
final String controllerId = "testCtrl";
testdataFactory.createTarget(controllerId);
// no update mode
updateTargetAttributesWithoutUpdateMode(controllerId);
// update mode REPLACE
updateTargetAttributesWithUpdateModeReplace(controllerId);
// update mode MERGE
updateTargetAttributesWithUpdateModeMerge(controllerId);
// update mode REMOVE
updateTargetAttributesWithUpdateModeRemove(controllerId);
}
@Step
private void updateTargetAttributesWithUpdateModeRemove(final String controllerId) {
final int previousSize = targetManagement.getControllerAttributes(controllerId).size();
// update the attributes using update mode REMOVE
final Map<String, String> removeAttributes = new HashMap<>();
removeAttributes.put("k1", "foo");
removeAttributes.put("k3", "bar");
controllerManagement.updateControllerAttributes(controllerId, removeAttributes, UpdateMode.REMOVE);
// verify attribute removal
final Map<String, String> updatedAttributes = targetManagement.getControllerAttributes(controllerId);
assertThat(updatedAttributes.size()).isEqualTo(previousSize - 2);
assertThat(updatedAttributes).doesNotContainKeys("k1", "k3");
}
@Step
private void updateTargetAttributesWithUpdateModeMerge(final String controllerId) {
// get the current attributes
final HashMap<String, String> attributes = new HashMap<>(
targetManagement.getControllerAttributes(controllerId));
// update the attributes using update mode MERGE
final Map<String, String> mergeAttributes = new HashMap<>();
mergeAttributes.put("k1", "v1_modified_again");
mergeAttributes.put("k4", "v4");
controllerManagement.updateControllerAttributes(controllerId, mergeAttributes, UpdateMode.MERGE);
// verify attribute merge
final Map<String, String> updatedAttributes = targetManagement.getControllerAttributes(controllerId);
assertThat(updatedAttributes.size()).isEqualTo(4);
assertThat(updatedAttributes).containsAllEntriesOf(mergeAttributes);
assertThat(updatedAttributes.get("k1")).isEqualTo("v1_modified_again");
attributes.keySet().forEach(assertThat(updatedAttributes)::containsKey);
}
@Step
private void updateTargetAttributesWithUpdateModeReplace(final String controllerId) {
// get the current attributes
final HashMap<String, String> attributes = new HashMap<>(
targetManagement.getControllerAttributes(controllerId));
// update the attributes using update mode REPLACE
final Map<String, String> replacementAttributes = new HashMap<>();
replacementAttributes.put("k1", "v1_modified");
replacementAttributes.put("k2", "v2");
replacementAttributes.put("k3", "v3");
controllerManagement.updateControllerAttributes(controllerId, replacementAttributes, UpdateMode.REPLACE);
// verify attribute replacement
final Map<String, String> updatedAttributes = targetManagement.getControllerAttributes(controllerId);
assertThat(updatedAttributes.size()).isEqualTo(replacementAttributes.size());
assertThat(updatedAttributes).containsAllEntriesOf(replacementAttributes);
assertThat(updatedAttributes.get("k1")).isEqualTo("v1_modified");
attributes.entrySet().forEach(assertThat(updatedAttributes)::doesNotContain);
}
@Step
private void updateTargetAttributesWithoutUpdateMode(final String controllerId) {
// set the initial attributes
final Map<String, String> attributes = new HashMap<>();
attributes.put("k0", "v0");
attributes.put("k1", "v1");
controllerManagement.updateControllerAttributes(controllerId, attributes, null);
// verify initial attributes
final Map<String, String> updatedAttributes = targetManagement.getControllerAttributes(controllerId);
assertThat(updatedAttributes.size()).isEqualTo(attributes.size());
assertThat(updatedAttributes).containsAllEntriesOf(attributes);
}
@Test
@Description("Ensures that target attribute update fails if quota hits.")
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
@@ -730,7 +830,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
for (int i = 0; i < allowedAttributes; i++) {
testData.put(keyPrefix + i, valuePrefix);
}
controllerManagement.updateControllerAttributes(controllerId, testData);
controllerManagement.updateControllerAttributes(controllerId, testData, null);
}
@Test

View File

@@ -418,7 +418,7 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
testData.put("test1", "testdata1");
targetManagement.create(entityFactory.target().create().controllerId(controllerId));
final Target target = controllerManagement.updateControllerAttributes(controllerId, testData);
final Target target = controllerManagement.updateControllerAttributes(controllerId, testData, null);
assertThat(targetManagement.getControllerAttributes(controllerId)).as("Controller Attributes are wrong")
.isEqualTo(testData);

View File

@@ -47,14 +47,14 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
target = targetManagement.create(entityFactory.target().create().controllerId("targetId123")
.name("targetName123").description("targetDesc123"));
attributes.put("revision", "1.1");
target = controllerManagement.updateControllerAttributes(target.getControllerId(), attributes);
target = controllerManagement.updateControllerAttributes(target.getControllerId(), attributes, null);
target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(target.getControllerId(), LOCALHOST);
target2 = targetManagement
.create(entityFactory.target().create().controllerId("targetId1234").description("targetId1234"));
attributes.put("revision", "1.2");
Thread.sleep(1);
target2 = controllerManagement.updateControllerAttributes(target2.getControllerId(), attributes);
target2 = controllerManagement.updateControllerAttributes(target2.getControllerId(), attributes, null);
target2 = controllerManagement.findOrRegisterTargetIfItDoesNotexist(target2.getControllerId(), LOCALHOST);
final Target target3 = testdataFactory.createTarget("targetId1235");