From a2fd46c732f3eccda3af1aa5a51485e0be1f5fed Mon Sep 17 00:00:00 2001 From: Stefan Behl Date: Thu, 6 Apr 2023 16:47:45 +0200 Subject: [PATCH] Initial commit (#1345) --- .../repository/RolloutGroupManagement.java | 25 ++ .../jpa/JpaRolloutGroupManagement.java | 40 ++- .../mgmt/rest/api/MgmtRolloutRestApi.java | 7 +- .../mgmt/rest/resource/MgmtRolloutMapper.java | 6 +- .../rest/resource/MgmtRolloutResource.java | 39 ++- .../resource/MgmtRolloutResourceTest.java | 251 ++++++++++-------- 6 files changed, 241 insertions(+), 127 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java index 3b4b221d8..8ae37d64b 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/RolloutGroupManagement.java @@ -102,6 +102,31 @@ public interface RolloutGroupManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) Page findByRolloutAndRsql(@NotNull Pageable pageable, long rolloutId, @NotNull String rsqlParam); + + + /** + * Retrieves a page of {@link RolloutGroup}s filtered by a given + * {@link Rollout} and a rsql filter with detailed status. + * + * @param pageable + * the page request to sort and limit the result + * @param rolloutId + * the rollout to filter the {@link RolloutGroup}s + * @param rsqlParam + * the specification to filter the result set based on attributes + * of the {@link RolloutGroup} + * + * @return a page of found {@link RolloutGroup}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_READ) + Page findByRolloutAndRsqlWithDetailedStatus(@NotNull Pageable pageable, long rolloutId, + @NotNull String rsqlParam); /** * Retrieves a page of {@link RolloutGroup}s filtered by a given diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java index c0e728184..0c82fa8c1 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java @@ -157,6 +157,33 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { return JpaManagementHelper.convertPage(rolloutGroups, pageable); } + @Override + public Page findByRolloutAndRsqlWithDetailedStatus(final Pageable pageable, final long rolloutId, + final String rsqlParam) { + throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId); + + final Page rolloutGroups = findByRolloutAndRsql(pageable, rolloutId, rsqlParam); + final List rolloutGroupIds = rolloutGroups.getContent().stream().map(RolloutGroup::getId) + .collect(Collectors.toList()); + + if (rolloutGroupIds.isEmpty()) { + // groups might already deleted, so return empty list. + return new PageImpl<>(Collections.emptyList()); + } + + final Map> allStatesForRollout = getStatusCountItemForRolloutGroup( + rolloutGroupIds); + + for (final RolloutGroup rolloutGroup : rolloutGroups) { + final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus( + allStatesForRollout.get(rolloutGroup.getId()), Long.valueOf(rolloutGroup.getTotalTargets()), + rolloutGroup.getRollout().getActionType()); + ((JpaRolloutGroup) rolloutGroup).setTotalTargetCountStatus(totalTargetCountStatus); + } + + return JpaManagementHelper.convertPage(rolloutGroups, pageable); + } + @Override public Optional getWithDetailedStatus(final long rolloutGroupId) { final Optional rolloutGroup = get(rolloutGroupId); @@ -265,15 +292,14 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { return new PageImpl<>(targetWithActionStatus, pageRequest, 0); } - private Predicate getRolloutGroupTargetWithRolloutGroupJoinCondition(final long rolloutGroupId, final CriteriaBuilder cb, - final Root targetRoot) { + private Predicate getRolloutGroupTargetWithRolloutGroupJoinCondition(final long rolloutGroupId, + final CriteriaBuilder cb, final Root targetRoot) { return cb.equal(targetRoot.get(RolloutTargetGroup_.rolloutGroup).get(JpaRolloutGroup_.id), // rolloutGroupId); } private TargetWithActionStatus getTargetWithActionStatusFromQuery(final Object[] o) { - return new TargetWithActionStatus((Target) o[0], (Action.Status) o[1], - (Integer) o[2]); + return new TargetWithActionStatus((Target) o[0], (Action.Status) o[1], (Integer) o[2]); } private List getOrderBy(final Pageable pageRequest, final CriteriaBuilder cb, @@ -283,7 +309,8 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { return pageRequest.getSort().get().flatMap(order -> { final List orders; final String property = order.getProperty(); - // we consider status, last_action_status_code as property from JpaAction ... + // we consider status, last_action_status_code as property from + // JpaAction ... if ("status".equals(property) || "lastActionStatusCode".equals(property)) { orders = QueryUtils.toOrders(Sort.by(order.getDirection(), property), actionJoin, cb); } @@ -302,7 +329,8 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement { final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaQuery countQuery = cb.createQuery(Long.class); final Root countQueryFrom = countQuery.from(RolloutTargetGroup.class); - countQuery.select(cb.count(countQueryFrom)).where(getRolloutGroupTargetWithRolloutGroupJoinCondition(rolloutGroupId, cb, countQueryFrom)); + countQuery.select(cb.count(countQueryFrom)) + .where(getRolloutGroupTargetWithRolloutGroupJoinCondition(rolloutGroupId, cb, countQueryFrom)); return entityManager.createQuery(countQuery).getSingleResult(); } diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java index df789622b..69a90fc72 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtRolloutRestApi.java @@ -180,6 +180,10 @@ public interface MgmtRolloutRestApi { * @param rsqlParam * the search parameter in the request URL, syntax * {@code q=name==abc} + * @param representationModeParam + * the representation mode parameter specifying whether a compact + * or a full representation shall be returned + * * @return a list of all rollout groups referred to a rollout for a defined * or default page request with status OK. The response is always * paged. In any failure the JsonResponseExceptionHandler is @@ -191,7 +195,8 @@ public interface MgmtRolloutRestApi { @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) int pagingOffsetParam, @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam, @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam, - @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) String rsqlParam); + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) String rsqlParam, + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE_DEFAULT) String representationModeParam); /** * Handles the GET request for retrieving a single rollout group. diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java index aa880f479..1a2d7070e 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutMapper.java @@ -105,7 +105,7 @@ final class MgmtRolloutMapper { body.add(linkTo(methodOn(MgmtRolloutRestApi.class).deny(rollout.getId(), null)).withRel("deny").expand()); body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroups(rollout.getId(), MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE, - MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("groups") + MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null, null)).withRel("groups") .expand()); final DistributionSet distributionSet = rollout.getDistributionSet(); @@ -165,12 +165,12 @@ final class MgmtRolloutMapper { } static List toResponseRolloutGroup(final List rollouts, - final boolean confirmationFlowEnabled) { + final boolean confirmationFlowEnabled, final boolean withDetails) { if (rollouts == null) { return Collections.emptyList(); } - return rollouts.stream().map(group -> toResponseRolloutGroup(group, false, confirmationFlowEnabled)) + return rollouts.stream().map(group -> toResponseRolloutGroup(group, withDetails, confirmationFlowEnabled)) .collect(Collectors.toList()); } diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java index 1afb43ad9..0cee352c1 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResource.java @@ -99,11 +99,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi { final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); final Sort sorting = PagingUtility.sanitizeRolloutSortParam(sortParam); - final boolean isFullMode = MgmtRepresentationMode.fromValue(representationModeParam).orElseGet(() -> { - // no need for a 400, just apply a safe fallback - LOG.warn("Received an invalid representation mode: {}", representationModeParam); - return MgmtRepresentationMode.COMPACT; - }) == MgmtRepresentationMode.FULL; + final boolean isFullMode = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL; final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); final Slice rollouts; @@ -237,23 +233,35 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi { @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam, @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam, @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam, - @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) { + @RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam, + final String representationModeParam) { final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam); final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam); final Sort sorting = PagingUtility.sanitizeRolloutGroupSortParam(sortParam); + final boolean isFullMode = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL; + final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting); - final Page findRolloutGroupsAll; + final Page rolloutGroups; if (rsqlParam != null) { - findRolloutGroupsAll = this.rolloutGroupManagement.findByRolloutAndRsql(pageable, rolloutId, rsqlParam); + if (isFullMode) { + rolloutGroups = this.rolloutGroupManagement.findByRolloutAndRsqlWithDetailedStatus(pageable, + rolloutId, rsqlParam); + } else { + rolloutGroups = this.rolloutGroupManagement.findByRolloutAndRsql(pageable, rolloutId, rsqlParam); + } } else { - findRolloutGroupsAll = this.rolloutGroupManagement.findByRollout(pageable, rolloutId); + if (isFullMode) { + rolloutGroups = this.rolloutGroupManagement.findByRolloutWithDetailedStatus(pageable, rolloutId); + } else { + rolloutGroups = this.rolloutGroupManagement.findByRollout(pageable, rolloutId); + } } final List rest = MgmtRolloutMapper.toResponseRolloutGroup( - findRolloutGroupsAll.getContent(), tenantConfigHelper.isConfirmationFlowEnabled()); - return ResponseEntity.ok(new PagedList<>(rest, findRolloutGroupsAll.getTotalElements())); + rolloutGroups.getContent(), tenantConfigHelper.isConfirmationFlowEnabled(), isFullMode); + return ResponseEntity.ok(new PagedList<>(rest, rolloutGroups.getTotalElements())); } @Override @@ -304,4 +312,13 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi { this.rolloutManagement.triggerNextGroup(rolloutId); return ResponseEntity.ok().build(); } + + private static MgmtRepresentationMode parseRepresentationMode(final String representationModeParam) { + return MgmtRepresentationMode.fromValue(representationModeParam).orElseGet(() -> { + // no need for a 400, just apply a safe fallback + LOG.warn("Received an invalid representation mode: {}", representationModeParam); + return MgmtRepresentationMode.COMPACT; + }); + } + } diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java index d97ee04b6..41f1c5850 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java @@ -305,7 +305,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { rolloutManagement.start(rollout.getId()); rolloutHandler.handleAll(); - // request the list of rollouts with full representation + // request the list of rollouts with full representation mvc.perform(get("/rest/v1/rollouts?representation=full").accept(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) @@ -592,10 +592,9 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { final Long forcetime = 45L; testdataFactory.createTargets(20, "target", "rollout"); - postRollout("rollout1", 5, dsA.getId(), "id==target*", 20, Action.ActionType.TIMEFORCED, - startAt, forcetime); - postRollout("rollout2", 5, dsA.getId(), "id==target-0001*", 10, Action.ActionType.TIMEFORCED, - startAt, forcetime); + postRollout("rollout1", 5, dsA.getId(), "id==target*", 20, Action.ActionType.TIMEFORCED, startAt, forcetime); + postRollout("rollout2", 5, dsA.getId(), "id==target-0001*", 10, Action.ActionType.TIMEFORCED, startAt, + forcetime); // Run here, because Scheduler is disabled during tests rolloutHandler.handleAll(); @@ -1165,7 +1164,8 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) .andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1))) - .andExpect(jsonPath("$.content[0].name", equalTo("group-1"))); + .andExpect(jsonPath("$.content[0].name", equalTo("group-1"))) + .andExpect(jsonPath("$.content[0].totalTargetsPerStatus").doesNotExist()); mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()) .accept(MediaType.APPLICATION_JSON).param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group*")) @@ -1178,10 +1178,47 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { .param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1,name==group-2")) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2))); + .andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2))) + .andExpect(jsonPath("$.content[0].totalTargetsPerStatus").doesNotExist()) + .andExpect(jsonPath("$.content[1].totalTargetsPerStatus").doesNotExist()); } + @Test + @Description("Testing that the list of rollout groups can be requested with representation mode 'full'.") + void retrieveRolloutGroupsFullRepresentation() throws Exception { + + testdataFactory.createTargets(20, "rollout", "rollout"); + final DistributionSet dsA = testdataFactory.createDistributionSet(""); + + // create a running rollout for the created targets + final Rollout rollout = rolloutManagement.create( + entityFactory.rollout().create().name("rollout1").set(dsA.getId()) + .targetFilterQuery("controllerId==rollout*"), + 4, false, new RolloutGroupConditionBuilder().withDefaults() + .successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build()); + + rolloutHandler.handleAll(); + rolloutManagement.start(rollout.getId()); + rolloutHandler.handleAll(); + + // retrieve the rollout groups of the created rollout + // filter for the first group by RSQL + mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()) + .accept(MediaType.APPLICATION_JSON).param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1") + .param("representation", "full")).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1))) + .andExpect(jsonPath("$.content[0].name", equalTo("group-1"))) + .andExpect(jsonPath("content[0].totalTargetsPerStatus").exists()) + .andExpect(jsonPath("content[0].totalTargetsPerStatus.running", equalTo(5))) + .andExpect(jsonPath("content[0].totalTargetsPerStatus.notstarted", equalTo(0))) + .andExpect(jsonPath("content[0].totalTargetsPerStatus.scheduled", equalTo(0))) + .andExpect(jsonPath("content[0].totalTargetsPerStatus.cancelled", equalTo(0))) + .andExpect(jsonPath("content[0].totalTargetsPerStatus.finished", equalTo(0))) + .andExpect(jsonPath("content[0].totalTargetsPerStatus.error", equalTo(0))); + } + @Test @Description("Verifies that a DOWNLOAD_ONLY rollout is possible") void createDownloadOnlyRollout() throws Exception { @@ -1199,7 +1236,8 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { final int weight = 66; final String invalideWeightRequest = JsonBuilder.rollout("withWeight", "d", 2, dsId, "id==rollout*", - new RolloutGroupConditionBuilder().withDefaults().build(), null, null, Action.WEIGHT_MIN - 1, null, null, null); + new RolloutGroupConditionBuilder().withDefaults().build(), null, null, Action.WEIGHT_MIN - 1, null, + null, null); final String valideWeightRequest = JsonBuilder.rollout("withWeight", "d", 2, dsId, "id==rollout*", new RolloutGroupConditionBuilder().withDefaults().build(), null, null, weight, null, null, null); @@ -1221,18 +1259,18 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { assertThat(rollouts.get(0).getWeight()).get().isEqualTo(weight); } - private void postRollout(final String name, final int groupSize, final Long distributionSetId, - final String targetFilterQuery, final int targets, final Action.ActionType type) throws Exception { + final String targetFilterQuery, final int targets, final Action.ActionType type) throws Exception { postRollout(name, groupSize, distributionSetId, targetFilterQuery, targets, type, null, null); } private void postRollout(final String name, final int groupSize, final Long distributionSetId, - final String targetFilterQuery, final int targets, final Action.ActionType type, final Long startTime, final Long forceTime) throws Exception { + final String targetFilterQuery, final int targets, final Action.ActionType type, final Long startTime, + final Long forceTime) throws Exception { final String actionType = MgmtRestModelMapper.convertActionType(type).getName(); final String rollout = JsonBuilder.rollout(name, "desc", groupSize, distributionSetId, targetFilterQuery, - new RolloutGroupConditionBuilder().withDefaults().build(), null, actionType, null, startTime, - forceTime, null); + new RolloutGroupConditionBuilder().withDefaults().build(), null, actionType, null, startTime, forceTime, + null); mvc.perform(post("/rest/v1/rollouts").content(rollout).contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated()) @@ -1246,12 +1284,10 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { .andExpect(jsonPath("$.lastModifiedBy", equalTo("bumlux"))) .andExpect(jsonPath("$.lastModifiedAt", not(equalTo(0)))) .andExpect(jsonPath("$.totalTargets", equalTo(targets))) - .andExpect(startTime != null ? - jsonPath("$.startAt", equalTo(startTime.intValue())) - : jsonPath("$.startAt").doesNotExist()) - .andExpect(forceTime != null ? - jsonPath("$.forcetime", equalTo(forceTime.intValue())) - : jsonPath("$.forcetime", equalTo(0))) + .andExpect(startTime != null ? jsonPath("$.startAt", equalTo(startTime.intValue())) + : jsonPath("$.startAt").doesNotExist()) + .andExpect(forceTime != null ? jsonPath("$.forcetime", equalTo(forceTime.intValue())) + : jsonPath("$.forcetime", equalTo(0))) .andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(0))) .andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(targets))) .andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0))) @@ -1366,94 +1402,97 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest { } private void retrieveAndCompareRolloutsContent(final DistributionSet dsA, final String urlTemplate, - final boolean isFullRepresentation, final boolean isStartTypeScheduled, final Long startAt, final Long forcetime) throws Exception { + final boolean isFullRepresentation, final boolean isStartTypeScheduled, final Long startAt, + final Long forcetime) throws Exception { mvc.perform(get(urlTemplate).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()) - .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2))) - .andExpect(jsonPath("content[0].name", equalTo("rollout1"))) - .andExpect(jsonPath("content[0].status", equalTo("ready"))) - .andExpect(jsonPath("content[0].targetFilterQuery", equalTo("id==target*"))) - .andExpect(jsonPath("content[0].distributionSetId", equalTo(dsA.getId().intValue()))) - .andExpect(jsonPath("content[0].createdBy", equalTo("bumlux"))) - .andExpect(jsonPath("content[0].createdAt", not(equalTo(0)))) - .andExpect(jsonPath("content[0].lastModifiedBy", equalTo("bumlux"))) - .andExpect(jsonPath("content[0].lastModifiedAt", not(equalTo(0)))) - .andExpect(jsonPath("content[0].totalTargets", equalTo(20))) - .andExpect(jsonPath("content[0].forcetime", equalTo(isStartTypeScheduled ? forcetime.intValue() : 0))) - .andExpect(isFullRepresentation ? jsonPath("$.content[0].totalTargetsPerStatus").exists() - : jsonPath("content[0].totalTargetsPerStatus").doesNotExist()) - .andExpect(isFullRepresentation ? jsonPath("$.content[0].totalGroups", equalTo(5)) - : jsonPath("content[0].totalGroups").doesNotExist()) - .andExpect(isFullRepresentation && isStartTypeScheduled ? jsonPath("$.content[0].startAt", equalTo(startAt.intValue())) - : jsonPath("$.content[0].startAt").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[0]._links.start.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[0]._links.start.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[0]._links.pause.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[0]._links.pause.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[0]._links.resume.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[0]._links.resume.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[0]._links.triggerNextGroup.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[0]._links.triggerNextGroup.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[0]._links.approve.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[0]._links.approve.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[0]._links.deny.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[0]._links.deny.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[0]._links.groups.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[0]._links.groups.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[0]._links.distributionset.href", - startsWith("http://localhost/rest/v1/distributionsets/")) - : jsonPath("content[0]._links.distributionset.href").doesNotExist()) - .andExpect(jsonPath("content[0]._links.self.href", startsWith(HREF_ROLLOUT_PREFIX))) - .andExpect(jsonPath("content[1].name", equalTo("rollout2"))) - .andExpect(jsonPath("content[1].status", equalTo("ready"))) - .andExpect(jsonPath("content[1].targetFilterQuery", equalTo("id==target-0001*"))) - .andExpect(jsonPath("content[1].distributionSetId", equalTo(dsA.getId().intValue()))) - .andExpect(jsonPath("content[1].createdBy", equalTo("bumlux"))) - .andExpect(jsonPath("content[1].createdAt", not(equalTo(0)))) - .andExpect(jsonPath("content[1].lastModifiedBy", equalTo("bumlux"))) - .andExpect(jsonPath("content[1].lastModifiedAt", not(equalTo(0)))) - .andExpect(jsonPath("content[1].totalTargets", equalTo(10))) - .andExpect(jsonPath("content[1].forcetime", equalTo(isStartTypeScheduled ? forcetime.intValue() : 0))) - .andExpect(isFullRepresentation ? jsonPath("$.content[1].totalTargetsPerStatus").exists() - : jsonPath("content[1].totalTargetsPerStatus").doesNotExist()) - .andExpect(isFullRepresentation ? jsonPath("$.content[1].totalGroups", equalTo(5)) - : jsonPath("content[1].totalGroups").doesNotExist()) - .andExpect(isFullRepresentation && isStartTypeScheduled ? jsonPath("content[1].startAt", equalTo(startAt.intValue())) - : jsonPath("content[1].startAt").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[1]._links.start.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[1]._links.start.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[1]._links.pause.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[1]._links.pause.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[1]._links.resume.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[1]._links.resume.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[1]._links.triggerNextGroup.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[1]._links.triggerNextGroup.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[1]._links.approve.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[1]._links.approve.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[1]._links.deny.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[1]._links.deny.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[1]._links.groups.href", startsWith(HREF_ROLLOUT_PREFIX)) - : jsonPath("content[1]._links.groups.href").doesNotExist()) - .andExpect(isFullRepresentation - ? jsonPath("$.content[1]._links.distributionset.href", - startsWith("http://localhost/rest/v1/distributionsets/")) - : jsonPath("content[1]._links.distributionset.href").doesNotExist()) - .andExpect(jsonPath("content[1]._links.self.href", startsWith(HREF_ROLLOUT_PREFIX))); + .andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2))) + .andExpect(jsonPath("content[0].name", equalTo("rollout1"))) + .andExpect(jsonPath("content[0].status", equalTo("ready"))) + .andExpect(jsonPath("content[0].targetFilterQuery", equalTo("id==target*"))) + .andExpect(jsonPath("content[0].distributionSetId", equalTo(dsA.getId().intValue()))) + .andExpect(jsonPath("content[0].createdBy", equalTo("bumlux"))) + .andExpect(jsonPath("content[0].createdAt", not(equalTo(0)))) + .andExpect(jsonPath("content[0].lastModifiedBy", equalTo("bumlux"))) + .andExpect(jsonPath("content[0].lastModifiedAt", not(equalTo(0)))) + .andExpect(jsonPath("content[0].totalTargets", equalTo(20))) + .andExpect(jsonPath("content[0].forcetime", equalTo(isStartTypeScheduled ? forcetime.intValue() : 0))) + .andExpect(isFullRepresentation ? jsonPath("$.content[0].totalTargetsPerStatus").exists() + : jsonPath("content[0].totalTargetsPerStatus").doesNotExist()) + .andExpect(isFullRepresentation ? jsonPath("$.content[0].totalGroups", equalTo(5)) + : jsonPath("content[0].totalGroups").doesNotExist()) + .andExpect(isFullRepresentation && isStartTypeScheduled + ? jsonPath("$.content[0].startAt", equalTo(startAt.intValue())) + : jsonPath("$.content[0].startAt").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[0]._links.start.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[0]._links.start.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[0]._links.pause.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[0]._links.pause.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[0]._links.resume.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[0]._links.resume.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[0]._links.triggerNextGroup.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[0]._links.triggerNextGroup.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[0]._links.approve.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[0]._links.approve.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[0]._links.deny.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[0]._links.deny.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[0]._links.groups.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[0]._links.groups.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[0]._links.distributionset.href", + startsWith("http://localhost/rest/v1/distributionsets/")) + : jsonPath("content[0]._links.distributionset.href").doesNotExist()) + .andExpect(jsonPath("content[0]._links.self.href", startsWith(HREF_ROLLOUT_PREFIX))) + .andExpect(jsonPath("content[1].name", equalTo("rollout2"))) + .andExpect(jsonPath("content[1].status", equalTo("ready"))) + .andExpect(jsonPath("content[1].targetFilterQuery", equalTo("id==target-0001*"))) + .andExpect(jsonPath("content[1].distributionSetId", equalTo(dsA.getId().intValue()))) + .andExpect(jsonPath("content[1].createdBy", equalTo("bumlux"))) + .andExpect(jsonPath("content[1].createdAt", not(equalTo(0)))) + .andExpect(jsonPath("content[1].lastModifiedBy", equalTo("bumlux"))) + .andExpect(jsonPath("content[1].lastModifiedAt", not(equalTo(0)))) + .andExpect(jsonPath("content[1].totalTargets", equalTo(10))) + .andExpect(jsonPath("content[1].forcetime", equalTo(isStartTypeScheduled ? forcetime.intValue() : 0))) + .andExpect(isFullRepresentation ? jsonPath("$.content[1].totalTargetsPerStatus").exists() + : jsonPath("content[1].totalTargetsPerStatus").doesNotExist()) + .andExpect(isFullRepresentation ? jsonPath("$.content[1].totalGroups", equalTo(5)) + : jsonPath("content[1].totalGroups").doesNotExist()) + .andExpect(isFullRepresentation && isStartTypeScheduled + ? jsonPath("content[1].startAt", equalTo(startAt.intValue())) + : jsonPath("content[1].startAt").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[1]._links.start.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[1]._links.start.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[1]._links.pause.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[1]._links.pause.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[1]._links.resume.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[1]._links.resume.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[1]._links.triggerNextGroup.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[1]._links.triggerNextGroup.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[1]._links.approve.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[1]._links.approve.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[1]._links.deny.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[1]._links.deny.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[1]._links.groups.href", startsWith(HREF_ROLLOUT_PREFIX)) + : jsonPath("content[1]._links.groups.href").doesNotExist()) + .andExpect(isFullRepresentation + ? jsonPath("$.content[1]._links.distributionset.href", + startsWith("http://localhost/rest/v1/distributionsets/")) + : jsonPath("content[1]._links.distributionset.href").doesNotExist()) + .andExpect(jsonPath("content[1]._links.self.href", startsWith(HREF_ROLLOUT_PREFIX))); } }