Sonar Fixes (8) (#2220)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-01-23 13:23:28 +02:00
committed by GitHub
parent bb9c9bfad8
commit 21b901a559
7 changed files with 168 additions and 138 deletions

View File

@@ -78,7 +78,7 @@ public class JpaActionManagement {
} }
log.debug( log.debug(
"Update of actionStatus {} for action {} not possible since action not active anymore.", "Update of actionStatus {} for action {} not possible since action not active anymore and not allowed as an action terminating.",
actionStatus.getStatus(), action.getId()); actionStatus.getStatus(), action.getId());
return action; return action;
} }
@@ -133,16 +133,17 @@ public class JpaActionManagement {
* status updates only once. * status updates only once.
*/ */
private boolean isUpdatingActionStatusAllowed(final JpaAction action, final JpaActionStatus actionStatus) { private boolean isUpdatingActionStatusAllowed(final JpaAction action, final JpaActionStatus actionStatus) {
if (action.isActive()) {
return true;
}
final boolean intermediateStatus = isIntermediateStatus(actionStatus); if (isIntermediateStatus(actionStatus)) {
return !repositoryProperties.isRejectActionStatusForClosedAction();
final boolean isAllowedByRepositoryConfiguration = intermediateStatus && !repositoryProperties.isRejectActionStatusForClosedAction(); } else {
// in case of download_only action Status#DOWNLOADED is treated as 'final' already,
//in case of download_only action Status#DOWNLOADED is treated as 'final' already, so we accept one final status from device in case it sends // so we accept one final status from device in case it sends
final boolean isAllowedForDownloadOnlyActions = isDownloadOnly( return isDownloadOnly(action) && action.getStatus() == Action.Status.DOWNLOADED;
action) && action.getStatus() == Action.Status.DOWNLOADED && !intermediateStatus; }
return action.isActive() || isAllowedByRepositoryConfiguration || isAllowedForDownloadOnlyActions;
} }
/** /**

View File

@@ -58,7 +58,7 @@ public interface ACMRepository<T> {
* @return matching entity * @return matching entity
*/ */
@NonNull @NonNull
Optional<T> findOne(@Nullable AccessController.Operation operation, @Nullable Specification<T> spec); Optional<T> findOne(@Nullable AccessController.Operation operation, @NonNull Specification<T> spec);
/** /**
* Returns all entries that match specification and the operation is allowed for. * Returns all entries that match specification and the operation is allowed for.

View File

@@ -19,7 +19,6 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -39,6 +38,10 @@ import org.springframework.lang.Nullable;
@Slf4j @Slf4j
public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity> implements BaseEntityRepository<T> { public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity> implements BaseEntityRepository<T> {
private static final String SPEC_MUST_NOT_BE_NULL = "Specification must not be null";
private static final String APPENDED_ACCESS_RULES_SPEC_OF_NON_NULL_SPEC_MUST_NOT_BE_NULL =
"Appended access rules specification of non-null specification must not be null";
private final BaseEntityRepository<T> repository; private final BaseEntityRepository<T> repository;
private final AccessController<T> accessController; private final AccessController<T> accessController;
@@ -147,7 +150,12 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
@Override @Override
@NonNull @NonNull
public Optional<T> findOne(final Specification<T> spec) { public Optional<T> findOne(final Specification<T> spec) {
return repository.findOne(accessController.appendAccessRules(AccessController.Operation.READ, spec)); Objects.requireNonNull(spec, SPEC_MUST_NOT_BE_NULL);
return repository.findOne(
// spec shall be non-null and the result of appending rules shall be non-null
Objects.requireNonNull(
accessController.appendAccessRules(AccessController.Operation.READ, spec),
APPENDED_ACCESS_RULES_SPEC_OF_NON_NULL_SPEC_MUST_NOT_BE_NULL));
} }
@Override @Override
@@ -186,7 +194,13 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
@Override @Override
public <S extends T, R> R findBy(final Specification<T> spec, final Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) { public <S extends T, R> R findBy(final Specification<T> spec, final Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
return repository.findBy(accessController.appendAccessRules(AccessController.Operation.READ, spec), queryFunction); Objects.requireNonNull(spec, SPEC_MUST_NOT_BE_NULL);
return repository.findBy(
// spec shall be non-null and the result of appending rules shall be non-null
Objects.requireNonNull(
accessController.appendAccessRules(AccessController.Operation.READ, spec),
APPENDED_ACCESS_RULES_SPEC_OF_NON_NULL_SPEC_MUST_NOT_BE_NULL),
queryFunction);
} }
@Override @Override
@@ -232,11 +246,16 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
} }
@NonNull @NonNull
public Optional<T> findOne(@Nullable AccessController.Operation operation, @Nullable Specification<T> spec) { public Optional<T> findOne(@Nullable AccessController.Operation operation, @NonNull Specification<T> spec) {
Objects.requireNonNull(spec, SPEC_MUST_NOT_BE_NULL);
if (operation == null) { if (operation == null) {
return repository.findOne(spec); return repository.findOne(spec);
} else { } else {
return repository.findOne(accessController.appendAccessRules(operation, spec)); return repository.findOne(
// spec shall be non-null and the result of appending rules shall be non-null
Objects.requireNonNull(
accessController.appendAccessRules(operation, spec),
APPENDED_ACCESS_RULES_SPEC_OF_NON_NULL_SPEC_MUST_NOT_BE_NULL));
} }
} }

View File

@@ -84,7 +84,7 @@ public class HawkbitBaseRepository<T, ID extends Serializable> extends SimpleJpa
} }
@NonNull @NonNull
public Optional<T> findOne(@Nullable AccessController.Operation operation, @Nullable Specification<T> spec) { public Optional<T> findOne(@Nullable AccessController.Operation operation, @NonNull Specification<T> spec) {
return findOne(spec); return findOne(spec);
} }

View File

@@ -74,11 +74,11 @@ class ConcurrentDistributionSetInvalidationTest extends AbstractJpaIntegrationTe
.until(() -> tenantAware.runAsTenant(tenant, () -> systemSecurityContext .until(() -> tenantAware.runAsTenant(tenant, () -> systemSecurityContext
.runAsSystem(() -> rolloutGroupManagement.findByRollout(rollout.getId(), PAGE).getSize() > 0))); .runAsSystem(() -> rolloutGroupManagement.findByRollout(rollout.getId(), PAGE).getSize() > 0)));
final DistributionSetInvalidation distributionSetInvalidation = new DistributionSetInvalidation(
Collections.singletonList(distributionSet.getId()), CancelationType.SOFT, true);
assertThatExceptionOfType(StopRolloutException.class) assertThatExceptionOfType(StopRolloutException.class)
.as("Invalidation of distributionSet should throw an exception") .as("Invalidation of distributionSet should throw an exception")
.isThrownBy(() -> distributionSetInvalidationManagement.invalidateDistributionSet( .isThrownBy(() -> distributionSetInvalidationManagement.invalidateDistributionSet(distributionSetInvalidation));
new DistributionSetInvalidation(Collections.singletonList(distributionSet.getId()),
CancelationType.SOFT, true)));
} }
private Rollout createRollout(final DistributionSet distributionSet) { private Rollout createRollout(final DistributionSet distributionSet) {

View File

@@ -132,11 +132,12 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
final List<Action> actions = assignDistributionSet(dsId, controllerId).getAssignedEntity(); final List<Action> actions = assignDistributionSet(dsId, controllerId).getAssignedEntity();
assertThat(actions).hasSize(1).allMatch(action -> action.getStatus() == Status.WAIT_FOR_CONFIRMATION); assertThat(actions).hasSize(1).allMatch(action -> action.getStatus() == Status.WAIT_FOR_CONFIRMATION);
final Action newAction = confirmationManagement.confirmAction(actions.get(0).getId(), null, null); final Long actionId = actions.get(0).getId();
final Action newAction = confirmationManagement.confirmAction(actionId, null, null);
// verify action in RUNNING state // verify action in RUNNING state
assertThat(newAction.getStatus()).isEqualTo(Status.RUNNING); assertThat(newAction.getStatus()).isEqualTo(Status.RUNNING);
assertThatThrownBy(() -> confirmationManagement.confirmAction(actions.get(0).getId(), null, null)) assertThatThrownBy(() -> confirmationManagement.confirmAction(actionId, null, null))
.isInstanceOf(InvalidConfirmationFeedbackException.class) .isInstanceOf(InvalidConfirmationFeedbackException.class)
.matches(e -> ((InvalidConfirmationFeedbackException) e) .matches(e -> ((InvalidConfirmationFeedbackException) e)
.getReason() == InvalidConfirmationFeedbackException.Reason.NOT_AWAITING_CONFIRMATION); .getReason() == InvalidConfirmationFeedbackException.Reason.NOT_AWAITING_CONFIRMATION);
@@ -146,9 +147,8 @@ class ConfirmationManagementTest extends AbstractJpaIntegrationTest {
@Description("Verify confirming a closed action will lead to a specific failure") @Description("Verify confirming a closed action will lead to a specific failure")
void confirmedActionCannotBeGivenOnFinishedAction() { void confirmedActionCannotBeGivenOnFinishedAction() {
enableConfirmationFlow(); enableConfirmationFlow();
final Action action = prepareFinishedUpdate(); final Long actionId = prepareFinishedUpdate().getId();
assertThatThrownBy(() -> confirmationManagement.confirmAction(actionId, null, null))
assertThatThrownBy(() -> confirmationManagement.confirmAction(action.getId(), null, null))
.isInstanceOf(InvalidConfirmationFeedbackException.class) .isInstanceOf(InvalidConfirmationFeedbackException.class)
.matches(e -> ((InvalidConfirmationFeedbackException) e) .matches(e -> ((InvalidConfirmationFeedbackException) e)
.getReason() == InvalidConfirmationFeedbackException.Reason.ACTION_CLOSED); .getReason() == InvalidConfirmationFeedbackException.Reason.ACTION_CLOSED);

View File

@@ -30,6 +30,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.function.IntConsumer;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import jakarta.validation.ConstraintViolationException; import jakarta.validation.ConstraintViolationException;
@@ -105,8 +106,9 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final int allowedAttributes = quotaManagement.getMaxAttributeEntriesPerTarget(); final int allowedAttributes = quotaManagement.getMaxAttributeEntriesPerTarget();
testdataFactory.createTarget(controllerId); testdataFactory.createTarget(controllerId);
final WithUser withController = SecurityContextSwitch.withController("controller", CONTROLLER_ROLE_ANONYMOUS);
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> SecurityContextSwitch assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> SecurityContextSwitch
.runAs(SecurityContextSwitch.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { .runAs(withController, () -> {
writeAttributes(controllerId, allowedAttributes + 1, "key", "value"); writeAttributes(controllerId, allowedAttributes + 1, "key", "value");
return null; return null;
})).withMessageContaining("" + allowedAttributes); })).withMessageContaining("" + allowedAttributes);
@@ -116,7 +118,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
// Write allowed number of attributes twice with same key should result // Write allowed number of attributes twice with same key should result
// in update but work // in update but work
SecurityContextSwitch.runAs(SecurityContextSwitch.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { SecurityContextSwitch.runAs(withController, () -> {
writeAttributes(controllerId, allowedAttributes, "key", "value1"); writeAttributes(controllerId, allowedAttributes, "key", "value1");
writeAttributes(controllerId, allowedAttributes, "key", "value2"); writeAttributes(controllerId, allowedAttributes, "key", "value2");
return null; return null;
@@ -125,7 +127,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
// Now rite one more // Now rite one more
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> SecurityContextSwitch assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> SecurityContextSwitch
.runAs(SecurityContextSwitch.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { .runAs(withController, () -> {
writeAttributes(controllerId, 1, "additional", "value1"); writeAttributes(controllerId, 1, "additional", "value1");
return null; return null;
})).withMessageContaining("" + allowedAttributes); })).withMessageContaining("" + allowedAttributes);
@@ -139,25 +141,28 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final String controllerId = "targetId123"; final String controllerId = "targetId123";
testdataFactory.createTarget(controllerId); testdataFactory.createTarget(controllerId);
final Map<String, String> attributesLV =
Collections.singletonMap(TargetTestData.ATTRIBUTE_KEY_TOO_LONG, TargetTestData.ATTRIBUTE_VALUE_VALID);
assertThatExceptionOfType(InvalidTargetAttributeException.class) assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with key too long should not be created") .as("Attribute with key too long should not be created")
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, attributesLV, null));
Collections.singletonMap(TargetTestData.ATTRIBUTE_KEY_TOO_LONG, TargetTestData.ATTRIBUTE_VALUE_VALID), null));
final Map<String, String> attributesLL =
Collections.singletonMap(TargetTestData.ATTRIBUTE_KEY_TOO_LONG, TargetTestData.ATTRIBUTE_VALUE_TOO_LONG);
assertThatExceptionOfType(InvalidTargetAttributeException.class) assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with key too long and value too long should not be created") .as("Attribute with key too long and value too long should not be created")
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, attributesLL, null));
Collections.singletonMap(TargetTestData.ATTRIBUTE_KEY_TOO_LONG, TargetTestData.ATTRIBUTE_VALUE_TOO_LONG), null));
final Map<String, String> attributesVL =
Collections.singletonMap(TargetTestData.ATTRIBUTE_KEY_VALID, TargetTestData.ATTRIBUTE_VALUE_TOO_LONG);
assertThatExceptionOfType(InvalidTargetAttributeException.class) assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with value too long should not be created") .as("Attribute with value too long should not be created")
.isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, attributesVL, null));
Collections.singletonMap(TargetTestData.ATTRIBUTE_KEY_VALID, TargetTestData.ATTRIBUTE_VALUE_TOO_LONG), null));
final Map<String, String> attributesNV = Collections.singletonMap(null, TargetTestData.ATTRIBUTE_VALUE_VALID);
assertThatExceptionOfType(InvalidTargetAttributeException.class) assertThatExceptionOfType(InvalidTargetAttributeException.class)
.as("Attribute with key NULL should not be created").isThrownBy(() -> controllerManagement .as("Attribute with key NULL should not be created")
.updateControllerAttributes(controllerId, .isThrownBy(() -> controllerManagement.updateControllerAttributes(controllerId, attributesNV, null));
Collections.singletonMap(null, TargetTestData.ATTRIBUTE_VALUE_VALID), null));
} }
@Test @Test
@@ -222,7 +227,6 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 2) }) @Expect(type = TargetAssignDistributionSetEvent.class, count = 2) })
void addActionStatusUpdatesUntilQuotaIsExceeded() { void addActionStatusUpdatesUntilQuotaIsExceeded() {
// any distribution set assignment causes 1 status entity to be created // any distribution set assignment causes 1 status entity to be created
final int maxStatusEntries = quotaManagement.getMaxStatusEntriesPerAction() - 1; final int maxStatusEntries = quotaManagement.getMaxStatusEntriesPerAction() - 1;
@@ -230,24 +234,23 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId1 = getFirstAssignedActionId(assignDistributionSet( final Long actionId1 = getFirstAssignedActionId(assignDistributionSet(
testdataFactory.createDistributionSet("ds1"), testdataFactory.createTargets(1, "t1"))); testdataFactory.createDistributionSet("ds1"), testdataFactory.createTargets(1, "t1")));
assertThat(actionId1).isNotNull(); assertThat(actionId1).isNotNull();
final ActionStatusCreate status = entityFactory.actionStatus().create(actionId1).status(Status.WARNING);
for (int i = 0; i < maxStatusEntries; ++i) { for (int i = 0; i < maxStatusEntries; ++i) {
controllerManagement.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1) controllerManagement.addInformationalActionStatus(status.message("Msg " + i).occurredAt(System.currentTimeMillis()));
.status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis()));
} }
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> controllerManagement assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1).status(Status.WARNING))); .isThrownBy(() -> controllerManagement.addInformationalActionStatus(status));
// test for update status (and mixed case) // test for update status (and mixed case)
final Long actionId2 = getFirstAssignedActionId(assignDistributionSet( final Long actionId2 = getFirstAssignedActionId(assignDistributionSet(
testdataFactory.createDistributionSet("ds2"), testdataFactory.createTargets(1, "t2"))); testdataFactory.createDistributionSet("ds2"), testdataFactory.createTargets(1, "t2")));
assertThat(actionId2).isNotEqualTo(actionId1); assertThat(actionId2).isNotEqualTo(actionId1);
final ActionStatusCreate statusWarning = entityFactory.actionStatus().create(actionId2).status(Status.WARNING);
for (int i = 0; i < maxStatusEntries; ++i) { for (int i = 0; i < maxStatusEntries; ++i) {
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId2) controllerManagement.addUpdateActionStatus(statusWarning.message("Msg " + i).occurredAt(System.currentTimeMillis()));
.status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis()));
} }
assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> controllerManagement assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.addInformationalActionStatus(entityFactory.actionStatus().create(actionId2).status(Status.WARNING))); .isThrownBy(() -> controllerManagement.addInformationalActionStatus(statusWarning));
} }
@Test @Test
@@ -262,7 +265,6 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1) }) @Expect(type = TargetAssignDistributionSetEvent.class, count = 1) })
void createActionStatusWithTooManyMessages() { void createActionStatusWithTooManyMessages() {
final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus();
final Long actionId = getFirstAssignedActionId( final Long actionId = getFirstAssignedActionId(
@@ -276,10 +278,9 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))).isNotNull(); entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))).isNotNull();
messages.add("msg"); messages.add("msg");
final ActionStatusCreate statusToManyMessages = entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING);
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> controllerManagement.addInformationalActionStatus( .isThrownBy(() -> controllerManagement.addInformationalActionStatus(statusToManyMessages));
entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING)));
} }
@Test @Test
@@ -410,16 +411,17 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
simulateIntermediateStatusOnUpdate(actionId); simulateIntermediateStatusOnUpdate(actionId);
final ActionStatusCreate statusSingleMessage = entityFactory.actionStatus().create(actionId)
.status(Status.FINISHED).message(INVALID_TEXT_HTML);
assertThatExceptionOfType(ConstraintViolationException.class) assertThatExceptionOfType(ConstraintViolationException.class)
.as("set invalid description text should not be created") .as("set invalid description text should not be created")
.isThrownBy(() -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus() .isThrownBy(() -> controllerManagement.addUpdateActionStatus(statusSingleMessage));
.create(actionId).status(Action.Status.FINISHED).message(INVALID_TEXT_HTML)));
final ActionStatusCreate statusMulipleMessages = entityFactory.actionStatus().create(actionId)
.status(Status.FINISHED).messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML));
assertThatExceptionOfType(ConstraintViolationException.class) assertThatExceptionOfType(ConstraintViolationException.class)
.as("set invalid description text should not be created") .as("set invalid description text should not be created")
.isThrownBy(() -> controllerManagement.addUpdateActionStatus( .isThrownBy(() -> controllerManagement.addUpdateActionStatus(statusMulipleMessages));
entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)
.messages(Arrays.asList("this is valid.", INVALID_TEXT_HTML))));
assertThat(actionStatusRepository.count()).isEqualTo(6); assertThat(actionStatusRepository.count()).isEqualTo(6);
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(6); assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(6);
@@ -467,13 +469,12 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
void cancellationFeedbackRejectedIfActionIsNotInCanceling() { void cancellationFeedbackRejectedIfActionIsNotInCanceling() {
final Long actionId = createTargetAndAssignDs(); final Long actionId = createTargetAndAssignDs();
final ActionStatusCreate status = entityFactory.actionStatus().create(actionId).status(Status.FINISHED);
assertThatExceptionOfType(CancelActionNotAllowedException.class) assertThatExceptionOfType(CancelActionNotAllowedException.class)
.as("Expected " + CancelActionNotAllowedException.class.getName()) .as("Expected " + CancelActionNotAllowedException.class.getName())
.isThrownBy(() -> controllerManagement.addCancelActionStatus( .isThrownBy(() -> controllerManagement.addCancelActionStatus(status));
entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)));
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.PENDING, Action.Status.RUNNING, Action.Status.RUNNING, true);
Action.Status.RUNNING, true);
assertThat(actionStatusRepository.count()).isEqualTo(1); assertThat(actionStatusRepository.count()).isEqualTo(1);
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(1); assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(1);
@@ -797,10 +798,11 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
.as("register target with empty controllerId should fail") .as("register target with empty controllerId should fail")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST)); .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(" ", LOCALHOST));
final String controllerId = randomString(Target.CONTROLLER_ID_MAX_SIZE + 1);
assertThatExceptionOfType(ConstraintViolationException.class) assertThatExceptionOfType(ConstraintViolationException.class)
.as("register target with too long controllerId should fail") .as("register target with too long controllerId should fail")
.isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist( .isThrownBy(() -> controllerManagement.findOrRegisterTargetIfItDoesNotExist(
randomString(Target.CONTROLLER_ID_MAX_SIZE + 1), LOCALHOST)); controllerId, LOCALHOST));
} }
@Test @Test
@@ -936,9 +938,9 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Test @Test
@Description("Verify that controller registration does not result in a TargetPollEvent if feature is disabled") @Description("Verify that controller registration does not result in a TargetPollEvent if feature is disabled")
@ExpectEvents({ @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1) })
@Expect(type = TargetCreatedEvent.class, count = 1), @SuppressWarnings("java:S2699")
@Expect(type = TargetPollEvent.class, count = 0) }) // java:S2699 - test tests the fired events, no need for assert
void targetPollEventNotSendIfDisabled() { void targetPollEventNotSendIfDisabled() {
repositoryProperties.setPublishTargetPollEvent(false); repositoryProperties.setPublishTargetPollEvent(false);
controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST); controllerManagement.findOrRegisterTargetIfItDoesNotExist("AA", LOCALHOST);
@@ -968,16 +970,16 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
// try with disabled late feedback // try with disabled late feedback
repositoryProperties.setRejectActionStatusForClosedAction(true); withRejectActionStatusForClosedAction(true, () ->
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)); controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)));
// test // test
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
// try with enabled late feedback - should not make a difference as it // try with enabled late feedback - should not make a difference as it
// only allows intermediate feedback and not multiple close // only allows intermediate feedback and not multiple close
repositoryProperties.setRejectActionStatusForClosedAction(false); withRejectActionStatusForClosedAction(false,
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)); () -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)));
// test // test
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false); assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.ERROR, Action.Status.ERROR, Action.Status.ERROR, false);
@@ -1002,28 +1004,21 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
void tryToFinishUpdateProcessMoreThanOnce() { void tryToFinishUpdateProcessMoreThanOnce() {
final Long actionId = prepareFinishedUpdate().getId(); final Long actionId = prepareFinishedUpdate().getId();
// try with disabled late feedback withRejectActionStatusForClosedAction(true,
repositoryProperties.setRejectActionStatusForClosedAction(true); () -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)));
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
// test // test
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED, assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED,
Action.Status.FINISHED, false); Action.Status.FINISHED, false);
// try with enabled late feedback - should not make a difference as it withRejectActionStatusForClosedAction(false,
// only allows intermediate feedback and not multiple close () -> controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED)));
repositoryProperties.setRejectActionStatusForClosedAction(false);
controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Action.Status.FINISHED));
// test // test
assertActionStatus(actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED, assertActionStatus(
Action.Status.FINISHED, false); actionId, DEFAULT_CONTROLLER_ID, TargetUpdateStatus.IN_SYNC, Action.Status.FINISHED, Action.Status.FINISHED, false);
assertThat(actionStatusRepository.count()).isEqualTo(3); assertThat(actionStatusRepository.count()).isEqualTo(3);
assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(3); assertThat(controllerManagement.findActionStatusByAction(PAGE, actionId).getNumberOfElements()).isEqualTo(3);
} }
@Test @Test
@@ -1041,17 +1036,14 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1) }) @Expect(type = TargetAttributesRequestedEvent.class, count = 1) })
void sendUpdatesForFinishUpdateProcessDroppedIfDisabled() { void sendUpdatesForFinishUpdateProcessDroppedIfDisabled() {
repositoryProperties.setRejectActionStatusForClosedAction(true);
final Action action = prepareFinishedUpdate(); final Action action = prepareFinishedUpdate();
withRejectActionStatusForClosedAction(true,
controllerManagement.addUpdateActionStatus( () -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(action.getId()).status(Action.Status.RUNNING)); entityFactory.actionStatus().create(action.getId()).status(Action.Status.RUNNING)));
// nothing changed as "feedback after close" is disabled // nothing changed as "feedback after close" is disabled
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getUpdateStatus()) assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getUpdateStatus())
.isEqualTo(TargetUpdateStatus.IN_SYNC); .isEqualTo(TargetUpdateStatus.IN_SYNC);
assertThat(actionRepository.findById(action.getId())) assertThat(actionRepository.findById(action.getId()))
.hasValueSatisfying(a -> assertThat(a.getStatus()).isEqualTo(Status.FINISHED)); .hasValueSatisfying(a -> assertThat(a.getStatus()).isEqualTo(Status.FINISHED));
assertThat(actionStatusRepository.count()).isEqualTo(3); assertThat(actionStatusRepository.count()).isEqualTo(3);
@@ -1074,20 +1066,16 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = TargetAttributesRequestedEvent.class, count = 1) }) @Expect(type = TargetAttributesRequestedEvent.class, count = 1) })
void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() { void sendUpdatesForFinishUpdateProcessAcceptedIfEnabled() {
repositoryProperties.setRejectActionStatusForClosedAction(false);
Action action = prepareFinishedUpdate(); Action action = prepareFinishedUpdate();
action = controllerManagement.addUpdateActionStatus( withRejectActionStatusForClosedAction(false,
entityFactory.actionStatus().create(action.getId()).status(Action.Status.RUNNING)); () -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(action.getId()).status(Action.Status.RUNNING)));
// nothing changed as "feedback after close" is disabled // nothing changed as "feedback after close" is disabled
assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getUpdateStatus()) assertThat(targetManagement.getByControllerID(DEFAULT_CONTROLLER_ID).get().getUpdateStatus()).isEqualTo(TargetUpdateStatus.IN_SYNC);
.isEqualTo(TargetUpdateStatus.IN_SYNC);
// however, additional action status has been stored // however, additional action status has been stored
assertThat(actionStatusRepository.findAll(PAGE).getNumberOfElements()).isEqualTo(4); assertThat(actionStatusRepository.findAll(PAGE).getNumberOfElements()).isEqualTo(4);
assertThat(controllerManagement.findActionStatusByAction(PAGE, action.getId()).getNumberOfElements()) assertThat(controllerManagement.findActionStatusByAction(PAGE, action.getId()).getNumberOfElements()).isEqualTo(4);
.isEqualTo(4);
} }
@Test @Test
@@ -1233,15 +1221,16 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = TargetAttributesRequestedEvent.class, count = 9), @Expect(type = TargetAttributesRequestedEvent.class, count = 9),
@Expect(type = ActionUpdatedEvent.class, count = 1) }) @Expect(type = ActionUpdatedEvent.class, count = 1) })
void quotaExceptionWhencontrollerReportsTooManyDownloadedMessagesForDownloadOnlyAction() { void quotaExceptionWhenControllerReportsTooManyDownloadedMessagesForDownloadOnlyAction() {
final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus();
testdataFactory.createTarget(); testdataFactory.createTarget();
final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDsTMD", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull(); assertThat(actionId).isNotNull();
Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> final IntConsumer op = i -> controllerManagement.addUpdateActionStatus(
IntStream.range(0, maxMessages).forEach(i -> controllerManagement entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED));
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED)))); Assertions.assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.isThrownBy(() -> forNTimes(maxMessages, op));
} }
@Test @Test
@@ -1260,16 +1249,17 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
void quotaExceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() { void quotaExceededExceptionWhenControllerReportsTooManyUpdateActionStatusMessagesForDownloadOnlyAction() {
final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus(); final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus();
testdataFactory.createTarget(); testdataFactory.createTarget();
final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs", DEFAULT_CONTROLLER_ID); final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDsTMU", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull(); assertThat(actionId).isNotNull();
//assert that too many intermediate statuses will throw quota exception // assert that too many intermediate statuses will throw quota exception
final IntConsumer op = i -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED));
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates").isThrownBy( .as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement.addUpdateActionStatus( .isThrownBy(() -> forNTimes(maxMessages, op));
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
//assert that Final result is accepted even if quota is reached // assert that Final result is accepted even if quota is reached
assertThatNoException().isThrownBy(() -> { assertThatNoException().isThrownBy(() -> {
Action updatedAction = controllerManagement.addUpdateActionStatus( Action updatedAction = controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.FINISHED)); entityFactory.actionStatus().create(actionId).status(Status.FINISHED));
@@ -1279,7 +1269,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(updatedAction.getStatus()).isEqualTo(Status.FINISHED); assertThat(updatedAction.getStatus()).isEqualTo(Status.FINISHED);
}); });
//assert that additional final result is not accepted // assert that additional final result is not accepted
assertThatNoException().isThrownBy(() -> { assertThatNoException().isThrownBy(() -> {
Action updatedAction = controllerManagement Action updatedAction = controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR)); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR));
@@ -1308,13 +1298,14 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
final Long actionId = createTargetAndAssignDs(); final Long actionId = createTargetAndAssignDs();
assertThat(actionId).isNotNull(); assertThat(actionId).isNotNull();
//assert that too many intermediate statuses will throw quota exception // assert that too many intermediate statuses will throw quota exception
final IntConsumer op = i -> controllerManagement.addUpdateActionStatus(
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED));
assertThatExceptionOfType(AssignmentQuotaExceededException.class) assertThatExceptionOfType(AssignmentQuotaExceededException.class)
.as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates").isThrownBy( .as("No QuotaExceededException thrown for too many DOWNLOADED updateActionStatus updates")
() -> IntStream.range(0, maxMessages).forEach(i -> controllerManagement.addUpdateActionStatus( .isThrownBy(() -> forNTimes(maxMessages, op));
entityFactory.actionStatus().create(actionId).status(Status.DOWNLOADED))));
//assert that Final result is accepted even if quota is reached // assert that Final result is accepted even if quota is reached
assertThatNoException().isThrownBy(() -> { assertThatNoException().isThrownBy(() -> {
Action updatedAction = controllerManagement Action updatedAction = controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED)); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.FINISHED));
@@ -1324,7 +1315,7 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(updatedAction.getStatus()).isEqualTo(Status.FINISHED); assertThat(updatedAction.getStatus()).isEqualTo(Status.FINISHED);
}); });
//assert that additional final result is not accepted // assert that additional final result is not accepted
assertThatNoException().isThrownBy(() -> { assertThatNoException().isThrownBy(() -> {
Action updatedAction = controllerManagement Action updatedAction = controllerManagement
.addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR)); .addUpdateActionStatus(entityFactory.actionStatus().create(actionId).status(Status.ERROR));
@@ -1430,8 +1421,8 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
} }
@Test @Test
@Description("Verifies that a target can report FINISHED/ERROR updates for DOWNLOAD_ONLY assignments regardless of " @Description("Verifies that a target can report FINISHED/ERROR updates for DOWNLOAD_ONLY assignments regardless of " +
+ "repositoryProperties.rejectActionStatusForClosedAction value.") "repositoryProperties.rejectActionStatusForClosedAction value.")
@ExpectEvents({ @ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1), @Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 4), @Expect(type = DistributionSetCreatedEvent.class, count = 4),
@@ -1444,34 +1435,35 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = TargetAttributesRequestedEvent.class, count = 6), @Expect(type = TargetAttributesRequestedEvent.class, count = 6),
@Expect(type = ActionUpdatedEvent.class, count = 8) }) @Expect(type = ActionUpdatedEvent.class, count = 8) })
void targetCanAlwaysReportFinishedOrErrorAfterActionIsClosedForDownloadOnlyAssignments() { void targetCanAlwaysReportFinishedOrErrorAfterActionIsClosedForDownloadOnlyAssignments() {
testdataFactory.createTarget(); testdataFactory.createTarget();
// allow actionStatusUpdates for closed actions // allow actionStatusUpdates for closed actions
repositoryProperties.setRejectActionStatusForClosedAction(false); withRejectActionStatusForClosedAction(false,
() -> {
final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs1", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull();
finishDownloadOnlyUpdateAndSendUpdateActionStatus(actionId, Status.FINISHED);
final Long actionId = createAndAssignDsAsDownloadOnly("downloadOnlyDs1", DEFAULT_CONTROLLER_ID); final Long actionId2 = createAndAssignDsAsDownloadOnly("downloadOnlyDs2", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull(); assertThat(actionId2).isNotNull();
finishDownloadOnlyUpdateAndSendUpdateActionStatus(actionId, Status.FINISHED); finishDownloadOnlyUpdateAndSendUpdateActionStatus(actionId2, Status.ERROR);
});
final Long actionId2 = createAndAssignDsAsDownloadOnly("downloadOnlyDs2", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull();
finishDownloadOnlyUpdateAndSendUpdateActionStatus(actionId2, Status.ERROR);
// disallow actionStatusUpdates for closed actions // disallow actionStatusUpdates for closed actions
repositoryProperties.setRejectActionStatusForClosedAction(true); withRejectActionStatusForClosedAction(true,
() -> {
final Long actionId3 = createAndAssignDsAsDownloadOnly("downloadOnlyDs3", DEFAULT_CONTROLLER_ID);
assertThat(actionId3).isNotNull();
finishDownloadOnlyUpdateAndSendUpdateActionStatus(actionId3, Status.FINISHED);
final Long actionId3 = createAndAssignDsAsDownloadOnly("downloadOnlyDs3", DEFAULT_CONTROLLER_ID); final Long actionId4 = createAndAssignDsAsDownloadOnly("downloadOnlyDs4", DEFAULT_CONTROLLER_ID);
assertThat(actionId).isNotNull(); assertThat(actionId4).isNotNull();
finishDownloadOnlyUpdateAndSendUpdateActionStatus(actionId3, Status.FINISHED); finishDownloadOnlyUpdateAndSendUpdateActionStatus(actionId4, Status.ERROR);
final Long actionId4 = createAndAssignDsAsDownloadOnly("downloadOnlyDs4", DEFAULT_CONTROLLER_ID); // actionStatusRepository should have 12 ActionStatusUpdates, 3 from
assertThat(actionId).isNotNull(); // each action
finishDownloadOnlyUpdateAndSendUpdateActionStatus(actionId4, Status.ERROR); assertThat(actionStatusRepository.count()).isEqualTo(12L);
});
// actionStatusRepository should have 12 ActionStatusUpdates, 3 from
// each action
assertThat(actionStatusRepository.count()).isEqualTo(12L);
} }
@Test @Test
@@ -1585,12 +1577,13 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
assertThat(target).as("target should not be null").isNotNull(); assertThat(target).as("target should not be null").isNotNull();
assertThat(targetRepository.count()).as("target exists and is ready for deletion").isEqualTo(1L); assertThat(targetRepository.count()).as("target exists and is ready for deletion").isEqualTo(1L);
controllerManagement.deleteExistingTarget(target.getControllerId()); final String controllerId = target.getControllerId();
controllerManagement.deleteExistingTarget(controllerId);
assertThat(targetRepository.count()).as("target should not exist anymore").isZero(); assertThat(targetRepository.count()).as("target should not exist anymore").isZero();
assertThatExceptionOfType(EntityNotFoundException.class) assertThatExceptionOfType(EntityNotFoundException.class)
.as("No EntityNotFoundException thrown when deleting a non-existing target") .as("No EntityNotFoundException thrown when deleting a non-existing target")
.isThrownBy(() -> controllerManagement.deleteExistingTarget(target.getControllerId())); .isThrownBy(() -> controllerManagement.deleteExistingTarget(controllerId));
} }
@Test @Test
@@ -1606,7 +1599,24 @@ class ControllerManagementTest extends AbstractJpaIntegrationTest {
addUpdateActionStatusAndAssert(actionId, Action.Status.RUNNING, 20); addUpdateActionStatusAndAssert(actionId, Action.Status.RUNNING, 20);
assertLastActionStatusCodeInAction(actionId, 20); assertLastActionStatusCodeInAction(actionId, 20);
}
private static void forNTimes(final int n, final IntConsumer consumer) {
IntStream.range(0, n).forEach(consumer);
}
private void withRejectActionStatusForClosedAction(final boolean rejectActionStatusForClosedAction, final Runnable runnable) {
final boolean originalValue = repositoryProperties.isRejectActionStatusForClosedAction();
if (originalValue == rejectActionStatusForClosedAction) {
runnable.run();
} else {
repositoryProperties.setRejectActionStatusForClosedAction(rejectActionStatusForClosedAction);
try {
runnable.run();
} finally {
repositoryProperties.setRejectActionStatusForClosedAction(originalValue);
}
}
} }
@Step @Step