From 081c3cccbf1820e43a0fd20bf4c20d50c95926f5 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Thu, 23 Mar 2017 18:24:58 +0100 Subject: [PATCH] Complete repo exception tests (#452) Signed-off-by: kaizimmerm --- .../repository/DeploymentManagement.java | 40 ++-- .../repository/DistributionSetManagement.java | 7 +- .../hawkbit/repository/RolloutManagement.java | 8 +- .../repository/SoftwareManagement.java | 5 +- .../hawkbit/repository/TargetManagement.java | 10 +- .../exception/EntityNotFoundException.java | 5 +- .../jpa/JpaDeploymentManagement.java | 20 +- .../jpa/JpaDistributionSetManagement.java | 25 ++- .../repository/jpa/JpaRolloutManagement.java | 9 +- .../repository/jpa/JpaSoftwareManagement.java | 2 + .../repository/jpa/JpaTargetManagement.java | 32 +-- .../jpa/AbstractJpaIntegrationTest.java | 11 + .../jpa/ArtifactManagementTest.java | 50 ++--- .../jpa/ControllerManagementTest.java | 104 ++++----- .../jpa/DeploymentManagementTest.java | 48 ++++- .../jpa/DistributionSetManagementTest.java | 203 ++++++++++++++---- .../repository/jpa/RolloutManagementTest.java | 83 ++++--- .../jpa/SoftwareManagementTest.java | 83 +++++++ .../repository/jpa/TagManagementTest.java | 33 ++- .../jpa/TargetFilterQueryManagementTest.java | 43 ++++ .../repository/jpa/TargetManagementTest.java | 125 ++++++----- .../jpa/event/RepositoryEntityEventTest.java | 2 +- .../test/util/AbstractIntegrationTest.java | 24 --- .../repository/test/util/TestdataFactory.java | 62 ++++++ .../themes/hawkbit/customstyles/common.scss | 6 +- .../hawkbit/images/lightCorner_selected1.png | Bin 9331 -> 0 bytes 26 files changed, 740 insertions(+), 300 deletions(-) delete mode 100644 hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/images/lightCorner_selected1.png diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java index 1484a523a..84325efbb 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DeploymentManagement.java @@ -17,6 +17,7 @@ import javax.validation.constraints.NotNull; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.model.Action; @@ -58,12 +59,13 @@ public interface DeploymentManagement { * the IDs of the target to assign the distribution set * @return the assignment result * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. + * @throws IncompleteDistributionSetException + * if mandatory {@link SoftwareModuleType} are not assigned as + * define by the {@link DistributionSetType}. * - * @throw {@link EntityNotFoundException} if either provided - * {@link DistributionSet} or {@link Target}s do not exist + * @throws EntityNotFoundException + * if either provided {@link DistributionSet} or {@link Target}s + * do not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) DistributionSetAssignmentResult assignDistributionSet(@NotNull Long dsID, @NotNull ActionType actionType, @@ -79,12 +81,13 @@ public interface DeploymentManagement { * a list of all targets and their action type * @return the assignment result * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. + * @throws IncompleteDistributionSetException + * if mandatory {@link SoftwareModuleType} are not assigned as + * define by the {@link DistributionSetType}. * - * @throw {@link EntityNotFoundException} if either provided - * {@link DistributionSet} or {@link Target}s do not exist + * @throws EntityNotFoundException + * if either provided {@link DistributionSet} or {@link Target}s + * do not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) DistributionSetAssignmentResult assignDistributionSet(@NotNull Long dsID, @@ -102,12 +105,13 @@ public interface DeploymentManagement { * an optional message for the action status * @return the assignment result * - * @throw IncompleteDistributionSetException if mandatory - * {@link SoftwareModuleType} are not assigned as define by the - * {@link DistributionSetType}. + * @throws IncompleteDistributionSetException + * if mandatory {@link SoftwareModuleType} are not assigned as + * define by the {@link DistributionSetType}. * - * @throw {@link EntityNotFoundException} if either provided - * {@link DistributionSet} or {@link Target}s do not exist + * @throws EntityNotFoundException + * if either provided {@link DistributionSet} or {@link Target}s + * do not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) DistributionSetAssignmentResult assignDistributionSet(@NotNull Long dsID, @@ -210,6 +214,9 @@ public interface DeploymentManagement { * in the result * @return a list of {@link Action} which are assigned to a specific * {@link DistributionSet} + * + * @throws EntityNotFoundException + * if distribution set with given ID does not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) Slice findActionsByDistributionSet(@NotNull Pageable pageable, @NotNull Long distributionSetId); @@ -290,6 +297,9 @@ public interface DeploymentManagement { * the target associated with the actions * @return a list of actions associated with the given target ordered by * action ID + * + * @throws EntityNotFoundException + * if target with given ID does not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) List findActionsWithStatusCountByTargetOrderByIdDesc(@NotNull String controllerId); diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index a58c62650..a67eb6e94 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -255,7 +255,7 @@ public interface DistributionSetManagement { * if given set does not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - void deleteDistributionSetMetadata(@NotNull final Long dsId, @NotNull final String key); + void deleteDistributionSetMetadata(@NotNull final Long dsId, @NotEmpty final String key); /** * Deletes or mark as delete in case the type is in use. @@ -517,7 +517,10 @@ public interface DistributionSetManagement { * of the {@link DistributionSet} * @param key * of the meta data element - * @return the found DistributionSetMetadata or {@code null} if not exits + * @return the found DistributionSetMetadata + * + * @throws EntityNotFoundException + * is set with given ID does not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) Optional findDistributionSetMetadata(@NotNull Long setId, @NotEmpty String key); diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java index 2afae7a25..a034479ff 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutManagement.java @@ -310,7 +310,7 @@ public interface RolloutManagement { * sufficient due the {@link #checkRunningRollouts(long)} will not check * this rollout anymore. * - * @param rollout + * @param rolloutId * the rollout to be paused. * * @throws EntityNotFoundException @@ -321,14 +321,14 @@ public interface RolloutManagement { * */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) - void pauseRollout(@NotNull Long rollout); + void pauseRollout(@NotNull Long rolloutId); /** * Resumes a paused rollout. The rollout switches back to * {@link RolloutStatus#RUNNING} state which is then picked up again by the * {@link #checkRunningRollouts(long)}. * - * @param rollout + * @param rolloutId * the rollout to be resumed * * @throws EntityNotFoundException @@ -338,7 +338,7 @@ public interface RolloutManagement { * paused rollouts can be resumed. */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE) - void resumeRollout(@NotNull Long rollout); + void resumeRollout(@NotNull Long rolloutId); /** * Starts a rollout which has been created. The rollout must be in diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java index 064529474..f8b7ba705 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java @@ -286,6 +286,9 @@ public interface SoftwareManagement { * @param key * of the meta data element * @return the found SoftwareModuleMetadata or {@code null} if not exits + * + * @throws EntityNotFoundException + * is module with given ID does not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) Optional findSoftwareModuleMetadata(@NotNull Long moduleId, @NotEmpty String key); @@ -441,7 +444,7 @@ public interface SoftwareManagement { * {@link SoftwareModuleType#getName()} */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Optional findSoftwareModuleTypeByName(@NotNull String name); + Optional findSoftwareModuleTypeByName(@NotEmpty String name); /** * @param pageable diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java index 414a95730..632b642f1 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -52,7 +52,7 @@ public interface TargetManagement { * @return list of assigned targets * * @throws EntityNotFoundException - * if given tagId does not exist + * if given tagId or at least one of the targets do not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET) List assignTag(@NotEmpty Collection controllerIds, @NotNull Long tagId); @@ -413,7 +413,7 @@ public interface TargetManagement { * the ID of the {@link DistributionSet} * @param rsqlParam * the specification to filter the result - * @param pageable + * @param pageReq * page parameter * @return the found {@link Target}s, never {@code null} * @@ -428,7 +428,7 @@ public interface TargetManagement { */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET) Page findTargetByInstalledDistributionSet(@NotNull Long distributionSetId, @NotNull String rsqlParam, - @NotNull Pageable pageable); + @NotNull Pageable pageReq); /** * Retrieves the {@link Target} which have a certain @@ -547,7 +547,7 @@ public interface TargetManagement { * yet assigned, they will be. If all of theme have the tag already assigned * they will be removed instead. * - * @param targetIds + * @param controllerIds * to toggle for * @param tagName * to toggle @@ -557,7 +557,7 @@ public interface TargetManagement { * if tag with given name does not exist */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET) - TargetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection targetIds, @NotEmpty String tagName); + TargetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection controllerIds, @NotEmpty String tagName); /** * Un-assign all {@link Target} from a given {@link TargetTag} . diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java index 146807db5..d1d9f836f 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java @@ -102,9 +102,10 @@ public class EntityNotFoundException extends AbstractServerRtException { * @param found * collection of the {@link BaseEntity#getId()}s */ - public EntityNotFoundException(final Class type, final Collection expected, - final Collection found) { + public EntityNotFoundException(final Class type, final Collection expected, + final Collection found) { this(type.getSimpleName() + "s with given identifiers {" + expected.stream().filter(id -> !found.contains(id)) .map(String::valueOf).collect(Collectors.joining(",")) + "} do not exist."); } + } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java index 2e2836ae7..c7be7aff4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java @@ -111,7 +111,7 @@ public class JpaDeploymentManagement implements DeploymentManagement { private ActionRepository actionRepository; @Autowired - private DistributionSetRepository distributoinSetRepository; + private DistributionSetRepository distributionSetRepository; @Autowired private TargetRepository targetRepository; @@ -165,7 +165,7 @@ public class JpaDeploymentManagement implements DeploymentManagement { @Transactional(isolation = Isolation.READ_COMMITTED) public DistributionSetAssignmentResult assignDistributionSet(final Long dsID, final Collection targets, final String actionMessage) { - final JpaDistributionSet set = distributoinSetRepository.findOne(dsID); + final JpaDistributionSet set = distributionSetRepository.findOne(dsID); if (set == null) { throw new EntityNotFoundException(DistributionSet.class, dsID); } @@ -535,11 +535,14 @@ public class JpaDeploymentManagement implements DeploymentManagement { @Override public Slice findActionsByTarget(final String controllerId, final Pageable pageable) { + throwExceptionIfTargetDoesNotExist(controllerId); return actionRepository.findByTargetControllerId(pageable, controllerId); } @Override public List findActionsWithStatusCountByTargetOrderByIdDesc(final String controllerId) { + throwExceptionIfTargetDoesNotExist(controllerId); + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaQuery query = cb.createQuery(JpaActionWithStatusCount.class); final Root actionRoot = query.from(JpaAction.class); @@ -564,6 +567,7 @@ public class JpaDeploymentManagement implements DeploymentManagement { @Override public Page findActionsByTarget(final String rsqlParam, final String controllerId, final Pageable pageable) { + throwExceptionIfTargetDoesNotExist(controllerId); final Specification byTargetSpec = createSpecificationFor(controllerId, rsqlParam); final Page actions = actionRepository.findAll(byTargetSpec, pageable); @@ -614,6 +618,12 @@ public class JpaDeploymentManagement implements DeploymentManagement { } } + private void throwExceptionIfDistributionSetDoesNotExist(final Long dsId) { + if (!distributionSetRepository.exists(dsId)) { + throw new EntityNotFoundException(DistributionSet.class, dsId); + } + } + @Override @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) @@ -667,6 +677,8 @@ public class JpaDeploymentManagement implements DeploymentManagement { @Override public Slice findActionsByDistributionSet(final Pageable pageable, final Long dsId) { + throwExceptionIfDistributionSetDoesNotExist(dsId); + return actionRepository.findByDistributionSetId(pageable, dsId); } @@ -679,13 +691,13 @@ public class JpaDeploymentManagement implements DeploymentManagement { public Optional getAssignedDistributionSet(final String controllerId) { throwExceptionIfTargetDoesNotExist(controllerId); - return distributoinSetRepository.findAssignedToTarget(controllerId); + return distributionSetRepository.findAssignedToTarget(controllerId); } @Override public Optional getInstalledDistributionSet(final String controllerId) { throwExceptionIfTargetDoesNotExist(controllerId); - return distributoinSetRepository.findInstalledAtTarget(controllerId); + return distributionSetRepository.findInstalledAtTarget(controllerId); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 991350100..44e57f43d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -693,9 +693,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Override public Page findDistributionSetMetadataByDistributionSetId(final Long distributionSetId, final Pageable pageable) { - if (!distributionSetRepository.exists(distributionSetId)) { - throw new EntityNotFoundException(DistributionSet.class, distributionSetId); - } + throwExceptionIfDistributionSetDoesNotExist(distributionSetId); return convertMdPage(distributionSetMetadataRepository .findAll((Specification) (root, query, cb) -> cb.equal( @@ -708,9 +706,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { public Page findDistributionSetMetadataByDistributionSetId(final Long distributionSetId, final String rsqlParam, final Pageable pageable) { - if (!distributionSetRepository.exists(distributionSetId)) { - throw new EntityNotFoundException(DistributionSet.class, distributionSetId); - } + throwExceptionIfDistributionSetDoesNotExist(distributionSetId); final Specification spec = RSQLUtility.parse(rsqlParam, DistributionSetMetadataFields.class, virtualPropertyReplacer); @@ -730,9 +726,10 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { } @Override - public Optional findDistributionSetMetadata(final Long distributionSet, final String key) { - return Optional.ofNullable( - distributionSetMetadataRepository.findOne(new DsMetadataCompositeKey(distributionSet, key))); + public Optional findDistributionSetMetadata(final Long setId, final String key) { + throwExceptionIfDistributionSetDoesNotExist(setId); + + return Optional.ofNullable(distributionSetMetadataRepository.findOne(new DsMetadataCompositeKey(setId, key))); } @Override @@ -746,6 +743,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Override public boolean isDistributionSetInUse(final Long setId) { + throwExceptionIfDistributionSetDoesNotExist(setId); + return actionRepository.countByDistributionSetId(setId) > 0; } @@ -903,11 +902,15 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) public void deleteDistributionSet(final Long setId) { + throwExceptionIfDistributionSetDoesNotExist(setId); + + deleteDistributionSet(Lists.newArrayList(setId)); + } + + private void throwExceptionIfDistributionSetDoesNotExist(final Long setId) { if (!distributionSetRepository.exists(setId)) { throw new EntityNotFoundException(DistributionSet.class, setId); } - - deleteDistributionSet(Lists.newArrayList(setId)); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java index 93d7f5976..e1bad1f49 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java @@ -301,14 +301,14 @@ public class JpaRolloutManagement extends AbstractRolloutManagement { int readyGroups = 0; int totalTargets = 0; for (final RolloutGroup group : rolloutGroups) { - if (group.getStatus() != RolloutGroupStatus.CREATING) { + if (RolloutGroupStatus.READY.equals(group.getStatus())) { readyGroups++; totalTargets += group.getTotalTargets(); continue; } final RolloutGroup filledGroup = fillRolloutGroupWithTargets(rollout, group); - if (filledGroup.getStatus() == RolloutGroupStatus.READY) { + if (RolloutGroupStatus.READY.equals(filledGroup.getStatus())) { readyGroups++; totalTargets += filledGroup.getTotalTargets(); } @@ -788,6 +788,11 @@ public class JpaRolloutManagement extends AbstractRolloutManagement { @Modifying public void deleteRollout(final long rolloutId) { final JpaRollout jpaRollout = rolloutRepository.findOne(rolloutId); + + if (jpaRollout == null) { + throw new EntityNotFoundException(Rollout.class, rolloutId); + } + if (RolloutStatus.DELETING.equals(jpaRollout.getStatus())) { return; } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java index e6e2ca6ff..33d92a313 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -655,6 +655,8 @@ public class JpaSoftwareManagement implements SoftwareManagement { @Override public Optional findSoftwareModuleMetadata(final Long moduleId, final String key) { + throwExceptionIfSoftwareModuleDoesNotExist(moduleId); + return Optional.ofNullable(softwareModuleMetadataRepository.findOne(new SwMetadataCompositeKey(moduleId, key))); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index c61f71b7f..31e1b2fbd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -9,7 +9,6 @@ package org.eclipse.hawkbit.repository.jpa; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -327,21 +326,25 @@ public class JpaTargetManagement implements TargetManagement { @Override @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public TargetTagAssignmentResult toggleTagAssignment(final Collection targetIds, final String tagName) { + public TargetTagAssignmentResult toggleTagAssignment(final Collection controllerIds, final String tagName) { final TargetTag tag = targetTagRepository.findByNameEquals(tagName) .orElseThrow(() -> new EntityNotFoundException(TargetTag.class, tagName)); - final List alreadyAssignedTargets = targetRepository.findByTagNameAndControllerIdIn(tagName, - targetIds); final List allTargets = targetRepository - .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(targetIds)); + .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(controllerIds)); + + if (allTargets.size() < controllerIds.size()) { + throw new EntityNotFoundException(Target.class, controllerIds, + allTargets.stream().map(Target::getControllerId).collect(Collectors.toList())); + } + + final List alreadyAssignedTargets = targetRepository.findByTagNameAndControllerIdIn(tagName, + controllerIds); // all are already assigned -> unassign if (alreadyAssignedTargets.size() == allTargets.size()) { alreadyAssignedTargets.forEach(target -> target.removeTag(tag)); - final TargetTagAssignmentResult result = new TargetTagAssignmentResult(0, 0, alreadyAssignedTargets.size(), - Collections.emptyList(), Collections.unmodifiableList(alreadyAssignedTargets), tag); - - return result; + return new TargetTagAssignmentResult(0, 0, alreadyAssignedTargets.size(), Collections.emptyList(), + Collections.unmodifiableList(alreadyAssignedTargets), tag); } allTargets.removeAll(alreadyAssignedTargets); @@ -365,6 +368,11 @@ public class JpaTargetManagement implements TargetManagement { final List allTargets = targetRepository .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(controllerIds)); + if (allTargets.size() < controllerIds.size()) { + throw new EntityNotFoundException(Target.class, controllerIds, + allTargets.stream().map(Target::getControllerId).collect(Collectors.toList())); + } + final JpaTargetTag tag = targetTagRepository.findById(tagId) .orElseThrow(() -> new EntityNotFoundException(TargetTag.class, tagId)); @@ -402,13 +410,13 @@ public class JpaTargetManagement implements TargetManagement { @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) public Target unAssignTag(final String controllerID, final Long targetTagId) { - final List allTargets = Collections.unmodifiableList(targetRepository - .findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(Arrays.asList(controllerID)))); + final Target target = targetRepository.findByControllerId(controllerID) + .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerID)); final TargetTag tag = targetTagRepository.findById(targetTagId) .orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagId)); - final List unAssignTag = unAssignTag(allTargets, tag); + final List unAssignTag = unAssignTag(Lists.newArrayList(target), tag); return unAssignTag.isEmpty() ? null : unAssignTag.get(0); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java index a5878b4c6..e57ac909f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java @@ -15,7 +15,10 @@ import java.util.stream.Collectors; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.eclipse.hawkbit.cache.TenantAwareCacheManager; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetTag; @@ -37,6 +40,9 @@ import com.google.common.collect.Lists; org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration.class }) public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest { + protected static final String NOT_EXIST_ID = "1234"; + protected static final long NOT_EXIST_IDL = Long.parseLong(NOT_EXIST_ID); + @PersistenceContext protected EntityManager entityManager; @@ -96,6 +102,11 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest return Lists.newArrayList(actionRepository.findByRolloutIdAndStatus(pageReq, rollout.getId(), actionStatus)); } + protected static void verifyThrownExceptionBy(final ThrowingCallable tc, final String objectType) { + Assertions.assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(tc) + .withMessageContaining(NOT_EXIST_ID).withMessageContaining(objectType); + } + protected TargetTagAssignmentResult toggleTagAssignment(final Collection targets, final TargetTag tag) { return targetManagement.toggleTagAssignment( targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()), tag.getName()); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java index 907522d21..a613703f7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java @@ -9,7 +9,6 @@ package org.eclipse.hawkbit.repository.jpa; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -23,8 +22,8 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; @@ -48,38 +47,41 @@ import ru.yandex.qatools.allure.annotations.Stories; public class ArtifactManagementTest extends AbstractJpaIntegrationTest { @Test - @Description("Verifies that management queries react as specfied on calls for non existing entities.") + @Description("Verifies that management get access react as specfied on calls for non existing entities by means " + + "of Optional not present.") @ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) }) - public void nonExistingEntityQueries() throws URISyntaxException { + public void nonExistingEntityAccessReturnsNotPresent() { final SoftwareModule module = testdataFactory.createSoftwareModuleOs(); - assertThatThrownBy(() -> artifactManagement.createArtifact(IOUtils.toInputStream("test", "UTF-8"), 1234L, "xxx", - null, null, false, null)).isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("SoftwareModule"); + assertThat(artifactManagement.findArtifact(NOT_EXIST_IDL)).isNotPresent(); + assertThat(artifactManagement.findByFilenameAndSoftwareModule(NOT_EXIST_ID, module.getId()).isPresent()) + .isFalse(); - assertThatThrownBy( - () -> artifactManagement.createArtifact(IOUtils.toInputStream("test", "UTF-8"), 1234L, "xxx", false)) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("SoftwareModule"); + assertThat(artifactManagement.findFirstArtifactBySHA1(NOT_EXIST_ID)).isNotPresent(); + assertThat(artifactManagement.loadArtifactBinary(NOT_EXIST_ID)).isNotPresent(); + } - assertThatThrownBy(() -> artifactManagement.deleteArtifact(1234L)).isInstanceOf(EntityNotFoundException.class) - .hasMessageContaining("1234").hasMessageContaining("Artifact"); + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @ExpectEvents({ @Expect(type = SoftwareModuleDeletedEvent.class, count = 0) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws URISyntaxException { - assertThat(artifactManagement.findArtifact(1234L)).isNotPresent(); - assertThatThrownBy(() -> artifactManagement.findArtifactBySoftwareModule(pageReq, 1234L)) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("SoftwareModule"); - assertThat(artifactManagement.findArtifactByFilename("1234")).isNotPresent(); + verifyThrownExceptionBy(() -> artifactManagement.createArtifact(IOUtils.toInputStream("test", "UTF-8"), + NOT_EXIST_IDL, "xxx", null, null, false, null), "SoftwareModule"); - assertThatThrownBy(() -> artifactManagement.findByFilenameAndSoftwareModule("xxx", 1234L)) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("SoftwareModule"); + verifyThrownExceptionBy( + () -> artifactManagement.createArtifact(IOUtils.toInputStream("test", "UTF-8"), 1234L, "xxx", false), + "SoftwareModule"); - assertThat(artifactManagement.findByFilenameAndSoftwareModule("1234", module.getId())).isNotPresent(); + verifyThrownExceptionBy(() -> artifactManagement.deleteArtifact(NOT_EXIST_IDL), "Artifact"); - assertThat(artifactManagement.findFirstArtifactBySHA1("1234")).isNotPresent(); - assertThat(artifactManagement.loadArtifactBinary("1234")).isNotPresent(); + verifyThrownExceptionBy(() -> artifactManagement.findArtifactBySoftwareModule(pageReq, NOT_EXIST_IDL), + "SoftwareModule"); + assertThat(artifactManagement.findArtifactByFilename(NOT_EXIST_ID).isPresent()).isFalse(); + verifyThrownExceptionBy(() -> artifactManagement.findByFilenameAndSoftwareModule("xxx", NOT_EXIST_IDL), + "SoftwareModule"); } @Test diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java index 33a9c325a..a7262be71 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ControllerManagementTest.java @@ -9,7 +9,6 @@ package org.eclipse.hawkbit.repository.jpa; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS; import static org.junit.Assert.fail; @@ -33,7 +32,6 @@ import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedE 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.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.Artifact; @@ -58,77 +56,67 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("Controller Management") public class ControllerManagementTest extends AbstractJpaIntegrationTest { - @Autowired private RepositoryProperties repositoryProperties; @Test - @Description("Verifies that management queries react as specfied on calls for non existing entities.") + @Description("Verifies that management get access react as specfied 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) }) - public void nonExistingEntityQueries() throws URISyntaxException { + public void nonExistingEntityAccessReturnsNotPresent() { final Target target = testdataFactory.createTarget(); final SoftwareModule module = testdataFactory.createSoftwareModuleOs(); - assertThatThrownBy(() -> controllerManagement - .addCancelActionStatus(entityFactory.actionStatus().create(1234L).status(Action.Status.FINISHED))) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Action"); - - assertThatThrownBy(() -> controllerManagement - .addInformationalActionStatus(entityFactory.actionStatus().create(1234L).status(Action.Status.RUNNING))) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Action"); - - assertThatThrownBy(() -> controllerManagement - .addUpdateActionStatus(entityFactory.actionStatus().create(1234L).status(Action.Status.FINISHED))) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Action"); - - assertThat(controllerManagement.findActionWithDetails(1234L)).isNotPresent(); - assertThat(controllerManagement.findByControllerId("1234")).isNotPresent(); - assertThat(controllerManagement.findByTargetId(1234L)).isNotPresent(); - - assertThatThrownBy(() -> controllerManagement.findOldestActiveActionByTarget("1234")) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Target"); - - assertThatThrownBy(() -> controllerManagement - .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), 1234L)) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("SoftwareModule"); - - assertThatThrownBy( - () -> controllerManagement.getActionForDownloadByTargetAndSoftwareModule("1234", module.getId())) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Target"); - - assertThat(controllerManagement - .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module.getId()).isPresent()) - .isFalse(); - - assertThatThrownBy(() -> controllerManagement.hasTargetArtifactAssigned(1234L, "XXX")) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Target"); - - assertThatThrownBy(() -> controllerManagement.hasTargetArtifactAssigned("1234", "XXX")) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Target"); + assertThat(controllerManagement.findActionWithDetails(NOT_EXIST_IDL)).isNotPresent(); + assertThat(controllerManagement.findByControllerId(NOT_EXIST_ID)).isNotPresent(); + assertThat(controllerManagement.findByTargetId(NOT_EXIST_IDL)).isNotPresent(); + assertThat(controllerManagement.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), + module.getId())).isNotPresent(); assertThat(controllerManagement.hasTargetArtifactAssigned(target.getControllerId(), "XXX")).isFalse(); assertThat(controllerManagement.hasTargetArtifactAssigned(target.getId(), "XXX")).isFalse(); + } - assertThatThrownBy(() -> controllerManagement.registerRetrieved(1234L, "test message")) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Action"); + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws URISyntaxException { + final Target target = testdataFactory.createTarget(); + final SoftwareModule module = testdataFactory.createSoftwareModuleOs(); - assertThatThrownBy(() -> controllerManagement.updateControllerAttributes("1234", Maps.newHashMap())) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Target"); + verifyThrownExceptionBy(() -> controllerManagement.addCancelActionStatus( + entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.FINISHED)), "Action"); - assertThatThrownBy(() -> controllerManagement.updateLastTargetQuery("1234", new URI("http://test.com"))) - .isInstanceOf(EntityNotFoundException.class).hasMessageContaining("1234") - .hasMessageContaining("Target"); + verifyThrownExceptionBy(() -> controllerManagement.addInformationalActionStatus( + entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.RUNNING)), "Action"); + + verifyThrownExceptionBy(() -> controllerManagement.addUpdateActionStatus( + entityFactory.actionStatus().create(NOT_EXIST_IDL).status(Action.Status.FINISHED)), "Action"); + + verifyThrownExceptionBy(() -> controllerManagement.findOldestActiveActionByTarget(NOT_EXIST_ID), "Target"); + + verifyThrownExceptionBy(() -> controllerManagement + .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), NOT_EXIST_IDL), + "SoftwareModule"); + + verifyThrownExceptionBy( + () -> controllerManagement.getActionForDownloadByTargetAndSoftwareModule(NOT_EXIST_ID, module.getId()), + "Target"); + + verifyThrownExceptionBy(() -> controllerManagement.hasTargetArtifactAssigned(NOT_EXIST_IDL, "XXX"), "Target"); + + verifyThrownExceptionBy(() -> controllerManagement.hasTargetArtifactAssigned(NOT_EXIST_ID, "XXX"), "Target"); + + verifyThrownExceptionBy(() -> controllerManagement.registerRetrieved(NOT_EXIST_IDL, "test message"), "Action"); + + verifyThrownExceptionBy(() -> controllerManagement.updateControllerAttributes(NOT_EXIST_ID, Maps.newHashMap()), + "Target"); + + verifyThrownExceptionBy( + () -> controllerManagement.updateLastTargetQuery(NOT_EXIST_ID, new URI("http://test.com")), "Target"); } @Test diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java index 1c4bc384f..db1301818 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java @@ -24,6 +24,7 @@ import java.util.stream.Collectors; import org.eclipse.hawkbit.repository.ActionStatusFields; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent; +import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException; import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; @@ -42,6 +43,9 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.model.TargetWithActionType; +import org.eclipse.hawkbit.repository.test.matcher.Expect; +import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -67,7 +71,6 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("Deployment Management") public class DeploymentManagementTest extends AbstractJpaIntegrationTest { - private EventHandlerStub eventHandlerStub; private CancelEventHandlerStub cancelEventHandlerStub; @@ -84,6 +87,49 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest { applicationContext.addApplicationListener(cancelEventHandlerStub); } + @Test + @Description("Verifies that management get access react as specfied on calls for non existing entities by means " + + "of Optional not present.") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) }) + public void nonExistingEntityAccessReturnsNotPresent() { + assertThat(deploymentManagement.findAction(1234L)).isNotPresent(); + assertThat(deploymentManagement.findActionWithDetails(NOT_EXIST_IDL)).isNotPresent(); + } + + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() { + final Target target = testdataFactory.createTarget(); + + verifyThrownExceptionBy(() -> deploymentManagement.assignDistributionSet(NOT_EXIST_IDL, + Lists.newArrayList(new TargetWithActionType(target.getControllerId()))), "DistributionSet"); + verifyThrownExceptionBy( + () -> deploymentManagement.assignDistributionSet(NOT_EXIST_IDL, + Lists.newArrayList(new TargetWithActionType(target.getControllerId())), "xxx"), + "DistributionSet"); + verifyThrownExceptionBy(() -> deploymentManagement.assignDistributionSet(NOT_EXIST_IDL, ActionType.FORCED, + System.currentTimeMillis(), Lists.newArrayList(target.getControllerId())), "DistributionSet"); + + verifyThrownExceptionBy(() -> deploymentManagement.cancelAction(NOT_EXIST_IDL), "Action"); + verifyThrownExceptionBy(() -> deploymentManagement.countActionsByTarget(NOT_EXIST_ID), "Target"); + verifyThrownExceptionBy(() -> deploymentManagement.countActionsByTarget("xxx", NOT_EXIST_ID), "Target"); + + verifyThrownExceptionBy(() -> deploymentManagement.findActionsByDistributionSet(pageReq, NOT_EXIST_IDL), + "DistributionSet"); + verifyThrownExceptionBy(() -> deploymentManagement.findActionsByTarget(NOT_EXIST_ID, pageReq), "Target"); + verifyThrownExceptionBy(() -> deploymentManagement.findActionsByTarget("id==*", NOT_EXIST_ID, pageReq), + "Target"); + verifyThrownExceptionBy( + () -> deploymentManagement.findActionsWithStatusCountByTargetOrderByIdDesc(NOT_EXIST_ID), "Target"); + + verifyThrownExceptionBy(() -> deploymentManagement.findActiveActionsByTarget(NOT_EXIST_ID), "Target"); + verifyThrownExceptionBy(() -> deploymentManagement.findInActiveActionsByTarget(NOT_EXIST_ID), "Target"); + verifyThrownExceptionBy(() -> deploymentManagement.forceQuitAction(NOT_EXIST_IDL), "Action"); + verifyThrownExceptionBy(() -> deploymentManagement.forceTargetAction(NOT_EXIST_IDL), "Action"); + } + @Test @Description("Test verifies that the repistory retrieves the action including all defined (lazy) details.") public void findActionWithLazyDetails() { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java index b5076c1f4..4eb8533ba 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java @@ -9,7 +9,7 @@ package org.eclipse.hawkbit.repository.jpa; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.ArrayList; import java.util.Collection; @@ -22,8 +22,10 @@ import org.assertj.core.api.Condition; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.builder.DistributionSetCreate; import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent; +import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; @@ -58,32 +60,165 @@ import ru.yandex.qatools.allure.annotations.Stories; @Features("Component Tests - Repository") @Stories("DistributionSet Management") public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { + @Test + @Description("Verifies that management get access react as specfied on calls for non existing entities by means " + + "of Optional not present.") + @ExpectEvents({ @Expect(type = DistributionSetCreatedEvent.class, count = 1), + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void nonExistingEntityAccessReturnsNotPresent() { + final DistributionSet set = testdataFactory.createDistributionSet(); + assertThat(distributionSetManagement.findDistributionSetById(NOT_EXIST_IDL)).isNotPresent(); + assertThat(distributionSetManagement.findDistributionSetByIdWithDetails(NOT_EXIST_IDL)).isNotPresent(); + assertThat(distributionSetManagement.findDistributionSetByNameAndVersion(NOT_EXIST_ID, NOT_EXIST_ID)) + .isNotPresent(); + assertThat(distributionSetManagement.findDistributionSetMetadata(set.getId(), NOT_EXIST_ID)).isNotPresent(); + + assertThat(distributionSetManagement.findDistributionSetTypeById(NOT_EXIST_IDL)).isNotPresent(); + assertThat(distributionSetManagement.findDistributionSetTypeByKey(NOT_EXIST_ID)).isNotPresent(); + assertThat(distributionSetManagement.findDistributionSetTypeByName(NOT_EXIST_ID)).isNotPresent(); + } + + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @ExpectEvents({ @Expect(type = DistributionSetCreatedEvent.class, count = 1), + @Expect(type = DistributionSetTagCreatedEvent.class, count = 1), + @Expect(type = SoftwareModuleCreatedEvent.class, count = 4) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() { + final DistributionSet set = testdataFactory.createDistributionSet(); + final DistributionSetTag dsTag = testdataFactory.createDistributionSetTags(1).get(0); + final SoftwareModule module = testdataFactory.createSoftwareModuleApp(); + + verifyThrownExceptionBy(() -> distributionSetManagement.assignMandatorySoftwareModuleTypes(NOT_EXIST_IDL, + Lists.newArrayList(osType.getId())), "DistributionSetType"); + verifyThrownExceptionBy(() -> distributionSetManagement.assignMandatorySoftwareModuleTypes( + testdataFactory.findOrCreateDistributionSetType("xxx", "xxx").getId(), + Lists.newArrayList(NOT_EXIST_IDL)), "SoftwareModuleType"); + + verifyThrownExceptionBy(() -> distributionSetManagement.assignOptionalSoftwareModuleTypes(1234L, + Lists.newArrayList(osType.getId())), "DistributionSetType"); + verifyThrownExceptionBy(() -> distributionSetManagement.assignOptionalSoftwareModuleTypes( + testdataFactory.findOrCreateDistributionSetType("xxx", "xxx").getId(), + Lists.newArrayList(NOT_EXIST_IDL)), "SoftwareModuleType"); + + verifyThrownExceptionBy(() -> distributionSetManagement.assignSoftwareModules(NOT_EXIST_IDL, + Lists.newArrayList(module.getId())), "DistributionSet"); + verifyThrownExceptionBy( + () -> distributionSetManagement.assignSoftwareModules(set.getId(), Lists.newArrayList(NOT_EXIST_IDL)), + "SoftwareModule"); + + verifyThrownExceptionBy(() -> distributionSetManagement.unassignSoftwareModule(NOT_EXIST_IDL, module.getId()), + "DistributionSet"); + verifyThrownExceptionBy(() -> distributionSetManagement.unassignSoftwareModule(set.getId(), NOT_EXIST_IDL), + "SoftwareModule"); + + verifyThrownExceptionBy( + () -> distributionSetManagement.assignTag(Lists.newArrayList(set.getId()), NOT_EXIST_IDL), + "DistributionSetTag"); + + verifyThrownExceptionBy( + () -> distributionSetManagement.assignTag(Lists.newArrayList(NOT_EXIST_IDL), dsTag.getId()), + "DistributionSet"); + + verifyThrownExceptionBy( + () -> distributionSetManagement.toggleTagAssignment(Lists.newArrayList(NOT_EXIST_IDL), dsTag.getName()), + "DistributionSet"); + verifyThrownExceptionBy( + () -> distributionSetManagement.toggleTagAssignment(Lists.newArrayList(set.getId()), NOT_EXIST_ID), + "DistributionSetTag"); + + verifyThrownExceptionBy(() -> distributionSetManagement.unAssignAllDistributionSetsByTag(NOT_EXIST_IDL), + "DistributionSetTag"); + + verifyThrownExceptionBy(() -> distributionSetManagement.unAssignTag(set.getId(), NOT_EXIST_IDL), + "DistributionSetTag"); + + verifyThrownExceptionBy(() -> distributionSetManagement.unAssignTag(NOT_EXIST_IDL, dsTag.getId()), + "DistributionSet"); + + verifyThrownExceptionBy(() -> distributionSetManagement.countDistributionSetsByType(NOT_EXIST_IDL), + "DistributionSet"); + + verifyThrownExceptionBy( + () -> distributionSetManagement + .createDistributionSet(entityFactory.distributionSet().create().name("xxx").type(NOT_EXIST_ID)), + "DistributionSetType"); + + verifyThrownExceptionBy(() -> distributionSetManagement.createDistributionSetMetadata(NOT_EXIST_IDL, + Lists.newArrayList(entityFactory.generateMetadata("123", "123"))), "DistributionSet"); + + verifyThrownExceptionBy( + () -> distributionSetManagement.deleteDistributionSet(Lists.newArrayList(NOT_EXIST_IDL)), + "DistributionSet"); + verifyThrownExceptionBy(() -> distributionSetManagement.deleteDistributionSet(NOT_EXIST_IDL), + "DistributionSet"); + verifyThrownExceptionBy(() -> distributionSetManagement.deleteDistributionSetMetadata(NOT_EXIST_IDL, "xxx"), + "DistributionSet"); + verifyThrownExceptionBy( + () -> distributionSetManagement.deleteDistributionSetMetadata(set.getId(), NOT_EXIST_ID), + "DistributionSetMetadata"); + + verifyThrownExceptionBy(() -> distributionSetManagement.deleteDistributionSetType(NOT_EXIST_IDL), + "DistributionSetType"); + + verifyThrownExceptionBy(() -> distributionSetManagement.findDistributionSetByAction(NOT_EXIST_IDL), "Action"); + + verifyThrownExceptionBy(() -> distributionSetManagement.findDistributionSetMetadata(NOT_EXIST_IDL, "xxx"), + "DistributionSet"); + + verifyThrownExceptionBy( + () -> distributionSetManagement.findDistributionSetMetadataByDistributionSetId(NOT_EXIST_IDL, pageReq), + "DistributionSet"); + + verifyThrownExceptionBy(() -> distributionSetManagement + .findDistributionSetMetadataByDistributionSetId(NOT_EXIST_IDL, "name==*", pageReq), "DistributionSet"); + + assertThatThrownBy(() -> distributionSetManagement.isDistributionSetInUse(NOT_EXIST_IDL)) + .isInstanceOf(EntityNotFoundException.class).hasMessageContaining(NOT_EXIST_ID) + .hasMessageContaining("DistributionSet"); + + verifyThrownExceptionBy( + () -> distributionSetManagement + .updateDistributionSet(entityFactory.distributionSet().update(NOT_EXIST_IDL)), + "DistributionSet"); + + verifyThrownExceptionBy(() -> distributionSetManagement.updateDistributionSetMetadata(NOT_EXIST_IDL, + entityFactory.generateMetadata("xxx", "xxx")), "DistributionSet"); + + verifyThrownExceptionBy(() -> distributionSetManagement.updateDistributionSetMetadata(set.getId(), + entityFactory.generateMetadata(NOT_EXIST_ID, "xxx")), "DistributionSetMetadata"); + + verifyThrownExceptionBy( + () -> distributionSetManagement + .updateDistributionSetType(entityFactory.distributionSetType().update(NOT_EXIST_IDL)), + "DistributionSet"); + } @Test @Description("Tests the successfull module update of unused distribution set type which is in fact allowed.") public void updateUnassignedDistributionSetTypeModules() { - DistributionSetType updatableType = distributionSetManagement.createDistributionSetType( + final DistributionSetType updatableType = distributionSetManagement.createDistributionSetType( entityFactory.distributionSetType().create().key("updatableType").name("to be deleted")); assertThat( distributionSetManagement.findDistributionSetTypeByKey("updatableType").get().getMandatoryModuleTypes()) .isEmpty(); // add OS - updatableType = distributionSetManagement.assignMandatorySoftwareModuleTypes(updatableType.getId(), + distributionSetManagement.assignMandatorySoftwareModuleTypes(updatableType.getId(), Sets.newHashSet(osType.getId())); assertThat( distributionSetManagement.findDistributionSetTypeByKey("updatableType").get().getMandatoryModuleTypes()) .containsOnly(osType); // add JVM - updatableType = distributionSetManagement.assignMandatorySoftwareModuleTypes(updatableType.getId(), + distributionSetManagement.assignMandatorySoftwareModuleTypes(updatableType.getId(), Sets.newHashSet(runtimeType.getId())); assertThat( distributionSetManagement.findDistributionSetTypeByKey("updatableType").get().getMandatoryModuleTypes()) .containsOnly(osType, runtimeType); // remove OS - updatableType = distributionSetManagement.unassignSoftwareModuleType(updatableType.getId(), osType.getId()); + distributionSetManagement.unassignSoftwareModuleType(updatableType.getId(), osType.getId()); assertThat( distributionSetManagement.findDistributionSetTypeByKey("updatableType").get().getMandatoryModuleTypes()) .containsOnly(runtimeType); @@ -120,14 +255,8 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { distributionSetManagement.createDistributionSet(entityFactory.distributionSet().create().name("newtypesoft") .version("1").type(nonUpdatableType.getKey())); - try { - distributionSetManagement.assignMandatorySoftwareModuleTypes(nonUpdatableType.getId(), - Sets.newHashSet(osType.getId())); - fail("Should not have worked as DS is in use."); - } catch (final EntityReadOnlyException e) { - - } - + assertThatThrownBy(() -> distributionSetManagement.assignMandatorySoftwareModuleTypes(nonUpdatableType.getId(), + Sets.newHashSet(osType.getId()))).isInstanceOf(EntityReadOnlyException.class); } @Test @@ -144,12 +273,9 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { distributionSetManagement.createDistributionSet(entityFactory.distributionSet().create().name("newtypesoft") .version("1").type(nonUpdatableType.getKey())); - try { - distributionSetManagement.unassignSoftwareModuleType(nonUpdatableType.getId(), osType.getId()); - fail("Should not have worked as DS is in use."); - } catch (final EntityReadOnlyException e) { - - } + final Long typeId = nonUpdatableType.getId(); + assertThatThrownBy(() -> distributionSetManagement.unassignSoftwareModuleType(typeId, osType.getId())) + .isInstanceOf(EntityReadOnlyException.class); } @Test @@ -186,12 +312,8 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { public void createDuplicateDistributionSetsFailsWithException() { testdataFactory.createDistributionSet("a"); - try { - testdataFactory.createDistributionSet("a"); - fail("Should not have worked as DS with same UK already exists."); - } catch (final EntityAlreadyExistsException e) { - - } + assertThatThrownBy(() -> testdataFactory.createDistributionSet("a")) + .isInstanceOf(EntityAlreadyExistsException.class); } @Test @@ -261,22 +383,15 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { assignDistributionSet(ds.getId(), target.getControllerId()); ds = distributionSetManagement.findDistributionSetByIdWithDetails(ds.getId()).get(); + final Long dsId = ds.getId(); // not allowed as it is assigned now - try { - ds = distributionSetManagement.assignSoftwareModules(ds.getId(), Sets.newHashSet(os2.getId())); - fail("Expected EntityReadOnlyException"); - } catch (final EntityReadOnlyException e) { - - } + assertThatThrownBy(() -> distributionSetManagement.assignSoftwareModules(dsId, Sets.newHashSet(os2.getId()))) + .isInstanceOf(EntityReadOnlyException.class); // not allowed as it is assigned now - try { - ds = distributionSetManagement.unassignSoftwareModule(ds.getId(), - ds.findFirstModuleByType(appType).get().getId()); - fail("Expected EntityReadOnlyException"); - } catch (final EntityReadOnlyException e) { - - } + final Long appId = ds.findFirstModuleByType(appType).get().getId(); + assertThatThrownBy(() -> distributionSetManagement.unassignSoftwareModule(dsId, appId)) + .isInstanceOf(EntityReadOnlyException.class); } @Test @@ -292,19 +407,15 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { entityFactory.softwareModule().create().name("agent-hub2").version("1.0.5").type(appType.getKey())); // update data - try { - distributionSetManagement.assignSoftwareModules(set.getId(), Sets.newHashSet(module.getId())); - fail("Should not have worked as module type is not in DS type."); - } catch (final UnsupportedSoftwareModuleForThisDistributionSetException e) { - - } + assertThatThrownBy( + () -> distributionSetManagement.assignSoftwareModules(set.getId(), Sets.newHashSet(module.getId()))) + .isInstanceOf(UnsupportedSoftwareModuleForThisDistributionSetException.class); } @Test @Description("Legal updates of a DS, e.g. name or description and module addition, removal while still unassigned.") public void updateDistributionSet() { // prepare data - final Target target = testdataFactory.createTarget(); DistributionSet ds = testdataFactory.createDistributionSet(""); final SoftwareModule os = testdataFactory.createSoftwareModuleOs(); @@ -722,7 +833,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { assignDistributionSet(dsToTargetAssigned.getId(), savedTarget.getControllerId()); // create assigned rollout - createRolloutByVariables("test", "test", 5, "name==*", dsToRolloutAssigned, "50", "5"); + testdataFactory.createRolloutByVariables("test", "test", 5, "name==*", dsToRolloutAssigned, "50", "5"); // delete assigned ds assertThat(distributionSetRepository.findAll()).hasSize(4); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java index dbf89430b..d64fdd5eb 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java @@ -19,8 +19,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; -import org.eclipse.hawkbit.repository.RolloutGroupManagement; -import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.builder.RolloutCreate; import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate; import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent; @@ -54,15 +52,12 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; -import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; import org.eclipse.hawkbit.repository.test.matcher.Expect; import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; -import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Description; import org.springframework.data.domain.Page; import org.springframework.data.domain.Slice; @@ -82,12 +77,44 @@ import ru.yandex.qatools.allure.annotations.Title; @Features("Component Tests - Repository") @Stories("Rollout Management") public class RolloutManagementTest extends AbstractJpaIntegrationTest { + @Test + @Description("Verifies that management get access reacts as specfied on calls for non existing entities by means " + + "of Optional not present.") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) }) + public void nonExistingEntityAccessReturnsNotPresent() { + assertThat(rolloutManagement.findRolloutById(NOT_EXIST_IDL)).isNotPresent(); + assertThat(rolloutManagement.findRolloutByName(NOT_EXIST_ID)).isNotPresent(); + assertThat(rolloutManagement.findRolloutWithDetailedStatus(NOT_EXIST_IDL)).isNotPresent(); + } - @Autowired - private RolloutManagement rolloutManagement; + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @ExpectEvents({ @Expect(type = RolloutDeletedEvent.class, count = 0), + @Expect(type = RolloutGroupCreatedEvent.class, count = 10), + @Expect(type = RolloutGroupUpdatedEvent.class, count = 20), + @Expect(type = DistributionSetCreatedEvent.class, count = 1), + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3), + @Expect(type = RolloutUpdatedEvent.class, count = 1), + @Expect(type = TargetCreatedEvent.class, count = 10) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() { + final Rollout createdRollout = testdataFactory.createRollout("xxx"); - @Autowired - private RolloutGroupManagement rolloutGroupManagement; + verifyThrownExceptionBy(() -> rolloutManagement.deleteRollout(NOT_EXIST_IDL), "Rollout"); + + verifyThrownExceptionBy(() -> rolloutManagement.getFinishedPercentForRunningGroup(NOT_EXIST_IDL, NOT_EXIST_IDL), + "Rollout"); + verifyThrownExceptionBy( + () -> rolloutManagement.getFinishedPercentForRunningGroup(createdRollout.getId(), NOT_EXIST_IDL), + "RolloutGroup"); + + verifyThrownExceptionBy(() -> rolloutManagement.pauseRollout(NOT_EXIST_IDL), "Rollout"); + verifyThrownExceptionBy(() -> rolloutManagement.resumeRollout(NOT_EXIST_IDL), "Rollout"); + verifyThrownExceptionBy(() -> rolloutManagement.startRollout(NOT_EXIST_IDL), "Rollout"); + + verifyThrownExceptionBy(() -> rolloutManagement.updateRollout(entityFactory.rollout().update(NOT_EXIST_IDL)), + "Rollout"); + } @Test @Description("Verifying that the rollout is created correctly, executing the filter and split up the targets in the correct group size.") @@ -605,8 +632,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { final DistributionSet dsForRolloutTwo = testdataFactory.createDistributionSet("dsForRolloutTwo"); - final Rollout rolloutTwo = createRolloutByVariables("rolloutTwo", "This is the description for rollout two", 1, - "controllerId==rollout-*", dsForRolloutTwo, "50", "80"); + final Rollout rolloutTwo = testdataFactory.createRolloutByVariables("rolloutTwo", + "This is the description for rollout two", 1, "controllerId==rollout-*", dsForRolloutTwo, "50", "80"); changeStatusForAllRunningActions(rolloutOne, Status.FINISHED); rolloutManagement.handleRollouts(); // Verify that 5 targets are finished, 5 are running and 5 are ready. @@ -664,8 +691,9 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { assertThat(rolloutOne.getStatus()).isEqualTo(RolloutStatus.FINISHED); final int amountGroupsForRolloutTwo = 1; - Rollout rolloutTwo = createRolloutByVariables("rolloutTwo", "This is the description for rollout two", - amountGroupsForRolloutTwo, "controllerId==rollout-*", distributionSet, "50", "80"); + Rollout rolloutTwo = testdataFactory.createRolloutByVariables("rolloutTwo", + "This is the description for rollout two", amountGroupsForRolloutTwo, "controllerId==rollout-*", + distributionSet, "50", "80"); rolloutManagement.startRollout(rolloutTwo.getId()); @@ -1012,8 +1040,8 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); try { - createRolloutByVariables(rolloutName, "desc", amountGroups, "id==notExisting", distributionSet, - successCondition, errorCondition); + testdataFactory.createRolloutByVariables(rolloutName, "desc", amountGroups, "id==notExisting", + distributionSet, successCondition, errorCondition); fail("Was able to create a Rollout without targets."); } catch (final ConstraintViolationException e) { // OK @@ -1033,11 +1061,11 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { testdataFactory.createTargets(amountTargetsForRollout, "dup-ro-", "rollout"); final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); - createRolloutByVariables(rolloutName, "desc", amountGroups, "id==dup-ro-*", distributionSet, successCondition, - errorCondition); + testdataFactory.createRolloutByVariables(rolloutName, "desc", amountGroups, "id==dup-ro-*", distributionSet, + successCondition, errorCondition); try { - createRolloutByVariables(rolloutName, "desc", amountGroups, "id==dup-ro-*", distributionSet, + testdataFactory.createRolloutByVariables(rolloutName, "desc", amountGroups, "id==dup-ro-*", distributionSet, successCondition, errorCondition); fail("Was able to create a duplicate Rollout."); } catch (final EntityAlreadyExistsException e) { @@ -1058,7 +1086,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName); - Rollout myRollout = createRolloutByVariables(rolloutName, "desc", amountGroups, + Rollout myRollout = testdataFactory.createRolloutByVariables(rolloutName, "desc", amountGroups, "controllerId==" + targetPrefixName + "-*", distributionSet, successCondition, errorCondition); assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY); @@ -1107,7 +1135,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName); - Rollout myRollout = createRolloutByVariables(rolloutName, "desc", amountGroups, + Rollout myRollout = testdataFactory.createRolloutByVariables(rolloutName, "desc", amountGroups, "controllerId==" + targetPrefixName + "-*", distributionSet, successCondition, errorCondition); assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY); @@ -1148,7 +1176,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName); - Rollout myRollout = createRolloutByVariables(rolloutName, "desc", amountGroups, + Rollout myRollout = testdataFactory.createRolloutByVariables(rolloutName, "desc", amountGroups, "controllerId==" + targetPrefixName + "-*", distributionSet, successCondition, errorCondition); assertThat(myRollout.getStatus()).isEqualTo(RolloutStatus.READY); @@ -1508,17 +1536,12 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { private Rollout createSimpleTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout, final int amountOtherTargets, final int groupSize, final String successCondition, final String errorCondition) { - final SoftwareModule ah = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP); - final SoftwareModule jvm = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_RT); - final SoftwareModule os = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_OS); - - final DistributionSet rolloutDS = testdataFactory.createDistributionSet("rolloutDS", "0.0.0", standardDsType, - Lists.newArrayList(os, jvm, ah)); + final DistributionSet rolloutDS = testdataFactory.createDistributionSet("rolloutDS"); testdataFactory.createTargets(amountTargetsForRollout, "rollout-", "rollout"); testdataFactory.createTargets(amountOtherTargets, "others-", "rollout"); final String filterQuery = "controllerId==rollout-*"; - return createRolloutByVariables("test-rollout-name-1", "test-rollout-description-1", groupSize, filterQuery, - rolloutDS, successCondition, errorCondition); + return testdataFactory.createRolloutByVariables("test-rollout-name-1", "test-rollout-description-1", groupSize, + filterQuery, rolloutDS, successCondition, errorCondition); } private Rollout createTestRolloutWithTargetsAndDistributionSet(final int amountTargetsForRollout, @@ -1526,7 +1549,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { final String targetPrefixName) { final DistributionSet dsForRolloutTwo = testdataFactory.createDistributionSet("dsFor" + rolloutName); testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName); - return createRolloutByVariables(rolloutName, rolloutName + "description", groupSize, + return testdataFactory.createRolloutByVariables(rolloutName, rolloutName + "description", groupSize, "controllerId==" + targetPrefixName + "-*", dsForRolloutTwo, successCondition, errorCondition); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java index 7ea07b8cb..6eaaebf53 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java @@ -22,6 +22,7 @@ import javax.validation.ConstraintViolationException; import org.apache.commons.lang3.RandomUtils; import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate; +import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; @@ -38,6 +39,8 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.eclipse.hawkbit.repository.test.matcher.Expect; +import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.Test; import org.springframework.data.domain.Page; @@ -54,6 +57,86 @@ import ru.yandex.qatools.allure.annotations.Stories; @Stories("Software Management") public class SoftwareManagementTest extends AbstractJpaIntegrationTest { + @Test + @Description("Verifies that management get access reacts as specfied on calls for non existing entities by means " + + "of Optional not present.") + @ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) }) + public void nonExistingEntityAccessReturnsNotPresent() { + final SoftwareModule module = testdataFactory.createSoftwareModuleApp(); + + assertThat(softwareManagement.findSoftwareModuleById(1234L)).isNotPresent(); + + assertThat(softwareManagement.findSoftwareModuleTypeById(NOT_EXIST_IDL)).isNotPresent(); + assertThat(softwareManagement.findSoftwareModuleTypeByKey(NOT_EXIST_ID)).isNotPresent(); + assertThat(softwareManagement.findSoftwareModuleTypeByName(NOT_EXIST_ID)).isNotPresent(); + + assertThat(softwareManagement.findSoftwareModuleByNameAndVersion(NOT_EXIST_ID, NOT_EXIST_ID, osType.getId())) + .isNotPresent(); + + assertThat(softwareManagement.findSoftwareModuleMetadata(module.getId(), NOT_EXIST_ID)).isNotPresent(); + } + + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @ExpectEvents({ @Expect(type = SoftwareModuleCreatedEvent.class, count = 1) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() { + final SoftwareModule module = testdataFactory.createSoftwareModuleApp(); + + verifyThrownExceptionBy( + () -> softwareManagement.createSoftwareModule( + Lists.newArrayList(entityFactory.softwareModule().create().name("xxx").type(NOT_EXIST_ID))), + "SoftwareModuleType"); + verifyThrownExceptionBy( + () -> softwareManagement + .createSoftwareModule(entityFactory.softwareModule().create().name("xxx").type(NOT_EXIST_ID)), + "SoftwareModuleType"); + + verifyThrownExceptionBy(() -> softwareManagement.createSoftwareModuleMetadata(NOT_EXIST_IDL, + entityFactory.generateMetadata("xxx", "xxx")), "SoftwareModule"); + verifyThrownExceptionBy(() -> softwareManagement.createSoftwareModuleMetadata(NOT_EXIST_IDL, + Lists.newArrayList(entityFactory.generateMetadata("xxx", "xxx"))), "SoftwareModule"); + + verifyThrownExceptionBy(() -> softwareManagement.deleteSoftwareModule(NOT_EXIST_IDL), "SoftwareModule"); + verifyThrownExceptionBy(() -> softwareManagement.deleteSoftwareModules(Lists.newArrayList(NOT_EXIST_IDL)), + "SoftwareModule"); + verifyThrownExceptionBy(() -> softwareManagement.deleteSoftwareModuleMetadata(NOT_EXIST_IDL, "xxx"), + "SoftwareModule"); + verifyThrownExceptionBy(() -> softwareManagement.deleteSoftwareModuleMetadata(module.getId(), NOT_EXIST_ID), + "SoftwareModuleMetadata"); + + verifyThrownExceptionBy(() -> softwareManagement.updateSoftwareModuleMetadata(NOT_EXIST_IDL, + entityFactory.generateMetadata("xxx", "xxx")), "SoftwareModule"); + verifyThrownExceptionBy(() -> softwareManagement.updateSoftwareModuleMetadata(module.getId(), + entityFactory.generateMetadata(NOT_EXIST_ID, "xxx")), "SoftwareModuleMetadata"); + + verifyThrownExceptionBy(() -> softwareManagement.deleteSoftwareModuleType(NOT_EXIST_IDL), "SoftwareModuleType"); + + verifyThrownExceptionBy(() -> softwareManagement.findSoftwareModuleByAssignedTo(pageReq, NOT_EXIST_IDL), + "DistributionSet"); + + verifyThrownExceptionBy( + () -> softwareManagement.findSoftwareModuleByNameAndVersion("xxx", "xxx", NOT_EXIST_IDL), + "SoftwareModuleType"); + + verifyThrownExceptionBy(() -> softwareManagement.findSoftwareModuleMetadata(NOT_EXIST_IDL, NOT_EXIST_ID), + "SoftwareModule"); + + verifyThrownExceptionBy(() -> softwareManagement.findSoftwareModuleMetadataBySoftwareModuleId(NOT_EXIST_IDL), + "SoftwareModule"); + verifyThrownExceptionBy(() -> softwareManagement.findSoftwareModuleMetadataBySoftwareModuleId(NOT_EXIST_IDL, + "name==*", pageReq), "SoftwareModule"); + verifyThrownExceptionBy(() -> softwareManagement.findSoftwareModulesByType(pageReq, NOT_EXIST_IDL), + "SoftwareModule"); + + verifyThrownExceptionBy( + () -> softwareManagement.updateSoftwareModule(entityFactory.softwareModule().update(NOT_EXIST_IDL)), + "SoftwareModule"); + verifyThrownExceptionBy( + () -> softwareManagement.updateSoftwareModuleType(entityFactory.softwareModuleType().update(1234L)), + "SoftwareModuleType"); + } + @Test @Description("Calling update without changing fields results in no recorded change in the repository including unchanged audit fields.") public void updateNothingResultsInUnchangedRepositoryForType() { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TagManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TagManagementTest.java index 58f014525..354af3a2a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TagManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TagManagementTest.java @@ -19,6 +19,9 @@ import java.util.List; import java.util.stream.Collectors; import org.eclipse.hawkbit.repository.TagManagement; +import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdateEvent; +import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdateEvent; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.DistributionSet; @@ -29,7 +32,8 @@ import org.eclipse.hawkbit.repository.model.Tag; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; -import org.junit.Before; +import org.eclipse.hawkbit.repository.test.matcher.Expect; +import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; import org.junit.Test; import com.google.common.collect.Lists; @@ -46,9 +50,30 @@ import ru.yandex.qatools.allure.annotations.Stories; @Stories("Tag Management") public class TagManagementTest extends AbstractJpaIntegrationTest { - @Before - public void setup() { - assertThat(targetTagRepository.findAll()).as("Not tags should be available").isEmpty(); + @Test + @Description("Verifies that management get access reacts as specfied on calls for non existing entities by means " + + "of Optional not present.") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) }) + public void nonExistingEntityAccessReturnsNotPresent() { + assertThat(tagManagement.findDistributionSetTag(NOT_EXIST_ID)).isNotPresent(); + assertThat(tagManagement.findDistributionSetTagById(NOT_EXIST_IDL)).isNotPresent(); + assertThat(tagManagement.findTargetTag(NOT_EXIST_ID)).isNotPresent(); + assertThat(tagManagement.findTargetTagById(NOT_EXIST_IDL)).isNotPresent(); + } + + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @ExpectEvents({ @Expect(type = DistributionSetTagUpdateEvent.class, count = 0), + @Expect(type = TargetTagUpdateEvent.class, count = 0) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() { + verifyThrownExceptionBy(() -> tagManagement.deleteDistributionSetTag(NOT_EXIST_ID), "DistributionSetTag"); + verifyThrownExceptionBy(() -> tagManagement.deleteTargetTag(NOT_EXIST_ID), "TargetTag"); + + verifyThrownExceptionBy(() -> tagManagement.updateDistributionSetTag(entityFactory.tag().update(NOT_EXIST_IDL)), + "DistributionSetTag"); + verifyThrownExceptionBy(() -> tagManagement.updateTargetTag(entityFactory.tag().update(NOT_EXIST_IDL)), + "TargetTag"); } @Test diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryManagementTest.java index ecaea960f..e2742f0d5 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetFilterQueryManagementTest.java @@ -20,11 +20,16 @@ import java.util.Iterator; import java.util.List; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; +import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent; +import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; +import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; +import org.eclipse.hawkbit.repository.test.matcher.Expect; +import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents; import org.junit.Test; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -41,6 +46,44 @@ import ru.yandex.qatools.allure.annotations.Stories; @Stories("Target Filter Query Management") public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest { + @Test + @Description("Verifies that management get access reacts as specfied on calls for non existing entities by means " + + "of Optional not present.") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) }) + public void nonExistingEntityAccessReturnsNotPresent() { + assertThat(targetFilterQueryManagement.findTargetFilterQueryById(NOT_EXIST_IDL)).isNotPresent(); + assertThat(targetFilterQueryManagement.findTargetFilterQueryByName(NOT_EXIST_ID)).isNotPresent(); + } + + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") + @ExpectEvents({ @Expect(type = DistributionSetCreatedEvent.class, count = 1), + @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() { + final DistributionSet set = testdataFactory.createDistributionSet(); + final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.createTargetFilterQuery( + entityFactory.targetFilterQuery().create().name("test filter").query("name==PendingTargets001")); + + verifyThrownExceptionBy(() -> targetFilterQueryManagement.deleteTargetFilterQuery(NOT_EXIST_IDL), + "TargetFilterQuery"); + + verifyThrownExceptionBy(() -> targetFilterQueryManagement.findTargetFilterQueryByAutoAssignDS(pageReq, + NOT_EXIST_IDL, "name==*"), "DistributionSet"); + + verifyThrownExceptionBy( + () -> targetFilterQueryManagement + .updateTargetFilterQuery(entityFactory.targetFilterQuery().update(NOT_EXIST_IDL)), + "TargetFilterQuery"); + verifyThrownExceptionBy(() -> targetFilterQueryManagement + .updateTargetFilterQueryAutoAssignDS(targetFilterQuery.getId(), NOT_EXIST_IDL), "DistributionSet"); + verifyThrownExceptionBy( + () -> targetFilterQueryManagement.updateTargetFilterQueryAutoAssignDS(1234L, set.getId()), + "TargetFilterQuery"); + verifyThrownExceptionBy(() -> targetFilterQueryManagement + .updateTargetFilterQueryAutoAssignDS(targetFilterQuery.getId(), NOT_EXIST_IDL), "DistributionSet"); + } + @Test @Description("Test creation of target filter query.") public void createTargetFilterQuery() { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java index ec4880b73..d27a34800 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java @@ -8,12 +8,7 @@ */ package org.eclipse.hawkbit.repository.jpa; -import static com.google.common.collect.Iterables.limit; -import static com.google.common.collect.Iterables.toArray; -import static com.google.common.collect.Lists.newArrayList; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; @@ -65,37 +60,73 @@ import ru.yandex.qatools.allure.annotations.Stories; public class TargetManagementTest extends AbstractJpaIntegrationTest { @Test - @Description("Ensures that an anonymous target update is not monitored by auditing.") - @WithUser(principal = "knownPrincipal", authorities = { SpPermission.READ_TARGET, SpPermission.UPDATE_TARGET, - SpPermission.CREATE_TARGET }, allSpPermissions = false) + @Description("Verifies that management get access react as specfied on calls for non existing entities by means " + + "of Optional not present.") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 0) }) + public void nonExistingEntityAccessReturnsNotPresent() { + assertThat(targetManagement.findTargetByControllerID(NOT_EXIST_ID)).isNotPresent(); + assertThat(targetManagement.findTargetById(NOT_EXIST_IDL)).isNotPresent(); + } + + @Test + @Description("Verifies that management queries react as specfied on calls for non existing entities " + + " by means of throwing EntityNotFoundException.") @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 2) }) - public void controllerAccessDoesNotChangeAuditData() throws Exception { - // create target first with "knownPrincipal" user and audit data - final String knownTargetControllerId = "target1"; - final String knownCreatedBy = "knownPrincipal"; - testdataFactory.createTarget(knownTargetControllerId); - targetManagement.updateTarget(entityFactory.target().update(knownTargetControllerId).description("updated1")); - final Target findTargetByControllerID = targetManagement.findTargetByControllerID(knownTargetControllerId) - .get(); - assertThat(findTargetByControllerID.getCreatedBy()).isEqualTo(knownCreatedBy); - assertThat(findTargetByControllerID.getCreatedAt()).isNotNull(); - assertThat(findTargetByControllerID.getLastModifiedBy()).isEqualTo(knownCreatedBy); - assertThat(findTargetByControllerID.getLastModifiedAt()).isNotNull(); + @Expect(type = TargetTagCreatedEvent.class, count = 1) }) + public void entityQueriesReferringToNotExistingEntitiesThrowsException() { + final TargetTag tag = tagManagement.createTargetTag(entityFactory.tag().create().name("A")); + final Target target = testdataFactory.createTarget(); - // make an update, audit information should not be changed, run as - // controller principal! - securityRule.runAs(WithSpringAuthorityRule.withController("controller", CONTROLLER_ROLE_ANONYMOUS), () -> { - targetManagement.updateTarget(entityFactory.target().update("target1").description("updated2")); - return null; - }); + verifyThrownExceptionBy( + () -> targetManagement.assignTag(Lists.newArrayList(target.getControllerId()), NOT_EXIST_IDL), + "TargetTag"); + verifyThrownExceptionBy(() -> targetManagement.assignTag(Lists.newArrayList(NOT_EXIST_ID), tag.getId()), + "Target"); - // verify that audit information has not changed - final Target targetVerify = targetManagement.findTargetByControllerID(knownTargetControllerId).get(); - assertThat(targetVerify.getCreatedBy()).isEqualTo(findTargetByControllerID.getCreatedBy()); - assertThat(targetVerify.getCreatedAt()).isEqualTo(findTargetByControllerID.getCreatedAt()); - assertThat(targetVerify.getLastModifiedBy()).isEqualTo(findTargetByControllerID.getLastModifiedBy()); - assertThat(targetVerify.getLastModifiedAt()).isEqualTo(findTargetByControllerID.getLastModifiedAt()); + verifyThrownExceptionBy(() -> targetManagement.countTargetByAssignedDistributionSet(NOT_EXIST_IDL), + "DistributionSet"); + verifyThrownExceptionBy(() -> targetManagement.countTargetByInstalledDistributionSet(NOT_EXIST_IDL), + "DistributionSet"); + + verifyThrownExceptionBy(() -> targetManagement.countTargetByTargetFilterQuery(NOT_EXIST_IDL), + "TargetFilterQuery"); + verifyThrownExceptionBy( + () -> targetManagement.countTargetsByTargetFilterQueryAndNonDS(NOT_EXIST_IDL, "name==*"), + "DistributionSet"); + + verifyThrownExceptionBy(() -> targetManagement.deleteTarget(NOT_EXIST_ID), "Target"); + verifyThrownExceptionBy(() -> targetManagement.deleteTargets(Lists.newArrayList(NOT_EXIST_IDL)), "Target"); + + verifyThrownExceptionBy( + () -> targetManagement.findAllTargetsByTargetFilterQueryAndNonDS(pageReq, NOT_EXIST_IDL, "name==*"), + "DistributionSet"); + verifyThrownExceptionBy( + () -> targetManagement.findAllTargetsInRolloutGroupWithoutAction(pageReq, NOT_EXIST_IDL), + "RolloutGroup"); + verifyThrownExceptionBy(() -> targetManagement.findTargetByAssignedDistributionSet(NOT_EXIST_IDL, pageReq), + "DistributionSet"); + verifyThrownExceptionBy( + () -> targetManagement.findTargetByAssignedDistributionSet(NOT_EXIST_IDL, "name==*", pageReq), + "DistributionSet"); + + verifyThrownExceptionBy(() -> targetManagement.findTargetByInstalledDistributionSet(NOT_EXIST_IDL, pageReq), + "DistributionSet"); + verifyThrownExceptionBy( + () -> targetManagement.findTargetByInstalledDistributionSet(NOT_EXIST_IDL, "name==*", pageReq), + "DistributionSet"); + + verifyThrownExceptionBy( + () -> targetManagement.toggleTagAssignment(Lists.newArrayList(target.getControllerId()), NOT_EXIST_ID), + "TargetTag"); + verifyThrownExceptionBy( + () -> targetManagement.toggleTagAssignment(Lists.newArrayList(NOT_EXIST_ID), tag.getName()), "Target"); + + verifyThrownExceptionBy(() -> targetManagement.unAssignAllTargetsByTag(NOT_EXIST_IDL), "TargetTag"); + verifyThrownExceptionBy(() -> targetManagement.unAssignTag(NOT_EXIST_ID, tag.getId()), "Target"); + verifyThrownExceptionBy(() -> targetManagement.unAssignTag(target.getControllerId(), NOT_EXIST_IDL), + "TargetTag"); + verifyThrownExceptionBy(() -> targetManagement.updateTarget(entityFactory.target().update(NOT_EXIST_ID)), + "Target"); } @Test @@ -224,7 +255,6 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest { .getControllerId()); assignTarget.add(targetManagement.createTarget(entityFactory.target().create().controllerId("targetId1236")) .getControllerId()); - assignTarget.add("NotExist"); final TargetTag targetTag = tagManagement.createTargetTag(entityFactory.tag().create().name("Tag1")); @@ -237,9 +267,6 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest { assertThat(assignedTargets.size()).as("Assigned targets are wrong") .isEqualTo(findTargetTag.getAssignedToTargets().size()); - assertThat(targetManagement.unAssignTag("NotExist", findTargetTag.getId())).as("Unassign target does not work") - .isNull(); - final Target unAssignTarget = targetManagement.unAssignTag("targetId123", findTargetTag.getId()); assertThat(unAssignTarget.getControllerId()).as("Controller id is wrong").isEqualTo("targetId123"); assertThat(tagManagement.findAllTargetTags(pageReq, unAssignTarget.getControllerId())).as("Tag size is wrong") @@ -478,7 +505,7 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest { firstList = firstList.stream() .map(t -> targetManagement.updateTarget( entityFactory.target().update(t.getControllerId()).name(t.getName().concat("\tchanged")))) - .collect(toList()); + .collect(Collectors.toList()); // verify that all entries are found _founds: for (final Target foundTarget : allFound) { @@ -507,10 +534,10 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest { targetManagement.deleteTarget(extra.getControllerId()); final int numberToDelete = 50; - final Iterable targetsToDelete = limit(firstList, numberToDelete); - final Target[] deletedTargets = toArray(targetsToDelete, Target.class); - final List targetsIdsToDelete = newArrayList(targetsToDelete.iterator()).stream().map(Target::getId) - .collect(toList()); + final Iterable targetsToDelete = Iterables.limit(firstList, numberToDelete); + final Target[] deletedTargets = Iterables.toArray(targetsToDelete, Target.class); + final List targetsIdsToDelete = Lists.newArrayList(targetsToDelete.iterator()).stream().map(Target::getId) + .collect(Collectors.toList()); targetManagement.deleteTargets(targetsIdsToDelete); @@ -723,27 +750,23 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest { final String rsqlFilter = "tag==Targ-A-Tag,id==target-id-B-00001,id==target-id-B-00008"; final TargetTag targTagA = tagManagement.createTargetTag(entityFactory.tag().create().name("Targ-A-Tag")); final List targAs = testdataFactory.createTargets(25, "target-id-A", "first description").stream() - .map(Target::getControllerId).collect(toList()); + .map(Target::getControllerId).collect(Collectors.toList()); targetManagement.toggleTagAssignment(targAs, targTagA.getName()); testdataFactory.createTargets(25, "target-id-B", "first description"); - final Page foundTargets = targetManagement.findTargetsAll(rsqlFilter, new PageRequest(0, 100)); + final Page foundTargets = targetManagement.findTargetsAll(rsqlFilter, pageReq); - assertThat(targetManagement.findTargetsAll(new PageRequest(0, 100)).getNumberOfElements()).as("Total targets") - .isEqualTo(50); + assertThat(targetManagement.countTargetsAll()).as("Total targets").isEqualTo(50L); assertThat(foundTargets.getTotalElements()).as("Targets in RSQL filter").isEqualTo(27L); - } @Test @Description("Verify that the find all targets by ids method contains the entities that we are looking for") @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 12) }) public void verifyFindTargetAllById() { - final List searchIds = new ArrayList<>(); - searchIds.add(testdataFactory.createTarget("target-4").getId()); - searchIds.add(testdataFactory.createTarget("target-5").getId()); - searchIds.add(testdataFactory.createTarget("target-6").getId()); + final List searchIds = Lists.newArrayList(testdataFactory.createTarget("target-4").getId(), + testdataFactory.createTarget("target-5").getId(), testdataFactory.createTarget("target-6").getId()); for (int i = 0; i < 9; i++) { testdataFactory.createTarget("test" + i); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/event/RepositoryEntityEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/event/RepositoryEntityEventTest.java index a975322a2..365077463 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/event/RepositoryEntityEventTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/event/RepositoryEntityEventTest.java @@ -104,7 +104,7 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest { final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName); testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName); - final Rollout createdRollout = createRolloutByVariables(rolloutName, "desc", amountGroups, + final Rollout createdRollout = testdataFactory.createRolloutByVariables(rolloutName, "desc", amountGroups, "controllerId==" + targetPrefixName + "-*", distributionSet, successCondition, errorCondition); rolloutManagement.deleteRollout(createdRollout.getId()); diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java index 768e5fd32..3fc3d0a06 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java @@ -43,12 +43,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.MetaData; -import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; -import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; -import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; -import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetWithActionType; @@ -273,24 +267,6 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware { entityFactory.actionStatus().create(savedAction.getId()).status(Action.Status.FINISHED)); } - protected Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, - final int groupSize, final String filterQuery, final DistributionSet distributionSet, - final String successCondition, final String errorCondition) { - final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults() - .successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition) - .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) - .errorAction(RolloutGroupErrorAction.PAUSE, null).build(); - - final Rollout rollout = rolloutManagement.createRollout(entityFactory.rollout().create().name(rolloutName) - .description(rolloutDescription).targetFilterQuery(filterQuery).set(distributionSet), groupSize, - conditions); - - // Run here, because Scheduler is disabled during tests - rolloutManagement.handleRollouts(); - - return rolloutManagement.findRolloutById(rollout.getId()).get(); - } - @Before public void before() throws Exception { mvc = createMvcWebAppContext().build(); diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java index 8a9ae8d0e..7adcaa133 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java @@ -28,6 +28,7 @@ import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.RolloutManagement; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.TagManagement; import org.eclipse.hawkbit.repository.TargetManagement; @@ -42,6 +43,12 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.NamedEntity; import org.eclipse.hawkbit.repository.model.NamedVersionedEntity; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; +import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.Target; @@ -127,6 +134,9 @@ public class TestdataFactory { @Autowired private ArtifactManagement artifactManagement; + @Autowired + private RolloutManagement rolloutManagement; + /** * Creates {@link DistributionSet} in repository including three * {@link SoftwareModule}s of types {@link #SM_TYPE_OS}, {@link #SM_TYPE_RT} @@ -902,4 +912,56 @@ public class TestdataFactory { } return result; } + + /** + * Creates rollout based on given parameters. + * + * @param rolloutName + * of the {@link Rollout} + * @param rolloutDescription + * of the {@link Rollout} + * @param groupSize + * of the {@link Rollout} + * @param filterQuery + * to identify the {@link Target}s + * @param distributionSet + * to assign + * @param successCondition + * to switch to next group + * @param errorCondition + * to switch to next group + * @return created {@link Rollout} + */ + public Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, + final int groupSize, final String filterQuery, final DistributionSet distributionSet, + final String successCondition, final String errorCondition) { + final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults() + .successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition) + .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) + .errorAction(RolloutGroupErrorAction.PAUSE, null).build(); + + final Rollout rollout = rolloutManagement.createRollout(entityFactory.rollout().create().name(rolloutName) + .description(rolloutDescription).targetFilterQuery(filterQuery).set(distributionSet), groupSize, + conditions); + + // Run here, because Scheduler is disabled during tests + rolloutManagement.handleRollouts(); + + return rolloutManagement.findRolloutById(rollout.getId()).get(); + } + + /** + * Create {@link Rollout} with a new {@link DistributionSet} and + * {@link Target}s. + * + * @param prefix + * for rollouts name, description, + * {@link Target#getControllerId()} filter + * @return created {@link Rollout} + */ + public Rollout createRollout(final String prefix) { + createTargets(10, prefix); + return createRolloutByVariables(prefix, prefix + " description", 10, "controllerId==" + prefix + "*", + createDistributionSet(prefix), "50", "5"); + } } diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/common.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/common.scss index db74d112b..34a990f4b 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/common.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/common.scss @@ -144,9 +144,9 @@ .valo-menu-item-selected { border: 0 solid white; border-bottom: 5px solid transparent; - border-image: url("../images/lightCorner_top.png") 30 30 stretch; - o-border-image: url("../images/lightCorner_top.png") 30 30 stretch; - webkit-border-image: url("../images/lightCorner_top.png") 30 30 stretch; + border-image: url("images/lightCorner_top.png") 30 30 stretch; + o-border-image: url("images/lightCorner_top.png") 30 30 stretch; + webkit-border-image: url("images/lightCorner_top.png") 30 30 stretch; } .v-csslayout-valo-menu-item { border: 0 solid white; diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/images/lightCorner_selected1.png b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/images/lightCorner_selected1.png deleted file mode 100644 index 4568892e57a66f3632a205f2015e64b565d07ba0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9331 zcmV-(B#hgMP)*XO@NueK@w#BbW3V!x*|HNibb-zNaEwk zlL>(S@t2S8?eS$E|M32i^7FsWu{{6FdFH=AP4t!i9si9U#`LxSfqdSUbLsx+!zX^b zs<#h%gUXjX)}IR?|C3U;-#>VN@q2z|rf=~e{z$}E91n(L@mU*w2F&vG1{ZitZ-?Mz z9t$x1=LE&*q3~FqJ4h_A54U^T0m^%#uMV0IeEiSr|Nd|Qmxum$@HOxm99zEfyyx$t z3*bp_PiANfMj@#z;Ou}R#l8Zfsil*cFD zuJ?XlWYHzyWYse|2MQevoaJ0T3o_q3Xx^X#k8Gr>iTXJpGEyH$@KA7E0)~Ao-{LPp z;^UwhEUMrTGMff}19SpipFP#{VTU;yVp-q}U_&qA;~;4M zZVLRZ8o_Ty?F*@rJ%}8IFA9+(FT=uPq%igxxP`GGb$H<0Xj>&Pe+hC z^LYCa%tqiD0cWIe_Pm@7n3oEdzIF97y}{%@m|PRiTv8#ZKt{?VD-Ki(83?K{MydjV zF)g3R0eo1NO=kOGRvp3Th$uwc6!o%zBVU&pvCVe_gJu6S>?`M75JcYXLWeAT^tj-6 zM1f6yt-#3&$HHc$YBYR81%rUux#93F*XOqcmtPfBo*UlmrEW*zj8!2=Axu^u-Zb*u zsG|W0f+K%s8!|%!%CG$Z61qY%bt;!sNTAzQ3SSXIncv(&!z!4(F9cOS)D;W{I%$yg z$!f>UifrHC!=yWM;x+Pq?Cro;cbu!dh(YG#E(LnJvFkY zM63!y1%d#{yURexnVV?<15_IcfTFixT~F@tWFdi2$jf;f?s$IynfP2EWuzt`j3KiQ z0xB=pQbL6fNfaf=lWmx^tY3kn`;`{SxE}<~iTV)gqk&8`pvjQI8;T8=(EQD62H|3^ zy}RmUUPGAly($%g1AaG5_Dt42gB8_?RU#wvw1yoSFoH}IKZe-$bNWuvf|%{qH(<~&$t0kfxK zMhZqlq?b@IIXu$WUph?sE|ki1GB*knENwpuZLGnnFd3;4^g?tQNkhzPM3qQzThByQ zNN(f^kOvyWgHf5twh_Rg%7sCJzaM;F zR7eousJcPWjFbu)Se*ef2_SQ#?J+_n5faKD#euD~z zHTn6u^(5E8BtW~l6xy5*K%yZ{-o@GYA<}@W2LfOqgh>7i4GLx12p+nR5jX%C2!#qd z*cRIHSiuaG2<@mDz9162XpMej!lIgia3(P-6Zy=8vKfIU?*sOy(9X?1Unpda zT?-ghEOP#-fQYJUB|lIw*8nENC10Z$B3)_hk_FzE3XQ%wsJs+R@L^#Bs>BV9JHqe= zVR8*fRE=o%M$|+7rUx)tGc@!{4(n_DjI1(I2oSs;fTO%-*q)3sA^6OIZckoVEl&fP z!-LQU^Sx45Jlq+WR`PKl}tWIIXtS$M<9bLM#Cf; zcrmqphE}*pc(gHj6)@_-Sh)NF+$~iu_jDKd5@7k(pz|YRV^c{;B%&=Up-Ww8}3|FTXG2|SjD>Ql`I#Vs*({%#0NOT?A-05gMmJvWFHvv-0_ zQOv(fU}XIlO;hJ>v5!9jNd}{7`eGU@nip?maiEKnenLZze12g4(8 zWeJ2)9`@tiw(d{aHIt}OgN<6L0O6)u@cRNlD0%rV6B<>f$#2M@ z@ka_qj>_tD(W+i@c$9$wepd$<>$@OaG&CB3g`d_GbOnosL#kNr35Rlx%kuZ)X72Po z0_7IpWCRrPN@x_~)P}tR(dQx(D=YU`B7ZXi?l;hK7p zh^BfkiCT!HfUWSFn*rRZ7j>I`1K3*WyPl+raCsC^*^JQ$Ea#JdzOUFB0$=z7Yqg2w0+GUc~vf{{a+<( zB*uQ{xhP!n`9KuN|h zRiNZ$n$_W6O^`qW-&?o@@tZ-z7;1nS8Ia^Y<2CC5qo7*AJoJq5xCX zas(E*WT)D$=C-r^;X{kK*cW^Qd)!yMN2r!)4fr$sN1r>`b zmGXK37_E27+XM>{+A0)}o(lj7Yh4`pDHIbwEISSFC%@2+@*P^0K|UEYFHrdunSMIQ z$3Om(PQQB$=XaCOx5qQBiX|}s#Dqc&DkTA2JfxGO>pEdK@M!&tZxHd^jMok>uw7RO zcmXcx!&KE0ASB`yARc~832`%U;;LxCB?S8EDNg^l{N;5Qu;j35c1@)u*#^zn$PFg5g^YwO1X&^V zN7y%yB*O7ga~DGzghZ!Q;B^9!d4-9@RxF`u5|~s2EJ8RW2j1TU7Hi;Q+Idg0h}Uv8 zSpIGb&rU5*-?~D%Hp4SeDDJ#t1fwBa4ifc42P6TFQs6m2QSZbm3HE$43vYmEbfGca*|O1ixM%|qa6p-_&7f@i+~=j?hD zmcb;h=B~hJ60j&#A`jGznBz%)E5kpp>ys!KtOl;xC5H69!h>2iY6BJ-BuWbxlbi%f z4Kge}$Qim=Bn_!^y~`!AcRVst9+y>5VmD3*uLi6F zKyGadOlVn;m%9m(=<&S$a#8VeArYFET?pbO6I4>HRG{R$&q=@_mAS4DO+tdOhd^;i zaaKq@3=jm}a%u4WvMo$BB^>mxq{`W8=_T1eP%;6kcvoO?t`lK_2G#6Neh!o8c{z|X z^Sls98$3b7W&le5%UAl@$sZYmR}_tgI!q>IEv9XRWpS49N+HBe<&*{=w_Z{L132lm zQ9YG)%$6iwHA=;;yl2Sw?|L~088>1`(pC)P> zhwPDj#?tONflZR2$Sy*q?wXcnQAg`JjkJ!5n=hDk9j@ILk`&Q-YU${1{F~)sD9g{S zLuaY(U4DGNIq@uQBp;MX`yXlORMu;4=+DcpPRg*f->1+3=c-BBUK%R&%=Nn;ZJ~kk z4`ccK`~x)=l1#_8)C#C;7DKB;qvs(@{`@3~hTOg6v}PHy)UR4b%VDvj?T`#ru&IliA;4>SaW(8jbie{st1&S&h4;d`hVH0R= zkcLEGh*gbG0liuVfEBt5m+?r$VhGg2aPZQwZ$q;C9ET9pT?j;H1QgM=LUJS+z& z$DIubYXhc{>d4`TR;~hrc&vhjng`+mHlfSdPy-LHC#u1tM}ncw zDx&mzc@jG(?;|(-$7SUQUtm(+KPW)_dX6hJ$}*w{1W5ke_h9kTdz#jozg3NSD3l`! z+cfRHE+cX#4VxQfl!jM^5LhBe0Za~yO5;myXaP=bTjo}En}P5ta_JiLX(7NTX*V-K zXO{aPI?D~*om1N$ffCm`wE~A3d>PG5;j{C->QeQQs+ys;uBfEwb)O_kM$`wd z-bz(4VGX?sV5WZXsp8d~)*n;53S{tn;s%|tDxCDx0Fu2z{%JYnp{kleG$4y|JAH3_ z8&xsV?srwpW;jXh6?~ND{e2yiwWrsgQWwwVaG^HjPh3nUvZJ!6*5i|;L9Qk!w;B-* zNqp;=SMK;}T{p+=1SRTvr`IxZuUQE(JSQypGL1M87@)Gx;K4lQwvL7r9=A7!Cy6pB zo`e8u5`ZaWg6p>;W;uRzU&J3I&;1RG!zxrUU>+wEMmYm2EyzPPmf(Ho_h1H#n)id9F6;Jb zfrDR7+3xe0q0!9R`aYD-ikw=5%GB=R<*vCl z^n5(mefs<{F;Pvc76Z1Z0968$coC~lR?1IAIj|0hrmsDOBoitU0iOB}eq@BY29}Ae z5lR3Z0Ewsv4=G*=9Z z@P=yTVklhic2pGz+}gN4uPrcx1crDd9V)V@8>SU3NkSWeNbI3P8upw8CaYqh)r$e3 zSnxy%ixNNr0K&=E%Wx~&W9!}MKIHq+=P7?##YhNL!!ByDQR8^#zGrp$ZN+~fLeRw8 zMPOMDy}v`0_42Zls6=V_IzCL&@L%UnI>QKfzghmz$K^a^xMT(_GLIKA0mXNX0htqj z8D8Ug`8G?b|d#I4}KFbF*reSZdp^9hzk@mmt?536>gQ5F#t zMTDA{S)+6YpT@Tu8&0rq?c|t1!3Y$pTJfuAqx)c^T8dH$4It`n#K+&}eKXcnAsJ9`5{Yh;=^JLuSb!k{h6qpRyRx>~_E{Uh!E9rU{V}TmA zdXWGVnKD?%vqg<28x1kx5jDedoHf}G|Gn@Bk7|6<+vS_-< z)FTBVPY%pkz6_EjjNxIsjp?&xe{NARckSapmQ$R=DGZ}NR2LiOU7=C`bMk2<9lc+Y^v&k z;SmCK0|*dyd6P++jHwLuEh}7j{hLbFcYaMBP>Mk=srm46PN(;ikDdrdi(?I667?Ao zfkobwA-tfZ?_~su2#prkix^%|rzm)7tQ1Y5n|@C%gj?$lSyTljB&n3;seyw7D35n=;|!uiV(S}J0FhNlUjN;8V*0F9%3YvAqP_kzi(n)0PJRjwh3 zR?9Be6hEw$vK&is+uGP?DRh%0MpZqlr%}vNoix5y(dG(TJK_+Q>HjGe&yuewa(hvM z@R~am@-@YEcyKaca(S~Imsa~ld??N}_5CK~R(z7a6|31*`c{;aD>8(oY95Di9J^yQ)crRz)NLDk5zG6;NVGQ10;z~c#`m>l<}vK#di z!thD5LIL|FVcPt+Cx80ykMrYCAKCrx-86e@^%~F#uxseGjDBs9&h_J^;9%FujP}Nm zqOHcI8F~_{VzKho4&YRQ;?1}#b{ibFQm)3j-$Zq^eN`7&H^M=tU-fH6Vky&qTpIZ- zaw*4;S_Jn_8vj|U?KJGqs$&u4Z2S7`&2)&f9Of*|t>dX=vvpK|_Ps#m=0`q&87%pL zX0ZGSeINAT=iZ#y$?&vJ3dPuS87Gd?i!~7Y1Daq#K2#W^3wr)47p)-=-Uj7Qr%kI{o2sn*Qs< z`SFiGpWW}@h52#vSleND$u*0f7a> z8ldr7VMToh#X7WQFxyXJ{6N|~)%lxgg$#_qU%U`D)2Jd$)MQ1V9Kj@C_fL|Pxp%Vn z=K|%`LnTx5))C;2z@jI^f<@tytD_Vwsg+I_WfG{CUXv&khH+MsEN2`Rfu-~{VTUt- z3y#47Q$~=5i-RuqZU7iEW6`?pa0$+YVs=obfT?0O!zbXV`9{@D4}qq?{_)}C|14nn z&tGQ0yyqWJK0O3~UN)SG)I*_J%*&+HT5vxJ7|vE$OZG2~O>2~eGb#qx*SUHUf?xm^ zH~22y_h^10RVn(v+Bu$6Xk%d}F|$^+asU*C2~6#AQJvfn+6;m6LZ0aNrBp^>k@sae zs+JFsW>>%{Se%Sop{nJ~ZDRExy-roN09>?)tAIw~qBURIVGNZ^=rc&{oA->2r*71JqiWW!0t;mS@`uyMk8=wD_bE<)`n39} zr9Z%Oz!vp#K6y8X%u(v9M;&iRd2?o}4(9QgwYAR+q;NYBfCAF+W)~z3^Z)q1Pmgos zLABY!L_-}9>*8eZ2$RrHf>gny3gudLqM^>cFu^*rml&Yw)k8&oAm1|qyB^?6;ShQ) zcrp<#3XhR$0dM6hxVV1sB8Q#wE~pnAb!-Cw-%lc@N(BdWu30KOKCL&MF5O@Xj|3eD zam<(0YGV8XkMORYs+vxQl5ECK#d38NUSwn69AKwrY>Z_8_YuKniCs1Dc@l7a|Jpb!GVA%_YtZLcwS`;pi zI1HJAi)I7jHY`$w;@C_W#{FEs)aLQ-#}kpd1}v;gI8&i(Bi)l5%YRVe=MrjCDGb=EfeGP3qbRKkO9%WP^usj*)RM0r{hw1_+W=}?q zAiV4{-z%XyQob92BtqzdFv-`@2qt@>&glBZsZU2Rc`2a0fUPl%OEG(c|Reto@+^OukOrDKaSS%qp11)0aATFt74x(lFRB zw)D-U?&h!rJGQOK*rETCjQPoEgxh7QfsAP|dtvHlC1hjxcHzpYJDbnX=DjMD5lp^BxbxCJ$~Wz)++*I3!Xa3`@mnGcaAU(FRU!(QqtHm;QpX{6 zZERHMjDmRrz@*jS)dCD2K}TBWA!xXV0~)c;sFFIQL259>Aq={G0buIz>pTDtLBAin z%$a3)u97isG3)^U!(r&;3@F^zFx@~T7>F>yik+0bQ=KrZE1BmN91bRA&t|=o^Iv4! zS^ShBO69aOXEK81b7giuN9y>yQ7WHHy{LlOQ!aYaM^mKQX+9u?>XxB`!Gb!gV)Qed zgL#4mFJ^Do9fA7F-fmDUnB#c(IUNk1MLQF+Oc=why@MqH-h5Od6AFQh(g1t+Gneh=Y~3;ONIPuvOn2#u?^yy*$q*>z{z8Tiz=6g zwcGd5)K&G8;i5%!a&akKYJ>3t5GnldpnR%|(Sf#MT$oPDNZ$iOlT}SW3mXRYg6kVd zc%u}$W9N5ZGVogV9vJFaU&N)s#Sfk6&@^?>?*)~IQ_m$JAOIk|^=Jw}G&7?RA^7gu zs1fx@P>m==5H6Qg$+a-KC)D|xF!`QS%C@88)uEBe7HvEiG<8SmXf2}CtPxh}8Wp3{ zTt)@VK*cZ=*~!4$b)-7I1Cmr<)=(z8I*~Eikj4TB6iyrg#qS?O+FM}5pG%P0d5@Ev zZ@{9U2mlYOL`?Y90R+RDPKj&{V(lPU!y35>xFd*Y7H3prqSw)bvF%WmJi+yKOQ`cX zLz-VZRO$iF&(A5IL(gTDF&Y5|)eD9>+BmeIkoqtR7^`9&D47}pQR^V-K+#y(JaIoy z5w*rg16V|>Ou~2wgTvzpogXbN(h*S*4)%dc!^~#Jb8qCgUBVH#43{KWOP)i4~B4kgUU-jAU#%<%e51}8|Biq2kX1+0mecG z+lqQI@5GBSN`}FYi5POkHkF>=_!?S}2e1*SZMK=spjm?!B7hgR)vUzFb6?0g2=5t$&SVs!Z#IwabVX%9BgXj(7n*4bqU9o)C==$=Mn3Ad?GUi{$= z2ow|}Fpbm(?k8;lm8?&r-vMfJ7|!I^=!+!q$36^3J{yHLnz_*lz3vTdMqbHlQ6`(4 z!uOEGk#OnNO`Mi<9m zmc-EjI3;w_3(_i?y^u+2DmvIu|G7VC@ND1{2aR?Jh;=wMmeltafOKQEP}+q_9!Q9W z6g~ox9aGgRj;0uybsQ2@WuO@KeF4YF>KvJ?Bh_j{o9EP&yf&}o4Jyw#iMM(%M;8yO z8ckWlh3YSbOc(r_jZb5tgDS_SZVgDbcknV0FMakqq&C*`K&c=EEG)3}z4JQ^INtBj zZxq5DDG&{1jOx7Udbr{G`(__+P`Tj2+*7@Kg{qO-limWbO2)#*hEE1Mn+Ef~Ok>h# zSN7D70ti$9r7v9XfL;cMBO}1rFa`aNYr*lb1DjFkVgd33CGzQeZ8&dGdH%`2Nzq(T zHB~W;Mz1^cHwH5pj2hJYgO~*&628*$PCYaZAJ-_2y?PKEu8iREQayiPLqXabR9?yB zN^`6f9OcQ^URc%eK`1r!Yi#2gnZ@zOi~H%oaDL$si0|0uA}}m8GB7MGuomg1AFrh# z?F}m5E`Sa%o_qT!T`9S{&wfwzA~5)o=v!$J>EO71HD&v)nXGS6`TjzwVR&`t*YVpC he>+BB