Enable sorting in tables (#1279)

* provided infrastructure to enable sorting in grids
* Fixed sorting in RolloutGroupTarget
* fixed sorting with pinning and assigned SoftwareModules
* Added sorting for columns createdBy, createdAt, lastModifiedBy and lastModifiedAt
* Adapted status columns to be sortable
* fixed unit tests
* fixing sonar findings
* making Sonar happy
* added testcases for management classes regarding sorting
* added testcases for management classes regarding sorting
* using name for element ids in DOM
* incorporated code review remarks

Signed-off-by: Markus Block <markus.block@bosch-si.com>
This commit is contained in:
Markus Block
2022-09-30 09:54:17 +02:00
committed by GitHub
parent 3d3481110e
commit 60e33afca4
23 changed files with 593 additions and 154 deletions

View File

@@ -374,14 +374,14 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Override
public Slice<DistributionSet> findByDistributionSetFilterOrderByLinkedTarget(final Pageable pageable,
final DistributionSetFilter distributionSetFilter, final String assignedOrInstalled) {
final List<Specification<JpaDistributionSet>> specList = buildDistributionSetSpecifications(
distributionSetFilter);
specList.add(DistributionSetSpecification.orderedByLinkedTarget(assignedOrInstalled));
// remove default sort from pageable to not overwrite sorted spec
final OffsetBasedPageRequest unsortedPage = new OffsetBasedPageRequest(pageable.getOffset(),
pageable.getPageSize(), Sort.unsorted());
final List<Specification<JpaDistributionSet>> specList = buildDistributionSetSpecifications(
distributionSetFilter);
specList.add(DistributionSetSpecification.orderedByLinkedTarget(assignedOrInstalled, pageable.getSort()));
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetRepository, unsortedPage, specList);
}

View File

@@ -21,6 +21,7 @@ import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;
import org.eclipse.hawkbit.repository.RolloutGroupFields;
@@ -51,7 +52,9 @@ import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@@ -259,7 +262,8 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
final CriteriaQuery<Object[]> multiselect = query.multiselect(targetJoin, actionJoin.get(JpaAction_.status))
.where(cb.equal(targetRoot.get(RolloutTargetGroup_.rolloutGroup).get(JpaRolloutGroup_.id),
rolloutGroupId));
rolloutGroupId))
.orderBy(getOrderBy(pageRequest, cb, targetJoin, actionJoin));
final List<TargetWithActionStatus> targetWithActionStatus = entityManager.createQuery(multiselect)
.setFirstResult((int) pageRequest.getOffset()).setMaxResults(pageRequest.getPageSize()).getResultList()
.stream().map(o -> new TargetWithActionStatus((Target) o[0], (Action.Status) o[1]))
@@ -268,6 +272,25 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
return new PageImpl<>(targetWithActionStatus, pageRequest, totalCount);
}
private List<Order> getOrderBy(final Pageable pageRequest, final CriteriaBuilder cb,
final Join<RolloutTargetGroup, JpaTarget> targetJoin,
final ListJoin<RolloutTargetGroup, JpaAction> actionJoin) {
return pageRequest.getSort().get().flatMap(order -> {
final List<Order> orders;
final String property = order.getProperty();
// we consider status as property from JpaAction ...
if ("status".equals(property)) {
orders = QueryUtils.toOrders(Sort.by(order.getDirection(), property), actionJoin, cb);
}
// ... and every other property from JpaTarget
else {
orders = QueryUtils.toOrders(Sort.by(order.getDirection(), property), targetJoin, cb);
}
return orders.stream();
}).collect(Collectors.toList());
}
@Override
public long countTargetsOfRolloutsGroup(final long rolloutGroupId) {
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);

View File

@@ -47,6 +47,7 @@ import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_;
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
@@ -75,6 +76,8 @@ import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.integration.support.locks.LockRegistry;
import org.springframework.orm.jpa.vendor.Database;
@@ -162,7 +165,8 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override
public Page<Rollout> findAll(final Pageable pageable, final boolean deleted) {
return JpaManagementHelper.findAllWithCountBySpec(rolloutRepository, pageable,
Collections.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted)));
Collections
.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort())));
}
@Override
@@ -170,7 +174,7 @@ public class JpaRolloutManagement implements RolloutManagement {
final List<Specification<JpaRollout>> specList = Lists.newArrayListWithExpectedSize(2);
specList.add(
RSQLUtility.buildRsqlSpecification(rsqlParam, RolloutFields.class, virtualPropertyReplacer, database));
specList.add(RolloutSpecification.isDeletedWithDistributionSet(deleted));
specList.add(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort()));
return JpaManagementHelper.findAllWithCountBySpec(rolloutRepository, pageable, specList);
}
@@ -298,7 +302,7 @@ public class JpaRolloutManagement implements RolloutManagement {
/**
* In case the given group is missing conditions or actions, they will be
* set from the supplied default conditions.
*
*
* @param create
* group to check
* @param conditions
@@ -481,7 +485,8 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override
public long count() {
return rolloutRepository.count(RolloutSpecification.isDeletedWithDistributionSet(false));
return rolloutRepository.count(
RolloutSpecification.isDeletedWithDistributionSet(false, Sort.by(Direction.DESC, JpaRollout_.ID)));
}
@Override
@@ -553,7 +558,8 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override
public Slice<Rollout> findAllWithDetailedStatus(final Pageable pageable, final boolean deleted) {
final Slice<Rollout> rollouts = JpaManagementHelper.findAllWithoutCountBySpec(rolloutRepository, pageable,
Collections.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted)));
Collections
.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort())));
setRolloutStatusDetails(rollouts);
return rollouts;
}

View File

@@ -27,6 +27,7 @@ import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
@@ -73,7 +74,9 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
@@ -308,6 +311,10 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
}
@Override
// In the interface org.springframework.data.domain.Pageable.getSort the
// return value is not guaranteed to be non-null, therefore a null check is
// necessary otherwise we rely on the implementation but this could change.
@SuppressWarnings({ "squid:S2583", "squid:S2589" })
public Slice<AssignedSoftwareModule> findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(
final Pageable pageable, final long dsId, final String searchText, final Long smTypeId) {
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
@@ -331,8 +338,16 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
query.groupBy(smRoot);
query.orderBy(cb.desc(assignedCaseMax), cb.asc(smRoot.get(JpaSoftwareModule_.name)),
cb.asc(smRoot.get(JpaSoftwareModule_.version)));
final Sort sort = pageable.getSort();
final List<Order> orders = new ArrayList<>();
orders.add(cb.desc(assignedCaseMax));
if (sort == null || sort.isEmpty()) {
orders.add(cb.asc(smRoot.get(JpaSoftwareModule_.name)));
orders.add(cb.asc(smRoot.get(JpaSoftwareModule_.version)));
} else {
orders.addAll(QueryUtils.toOrders(sort, smRoot, cb));
}
query.orderBy(orders);
final int pageSize = pageable.getPageSize();
final List<Tuple> smWithAssignedFlagList = entityManager.createQuery(query)
@@ -486,7 +501,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
/**
* Asserts the meta data quota for the software module with the given ID.
*
*
* @param moduleId
* The software module ID.
* @param requested

View File

@@ -638,7 +638,7 @@ public class JpaTargetManagement implements TargetManagement {
pageable.getPageSize(), Sort.unsorted());
final List<Specification<JpaTarget>> specList = buildSpecificationList(filterParams);
specList.add(TargetSpecifications.orderedByLinkedDistributionSet(orderByDistributionId));
specList.add(TargetSpecifications.orderedByLinkedDistributionSet(orderByDistributionId, pageable.getSort()));
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, unsortedPage, specList);
}

View File

@@ -16,6 +16,7 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
@@ -29,7 +30,9 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.util.CollectionUtils;
/**
@@ -265,7 +268,8 @@ public final class DistributionSetSpecification {
* Can be added to specification chain to order result by provided target
*
* Order: 1. Distribution set installed on target, 2. Distribution set(s)
* assigned to target, 3. Based on distribution set id
* assigned to target, 3. Based on requested sorting or id if
* <code>null</code>.
*
* NOTE: Other specs, pagables and sort objects may alter the queries
* orderBy entry too, possibly invalidating the applied order, keep in mind
@@ -273,16 +277,26 @@ public final class DistributionSetSpecification {
*
* @param linkedControllerId
* controller id to get installed/assigned DS for
* @param sort
* @return specification that applies order by target, may be overwritten
*/
public static Specification<JpaDistributionSet> orderedByLinkedTarget(final String linkedControllerId) {
public static Specification<JpaDistributionSet> orderedByLinkedTarget(final String linkedControllerId,
final Sort sort) {
return (dsRoot, query, cb) -> {
final Root<JpaTarget> targetRoot = query.from(JpaTarget.class);
final Expression<Object> assignedInstalledCase = cb.selectCase()
.when(cb.equal(targetRoot.get(JpaTarget_.installedDistributionSet), dsRoot), 1)
.when(cb.equal(targetRoot.get(JpaTarget_.assignedDistributionSet), dsRoot), 2).otherwise(3);
query.orderBy(cb.asc(assignedInstalledCase), cb.asc(dsRoot.get(JpaDistributionSet_.id)));
final List<Order> orders = new ArrayList<>();
orders.add(cb.asc(assignedInstalledCase));
if (sort == null || sort.isEmpty()) {
orders.add(cb.asc(dsRoot.get(JpaDistributionSet_.id)));
} else {
orders.addAll(QueryUtils.toOrders(sort, dsRoot, cb));
}
query.orderBy(orders);
return cb.equal(targetRoot.get(JpaTarget_.controllerId), linkedControllerId);
};

View File

@@ -13,7 +13,9 @@ import javax.persistence.criteria.Predicate;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.query.QueryUtils;
/**
* Specifications class for {@link Rollout}s. The class provides Spring Data
@@ -29,17 +31,18 @@ public final class RolloutSpecification {
* {@link Specification} for retrieving {@link Rollout}s by its DELETED
* attribute. Includes fetch for stuff that is required for {@link Rollout}
* queries.
*
*
* @param isDeleted
* TRUE/FALSE are compared to the attribute DELETED. If NULL the
* attribute is ignored
* @return the {@link Rollout} {@link Specification}
*/
public static Specification<JpaRollout> isDeletedWithDistributionSet(final Boolean isDeleted) {
public static Specification<JpaRollout> isDeletedWithDistributionSet(final Boolean isDeleted, final Sort sort) {
return (root, query, cb) -> {
final Predicate predicate = cb.equal(root.<Boolean> get(JpaRollout_.deleted), isDeleted);
root.fetch(JpaRollout_.distributionSet);
query.orderBy(QueryUtils.toOrders(sort, root, cb));
return predicate;
};
@@ -47,14 +50,14 @@ public final class RolloutSpecification {
/**
* Builds a {@link Specification} to search a rollout by name.
*
*
* @param searchText
* search string
* @param isDeleted
* <code>true</code> if deleted rollouts should be included in
* the search. Otherwise <code>false</code>
* @return criteria specification with a query for name of a rollout
*
*
*/
public static Specification<JpaRollout> likeName(final String searchText, final boolean isDeleted) {
return (rolloutRoot, query, criteriaBuilder) -> {

View File

@@ -18,6 +18,7 @@ import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.MapJoin;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
@@ -47,7 +48,9 @@ import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.query.QueryUtils;
/**
* Specifications class for {@link Target}s. The class provides Spring Data JPQL
@@ -571,7 +574,7 @@ public final class TargetSpecifications {
* distribution set
*
* Order: 1. Targets with DS installed, 2. Targets with DS assigned, 3.
* Based on target id
* Based on requested sorting or id if <code>null</code>.
*
* NOTE: Other specs, pagables and sort objects may alter the queries
* orderBy entry too, possibly invalidating the applied order, keep in mind
@@ -579,9 +582,12 @@ public final class TargetSpecifications {
*
* @param distributionSetIdForOrder
* distribution set to consider
* @param sort
* the sorting requested
* @return specification that applies order by ds, may be overwritten
*/
public static Specification<JpaTarget> orderedByLinkedDistributionSet(final long distributionSetIdForOrder) {
public static Specification<JpaTarget> orderedByLinkedDistributionSet(final long distributionSetIdForOrder,
final Sort sort) {
return (targetRoot, query, cb) -> {
// Enhance query with custom select based sort
final Expression<Object> selectCase = cb.selectCase()
@@ -590,7 +596,14 @@ public final class TargetSpecifications {
.when(cb.equal(targetRoot.get(JpaTarget_.assignedDistributionSet).get(JpaDistributionSet_.id),
distributionSetIdForOrder), 2)
.otherwise(100);
query.orderBy(cb.asc(selectCase), cb.desc(targetRoot.get(JpaTarget_.id)));
final List<Order> orders = new ArrayList<>();
orders.add(cb.asc(selectCase));
if (sort == null || sort.isEmpty()) {
orders.add(cb.desc(targetRoot.get(JpaTarget_.id)));
} else {
orders.addAll(QueryUtils.toOrders(sort, targetRoot, cb));
}
query.orderBy(orders);
// Spec only provides order, so no further filtering
return query.getRestriction();

View File

@@ -63,6 +63,8 @@ import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -627,7 +629,7 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
final Iterator<DistributionSet> dsIterator = buildDistributionSets.iterator();
final Iterator<Target> tIterator = buildTargetFixtures.iterator();
dsIterator.next();
final DistributionSet dsFirst = dsIterator.next();
final DistributionSet dsSecond = dsIterator.next();
final DistributionSet dsThree = dsIterator.next();
final DistributionSet dsFour = dsIterator.next();
@@ -650,17 +652,50 @@ class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
final List<DistributionSet> tFirstPin = distributionSetManagement
.findByDistributionSetFilterOrderByLinkedTarget(PAGE, distributionSetFilter, tFirst.getControllerId())
.getContent();
assertThat(tFirstPin.get(0)).isEqualTo(dsThree);
assertThat(tFirstPin).hasSize(10);
// assigned
assertThat(tFirstPin.get(0)).isEqualTo(dsThree);
// remaining id:ASC
assertThat(tFirstPin.get(1)).isEqualTo(dsFirst);
assertThat(tFirstPin.get(2)).isEqualTo(dsSecond);
assertThat(tFirstPin.get(3)).isEqualTo(dsFour);
// target second has installed DS-2 and assigned DS-4 so check order
// correct
final List<DistributionSet> tSecondPin = distributionSetManagement
.findByDistributionSetFilterOrderByLinkedTarget(PAGE, distributionSetFilter, tSecond.getControllerId())
.getContent();
assertThat(tSecondPin).hasSize(10);
// installed
assertThat(tSecondPin.get(0)).isEqualTo(dsSecond);
// assigned
assertThat(tSecondPin.get(1)).isEqualTo(dsFour);
assertThat(tFirstPin).hasSize(10);
// remaining id:ASC
assertThat(tSecondPin.get(2)).isEqualTo(dsFirst);
assertThat(tSecondPin.get(3)).isEqualTo(dsThree);
// target second has installed DS-2 and assigned DS-4 so check order
// correct
final List<DistributionSet> tSecondPinOrderedByName = distributionSetManagement
.findByDistributionSetFilterOrderByLinkedTarget(
PageRequest.of(0, 500, Sort.by(Direction.DESC, "version")),
distributionSetFilter, tSecond.getControllerId())
.getContent();
assertThat(tSecondPinOrderedByName).hasSize(10);
// installed
assertThat(tSecondPinOrderedByName.get(0)).isEqualTo(buildDistributionSets.get(1));
// assigned
assertThat(tSecondPinOrderedByName.get(1)).isEqualTo(buildDistributionSets.get(3));
// remaining version:DESC
assertThat(tSecondPinOrderedByName.get(2)).isEqualTo(buildDistributionSets.get(9));
assertThat(tSecondPinOrderedByName.get(3)).isEqualTo(buildDistributionSets.get(8));
assertThat(tSecondPinOrderedByName.get(4)).isEqualTo(buildDistributionSets.get(7));
assertThat(tSecondPinOrderedByName.get(5)).isEqualTo(buildDistributionSets.get(6));
assertThat(tSecondPinOrderedByName.get(6)).isEqualTo(buildDistributionSets.get(5));
assertThat(tSecondPinOrderedByName.get(7)).isEqualTo(buildDistributionSets.get(4));
assertThat(tSecondPinOrderedByName.get(8)).isEqualTo(buildDistributionSets.get(2));
assertThat(tSecondPinOrderedByName.get(9)).isEqualTo(buildDistributionSets.get(0));
}
@Test

View File

@@ -10,6 +10,9 @@ package org.eclipse.hawkbit.repository.jpa;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutCreatedEvent;
@@ -18,9 +21,17 @@ import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupUpdatedEve
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetWithActionStatus;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
@@ -28,13 +39,13 @@ import io.qameta.allure.Story;
@Feature("Component Tests - Repository")
@Story("Rollout Management")
public class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
class RolloutGroupManagementTest 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() {
void nonExistingEntityAccessReturnsNotPresent() {
assertThat(rolloutGroupManagement.get(NOT_EXIST_IDL)).isNotPresent();
assertThat(rolloutGroupManagement.getWithDetailedStatus(NOT_EXIST_IDL)).isNotPresent();
@@ -48,11 +59,11 @@ public class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
@Expect(type = RolloutGroupUpdatedEvent.class, count = 5),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = RolloutUpdatedEvent.class, count = 1),
@Expect(type = RolloutUpdatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 125),
@Expect(type = RolloutCreatedEvent.class, count = 1) })
public void entityQueriesReferringToNotExistingEntitiesThrowsException() {
void entityQueriesReferringToNotExistingEntitiesThrowsException() {
testdataFactory.createRollout("xxx");
verifyThrownExceptionBy(() -> rolloutGroupManagement.countByRollout(NOT_EXIST_IDL), "Rollout");
@@ -73,4 +84,71 @@ public class RolloutGroupManagementTest extends AbstractJpaIntegrationTest {
"RolloutGroup");
}
@Test
@Description("Verifies that the returned result considers the provided sort parameters.")
void findAllTargetsOfRolloutGroupWithActionStatusConsidersSorting() {
final String prefix = RandomStringUtils.randomAlphanumeric(5);
final Rollout rollout = testdataFactory.createRollout(prefix);
final List<RolloutGroup> rolloutGroups = rolloutGroupManagement.findByRollout(PAGE, rollout.getId())
.getContent();
final RolloutGroup rolloutGroup = rolloutGroups.get(0);
rolloutManagement.handleRollouts();
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
rolloutManagement.pauseRollout(rollout.getId());
rolloutManagement.handleRollouts();
final List<Target> targets = rolloutGroupManagement.findTargetsOfRolloutGroup(PAGE, rolloutGroup.getId())
.getContent();
Target targetCancelled = targets.get(0);
final Action actionCancelled = deploymentManagement.findActionsByTarget(targetCancelled.getControllerId(), PAGE)
.getContent().get(0);
deploymentManagement.cancelAction(actionCancelled.getId());
deploymentManagement.forceQuitAction(actionCancelled.getId());
targetCancelled = reloadTarget(targetCancelled);
Target targetCancelling = targets.get(1);
final Action actionCancelling = deploymentManagement
.findActionsByTarget(targetCancelling.getControllerId(), PAGE).getContent().get(0);
deploymentManagement.cancelAction(actionCancelling.getId());
targetCancelling = reloadTarget(targetCancelling);
final List<TargetWithActionStatus> targetsWithActionStatus = rolloutGroupManagement
.findAllTargetsOfRolloutGroupWithActionStatus(PageRequest.of(0, 500, Sort.by(Direction.DESC, "status")),
rolloutGroup.getId())
.getContent();
assertThat(targetsWithActionStatus.get(0).getTarget()).isEqualTo(targetCancelling);
assertThat(targetsWithActionStatus.get(1).getTarget()).isEqualTo(targetCancelled);
final List<TargetWithActionStatus> targetsWithActionStatusOrderedByNameDesc = rolloutGroupManagement
.findAllTargetsOfRolloutGroupWithActionStatus(PageRequest.of(0, 500, Sort.by(Direction.DESC, "name")),
rolloutGroup.getId())
.getContent();
assertThatListIsSortedByTargetName(targetsWithActionStatusOrderedByNameDesc, Direction.DESC);
final List<TargetWithActionStatus> targetsWithActionStatusOrderedByNameAsc = rolloutGroupManagement
.findAllTargetsOfRolloutGroupWithActionStatus(PageRequest.of(0, 500, Sort.by(Direction.ASC, "name")),
rolloutGroup.getId())
.getContent();
assertThatListIsSortedByTargetName(targetsWithActionStatusOrderedByNameAsc, Direction.ASC);
}
private void assertThatListIsSortedByTargetName(final List<TargetWithActionStatus> targets,
final Direction sortDirection) {
String previousName = null;
for (final TargetWithActionStatus targetWithActionStatus : targets) {
final String actualName = targetWithActionStatus.getTarget().getName();
if (previousName != null) {
if (Direction.ASC == sortDirection) {
assertThat(actualName).isGreaterThan(previousName);
} else {
assertThat(actualName).isLessThan(previousName);
}
}
previousName = actualName;
}
}
private Target reloadTarget(final Target targetCancelled) {
return targetManagement.get(targetCancelled.getId()).orElseThrow();
}
}

View File

@@ -26,6 +26,7 @@ import java.util.stream.Collectors;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import org.apache.commons.lang3.RandomStringUtils;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.Condition;
import org.awaitility.Awaitility;
@@ -81,6 +82,7 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.T
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
@@ -1761,6 +1763,47 @@ class RolloutManagementTest extends AbstractJpaIntegrationTest {
.getNumberOfElements()).isEqualTo(2);
}
@Test
@Description("Verifies that returned result considers provided sort parameter.")
void findAllRolloutsConsidersSorting() {
final String randomString = RandomStringUtils.randomAlphanumeric(5);
final DistributionSet testDs = testdataFactory.createDistributionSet(randomString + "-testDs");
testdataFactory.createTargets(10, randomString + "-testTarget-");
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
final String prefixRolloutRunning = randomString + "1";
final RolloutCreate rolloutRunningCreate = entityFactory.rollout().create()
.name(prefixRolloutRunning + "-testRollout").targetFilterQuery("name==" + randomString + "*")
.set(testDs);
Rollout rolloutRunning = rolloutManagement.create(rolloutRunningCreate, 1, conditions);
// Let the executor handle created Rollout
rolloutManagement.handleRollouts();
// start the rollout, so it has active running actions and a group which
// has been started
rolloutManagement.start(rolloutRunning.getId());
rolloutManagement.handleRollouts();
rolloutRunning = reloadRollout(rolloutRunning);
final String prefixRolloutReady = randomString + "2";
final RolloutCreate rolloutReadyCreate = entityFactory.rollout().create()
.name(prefixRolloutReady + "-testRollout").targetFilterQuery("name==" + randomString + "*")
.set(testDs);
Rollout rolloutReady = rolloutManagement.create(rolloutReadyCreate, 1, conditions);
// Let the executor handle created Rollout
rolloutManagement.handleRollouts();
rolloutReady = reloadRollout(rolloutReady);
final List<Rollout> rolloutsOrderedByStatus = rolloutManagement
.findAll(PageRequest.of(0, 500, Sort.by(Direction.ASC, "status")), false).getContent();
assertThat(rolloutsOrderedByStatus).containsSubsequence(List.of(rolloutReady, rolloutRunning));
final List<Rollout> rolloutsOrderedByName = rolloutManagement
.findAll(PageRequest.of(0, 500, Sort.by(Direction.ASC, "name")), false).getContent();
assertThat(rolloutsOrderedByName).containsSubsequence(List.of(rolloutRunning, rolloutReady));
}
@Test
@Description("Creating a rollout without weight value when multi assignment in enabled.")
void weightNotRequiredInMultiAssignmentMode() {

View File

@@ -46,6 +46,8 @@ import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -545,19 +547,28 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
.containsExactly(new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
new AssignedSoftwareModule(unassigned, false));
// with filter on name, version and module type, sorting defined by
// Pagerequest
assertThat(softwareModuleManagement.findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(
PageRequest.of(0, 500, Sort.by(Direction.DESC, "name")), set.getId(), "%found%", testType.getId())
.getContent()).as(
"Found modules with given name, given module type, the assigned ones first, ordered by name DESC")
.containsExactly(new AssignedSoftwareModule(two, true), new AssignedSoftwareModule(one, true),
new AssignedSoftwareModule(unassigned, false));
// with filter on module type only
assertThat(softwareModuleManagement
.findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(PAGE, set.getId(), null, testType.getId())
.getContent()).as("Found modules with given module type and the assigned ones first").containsExactly(
new AssignedSoftwareModule(differentName, true), new AssignedSoftwareModule(one, true),
new AssignedSoftwareModule(two, true), new AssignedSoftwareModule(unassigned, false));
new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
new AssignedSoftwareModule(differentName, true), new AssignedSoftwareModule(unassigned, false));
// without any filter
assertThat(softwareModuleManagement
.findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(PAGE, set.getId(), null, null)
.getContent()).as("Found modules with the assigned ones first").containsExactly(
new AssignedSoftwareModule(differentName, true), new AssignedSoftwareModule(one, true),
new AssignedSoftwareModule(two, true), new AssignedSoftwareModule(four, true),
new AssignedSoftwareModule(one, true), new AssignedSoftwareModule(two, true),
new AssignedSoftwareModule(differentName, true), new AssignedSoftwareModule(four, true),
new AssignedSoftwareModule(unassigned, false));
}

View File

@@ -31,7 +31,10 @@ import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
@@ -573,7 +576,7 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
final Slice<Target> result = targetManagement.findByFilterOrderByLinkedDistributionSet(PAGE, ds.getId(),
new FilterParams(null, null, null, null, Boolean.FALSE));
final Comparator<TenantAwareBaseEntity> byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId());
final Comparator<TenantAwareBaseEntity> byId = (e1, e2) -> Long.compare(e1.getId(), e2.getId());
assertThat(result.getNumberOfElements()).isEqualTo(9);
final List<Target> expected = new ArrayList<>();
@@ -586,7 +589,45 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
assertThat(result.getContent()).usingElementComparator(controllerIdComparator())
.containsExactly(expected.toArray(new Target[0]));
}
@Test
@Description("Tests the correct order of targets based on selected distribution set and sort parameter. The system expects to have an order based on installed, assigned DS.")
void targetSearchWithOrderByDistributionSetAndSortParam() {
final List<Target> notAssigned = testdataFactory.createTargets(3, "not", "first description");
List<Target> targAssigned = testdataFactory.createTargets(3, "assigned", "first description");
List<Target> targInstalled = testdataFactory.createTargets(3, "installed", "first description");
final DistributionSet ds = testdataFactory.createDistributionSet("a");
targAssigned = assignDistributionSet(ds, targAssigned).getAssignedEntity().stream().map(Action::getTarget)
.collect(Collectors.toList());
targInstalled = assignDistributionSet(ds, targInstalled).getAssignedEntity().stream().map(Action::getTarget)
.collect(Collectors.toList());
targInstalled = testdataFactory
.sendUpdateActionStatusToTargets(targInstalled, Status.FINISHED, Collections.singletonList("installed"))
.stream().map(Action::getTarget).collect(Collectors.toList());
final List<Target> targetsOrderedByDistAndName = targetManagement
.findByFilterOrderByLinkedDistributionSet(PageRequest.of(0, 500, Sort.by(Direction.DESC, "name")),
ds.getId(), new FilterParams(null, null, null, null, Boolean.FALSE))
.getContent();
assertThat(targetsOrderedByDistAndName).hasSize(9);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 0, targInstalled, 2);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 1, targInstalled, 1);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 2, targInstalled, 0);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 3, targAssigned, 2);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 4, targAssigned, 1);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 5, targAssigned, 0);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 6, notAssigned, 2);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 7, notAssigned, 1);
assertThatTargetNameEquals(targetsOrderedByDistAndName, 8, notAssigned, 0);
}
private void assertThatTargetNameEquals(final List<Target> targets1, final int index1, final List<Target> targets2,
final int index2) {
assertThat(targets1.get(index1).getName()).isEqualTo(targets2.get(index2).getName());
}
@Test
@@ -626,7 +667,7 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
final Slice<Target> result = targetManagement.findByFilterOrderByLinkedDistributionSet(PAGE, ds.getId(),
new FilterParams(null, Boolean.TRUE, null, null, Boolean.FALSE));
final Comparator<TenantAwareBaseEntity> byId = (e1, e2) -> Long.compare(e2.getId(), e1.getId());
final Comparator<TenantAwareBaseEntity> byId = (e1, e2) -> Long.compare(e1.getId(), e2.getId());
assertThat(result.getNumberOfElements()).isEqualTo(9);
final List<Target> expected = new ArrayList<>();