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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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) -> {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
Reference in New Issue
Block a user