Introduce new DMF message THING_REMOVED (#891)

* Introduce new DMF message THING_REMOVED

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* rename test to its original name

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* API documentation adapted; constant defined for duplicated string

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* Resolve review comments; Replace try/catch blocks in exceptions testing

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* Re-add finally block in test cases

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>
This commit is contained in:
Natalia Kislicyn
2019-10-10 14:41:47 +02:00
committed by Dominic Schabel
parent 8687510131
commit 193603282a
7 changed files with 316 additions and 220 deletions

View File

@@ -48,14 +48,14 @@ public interface ControllerManagement {
/**
* Adds an {@link ActionStatus} for a cancel {@link Action} including
* potential state changes for the target and the {@link Action} itself.
*
*
* @param create
* to be added
* @return the updated {@link Action}
*
*
* @throws EntityAlreadyExistsException
* if a given entity already exists
*
*
* @throws QuotaExceededException
* if more than the allowed number of status entries or messages
* per entry are inserted
@@ -64,14 +64,14 @@ public interface ControllerManagement {
* @throws ConstraintViolationException
* if fields are not filled as specified. Check
* {@link ActionStatusCreate} for field constraints.
*
*
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Action addCancelActionStatus(@NotNull @Valid ActionStatusCreate create);
/**
* Retrieves assigned {@link SoftwareModule} of a target.
*
*
* @param moduleId
* of the {@link SoftwareModule}
* @return {@link SoftwareModule} identified by ID
@@ -82,7 +82,7 @@ public interface ControllerManagement {
/**
* Retrieves {@link SoftwareModuleMetadata} where
* {@link SoftwareModuleMetadata#isTargetVisible()}.
*
*
* @param moduleId
* of the {@link SoftwareModule}
* @return list of {@link SoftwareModuleMetadata} with maximum size of
@@ -95,12 +95,12 @@ public interface ControllerManagement {
/**
* Simple addition of a new {@link ActionStatus} entry to the {@link Action}
* . No state changes.
*
*
* @param create
* to add to the action
*
*
* @return created {@link ActionStatus} entity
*
*
* @throws QuotaExceededException
* if more than the allowed number of status entries or messages
* per entry are inserted
@@ -138,15 +138,15 @@ public interface ControllerManagement {
/**
* Retrieves oldest {@link Action} that is active and assigned to a
* {@link Target}.
*
*
* For performance reasons this method does not throw
* {@link EntityNotFoundException} in case target with given controlelrId
* {@link EntityNotFoundException} in case target with given controllerId
* does not exist but will return an {@link Optional#empty()} instead.
*
* @param controllerId
* identifies the target to retrieve the actions from
* @return a list of actions assigned to given target which are active
*
*
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Optional<Action> findOldestActiveActionByTarget(@NotEmpty String controllerId);
@@ -154,7 +154,7 @@ public interface ControllerManagement {
/**
* Retrieves all active actions which are assigned to the target with the
* given controller ID.
*
*
* @param pageable
* pagination parameter
* @param controllerId
@@ -184,7 +184,7 @@ public interface ControllerManagement {
* @param actionId
* to be filtered on
* @return the corresponding {@link Page} of {@link ActionStatus}
*
*
* @throws EntityNotFoundException
* if action with given ID does not exist
*/
@@ -217,7 +217,7 @@ public interface ControllerManagement {
* of the the {@link SoftwareModule} that should be assigned to
* the target
* @return last {@link Action} for given combination
*
*
* @throws EntityNotFoundException
* if target with given ID does not exist
*
@@ -244,7 +244,7 @@ public interface ControllerManagement {
/**
* Returns the count to be used for reducing polling interval while calling
* {@link ControllerManagement#getPollingTimeForAction()}.
* {@link ControllerManagement#getPollingTimeForAction(long)}.
*
* @return configured value of
* {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}.
@@ -277,7 +277,7 @@ public interface ControllerManagement {
* a target is allowed to download a given artifact because it has currently
* assigned or had ever been assigned to the target and so it's visible to a
* specific target e.g. for downloading.
*
*
* @param controllerId
* the ID of the target to check
* @param sha1Hash
@@ -286,7 +286,7 @@ public interface ControllerManagement {
* @return {@code true} if the given target has currently or had ever a
* relation to the given artifact through the action history,
* otherwise {@code false}
*
*
* @throws EntityNotFoundException
* if target with given ID does not exist
*/
@@ -299,7 +299,7 @@ public interface ControllerManagement {
* a target is allowed to download a given artifact because it has currently
* assigned or had ever been assigned to the target and so it's visible to a
* specific target e.g. for downloading.
*
*
* @param targetId
* the ID of the target to check
* @param sha1Hash
@@ -308,7 +308,7 @@ public interface ControllerManagement {
* @return {@code true} if the given target has currently or had ever a
* relation to the given artifact through the action history,
* otherwise {@code false}
*
*
* @throws EntityNotFoundException
* if target with given ID does not exist
*/
@@ -325,7 +325,7 @@ public interface ControllerManagement {
* for the status
* @return the update action in case the status has been changed to
* {@link Status#RETRIEVED}
*
*
* @throws EntityNotFoundException
* if action with given ID does not exist
*/
@@ -432,7 +432,7 @@ public interface ControllerManagement {
/**
* Updates given {@link Action} with its external id.
*
*
* @param actionId
* to be updated
* @param externalRef
@@ -451,4 +451,13 @@ public interface ControllerManagement {
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
List<Action> getActiveActionsByExternalRef(@NotNull List<String> externalRefs);
/**
* Delete a single target.
*
* @param controllerId
* of the target to delete
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
void deleteExistingTarget(@NotEmpty String controllerId);
}

View File

@@ -193,7 +193,7 @@ public class JpaControllerManagement implements ControllerManagement {
/**
* Returns the count to be used for reducing polling interval while calling
* {@link ControllerManagement#getPollingTimeForAction()}.
* {@link ControllerManagement#getPollingTimeForAction(long)}.
*
* @return configured value of
* {@link TenantConfigurationKey#MAINTENANCE_WINDOW_POLL_COUNT}.
@@ -243,7 +243,7 @@ public class JpaControllerManagement implements ControllerManagement {
* @param minimumEventInterval
* for loading {@link DistributionSet#getModules()}. This
* puts a lower bound to the timer value
* @param timerUnit
* @param timeUnit
* representing the unit of time to be used for timer.
*/
EventTimer(final String defaultEventInterval, final String minimumEventInterval, final TemporalUnit timeUnit) {
@@ -375,6 +375,13 @@ public class JpaControllerManagement implements ControllerManagement {
return actionRepository.findByExternalRefInAndActive(externalRefs, true);
}
@Override
public void deleteExistingTarget(@NotEmpty String controllerId) {
final Target target = targetRepository.findByControllerId(controllerId)
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
targetRepository.deleteById(target.getId());
}
@Override
@Transactional(isolation = Isolation.READ_COMMITTED)
@Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
@@ -997,8 +1004,8 @@ public class JpaControllerManagement implements ControllerManagement {
* Cancels given {@link Action} for this {@link Target}. The method will
* immediately add a {@link Status#CANCELED} status to the action. However,
* it might be possible that the controller will continue to work on the
* cancelation. The controller needs to acknowledge or reject the
* cancelation using {@link DdiRootController#postCancelActionFeedback}.
* cancellation. The controller needs to acknowledge or reject the
* cancellation using {@link DdiRootController#postCancelActionFeedback}.
*
* @param actionId
* to be canceled

View File

@@ -14,7 +14,6 @@ import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpre
import static org.eclipse.hawkbit.repository.jpa.configuration.Constants.TX_RT_MAX;
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
import static org.eclipse.hawkbit.repository.test.util.TestdataFactory.DEFAULT_CONTROLLER_ID;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -40,6 +39,7 @@ 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.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;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
@@ -51,6 +51,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
@@ -89,7 +90,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
private RepositoryProperties repositoryProperties;
@Test
@Description("Verifies that management get access react as specfied on calls for non existing entities by means "
@Description("Verifies that management get access react as specified on calls for non existing entities by means "
+ "of Optional not present.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 1)})
@@ -110,7 +111,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Verifies that management queries react as specfied on calls for non existing entities "
@Description("Verifies that management queries react as specified on calls for non existing entities "
+ " by means of throwing EntityNotFoundException.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 1)})
@@ -147,7 +148,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Controller confirms successfull update with FINISHED status.")
@Description("Controller confirms successful update with FINISHED status.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1),
@@ -170,7 +171,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Controller confirmation failes with invalid messages.")
@Description("Controller confirmation fails with invalid messages.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1),
@@ -182,23 +183,23 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
simulateIntermediateStatusOnUpdate(actionId);
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set invalid description text should not be created")
.isThrownBy(() -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus()
.create(actionId).status(Action.Status.FINISHED).message(INVALID_TEXT_HTML)))
.as("set invalid description text should not be created");
.create(actionId).status(Action.Status.FINISHED).message(INVALID_TEXT_HTML)));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("set invalid description text should not be created")
.isThrownBy(() -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)
.messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML))))
.as("set invalid description text should not be created");
.messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML))));
assertThat(actionStatusRepository.count()).isEqualTo(6);
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(6);
}
@Test
@Description("Controller confirms successfull update with FINISHED status on a action that is on canceling. "
+ "Reason: The decission to ignore the cancellation is in fact up to the controller.")
@Description("Controller confirms successful update with FINISHED status on a action that is on canceling. "
+ "Reason: The decision to ignore the cancellation is in fact up to the controller.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2),
@@ -207,7 +208,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
public void controllerConfirmsUpdateWithFinishedAndIgnorsCancellationWithThat() {
public void controllerConfirmsUpdateWithFinishedAndIgnoresCancellationWithThat() {
final Long actionId = createTargetAndAssignDs();
deploymentManagement.cancelAction(actionId);
@@ -221,7 +222,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Update server rejects cancelation feedback if action is not in CANCELING state.")
@Description("Update server rejects cancellation feedback if action is not in CANCELING state.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1),
@@ -230,24 +231,20 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
public void cancellationFeedbackRejectedIfActionIsNotInCanceling() {
final Long actionId = createTargetAndAssignDs();
try {
controllerManagement.addCancelActionStatus(
entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
fail("Expected " + CancelActionNotAllowedException.class.getName());
} catch (final CancelActionNotAllowedException e) {
// expected
}
assertThatExceptionOfType(CancelActionNotAllowedException.class)
.as("Expected " + CancelActionNotAllowedException.class.getName())
.isThrownBy(() -> controllerManagement.addCancelActionStatus(
entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)));
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING,
Action.Status.RUNNING, true);
assertThat(actionStatusRepository.count()).isEqualTo(1);
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(1);
}
@Test
@Description("Controller confirms action cancelation with FINISHED status.")
@Description("Controller confirms action cancellation with FINISHED status.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2),
@@ -255,7 +252,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
public void controllerConfirmsActionCancelationWithFinished() {
public void controllerConfirmsActionCancellationWithFinished() {
final Long actionId = createTargetAndAssignDs();
deploymentManagement.cancelAction(actionId);
@@ -274,7 +271,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Controller confirms action cancelation with FINISHED status.")
@Description("Controller confirms action cancellation with FINISHED status.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 2),
@@ -282,7 +279,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
public void controllerConfirmsActionCancelationWithCanceled() {
public void controllerConfirmsActionCancellationWithCanceled() {
final Long actionId = createTargetAndAssignDs();
deploymentManagement.cancelAction(actionId);
@@ -301,7 +298,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Controller rejects action cancelation with CANCEL_REJECTED status. Action goes back to RUNNING status as it expects "
@Description("Controller rejects action cancellation with CANCEL_REJECTED status. Action goes back to RUNNING status as it expects "
+ "that the controller will continue the original update.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@@ -310,7 +307,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
public void controllerRejectsActionCancelationWithReject() {
public void controllerRejectsActionCancellationWithReject() {
final Long actionId = createTargetAndAssignDs();
deploymentManagement.cancelAction(actionId);
@@ -329,7 +326,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Controller rejects action cancelation with ERROR status. Action goes back to RUNNING status as it expects "
@Description("Controller rejects action cancellation with ERROR status. Action goes back to RUNNING status as it expects "
+ "that the controller will continue the original update.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@@ -338,7 +335,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
public void controllerRejectsActionCancelationWithError() {
public void controllerRejectsActionCancellationWithError() {
final Long actionId = createTargetAndAssignDs();
deploymentManagement.cancelAction(actionId);
@@ -466,7 +463,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Verifies that assignement verification works based on SHA1 hash. By design it is not important which artifact "
@Description("Verifies that assignment verification works based on SHA1 hash. By design it is not important which artifact "
+ "is actually used for the check as long as they have an identical binary, i.e. same SHA1 hash. ")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@@ -511,28 +508,28 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Target sameTarget = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
assertThat(target.getId()).as("Target should be the equals").isEqualTo(sameTarget.getId());
assertThat(targetRepository.count()).as("Only 1 target should be registred").isEqualTo(1L);
assertThat(targetRepository.count()).as("Only 1 target should be registered").isEqualTo(1L);
}
@Test
@Description("Tries to register a target with an invalid controller id")
public void findOrRegisterTargetIfItDoesNotExistThrowsExceptionForInvalidControllerIdParam() {
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST))
.as("register target with null as controllerId should fail");
.as("register target with null as controllerId should fail")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(null, LOCALHOST));
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("", LOCALHOST))
.as("register target with empty controllerId should fail");
.as("register target with empty controllerId should fail")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("", LOCALHOST));
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST))
.as("register target with empty controllerId should fail");
.as("register target with empty controllerId should fail")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST));
assertThatExceptionOfType(ConstraintViolationException.class)
.as("register target with too long controllerId should fail")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(
RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST))
.as("register target with too long controllerId should fail");
RandomStringUtils.randomAlphabetic(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST));
}
@Test
@@ -544,11 +541,13 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
((JpaControllerManagement) controllerManagement).setTargetRepository(mockTargetRepository);
try {
controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
fail("Expected an ConcurrencyFailureException to be thrown!");
} catch (final ConcurrencyFailureException e) {
assertThatExceptionOfType(ConcurrencyFailureException.class)
.as("Expected an ConcurrencyFailureException to be thrown!")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST));
verify(mockTargetRepository, times(TX_RT_MAX)).findOne(any());
} finally {
}
finally {
// revert
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
}
@@ -593,12 +592,13 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
when(mockTargetRepository.save(any())).thenThrow(EntityAlreadyExistsException.class);
try {
controllerManagement.findOrRegisterTargetIfItDoesNotExist("1234", LOCALHOST);
fail("Expected an EntityAlreadyExistsException to be thrown!");
} catch (final EntityAlreadyExistsException e) {
assertThatExceptionOfType(EntityAlreadyExistsException.class)
.as("Expected an EntityAlreadyExistsException to be thrown!")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("1234", LOCALHOST));
verify(mockTargetRepository, times(1)).findOne(any());
verify(mockTargetRepository, times(1)).save(any());
} finally {
}
finally {
// revert
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
}
@@ -615,11 +615,13 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
when(mockTargetRepository.findOne(any())).thenThrow(RuntimeException.class);
try {
controllerManagement.findOrRegisterTargetIfItDoesNotExist("aControllerId", LOCALHOST);
fail("Expected a RuntimeException to be thrown!");
} catch (final RuntimeException e) {
assertThatExceptionOfType(RuntimeException.class)
.as("Expected a RuntimeException to be thrown!")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist("aControllerId",
LOCALHOST));
verify(mockTargetRepository, times(1)).findOne(any());
} finally {
}
finally {
// revert
((JpaControllerManagement) controllerManagement).setTargetRepository(targetRepository);
}
@@ -639,7 +641,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
set.getModules().stream().map(SoftwareModule::getId).collect(Collectors.toList()));
assertThat(result).hasSize(3);
result.entrySet().forEach(entry -> assertThat(entry.getValue()).hasSize(1));
result.forEach((key, value) -> assertThat(value).hasSize(1));
}
@Test
@@ -684,7 +686,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
Action.Status.ERROR, false);
// try with enabled late feedback - should not make a difference as it
// only allows intermediate feedbacks and not multiple close
// only allows intermediate feedback and not multiple close
repositoryProperties.setRejectActionStatusForClosedAction(false);
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
@@ -699,7 +701,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Controller trys to finish an update process after it has been finished by an FINISHED action status.")
@Description("Controller tries to finish an update process after it has been finished by an FINISHED action status.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1),
@@ -720,7 +722,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
Action.Status.FINISHED, false);
// try with enabled late feedback - should not make a difference as it
// only allows intermediate feedbacks and not multiple close
// only allows intermediate feedback and not multiple close
repositoryProperties.setRejectActionStatusForClosedAction(false);
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
@@ -735,7 +737,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Controller trys to send an update feedback after it has been finished which is reject as the repository is "
@Description("Controller tries to send an update feedback after it has been finished which is reject as the repository is "
+ "configured to reject that.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@@ -744,7 +746,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
public void sendUpdatesForFinishUpdateProcessDropedIfDisabled() {
public void sendUpdatesForFinishUpdateProcessDroppedIfDisabled() {
repositoryProperties.setRejectActionStatusForClosedAction(true);
final Action action = prepareFinishedUpdate();
@@ -762,7 +764,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Controller trys to send an update feedback after it has been finished which is accepted as the repository is "
@Description("Controller tries to send an update feedback after it has been finished which is accepted as the repository is "
+ "configured to accept them.")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@@ -1001,24 +1003,24 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
testdataFactory.createTarget(controllerId);
assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with key too long should not be created")
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId,
Collections.singletonMap(keyTooLong, valueValid), null))
.as("Attribute with key too long should not be created");
Collections.singletonMap(keyTooLong, valueValid), null));
assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with key too long and value too long should not be created")
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId,
Collections.singletonMap(keyTooLong, valueTooLong), null))
.as("Attribute with key too long and value too long should not be created");
Collections.singletonMap(keyTooLong, valueTooLong), null));
assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with value too long should not be created")
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId,
Collections.singletonMap(keyValid, valueTooLong), null))
.as("Attribute with value too long should not be created");
Collections.singletonMap(keyValid, valueTooLong), null));
assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with key NULL should not be created")
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId,
Collections.singletonMap(keyNull, valueValid), null))
.as("Attribute with key NULL should not be created");
Collections.singletonMap(keyNull, valueValid), null));
}
@Test
@@ -1253,32 +1255,26 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() {
public void quotaExceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() {
final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus();
testdataFactory.createTarget();
final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull();
try {
IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)));
fail("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates");
} catch (final QuotaExceededException e) {
}
assertThatExceptionOfType(QuotaExceededException.class)
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
try {
IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR)));
fail("No QuotaExceededException thrown for too many ERROR updateActionStatus updates");
} catch (final QuotaExceededException e) {
}
assertThatExceptionOfType(QuotaExceededException.class)
.as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates")
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR))));
try {
IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED)));
fail("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates");
} catch (final QuotaExceededException e) {
}
assertThatExceptionOfType(QuotaExceededException.class)
.as("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates")
.isThrownBy(() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED))));
}
@Test
@@ -1288,35 +1284,29 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3)})
public void quotaEceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForForced() {
public void quotaExceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForForced() {
final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus();
final Long actionId = createTargetAndAssignDs();
assertThat(actionId).isNotNull();
try {
IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)));
fail("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates");
} catch (final QuotaExceededException e) {
}
assertThatExceptionOfType(QuotaExceededException.class)
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
.isThrownBy( ()-> IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
try {
IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR)));
fail("No QuotaExceededException thrown for too many ERROR updateActionStatus updates");
} catch (final QuotaExceededException e) {
}
assertThatExceptionOfType(QuotaExceededException.class)
.as("No QuotaExceededException thrown for too many ERROR updateActionStatus updates")
.isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR))));
try {
IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED)));
fail("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates");
} catch (final QuotaExceededException e) {
}
assertThatExceptionOfType(QuotaExceededException.class)
.as("No QuotaExceededException thrown for too many FINISHED updateActionStatus updates")
.isThrownBy(()->IntStream.range(0, maxMessages).forEach(i -> controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED))));
}
@Test
@Description("Verify that the attaching externalRef to an action is propery stored")
@Description("Verify that the attaching externalRef to an action is properly stored")
public void updatedExternalRefOnActionIsReallyUpdated() {
final List<String> allExternalRef = new ArrayList<>();
final List<Long> allActionId = new ArrayList<>();
@@ -1324,15 +1314,15 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
final DistributionSet knownDistributionSet = testdataFactory.createDistributionSet();
for (int i = 0; i < numberOfActions; i++) {
final String knownControllerId = "controllerId" + i;
final String knownExternalref = "externalRefId" + i;
final String knownExternalRef = "externalRefId" + i;
testdataFactory.createTarget(knownControllerId);
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(knownDistributionSet.getId(),
knownControllerId);
final Long actionId = getFirstAssignedActionId(assignmentResult);
controllerManagement.updateActionExternalRef(actionId, knownExternalref);
controllerManagement.updateActionExternalRef(actionId, knownExternalRef);
allExternalRef.add(knownExternalref);
allExternalRef.add(knownExternalRef);
allActionId.add(actionId);
}
@@ -1346,11 +1336,9 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Verify that a null externalRef cannot be assigned to an action")
public void externalRefCannotBeNull() {
try {
controllerManagement.updateActionExternalRef(1L, null);
fail("No ConstraintViolationException thrown when a null externalRef was set on an action");
} catch (final ConstraintViolationException e) {
}
assertThatExceptionOfType(ConstraintViolationException.class)
.as("No ConstraintViolationException thrown when a null externalRef was set on an action")
.isThrownBy(() -> controllerManagement.updateActionExternalRef(1L, null));
}
@Test
@@ -1470,4 +1458,47 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(actionRepository.activeActionExistsForControllerId(controllerId)).isEqualTo(false);
}
@Test
@Description("Delete a target on requested target deletion from client side")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TargetDeletedEvent.class, count = 1)})
public void deleteTargetWithValidThingId() {
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
assertThat(target).as("target should not be null").isNotNull();
assertThat(targetRepository.count()).as("target exists and is ready for deletion").isEqualTo(1L);
controllerManagement.deleteExistingTarget(target.getControllerId());
assertThat(targetRepository.count()).as("target should not exist anymore").isEqualTo(0L);
}
@Test
@Description("Delete a target with a non existing thingId")
@ExpectEvents({@Expect(type = TargetDeletedEvent.class, count = 0)})
public void deleteTargetWithInvalidThingId() {
assertThatExceptionOfType(EntityNotFoundException.class)
.as("No EntityNotFoundException thrown when deleting a non-existing target")
.isThrownBy(() -> controllerManagement.deleteExistingTarget("BB"));
assertThat(targetRepository.count()).as("target should not exist").isEqualTo(0L);
}
@Test
@Description("Delete a target after it has been deleted already")
@ExpectEvents({@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1),
@Expect(type = TargetDeletedEvent.class, count = 1)})
public void deleteTargetAfterItWasDeleted() {
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
assertThat(target).as("target should not be null").isNotNull();
assertThat(targetRepository.count()).as("target exists and is ready for deletion").isEqualTo(1L);
controllerManagement.deleteExistingTarget(target.getControllerId());
assertThat(targetRepository.count()).as("target should not exist anymore").isEqualTo(0L);
assertThatExceptionOfType(EntityNotFoundException.class)
.as("No EntityNotFoundException thrown when deleting a non-existing target")
.isThrownBy(() -> controllerManagement.deleteExistingTarget(target.getControllerId()));
}
}