Support user consent flow (#1293)

* Introduce user consent flow
* Add permissions to confirmation management
* rename from consent to confirmation
* Reformat code. Remove unused imports. Change and add permission checks when configuring auto-confirmation.
* Do not include null values for DDI confirmation base endpoint
* fix confirmation required checkbox id
* Remove unused import. Fix consume/produce type of new API's.
* Change term processing to proceeding when activating user consent flow
* Align formatting and extend integration test cases for DMF and DDI.
* Extend DMF test cases to consider auto-confirmation
* Refactor action management to fix problem of handling action status updates on closed actions.
* remove unsupported validation
* use new confirmation api for DMF. Extend test cases.,
* Remove unnecessary fields.
* Extend API documentation for DDI and MGMT API.
* adapt ddi api docs adoc file
* Fixed the duplicate migration version for db files
* fix method to support confirmation
* Fixed PR comments
* Addressed PR comments
* Fixed after merge compilation issue
* Fixed after merge compilation issue
* Fix failing tests in MgmtRolloutResourceTest
* Fixed the permissions issue reflected by integration tests
* Added back the missing line of code lost during merge
* Fix the failing test on Jenkins

Signed-off-by: Stanislav Trailov <stanislav.trailov@bosch.io>
Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io>
Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io>
Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
Co-authored-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
This commit is contained in:
Michael Herdt
2023-01-25 12:11:05 +01:00
committed by GitHub
parent b919ceda5c
commit 21f1569881
208 changed files with 7830 additions and 831 deletions

View File

@@ -14,7 +14,6 @@ import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentR
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtDistributionSetAssignment;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
import org.eclipse.hawkbit.repository.model.DeploymentRequestBuilder;
/**
@@ -26,38 +25,37 @@ public final class MgmtDeploymentRequestMapper {
}
/**
* Convert assignment information to an {@link DeploymentRequest}
* Convert assignment information to an {@link DeploymentRequestBuilder}
*
* @param dsAssignment
* DS assignment information
* @param targetId
* target to assign the DS to
* @return resulting {@link DeploymentRequest}
* @return resulting {@link DeploymentRequestBuilder}
*/
public static DeploymentRequest createAssignmentRequest(final MgmtDistributionSetAssignment dsAssignment,
final String targetId) {
public static DeploymentRequestBuilder createAssignmentRequestBuilder(
final MgmtDistributionSetAssignment dsAssignment, final String targetId) {
return createAssignmentRequest(targetId, dsAssignment.getId(), dsAssignment.getType(),
return createAssignmentRequestBuilder(targetId, dsAssignment.getId(), dsAssignment.getType(),
dsAssignment.getForcetime(), dsAssignment.getWeight(), dsAssignment.getMaintenanceWindow());
}
/**
* Convert assignment information to an {@link DeploymentRequest}
* Convert assignment information to an {@link DeploymentRequestBuilder}
*
* @param targetAssignment
* target assignment information
* @param dsId
* DS to assign the target to
* @return resulting {@link DeploymentRequest}
* @return resulting {@link DeploymentRequestBuilder}
*/
public static DeploymentRequest createAssignmentRequest(final MgmtTargetAssignmentRequestBody targetAssignment,
final Long dsId) {
return createAssignmentRequest(targetAssignment.getId(), dsId, targetAssignment.getType(),
public static DeploymentRequestBuilder createAssignmentRequestBuilder(
final MgmtTargetAssignmentRequestBody targetAssignment, final Long dsId) {
return createAssignmentRequestBuilder(targetAssignment.getId(), dsId, targetAssignment.getType(),
targetAssignment.getForcetime(), targetAssignment.getWeight(), targetAssignment.getMaintenanceWindow());
}
private static DeploymentRequest createAssignmentRequest(final String targetId, final Long dsId,
private static DeploymentRequestBuilder createAssignmentRequestBuilder(final String targetId, final Long dsId,
final MgmtActionType type, final long forcetime, final Integer weight,
final MgmtMaintenanceWindowRequestBody maintenanceWindow) {
final DeploymentRequestBuilder request = DeploymentManagement.deploymentRequest(targetId, dsId)
@@ -69,6 +67,6 @@ public final class MgmtDeploymentRequestMapper {
MaintenanceScheduleHelper.validateMaintenanceSchedule(cronSchedule, duration, timezone);
request.setMaintenance(cronSchedule, duration, timezone);
}
return request.build();
return request;
}
}

View File

@@ -41,6 +41,7 @@ import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -51,6 +52,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
@@ -88,13 +90,16 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
private final SystemSecurityContext systemSecurityContext;
private final DistributionSetInvalidationManagement distributionSetInvalidationManagement;
private final TenantConfigHelper tenantConfigHelper;
MgmtDistributionSetResource(final SoftwareModuleManagement softwareModuleManagement,
final TargetManagement targetManagement, final TargetFilterQueryManagement targetFilterQueryManagement,
final DeploymentManagement deployManagament, final SystemManagement systemManagement,
final EntityFactory entityFactory, final DistributionSetManagement distributionSetManagement,
final SystemSecurityContext systemSecurityContext,
final DistributionSetInvalidationManagement distributionSetInvalidationManagement) {
final DistributionSetInvalidationManagement distributionSetInvalidationManagement,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.softwareModuleManagement = softwareModuleManagement;
this.targetManagement = targetManagement;
this.targetFilterQueryManagement = targetFilterQueryManagement;
@@ -104,6 +109,7 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
this.distributionSetManagement = distributionSetManagement;
this.systemSecurityContext = systemSecurityContext;
this.distributionSetInvalidationManagement = distributionSetInvalidationManagement;
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
}
@Override
@@ -203,8 +209,9 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
targetsAssignedDS = this.targetManagement.findByAssignedDistributionSet(pageable, distributionSetId);
}
return ResponseEntity.ok(new PagedList<>(MgmtTargetMapper.toResponse(targetsAssignedDS.getContent()),
targetsAssignedDS.getTotalElements()));
return ResponseEntity
.ok(new PagedList<>(MgmtTargetMapper.toResponse(targetsAssignedDS.getContent(), tenantConfigHelper),
targetsAssignedDS.getTotalElements()));
}
@Override
@@ -231,8 +238,9 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
targetsInstalledDS = this.targetManagement.findByInstalledDistributionSet(pageable, distributionSetId);
}
return ResponseEntity.ok(new PagedList<>(MgmtTargetMapper.toResponse(targetsInstalledDS.getContent()),
targetsInstalledDS.getTotalElements()));
return ResponseEntity
.ok(new PagedList<>(MgmtTargetMapper.toResponse(targetsInstalledDS.getContent(), tenantConfigHelper),
targetsInstalledDS.getTotalElements()));
}
@Override
@@ -251,8 +259,8 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
.findByAutoAssignDSAndRsql(pageable, distributionSetId, rsqlParam);
return ResponseEntity
.ok(new PagedList<>(MgmtTargetFilterQueryMapper.toResponse(targetFilterQueries.getContent()),
targetFilterQueries.getTotalElements()));
.ok(new PagedList<>(MgmtTargetFilterQueryMapper.toResponse(targetFilterQueries.getContent(),
tenantConfigHelper.isConfirmationFlowEnabled()), targetFilterQueries.getTotalElements()));
}
@Override
@@ -268,9 +276,13 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
.toResponse(deployManagament.offlineAssignedDistributionSets(offlineAssignments)));
}
final List<DeploymentRequest> deploymentRequests = assignments.stream()
.map(assignment -> MgmtDeploymentRequestMapper.createAssignmentRequest(assignment, distributionSetId))
.collect(Collectors.toList());
final List<DeploymentRequest> deploymentRequests = assignments.stream().map(dsAssignment -> {
final boolean isConfirmationRequired = dsAssignment.isConfirmationRequired() == null
? tenantConfigHelper.isConfirmationFlowEnabled()
: dsAssignment.isConfirmationRequired();
return MgmtDeploymentRequestMapper.createAssignmentRequestBuilder(dsAssignment, distributionSetId)
.setConfirmationRequired(isConfirmationRequired).build();
}).collect(Collectors.toList());
final List<DistributionSetAssignmentResult> assignmentResults = deployManagament
.assignDistributionSets(deploymentRequests);
@@ -302,7 +314,6 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
return ResponseEntity
.ok(new PagedList<>(MgmtDistributionSetMapper.toResponseDsMetadata(metaDataPage.getContent()),
metaDataPage.getTotalElements()));
}
@Override

View File

@@ -157,16 +157,18 @@ final class MgmtRolloutMapper {
return conditions.build();
}
static List<MgmtRolloutGroupResponseBody> toResponseRolloutGroup(final List<RolloutGroup> rollouts) {
static List<MgmtRolloutGroupResponseBody> toResponseRolloutGroup(final List<RolloutGroup> rollouts,
final boolean confirmationFlowEnabled) {
if (rollouts == null) {
return Collections.emptyList();
}
return rollouts.stream().map(group -> toResponseRolloutGroup(group, false)).collect(Collectors.toList());
return rollouts.stream().map(group -> toResponseRolloutGroup(group, false, confirmationFlowEnabled))
.collect(Collectors.toList());
}
static MgmtRolloutGroupResponseBody toResponseRolloutGroup(final RolloutGroup rolloutGroup,
final boolean withDetailedStatus) {
final boolean withDetailedStatus, final boolean confirmationFlowEnabled) {
final MgmtRolloutGroupResponseBody body = new MgmtRolloutGroupResponseBody();
body.setCreatedAt(rolloutGroup.getCreatedAt());
body.setCreatedBy(rolloutGroup.getCreatedBy());
@@ -180,6 +182,10 @@ final class MgmtRolloutMapper {
body.setTargetFilterQuery(rolloutGroup.getTargetFilterQuery());
body.setTotalTargets(rolloutGroup.getTotalTargets());
if (confirmationFlowEnabled) {
body.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
}
body.setSuccessCondition(new MgmtRolloutCondition(map(rolloutGroup.getSuccessCondition()),
rolloutGroup.getSuccessConditionExp()));
body.setSuccessAction(

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.mgmt.rest.resource;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.validation.ValidationException;
@@ -16,6 +17,7 @@ import javax.validation.ValidationException;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody;
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroup;
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
@@ -27,6 +29,7 @@ import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
@@ -38,6 +41,8 @@ import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.repository.model.Target;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -66,15 +71,19 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
private final TargetFilterQueryManagement targetFilterQueryManagement;
private final EntityFactory entityFactory;
private final TenantConfigHelper tenantConfigHelper;
MgmtRolloutResource(final RolloutManagement rolloutManagement, final RolloutGroupManagement rolloutGroupManagement,
final DistributionSetManagement distributionSetManagement,
final TargetFilterQueryManagement targetFilterQueryManagement, final EntityFactory entityFactory) {
final TargetFilterQueryManagement targetFilterQueryManagement, final EntityFactory entityFactory,
final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.rolloutManagement = rolloutManagement;
this.rolloutGroupManagement = rolloutGroupManagement;
this.distributionSetManagement = distributionSetManagement;
this.targetFilterQueryManagement = targetFilterQueryManagement;
this.entityFactory = entityFactory;
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
}
@Override
@@ -132,18 +141,26 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
final DistributionSet distributionSet = distributionSetManagement
.getValidAndComplete(rolloutRequestBody.getDistributionSetId());
final RolloutGroupConditions rolloutGroupConditions = MgmtRolloutMapper.fromRequest(rolloutRequestBody, true);
final RolloutCreate create = MgmtRolloutMapper.fromRequest(entityFactory, rolloutRequestBody, distributionSet);
final boolean confirmationFlowActive = tenantConfigHelper.isConfirmationFlowEnabled();
Rollout rollout;
if (rolloutRequestBody.getGroups() != null) {
final List<RolloutGroupCreate> rolloutGroups = rolloutRequestBody.getGroups().stream()
.map(mgmtRolloutGroup -> MgmtRolloutMapper.fromRequest(entityFactory, mgmtRolloutGroup))
.collect(Collectors.toList());
.map(mgmtRolloutGroup -> {
final boolean confirmationRequired = isConfirmationRequiredForGroup(mgmtRolloutGroup,
rolloutRequestBody).orElse(confirmationFlowActive);
return MgmtRolloutMapper.fromRequest(entityFactory, mgmtRolloutGroup)
.confirmationRequired(confirmationRequired);
}).collect(Collectors.toList());
rollout = rolloutManagement.create(create, rolloutGroups, rolloutGroupConditions);
} else if (rolloutRequestBody.getAmountGroups() != null) {
rollout = rolloutManagement.create(create, rolloutRequestBody.getAmountGroups(), rolloutGroupConditions);
final boolean confirmationRequired = rolloutRequestBody.isConfirmationRequired() == null
? confirmationFlowActive
: rolloutRequestBody.isConfirmationRequired();
rollout = rolloutManagement.create(create, rolloutRequestBody.getAmountGroups(), confirmationRequired,
rolloutGroupConditions);
} else {
throw new ValidationException("Either 'amountGroups' or 'groups' must be defined in the request");
@@ -152,6 +169,16 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtRolloutMapper.toResponseRollout(rollout, true));
}
private Optional<Boolean> isConfirmationRequiredForGroup(final MgmtRolloutGroup group,
final MgmtRolloutRestRequestBody request) {
if (group.isConfirmationRequired() != null) {
return Optional.of(group.isConfirmationRequired());
} else if (request.isConfirmationRequired() != null) {
return Optional.of(request.isConfirmationRequired());
}
return Optional.empty();
}
@Override
public ResponseEntity<Void> approve(@PathVariable("rolloutId") final Long rolloutId, final String remark) {
rolloutManagement.approveOrDeny(rolloutId, Rollout.ApprovalDecision.APPROVED, remark);
@@ -209,7 +236,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
}
final List<MgmtRolloutGroupResponseBody> rest = MgmtRolloutMapper
.toResponseRolloutGroup(findRolloutGroupsAll.getContent());
.toResponseRolloutGroup(findRolloutGroupsAll.getContent(), tenantConfigHelper.isConfirmationFlowEnabled());
return ResponseEntity.ok(new PagedList<>(rest, findRolloutGroupsAll.getTotalElements()));
}
@@ -220,7 +247,8 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
final RolloutGroup rolloutGroup = rolloutGroupManagement.getWithDetailedStatus(groupId)
.orElseThrow(() -> new EntityNotFoundException(RolloutGroup.class, rolloutId));
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRolloutGroup(rolloutGroup, true));
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRolloutGroup(rolloutGroup, true,
tenantConfigHelper.isConfirmationFlowEnabled()));
}
private void findRolloutOrThrowException(final Long rolloutId) {
@@ -251,7 +279,7 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
final Page<Target> pageTargets = this.rolloutGroupManagement.findTargetsOfRolloutGroup(pageable, groupId);
rolloutGroupTargets = pageTargets;
}
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent());
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent(), tenantConfigHelper);
return ResponseEntity.ok(new PagedList<>(rest, rolloutGroupTargets.getTotalElements()));
}

View File

@@ -38,14 +38,15 @@ public final class MgmtTargetFilterQueryMapper {
// Utility class
}
static List<MgmtTargetFilterQuery> toResponse(final List<TargetFilterQuery> filters) {
static List<MgmtTargetFilterQuery> toResponse(final List<TargetFilterQuery> filters,
final boolean confirmationFlowEnabled) {
if (CollectionUtils.isEmpty(filters)) {
return Collections.emptyList();
}
return filters.stream().map(MgmtTargetFilterQueryMapper::toResponse).collect(Collectors.toList());
return filters.stream().map(filter -> toResponse(filter, confirmationFlowEnabled)).collect(Collectors.toList());
}
static MgmtTargetFilterQuery toResponse(final TargetFilterQuery filter) {
static MgmtTargetFilterQuery toResponse(final TargetFilterQuery filter, final boolean confirmationFlowEnabled) {
final MgmtTargetFilterQuery targetRest = new MgmtTargetFilterQuery();
targetRest.setFilterId(filter.getId());
targetRest.setName(filter.getName());
@@ -62,6 +63,9 @@ public final class MgmtTargetFilterQueryMapper {
targetRest.setAutoAssignDistributionSet(distributionSet.getId());
targetRest.setAutoAssignActionType(MgmtRestModelMapper.convertActionType(filter.getAutoAssignActionType()));
filter.getAutoAssignWeight().ifPresent(targetRest::setAutoAssignWeight);
if (confirmationFlowEnabled) {
targetRest.setConfirmationRequired(filter.isConfirmationRequired());
}
}
targetRest.add(linkTo(methodOn(MgmtTargetFilterQueryRestApi.class).getFilter(filter.getId())).withSelfRel());

View File

@@ -20,9 +20,13 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
@@ -46,18 +50,23 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA
private final TargetFilterQueryManagement filterManagement;
private final EntityFactory entityFactory;
private final TenantConfigHelper tenantConfigHelper;
MgmtTargetFilterQueryResource(final TargetFilterQueryManagement filterManagement,
final EntityFactory entityFactory) {
MgmtTargetFilterQueryResource(final TargetFilterQueryManagement filterManagement, final EntityFactory entityFactory,
final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.filterManagement = filterManagement;
this.entityFactory = entityFactory;
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
}
@Override
public ResponseEntity<MgmtTargetFilterQuery> getFilter(@PathVariable("filterId") final Long filterId) {
final TargetFilterQuery findTarget = findFilterWithExceptionIfNotFound(filterId);
// to single response include poll status
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(findTarget);
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(findTarget,
tenantConfigHelper.isConfirmationFlowEnabled());
MgmtTargetFilterQueryMapper.addLinks(response);
return ResponseEntity.ok(response);
@@ -87,7 +96,7 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA
}
final List<MgmtTargetFilterQuery> rest = MgmtTargetFilterQueryMapper
.toResponse(findTargetFiltersAll.getContent());
.toResponse(findTargetFiltersAll.getContent(), tenantConfigHelper.isConfirmationFlowEnabled());
return ResponseEntity.ok(new PagedList<>(rest, countTargetsAll));
}
@@ -97,7 +106,8 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA
final TargetFilterQuery createdTarget = filterManagement
.create(MgmtTargetFilterQueryMapper.fromRequest(entityFactory, filter));
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(createdTarget);
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(createdTarget,
tenantConfigHelper.isConfirmationFlowEnabled());
MgmtTargetFilterQueryMapper.addLinks(response);
return new ResponseEntity<>(response, HttpStatus.CREATED);
@@ -112,7 +122,8 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA
.update(entityFactory.targetFilterQuery().update(filterId).name(targetFilterRest.getName())
.query(targetFilterRest.getQuery()));
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter);
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter,
tenantConfigHelper.isConfirmationFlowEnabled());
MgmtTargetFilterQueryMapper.addLinks(response);
return ResponseEntity.ok(response);
@@ -130,10 +141,17 @@ public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestA
@PathVariable("filterId") final Long filterId,
@RequestBody final MgmtDistributionSetAutoAssignment autoAssignRequest) {
final TargetFilterQuery updateFilter = filterManagement.updateAutoAssignDS(
MgmtTargetFilterQueryMapper.fromRequest(entityFactory, filterId, autoAssignRequest));
final boolean confirmationRequired = autoAssignRequest.isConfirmationRequired() == null
? tenantConfigHelper.isConfirmationFlowEnabled()
: autoAssignRequest.isConfirmationRequired();
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter);
final AutoAssignDistributionSetUpdate update = MgmtTargetFilterQueryMapper
.fromRequest(entityFactory, filterId, autoAssignRequest).confirmationRequired(confirmationRequired);
final TargetFilterQuery updateFilter = filterManagement.updateAutoAssignDS(update);
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter,
tenantConfigHelper.isConfirmationFlowEnabled());
MgmtTargetFilterQueryMapper.addLinks(response);
return ResponseEntity.ok(response);

View File

@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.mgmt.json.model.MgmtPollStatus;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionStatus;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAutoConfirm;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
@@ -40,6 +41,7 @@ import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Rollout;
@@ -48,6 +50,7 @@ import org.eclipse.hawkbit.repository.model.TargetMetadata;
import org.eclipse.hawkbit.rest.data.ResponseList;
import org.eclipse.hawkbit.rest.data.SortDirection;
import org.eclipse.hawkbit.util.IpUtil;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.springframework.data.domain.PageRequest;
/**
@@ -85,6 +88,27 @@ public final class MgmtTargetMapper {
response.add(linkTo(methodOn(MgmtTargetTypeRestApi.class).getTargetType(response.getTargetType()))
.withRel(MgmtRestConstants.TARGET_V1_ASSIGNED_TARGET_TYPE));
}
if (response.getAutoConfirmActive() != null) {
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAutoConfirmStatus(response.getControllerId()))
.withRel(MgmtRestConstants.TARGET_V1_AUTO_CONFIRM));
}
}
public static MgmtTargetAutoConfirm getTargetAutoConfirmResponse(final Target target) {
final AutoConfirmationStatus status = target.getAutoConfirmationStatus();
final MgmtTargetAutoConfirm response;
if (status != null) {
response = MgmtTargetAutoConfirm.active(status.getActivatedAt());
response.setInitiator(status.getInitiator());
response.setRemark(status.getRemark());
response.add(linkTo(methodOn(MgmtTargetRestApi.class).deactivateAutoConfirm(target.getControllerId()))
.withRel(MgmtRestConstants.TARGET_V1_DEACTIVATE_AUTO_CONFIRM));
} else {
response = MgmtTargetAutoConfirm.disabled();
response.add(linkTo(methodOn(MgmtTargetRestApi.class).activateAutoConfirm(target.getControllerId(), null))
.withRel(MgmtRestConstants.TARGET_V1_ACTIVATE_AUTO_CONFIRM));
}
return response;
}
static void addPollStatus(final Target target, final MgmtTarget targetRest) {
@@ -107,12 +131,13 @@ public final class MgmtTargetMapper {
* list of targets
* @return the response
*/
public static List<MgmtTarget> toResponse(final Collection<Target> targets) {
public static List<MgmtTarget> toResponse(final Collection<Target> targets, final TenantConfigHelper configHelper) {
if (targets == null) {
return Collections.emptyList();
}
return new ResponseList<>(targets.stream().map(MgmtTargetMapper::toResponse).collect(Collectors.toList()));
return new ResponseList<>(
targets.stream().map(target -> toResponse(target, configHelper)).collect(Collectors.toList()));
}
/**
@@ -122,7 +147,7 @@ public final class MgmtTargetMapper {
* the target
* @return the response
*/
public static MgmtTarget toResponse(final Target target) {
public static MgmtTarget toResponse(final Target target, final TenantConfigHelper configHelper) {
if (target == null) {
return null;
}
@@ -163,6 +188,9 @@ public final class MgmtTargetMapper {
targetRest.setTargetType(target.getTargetType().getId());
targetRest.setTargetTypeName(target.getTargetType().getName());
}
if (configHelper.isConfirmationFlowEnabled()) {
targetRest.setAutoConfirmActive(target.getAutoConfirmationStatus() != null);
}
targetRest.add(linkTo(methodOn(MgmtTargetRestApi.class).getTarget(target.getControllerId())).withSelfRel());

View File

@@ -13,6 +13,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.validation.Valid;
@@ -31,13 +32,17 @@ import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentR
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtDistributionSetAssignments;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAttributes;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAutoConfirm;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAutoConfirmUpdate;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionStatus;
@@ -45,6 +50,8 @@ import org.eclipse.hawkbit.repository.model.DeploymentRequest;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetMetadata;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
@@ -69,22 +76,30 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
private final TargetManagement targetManagement;
private final ConfirmationManagement confirmationManagement;
private final DeploymentManagement deploymentManagement;
private final EntityFactory entityFactory;
private final TenantConfigHelper tenantConfigHelper;
MgmtTargetResource(final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
final EntityFactory entityFactory) {
final ConfirmationManagement confirmationManagement, final EntityFactory entityFactory,
final SystemSecurityContext systemSecurityContext,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.targetManagement = targetManagement;
this.deploymentManagement = deploymentManagement;
this.confirmationManagement = confirmationManagement;
this.entityFactory = entityFactory;
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
}
@Override
public ResponseEntity<MgmtTarget> getTarget(@PathVariable("targetId") final String targetId) {
final Target findTarget = findTargetWithExceptionIfNotFound(targetId);
// to single response include poll status
final MgmtTarget response = MgmtTargetMapper.toResponse(findTarget);
final MgmtTarget response = MgmtTargetMapper.toResponse(findTarget, tenantConfigHelper);
MgmtTargetMapper.addPollStatus(findTarget, response);
MgmtTargetMapper.addTargetLinks(response);
@@ -113,7 +128,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
countTargetsAll = targetManagement.count();
}
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent());
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper);
return ResponseEntity.ok(new PagedList<>(rest, countTargetsAll));
}
@@ -123,7 +138,8 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
final Collection<Target> createdTargets = this.targetManagement
.create(MgmtTargetMapper.fromRequest(entityFactory, targets));
LOG.debug("{} targets created, return status {}", targets.size(), HttpStatus.CREATED);
return new ResponseEntity<>(MgmtTargetMapper.toResponse(createdTargets), HttpStatus.CREATED);
return new ResponseEntity<>(MgmtTargetMapper.toResponse(createdTargets, tenantConfigHelper),
HttpStatus.CREATED);
}
@Override
@@ -143,7 +159,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
.targetType(targetRest.getTargetType()).securityToken(targetRest.getSecurityToken())
.requestAttributes(targetRest.isRequestAttributes()));
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget);
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget, tenantConfigHelper);
MgmtTargetMapper.addPollStatus(updateTarget, response);
MgmtTargetMapper.addTargetLinks(response);
@@ -309,9 +325,13 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
}
findTargetWithExceptionIfNotFound(targetId);
final List<DeploymentRequest> deploymentRequests = dsAssignments.stream()
.map(dsAssignment -> MgmtDeploymentRequestMapper.createAssignmentRequest(dsAssignment, targetId))
.collect(Collectors.toList());
final List<DeploymentRequest> deploymentRequests = dsAssignments.stream().map(dsAssignment -> {
final boolean isConfirmationRequired = dsAssignment.isConfirmationRequired() == null
? tenantConfigHelper.isConfirmationFlowEnabled()
: dsAssignment.isConfirmationRequired();
return MgmtDeploymentRequestMapper.createAssignmentRequestBuilder(dsAssignment, targetId)
.setConfirmationRequired(isConfirmationRequired).build();
}).collect(Collectors.toList());
final List<DistributionSetAssignmentResult> assignmentResults = deploymentManagement
.assignDistributionSets(deploymentRequests);
@@ -416,4 +436,30 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
return new ResponseEntity<>(MgmtTargetMapper.toResponseTargetMetadata(created), HttpStatus.CREATED);
}
@Override
public ResponseEntity<MgmtTargetAutoConfirm> getAutoConfirmStatus(@PathVariable("targetId") final String targetId) {
final Target findTarget = findTargetWithExceptionIfNotFound(targetId);
final MgmtTargetAutoConfirm state = MgmtTargetMapper.getTargetAutoConfirmResponse(findTarget);
return ResponseEntity.ok(state);
}
@Override
public ResponseEntity<Void> activateAutoConfirm(@PathVariable("targetId") final String targetId,
@RequestBody(required = false) final MgmtTargetAutoConfirmUpdate update) {
final String initiator = getNullIfEmpty(update, MgmtTargetAutoConfirmUpdate::getInitiator);
final String remark = getNullIfEmpty(update, MgmtTargetAutoConfirmUpdate::getRemark);
confirmationManagement.activateAutoConfirmation(targetId, initiator, remark);
return new ResponseEntity<>(HttpStatus.OK);
}
private <T, R> R getNullIfEmpty(final T object, final Function<T, R> extractMethod) {
return object == null ? null : extractMethod.apply(object);
}
@Override
public ResponseEntity<Void> deactivateAutoConfirm(@PathVariable("targetId") final String targetId) {
confirmationManagement.deactivateAutoConfirmation(targetId);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -23,10 +23,13 @@ import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
@@ -54,11 +57,15 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
private final EntityFactory entityFactory;
private final TenantConfigHelper tenantConfigHelper;
MgmtTargetTagResource(final TargetTagManagement tagManagement, final TargetManagement targetManagement,
final EntityFactory entityFactory) {
final EntityFactory entityFactory, final SystemSecurityContext securityContext,
final TenantConfigurationManagement configurationManagement) {
this.tagManagement = tagManagement;
this.targetManagement = targetManagement;
this.entityFactory = entityFactory;
this.tenantConfigHelper = TenantConfigHelper.usingContext(securityContext, configurationManagement);
}
@Override
@@ -149,7 +156,7 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
findTargetsAll = targetManagement.findByRsqlAndTag(pageable, rsqlParam, targetTagId);
}
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent());
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper);
return ResponseEntity.ok(new PagedList<>(rest, findTargetsAll.getTotalElements()));
}
@@ -164,8 +171,10 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
.toggleTagAssignment(findTargetControllerIds(assignedTargetRequestBodies), targetTag.getName());
final MgmtTargetTagAssigmentResult tagAssigmentResultRest = new MgmtTargetTagAssigmentResult();
tagAssigmentResultRest.setAssignedTargets(MgmtTargetMapper.toResponse(assigmentResult.getAssignedEntity()));
tagAssigmentResultRest.setUnassignedTargets(MgmtTargetMapper.toResponse(assigmentResult.getUnassignedEntity()));
tagAssigmentResultRest.setAssignedTargets(
MgmtTargetMapper.toResponse(assigmentResult.getAssignedEntity(), tenantConfigHelper));
tagAssigmentResultRest.setUnassignedTargets(
MgmtTargetMapper.toResponse(assigmentResult.getUnassignedEntity(), tenantConfigHelper));
return ResponseEntity.ok(tagAssigmentResultRest);
}
@@ -175,7 +184,7 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
LOG.debug("Assign Targets {} for target tag {}", assignedTargetRequestBodies.size(), targetTagId);
final List<Target> assignedTarget = this.targetManagement
.assignTag(findTargetControllerIds(assignedTargetRequestBodies), targetTagId);
return ResponseEntity.ok(MgmtTargetMapper.toResponse(assignedTarget));
return ResponseEntity.ok(MgmtTargetMapper.toResponse(assignedTarget, tenantConfigHelper));
}
@Override

View File

@@ -29,6 +29,7 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.exception.SpServerError;
@@ -54,6 +55,9 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
@@ -143,7 +147,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
// create Targets
final String[] knownTargetIds = new String[] { "1", "2" };
final JSONArray list = createTargetAndJsonArray(null, null, null, null, knownTargetIds);
final JSONArray list = createTargetAndJsonArray(null, null, null, null, null, knownTargetIds);
// assign DisSet to target and test assignment
assignDistributionSet(disSet.getId(), knownTargetIds[0]);
mvc.perform(
@@ -257,7 +261,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
// prepare targets
final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" };
final JSONArray list = createTargetAndJsonArray(null, null, null, null, knownTargetIds);
final JSONArray list = createTargetAndJsonArray(null, null, null, null, null, knownTargetIds);
// assign already one target to DS
assignDistributionSet(createdDs.getId(), knownTargetIds[0]);
@@ -378,7 +382,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final DistributionSet createdDs = testdataFactory.createDistributionSet();
// prepare targets
final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" };
final JSONArray list = createTargetAndJsonArray(getTestSchedule(0), null, null, null, knownTargetIds);
final JSONArray list = createTargetAndJsonArray(getTestSchedule(0), null, null, null, null, knownTargetIds);
// assign already one target to DS
assignDistributionSet(createdDs.getId(), knownTargetIds[0]);
@@ -395,7 +399,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final DistributionSet createdDs = testdataFactory.createDistributionSet();
// prepare targets
final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" };
final JSONArray list = createTargetAndJsonArray(null, getTestDuration(10), null, null, knownTargetIds);
final JSONArray list = createTargetAndJsonArray(null, getTestDuration(10), null, null, null, knownTargetIds);
// assign already one target to DS
assignDistributionSet(createdDs.getId(), knownTargetIds[0]);
@@ -413,7 +417,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
// prepare targets
final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" };
final JSONArray list = createTargetAndJsonArray(getTestSchedule(10), getTestDuration(10), getTestTimeZone(),
null, knownTargetIds);
null, null, knownTargetIds);
// assign already one target to DS
assignDistributionSet(createdDs.getId(), knownTargetIds[0]);
@@ -431,7 +435,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
// prepare targets
final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" };
final JSONArray list = createTargetAndJsonArray(getTestSchedule(-30), getTestDuration(5), getTestTimeZone(),
null, knownTargetIds);
null, null, knownTargetIds);
// assign already one target to DS
assignDistributionSet(createdDs.getId(), knownTargetIds[0]);
@@ -474,7 +478,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final DistributionSet createdDs = testdataFactory.createDistributionSet();
final String[] knownTargetIds = new String[] { "1", "2", "3" };
final JSONArray assignTargetJson = createTargetAndJsonArray(null, null, null, "forced", knownTargetIds);
final JSONArray assignTargetJson = createTargetAndJsonArray(null, null, null, "forced", null, knownTargetIds);
assignDistributionSet(createdDs.getId(), knownTargetIds[0]);
assignTargetJson.put(new JSONObject().put("id", "notexistingtarget").put("type", "forced"));
@@ -487,7 +491,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
}
private JSONArray createTargetAndJsonArray(final String schedule, final String duration, final String timezone,
final String type, final String... targetIds) throws Exception {
final String type, final Boolean confirmationRequired, final String... targetIds) throws Exception {
final JSONArray result = new JSONArray();
for (final String targetId : targetIds) {
testdataFactory.createTarget(targetId);
@@ -501,7 +505,6 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
if (schedule != null || duration != null || timezone != null) {
final JSONObject maintenanceJsonObject = new JSONObject();
targetJsonObject.put("maintenanceWindow", maintenanceJsonObject);
if (schedule != null) {
maintenanceJsonObject.put("schedule", schedule);
}
@@ -511,6 +514,10 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
if (timezone != null) {
maintenanceJsonObject.put("timezone", timezone);
}
targetJsonObject.put("maintenanceWindow", maintenanceJsonObject);
}
if (confirmationRequired != null) {
targetJsonObject.put("confirmationRequired", confirmationRequired);
}
}
return result;
@@ -1263,7 +1270,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
// prepare targets
final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" };
final JSONArray list = createTargetAndJsonArray(null, null, null, null, knownTargetIds);
final JSONArray list = createTargetAndJsonArray(null, null, null, null, null, knownTargetIds);
// assign already one target to DS
assignDistributionSet(createdDs.getId(), knownTargetIds[0], Action.ActionType.DOWNLOAD_ONLY);
@@ -1277,6 +1284,41 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
.as("Five targets in repository have DS assigned").hasSize(5);
}
@ParameterizedTest
@MethodSource("confirmationOptions")
@Description("Ensures that confirmation option is considered in assignment request.")
public void assignTargetsToDistributionSetWithConfirmationOptions(final boolean confirmationFlowActive,
final Boolean confirmationRequired) throws Exception {
final DistributionSet createdDs = testdataFactory.createDistributionSet();
if (confirmationFlowActive) {
enableConfirmationFlow();
}
// prepare targets
final String targetId = "1";
final JSONArray list = createTargetAndJsonArray(null, null, null, null, confirmationRequired, targetId);
mvc.perform(post("/rest/v1/distributionsets/{ds}/assignedTargets", createdDs.getId())
.contentType(MediaType.APPLICATION_JSON).content(list.toString())).andExpect(status().isOk())
.andExpect(jsonPath("$.assigned", equalTo(1))).andExpect(jsonPath("$.alreadyAssigned", equalTo(0)))
.andExpect(jsonPath("$.total", equalTo(1)));
assertThat(deploymentManagement.findActionsByDistributionSet(PAGE, createdDs.getId()).getContent()).hasSize(1)
.allMatch(action -> {
if (!confirmationFlowActive) {
return !action.isWaitingConfirmation();
}
return confirmationRequired == null ? action.isWaitingConfirmation()
: confirmationRequired == action.isWaitingConfirmation();
});
}
private static Stream<Arguments> confirmationOptions() {
return Stream.of(Arguments.of(true, true), Arguments.of(true, false), Arguments.of(false, true),
Arguments.of(false, false), Arguments.of(true, null), Arguments.of(false, null));
}
@Test
@Description("A request for assigning a target multiple times results in a Bad Request when multiassignment is disabled.")
public void multiassignmentRequestNotAllowedIfDisabled() throws Exception {

View File

@@ -27,6 +27,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import org.awaitility.Awaitility;
@@ -52,6 +53,10 @@ import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
@@ -209,7 +214,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout2", "desc", null, dsA.getId(), "id==ro-target*",
.content(JsonBuilder.rolloutWithGroups("rollout2", "desc", null, dsA.getId(), "id==ro-target*",
rolloutGroupConditions, rolloutGroups))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated()).andReturn();
@@ -239,7 +244,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout4", "desc", null, dsA.getId(), "id==ro-target*",
.content(JsonBuilder.rolloutWithGroups("rollout4", "desc", null, dsA.getId(), "id==ro-target*",
rolloutGroupConditions, rolloutGroups))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest())
@@ -270,7 +275,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout4", "desc", null, dsA.getId(), "id==ro-target*",
.content(JsonBuilder.rolloutWithGroups("rollout4", "desc", null, dsA.getId(), "id==ro-target*",
rolloutGroupConditions, rolloutGroups))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest())
@@ -296,13 +301,11 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = rolloutManagement.create(entityFactory.rollout()
.create()
.name("rollout1")
.set(dsA.getId())
.targetFilterQuery("controllerId==rollout*"), 4, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100")
.build());
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());
retrieveAndVerifyRolloutInCreating(dsA, rollout);
retrieveAndVerifyRolloutInReady(rollout);
@@ -310,6 +313,134 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
retrieveAndVerifyRolloutInRunning(rollout);
}
@ParameterizedTest
@ValueSource(booleans = { true, false })
@Description("Verify the confirmation required flag is not part of the rollout parent entity")
void verifyConfirmationFlagIsNeverPartOfRolloutEntity(final boolean confirmationFlowActive) throws Exception {
testdataFactory.createTargets(20, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
if (confirmationFlowActive) {
enableConfirmationFlow();
}
// create rollout including the created targets with prefix 'rollout'
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());
mvc.perform(get("/rest/v1/rollouts/" + rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("$.confirmationRequired").doesNotExist());
}
@ParameterizedTest
@ValueSource(booleans = { true, false })
@Description("Verify the confirmation required flag will be set based on the feature state")
void verifyConfirmationStateIfNotProvided(final boolean confirmationFlowActive) throws Exception {
if (confirmationFlowActive) {
enableConfirmationFlow();
}
testdataFactory.createTargets(20, "target", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
postRollout("rollout1", 5, dsA.getId(), "id==target*", 20, Action.ActionType.FORCED);
final List<Rollout> content = rolloutManagement.findAll(PAGE, false).getContent();
assertThat(content).hasSizeGreaterThan(0).allSatisfy(rollout -> {
assertThat(rolloutGroupManagement.findByRollout(PAGE, rollout.getId()))
.describedAs("Confirmation required flag depends on feature active.")
.allMatch(group -> group.isConfirmationRequired() == confirmationFlowActive);
});
}
@Test
@Description("Confirmation required flag will be read from the Rollout, if specified.")
void verifyRolloutGroupWillUseRolloutPropertyFirst() throws Exception {
enableConfirmationFlow();
final DistributionSet dsA = testdataFactory.createDistributionSet("ro");
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "ro-target", "rollout");
final float percentTargetsInGroup1 = 20;
final float percentTargetsInGroup2 = 100;
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
final List<String> rolloutGroups = Arrays.asList(
JsonBuilder.rolloutGroup("Group1", "Group1desc", null, percentTargetsInGroup1, true,
rolloutGroupConditions),
JsonBuilder.rolloutGroup("Group2", "Group1desc", null, percentTargetsInGroup2, null,
rolloutGroupConditions));
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout2", "desc", null, dsA.getId(), "id==ro-target*",
rolloutGroupConditions, rolloutGroups, null, null, false))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated()).andReturn();
final List<Rollout> content = rolloutManagement.findAll(PAGE, false).getContent();
assertThat(content).hasSize(1).allSatisfy(rollout -> {
final List<RolloutGroup> groups = rolloutGroupManagement.findByRollout(PAGE, rollout.getId()).getContent();
assertThat(groups).hasSize(2).allMatch(group -> {
if (group.getName().equals("Group1")) {
return group.isConfirmationRequired();
} else if (group.getName().equals("Group2")) {
return !group.isConfirmationRequired();
}
return false;
});
});
}
@Test
@Description("Confirmation required flag will be read from the tenant config (confirmation flow state), if never specified.")
void verifyRolloutGroupWillUseConfigIfNotProvidedWithRollout() throws Exception {
enableConfirmationFlow();
final DistributionSet dsA = testdataFactory.createDistributionSet("ro");
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "ro-target", "rollout");
final float percentTargetsInGroup1 = 20;
final float percentTargetsInGroup2 = 100;
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
final List<String> rolloutGroups = Arrays.asList(
JsonBuilder.rolloutGroup("Group1", "Group1desc", null, percentTargetsInGroup1, false,
rolloutGroupConditions),
JsonBuilder.rolloutGroup("Group2", "Group1desc", null, percentTargetsInGroup2, null,
rolloutGroupConditions));
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout2", "desc", null, dsA.getId(), "id==ro-target*",
rolloutGroupConditions, rolloutGroups, null, null, null))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated()).andReturn();
final List<Rollout> content = rolloutManagement.findAll(PAGE, false).getContent();
assertThat(content).hasSize(1).allSatisfy(rollout -> {
final List<RolloutGroup> groups = rolloutGroupManagement.findByRollout(PAGE, rollout.getId()).getContent();
assertThat(groups).hasSize(2).allMatch(group -> {
if (group.getName().equals("Group1")) {
return !group.isConfirmationRequired();
} else if (group.getName().equals("Group2")) {
return group.isConfirmationRequired();
}
return false;
});
});
}
@Step
private void retrieveAndVerifyRolloutInRunning(final Rollout rollout) throws Exception {
rolloutManagement.handleRollouts();
@@ -459,16 +590,22 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(2)));
}
@Test
@ParameterizedTest
@MethodSource("confirmationOptions")
@Description("Testing that rollout paged list is limited by the query param limit")
void retrieveRolloutGroupsForSpecificRollout() throws Exception {
void retrieveRolloutGroupsForSpecificRollout(final boolean confirmationFlowEnabled, final boolean confirmationRequired) throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
if (confirmationFlowEnabled) {
enableConfirmationFlow();
}
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*",
confirmationRequired);
// retrieve rollout groups from created rollout
mvc.perform(
@@ -479,7 +616,19 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("$.content[0].status", equalTo("ready")))
.andExpect(jsonPath("$.content[1].status", equalTo("ready")))
.andExpect(jsonPath("$.content[2].status", equalTo("ready")))
.andExpect(jsonPath("$.content[3].status", equalTo("ready")));
.andExpect(jsonPath("$.content[3].status", equalTo("ready")))
.andExpect(isConfirmationFlowEnabled()
? jsonPath("$.content[0].confirmationRequired", equalTo(confirmationRequired))
: jsonPath("confirmationRequired").doesNotExist())
.andExpect(isConfirmationFlowEnabled()
? jsonPath("$.content[1].confirmationRequired", equalTo(confirmationRequired))
: jsonPath("confirmationRequired").doesNotExist())
.andExpect(isConfirmationFlowEnabled()
? jsonPath("$.content[2].confirmationRequired", equalTo(confirmationRequired))
: jsonPath("confirmationRequired").doesNotExist())
.andExpect(isConfirmationFlowEnabled()
? jsonPath("$.content[3].confirmationRequired", equalTo(confirmationRequired))
: jsonPath("confirmationRequired").doesNotExist());
}
@Test
@@ -648,20 +797,25 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("$.content[1].status", equalTo("scheduled")));
}
@Test
@ParameterizedTest
@MethodSource("confirmationOptions")
@Description("Testing that a single rollout group can be retrieved")
void retrieveSingleRolloutGroup() throws Exception {
void retrieveSingleRolloutGroup(final boolean confirmationFlowEnabled, final boolean confirmationRequired)
throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
if (confirmationFlowEnabled) {
enableConfirmationFlow();
}
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = rolloutManagement.create(entityFactory.rollout()
.create()
.name("rollout1")
.set(dsA.getId())
.targetFilterQuery("controllerId==rollout*"), 4, new RolloutGroupConditionBuilder().withDefaults()
final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").set(dsA.getId())
.targetFilterQuery("controllerId==rollout*"),
4, confirmationRequired, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
final RolloutGroup firstGroup = rolloutGroupManagement
@@ -671,12 +825,18 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
retrieveAndVerifyRolloutGroupInCreating(rollout, firstGroup);
retrieveAndVerifyRolloutGroupInReady(rollout, firstGroup);
retrieveAndVerifyRolloutGroupInRunningAndScheduled(rollout, firstGroup, secondGroup);
retrieveAndVerifyRolloutGroupInRunningAndScheduled(rollout, firstGroup, secondGroup, confirmationFlowEnabled,
confirmationRequired);
}
private static Stream<Arguments> confirmationOptions() {
return Stream.of(Arguments.of(true, false), Arguments.of(true, true), Arguments.of(false, true));
}
@Step
private void retrieveAndVerifyRolloutGroupInRunningAndScheduled(final Rollout rollout,
final RolloutGroup firstGroup, final RolloutGroup secondGroup) throws Exception {
final RolloutGroup firstGroup, final RolloutGroup secondGroup, final boolean confirmationFlowEnabled,
final boolean confirmationRequired) throws Exception {
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), firstGroup.getId())
@@ -688,7 +848,9 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)));
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(isConfirmationFlowEnabled() ? jsonPath("confirmationRequired", equalTo(confirmationRequired))
: jsonPath("confirmationRequired").doesNotExist());
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), secondGroup.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -699,7 +861,10 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(5)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)));
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(isConfirmationFlowEnabled() ? jsonPath("confirmationRequired", equalTo(confirmationRequired))
: jsonPath("confirmationRequired").doesNotExist());
;
}
@Step
@@ -718,7 +883,10 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)));
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(isConfirmationFlowEnabled() ? jsonPath("confirmationRequired").exists()
: jsonPath("confirmationRequired").doesNotExist());
;
}
@Step
@@ -729,6 +897,8 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("id", equalTo(firstGroup.getId().intValue())))
.andExpect(isConfirmationFlowEnabled() ? jsonPath("confirmationRequired").exists()
: jsonPath("confirmationRequired").doesNotExist())
.andExpect(jsonPath("status", equalTo("creating"))).andExpect(jsonPath("name", endsWith("1")))
.andExpect(jsonPath("description", endsWith("1")))
.andExpect(jsonPath("$.targetFilterQuery", equalTo("")))
@@ -983,9 +1153,9 @@ 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);
new RolloutGroupConditionBuilder().withDefaults().build(), null, null, Action.WEIGHT_MIN - 1, null);
final String valideWeightRequest = JsonBuilder.rollout("withWeight", "d", 2, dsId, "id==rollout*",
new RolloutGroupConditionBuilder().withDefaults().build(), null, null, weight);
new RolloutGroupConditionBuilder().withDefaults().build(), null, null, weight, null);
mvc.perform(post("/rest/v1/rollouts").content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
@@ -1009,7 +1179,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final String targetFilterQuery, final int targets, final Action.ActionType type) 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);
new RolloutGroupConditionBuilder().withDefaults().build(), null, actionType, null, null);
mvc.perform(post("/rest/v1/rollouts").content(rollout).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
@@ -1040,7 +1210,15 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId,
final String targetFilterQuery) {
final Rollout rollout = createRolloutInCreatingSatate(name, amountGroups, distributionSetId, targetFilterQuery);
return createRollout(name, amountGroups, distributionSetId, targetFilterQuery, false);
}
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId,
final String targetFilterQuery, final boolean confirmationRequired) {
final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name(name).set(distributionSetId).targetFilterQuery(targetFilterQuery),
amountGroups, confirmationRequired, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
@@ -1048,14 +1226,6 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
return rolloutManagement.get(rollout.getId()).orElseThrow(NoSuchElementException::new);
}
private Rollout createRolloutInCreatingSatate(final String name, final int amountGroups,
final long distributionSetId, final String targetFilterQuery) {
return rolloutManagement.create(
entityFactory.rollout().create().name(name).set(distributionSetId).targetFilterQuery(targetFilterQuery),
amountGroups, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
}
@Test
@Description("Trigger next rollout group")
void triggeringNextGroupRollout() throws Exception {
@@ -1085,7 +1255,7 @@ class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// CREATING state
final Rollout rollout = createRolloutInCreatingSatate("rollout1", 3, dsA.getId(), "controllerId==rollout*");
final Rollout rollout = createRollout("rollout1", 3, dsA.getId(), "controllerId==rollout*", false);
triggerNextGroupAndExpect(rollout, status().isBadRequest());
// READY state

View File

@@ -21,6 +21,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.List;
import java.util.stream.Stream;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
@@ -37,6 +38,10 @@ import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
@@ -59,6 +64,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
private static final String JSON_PATH_FIELD_ID = ".id";
private static final String JSON_PATH_FIELD_NAME = ".name";
private static final String JSON_PATH_FIELD_QUERY = ".query";
private static final String JSON_PATH_FIELD_CONFIRMATION_REQUIRED = ".confirmationRequired";
private static final String JSON_PATH_FIELD_CONTENT = ".content";
private static final String JSON_PATH_FIELD_SIZE = ".size";
private static final String JSON_PATH_FIELD_TOTAL = ".total";
@@ -76,6 +82,8 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
private static final String JSON_PATH_NAME = JSON_PATH_ROOT + JSON_PATH_FIELD_NAME;
private static final String JSON_PATH_ID = JSON_PATH_ROOT + JSON_PATH_FIELD_ID;
private static final String JSON_PATH_QUERY = JSON_PATH_ROOT + JSON_PATH_FIELD_QUERY;
private static final String JSON_PATH_CONFIRMATION_REQUIRED = JSON_PATH_ROOT
+ JSON_PATH_FIELD_CONFIRMATION_REQUIRED;
private static final String JSON_PATH_AUTO_ASSIGN_DS = JSON_PATH_ROOT + JSON_PATH_FIELD_AUTO_ASSIGN_DS;
private static final String JSON_PATH_AUTO_ASSIGN_ACTION_TYPE = JSON_PATH_ROOT
+ JSON_PATH_FIELD_AUTO_ASSIGN_ACTION_TYPE;
@@ -126,7 +134,8 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_ID, equalTo(tfq.getId().intValue())))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(filterQuery2)))
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(filterName)));
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(filterName)))
.andExpect(jsonPath(JSON_PATH_CONFIRMATION_REQUIRED).doesNotExist());
final TargetFilterQuery tfqCheck = targetFilterQueryManagement.get(tfq.getId()).get();
assertThat(tfqCheck.getQuery()).isEqualTo(filterQuery2);
@@ -149,7 +158,9 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_ID, equalTo(tfq.getId().intValue())))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(filterQuery)))
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(filterName2)));
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(filterName2)))
.andExpect(jsonPath(JSON_PATH_CONFIRMATION_REQUIRED).doesNotExist());
;
final TargetFilterQuery tfqCheck = targetFilterQueryManagement.get(tfq.getId()).get();
assertThat(tfqCheck.getQuery()).isEqualTo(filterQuery);
@@ -257,6 +268,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId())).andDo(print())
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(knownName)))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(knownQuery)))
.andExpect(jsonPath(JSON_PATH_CONFIRMATION_REQUIRED).doesNotExist())
.andExpect(jsonPath("$._links.self.href", equalTo(hrefPrefix)))
.andExpect(jsonPath("$._links.autoAssignDS.href", equalTo(hrefPrefix + "/autoAssignDS")));
}
@@ -364,24 +376,30 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
}
@Test
@Description("Ensures that the distribution set auto-assignment works as intended with distribution set and action type validation")
public void setAutoAssignDistributionSetToTargetFilterQuery() throws Exception {
@ParameterizedTest
@MethodSource("confirmationOptions")
@Description("Ensures that the distribution set auto-assignment works as intended with distribution set, action type and confirmation validation")
public void setAutoAssignDistributionSetToTargetFilterQuery(final boolean confirmationFlowActive,
final Boolean confirmationRequired) throws Exception {
final String knownQuery = "name==test05";
final String knownName = "filter05";
if (confirmationFlowActive) {
enableConfirmationFlow();
}
final DistributionSet set = testdataFactory.createDistributionSet();
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
verifyAutoAssignmentWithoutActionType(tfq, set);
verifyAutoAssignmentWithoutActionType(tfq, set, confirmationRequired);
verifyAutoAssignmentWithForcedActionType(tfq, set);
verifyAutoAssignmentWithForcedActionType(tfq, set, confirmationRequired);
verifyAutoAssignmentWithSoftActionType(tfq, set);
verifyAutoAssignmentWithSoftActionType(tfq, set, confirmationRequired);
verifyAutoAssignmentWithTimeForcedActionType(tfq, set);
verifyAutoAssignmentWithDownloadOnlyActionType(tfq, set);
verifyAutoAssignmentWithDownloadOnlyActionType(tfq, set, confirmationRequired);
verifyAutoAssignmentWithUnknownActionType(tfq, set);
@@ -390,34 +408,68 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
verifyAutoAssignmentWithSoftDeletedDs(tfq);
}
@Step
private void verifyAutoAssignmentWithoutActionType(final TargetFilterQuery tfq, final DistributionSet set)
throws Exception {
verifyAutoAssignmentByActionType(tfq, set, null);
@ParameterizedTest
@ValueSource(booleans = { true, false })
@Description("Verify the confirmation required flag will be set based on the feature state")
void verifyConfirmationStateIfNotProvided(final boolean confirmationFlowActive) throws Exception {
final String knownQuery = "name==test05";
final String knownName = "filter05";
if (confirmationFlowActive) {
enableConfirmationFlow();
}
final DistributionSet set = testdataFactory.createDistributionSet();
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
// do not provide something about the confirmation
verifyAutoAssignmentByActionType(tfq, set, null, null);
assertThat(targetFilterQueryManagement.get(tfq.getId())).hasValueSatisfying(filter -> {
assertThat(filter.isConfirmationRequired()).isEqualTo(confirmationFlowActive);
});
}
private static Stream<Arguments> confirmationOptions() {
return Stream.of(Arguments.of(true, false), Arguments.of(true, true), Arguments.of(false, true),
Arguments.of(true, null), Arguments.of(false, null));
}
@Step
private void verifyAutoAssignmentWithForcedActionType(final TargetFilterQuery tfq, final DistributionSet set)
throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.FORCED);
private void verifyAutoAssignmentWithoutActionType(final TargetFilterQuery tfq, final DistributionSet set,
final Boolean confirmationRequired) throws Exception {
verifyAutoAssignmentByActionType(tfq, set, null, confirmationRequired);
}
@Step
private void verifyAutoAssignmentWithSoftActionType(final TargetFilterQuery tfq, final DistributionSet set)
throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.SOFT);
private void verifyAutoAssignmentWithForcedActionType(final TargetFilterQuery tfq, final DistributionSet set,
final Boolean confirmationRequired) throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.FORCED, confirmationRequired);
}
@Step
private void verifyAutoAssignmentWithSoftActionType(final TargetFilterQuery tfq, final DistributionSet set,
final Boolean confirmationRequired) throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.SOFT, confirmationRequired);
}
private void verifyAutoAssignmentByActionType(final TargetFilterQuery tfq, final DistributionSet set,
final MgmtActionType actionType) throws Exception {
final MgmtActionType actionType, final Boolean confirmationRequired) throws Exception {
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
+ tfq.getId();
final String payload = actionType != null
? "{\"id\":" + set.getId() + ", \"type\":\"" + actionType.getName() + "\"}"
: "{\"id\":" + set.getId() + "}";
final JSONObject jsonObject = new JSONObject();
jsonObject.put("id", set.getId());
if (actionType != null) {
jsonObject.put("type", actionType.getName());
}
if (confirmationRequired != null) {
jsonObject.put("confirmationRequired", confirmationRequired);
}
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content(payload).contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk());
.content(jsonObject.toString()).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(tfq.getId()).get();
final MgmtActionType expectedActionType = actionType != null ? actionType : MgmtActionType.FORCED;
@@ -429,6 +481,10 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId())).andDo(print())
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(tfq.getName())))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(tfq.getQuery())))
.andExpect(isConfirmationFlowEnabled()
? jsonPath(JSON_PATH_CONFIRMATION_REQUIRED,
equalTo(confirmationRequired == null || confirmationRequired))
: jsonPath(JSON_PATH_CONFIRMATION_REQUIRED).doesNotExist())
.andExpect(jsonPath(JSON_PATH_AUTO_ASSIGN_DS, equalTo(set.getId().intValue())))
.andExpect(jsonPath(JSON_PATH_AUTO_ASSIGN_ACTION_TYPE, equalTo(expectedActionType.getName())))
.andExpect(jsonPath("$._links.self.href", equalTo(hrefPrefix)))
@@ -448,9 +504,9 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiInte
}
@Step
private void verifyAutoAssignmentWithDownloadOnlyActionType(final TargetFilterQuery tfq, final DistributionSet set)
throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.DOWNLOAD_ONLY);
private void verifyAutoAssignmentWithDownloadOnlyActionType(final TargetFilterQuery tfq, final DistributionSet set,
final Boolean confirmationRequired) throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.DOWNLOAD_ONLY, confirmationRequired);
}
@Step

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants.TARGET_V1_AUTO_CONFIRM;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
@@ -36,6 +37,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.validation.ConstraintViolationException;
@@ -73,6 +75,9 @@ import org.hamcrest.Matchers;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.data.domain.PageRequest;
@@ -764,9 +769,10 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
final Target test1 = entityFactory.target().create().controllerId("id1")
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1)).build();
final MvcResult mvcResult = mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)
.content(JsonBuilder.targets(Collections.singletonList(test1), true))
.contentType(MediaType.APPLICATION_JSON))
final MvcResult mvcResult = mvc
.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)
.content(JsonBuilder.targets(Collections.singletonList(test1), true))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn();
assertThat(targetManagement.count()).isZero();
@@ -1253,8 +1259,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
// Update
if (schedule == null) {
final List<Target> updatedTargets = assignDistributionSet(one, Collections.singletonList(target))
.getAssignedEntity()
.stream().map(Action::getTarget).collect(Collectors.toList());
.getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
// 2nd update
// sleep 10ms to ensure that we can sort by reportedAt
Awaitility.await().atMost(Duration.ONE_HUNDRED_MILLISECONDS).atLeast(5, TimeUnit.MILLISECONDS)
@@ -1336,6 +1341,48 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
assertThat(targetManagement.getByControllerID(target.getControllerId()).get()).isEqualTo(target);
}
@ParameterizedTest
@MethodSource("confirmationOptions")
@Description("Ensures that confirmation option is considered in assignment request.")
void assignDistributionSetToTargetWithConfirmationOptions(final boolean confirmationFlowActive,
final Boolean confirmationRequired) throws Exception {
final Target target = testdataFactory.createTarget();
final DistributionSet set = testdataFactory.createDistributionSet("one");
if (confirmationFlowActive) {
enableConfirmationFlow();
}
final JSONObject jsonPayload = new JSONObject();
jsonPayload.put("id", set.getId());
if (confirmationRequired != null) {
jsonPayload.put("confirmationRequired", confirmationRequired);
}
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + target.getControllerId() + "/assignedDS")
.content(jsonPayload.toString()).contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("assigned", equalTo(1))).andExpect(jsonPath("alreadyAssigned", equalTo(0)))
.andExpect(jsonPath("total", equalTo(1)));
assertThat(deploymentManagement.getAssignedDistributionSet(target.getControllerId()).get()).isEqualTo(set);
assertThat(deploymentManagement.findActionsByDistributionSet(PAGE, set.getId()).getContent()).hasSize(1)
.allMatch(action -> {
if (!confirmationFlowActive) {
return !action.isWaitingConfirmation();
}
return confirmationRequired == null ? action.isWaitingConfirmation()
: confirmationRequired == action.isWaitingConfirmation();
});
}
private static Stream<Arguments> confirmationOptions() {
return Stream.of(Arguments.of(true, true), Arguments.of(true, false), Arguments.of(false, true),
Arguments.of(false, false), Arguments.of(true, null), Arguments.of(false, null));
}
@Test
@Description("Verfies that a DOWNLOAD_ONLY DS to target assignment is properly handled")
void assignDownloadOnlyDistributionSetToTarget() throws Exception {
@@ -2003,9 +2050,9 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
final JSONObject bodyValid = getAssignmentObject(dsId, MgmtActionType.FORCED, 98);
mvc.perform(post("/rest/v1/targets/{targetId}/assignedDS", targetId).content(bodyValid.toString())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.multiassignmentNotEnabled")));
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.multiassignmentNotEnabled")));
}
@Test
@@ -2057,7 +2104,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
}
}
@Test
@Description("An action provides information of the rollout it was created for (if any).")
void getActionWithRolloutInfo() throws Exception {
@@ -2094,8 +2141,10 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
@Test
@Description("Ensures that a post request for creating targets with target type works.")
void createTargetsWithTargetType() throws Exception {
final TargetType type1 = testdataFactory.createTargetType("typeWithDs", Collections.singletonList(standardDsType));
final TargetType type2 = testdataFactory.createTargetType("typeWithOutDs", Collections.singletonList(standardDsType));
final TargetType type1 = testdataFactory.createTargetType("typeWithDs",
Collections.singletonList(standardDsType));
final TargetType type2 = testdataFactory.createTargetType("typeWithOutDs",
Collections.singletonList(standardDsType));
final Target test1 = entityFactory.target().create().controllerId("id1").name("targetWithoutType")
.securityToken("token").address("amqp://test123/foobar").description("testid1").build();
@@ -2132,8 +2181,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("[2].description", equalTo("testid3")))
.andExpect(jsonPath("[2].createdAt", not(equalTo(0))))
.andExpect(jsonPath("[2].createdBy", equalTo("bumlux")))
.andExpect(jsonPath("[2].targetType", equalTo(type2.getId().intValue())))
.andReturn();
.andExpect(jsonPath("[2].targetType", equalTo(type2.getId().intValue()))).andReturn();
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + test2.getControllerId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -2159,10 +2207,11 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
@Description("Ensures that a post request for creating target with target type works.")
void createTargetWithExistingTargetType() throws Exception {
// create target type
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype",1);
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype", 1);
assertThat(targetTypes).hasSize(1);
final Target target = entityFactory.target().create().controllerId("targetcontroller").name("testtarget").targetType(targetTypes.get(0).getId()).build();
final Target target = entityFactory.target().create().controllerId("targetcontroller").name("testtarget")
.targetType(targetTypes.get(0).getId()).build();
final String targetList = JsonBuilder.targets(Collections.singletonList(target), false);
@@ -2172,14 +2221,15 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
.andExpect(jsonPath("[0].controllerId", equalTo("targetcontroller")))
.andExpect(jsonPath("[0].targetType", equalTo(targetTypes.get(0).getId().intValue())));
assertThat(targetManagement.getByControllerID("targetcontroller").get().getTargetType().getId()).isEqualTo(targetTypes.get(0).getId());
assertThat(targetManagement.getByControllerID("targetcontroller").get().getTargetType().getId())
.isEqualTo(targetTypes.get(0).getId());
}
@Test
@Description("Ensures that a put request for updating targets with target type works.")
void updateTargetTypeInTarget() throws Exception {
// create target type
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype",2);
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype", 2);
assertThat(targetTypes).hasSize(2);
String controllerId = "targetcontroller";
@@ -2234,7 +2284,8 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
.content("{\"id\":" + targetType.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(targetManagement.getByControllerID(targetControllerId).get().getTargetType().getId()).isEqualTo(targetType.getId());
assertThat(targetManagement.getByControllerID(targetControllerId).get().getTargetType().getId())
.isEqualTo(targetType.getId());
}
@Test
@@ -2254,8 +2305,10 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
// verify response json exception message if body does not include id field
final MvcResult mvcResult = mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetControllerId + "/targettype")
.content("{\"unknownfield\":" + invalidTargetTypeId + "}").contentType(MediaType.APPLICATION_JSON))
final MvcResult mvcResult = mvc
.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetControllerId + "/targettype")
.content("{\"unknownfield\":" + invalidTargetTypeId + "}")
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn();
final ExceptionInfo exceptionInfo = ResourceUtility
.convertException(mvcResult.getResponse().getContentAsString());
@@ -2268,7 +2321,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
@Description("Ensures that a delete request for unassign target type from target works.")
void unassignTargetTypeFromTarget() throws Exception {
// create target type
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype",1);
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype", 1);
assertThat(targetTypes).hasSize(1);
String targetControllerId = "targetcontroller";
@@ -2296,24 +2349,24 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
knownTargetId)).andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
// PUT is not allowed
mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING
+ MgmtRestConstants.TARGET_TARGET_TYPE_V1_REQUEST_MAPPING, knownTargetId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
mvc.perform(put(
MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + MgmtRestConstants.TARGET_TARGET_TYPE_V1_REQUEST_MAPPING,
knownTargetId)).andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
// POST does not exist with path parameter targettype
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING
+ MgmtRestConstants.TARGET_TARGET_TYPE_V1_REQUEST_MAPPING + "/123", knownTargetId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
// DELETE does not exist with path parameter targettype
// DELETE does not exist with path parameter targettype
mvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING
+ MgmtRestConstants.TARGET_TARGET_TYPE_V1_REQUEST_MAPPING + "/123", knownTargetId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
// Invalid content
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + MgmtRestConstants.TARGET_TARGET_TYPE_V1_REQUEST_MAPPING,
knownTargetId)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isUnsupportedMediaType());
mvc.perform(post(
MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + MgmtRestConstants.TARGET_TARGET_TYPE_V1_REQUEST_MAPPING,
knownTargetId)).andDo(MockMvcResultPrinter.print()).andExpect(status().isUnsupportedMediaType());
// Bad request if id field is missing
mvc.perform(post(
@@ -2321,4 +2374,87 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
knownTargetId).content("{\"unknownfield\":123}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
}
@ParameterizedTest
@MethodSource("possibleActiveStates")
void getAutoConfirmActive(final String initiator, final String remark) throws Exception {
final String knownTargetId = "targetId";
testdataFactory.createTarget(knownTargetId);
confirmationManagement.activateAutoConfirmation(knownTargetId, initiator, remark);
// GET with all possible responses
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/" + TARGET_V1_AUTO_CONFIRM,
knownTargetId)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("active", equalTo(Boolean.TRUE)))
.andExpect(initiator == null ? jsonPath("initiator").doesNotExist()
: jsonPath("initiator", equalTo(initiator)))
.andExpect(remark == null ? jsonPath("remark").doesNotExist() : jsonPath("remark", equalTo(remark)))
.andExpect(jsonPath("_links.deactivate").exists())
.andExpect(jsonPath("_links.activate").doesNotExist());
}
@Test
void getAutoConfirmStateFromTargetsEndpoint() throws Exception {
final String knownTargetId = "targetId";
testdataFactory.createTarget(knownTargetId);
// GET if active
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("content.[0].autoConfirmActive").doesNotExist());
enableConfirmationFlow();
// GET if not active
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("content.[0].autoConfirmActive", equalTo(Boolean.FALSE)));
confirmationManagement.activateAutoConfirmation(knownTargetId, "test", "remark");
// GET if active
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("content.[0].autoConfirmActive", equalTo(Boolean.TRUE)));
}
@Test
void getAutoConfirmNotActive() throws Exception {
final String knownTargetId = "targetId";
// GET for not existing target
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/" + TARGET_V1_AUTO_CONFIRM,
knownTargetId)).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
testdataFactory.createTarget(knownTargetId);
// GET for auto-confirm not active
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/" + TARGET_V1_AUTO_CONFIRM,
knownTargetId)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("active", equalTo(Boolean.FALSE))).andExpect(jsonPath("initiator").doesNotExist())
.andExpect(jsonPath("remark").doesNotExist()).andExpect(jsonPath("_links.activate").exists());
}
@Test
void autoConfirmStateReferenceOnTarget() throws Exception {
final String knownTargetId = "targetId";
testdataFactory.createTarget(knownTargetId);
// GET with confirmation flow not active should not expose
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", knownTargetId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("autoConfirmActive").doesNotExist())
.andExpect(jsonPath("_links.autoConfirm").doesNotExist());
enableConfirmationFlow();
// GET with confirmation flow active should expose
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", knownTargetId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("autoConfirmActive").exists()).andExpect(jsonPath("_links.autoConfirm").exists());
}
private static Stream<Arguments> possibleActiveStates() {
return Stream.of(Arguments.of("someInitiator", "someRemark"), Arguments.of(null, "someRemark"),
Arguments.of("someInitiator", null), Arguments.of(null, null));
}
}