Move Mgmt artifacts into hawkbit-mgmt (#2003)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class MgmtActionMapper {
|
||||
|
||||
/**
|
||||
* Create a response for actions.
|
||||
*
|
||||
* @param actions list of actions
|
||||
* @param repMode the representation mode
|
||||
* @return the response
|
||||
*/
|
||||
public static List<MgmtAction> toResponse(final Collection<Action> actions, final MgmtRepresentationMode repMode) {
|
||||
if (actions == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ResponseList<>(actions.stream()
|
||||
.map(action -> toResponse(action, repMode))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtAction toResponse(final Action action, final MgmtRepresentationMode repMode) {
|
||||
final String controllerId = action.getTarget().getControllerId();
|
||||
if (repMode == MgmtRepresentationMode.COMPACT) {
|
||||
return MgmtTargetMapper.toResponse(controllerId, action);
|
||||
}
|
||||
return MgmtTargetMapper.toResponseWithLinks(controllerId, action);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtActionRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@ConditionalOnProperty(name = "hawkbit.rest.MgmtActionResource.enabled", matchIfMissing = true)
|
||||
public class MgmtActionResource implements MgmtActionRestApi {
|
||||
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
|
||||
MgmtActionResource(final DeploymentManagement deploymentManagement) {
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtAction>> getActions(final int pagingOffsetParam, final int pagingLimitParam,
|
||||
final String sortParam, final String rsqlParam, final String representationModeParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeActionSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<Action> actions;
|
||||
final Long totalActionCount;
|
||||
if (rsqlParam != null) {
|
||||
actions = this.deploymentManagement.findActions(rsqlParam, pageable);
|
||||
totalActionCount = this.deploymentManagement.countActions(rsqlParam);
|
||||
} else {
|
||||
actions = this.deploymentManagement.findActionsAll(pageable);
|
||||
totalActionCount = this.deploymentManagement.countActionsAll();
|
||||
}
|
||||
|
||||
final MgmtRepresentationMode repMode = getRepresentationModeFromString(representationModeParam);
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtActionMapper.toResponse(actions.getContent(), repMode), totalActionCount));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtAction> getAction(final Long actionId) {
|
||||
|
||||
final Action action = deploymentManagement.findAction(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
|
||||
return ResponseEntity.ok(MgmtActionMapper.toResponse(action, MgmtRepresentationMode.FULL));
|
||||
}
|
||||
|
||||
private MgmtRepresentationMode getRepresentationModeFromString(final String representationModeParam) {
|
||||
return MgmtRepresentationMode.fromValue(representationModeParam)
|
||||
.orElseGet(() -> {
|
||||
// no need for a 400, just apply a safe fallback
|
||||
log.warn("Received an invalid representation mode: {}", representationModeParam);
|
||||
return MgmtRepresentationMode.COMPACT;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.rest.OpenApiConfiguration;
|
||||
import org.eclipse.hawkbit.rest.RestConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
/**
|
||||
* Enable {@link ComponentScan} in the resource package to setup all
|
||||
* {@link Controller} annotated classes and setup the REST-Resources for the
|
||||
* Management API.
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@Import({ RestConfiguration.class, OpenApiConfiguration.class })
|
||||
@PropertySource("classpath:/hawkbit-mgmt-api-defaults.properties")
|
||||
public class MgmtApiConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.auth.MgmtUserInfo;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtBasicAuthRestApi;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling basic auth validation.
|
||||
*/
|
||||
@RestController
|
||||
public class MgmtBasicAuthResource implements MgmtBasicAuthRestApi {
|
||||
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param tenantAware tenantAware
|
||||
*/
|
||||
public MgmtBasicAuthResource(TenantAware tenantAware) {
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtUserInfo> validateBasicAuth() {
|
||||
MgmtUserInfo userInfo = new MgmtUserInfo();
|
||||
userInfo.setUsername(tenantAware.getCurrentUsername());
|
||||
userInfo.setTenant(tenantAware.getCurrentTenant());
|
||||
return ResponseEntity.ok(userInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindowRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentRequestBody;
|
||||
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.DeploymentRequestBuilder;
|
||||
|
||||
/**
|
||||
* A mapper for assignment requests
|
||||
*/
|
||||
public final class MgmtDeploymentRequestMapper {
|
||||
|
||||
private MgmtDeploymentRequestMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert assignment information to an {@link DeploymentRequestBuilder}
|
||||
*
|
||||
* @param dsAssignment DS assignment information
|
||||
* @param targetId target to assign the DS to
|
||||
* @return resulting {@link DeploymentRequestBuilder}
|
||||
*/
|
||||
public static DeploymentRequestBuilder createAssignmentRequestBuilder(
|
||||
final MgmtDistributionSetAssignment dsAssignment, final String targetId) {
|
||||
|
||||
return createAssignmentRequestBuilder(targetId, dsAssignment.getId(), dsAssignment.getType(),
|
||||
dsAssignment.getForcetime(), dsAssignment.getWeight(), dsAssignment.getMaintenanceWindow());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert assignment information to an {@link DeploymentRequestBuilder}
|
||||
*
|
||||
* @param targetAssignment target assignment information
|
||||
* @param dsId DS to assign the target to
|
||||
* @return resulting {@link DeploymentRequestBuilder}
|
||||
*/
|
||||
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 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)
|
||||
.setActionType(MgmtRestModelMapper.convertActionType(type)).setForceTime(forcetime).setWeight(weight);
|
||||
if (maintenanceWindow != null) {
|
||||
final String cronSchedule = maintenanceWindow.getSchedule();
|
||||
final String duration = maintenanceWindow.getDuration();
|
||||
final String timezone = maintenanceWindow.getTimezone();
|
||||
MaintenanceScheduleHelper.validateMaintenanceSchedule(cronSchedule, duration, timezone);
|
||||
request.setMaintenance(cronSchedule, duration, timezone);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionId;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.MetaData;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class MgmtDistributionSetMapper {
|
||||
|
||||
/**
|
||||
* {@link MgmtDistributionSetRequestBodyPost}s to {@link DistributionSet}s.
|
||||
*
|
||||
* @param sets to convert
|
||||
* @return converted list of {@link DistributionSet}s
|
||||
*/
|
||||
static List<DistributionSetCreate> dsFromRequest(final Collection<MgmtDistributionSetRequestBodyPost> sets,
|
||||
final EntityFactory entityFactory) {
|
||||
return sets.stream().map(dsRest -> fromRequest(dsRest, entityFactory)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MetaData> fromRequestDsMetadata(final List<MgmtMetadata> metadata, final EntityFactory entityFactory) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return metadata.stream()
|
||||
.map(metadataRest -> entityFactory.generateDsMetadata(metadataRest.getKey(), metadataRest.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtDistributionSet toResponse(final DistributionSet distributionSet) {
|
||||
if (distributionSet == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final MgmtDistributionSet response = new MgmtDistributionSet();
|
||||
MgmtRestModelMapper.mapNamedToNamed(response, distributionSet);
|
||||
|
||||
response.setDsId(distributionSet.getId());
|
||||
response.setVersion(distributionSet.getVersion());
|
||||
response.setComplete(distributionSet.isComplete());
|
||||
response.setType(distributionSet.getType().getKey());
|
||||
response.setTypeName(distributionSet.getType().getName());
|
||||
response.setLocked(distributionSet.isLocked());
|
||||
response.setDeleted(distributionSet.isDeleted());
|
||||
response.setValid(distributionSet.isValid());
|
||||
|
||||
distributionSet.getModules()
|
||||
.forEach(module -> response.getModules().add(MgmtSoftwareModuleMapper.toResponse(module)));
|
||||
|
||||
response.setRequiredMigrationStep(distributionSet.isRequiredMigrationStep());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(response.getDsId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void addLinks(final DistributionSet distributionSet, final MgmtDistributionSet response) {
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getAssignedSoftwareModules(response.getDsId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null))
|
||||
.withRel(MgmtRestConstants.DISTRIBUTIONSET_V1_MODULE).expand());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class)
|
||||
.getDistributionSetType(distributionSet.getType().getId())).withRel("type").expand());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getMetadata(response.getDsId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("metadata")
|
||||
.expand());
|
||||
}
|
||||
|
||||
static MgmtTargetAssignmentResponseBody toResponse(final DistributionSetAssignmentResult dsAssignmentResult) {
|
||||
final MgmtTargetAssignmentResponseBody result = new MgmtTargetAssignmentResponseBody();
|
||||
result.setAlreadyAssigned(dsAssignmentResult.getAlreadyAssigned());
|
||||
result.setAssignedActions(dsAssignmentResult.getAssignedEntity().stream()
|
||||
.map(a -> new MgmtActionId(a.getTarget().getControllerId(), a.getId())).collect(Collectors.toList()));
|
||||
return result;
|
||||
}
|
||||
|
||||
static MgmtTargetAssignmentResponseBody toResponse(
|
||||
final List<DistributionSetAssignmentResult> dsAssignmentResults) {
|
||||
final MgmtTargetAssignmentResponseBody result = new MgmtTargetAssignmentResponseBody();
|
||||
final int alreadyAssigned = dsAssignmentResults.stream()
|
||||
.mapToInt(DistributionSetAssignmentResult::getAlreadyAssigned).sum();
|
||||
final List<MgmtActionId> assignedActions = dsAssignmentResults.stream()
|
||||
.flatMap(assignmentResult -> assignmentResult.getAssignedEntity().stream())
|
||||
.map(action -> new MgmtActionId(action.getTarget().getControllerId(), action.getId()))
|
||||
.collect(Collectors.toList());
|
||||
result.setAlreadyAssigned(alreadyAssigned);
|
||||
result.setAssignedActions(assignedActions);
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<MgmtDistributionSet> toResponseDistributionSets(final Collection<DistributionSet> sets) {
|
||||
if (sets == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ResponseList<>(
|
||||
sets.stream().map(MgmtDistributionSetMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtMetadata toResponseDsMetadata(final DistributionSetMetadata metadata) {
|
||||
final MgmtMetadata metadataRest = new MgmtMetadata();
|
||||
metadataRest.setKey(metadata.getKey());
|
||||
metadataRest.setValue(metadata.getValue());
|
||||
return metadataRest;
|
||||
}
|
||||
|
||||
static List<MgmtMetadata> toResponseDsMetadata(final List<DistributionSetMetadata> metadata) {
|
||||
final List<MgmtMetadata> mappedList = new ArrayList<>(metadata.size());
|
||||
for (final DistributionSetMetadata distributionSetMetadata : metadata) {
|
||||
mappedList.add(toResponseDsMetadata(distributionSetMetadata));
|
||||
}
|
||||
return mappedList;
|
||||
}
|
||||
|
||||
static List<MgmtDistributionSet> toResponseFromDsList(final List<DistributionSet> sets) {
|
||||
if (sets == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return sets.stream().map(MgmtDistributionSetMapper::toResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MgmtDistributionSetRequestBodyPost} to {@link DistributionSet}.
|
||||
*
|
||||
* @param dsRest to convert
|
||||
* @return converted {@link DistributionSet}
|
||||
*/
|
||||
private static DistributionSetCreate fromRequest(final MgmtDistributionSetRequestBodyPost dsRest,
|
||||
final EntityFactory entityFactory) {
|
||||
final List<Long> modules = new ArrayList<>();
|
||||
if (dsRest.getOs() != null) {
|
||||
modules.add(dsRest.getOs().getId());
|
||||
}
|
||||
if (dsRest.getApplication() != null) {
|
||||
modules.add(dsRest.getApplication().getId());
|
||||
}
|
||||
if (dsRest.getRuntime() != null) {
|
||||
modules.add(dsRest.getRuntime().getId());
|
||||
}
|
||||
if (dsRest.getModules() != null) {
|
||||
dsRest.getModules().forEach(module -> modules.add(module.getId()));
|
||||
}
|
||||
return entityFactory.distributionSet().create().name(dsRest.getName()).version(dsRest.getVersion())
|
||||
.description(dsRest.getDescription()).type(dsRest.getType()).modules(modules)
|
||||
.requiredMigrationStep(dsRest.getRequiredMigrationStep());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetStatistics;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtInvalidateDistributionSetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
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;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
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.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link DistributionSet} CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
||||
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
private final TargetManagement targetManagement;
|
||||
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
|
||||
private final DeploymentManagement deployManagament;
|
||||
|
||||
private final SystemManagement systemManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
|
||||
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 DistributionSetTypeManagement distributionSetTypeManagement, final SystemSecurityContext systemSecurityContext,
|
||||
final DistributionSetInvalidationManagement distributionSetInvalidationManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.targetManagement = targetManagement;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.deployManagament = deployManagament;
|
||||
this.systemManagement = systemManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.distributionSetInvalidationManagement = distributionSetInvalidationManagement;
|
||||
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtDistributionSet>> getDistributionSets(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeDistributionSetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Slice<DistributionSet> findDsPage;
|
||||
final long countModulesAll;
|
||||
if (rsqlParam != null) {
|
||||
findDsPage = distributionSetManagement.findByRsql(pageable, rsqlParam);
|
||||
countModulesAll = ((Page<DistributionSet>) findDsPage).getTotalElements();
|
||||
} else {
|
||||
findDsPage = distributionSetManagement.findAll(pageable);
|
||||
countModulesAll = distributionSetManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtDistributionSet> rest = MgmtDistributionSetMapper.toResponseFromDsList(findDsPage.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> getDistributionSet(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId) {
|
||||
final DistributionSet foundDs = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(foundDs);
|
||||
MgmtDistributionSetMapper.addLinks(foundDs, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtDistributionSet>> createDistributionSets(
|
||||
@RequestBody final List<MgmtDistributionSetRequestBodyPost> sets) {
|
||||
|
||||
log.debug("creating {} distribution sets", sets.size());
|
||||
// set default Ds type if ds type is null
|
||||
final String defaultDsKey = systemSecurityContext
|
||||
.runAsSystem(systemManagement.getTenantMetadata().getDefaultDsType()::getKey);
|
||||
sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(defaultDsKey));
|
||||
|
||||
//check if there is already deleted DS Type
|
||||
for (MgmtDistributionSetRequestBodyPost ds : sets) {
|
||||
final Optional<DistributionSetType> opt = distributionSetTypeManagement.getByKey(ds.getType());
|
||||
opt.ifPresent(dsType -> {
|
||||
if (dsType.isDeleted()) {
|
||||
final String text = "Cannot create Distribution Set from type with key {0}. Distribution Set Type already deleted!";
|
||||
final String message = MessageFormat.format(text, dsType.getKey());
|
||||
throw new ValidationException(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final Collection<DistributionSet> createdDSets = distributionSetManagement
|
||||
.create(MgmtDistributionSetMapper.dsFromRequest(sets, entityFactory));
|
||||
|
||||
log.debug("{} distribution sets created, return status {}", sets.size(), HttpStatus.CREATED);
|
||||
return new ResponseEntity<>(MgmtDistributionSetMapper.toResponseDistributionSets(createdDSets),
|
||||
HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteDistributionSet(@PathVariable("distributionSetId") final Long distributionSetId) {
|
||||
distributionSetManagement.delete(distributionSetId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> updateDistributionSet(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestBody final MgmtDistributionSetRequestBodyPut toUpdate) {
|
||||
final DistributionSet updated = distributionSetManagement.update(entityFactory.distributionSet()
|
||||
.update(distributionSetId).name(toUpdate.getName()).description(toUpdate.getDescription())
|
||||
.version(toUpdate.getVersion()).locked(toUpdate.getLocked())
|
||||
.requiredMigrationStep(toUpdate.getRequiredMigrationStep()));
|
||||
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(updated);
|
||||
MgmtDistributionSetMapper.addLinks(updated, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getAssignedTargets(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<Target> targetsAssignedDS;
|
||||
if (rsqlParam != null) {
|
||||
targetsAssignedDS = this.targetManagement.findByAssignedDistributionSetAndRsql(pageable, distributionSetId,
|
||||
rsqlParam);
|
||||
} else {
|
||||
targetsAssignedDS = this.targetManagement.findByAssignedDistributionSet(pageable, distributionSetId);
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtTargetMapper.toResponse(targetsAssignedDS.getContent(), tenantConfigHelper),
|
||||
targetsAssignedDS.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getInstalledTargets(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<Target> targetsInstalledDS;
|
||||
if (rsqlParam != null) {
|
||||
targetsInstalledDS = this.targetManagement.findByInstalledDistributionSetAndRsql(pageable,
|
||||
distributionSetId, rsqlParam);
|
||||
} else {
|
||||
targetsInstalledDS = this.targetManagement.findByInstalledDistributionSet(pageable, distributionSetId);
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtTargetMapper.toResponse(targetsInstalledDS.getContent(), tenantConfigHelper),
|
||||
targetsInstalledDS.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTargetFilterQuery>> getAutoAssignTargetFilterQueries(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetFilterQuerySortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<TargetFilterQuery> targetFilterQueries = targetFilterQueryManagement
|
||||
.findByAutoAssignDSAndRsql(pageable, distributionSetId, rsqlParam);
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtTargetFilterQueryMapper.toResponse(targetFilterQueries.getContent(),
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), false), targetFilterQueries.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetAssignmentResponseBody> createAssignedTarget(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestBody final List<MgmtTargetAssignmentRequestBody> assignments,
|
||||
@RequestParam(value = "offline", required = false) final Boolean offline) {
|
||||
if (offline != null && offline) {
|
||||
final List<Entry<String, Long>> offlineAssignments = assignments.stream()
|
||||
.map(assignment -> new SimpleEntry<>(assignment.getId(), distributionSetId))
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper
|
||||
.toResponse(deployManagament.offlineAssignedDistributionSets(offlineAssignments)));
|
||||
}
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = assignments.stream().map(dsAssignment -> {
|
||||
final boolean isConfirmationRequired = dsAssignment.getConfirmationRequired() == null
|
||||
? tenantConfigHelper.isConfirmationFlowEnabled()
|
||||
: dsAssignment.getConfirmationRequired();
|
||||
return MgmtDeploymentRequestMapper.createAssignmentRequestBuilder(dsAssignment, distributionSetId)
|
||||
.setConfirmationRequired(isConfirmationRequired).build();
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
final List<DistributionSetAssignmentResult> assignmentResults = deployManagament
|
||||
.assignDistributionSets(deploymentRequests);
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponse(assignmentResults));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtMetadata>> getMetadata(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeDistributionSetMetadataSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<DistributionSetMetadata> metaDataPage;
|
||||
|
||||
if (rsqlParam != null) {
|
||||
metaDataPage = distributionSetManagement.findMetaDataByDistributionSetIdAndRsql(pageable, distributionSetId,
|
||||
rsqlParam);
|
||||
} else {
|
||||
metaDataPage = distributionSetManagement.findMetaDataByDistributionSetId(pageable, distributionSetId);
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtDistributionSetMapper.toResponseDsMetadata(metaDataPage.getContent()),
|
||||
metaDataPage.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtMetadata> getMetadataValue(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
final DistributionSetMetadata findOne = distributionSetManagement
|
||||
.getMetaDataByDistributionSetId(distributionSetId, metadataKey)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetMetadata.class, distributionSetId,
|
||||
metadataKey));
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDsMetadata(findOne));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadataBodyPut metadata) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
final DistributionSetMetadata updated = distributionSetManagement.updateMetaData(distributionSetId,
|
||||
entityFactory.generateDsMetadata(metadataKey, metadata.getValue()));
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDsMetadata(updated));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteMetadata(@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
distributionSetManagement.deleteMetaData(distributionSetId, metadataKey);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtMetadata>> createMetadata(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestBody final List<MgmtMetadata> metadataRest) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
final List<DistributionSetMetadata> created = distributionSetManagement.createMetaData(distributionSetId,
|
||||
MgmtDistributionSetMapper.fromRequestDsMetadata(metadataRest, entityFactory));
|
||||
return new ResponseEntity<>(MgmtDistributionSetMapper.toResponseDsMetadata(created), HttpStatus.CREATED);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignSoftwareModules(@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestBody final List<MgmtSoftwareModuleAssigment> softwareModuleIDs) {
|
||||
|
||||
distributionSetManagement.assignSoftwareModules(distributionSetId,
|
||||
softwareModuleIDs.stream().map(MgmtSoftwareModuleAssigment::getId).collect(Collectors.toList()));
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteAssignSoftwareModules(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId) {
|
||||
distributionSetManagement.unassignSoftwareModule(distributionSetId, softwareModuleId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtSoftwareModule>> getAssignedSoftwareModules(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeSoftwareModuleSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<SoftwareModule> softwaremodules = softwareModuleManagement.findByAssignedTo(pageable,
|
||||
distributionSetId);
|
||||
return ResponseEntity.ok(new PagedList<>(MgmtSoftwareModuleMapper.toResponse(softwaremodules.getContent()),
|
||||
softwaremodules.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetStatistics> getRolloutsCountByStatusForDistributionSet(Long distributionSetId) {
|
||||
MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(false);
|
||||
distributionSetManagement.countRolloutsByStatusForDistributionSet(distributionSetId).forEach(statistic ->
|
||||
statistics.addTotalRolloutPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString())));
|
||||
return ResponseEntity.ok(statistics.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetStatistics> getActionsCountByStatusForDistributionSet(Long distributionSetId) {
|
||||
MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(false);
|
||||
distributionSetManagement.countActionsByStatusForDistributionSet(distributionSetId).forEach(statistic ->
|
||||
statistics.addTotalActionPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString())));
|
||||
return ResponseEntity.ok(statistics.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetStatistics> getAutoAssignmentsCountForDistributionSet(Long distributionSetId) {
|
||||
MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(false);
|
||||
statistics.addTotalAutoAssignments(distributionSetManagement.countAutoAssignmentsForDistributionSet(distributionSetId));
|
||||
return ResponseEntity.ok(statistics.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetStatistics> getStatisticsForDistributionSet(Long distributionSetId) {
|
||||
MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(true);
|
||||
distributionSetManagement.countRolloutsByStatusForDistributionSet(distributionSetId).forEach(statistic ->
|
||||
statistics.addTotalRolloutPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString())));
|
||||
distributionSetManagement.countActionsByStatusForDistributionSet(distributionSetId).forEach(statistic ->
|
||||
statistics.addTotalActionPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString())));
|
||||
statistics.addTotalAutoAssignments(distributionSetManagement.countAutoAssignmentsForDistributionSet(distributionSetId));
|
||||
return ResponseEntity.ok(statistics.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> invalidateDistributionSet(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@Valid @RequestBody final MgmtInvalidateDistributionSetRequestBody invalidateRequestBody) {
|
||||
distributionSetInvalidationManagement
|
||||
.invalidateDistributionSet(new DistributionSetInvalidation(Arrays.asList(distributionSetId),
|
||||
MgmtRestModelMapper.convertCancelationType(invalidateRequestBody.getActionCancelationType()),
|
||||
invalidateRequestBody.isCancelRollouts()));
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedDistributionSetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtDistributionSetTagAssigmentResult;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link DistributionSetTag} CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRestApi {
|
||||
|
||||
private final DistributionSetTagManagement distributionSetTagManagement;
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtDistributionSetTagResource(final DistributionSetTagManagement distributionSetTagManagement,
|
||||
final DistributionSetManagement distributionSetManagement, final EntityFactory entityFactory) {
|
||||
this.distributionSetTagManagement = distributionSetTagManagement;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTag>> getDistributionSetTags(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTagSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Slice<DistributionSetTag> distributionSetTags;
|
||||
final long count;
|
||||
if (rsqlParam == null) {
|
||||
distributionSetTags = distributionSetTagManagement.findAll(pageable);
|
||||
count = distributionSetTagManagement.count();
|
||||
|
||||
} else {
|
||||
final Page<DistributionSetTag> page = distributionSetTagManagement.findByRsql(pageable, rsqlParam);
|
||||
distributionSetTags = page;
|
||||
count = page.getTotalElements();
|
||||
|
||||
}
|
||||
|
||||
final List<MgmtTag> rest = MgmtTagMapper.toResponseDistributionSetTag(distributionSetTags.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, count));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTag> getDistributionSetTag(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId) {
|
||||
final DistributionSetTag distributionSetTag = findDistributionTagById(distributionsetTagId);
|
||||
|
||||
final MgmtTag response = MgmtTagMapper.toResponse(distributionSetTag);
|
||||
MgmtTagMapper.addLinks(distributionSetTag, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTag>> createDistributionSetTags(
|
||||
@RequestBody final List<MgmtTagRequestBodyPut> tags) {
|
||||
log.debug("creating {} ds tags", tags.size());
|
||||
|
||||
final List<DistributionSetTag> createdTags = distributionSetTagManagement
|
||||
.create(MgmtTagMapper.mapTagFromRequest(entityFactory, tags));
|
||||
|
||||
return new ResponseEntity<>(MgmtTagMapper.toResponseDistributionSetTag(createdTags), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTag> updateDistributionSetTag(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestBody final MgmtTagRequestBodyPut restDSTagRest) {
|
||||
|
||||
final DistributionSetTag distributionSetTag = distributionSetTagManagement
|
||||
.update(entityFactory.tag().update(distributionsetTagId).name(restDSTagRest.getName())
|
||||
.description(restDSTagRest.getDescription()).colour(restDSTagRest.getColour()));
|
||||
|
||||
final MgmtTag response = MgmtTagMapper.toResponse(distributionSetTag);
|
||||
MgmtTagMapper.addLinks(distributionSetTag, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteDistributionSetTag(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId) {
|
||||
log.debug("Delete {} distribution set tag", distributionsetTagId);
|
||||
final DistributionSetTag tag = findDistributionTagById(distributionsetTagId);
|
||||
|
||||
distributionSetTagManagement.delete(tag.getName());
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtDistributionSet>> getAssignedDistributionSets(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTagSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
Page<DistributionSet> findDistrAll;
|
||||
if (rsqlParam == null) {
|
||||
findDistrAll = distributionSetManagement.findByTag(pageable, distributionsetTagId);
|
||||
|
||||
} else {
|
||||
findDistrAll = distributionSetManagement.findByRsqlAndTag(pageable, rsqlParam, distributionsetTagId);
|
||||
}
|
||||
|
||||
final List<MgmtDistributionSet> rest = MgmtDistributionSetMapper
|
||||
.toResponseFromDsList(findDistrAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, findDistrAll.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignDistributionSet(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@PathVariable("distributionsetId") final Long distributionsetId) {
|
||||
log.debug("Assign ds {} for ds tag {}", distributionsetId, distributionsetTagId);
|
||||
this.distributionSetManagement.assignTag(List.of(distributionsetId), distributionsetTagId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignDistributionSets(
|
||||
final Long distributionsetTagId,
|
||||
final List<Long> distributionsetIds) {
|
||||
log.debug("Assign DistributionSet {} for ds tag {}", distributionsetIds.size(), distributionsetTagId);
|
||||
final List<DistributionSet> assignedDs = this.distributionSetManagement
|
||||
.assignTag(distributionsetIds, distributionsetTagId);
|
||||
log.debug("Assigned DistributionSet {}", assignedDs.size());
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignDistributionSet(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@PathVariable("distributionsetId") final Long distributionsetId) {
|
||||
log.debug("Unassign ds {} for ds tag {}", distributionsetId, distributionsetTagId);
|
||||
this.distributionSetManagement.unassignTag(List.of(distributionsetId), distributionsetTagId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignDistributionSets(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestBody final List<Long> distributionsetIds) {
|
||||
log.debug("Unassign DistributionSet {} for ds tag {}", distributionsetIds.size(), distributionsetTagId);
|
||||
final List<DistributionSet> assignedDs = this.distributionSetManagement
|
||||
.unassignTag(distributionsetIds, distributionsetTagId);
|
||||
log.debug("Unassigned DistributionSet {}", assignedDs.size());
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetTagAssigmentResult> toggleTagAssignment(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestBody final List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies) {
|
||||
log.debug("Toggle distribution set assignment {} for ds tag {}", assignedDSRequestBodies.size(),
|
||||
distributionsetTagId);
|
||||
|
||||
final DistributionSetTag tag = findDistributionTagById(distributionsetTagId);
|
||||
|
||||
final DistributionSetTagAssignmentResult assigmentResult = this.distributionSetManagement
|
||||
.toggleTagAssignment(findDistributionSetIds(assignedDSRequestBodies), tag.getName());
|
||||
|
||||
final MgmtDistributionSetTagAssigmentResult tagAssigmentResultRest = new MgmtDistributionSetTagAssigmentResult();
|
||||
tagAssigmentResultRest.setAssignedDistributionSets(
|
||||
MgmtDistributionSetMapper.toResponseDistributionSets(assigmentResult.getAssignedEntity()));
|
||||
tagAssigmentResultRest.setUnassignedDistributionSets(
|
||||
MgmtDistributionSetMapper.toResponseDistributionSets(assigmentResult.getUnassignedEntity()));
|
||||
|
||||
log.debug("Toggled assignedDS {} and unassignedDS{}", assigmentResult.getAssigned(),
|
||||
assigmentResult.getUnassigned());
|
||||
|
||||
return ResponseEntity.ok(tagAssigmentResultRest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtDistributionSet>> assignDistributionSetsByRequestBody(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestBody final List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies) {
|
||||
log.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId);
|
||||
final List<DistributionSet> assignedDs = this.distributionSetManagement
|
||||
.assignTag(findDistributionSetIds(assignedDSRequestBodies), distributionsetTagId);
|
||||
log.debug("Assigned DistributionSet {}", assignedDs.size());
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDistributionSets(assignedDs));
|
||||
}
|
||||
|
||||
private static List<Long> findDistributionSetIds(
|
||||
final List<MgmtAssignedDistributionSetRequestBody> assignedDistributionSetRequestBodies) {
|
||||
return assignedDistributionSetRequestBodies.stream()
|
||||
.map(MgmtAssignedDistributionSetRequestBody::getDistributionSetId).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private DistributionSetTag findDistributionTagById(final Long distributionsetTagId) {
|
||||
return distributionSetTagManagement.get(distributionsetTagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, distributionsetTagId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeAssigment;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
final class MgmtDistributionSetTypeMapper {
|
||||
|
||||
// private constructor, utility class
|
||||
private MgmtDistributionSetTypeMapper() {
|
||||
|
||||
}
|
||||
|
||||
static List<DistributionSetTypeCreate> smFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtDistributionSetTypeRequestBodyPost> smTypesRest) {
|
||||
if (smTypesRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return smTypesRest.stream().map(smRest -> fromRequest(entityFactory, smRest)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtDistributionSetType> toListResponse(final Collection<DistributionSetType> types) {
|
||||
if (types == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ResponseList<>(
|
||||
types.stream().map(MgmtDistributionSetTypeMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtDistributionSetType toResponse(final DistributionSetType type) {
|
||||
final MgmtDistributionSetType result = new MgmtDistributionSetType();
|
||||
|
||||
MgmtRestModelMapper.mapTypeToType(result, type);
|
||||
result.setModuleId(type.getId());
|
||||
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getDistributionSetType(result.getModuleId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void addLinks(final MgmtDistributionSetType result) {
|
||||
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getMandatoryModules(result.getModuleId()))
|
||||
.withRel(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULES).expand());
|
||||
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getOptionalModules(result.getModuleId()))
|
||||
.withRel(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULES).expand());
|
||||
}
|
||||
|
||||
private static DistributionSetTypeCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtDistributionSetTypeRequestBodyPost smsRest) {
|
||||
return entityFactory.distributionSetType().create().key(smsRest.getKey()).name(smsRest.getName())
|
||||
.description(smsRest.getDescription()).colour(smsRest.getColour())
|
||||
.mandatory(getMandatoryModules(smsRest)).optional(getOptionalmodules(smsRest));
|
||||
}
|
||||
|
||||
private static Collection<Long> getMandatoryModules(final MgmtDistributionSetTypeRequestBodyPost smsRest) {
|
||||
return Optional.ofNullable(smsRest.getMandatorymodules()).map(
|
||||
modules -> modules.stream().map(MgmtSoftwareModuleTypeAssigment::getId).collect(Collectors.toList()))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private static Collection<Long> getOptionalmodules(final MgmtDistributionSetTypeRequestBodyPost smsRest) {
|
||||
return Optional.ofNullable(smsRest.getOptionalmodules()).map(
|
||||
modules -> modules.stream().map(MgmtSoftwareModuleTypeAssigment::getId).collect(Collectors.toList()))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.SoftwareModuleTypeNotInDistributionSetTypeException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link DistributionSetType} CRUD operations.
|
||||
*/
|
||||
@RestController
|
||||
public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeRestApi {
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtDistributionSetTypeResource(final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final EntityFactory entityFactory) {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtDistributionSetType>> getDistributionSetTypes(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeDistributionSetTypeSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<DistributionSetType> findModuleTypessAll;
|
||||
long countModulesAll;
|
||||
if (rsqlParam != null) {
|
||||
findModuleTypessAll = distributionSetTypeManagement.findByRsql(pageable, rsqlParam);
|
||||
countModulesAll = ((Page<DistributionSetType>) findModuleTypessAll).getTotalElements();
|
||||
} else {
|
||||
findModuleTypessAll = distributionSetTypeManagement.findAll(pageable);
|
||||
countModulesAll = distributionSetTypeManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtDistributionSetType> rest = MgmtDistributionSetTypeMapper
|
||||
.toListResponse(findModuleTypessAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetType> getDistributionSetType(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
|
||||
final MgmtDistributionSetType reponse = MgmtDistributionSetTypeMapper.toResponse(foundType);
|
||||
MgmtDistributionSetTypeMapper.addLinks(reponse);
|
||||
|
||||
return ResponseEntity.ok(reponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteDistributionSetType(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
distributionSetTypeManagement.delete(distributionSetTypeId);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetType> updateDistributionSetType(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@RequestBody final MgmtDistributionSetTypeRequestBodyPut restDistributionSetType) {
|
||||
|
||||
final DistributionSetType updated = distributionSetTypeManagement.update(entityFactory.distributionSetType()
|
||||
.update(distributionSetTypeId).description(restDistributionSetType.getDescription())
|
||||
.colour(restDistributionSetType.getColour()));
|
||||
|
||||
final MgmtDistributionSetType reponse = MgmtDistributionSetTypeMapper.toResponse(updated);
|
||||
MgmtDistributionSetTypeMapper.addLinks(reponse);
|
||||
|
||||
return ResponseEntity.ok(reponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtDistributionSetType>> createDistributionSetTypes(
|
||||
@RequestBody final List<MgmtDistributionSetTypeRequestBodyPost> distributionSetTypes) {
|
||||
|
||||
final List<DistributionSetType> createdSoftwareModules = distributionSetTypeManagement
|
||||
.create(MgmtDistributionSetTypeMapper.smFromRequest(entityFactory, distributionSetTypes));
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(MgmtDistributionSetTypeMapper.toListResponse(createdSoftwareModules));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModuleType>> getMandatoryModules(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toTypesResponse(foundType.getMandatoryModuleTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleType> getMandatoryModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
|
||||
|
||||
if (!foundType.containsMandatoryModuleType(foundSmType)) {
|
||||
throw new SoftwareModuleTypeNotInDistributionSetTypeException(softwareModuleTypeId, distributionSetTypeId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toResponse(foundSmType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleType> getOptionalModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
|
||||
|
||||
if (!foundType.containsOptionalModuleType(foundSmType)) {
|
||||
throw new SoftwareModuleTypeNotInDistributionSetTypeException(softwareModuleTypeId, distributionSetTypeId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toResponse(foundSmType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModuleType>> getOptionalModules(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toTypesResponse(foundType.getOptionalModuleTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> removeMandatoryModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
distributionSetTypeManagement.unassignSoftwareModuleType(distributionSetTypeId, softwareModuleTypeId);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> removeOptionalModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
|
||||
return removeMandatoryModule(distributionSetTypeId, softwareModuleTypeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> addMandatoryModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final MgmtId smtId) {
|
||||
|
||||
distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(distributionSetTypeId,
|
||||
Arrays.asList(smtId.getId()));
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> addOptionalModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final MgmtId smtId) {
|
||||
|
||||
distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(distributionSetTypeId,
|
||||
Arrays.asList(smtId.getId()));
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
private DistributionSetType findDistributionSetTypeWithExceptionIfNotFound(final Long distributionSetTypeId) {
|
||||
return distributionSetTypeManagement.get(distributionSetTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, distributionSetTypeId));
|
||||
}
|
||||
|
||||
private SoftwareModuleType findSoftwareModuleTypeWithExceptionIfNotFound(final Long softwareModuleTypeId) {
|
||||
|
||||
return softwareModuleTypeManagement.get(softwareModuleTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, softwareModuleTypeId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadArtifactRestApi;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNoLongerExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.rest.util.FileStreamingUtil;
|
||||
import org.eclipse.hawkbit.rest.util.HttpUtil;
|
||||
import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@Scope(value = WebApplicationContext.SCOPE_REQUEST)
|
||||
public class MgmtDownloadArtifactResource implements MgmtDownloadArtifactRestApi {
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
@Autowired
|
||||
private ArtifactManagement artifactManagement;
|
||||
|
||||
/**
|
||||
* Handles the GET request for downloading an artifact.
|
||||
*
|
||||
* @param softwareModuleId of the parent SoftwareModule
|
||||
* @param artifactId of the related Artifact
|
||||
* @return responseEntity with status ok if successful
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<InputStream> downloadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("artifactId") final Long artifactId) {
|
||||
|
||||
final SoftwareModule module = softwareModuleManagement.get(softwareModuleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId));
|
||||
if (module.isDeleted()) {
|
||||
throw new ArtifactBinaryNoLongerExistsException();
|
||||
}
|
||||
final Artifact artifact = module.getArtifact(artifactId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Artifact.class, artifactId));
|
||||
|
||||
final DbArtifact file = artifactManagement
|
||||
.loadArtifactBinary(artifact.getSha1Hash(), module.getId(), module.isEncrypted())
|
||||
.orElseThrow(() -> new ArtifactBinaryNotFoundException(artifact.getSha1Hash()));
|
||||
final HttpServletRequest request = RequestResponseContextHolder.getHttpServletRequest();
|
||||
final String ifMatch = request.getHeader(HttpHeaders.IF_MATCH);
|
||||
if (ifMatch != null && !HttpUtil.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
||||
return new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
|
||||
}
|
||||
|
||||
return FileStreamingUtil.writeFileResponse(file, artifact.getFilename(), artifact.getCreatedAt(),
|
||||
RequestResponseContextHolder.getHttpServletResponse(), request, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import org.eclipse.hawkbit.rest.OpenApiConfiguration;
|
||||
import org.springdoc.core.models.GroupedOpenApi;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
value = "hawkbit.server.swagger.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public class MgmtOpenApiConfiguration {
|
||||
|
||||
private static final String BASIC_AUTH_SEC_SCHEME_NAME = "Basic Authentication";
|
||||
private static final String BEARER_AUTH_SEC_SCHEME_NAME = "Bearer Authentication";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
value = OpenApiConfiguration.HAWKBIT_SERVER_SWAGGER_ENABLED,
|
||||
havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public GroupedOpenApi mgmtApi() {
|
||||
return GroupedOpenApi
|
||||
.builder()
|
||||
.group("Management API")
|
||||
.pathsToMatch("/rest/v1/**")
|
||||
.addOpenApiCustomizer(openApi ->
|
||||
openApi
|
||||
.addSecurityItem(new SecurityRequirement()
|
||||
.addList(BASIC_AUTH_SEC_SCHEME_NAME)
|
||||
.addList(BEARER_AUTH_SEC_SCHEME_NAME))
|
||||
.components(
|
||||
openApi
|
||||
.getComponents()
|
||||
.addSecuritySchemes(BASIC_AUTH_SEC_SCHEME_NAME,
|
||||
new SecurityScheme()
|
||||
.name(BASIC_AUTH_SEC_SCHEME_NAME)
|
||||
.type(SecurityScheme.Type.HTTP)
|
||||
.in(SecurityScheme.In.HEADER)
|
||||
.scheme("basic"))
|
||||
.addSecuritySchemes(BEARER_AUTH_SEC_SCHEME_NAME,
|
||||
new SecurityScheme()
|
||||
.name(BEARER_AUTH_SEC_SCHEME_NAME)
|
||||
.type(SecurityScheme.Type.HTTP)
|
||||
.in(SecurityScheme.In.HEADER)
|
||||
.bearerFormat("JWT")
|
||||
.scheme("bearer"))))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtBaseEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtTypeEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtCancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.Type;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtRestModelMapper {
|
||||
|
||||
// private constructor, utility class
|
||||
private MgmtRestModelMapper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given {@link MgmtActionType} into a corresponding repository
|
||||
* {@link ActionType}.
|
||||
*
|
||||
* @param actionTypeRest the REST representation of the action type
|
||||
* @return <null> or the repository action type
|
||||
*/
|
||||
public static ActionType convertActionType(final MgmtActionType actionTypeRest) {
|
||||
if (actionTypeRest == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (actionTypeRest) {
|
||||
case SOFT:
|
||||
return ActionType.SOFT;
|
||||
case FORCED:
|
||||
return ActionType.FORCED;
|
||||
case TIMEFORCED:
|
||||
return ActionType.TIMEFORCED;
|
||||
case DOWNLOAD_ONLY:
|
||||
return ActionType.DOWNLOAD_ONLY;
|
||||
default:
|
||||
throw new IllegalStateException("Action Type is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given repository {@link ActionType} into a corresponding
|
||||
* {@link MgmtActionType}.
|
||||
*
|
||||
* @param actionType the repository representation of the action type
|
||||
* @return <null> or the REST action type
|
||||
*/
|
||||
public static MgmtActionType convertActionType(final ActionType actionType) {
|
||||
if (actionType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (actionType) {
|
||||
case SOFT:
|
||||
return MgmtActionType.SOFT;
|
||||
case FORCED:
|
||||
return MgmtActionType.FORCED;
|
||||
case TIMEFORCED:
|
||||
return MgmtActionType.TIMEFORCED;
|
||||
case DOWNLOAD_ONLY:
|
||||
return MgmtActionType.DOWNLOAD_ONLY;
|
||||
default:
|
||||
throw new IllegalStateException("Action Type is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given repository {@link CancelationType} into a
|
||||
* corresponding {@link MgmtCancelationType}.
|
||||
*
|
||||
* @param cancelationType the repository representation of the cancellation type
|
||||
* @return <null> or the REST cancellation type
|
||||
*/
|
||||
public static CancelationType convertCancelationType(final MgmtCancelationType cancelationType) {
|
||||
if (cancelationType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (cancelationType) {
|
||||
case SOFT:
|
||||
return CancelationType.SOFT;
|
||||
case FORCE:
|
||||
return CancelationType.FORCE;
|
||||
case NONE:
|
||||
return CancelationType.NONE;
|
||||
default:
|
||||
throw new IllegalStateException("Action Cancelation Type is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
static void mapBaseToBase(final MgmtBaseEntity response, final TenantAwareBaseEntity base) {
|
||||
response.setCreatedBy(base.getCreatedBy());
|
||||
response.setLastModifiedBy(base.getLastModifiedBy());
|
||||
if (base.getCreatedAt() > 0) {
|
||||
response.setCreatedAt(base.getCreatedAt());
|
||||
}
|
||||
if (base.getLastModifiedAt() > 0) {
|
||||
response.setLastModifiedAt(base.getLastModifiedAt());
|
||||
}
|
||||
}
|
||||
|
||||
static void mapNamedToNamed(final MgmtNamedEntity response, final NamedEntity base) {
|
||||
mapBaseToBase(response, base);
|
||||
|
||||
response.setName(base.getName());
|
||||
response.setDescription(base.getDescription());
|
||||
}
|
||||
|
||||
static void mapTypeToType(final MgmtTypeEntity response, final Type base) {
|
||||
mapNamedToNamed(response, base);
|
||||
|
||||
response.setKey(base.getKey());
|
||||
response.setColour(base.getColour());
|
||||
response.setDeleted(base.isDeleted());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.AbstractMgmtRolloutConditionsEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition.Condition;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutErrorAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutErrorAction.ErrorAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutSuccessAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutSuccessAction.SuccessAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtDynamicRolloutGroupTemplate;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroup;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
final class MgmtRolloutMapper {
|
||||
|
||||
private static final String NOT_SUPPORTED = " is not supported";
|
||||
|
||||
private MgmtRolloutMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
static List<MgmtRolloutResponseBody> toResponseRollout(final List<Rollout> rollouts) {
|
||||
return toResponseRollout(rollouts, false);
|
||||
}
|
||||
|
||||
static List<MgmtRolloutResponseBody> toResponseRollout(final List<Rollout> rollouts, final boolean withDetails) {
|
||||
if (rollouts == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return rollouts.stream().map(rollout -> toResponseRollout(rollout, withDetails)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtRolloutResponseBody toResponseRollout(final Rollout rollout, final boolean withDetails) {
|
||||
final MgmtRolloutResponseBody body = new MgmtRolloutResponseBody();
|
||||
body.setCreatedAt(rollout.getCreatedAt());
|
||||
body.setCreatedBy(rollout.getCreatedBy());
|
||||
body.setDescription(rollout.getDescription());
|
||||
body.setLastModifiedAt(rollout.getLastModifiedAt());
|
||||
body.setLastModifiedBy(rollout.getLastModifiedBy());
|
||||
body.setName(rollout.getName());
|
||||
body.setRolloutId(rollout.getId());
|
||||
body.setDynamic(rollout.isDynamic());
|
||||
body.setTargetFilterQuery(rollout.getTargetFilterQuery());
|
||||
body.setDistributionSetId(rollout.getDistributionSet().getId());
|
||||
body.setStatus(rollout.getStatus().toString().toLowerCase());
|
||||
body.setTotalTargets(rollout.getTotalTargets());
|
||||
body.setDeleted(rollout.isDeleted());
|
||||
body.setType(MgmtRestModelMapper.convertActionType(rollout.getActionType()));
|
||||
body.setForcetime(rollout.getForcedTime());
|
||||
rollout.getWeight().ifPresent(body::setWeight);
|
||||
|
||||
if (withDetails) {
|
||||
for (final TotalTargetCountStatus.Status status : TotalTargetCountStatus.Status.values()) {
|
||||
body.addTotalTargetsPerStatus(status.name().toLowerCase(),
|
||||
rollout.getTotalTargetCountStatus().getTotalTargetCountByStatus(status));
|
||||
}
|
||||
body.setTotalGroups(rollout.getRolloutGroupsCreated());
|
||||
body.setStartAt(rollout.getStartAt());
|
||||
|
||||
body.setApproveDecidedBy(rollout.getApprovalDecidedBy());
|
||||
body.setApprovalRemark(rollout.getApprovalRemark());
|
||||
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).start(rollout.getId())).withRel("start").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).pause(rollout.getId())).withRel("pause").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).resume(rollout.getId())).withRel("resume").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).triggerNextGroup(rollout.getId()))
|
||||
.withRel("triggerNextGroup").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).approve(rollout.getId(), null)).withRel("approve")
|
||||
.expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).deny(rollout.getId(), null)).withRel("deny").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroups(rollout.getId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null, null)).withRel("groups")
|
||||
.expand());
|
||||
|
||||
final DistributionSet distributionSet = rollout.getDistributionSet();
|
||||
body.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(distributionSet.getId()))
|
||||
.withRel("distributionset").withName(distributionSet.getName() + ":" + distributionSet.getVersion())
|
||||
.expand());
|
||||
}
|
||||
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRollout(rollout.getId())).withSelfRel().expand());
|
||||
return body;
|
||||
}
|
||||
|
||||
static RolloutCreate fromRequest(final EntityFactory entityFactory, final MgmtRolloutRestRequestBodyPost restRequest,
|
||||
final DistributionSet distributionSet) {
|
||||
return entityFactory.rollout().create()
|
||||
.name(restRequest.getName())
|
||||
.description(restRequest.getDescription())
|
||||
.distributionSetId(distributionSet)
|
||||
.targetFilterQuery(restRequest.getTargetFilterQuery())
|
||||
.actionType(MgmtRestModelMapper.convertActionType(restRequest.getType()))
|
||||
.forcedTime(restRequest.getForcetime()).startAt(restRequest.getStartAt())
|
||||
.weight(restRequest.getWeight())
|
||||
.dynamic(restRequest.isDynamic());
|
||||
}
|
||||
|
||||
static RolloutUpdate fromRequest(final EntityFactory entityFactory, final MgmtRolloutRestRequestBodyPut restRequest, final long rolloutId) {
|
||||
return entityFactory.rollout().update(rolloutId)
|
||||
.name(restRequest.getName())
|
||||
.description(restRequest.getDescription());
|
||||
}
|
||||
|
||||
static RolloutCreate fromRetriedRollout(final EntityFactory entityFactory, final Rollout rollout) {
|
||||
return entityFactory.rollout().create()
|
||||
.name(rollout.getName().concat("_retry"))
|
||||
.description(rollout.getDescription())
|
||||
.distributionSetId(rollout.getDistributionSet())
|
||||
.targetFilterQuery("failedrollout==".concat(String.valueOf(rollout.getId())))
|
||||
.actionType(rollout.getActionType())
|
||||
.forcedTime(rollout.getForcedTime())
|
||||
.startAt(rollout.getStartAt())
|
||||
.weight(null);
|
||||
}
|
||||
|
||||
static RolloutGroupCreate fromRequest(final EntityFactory entityFactory, final MgmtRolloutGroup restRequest) {
|
||||
return entityFactory.rolloutGroup().create().name(restRequest.getName())
|
||||
.description(restRequest.getDescription()).targetFilterQuery(restRequest.getTargetFilterQuery())
|
||||
.targetPercentage(restRequest.getTargetPercentage()).conditions(fromRequest(restRequest, false));
|
||||
}
|
||||
|
||||
static DynamicRolloutGroupTemplate fromRequest(final MgmtDynamicRolloutGroupTemplate restRequest) {
|
||||
if (restRequest == null) {
|
||||
return null;
|
||||
}
|
||||
return DynamicRolloutGroupTemplate.builder()
|
||||
.nameSuffix(Optional.ofNullable(restRequest.getNameSuffix()).orElse(""))
|
||||
.targetCount(restRequest.getTargetCount())
|
||||
.build();
|
||||
}
|
||||
|
||||
static RolloutGroupConditions fromRequest(final AbstractMgmtRolloutConditionsEntity restRequest,
|
||||
final boolean withDefaults) {
|
||||
final RolloutGroupConditionBuilder conditions = new RolloutGroupConditionBuilder();
|
||||
|
||||
if (withDefaults) {
|
||||
conditions.withDefaults();
|
||||
}
|
||||
|
||||
if (restRequest.getSuccessCondition() != null) {
|
||||
conditions.successCondition(mapFinishCondition(restRequest.getSuccessCondition().getCondition()),
|
||||
restRequest.getSuccessCondition().getExpression());
|
||||
}
|
||||
if (restRequest.getSuccessAction() != null) {
|
||||
conditions.successAction(map(restRequest.getSuccessAction().getAction()),
|
||||
restRequest.getSuccessAction().getExpression());
|
||||
}
|
||||
|
||||
if (restRequest.getErrorCondition() != null) {
|
||||
conditions.errorCondition(mapErrorCondition(restRequest.getErrorCondition().getCondition()),
|
||||
restRequest.getErrorCondition().getExpression());
|
||||
}
|
||||
if (restRequest.getErrorAction() != null) {
|
||||
conditions.errorAction(map(restRequest.getErrorAction().getAction()),
|
||||
restRequest.getErrorAction().getExpression());
|
||||
}
|
||||
|
||||
return conditions.build();
|
||||
}
|
||||
|
||||
static List<MgmtRolloutGroupResponseBody> toResponseRolloutGroup(final List<RolloutGroup> rollouts,
|
||||
final boolean confirmationFlowEnabled, final boolean withDetails) {
|
||||
if (rollouts == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return rollouts.stream().map(group -> toResponseRolloutGroup(group, withDetails, confirmationFlowEnabled))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtRolloutGroupResponseBody toResponseRolloutGroup(final RolloutGroup rolloutGroup,
|
||||
final boolean withDetailedStatus, final boolean confirmationFlowEnabled) {
|
||||
final MgmtRolloutGroupResponseBody body = new MgmtRolloutGroupResponseBody();
|
||||
body.setCreatedAt(rolloutGroup.getCreatedAt());
|
||||
body.setCreatedBy(rolloutGroup.getCreatedBy());
|
||||
body.setDescription(rolloutGroup.getDescription());
|
||||
body.setLastModifiedAt(rolloutGroup.getLastModifiedAt());
|
||||
body.setLastModifiedBy(rolloutGroup.getLastModifiedBy());
|
||||
body.setName(rolloutGroup.getName());
|
||||
body.setRolloutGroupId(rolloutGroup.getId());
|
||||
body.setStatus(rolloutGroup.getStatus().toString().toLowerCase());
|
||||
body.setTargetPercentage(rolloutGroup.getTargetPercentage());
|
||||
body.setTargetFilterQuery(rolloutGroup.getTargetFilterQuery());
|
||||
body.setTotalTargets(rolloutGroup.getTotalTargets());
|
||||
|
||||
if (confirmationFlowEnabled) {
|
||||
body.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
|
||||
}
|
||||
|
||||
body.setDynamic(rolloutGroup.isDynamic());
|
||||
|
||||
body.setSuccessCondition(new MgmtRolloutCondition(map(rolloutGroup.getSuccessCondition()),
|
||||
rolloutGroup.getSuccessConditionExp()));
|
||||
body.setSuccessAction(
|
||||
new MgmtRolloutSuccessAction(map(rolloutGroup.getSuccessAction()), rolloutGroup.getSuccessActionExp()));
|
||||
|
||||
body.setErrorCondition(
|
||||
new MgmtRolloutCondition(map(rolloutGroup.getErrorCondition()), rolloutGroup.getErrorConditionExp()));
|
||||
body.setErrorAction(
|
||||
new MgmtRolloutErrorAction(map(rolloutGroup.getErrorAction()), rolloutGroup.getErrorActionExp()));
|
||||
|
||||
if (withDetailedStatus) {
|
||||
for (final TotalTargetCountStatus.Status status : TotalTargetCountStatus.Status.values()) {
|
||||
body.addTotalTargetsPerStatus(status.name().toLowerCase(),
|
||||
rolloutGroup.getTotalTargetCountStatus().getTotalTargetCountByStatus(status));
|
||||
}
|
||||
}
|
||||
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroup(rolloutGroup.getRollout().getId(),
|
||||
rolloutGroup.getId())).withSelfRel());
|
||||
return body;
|
||||
}
|
||||
|
||||
private static RolloutGroupErrorCondition mapErrorCondition(final Condition condition) {
|
||||
if (Condition.THRESHOLD == condition) {
|
||||
return RolloutGroupErrorCondition.THRESHOLD;
|
||||
}
|
||||
throw new IllegalArgumentException(createIllegalArgumentLiteral(condition));
|
||||
}
|
||||
|
||||
private static RolloutGroupSuccessCondition mapFinishCondition(final Condition condition) {
|
||||
if (Condition.THRESHOLD == condition) {
|
||||
return RolloutGroupSuccessCondition.THRESHOLD;
|
||||
}
|
||||
throw new IllegalArgumentException(createIllegalArgumentLiteral(condition));
|
||||
}
|
||||
|
||||
private static Condition map(final RolloutGroupSuccessCondition rolloutCondition) {
|
||||
if (RolloutGroupSuccessCondition.THRESHOLD == rolloutCondition) {
|
||||
return Condition.THRESHOLD;
|
||||
}
|
||||
throw new IllegalArgumentException("Rollout group condition " + rolloutCondition + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static Condition map(final RolloutGroupErrorCondition rolloutCondition) {
|
||||
if (RolloutGroupErrorCondition.THRESHOLD == rolloutCondition) {
|
||||
return Condition.THRESHOLD;
|
||||
}
|
||||
throw new IllegalArgumentException("Rollout group condition " + rolloutCondition + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static RolloutGroupErrorAction map(final ErrorAction action) {
|
||||
if (ErrorAction.PAUSE == action) {
|
||||
return RolloutGroupErrorAction.PAUSE;
|
||||
}
|
||||
throw new IllegalArgumentException("Error Action " + action + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static RolloutGroupSuccessAction map(final SuccessAction action) {
|
||||
if (SuccessAction.NEXTGROUP == action) {
|
||||
return RolloutGroupSuccessAction.NEXTGROUP;
|
||||
}
|
||||
throw new IllegalArgumentException("Success Action " + action + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static SuccessAction map(final RolloutGroupSuccessAction successAction) {
|
||||
if (RolloutGroupSuccessAction.NEXTGROUP == successAction) {
|
||||
return SuccessAction.NEXTGROUP;
|
||||
}
|
||||
throw new IllegalArgumentException("Rollout group success action " + successAction + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static ErrorAction map(final RolloutGroupErrorAction errorAction) {
|
||||
if (RolloutGroupErrorAction.PAUSE == errorAction) {
|
||||
return ErrorAction.PAUSE;
|
||||
}
|
||||
throw new IllegalArgumentException("Rollout group error action " + errorAction + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static String createIllegalArgumentLiteral(final Condition condition) {
|
||||
return "Condition " + condition + NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.MgmtRolloutRestRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPut;
|
||||
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;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
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;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
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;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling rollout CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtRolloutResource implements MgmtRolloutRestApi {
|
||||
|
||||
private final RolloutManagement rolloutManagement;
|
||||
|
||||
private final RolloutGroupManagement rolloutGroupManagement;
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
|
||||
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 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
|
||||
public ResponseEntity<PagedList<MgmtRolloutResponseBody>> getRollouts(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam,
|
||||
final String representationModeParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeRolloutSortParam(sortParam);
|
||||
|
||||
final boolean isFullMode = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL;
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<Rollout> rollouts;
|
||||
if (rsqlParam != null) {
|
||||
rollouts = this.rolloutManagement.findByRsql(pageable, rsqlParam, false);
|
||||
} else {
|
||||
rollouts = this.rolloutManagement.findAll(pageable, false);
|
||||
}
|
||||
|
||||
final long totalElements = rollouts.getTotalElements();
|
||||
|
||||
if (isFullMode) {
|
||||
this.rolloutManagement.setRolloutStatusDetails(rollouts);
|
||||
}
|
||||
|
||||
final List<MgmtRolloutResponseBody> rest = MgmtRolloutMapper.toResponseRollout(rollouts.getContent(),
|
||||
isFullMode);
|
||||
|
||||
return ResponseEntity.ok(new PagedList<>(rest, totalElements));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> getRollout(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
final Rollout findRolloutById = rolloutManagement.getWithDetailedStatus(rolloutId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||
|
||||
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRollout(findRolloutById, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> create(
|
||||
@RequestBody final MgmtRolloutRestRequestBodyPost rolloutRequestBody) {
|
||||
// first check the given RSQL query if it's well-formed, otherwise and
|
||||
// exception is thrown
|
||||
final String targetFilterQuery = rolloutRequestBody.getTargetFilterQuery();
|
||||
if (targetFilterQuery == null) {
|
||||
// Use RSQLParameterSyntaxException due to backwards compatibility
|
||||
throw new RSQLParameterSyntaxException("Cannot create a Rollout with an empty target query filter!");
|
||||
}
|
||||
targetFilterQueryManagement.verifyTargetFilterQuerySyntax(targetFilterQuery);
|
||||
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();
|
||||
|
||||
final Rollout rollout;
|
||||
if (rolloutRequestBody.getGroups() != null) {
|
||||
if (rolloutRequestBody.isDynamic()) {
|
||||
throw new ValidationException("Dynamic rollouts are not supported with groups");
|
||||
}
|
||||
if (rolloutRequestBody.getAmountGroups() != null) {
|
||||
throw new ValidationException("Either 'amountGroups' or 'groups' must be defined in the request");
|
||||
}
|
||||
final List<RolloutGroupCreate> rolloutGroups = rolloutRequestBody.getGroups().stream()
|
||||
.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) {
|
||||
final boolean confirmationRequired = rolloutRequestBody.getConfirmationRequired() == null
|
||||
? confirmationFlowActive
|
||||
: rolloutRequestBody.getConfirmationRequired();
|
||||
rollout = rolloutManagement.create(create, rolloutRequestBody.getAmountGroups(), confirmationRequired,
|
||||
rolloutGroupConditions, MgmtRolloutMapper.fromRequest(rolloutRequestBody.getDynamicGroupTemplate()));
|
||||
} else {
|
||||
throw new ValidationException("Either 'amountGroups' or 'groups' must be defined in the request");
|
||||
}
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtRolloutMapper.toResponseRollout(rollout, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> update(
|
||||
@PathVariable("rolloutId") final Long rolloutId,
|
||||
@RequestBody final MgmtRolloutRestRequestBodyPut rolloutUpdateBody) {
|
||||
final Rollout updated =
|
||||
rolloutManagement.update(MgmtRolloutMapper.fromRequest(entityFactory, rolloutUpdateBody, rolloutId));
|
||||
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRollout(updated, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> approve(@PathVariable("rolloutId") final Long rolloutId, final String remark) {
|
||||
rolloutManagement.approveOrDeny(rolloutId, Rollout.ApprovalDecision.APPROVED, remark);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deny(@PathVariable("rolloutId") final Long rolloutId, final String remark) {
|
||||
rolloutManagement.approveOrDeny(rolloutId, Rollout.ApprovalDecision.DENIED, remark);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> start(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.start(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> pause(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.pauseRollout(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> delete(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.delete(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> resume(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.resumeRollout(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtRolloutGroupResponseBody>> getRolloutGroups(
|
||||
@PathVariable("rolloutId") final Long rolloutId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam,
|
||||
final String representationModeParam) {
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeRolloutGroupSortParam(sortParam);
|
||||
|
||||
final boolean isFullMode = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL;
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Page<RolloutGroup> rolloutGroups;
|
||||
if (rsqlParam != null) {
|
||||
if (isFullMode) {
|
||||
rolloutGroups = this.rolloutGroupManagement.findByRolloutAndRsqlWithDetailedStatus(pageable,
|
||||
rolloutId, rsqlParam);
|
||||
} else {
|
||||
rolloutGroups = this.rolloutGroupManagement.findByRolloutAndRsql(pageable, rolloutId, rsqlParam);
|
||||
}
|
||||
} else {
|
||||
if (isFullMode) {
|
||||
rolloutGroups = this.rolloutGroupManagement.findByRolloutWithDetailedStatus(pageable, rolloutId);
|
||||
} else {
|
||||
rolloutGroups = this.rolloutGroupManagement.findByRollout(pageable, rolloutId);
|
||||
}
|
||||
}
|
||||
|
||||
final List<MgmtRolloutGroupResponseBody> rest = MgmtRolloutMapper.toResponseRolloutGroup(
|
||||
rolloutGroups.getContent(), tenantConfigHelper.isConfirmationFlowEnabled(), isFullMode);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, rolloutGroups.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutGroupResponseBody> getRolloutGroup(@PathVariable("rolloutId") final Long rolloutId,
|
||||
@PathVariable("groupId") final Long groupId) {
|
||||
findRolloutOrThrowException(rolloutId);
|
||||
|
||||
final RolloutGroup rolloutGroup = rolloutGroupManagement.getWithDetailedStatus(groupId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(RolloutGroup.class, rolloutId));
|
||||
|
||||
if (!Objects.equals(rolloutId, rolloutGroup.getRollout().getId())) {
|
||||
throw new EntityNotFoundException(RolloutGroup.class, groupId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRolloutGroup(rolloutGroup, true,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getRolloutGroupTargets(@PathVariable("rolloutId") final Long rolloutId,
|
||||
@PathVariable("groupId") final Long groupId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
findRolloutOrThrowException(rolloutId);
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Page<Target> rolloutGroupTargets;
|
||||
if (rsqlParam != null) {
|
||||
rolloutGroupTargets = this.rolloutGroupManagement.findTargetsOfRolloutGroupByRsql(pageable, groupId,
|
||||
rsqlParam);
|
||||
} else {
|
||||
final Page<Target> pageTargets = this.rolloutGroupManagement.findTargetsOfRolloutGroup(pageable, groupId);
|
||||
rolloutGroupTargets = pageTargets;
|
||||
}
|
||||
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent(), tenantConfigHelper);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, rolloutGroupTargets.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> triggerNextGroup(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.triggerNextGroup(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> retryRollout(final Long rolloutId) {
|
||||
final Rollout rolloutForRetry = this.rolloutManagement.get(rolloutId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||
|
||||
if (rolloutForRetry.isDeleted()) {
|
||||
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
||||
}
|
||||
|
||||
if (!rolloutForRetry.getStatus().equals(Rollout.RolloutStatus.FINISHED)) {
|
||||
throw new ValidationException("Rollout must be finished in order to be retried!");
|
||||
}
|
||||
|
||||
final RolloutCreate create = MgmtRolloutMapper.fromRetriedRollout(entityFactory, rolloutForRetry);
|
||||
final RolloutGroupConditions groupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
|
||||
|
||||
final Rollout retriedRollout = rolloutManagement.create(create, 1, false, groupConditions, null);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtRolloutMapper.toResponseRollout(retriedRollout, true));
|
||||
}
|
||||
|
||||
private static MgmtRepresentationMode parseRepresentationMode(final String representationModeParam) {
|
||||
return MgmtRepresentationMode.fromValue(representationModeParam).orElseGet(() -> {
|
||||
// no need for a 400, just apply a safe fallback
|
||||
log.warn("Received an invalid representation mode: {}", representationModeParam);
|
||||
return MgmtRepresentationMode.COMPACT;
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<Boolean> isConfirmationRequiredForGroup(final MgmtRolloutGroup group,
|
||||
final MgmtRolloutRestRequestBodyPost request) {
|
||||
if (group.getConfirmationRequired() != null) {
|
||||
return Optional.of(group.getConfirmationRequired());
|
||||
} else if (request.getConfirmationRequired() != null) {
|
||||
return Optional.of(request.getConfirmationRequired());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private void findRolloutOrThrowException(final Long rolloutId) {
|
||||
if (!rolloutManagement.exists(rolloutId)) {
|
||||
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.ApiType;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.ArtifactUrl;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.ArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.URLPlaceholder;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifactHash;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class MgmtSoftwareModuleMapper {
|
||||
|
||||
static List<SoftwareModuleMetadataCreate> fromRequestSwMetadata(final EntityFactory entityFactory,
|
||||
final Long softwareModuleId, final Collection<MgmtSoftwareModuleMetadata> metadata) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return metadata.stream()
|
||||
.map(metadataRest -> entityFactory.softwareModuleMetadata().create(softwareModuleId)
|
||||
.key(metadataRest.getKey()).value(metadataRest.getValue())
|
||||
.targetVisible(metadataRest.isTargetVisible()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<SoftwareModuleCreate> smFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtSoftwareModuleRequestBodyPost> smsRest) {
|
||||
if (smsRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return smsRest.stream().map(smRest -> fromRequest(entityFactory, smRest)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtSoftwareModule> toResponse(final Collection<SoftwareModule> softwareModules) {
|
||||
if (softwareModules == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ResponseList<>(
|
||||
softwareModules.stream().map(MgmtSoftwareModuleMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static List<MgmtSoftwareModuleMetadata> toResponseSwMetadata(final Collection<SoftwareModuleMetadata> metadata) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return metadata.stream().map(MgmtSoftwareModuleMapper::toResponseSwMetadata).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtSoftwareModuleMetadata toResponseSwMetadata(final SoftwareModuleMetadata metadata) {
|
||||
final MgmtSoftwareModuleMetadata metadataRest = new MgmtSoftwareModuleMetadata();
|
||||
metadataRest.setKey(metadata.getKey());
|
||||
metadataRest.setValue(metadata.getValue());
|
||||
metadataRest.setTargetVisible(metadata.isTargetVisible());
|
||||
return metadataRest;
|
||||
}
|
||||
|
||||
static MgmtSoftwareModule toResponse(final SoftwareModule softwareModule) {
|
||||
if (softwareModule == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final MgmtSoftwareModule response = new MgmtSoftwareModule();
|
||||
MgmtRestModelMapper.mapNamedToNamed(response, softwareModule);
|
||||
response.setModuleId(softwareModule.getId());
|
||||
response.setVersion(softwareModule.getVersion());
|
||||
response.setType(softwareModule.getType().getKey());
|
||||
response.setTypeName(softwareModule.getType().getName());
|
||||
response.setVendor(softwareModule.getVendor());
|
||||
response.setLocked(softwareModule.isLocked());
|
||||
response.setDeleted(softwareModule.isDeleted());
|
||||
response.setEncrypted(softwareModule.isEncrypted());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class).getSoftwareModule(response.getModuleId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void addLinks(final SoftwareModule softwareModule, final MgmtSoftwareModule response) {
|
||||
response.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class).getArtifacts(response.getModuleId(), null, null))
|
||||
.withRel(MgmtRestConstants.SOFTWAREMODULE_V1_ARTIFACT).expand());
|
||||
|
||||
response.add(linkTo(
|
||||
methodOn(MgmtSoftwareModuleTypeRestApi.class).getSoftwareModuleType(softwareModule.getType().getId()))
|
||||
.withRel(MgmtRestConstants.SOFTWAREMODULE_V1_TYPE).expand());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtSoftwareModuleResource.class).getMetadata(response.getModuleId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("metadata")
|
||||
.expand().expand());
|
||||
}
|
||||
|
||||
static MgmtArtifact toResponse(final Artifact artifact) {
|
||||
final MgmtArtifact artifactRest = new MgmtArtifact();
|
||||
artifactRest.setArtifactId(artifact.getId());
|
||||
artifactRest.setSize(artifact.getSize());
|
||||
artifactRest.setHashes(
|
||||
new MgmtArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash(), artifact.getSha256Hash()));
|
||||
|
||||
artifactRest.setProvidedFilename(artifact.getFilename());
|
||||
|
||||
MgmtRestModelMapper.mapBaseToBase(artifactRest, artifact);
|
||||
|
||||
artifactRest.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class)
|
||||
.getArtifact(artifact.getSoftwareModule().getId(), artifact.getId(), null)).withSelfRel().expand());
|
||||
|
||||
return artifactRest;
|
||||
}
|
||||
|
||||
static void addLinks(final Artifact artifact, final MgmtArtifact response) {
|
||||
response.add(linkTo(methodOn(MgmtDownloadArtifactResource.class)
|
||||
.downloadArtifact(artifact.getSoftwareModule().getId(), artifact.getId())).withRel("download")
|
||||
.expand());
|
||||
}
|
||||
|
||||
static void addLinks(final Artifact artifact, final MgmtArtifact response,
|
||||
final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement) {
|
||||
final List<ArtifactUrl> urls = artifactUrlHandler.getUrls(
|
||||
new URLPlaceholder(systemManagement.getTenantMetadata().getTenant(),
|
||||
systemManagement.getTenantMetadata().getId(), null, null,
|
||||
new URLPlaceholder.SoftwareData(artifact.getSoftwareModule().getId(), artifact.getFilename(),
|
||||
artifact.getId(), artifact.getSha1Hash())), ApiType.MGMT, null);
|
||||
urls.forEach(entry -> response.add(Link.of(entry.getRef()).withRel(entry.getRel()).expand()));
|
||||
}
|
||||
|
||||
private static SoftwareModuleCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtSoftwareModuleRequestBodyPost smsRest) {
|
||||
return entityFactory.softwareModule().create().type(smsRest.getType()).name(smsRest.getName())
|
||||
.version(smsRest.getVersion()).description(smsRest.getDescription()).vendor(smsRest.getVendor())
|
||||
.encrypted(smsRest.isEncrypted());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.ArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadataBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link SoftwareModule} and related
|
||||
* {@link Artifact} CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
|
||||
private final ArtifactManagement artifactManagement;
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
private final ArtifactUrlHandler artifactUrlHandler;
|
||||
private final SystemManagement systemManagement;
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtSoftwareModuleResource(final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareModuleManagement,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement,
|
||||
final EntityFactory entityFactory) {
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.artifactUrlHandler = artifactUrlHandler;
|
||||
this.systemManagement = systemManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtArtifact> uploadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@RequestPart("file") final MultipartFile file,
|
||||
@RequestParam(value = "filename", required = false) final String optionalFileName,
|
||||
@RequestParam(value = "md5sum", required = false) final String md5Sum,
|
||||
@RequestParam(value = "sha1sum", required = false) final String sha1Sum,
|
||||
@RequestParam(value = "sha256sum", required = false) final String sha256Sum) {
|
||||
|
||||
if (file.isEmpty()) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
String fileName = optionalFileName;
|
||||
|
||||
if (fileName == null) {
|
||||
fileName = file.getOriginalFilename();
|
||||
}
|
||||
|
||||
try (final InputStream in = file.getInputStream()) {
|
||||
final Artifact result = artifactManagement.create(new ArtifactUpload(in, softwareModuleId, fileName,
|
||||
md5Sum == null ? null : md5Sum.toLowerCase(), sha1Sum == null ? null : sha1Sum.toLowerCase(),
|
||||
sha256Sum == null ? null : sha256Sum.toLowerCase(), false, file.getContentType(), file.getSize()));
|
||||
|
||||
final MgmtArtifact reponse = MgmtSoftwareModuleMapper.toResponse(result);
|
||||
MgmtSoftwareModuleMapper.addLinks(result, reponse);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(reponse);
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to store artifact", e);
|
||||
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtArtifact>> getArtifacts(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId, final String representationModeParam,
|
||||
final Boolean useArtifactUrlHandler) {
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
|
||||
final boolean isFullMode = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL;
|
||||
|
||||
final List<MgmtArtifact> response = module.getArtifacts().stream().map(artifact -> {
|
||||
final MgmtArtifact mgmtArtifact = MgmtSoftwareModuleMapper.toResponse(artifact);
|
||||
if (isFullMode && !module.isDeleted() && Boolean.TRUE.equals(useArtifactUrlHandler)) {
|
||||
MgmtSoftwareModuleMapper.addLinks(artifact, mgmtArtifact, artifactUrlHandler, systemManagement);
|
||||
} else if (isFullMode && !module.isDeleted()) {
|
||||
MgmtSoftwareModuleMapper.addLinks(artifact, mgmtArtifact);
|
||||
}
|
||||
return mgmtArtifact;
|
||||
}).toList();
|
||||
return ResponseEntity.ok(new ResponseList<>(response));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ResponseBody
|
||||
// Exception squid:S3655 - Optional access is checked in
|
||||
// findSoftwareModuleWithExceptionIfNotFound
|
||||
// subroutine
|
||||
@SuppressWarnings("squid:S3655")
|
||||
public ResponseEntity<MgmtArtifact> getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("artifactId") final Long artifactId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_USE_ARTIFACT_URL_HANDLER, required = false) final Boolean useArtifactUrlHandler) {
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId);
|
||||
|
||||
final MgmtArtifact response = MgmtSoftwareModuleMapper.toResponse(module.getArtifact(artifactId).get());
|
||||
if (!module.isDeleted()) {
|
||||
if (Boolean.TRUE.equals(useArtifactUrlHandler)) {
|
||||
MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), response, artifactUrlHandler,
|
||||
systemManagement);
|
||||
} else {
|
||||
MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), response);
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ResponseBody
|
||||
public ResponseEntity<Void> deleteArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("artifactId") final Long artifactId) {
|
||||
|
||||
findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId);
|
||||
artifactManagement.delete(artifactId);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtSoftwareModule>> getSoftwareModules(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeSoftwareModuleSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<SoftwareModule> findModulesAll;
|
||||
final long countModulesAll;
|
||||
if (rsqlParam != null) {
|
||||
findModulesAll = softwareModuleManagement.findByRsql(pageable, rsqlParam);
|
||||
countModulesAll = ((Page<SoftwareModule>) findModulesAll).getTotalElements();
|
||||
} else {
|
||||
findModulesAll = softwareModuleManagement.findAll(pageable);
|
||||
countModulesAll = softwareModuleManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtSoftwareModule> rest = MgmtSoftwareModuleMapper.toResponse(findModulesAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModule> getSoftwareModule(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId) {
|
||||
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
|
||||
final MgmtSoftwareModule response = MgmtSoftwareModuleMapper.toResponse(module);
|
||||
MgmtSoftwareModuleMapper.addLinks(module, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModule>> createSoftwareModules(
|
||||
@RequestBody final List<MgmtSoftwareModuleRequestBodyPost> softwareModules) {
|
||||
|
||||
log.debug("creating {} softwareModules", softwareModules.size());
|
||||
|
||||
for (final MgmtSoftwareModuleRequestBodyPost sm : softwareModules) {
|
||||
final Optional<SoftwareModuleType> opt = softwareModuleTypeManagement.getByKey(sm.getType());
|
||||
opt.ifPresent(smType -> {
|
||||
if (smType.isDeleted()) {
|
||||
final String text = "Cannot create Software Module from type with key {0}. Software Module Type already deleted!";
|
||||
final String message = MessageFormat.format(text, smType.getKey());
|
||||
throw new ValidationException(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
final Collection<SoftwareModule> createdSoftwareModules = softwareModuleManagement
|
||||
.create(MgmtSoftwareModuleMapper.smFromRequest(entityFactory, softwareModules));
|
||||
log.debug("{} softwareModules created, return status {}", softwareModules.size(), HttpStatus.CREATED);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(MgmtSoftwareModuleMapper.toResponse(createdSoftwareModules));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModule> updateSoftwareModule(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@RequestBody final MgmtSoftwareModuleRequestBodyPut restSoftwareModule) {
|
||||
final SoftwareModule module = softwareModuleManagement
|
||||
.update(entityFactory.softwareModule().update(softwareModuleId)
|
||||
.description(restSoftwareModule.getDescription())
|
||||
.vendor(restSoftwareModule.getVendor())
|
||||
.locked(restSoftwareModule.getLocked()));
|
||||
|
||||
final MgmtSoftwareModule response = MgmtSoftwareModuleMapper.toResponse(module);
|
||||
MgmtSoftwareModuleMapper.addLinks(module, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteSoftwareModule(@PathVariable("softwareModuleId") final Long softwareModuleId) {
|
||||
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
softwareModuleManagement.delete(module.getId());
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtSoftwareModuleMetadata>> getMetadata(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
// check if software module exists otherwise throw exception immediately
|
||||
findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeSoftwareModuleMetadataSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<SoftwareModuleMetadata> metaDataPage;
|
||||
|
||||
if (rsqlParam != null) {
|
||||
metaDataPage = softwareModuleManagement.findMetaDataByRsql(pageable, softwareModuleId, rsqlParam);
|
||||
} else {
|
||||
metaDataPage = softwareModuleManagement.findMetaDataBySoftwareModuleId(pageable, softwareModuleId);
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtSoftwareModuleMapper.toResponseSwMetadata(metaDataPage.getContent()),
|
||||
metaDataPage.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleMetadata> getMetadataValue(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
|
||||
final SoftwareModuleMetadata findOne = softwareModuleManagement
|
||||
.getMetaDataBySoftwareModuleId(softwareModuleId, metadataKey).orElseThrow(
|
||||
() -> new EntityNotFoundException(SoftwareModuleMetadata.class, softwareModuleId, metadataKey));
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(findOne));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleMetadata> updateMetadata(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("metadataKey") final String metadataKey,
|
||||
@RequestBody final MgmtSoftwareModuleMetadataBodyPut metadata) {
|
||||
final SoftwareModuleMetadata updated = softwareModuleManagement
|
||||
.updateMetaData(entityFactory.softwareModuleMetadata().update(softwareModuleId, metadataKey)
|
||||
.value(metadata.getValue()).targetVisible(metadata.getTargetVisible()));
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(updated));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
softwareModuleManagement.deleteMetaData(softwareModuleId, metadataKey);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModuleMetadata>> createMetadata(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@RequestBody final List<MgmtSoftwareModuleMetadata> metadataRest) {
|
||||
|
||||
final List<SoftwareModuleMetadata> created = softwareModuleManagement.createMetaData(
|
||||
MgmtSoftwareModuleMapper.fromRequestSwMetadata(entityFactory, softwareModuleId, metadataRest));
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtSoftwareModuleMapper.toResponseSwMetadata(created));
|
||||
}
|
||||
|
||||
private static MgmtRepresentationMode parseRepresentationMode(final String representationModeParam) {
|
||||
return MgmtRepresentationMode.fromValue(representationModeParam).orElseGet(() -> {
|
||||
// no need for a 400, just apply a safe fallback
|
||||
log.warn("Received an invalid representation mode: {}", representationModeParam);
|
||||
return MgmtRepresentationMode.COMPACT;
|
||||
});
|
||||
}
|
||||
|
||||
private SoftwareModule findSoftwareModuleWithExceptionIfNotFound(final Long softwareModuleId,
|
||||
final Long artifactId) {
|
||||
|
||||
final SoftwareModule module = softwareModuleManagement.get(softwareModuleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId));
|
||||
|
||||
if (artifactId != null && !module.getArtifact(artifactId).isPresent()) {
|
||||
throw new EntityNotFoundException(Artifact.class, artifactId);
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
final class MgmtSoftwareModuleTypeMapper {
|
||||
|
||||
// private constructor, utility class
|
||||
private MgmtSoftwareModuleTypeMapper() {
|
||||
|
||||
}
|
||||
|
||||
static List<SoftwareModuleTypeCreate> smFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtSoftwareModuleTypeRequestBodyPost> smTypesRest) {
|
||||
if (smTypesRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return smTypesRest.stream().map(smRest -> fromRequest(entityFactory, smRest)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtSoftwareModuleType> toTypesResponse(final Collection<SoftwareModuleType> types) {
|
||||
if (types == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ResponseList<>(
|
||||
types.stream().map(MgmtSoftwareModuleTypeMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtSoftwareModuleType toResponse(final SoftwareModuleType type) {
|
||||
final MgmtSoftwareModuleType result = new MgmtSoftwareModuleType();
|
||||
|
||||
MgmtRestModelMapper.mapTypeToType(result, type);
|
||||
result.setMaxAssignments(type.getMaxAssignments());
|
||||
result.setModuleId(type.getId());
|
||||
|
||||
result.add(linkTo(methodOn(MgmtSoftwareModuleTypeRestApi.class).getSoftwareModuleType(result.getModuleId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static SoftwareModuleTypeCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtSoftwareModuleTypeRequestBodyPost smsRest) {
|
||||
return entityFactory.softwareModuleType().create().key(smsRest.getKey()).name(smsRest.getName())
|
||||
.description(smsRest.getDescription()).colour(smsRest.getColour())
|
||||
.maxAssignments(smsRest.getMaxAssignments());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link SoftwareModuleType} CRUD operations.
|
||||
*/
|
||||
@RestController
|
||||
public class MgmtSoftwareModuleTypeResource implements MgmtSoftwareModuleTypeRestApi {
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtSoftwareModuleTypeResource(final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final EntityFactory entityFactory) {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtSoftwareModuleType>> getTypes(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeSoftwareModuleTypeSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<SoftwareModuleType> findModuleTypessAll;
|
||||
Long countModulesAll;
|
||||
if (rsqlParam != null) {
|
||||
findModuleTypessAll = softwareModuleTypeManagement.findByRsql(pageable, rsqlParam);
|
||||
countModulesAll = ((Page<SoftwareModuleType>) findModuleTypessAll).getTotalElements();
|
||||
} else {
|
||||
findModuleTypessAll = softwareModuleTypeManagement.findAll(pageable);
|
||||
countModulesAll = softwareModuleTypeManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtSoftwareModuleType> rest = MgmtSoftwareModuleTypeMapper
|
||||
.toTypesResponse(findModuleTypessAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleType> getSoftwareModuleType(
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
final SoftwareModuleType foundType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toResponse(foundType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteSoftwareModuleType(
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
softwareModuleTypeManagement.delete(softwareModuleTypeId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleType> updateSoftwareModuleType(
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId,
|
||||
@RequestBody final MgmtSoftwareModuleTypeRequestBodyPut restSoftwareModuleType) {
|
||||
|
||||
final SoftwareModuleType updatedSoftwareModuleType = softwareModuleTypeManagement.update(entityFactory
|
||||
.softwareModuleType().update(softwareModuleTypeId).description(restSoftwareModuleType.getDescription())
|
||||
.colour(restSoftwareModuleType.getColour()));
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toResponse(updatedSoftwareModuleType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModuleType>> createSoftwareModuleTypes(
|
||||
@RequestBody final List<MgmtSoftwareModuleTypeRequestBodyPost> softwareModuleTypes) {
|
||||
|
||||
final List<SoftwareModuleType> createdSoftwareModules = softwareModuleTypeManagement
|
||||
.create(MgmtSoftwareModuleTypeMapper.smFromRequest(entityFactory, softwareModuleTypes));
|
||||
|
||||
return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toTypesResponse(createdSoftwareModules),
|
||||
HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
private SoftwareModuleType findSoftwareModuleTypeWithExceptionIfNotFound(final Long softwareModuleTypeId) {
|
||||
return softwareModuleTypeManagement.get(softwareModuleTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, softwareModuleTypeId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemCache;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemStatisticsRest;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemTenantServiceUsage;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemManagementRestApi;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.report.model.SystemUsageReportWithTenants;
|
||||
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* {@link SystemManagement} capabilities by REST.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtSystemManagementResource implements MgmtSystemManagementRestApi {
|
||||
|
||||
private final SystemManagement systemManagement;
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
MgmtSystemManagementResource(final SystemManagement systemManagement, final CacheManager cacheManager) {
|
||||
this.systemManagement = systemManagement;
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the tenant data of a given tenant. USE WITH CARE!
|
||||
*
|
||||
* @param tenant to delete
|
||||
* @return HttpStatus.OK
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTenant(@PathVariable("tenant") final String tenant) {
|
||||
systemManagement.deleteTenant(tenant);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects and returns system usage statistics. It provides a system wide
|
||||
* overview and tenant based stats.
|
||||
*
|
||||
* @return system usage statistics
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<MgmtSystemStatisticsRest> getSystemUsageStats() {
|
||||
final SystemUsageReportWithTenants report = systemManagement.getSystemUsageStatisticsWithTenants();
|
||||
|
||||
final MgmtSystemStatisticsRest result = new MgmtSystemStatisticsRest()
|
||||
.setOverallActions(report.getOverallActions()).setOverallArtifacts(report.getOverallArtifacts())
|
||||
.setOverallArtifactVolumeInBytes(report.getOverallArtifactVolumeInBytes())
|
||||
.setOverallTargets(report.getOverallTargets()).setOverallTenants(report.getTenants().size());
|
||||
|
||||
result.setTenantStats(report.getTenants().stream().map(MgmtSystemManagementResource::convertTenant)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all caches.
|
||||
*
|
||||
* @return a list of caches for all tenants
|
||||
*/
|
||||
@Override
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
public ResponseEntity<Collection<MgmtSystemCache>> getCaches() {
|
||||
final Collection<String> cacheNames = cacheManager.getCacheNames();
|
||||
return ResponseEntity
|
||||
.ok(cacheNames.stream().map(cacheManager::getCache)
|
||||
.filter(Objects::nonNull)
|
||||
.map(cache -> new MgmtSystemCache(cache.getName(), Collections.emptyList()))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all caches for all tenants.
|
||||
*
|
||||
* @return a list of cache names which has been invalidated
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
@Override
|
||||
public ResponseEntity<Collection<String>> invalidateCaches() {
|
||||
final Collection<String> cacheNames = cacheManager.getCacheNames();
|
||||
log.info("Invalidating caches {}", cacheNames);
|
||||
cacheNames.forEach(cacheName -> cacheManager.getCache(cacheName).clear());
|
||||
return ResponseEntity.ok(cacheNames);
|
||||
}
|
||||
|
||||
private static MgmtSystemTenantServiceUsage convertTenant(final TenantUsage tenant) {
|
||||
final MgmtSystemTenantServiceUsage result = new MgmtSystemTenantServiceUsage();
|
||||
result.setTenantName(tenant.getTenantName());
|
||||
result.setActions(tenant.getActions());
|
||||
result.setArtifacts(tenant.getArtifacts());
|
||||
result.setOverallArtifactVolumeInBytes(tenant.getOverallArtifactVolumeInBytes());
|
||||
result.setTargets(tenant.getTargets());
|
||||
if (!tenant.getUsageData().isEmpty()) {
|
||||
result.setUsageData(tenant.getUsageData());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and back.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
final class MgmtTagMapper {
|
||||
|
||||
static List<MgmtTag> toResponse(final List<TargetTag> targetTags) {
|
||||
final List<MgmtTag> tagsRest = new ArrayList<>();
|
||||
if (targetTags == null) {
|
||||
return tagsRest;
|
||||
}
|
||||
|
||||
for (final TargetTag target : targetTags) {
|
||||
final MgmtTag response = toResponse(target);
|
||||
|
||||
tagsRest.add(response);
|
||||
}
|
||||
return new ResponseList<>(tagsRest);
|
||||
}
|
||||
|
||||
static MgmtTag toResponse(final TargetTag targetTag) {
|
||||
final MgmtTag response = new MgmtTag();
|
||||
if (targetTag == null) {
|
||||
return response;
|
||||
}
|
||||
|
||||
mapTag(response, targetTag);
|
||||
|
||||
response.add(
|
||||
linkTo(methodOn(MgmtTargetTagRestApi.class).getTargetTag(targetTag.getId())).withSelfRel().expand());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void addLinks(final TargetTag targetTag, final MgmtTag response) {
|
||||
response.add(linkTo(methodOn(MgmtTargetTagRestApi.class).getAssignedTargets(targetTag.getId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("assignedTargets")
|
||||
.expand());
|
||||
|
||||
}
|
||||
|
||||
static List<MgmtTag> toResponseDistributionSetTag(final List<DistributionSetTag> distributionSetTags) {
|
||||
final List<MgmtTag> tagsRest = new ArrayList<>();
|
||||
if (distributionSetTags == null) {
|
||||
return tagsRest;
|
||||
}
|
||||
|
||||
for (final DistributionSetTag distributionSetTag : distributionSetTags) {
|
||||
final MgmtTag response = toResponse(distributionSetTag);
|
||||
|
||||
tagsRest.add(response);
|
||||
}
|
||||
return new ResponseList<>(tagsRest);
|
||||
}
|
||||
|
||||
static MgmtTag toResponse(final DistributionSetTag distributionSetTag) {
|
||||
final MgmtTag response = new MgmtTag();
|
||||
if (distributionSetTag == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
mapTag(response, distributionSetTag);
|
||||
|
||||
response.add(
|
||||
linkTo(methodOn(MgmtDistributionSetTagRestApi.class).getDistributionSetTag(distributionSetTag.getId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void addLinks(final DistributionSetTag distributionSetTag, final MgmtTag response) {
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetTagRestApi.class).getAssignedDistributionSets(
|
||||
distributionSetTag.getId(), MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null))
|
||||
.withRel("assignedDistributionSets").expand());
|
||||
}
|
||||
|
||||
static List<TagCreate> mapTagFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtTagRequestBodyPut> tags) {
|
||||
return tags.stream()
|
||||
.map(tagRest -> entityFactory.tag().create().name(tagRest.getName())
|
||||
.description(tagRest.getDescription()).colour(tagRest.getColour()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static void mapTag(final MgmtTag response, final Tag tag) {
|
||||
MgmtRestModelMapper.mapNamedToNamed(response, tag);
|
||||
response.setTagId(tag.getId());
|
||||
response.setColour(tag.getColour());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtDistributionSetAutoAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQueryRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtTargetFilterQueryMapper {
|
||||
|
||||
private MgmtTargetFilterQueryMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
static List<MgmtTargetFilterQuery> toResponse(final List<TargetFilterQuery> filters,
|
||||
final boolean confirmationFlowEnabled, final boolean isRepresentationFull) {
|
||||
if (CollectionUtils.isEmpty(filters)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return filters.stream().map(filter -> toResponse(filter, confirmationFlowEnabled, isRepresentationFull)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtTargetFilterQuery toResponse(final TargetFilterQuery filter, final boolean confirmationFlowEnabled,
|
||||
final boolean isReprentationFull) {
|
||||
final MgmtTargetFilterQuery targetRest = new MgmtTargetFilterQuery();
|
||||
targetRest.setFilterId(filter.getId());
|
||||
targetRest.setName(filter.getName());
|
||||
targetRest.setQuery(filter.getQuery());
|
||||
|
||||
targetRest.setCreatedBy(filter.getCreatedBy());
|
||||
targetRest.setLastModifiedBy(filter.getLastModifiedBy());
|
||||
|
||||
targetRest.setCreatedAt(filter.getCreatedAt());
|
||||
targetRest.setLastModifiedAt(filter.getLastModifiedAt());
|
||||
|
||||
final DistributionSet distributionSet = filter.getAutoAssignDistributionSet();
|
||||
if (distributionSet != null) {
|
||||
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().expand());
|
||||
if (isReprentationFull && distributionSet != null) {
|
||||
targetRest.add(
|
||||
linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSets(
|
||||
Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET),
|
||||
Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null,
|
||||
"name==" + distributionSet.getName() + ";version==" + distributionSet.getVersion())).withRel("DS").expand());
|
||||
}
|
||||
|
||||
return targetRest;
|
||||
}
|
||||
|
||||
static void addLinks(final MgmtTargetFilterQuery targetRest) {
|
||||
targetRest.add(linkTo(methodOn(MgmtTargetFilterQueryRestApi.class)
|
||||
.postAssignedDistributionSet(targetRest.getFilterId(), null)).withRel("autoAssignDS").expand());
|
||||
}
|
||||
|
||||
static TargetFilterQueryCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtTargetFilterQueryRequestBody filterRest) {
|
||||
|
||||
return entityFactory.targetFilterQuery().create().name(filterRest.getName()).query(filterRest.getQuery());
|
||||
}
|
||||
|
||||
static AutoAssignDistributionSetUpdate fromRequest(final EntityFactory entityFactory, final long filterId,
|
||||
final MgmtDistributionSetAutoAssignment assignRest) {
|
||||
final ActionType type = MgmtRestModelMapper.convertActionType(assignRest.getType());
|
||||
|
||||
return entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(assignRest.getId()).actionType(type)
|
||||
.weight(assignRest.getWeight());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtDistributionSetAutoAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQueryRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
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.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling target CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestApi {
|
||||
|
||||
private final TargetFilterQueryManagement filterManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
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,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), true);
|
||||
MgmtTargetFilterQueryMapper.addLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTargetFilterQuery>> getFilters(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE_DEFAULT) String representationModeParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetFilterQuerySortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Slice<TargetFilterQuery> findTargetFiltersAll;
|
||||
final Long countTargetsAll;
|
||||
if (rsqlParam != null) {
|
||||
final Page<TargetFilterQuery> findFilterPage = filterManagement.findByRsql(pageable, rsqlParam);
|
||||
countTargetsAll = findFilterPage.getTotalElements();
|
||||
findTargetFiltersAll = findFilterPage;
|
||||
} else {
|
||||
findTargetFiltersAll = filterManagement.findAll(pageable);
|
||||
countTargetsAll = filterManagement.count();
|
||||
}
|
||||
|
||||
final boolean isRepresentationFull = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL;
|
||||
|
||||
final List<MgmtTargetFilterQuery> rest = MgmtTargetFilterQueryMapper
|
||||
.toResponse(findTargetFiltersAll.getContent(), tenantConfigHelper.isConfirmationFlowEnabled(), isRepresentationFull);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countTargetsAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetFilterQuery> createFilter(
|
||||
@RequestBody final MgmtTargetFilterQueryRequestBody filter) {
|
||||
final TargetFilterQuery createdTarget = filterManagement
|
||||
.create(MgmtTargetFilterQueryMapper.fromRequest(entityFactory, filter));
|
||||
|
||||
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(createdTarget,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), false);
|
||||
MgmtTargetFilterQueryMapper.addLinks(response);
|
||||
|
||||
return new ResponseEntity<>(response, HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetFilterQuery> updateFilter(@PathVariable("filterId") final Long filterId,
|
||||
@RequestBody final MgmtTargetFilterQueryRequestBody targetFilterRest) {
|
||||
log.debug("updating target filter query {}", filterId);
|
||||
|
||||
final TargetFilterQuery updateFilter = filterManagement
|
||||
.update(entityFactory.targetFilterQuery().update(filterId).name(targetFilterRest.getName())
|
||||
.query(targetFilterRest.getQuery()));
|
||||
|
||||
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), false);
|
||||
MgmtTargetFilterQueryMapper.addLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteFilter(@PathVariable("filterId") final Long filterId) {
|
||||
filterManagement.delete(filterId);
|
||||
log.debug("{} target filter query deleted, return status {}", filterId, HttpStatus.OK);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> getAssignedDistributionSet(
|
||||
@PathVariable("filterId") final Long filterId) {
|
||||
final TargetFilterQuery filter = findFilterWithExceptionIfNotFound(filterId);
|
||||
final DistributionSet autoAssignDistributionSet = filter.getAutoAssignDistributionSet();
|
||||
|
||||
if (autoAssignDistributionSet == null) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(autoAssignDistributionSet);
|
||||
MgmtDistributionSetMapper.addLinks(autoAssignDistributionSet, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetFilterQuery> postAssignedDistributionSet(
|
||||
@PathVariable("filterId") final Long filterId,
|
||||
@RequestBody final MgmtDistributionSetAutoAssignment autoAssignRequest) {
|
||||
|
||||
final boolean confirmationRequired = autoAssignRequest.getConfirmationRequired() == null
|
||||
? tenantConfigHelper.isConfirmationFlowEnabled()
|
||||
: autoAssignRequest.getConfirmationRequired();
|
||||
|
||||
final AutoAssignDistributionSetUpdate update = MgmtTargetFilterQueryMapper
|
||||
.fromRequest(entityFactory, filterId, autoAssignRequest).confirmationRequired(confirmationRequired);
|
||||
|
||||
final TargetFilterQuery updateFilter = filterManagement.updateAutoAssignDS(update);
|
||||
|
||||
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), false);
|
||||
MgmtTargetFilterQueryMapper.addLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteAssignedDistributionSet(@PathVariable("filterId") final Long filterId) {
|
||||
filterManagement.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(null));
|
||||
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
private static MgmtRepresentationMode parseRepresentationMode(final String representationModeParam) {
|
||||
return MgmtRepresentationMode.fromValue(representationModeParam).orElseGet(() -> {
|
||||
// no need for a 400, just apply a safe fallback
|
||||
log.warn("Received an invalid representation mode: {}", representationModeParam);
|
||||
return MgmtRepresentationMode.COMPACT;
|
||||
});
|
||||
}
|
||||
|
||||
private TargetFilterQuery findFilterWithExceptionIfNotFound(final Long filterId) {
|
||||
return filterManagement.get(filterId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, filterId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||
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;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.SortDirection;
|
||||
import org.eclipse.hawkbit.repository.ActionFields;
|
||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||
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.AutoConfirmationStatus;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.MetaData;
|
||||
import org.eclipse.hawkbit.repository.model.PollStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
import org.eclipse.hawkbit.util.IpUtil;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtTargetMapper {
|
||||
|
||||
private MgmtTargetMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Add links to a target response.
|
||||
*
|
||||
* @param response the target response
|
||||
*/
|
||||
public static void addTargetLinks(final MgmtTarget response) {
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAssignedDistributionSet(response.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET).expand());
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getInstalledDistributionSet(response.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_INSTALLED_DISTRIBUTION_SET).expand());
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAttributes(response.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ATTRIBUTES).expand());
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionHistory(response.getControllerId(), 0,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
||||
ActionFields.ID.getJpaEntityFieldName() + ":" + SortDirection.DESC, null))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ACTIONS).expand());
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getMetadata(response.getControllerId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("metadata")
|
||||
.expand());
|
||||
if (response.getTargetType() != null) {
|
||||
response.add(linkTo(methodOn(MgmtTargetTypeRestApi.class).getTargetType(response.getTargetType()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ASSIGNED_TARGET_TYPE).expand());
|
||||
}
|
||||
if (response.getAutoConfirmActive() != null) {
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAutoConfirmStatus(response.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_AUTO_CONFIRM).expand());
|
||||
}
|
||||
}
|
||||
|
||||
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).expand());
|
||||
} else {
|
||||
response = MgmtTargetAutoConfirm.disabled();
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).activateAutoConfirm(target.getControllerId(), null))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ACTIVATE_AUTO_CONFIRM).expand());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a response for targets.
|
||||
*
|
||||
* @param targets list of targets
|
||||
* @return the response
|
||||
*/
|
||||
public static List<MgmtTarget> toResponse(final Collection<Target> targets, final TenantConfigHelper configHelper) {
|
||||
if (targets == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Function<Target, PollStatus> pollStatusResolver = configHelper.pollStatusResolver();
|
||||
return new ResponseList<>(
|
||||
targets.stream().map(target -> toResponse(target, configHelper, pollStatusResolver)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a response for target.
|
||||
*
|
||||
* @param target the target
|
||||
* @return the response
|
||||
*/
|
||||
public static MgmtTarget toResponse(final Target target, final TenantConfigHelper configHelper,
|
||||
final Function<Target, PollStatus> pollStatusResolver) {
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
final MgmtTarget targetRest = new MgmtTarget();
|
||||
targetRest.setControllerId(target.getControllerId());
|
||||
targetRest.setDescription(target.getDescription());
|
||||
targetRest.setName(target.getName());
|
||||
targetRest.setUpdateStatus(target.getUpdateStatus().name().toLowerCase());
|
||||
|
||||
final URI address = target.getAddress();
|
||||
if (address != null) {
|
||||
if (IpUtil.isIpAddresKnown(address)) {
|
||||
targetRest.setIpAddress(address.getHost());
|
||||
}
|
||||
targetRest.setAddress(address.toString());
|
||||
}
|
||||
|
||||
targetRest.setCreatedBy(target.getCreatedBy());
|
||||
targetRest.setLastModifiedBy(target.getLastModifiedBy());
|
||||
|
||||
targetRest.setCreatedAt(target.getCreatedAt());
|
||||
targetRest.setLastModifiedAt(target.getLastModifiedAt());
|
||||
|
||||
targetRest.setSecurityToken(target.getSecurityToken());
|
||||
targetRest.setRequestAttributes(target.isRequestControllerAttributes());
|
||||
|
||||
// last target query is the last controller request date
|
||||
final Long lastTargetQuery = target.getLastTargetQuery();
|
||||
final Long installationDate = target.getInstallationDate();
|
||||
|
||||
if (lastTargetQuery != null) {
|
||||
targetRest.setLastControllerRequestAt(lastTargetQuery);
|
||||
}
|
||||
if (installationDate != null) {
|
||||
targetRest.setInstalledAt(installationDate);
|
||||
}
|
||||
if (target.getTargetType() != null) {
|
||||
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().expand());
|
||||
|
||||
addPollStatus(target, targetRest, pollStatusResolver == null ? configHelper.pollStatusResolver() : pollStatusResolver);
|
||||
|
||||
return targetRest;
|
||||
}
|
||||
|
||||
static List<TargetCreate> fromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtTargetRequestBody> targetsRest) {
|
||||
if (targetsRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return targetsRest.stream().map(targetRest -> fromRequest(entityFactory, targetRest))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MetaData> fromRequestTargetMetadata(final List<MgmtMetadata> metadata,
|
||||
final EntityFactory entityFactory) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return metadata.stream().map(
|
||||
metadataRest -> entityFactory.generateTargetMetadata(metadataRest.getKey(), metadataRest.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtActionStatus> toActionStatusRestResponse(final Collection<ActionStatus> actionStatus,
|
||||
final DeploymentManagement deploymentManagement) {
|
||||
if (actionStatus == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return actionStatus.stream()
|
||||
.map(status -> toResponse(status,
|
||||
deploymentManagement.findMessagesByActionStatusId(
|
||||
PageRequest.of(0, MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT), status.getId())
|
||||
.getContent()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtAction toResponse(final String targetId, final Action action) {
|
||||
final MgmtAction result = new MgmtAction();
|
||||
|
||||
result.setActionId(action.getId());
|
||||
result.setType(getType(action));
|
||||
if (ActionType.TIMEFORCED == action.getActionType()) {
|
||||
result.setForceTime(action.getForcedTime());
|
||||
}
|
||||
action.getWeight().ifPresent(result::setWeight);
|
||||
result.setActionType(MgmtRestModelMapper.convertActionType(action.getActionType()));
|
||||
|
||||
if (action.isActive()) {
|
||||
result.setStatus(MgmtAction.ACTION_PENDING);
|
||||
} else {
|
||||
result.setStatus(MgmtAction.ACTION_FINISHED);
|
||||
}
|
||||
|
||||
result.setDetailStatus(action.getStatus().toString().toLowerCase());
|
||||
|
||||
action.getLastActionStatusCode().ifPresent(statusCode -> {
|
||||
result.setLastStatusCode(statusCode);
|
||||
});
|
||||
|
||||
final Rollout rollout = action.getRollout();
|
||||
if (rollout != null) {
|
||||
result.setRollout(rollout.getId());
|
||||
result.setRolloutName(rollout.getName());
|
||||
}
|
||||
|
||||
if (action.hasMaintenanceSchedule()) {
|
||||
final MgmtMaintenanceWindow maintenanceWindow = new MgmtMaintenanceWindow();
|
||||
maintenanceWindow.setSchedule(action.getMaintenanceWindowSchedule());
|
||||
maintenanceWindow.setDuration(action.getMaintenanceWindowDuration());
|
||||
maintenanceWindow.setTimezone(action.getMaintenanceWindowTimeZone());
|
||||
action.getMaintenanceWindowStartTime()
|
||||
.ifPresent(nextStart -> maintenanceWindow.setNextStartAt(nextStart.toInstant().toEpochMilli()));
|
||||
result.setMaintenanceWindow(maintenanceWindow);
|
||||
}
|
||||
|
||||
final String externalRef = action.getExternalRef();
|
||||
if (!ObjectUtils.isEmpty(externalRef)) {
|
||||
result.setExternalRef(externalRef);
|
||||
}
|
||||
|
||||
MgmtRestModelMapper.mapBaseToBase(result, action);
|
||||
|
||||
result.add(
|
||||
linkTo(methodOn(MgmtTargetRestApi.class).getAction(targetId, action.getId())).withSelfRel().expand());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static MgmtAction toResponseWithLinks(final String controllerId, final Action action) {
|
||||
final MgmtAction result = toResponse(controllerId, action);
|
||||
|
||||
if (action.isCancelingOrCanceled()) {
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getAction(controllerId, action.getId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_CANCELED_ACTION).expand());
|
||||
}
|
||||
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getTarget(controllerId)).withRel("target")
|
||||
.withName(action.getTarget().getName()).expand());
|
||||
|
||||
final DistributionSet distributionSet = action.getDistributionSet();
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(distributionSet.getId()))
|
||||
.withRel("distributionset").withName(distributionSet.getName() + ":" + distributionSet.getVersion())
|
||||
.expand());
|
||||
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionStatusList(controllerId, action.getId(), 0,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
||||
ActionStatusFields.ID.getJpaEntityFieldName() + ":" + SortDirection.DESC))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ACTION_STATUS).expand());
|
||||
|
||||
final Rollout rollout = action.getRollout();
|
||||
if (rollout != null) {
|
||||
result.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRollout(rollout.getId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ROLLOUT).withName(rollout.getName()).expand());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<MgmtAction> toResponse(final String targetId, final Collection<Action> actions) {
|
||||
if (actions == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return actions.stream().map(action -> toResponse(targetId, action)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtMetadata toResponseTargetMetadata(final TargetMetadata metadata) {
|
||||
final MgmtMetadata metadataRest = new MgmtMetadata();
|
||||
metadataRest.setKey(metadata.getKey());
|
||||
metadataRest.setValue(metadata.getValue());
|
||||
return metadataRest;
|
||||
}
|
||||
|
||||
static List<MgmtMetadata> toResponseTargetMetadata(final List<TargetMetadata> metadata) {
|
||||
return metadata.stream().map(MgmtTargetMapper::toResponseTargetMetadata).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static void addPollStatus(final Target target, final MgmtTarget targetRest, final Function<Target, PollStatus> pollStatusResolver) {
|
||||
final PollStatus pollStatus = pollStatusResolver == null ? target.getPollStatus() : pollStatusResolver.apply(target);
|
||||
if (pollStatus != null) {
|
||||
final MgmtPollStatus pollStatusRest = new MgmtPollStatus();
|
||||
pollStatusRest.setLastRequestAt(
|
||||
Date.from(pollStatus.getLastPollDate().atZone(ZoneId.systemDefault()).toInstant()).getTime());
|
||||
pollStatusRest.setNextExpectedRequestAt(
|
||||
Date.from(pollStatus.getNextPollDate().atZone(ZoneId.systemDefault()).toInstant()).getTime());
|
||||
pollStatusRest.setOverdue(pollStatus.isOverdue());
|
||||
targetRest.setPollStatus(pollStatusRest);
|
||||
}
|
||||
}
|
||||
|
||||
private static TargetCreate fromRequest(final EntityFactory entityFactory, final MgmtTargetRequestBody targetRest) {
|
||||
return entityFactory.target().create().controllerId(targetRest.getControllerId()).name(targetRest.getName())
|
||||
.description(targetRest.getDescription()).securityToken(targetRest.getSecurityToken())
|
||||
.address(targetRest.getAddress()).targetType(targetRest.getTargetType());
|
||||
}
|
||||
|
||||
private static String getType(final Action action) {
|
||||
if (!action.isCancelingOrCanceled()) {
|
||||
return MgmtAction.ACTION_UPDATE;
|
||||
} else if (action.isCancelingOrCanceled()) {
|
||||
return MgmtAction.ACTION_CANCEL;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static MgmtActionStatus toResponse(final ActionStatus actionStatus, final List<String> messages) {
|
||||
final MgmtActionStatus result = new MgmtActionStatus();
|
||||
|
||||
result.setMessages(messages);
|
||||
result.setReportedAt(actionStatus.getCreatedAt());
|
||||
result.setStatusId(actionStatus.getId());
|
||||
result.setType(actionStatus.getStatus().name().toLowerCase());
|
||||
actionStatus.getCode().ifPresent(result::setCode);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionStatus;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag;
|
||||
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.mgmt.rest.resource.util.PagingUtility;
|
||||
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;
|
||||
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.repository.model.TargetTag;
|
||||
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.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling target CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTargetResource implements MgmtTargetRestApi {
|
||||
|
||||
private static final String ACTION_TARGET_MISSING_ASSIGN_WARN = "given action ({}) is not assigned to given target ({}).";
|
||||
|
||||
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 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, tenantConfigHelper, null);
|
||||
MgmtTargetMapper.addTargetLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getTargets(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Slice<Target> findTargetsAll;
|
||||
final long countTargetsAll;
|
||||
if (rsqlParam != null) {
|
||||
findTargetsAll = targetManagement.findByRsql(pageable, rsqlParam);
|
||||
countTargetsAll = targetManagement.countByRsql(rsqlParam);
|
||||
} else {
|
||||
findTargetsAll = targetManagement.findAll(pageable);
|
||||
countTargetsAll = targetManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countTargetsAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTarget>> createTargets(@RequestBody final List<MgmtTargetRequestBody> targets) {
|
||||
log.debug("creating {} targets", targets.size());
|
||||
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, tenantConfigHelper),
|
||||
HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTarget> updateTarget(@PathVariable("targetId") final String targetId,
|
||||
@RequestBody final MgmtTargetRequestBody targetRest) {
|
||||
|
||||
if (targetRest.getRequestAttributes() != null) {
|
||||
if (targetRest.getRequestAttributes()) {
|
||||
targetManagement.requestControllerAttributes(targetId);
|
||||
} else {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
}
|
||||
|
||||
Target updateTarget;
|
||||
|
||||
if (targetRest.getTargetType() != null && targetRest.getTargetType() == -1L) {
|
||||
// if targetType in request is -1 - unassign targetType from target
|
||||
this.targetManagement.unassignType(targetId);
|
||||
// update target without targetType here ...
|
||||
updateTarget = this.targetManagement.update(entityFactory.target().update(targetId)
|
||||
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
|
||||
.securityToken(targetRest.getSecurityToken()).requestAttributes(targetRest.getRequestAttributes()));
|
||||
|
||||
} else {
|
||||
updateTarget = this.targetManagement.update(
|
||||
entityFactory.target().update(targetId).name(targetRest.getName()).description(targetRest.getDescription())
|
||||
.address(targetRest.getAddress()).targetType(targetRest.getTargetType())
|
||||
.securityToken(targetRest.getSecurityToken())
|
||||
.requestAttributes(targetRest.getRequestAttributes()));
|
||||
|
||||
}
|
||||
|
||||
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget, tenantConfigHelper, null);
|
||||
MgmtTargetMapper.addTargetLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTarget(@PathVariable("targetId") final String targetId) {
|
||||
this.targetManagement.deleteByControllerID(targetId);
|
||||
log.debug("{} target deleted, return status {}", targetId, HttpStatus.OK);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignTargetType(@PathVariable("targetId") final String targetId) {
|
||||
this.targetManagement.unassignType(targetId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignTargetType(@PathVariable("targetId") final String targetId,
|
||||
@RequestBody final MgmtId targetTypeId) {
|
||||
this.targetManagement.assignType(targetId, targetTypeId.getId());
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetAttributes> getAttributes(@PathVariable("targetId") final String targetId) {
|
||||
final Map<String, String> controllerAttributes = targetManagement.getControllerAttributes(targetId);
|
||||
if (controllerAttributes.isEmpty()) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
final MgmtTargetAttributes result = new MgmtTargetAttributes();
|
||||
result.putAll(controllerAttributes);
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtAction>> getActionHistory(@PathVariable("targetId") final String targetId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
findTargetWithExceptionIfNotFound(targetId);
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeActionSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<Action> activeActions;
|
||||
final Long totalActionCount;
|
||||
if (rsqlParam != null) {
|
||||
activeActions = this.deploymentManagement.findActionsByTarget(rsqlParam, targetId, pageable);
|
||||
totalActionCount = this.deploymentManagement.countActionsByTarget(rsqlParam, targetId);
|
||||
} else {
|
||||
activeActions = this.deploymentManagement.findActionsByTarget(targetId, pageable);
|
||||
totalActionCount = this.deploymentManagement.countActionsByTarget(targetId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(
|
||||
new PagedList<>(MgmtTargetMapper.toResponse(targetId, activeActions.getContent()), totalActionCount));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtAction> getAction(@PathVariable("targetId") final String targetId,
|
||||
@PathVariable("actionId") final Long actionId) {
|
||||
|
||||
final Action action = deploymentManagement.findAction(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
if (!action.getTarget().getControllerId().equals(targetId)) {
|
||||
log.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, action.getId(), targetId);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(targetId, action));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> cancelAction(@PathVariable("targetId") final String targetId,
|
||||
@PathVariable("actionId") final Long actionId,
|
||||
@RequestParam(value = "force", required = false, defaultValue = "false") final boolean force) {
|
||||
final Action action = deploymentManagement.findAction(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
|
||||
if (!action.getTarget().getControllerId().equals(targetId)) {
|
||||
log.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, actionId, targetId);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
if (force) {
|
||||
this.deploymentManagement.forceQuitAction(actionId);
|
||||
} else {
|
||||
this.deploymentManagement.cancelAction(actionId);
|
||||
}
|
||||
// both functions will throw an exception, when action is in wrong
|
||||
// state, which is mapped by MgmtResponseExceptionHandler.
|
||||
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtAction> updateAction(@PathVariable("targetId") final String targetId,
|
||||
@PathVariable("actionId") final Long actionId, @RequestBody final MgmtActionRequestBodyPut actionUpdate) {
|
||||
|
||||
Action action = deploymentManagement.findAction(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
if (!action.getTarget().getControllerId().equals(targetId)) {
|
||||
log.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, action.getId(), targetId);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
if (MgmtActionType.FORCED != actionUpdate.getActionType()) {
|
||||
throw new ValidationException("Resource supports only switch to FORCED.");
|
||||
}
|
||||
|
||||
action = deploymentManagement.forceTargetAction(actionId);
|
||||
|
||||
return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(targetId, action));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtActionStatus>> getActionStatusList(
|
||||
@PathVariable("targetId") final String targetId, @PathVariable("actionId") final Long actionId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam) {
|
||||
|
||||
final Target target = findTargetWithExceptionIfNotFound(targetId);
|
||||
|
||||
final Action action = deploymentManagement.findAction(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
|
||||
if (!action.getTarget().getId().equals(target.getId())) {
|
||||
log.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, action.getId(), target.getId());
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeActionStatusSortParam(sortParam);
|
||||
|
||||
final Page<ActionStatus> statusList = this.deploymentManagement.findActionStatusByAction(
|
||||
new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting), action.getId());
|
||||
|
||||
return ResponseEntity.ok(new PagedList<>(
|
||||
MgmtTargetMapper.toActionStatusRestResponse(statusList.getContent(), deploymentManagement),
|
||||
statusList.getTotalElements()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> getAssignedDistributionSet(
|
||||
@PathVariable("targetId") final String targetId) {
|
||||
final MgmtDistributionSet distributionSetRest = deploymentManagement.getAssignedDistributionSet(targetId)
|
||||
.map(ds -> {
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(ds);
|
||||
MgmtDistributionSetMapper.addLinks(ds, response);
|
||||
|
||||
return response;
|
||||
}).orElse(null);
|
||||
|
||||
if (distributionSetRest == null) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
return ResponseEntity.ok(distributionSetRest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetAssignmentResponseBody> postAssignedDistributionSet(
|
||||
@PathVariable("targetId") final String targetId,
|
||||
@RequestBody final MgmtDistributionSetAssignments dsAssignments,
|
||||
@RequestParam(value = "offline", required = false) final Boolean offline) {
|
||||
if (offline != null && offline) {
|
||||
final List<Entry<String, Long>> offlineAssignments = dsAssignments.stream()
|
||||
.map(dsAssignment -> new SimpleEntry<String, Long>(targetId, dsAssignment.getId()))
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper
|
||||
.toResponse(deploymentManagement.offlineAssignedDistributionSets(offlineAssignments)));
|
||||
}
|
||||
findTargetWithExceptionIfNotFound(targetId);
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = dsAssignments.stream().map(dsAssignment -> {
|
||||
final boolean isConfirmationRequired = dsAssignment.getConfirmationRequired() == null
|
||||
? tenantConfigHelper.isConfirmationFlowEnabled()
|
||||
: dsAssignment.getConfirmationRequired();
|
||||
return MgmtDeploymentRequestMapper.createAssignmentRequestBuilder(dsAssignment, targetId)
|
||||
.setConfirmationRequired(isConfirmationRequired).build();
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
final List<DistributionSetAssignmentResult> assignmentResults = deploymentManagement
|
||||
.assignDistributionSets(deploymentRequests);
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponse(assignmentResults));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> getInstalledDistributionSet(
|
||||
@PathVariable("targetId") final String targetId) {
|
||||
final MgmtDistributionSet distributionSetRest = deploymentManagement.getInstalledDistributionSet(targetId)
|
||||
.map(set -> {
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(set);
|
||||
MgmtDistributionSetMapper.addLinks(set, response);
|
||||
|
||||
return response;
|
||||
}).orElse(null);
|
||||
|
||||
if (distributionSetRest == null) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(distributionSetRest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTag>> getTags(@PathVariable("targetId") String targetId) {
|
||||
final Set<TargetTag> tags = targetManagement.getTagsByControllerId(targetId);
|
||||
return ResponseEntity.ok(
|
||||
MgmtTagMapper.toResponse(tags == null ? Collections.emptyList() : tags.stream().toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtMetadata>> getMetadata(@PathVariable("targetId") final String targetId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeDistributionSetMetadataSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<TargetMetadata> metaDataPage;
|
||||
|
||||
if (rsqlParam != null) {
|
||||
metaDataPage = targetManagement.findMetaDataByControllerIdAndRsql(pageable, targetId, rsqlParam);
|
||||
} else {
|
||||
metaDataPage = targetManagement.findMetaDataByControllerId(pageable, targetId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(new PagedList<>(MgmtTargetMapper.toResponseTargetMetadata(metaDataPage.getContent()),
|
||||
metaDataPage.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtMetadata> getMetadataValue(@PathVariable("targetId") final String targetId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
final TargetMetadata findOne = targetManagement.getMetaDataByControllerId(targetId, metadataKey)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetMetadata.class, targetId, metadataKey));
|
||||
return ResponseEntity.ok(MgmtTargetMapper.toResponseTargetMetadata(findOne));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("targetId") final String targetId,
|
||||
@PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadataBodyPut metadata) {
|
||||
final TargetMetadata updated = targetManagement.updateMetadata(targetId,
|
||||
entityFactory.generateTargetMetadata(metadataKey, metadata.getValue()));
|
||||
return ResponseEntity.ok(MgmtTargetMapper.toResponseTargetMetadata(updated));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteMetadata(@PathVariable("targetId") final String targetId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
targetManagement.deleteMetaData(targetId, metadataKey);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtMetadata>> createMetadata(@PathVariable("targetId") final String targetId,
|
||||
@RequestBody final List<MgmtMetadata> metadataRest) {
|
||||
final List<TargetMetadata> created = targetManagement.createMetaData(targetId,
|
||||
MgmtTargetMapper.fromRequestTargetMetadata(metadataRest, entityFactory));
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deactivateAutoConfirm(@PathVariable("targetId") final String targetId) {
|
||||
confirmationManagement.deactivateAutoConfirmation(targetId);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
private Target findTargetWithExceptionIfNotFound(final String targetId) {
|
||||
return targetManagement.getByControllerID(targetId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, targetId));
|
||||
}
|
||||
|
||||
private <T, R> R getNullIfEmpty(final T object, final Function<T, R> extractMethod) {
|
||||
return object == null ? null : extractMethod.apply(object);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedTargetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTargetTagAssigmentResult;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
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.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for tag CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
|
||||
|
||||
private final TargetTagManagement tagManagement;
|
||||
|
||||
private final TargetManagement targetManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
MgmtTargetTagResource(final TargetTagManagement tagManagement, final TargetManagement targetManagement,
|
||||
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
|
||||
public ResponseEntity<PagedList<MgmtTag>> getTargetTags(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTagSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
Page<TargetTag> findTargetsAll;
|
||||
if (rsqlParam == null) {
|
||||
findTargetsAll = this.tagManagement.findAll(pageable);
|
||||
|
||||
} else {
|
||||
findTargetsAll = this.tagManagement.findByRsql(pageable, rsqlParam);
|
||||
|
||||
}
|
||||
|
||||
final List<MgmtTag> rest = MgmtTagMapper.toResponse(findTargetsAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, findTargetsAll.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTag> getTargetTag(@PathVariable("targetTagId") final Long targetTagId) {
|
||||
final TargetTag tag = findTargetTagById(targetTagId);
|
||||
|
||||
final MgmtTag response = MgmtTagMapper.toResponse(tag);
|
||||
MgmtTagMapper.addLinks(tag, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTag>> createTargetTags(@RequestBody final List<MgmtTagRequestBodyPut> tags) {
|
||||
log.debug("creating {} target tags", tags.size());
|
||||
final List<TargetTag> createdTargetTags = this.tagManagement
|
||||
.create(MgmtTagMapper.mapTagFromRequest(entityFactory, tags));
|
||||
return new ResponseEntity<>(MgmtTagMapper.toResponse(createdTargetTags), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTag> updateTargetTag(@PathVariable("targetTagId") final Long targetTagId,
|
||||
@RequestBody final MgmtTagRequestBodyPut restTargetTagRest) {
|
||||
log.debug("update {} target tag", restTargetTagRest);
|
||||
|
||||
final TargetTag updateTargetTag = tagManagement
|
||||
.update(entityFactory.tag().update(targetTagId).name(restTargetTagRest.getName())
|
||||
.description(restTargetTagRest.getDescription()).colour(restTargetTagRest.getColour()));
|
||||
|
||||
log.debug("target tag updated");
|
||||
|
||||
final MgmtTag response = MgmtTagMapper.toResponse(updateTargetTag);
|
||||
MgmtTagMapper.addLinks(updateTargetTag, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTargetTag(@PathVariable("targetTagId") final Long targetTagId) {
|
||||
log.debug("Delete {} target tag", targetTagId);
|
||||
final TargetTag targetTag = findTargetTagById(targetTagId);
|
||||
|
||||
this.tagManagement.delete(targetTag.getName());
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<Target> findTargetsAll;
|
||||
if (rsqlParam == null) {
|
||||
findTargetsAll = targetManagement.findByTag(pageable, targetTagId);
|
||||
} else {
|
||||
findTargetsAll = targetManagement.findByRsqlAndTag(pageable, rsqlParam, targetTagId);
|
||||
}
|
||||
|
||||
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, findTargetsAll.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignTarget(final Long targetTagId, final String controllerId) {
|
||||
log.debug("Assign target {} for target tag {}", controllerId, targetTagId);
|
||||
this.targetManagement.assignTag(List.of(controllerId), targetTagId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignTargets(final Long targetTagId, final OnNotFoundPolicy onNotFoundPolicy,
|
||||
final List<String> controllerIds) {
|
||||
log.debug("Assign {} targets for target tag {}", controllerIds.size(), targetTagId);
|
||||
if (onNotFoundPolicy == OnNotFoundPolicy.FAIL) {
|
||||
this.targetManagement.assignTag(controllerIds, targetTagId);
|
||||
} else {
|
||||
final AtomicReference<Collection<String>> notFound = new AtomicReference<>();
|
||||
this.targetManagement.assignTag(controllerIds, targetTagId, notFound::set);
|
||||
if (notFound.get() != null) {
|
||||
// has not found
|
||||
if (onNotFoundPolicy == OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL) {
|
||||
throw new EntityNotFoundException(Target.class, notFound.get());
|
||||
} // else - success
|
||||
}
|
||||
}
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignTarget(final Long targetTagId,
|
||||
@PathVariable("controllerId") final String controllerId) {
|
||||
log.debug("Unassign target {} for target tag {}", controllerId, targetTagId);
|
||||
this.targetManagement.unassignTag(controllerId, targetTagId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignTargets(final Long targetTagId, final OnNotFoundPolicy onNotFoundPolicy,
|
||||
final List<String> controllerIds) {
|
||||
log.debug("Unassign {} targets for target tag {}", controllerIds.size(), targetTagId);
|
||||
if (onNotFoundPolicy == OnNotFoundPolicy.FAIL) {
|
||||
this.targetManagement.unassignTag(controllerIds, targetTagId);
|
||||
} else {
|
||||
final AtomicReference<Collection<String>> notFound = new AtomicReference<>();
|
||||
this.targetManagement.unassignTag(controllerIds, targetTagId, notFound::set);
|
||||
if (notFound.get() != null) {
|
||||
// has not found
|
||||
if (onNotFoundPolicy == OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL) {
|
||||
throw new EntityNotFoundException(Target.class, notFound.get());
|
||||
} // else - success
|
||||
}
|
||||
}
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetTagAssigmentResult> toggleTagAssignment(
|
||||
@PathVariable("targetTagId") final Long targetTagId,
|
||||
@RequestBody final List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies) {
|
||||
log.debug("Toggle Target assignment {} for target tag {}", assignedTargetRequestBodies.size(), targetTagId);
|
||||
|
||||
final TargetTag targetTag = findTargetTagById(targetTagId);
|
||||
final TargetTagAssignmentResult assigmentResult = this.targetManagement
|
||||
.toggleTagAssignment(findTargetControllerIds(assignedTargetRequestBodies), targetTag.getName());
|
||||
|
||||
final MgmtTargetTagAssigmentResult tagAssigmentResultRest = new MgmtTargetTagAssigmentResult();
|
||||
tagAssigmentResultRest.setAssignedTargets(
|
||||
MgmtTargetMapper.toResponse(assigmentResult.getAssignedEntity(), tenantConfigHelper));
|
||||
tagAssigmentResultRest.setUnassignedTargets(
|
||||
MgmtTargetMapper.toResponse(assigmentResult.getUnassignedEntity(), tenantConfigHelper));
|
||||
return ResponseEntity.ok(tagAssigmentResultRest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTarget>> assignTargetsByRequestBody(@PathVariable("targetTagId") final Long targetTagId,
|
||||
@RequestBody final List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies) {
|
||||
log.debug("Assign targets {} for target tag {}", assignedTargetRequestBodies, targetTagId);
|
||||
final List<Target> assignedTarget = this.targetManagement
|
||||
.assignTag(findTargetControllerIds(assignedTargetRequestBodies), targetTagId);
|
||||
return ResponseEntity.ok(MgmtTargetMapper.toResponse(assignedTarget, tenantConfigHelper));
|
||||
}
|
||||
|
||||
private TargetTag findTargetTagById(final Long targetTagId) {
|
||||
return tagManagement.get(targetTagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagId));
|
||||
}
|
||||
|
||||
private List<String> findTargetControllerIds(
|
||||
final List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies) {
|
||||
return assignedTargetRequestBodies.stream().map(MgmtAssignedTargetRequestBody::getControllerId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and back.
|
||||
*/
|
||||
public final class MgmtTargetTypeMapper {
|
||||
|
||||
// private constructor, utility class
|
||||
private MgmtTargetTypeMapper() {
|
||||
}
|
||||
|
||||
static List<TargetTypeCreate> targetFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtTargetTypeRequestBodyPost> targetTypesRest) {
|
||||
if (targetTypesRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return targetTypesRest.stream().map(targetRest -> fromRequest(entityFactory, targetRest))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtTargetType> toListResponse(final List<TargetType> types) {
|
||||
if (types == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ResponseList<>(types.stream().map(MgmtTargetTypeMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtTargetType toResponse(final TargetType type) {
|
||||
final MgmtTargetType result = new MgmtTargetType();
|
||||
|
||||
MgmtRestModelMapper.mapTypeToType(result, type);
|
||||
result.setTypeId(type.getId());
|
||||
result.add(
|
||||
linkTo(methodOn(MgmtTargetTypeRestApi.class).getTargetType(result.getTypeId())).withSelfRel().expand());
|
||||
return result;
|
||||
}
|
||||
|
||||
static void addLinks(final MgmtTargetType result) {
|
||||
result.add(linkTo(methodOn(MgmtTargetTypeRestApi.class).getCompatibleDistributionSets(result.getTypeId()))
|
||||
.withRel(MgmtRestConstants.TARGETTYPE_V1_DS_TYPES).expand());
|
||||
}
|
||||
|
||||
private static TargetTypeCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtTargetTypeRequestBodyPost targetTypesRest) {
|
||||
return entityFactory.targetType().create()
|
||||
.name(targetTypesRest.getName()).description(targetTypesRest.getDescription())
|
||||
.key(targetTypesRest.getKey()).colour(targetTypesRest.getColour())
|
||||
.compatible(getDistributionSets(targetTypesRest));
|
||||
}
|
||||
|
||||
private static Collection<Long> getDistributionSets(final MgmtTargetTypeRequestBodyPost targetTypesRest) {
|
||||
return Optional.ofNullable(targetTypesRest.getCompatibledistributionsettypes())
|
||||
.map(ds -> ds.stream().map(MgmtDistributionSetTypeAssignment::getId).collect(Collectors.toList()))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link TargetType} CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTargetTypeResource implements MgmtTargetTypeRestApi {
|
||||
|
||||
private final TargetTypeManagement targetTypeManagement;
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
public MgmtTargetTypeResource(final TargetTypeManagement targetTypeManagement, final EntityFactory entityFactory) {
|
||||
this.targetTypeManagement = targetTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTargetType>> getTargetTypes(
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetTypeSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<TargetType> findTargetTypesAll;
|
||||
long countTargetTypesAll;
|
||||
if (rsqlParam != null) {
|
||||
findTargetTypesAll = targetTypeManagement.findByRsql(pageable, rsqlParam);
|
||||
countTargetTypesAll = ((Page<TargetType>) findTargetTypesAll).getTotalElements();
|
||||
} else {
|
||||
findTargetTypesAll = targetTypeManagement.findAll(pageable);
|
||||
countTargetTypesAll = targetTypeManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtTargetType> rest = MgmtTargetTypeMapper.toListResponse(findTargetTypesAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countTargetTypesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetType> getTargetType(@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||
final TargetType foundType = findTargetTypeWithExceptionIfNotFound(targetTypeId);
|
||||
final MgmtTargetType response = MgmtTargetTypeMapper.toResponse(foundType);
|
||||
MgmtTargetTypeMapper.addLinks(response);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTargetType(@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||
log.debug("Delete {} target type", targetTypeId);
|
||||
targetTypeManagement.delete(targetTypeId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetType> updateTargetType(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||
@RequestBody final MgmtTargetTypeRequestBodyPut restTargetType) {
|
||||
|
||||
final TargetType updated = targetTypeManagement
|
||||
.update(entityFactory.targetType().update(targetTypeId).name(restTargetType.getName())
|
||||
.description(restTargetType.getDescription()).colour(restTargetType.getColour()));
|
||||
final MgmtTargetType response = MgmtTargetTypeMapper.toResponse(updated);
|
||||
MgmtTargetTypeMapper.addLinks(response);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTargetType>> createTargetTypes(
|
||||
@RequestBody final List<MgmtTargetTypeRequestBodyPost> targetTypes) {
|
||||
|
||||
final List<TargetType> createdTargetTypes = targetTypeManagement
|
||||
.create(MgmtTargetTypeMapper.targetFromRequest(entityFactory, targetTypes));
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtTargetTypeMapper.toListResponse(createdTargetTypes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtDistributionSetType>> getCompatibleDistributionSets(
|
||||
@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||
|
||||
final TargetType foundType = findTargetTypeWithExceptionIfNotFound(targetTypeId);
|
||||
return ResponseEntity
|
||||
.ok(MgmtDistributionSetTypeMapper.toListResponse(foundType.getCompatibleDistributionSetTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> removeCompatibleDistributionSet(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
|
||||
targetTypeManagement.unassignDistributionSetType(targetTypeId, distributionSetTypeId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> addCompatibleDistributionSets(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||
@RequestBody final List<MgmtDistributionSetTypeAssignment> distributionSetTypeIds) {
|
||||
|
||||
targetTypeManagement.assignCompatibleDistributionSetTypes(targetTypeId, distributionSetTypeIds.stream()
|
||||
.map(MgmtDistributionSetTypeAssignment::getId).collect(Collectors.toList()));
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
private TargetType findTargetTypeWithExceptionIfNotFound(final Long targetTypeId) {
|
||||
return targetTypeManagement.get(targetTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetTypeId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtTenantManagementMapper {
|
||||
|
||||
public static String DEFAULT_DISTRIBUTION_SET_TYPE_KEY = "default.ds.type";
|
||||
|
||||
private MgmtTenantManagementMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
public static MgmtSystemTenantConfigurationValue toResponseTenantConfigurationValue(String key, TenantConfigurationValue<?> repoConfValue) {
|
||||
final MgmtSystemTenantConfigurationValue restConfValue = new MgmtSystemTenantConfigurationValue();
|
||||
restConfValue.setValue(repoConfValue.getValue());
|
||||
restConfValue.setGlobal(repoConfValue.isGlobal());
|
||||
restConfValue.setCreatedAt(repoConfValue.getCreatedAt());
|
||||
restConfValue.setCreatedBy(repoConfValue.getCreatedBy());
|
||||
restConfValue.setLastModifiedAt(repoConfValue.getLastModifiedAt());
|
||||
restConfValue.setLastModifiedBy(repoConfValue.getLastModifiedBy());
|
||||
restConfValue.add(linkTo(methodOn(MgmtTenantManagementResource.class).getTenantConfigurationValue(key))
|
||||
.withSelfRel().expand());
|
||||
return restConfValue;
|
||||
}
|
||||
|
||||
public static MgmtSystemTenantConfigurationValue toResponseDefaultDsType(Long defaultDistributionSetType) {
|
||||
final MgmtSystemTenantConfigurationValue restConfValue = new MgmtSystemTenantConfigurationValue();
|
||||
restConfValue.setValue(defaultDistributionSetType);
|
||||
restConfValue.setGlobal(Boolean.FALSE);
|
||||
restConfValue.add(linkTo(methodOn(MgmtTenantManagementResource.class).getTenantConfigurationValue(DEFAULT_DISTRIBUTION_SET_TYPE_KEY))
|
||||
.withSelfRel().expand());
|
||||
return restConfValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValueRequest;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTenantManagementRestApi;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.eclipse.hawkbit.repository.exception.TenantConfigurationValidatorException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource for handling tenant specific configuration operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi {
|
||||
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final TenantConfigurationProperties tenantConfigurationProperties;
|
||||
private final SystemManagement systemManagement;
|
||||
|
||||
MgmtTenantManagementResource(final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final TenantConfigurationProperties tenantConfigurationProperties,
|
||||
final SystemManagement systemManagement) {
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.tenantConfigurationProperties = tenantConfigurationProperties;
|
||||
this.systemManagement = systemManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Map<String, MgmtSystemTenantConfigurationValue>> getTenantConfiguration() {
|
||||
// Load and Construct default Tenant Configuration
|
||||
final Map<String, MgmtSystemTenantConfigurationValue> tenantConfigurationValueMap = new HashMap<>();
|
||||
tenantConfigurationProperties.getConfigurationKeys().forEach(key -> {
|
||||
try {
|
||||
tenantConfigurationValueMap.put(key.getKeyName(), loadTenantConfigurationValueBy(key.getKeyName()));
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
// some values as gateway token may not be accessibly for the caller - just skip them
|
||||
}
|
||||
});
|
||||
|
||||
// Load and Add Default DistributionSetType
|
||||
final MgmtSystemTenantConfigurationValue defaultDsTypeId = loadTenantConfigurationValueBy(
|
||||
MgmtTenantManagementMapper.DEFAULT_DISTRIBUTION_SET_TYPE_KEY);
|
||||
tenantConfigurationValueMap.put(MgmtTenantManagementMapper.DEFAULT_DISTRIBUTION_SET_TYPE_KEY, defaultDsTypeId);
|
||||
|
||||
// return combined TenantConfiguration and TenantMetadata
|
||||
log.debug("getTenantConfiguration, return status {}", HttpStatus.OK);
|
||||
return ResponseEntity.ok(tenantConfigurationValueMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTenantConfigurationValue(@PathVariable("keyName") final String keyName) {
|
||||
|
||||
//Default DistributionSet Type cannot be deleted as is part of TenantMetadata
|
||||
if (isDefaultDistributionSetTypeKey(keyName)) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
tenantConfigurationManagement.deleteConfiguration(keyName);
|
||||
|
||||
log.debug("{} config value deleted, return status {}", keyName, HttpStatus.OK);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSystemTenantConfigurationValue> getTenantConfigurationValue(
|
||||
@PathVariable("keyName") final String keyName) {
|
||||
return ResponseEntity.ok(loadTenantConfigurationValueBy(keyName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSystemTenantConfigurationValue> updateTenantConfigurationValue(
|
||||
@PathVariable("keyName") final String keyName,
|
||||
@RequestBody final MgmtSystemTenantConfigurationValueRequest configurationValueRest) {
|
||||
Serializable configurationValue = configurationValueRest.getValue();
|
||||
final MgmtSystemTenantConfigurationValue responseUpdatedValue;
|
||||
if (isDefaultDistributionSetTypeKey(keyName)) {
|
||||
responseUpdatedValue = updateDefaultDsType(configurationValue);
|
||||
} else {
|
||||
final TenantConfigurationValue<? extends Serializable> updatedTenantConfigurationValue = tenantConfigurationManagement
|
||||
.addOrUpdateConfiguration(keyName, configurationValueRest.getValue());
|
||||
responseUpdatedValue = MgmtTenantManagementMapper.toResponseTenantConfigurationValue(keyName, updatedTenantConfigurationValue);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(responseUpdatedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSystemTenantConfigurationValue>> updateTenantConfiguration(
|
||||
Map<String, Serializable> configurationValueMap) {
|
||||
|
||||
boolean containsNull = configurationValueMap.keySet().stream()
|
||||
.anyMatch(Objects::isNull);
|
||||
|
||||
if (containsNull) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
//Try update TenantMetadata first
|
||||
Serializable defaultDsTypeValueUpdate = configurationValueMap.remove(MgmtTenantManagementMapper.DEFAULT_DISTRIBUTION_SET_TYPE_KEY);
|
||||
Long oldDefaultDsType = null;
|
||||
MgmtSystemTenantConfigurationValue updatedDefaultDsType = null;
|
||||
if (defaultDsTypeValueUpdate != null) {
|
||||
oldDefaultDsType = systemManagement.getTenantMetadata().getDefaultDsType().getId();
|
||||
updatedDefaultDsType = updateDefaultDsType(defaultDsTypeValueUpdate);
|
||||
}
|
||||
//try update TenantConfiguration, in case of Error -> rollback TenantMetadata
|
||||
Map<String, TenantConfigurationValue<Serializable>> tenantConfigurationValues;
|
||||
try {
|
||||
tenantConfigurationValues = tenantConfigurationManagement.addOrUpdateConfiguration(configurationValueMap);
|
||||
} catch (Exception ex) {
|
||||
//if DefaultDsType was updated, rollback it in case of TenantConfiguration update.
|
||||
if (updatedDefaultDsType != null) {
|
||||
systemManagement.updateTenantMetadata(oldDefaultDsType);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
|
||||
List<MgmtSystemTenantConfigurationValue> tenantConfigurationListUpdated = new java.util.ArrayList<>(
|
||||
tenantConfigurationValues.entrySet().stream()
|
||||
.map(entry -> MgmtTenantManagementMapper.toResponseTenantConfigurationValue(entry.getKey(), entry.getValue()))
|
||||
.toList());
|
||||
if (updatedDefaultDsType != null) {
|
||||
tenantConfigurationListUpdated.add(updatedDefaultDsType);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(tenantConfigurationListUpdated);
|
||||
}
|
||||
|
||||
private static boolean isDefaultDistributionSetTypeKey(String keyName) {
|
||||
return MgmtTenantManagementMapper.DEFAULT_DISTRIBUTION_SET_TYPE_KEY.equals(keyName);
|
||||
}
|
||||
|
||||
private MgmtSystemTenantConfigurationValue loadTenantConfigurationValueBy(String keyName) {
|
||||
|
||||
//Check if requested key is TenantConfiguration or TenantMetadata, load it and return it as rest response
|
||||
MgmtSystemTenantConfigurationValue response;
|
||||
if (isDefaultDistributionSetTypeKey(keyName)) {
|
||||
response = MgmtTenantManagementMapper.toResponseDefaultDsType(systemManagement.getTenantMetadata().getDefaultDsType().getId());
|
||||
} else {
|
||||
response = MgmtTenantManagementMapper.toResponseTenantConfigurationValue(keyName,
|
||||
tenantConfigurationManagement.getConfigurationValue(keyName));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private MgmtSystemTenantConfigurationValue updateDefaultDsType(Serializable defaultDsType) {
|
||||
long updateDefaultDsType;
|
||||
try {
|
||||
updateDefaultDsType = ((Number) defaultDsType).longValue();
|
||||
} catch (ClassCastException cce) {
|
||||
throw new TenantConfigurationValidatorException(String.format(
|
||||
"Default DistributionSetType Value Type is incorrect. Expected Long, received %s", defaultDsType.getClass().getName()));
|
||||
}
|
||||
systemManagement.updateTenantMetadata(updateDefaultDsType);
|
||||
return MgmtTenantManagementMapper.toResponseDefaultDsType(updateDefaultDsType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
|
||||
/**
|
||||
* Exception used by the REST API in case of invalid sort parameter syntax.
|
||||
*/
|
||||
public class SortParameterSyntaxErrorException extends AbstractServerRtException {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SortParameterSyntaxErrorException with {@link SpServerError#SP_REST_SORT_PARAM_SYNTAX} error.
|
||||
*/
|
||||
public SortParameterSyntaxErrorException() {
|
||||
super(SpServerError.SP_REST_SORT_PARAM_SYNTAX);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
|
||||
/**
|
||||
* Exception used by the REST API in case of invalid sort parameter direction name.
|
||||
*/
|
||||
public class SortParameterUnsupportedDirectionException extends AbstractServerRtException {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SortParameterSyntaxErrorException with {@link SpServerError#SP_REST_SORT_PARAM_INVALID_DIRECTION} error.
|
||||
*
|
||||
* @param cause the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted, and indicates
|
||||
* that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public SortParameterUnsupportedDirectionException(final Throwable cause) {
|
||||
super(SpServerError.SP_REST_SORT_PARAM_INVALID_DIRECTION, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
|
||||
/**
|
||||
* Exception used by the REST API in case of invalid field name in the sort parameter.
|
||||
*/
|
||||
public class SortParameterUnsupportedFieldException extends AbstractServerRtException {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SortParameterSyntaxErrorException with {@link SpServerError#SP_REST_SORT_PARAM_INVALID_FIELD} error.
|
||||
*
|
||||
* @param cause the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted, and indicates
|
||||
* that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public SortParameterUnsupportedFieldException(final Throwable cause) {
|
||||
super(SpServerError.SP_REST_SORT_PARAM_INVALID_FIELD, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.util;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.ActionFields;
|
||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetMetadataFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeFields;
|
||||
import org.eclipse.hawkbit.repository.RolloutFields;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
|
||||
import org.eclipse.hawkbit.repository.TagFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeFields;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
|
||||
/**
|
||||
* Utility class for for paged body generation.
|
||||
*/
|
||||
public final class PagingUtility {
|
||||
|
||||
/*
|
||||
* utility constructor private.
|
||||
*/
|
||||
private PagingUtility() {
|
||||
}
|
||||
|
||||
public static int sanitizeOffsetParam(final int offset) {
|
||||
if (offset < 0) {
|
||||
return MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
public static int sanitizePageLimitParam(final int pageLimit) {
|
||||
if (pageLimit < 1) {
|
||||
return MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE;
|
||||
} else if (pageLimit > MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT) {
|
||||
return MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT;
|
||||
}
|
||||
return pageLimit;
|
||||
}
|
||||
|
||||
public static Sort sanitizeTargetSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, TargetFields.CONTROLLERID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(TargetFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeTargetTypeSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, TargetTypeFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(TargetTypeFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeTagSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, TagFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(TagFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeTargetFilterQuerySortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, TargetFilterQueryFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(TargetFilterQueryFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeSoftwareModuleSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, SoftwareModuleFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(SoftwareModuleFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeSoftwareModuleTypeSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, SoftwareModuleTypeFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(SoftwareModuleTypeFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeDistributionSetSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, DistributionSetFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(DistributionSetFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeDistributionSetTypeSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, DistributionSetTypeFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(DistributionSetTypeFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeActionSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default sort is DESC in case of action to match behavior
|
||||
// of management UI (last entry on top)
|
||||
return Sort.by(Direction.DESC, ActionFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(ActionFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeActionStatusSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default sort is DESC in case of action status to match behavior
|
||||
// of management UI (last entry on top)
|
||||
return Sort.by(Direction.DESC, ActionStatusFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(ActionStatusFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeDistributionSetMetadataSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, DistributionSetMetadataFields.KEY.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(DistributionSetMetadataFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeSoftwareModuleMetadataSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, SoftwareModuleMetadataFields.KEY.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(SoftwareModuleMetadataFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeRolloutSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, RolloutFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(RolloutFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeRolloutGroupSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, RolloutGroupFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(RolloutGroupFields.class, sortParam));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterSyntaxErrorException;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedDirectionException;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
|
||||
/**
|
||||
* A utility class for parsing query parameters which define the sorting of elements.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class SortUtility {
|
||||
|
||||
/**
|
||||
* the delimiter between the different field directions in the sort request.
|
||||
*/
|
||||
public static final String DELIMITER_SORT_TUPLE = ",";
|
||||
/**
|
||||
* the delimiter between the field and direction in the sort request.
|
||||
*/
|
||||
public static final String DELIMITER_FIELD_DIRECTION = ":";
|
||||
|
||||
/**
|
||||
* Parses the sort string e.g. given in a REST call based on the definition
|
||||
* of sorting: <code>http://localhost/entity?s=field1:ASC,field2:DESC</code> The fields
|
||||
* will be split into the keys of the returned map. The direction of the
|
||||
* sorting will be mapped into the {@link Direction} enum.
|
||||
*
|
||||
* @param enumType the class of the enum which the fields in the sort string should be related to.
|
||||
* @param <T> the type of the enumeration which must be derived from {@link RsqlQueryField}
|
||||
* @param sortString the string representation of the query parameters. Might be {@code null} or an empty string.
|
||||
* @return a list which holds the {@link RsqlQueryField} and the specific {@link Direction} for them as a tuple. Never {@code null}.
|
||||
* In case of no sorting parameters an empty map will be returned.
|
||||
* @throws SortParameterSyntaxErrorException if the sorting query parameter is not well-formed
|
||||
* @throws SortParameterUnsupportedFieldException if a field name cannot be mapped to the enum type
|
||||
* @throws SortParameterUnsupportedDirectionException if the given direction is not "ASC" or "DESC"
|
||||
*/
|
||||
public static <T extends Enum<T> & RsqlQueryField> List<Order> parse(final Class<T> enumType, final String sortString)
|
||||
throws SortParameterSyntaxErrorException {
|
||||
final List<Order> orders = new ArrayList<>();
|
||||
// scan the sort tuples e.g. field:direction
|
||||
if (sortString != null) {
|
||||
final StringTokenizer tupleTokenizer = new StringTokenizer(sortString, DELIMITER_SORT_TUPLE);
|
||||
while (tupleTokenizer.hasMoreTokens()) {
|
||||
final String sortTuple = tupleTokenizer.nextToken().trim();
|
||||
final StringTokenizer fieldDirectionTokenizer = new StringTokenizer(sortTuple, DELIMITER_FIELD_DIRECTION);
|
||||
if (fieldDirectionTokenizer.countTokens() == 2) {
|
||||
final String fieldName = fieldDirectionTokenizer.nextToken().trim().toUpperCase();
|
||||
final String sortDirectionStr = fieldDirectionTokenizer.nextToken().trim();
|
||||
|
||||
final T identifier;
|
||||
try {
|
||||
identifier = Enum.valueOf(enumType, fieldName.toUpperCase());
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new SortParameterUnsupportedFieldException(e);
|
||||
}
|
||||
|
||||
final Direction sortDirection;
|
||||
try {
|
||||
sortDirection = Direction.fromString(sortDirectionStr);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new SortParameterUnsupportedDirectionException(e);
|
||||
}
|
||||
|
||||
orders.add(new Order(sortDirection, identifier.getJpaEntityFieldName()));
|
||||
} else {
|
||||
throw new SortParameterSyntaxErrorException();
|
||||
}
|
||||
}
|
||||
}
|
||||
return orders;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# Copyright (c) 2018 Microsoft and others
|
||||
#
|
||||
# This program and the accompanying materials are made
|
||||
# available under the terms of the Eclipse Public License 2.0
|
||||
# which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
#
|
||||
# SPDX-License-Identifier: EPL-2.0
|
||||
#
|
||||
|
||||
# Upload of large files
|
||||
spring.servlet.multipart.max-file-size=1024MB
|
||||
spring.servlet.multipart.max-request-size=-1
|
||||
spring.servlet.multipart.file-size-threshold=1MB
|
||||
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.NamedVersionedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.test.TestConfiguration;
|
||||
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
|
||||
import org.eclipse.hawkbit.rest.RestConfiguration;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
||||
@ContextConfiguration(classes = { MgmtApiConfiguration.class, RestConfiguration.class,
|
||||
RepositoryApplicationConfiguration.class, TestConfiguration.class })
|
||||
@Import(TestChannelBinderConfiguration.class)
|
||||
@TestPropertySource(locations = "classpath:/mgmt-test.properties")
|
||||
public abstract class AbstractManagementApiIntegrationTest extends AbstractRestIntegrationTest {
|
||||
|
||||
protected static ResultMatcher applyBaseEntityMatcherOnArrayResult(final BaseEntity entity,
|
||||
final String arrayElement) throws Exception {
|
||||
return mvcResult -> {
|
||||
jsonPath("$." + arrayElement + ".[?(@.id==" + entity.getId() + ")].createdBy",
|
||||
contains(entity.getCreatedBy())).match(mvcResult);
|
||||
jsonPath("$." + arrayElement + ".[?(@.id==" + entity.getId() + ")].createdAt",
|
||||
contains(entity.getCreatedAt())).match(mvcResult);
|
||||
jsonPath("$." + arrayElement + ".[?(@.id==" + entity.getId() + ")].lastModifiedBy",
|
||||
contains(entity.getLastModifiedBy())).match(mvcResult);
|
||||
jsonPath("$." + arrayElement + ".[?(@.id==" + entity.getId() + ")].lastModifiedAt",
|
||||
contains(entity.getLastModifiedAt())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyTargetEntityMatcherOnArrayResult(final Target entity, final String arrayElement)
|
||||
throws Exception {
|
||||
return mvcResult -> {
|
||||
jsonPath("$." + arrayElement + ".[?(@.controllerId=='" + entity.getControllerId() + "')].createdBy",
|
||||
contains(entity.getCreatedBy())).match(mvcResult);
|
||||
jsonPath("$." + arrayElement + ".[?(@.controllerId=='" + entity.getControllerId() + "')].createdAt",
|
||||
contains(entity.getCreatedAt())).match(mvcResult);
|
||||
jsonPath("$." + arrayElement + ".[?(@.controllerId=='" + entity.getControllerId() + "')].lastModifiedBy",
|
||||
contains(entity.getLastModifiedBy())).match(mvcResult);
|
||||
jsonPath("$." + arrayElement + ".[?(@.controllerId=='" + entity.getControllerId() + "')].lastModifiedAt",
|
||||
contains(entity.getLastModifiedAt())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyBaseEntityMatcherOnPagedResult(final BaseEntity entity) throws Exception {
|
||||
return applyBaseEntityMatcherOnArrayResult(entity, "content");
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyNamedEntityMatcherOnPagedResult(final NamedEntity entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
applyBaseEntityMatcherOnPagedResult(entity).match(mvcResult);
|
||||
jsonPath("$.content.[?(@.id==" + entity.getId() + ")].name", contains(entity.getName())).match(mvcResult);
|
||||
jsonPath("$.content.[?(@.id==" + entity.getId() + ")].description", contains(entity.getDescription()))
|
||||
.match(mvcResult);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyNamedVersionedEntityMatcherOnPagedResult(final NamedVersionedEntity entity)
|
||||
throws Exception {
|
||||
return mvcResult -> {
|
||||
applyNamedEntityMatcherOnPagedResult(entity).match(mvcResult);
|
||||
jsonPath("$.content.[?(@.id==" + entity.getId() + ")].version", contains(entity.getVersion()))
|
||||
.match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyTagMatcherOnPagedResult(final Tag entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
applyNamedEntityMatcherOnPagedResult(entity).match(mvcResult);
|
||||
jsonPath("$.content.[?(@.id==" + entity.getId() + ")].colour", contains(entity.getColour()))
|
||||
.match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applySelfLinkMatcherOnPagedResult(final BaseEntity entity, final String link)
|
||||
throws Exception {
|
||||
|
||||
return mvcResult -> {
|
||||
jsonPath("$.content.[?(@.id==" + entity.getId() + ")]._links.self.href", contains(link)).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyBaseEntityMatcherOnArrayResult(final BaseEntity entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
jsonPath("$.[?(@.id==" + entity.getId() + ")].createdBy", contains(entity.getCreatedBy())).match(mvcResult);
|
||||
jsonPath("$.[?(@.id==" + entity.getId() + ")].createdAt", contains(entity.getCreatedAt())).match(mvcResult);
|
||||
jsonPath("$.[?(@.id==" + entity.getId() + ")].lastModifiedBy", contains(entity.getLastModifiedBy()))
|
||||
.match(mvcResult);
|
||||
jsonPath("$.[?(@.id==" + entity.getId() + ")].lastModifiedAt", contains(entity.getLastModifiedAt()))
|
||||
.match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyTargetEntityMatcherOnArrayResult(final Target entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
jsonPath("$.[?(@.controllerId=='" + entity.getControllerId() + "')].createdBy",
|
||||
contains(entity.getCreatedBy())).match(mvcResult);
|
||||
jsonPath("$.[?(@.controllerId=='" + entity.getControllerId() + "')].createdAt",
|
||||
contains(entity.getCreatedAt())).match(mvcResult);
|
||||
jsonPath("$.[?(@.controllerId=='" + entity.getControllerId() + "')].lastModifiedBy",
|
||||
contains(entity.getLastModifiedBy())).match(mvcResult);
|
||||
jsonPath("$.[?(@.controllerId=='" + entity.getControllerId() + "')].lastModifiedAt",
|
||||
contains(entity.getLastModifiedAt())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyNamedEntityMatcherOnArrayResult(final NamedEntity entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
applyBaseEntityMatcherOnPagedResult(entity);
|
||||
|
||||
jsonPath("$.[?(@.id=='" + entity.getId() + "')].name", contains(entity.getName())).match(mvcResult);
|
||||
jsonPath("$.[?(@.id=='" + entity.getId() + "')].description", contains(entity.getDescription()))
|
||||
.match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyNamedVersionedEntityMatcherOnArrayResult(final NamedVersionedEntity entity)
|
||||
throws Exception {
|
||||
return mvcResult -> {
|
||||
applyNamedEntityMatcherOnPagedResult(entity);
|
||||
|
||||
jsonPath("$.[?(@.id=='" + entity.getId() + "')].version", contains(entity.getVersion())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyTagMatcherOnArrayResult(final Tag entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
applyNamedEntityMatcherOnPagedResult(entity);
|
||||
|
||||
jsonPath("$.[?(@.id=='" + entity.getId() + "')].colour", contains(entity.getColour())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applySelfLinkMatcherOnArrayResult(final BaseEntity entity, final String link)
|
||||
throws Exception {
|
||||
return mvcResult -> {
|
||||
jsonPath("$.[?(@.id=='" + entity.getId() + "')]._links.self.href", contains(link)).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyBaseEntityMatcherOnSingleResult(final BaseEntity entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
jsonPath("createdBy", equalTo(entity.getCreatedBy())).match(mvcResult);
|
||||
jsonPath("createdAt", equalTo(entity.getCreatedAt())).match(mvcResult);
|
||||
jsonPath("lastModifiedBy", equalTo(entity.getLastModifiedBy())).match(mvcResult);
|
||||
jsonPath("lastModifiedAt", equalTo(entity.getLastModifiedAt())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyNamedEntityMatcherOnSingleResult(final NamedEntity entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
applyBaseEntityMatcherOnSingleResult(entity);
|
||||
|
||||
jsonPath("name", equalTo(entity.getName())).match(mvcResult);
|
||||
jsonPath("description", equalTo(entity.getDescription())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyNamedVersionedEntityMatcherOnSingleResult(final NamedVersionedEntity entity)
|
||||
throws Exception {
|
||||
return mvcResult -> {
|
||||
applyNamedEntityMatcherOnSingleResult(entity);
|
||||
|
||||
jsonPath("version", equalTo(entity.getVersion())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applyTagMatcherOnSingleResult(final Tag entity) throws Exception {
|
||||
return mvcResult -> {
|
||||
applyNamedEntityMatcherOnSingleResult(entity);
|
||||
|
||||
jsonPath("colour", equalTo(entity.getColour())).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static ResultMatcher applySelfLinkMatcherOnSingleResult(final String link) throws Exception {
|
||||
return mvcResult -> {
|
||||
jsonPath("_links.self.href", equalTo(link)).match(mvcResult);
|
||||
};
|
||||
}
|
||||
|
||||
protected static JSONObject getAssignmentObject(final Object id, final MgmtActionType type) {
|
||||
final JSONObject obj = new JSONObject();
|
||||
try {
|
||||
obj.put("id", id);
|
||||
obj.put("type", type.getName());
|
||||
} catch (final JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected static JSONObject getAssignmentObject(final Object id, final MgmtActionType type, final int weight) {
|
||||
try {
|
||||
return getAssignmentObject(id, type).put("weight", weight);
|
||||
} catch (final JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new JSONObject();
|
||||
}
|
||||
|
||||
// the set is a candidate for implicitly locking. So, lock it if not already locked
|
||||
// set lock flag to true to avoid re-locking
|
||||
static void implicitLock(final DistributionSet set) {
|
||||
if (!set.isLocked()) {
|
||||
((JpaDistributionSet) set).setOptLockRevision(set.getOptLockRevision() + 1);
|
||||
((JpaDistributionSet) set).lock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,599 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Step;
|
||||
import io.qameta.allure.Story;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtActionRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
/**
|
||||
* Integration test for the {@link MgmtActionRestApi}.
|
||||
*/
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Action Resource")
|
||||
class MgmtActionResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
private static final String JSON_PATH_ROOT = "$";
|
||||
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";
|
||||
|
||||
private static final String JSON_PATH_FIELD_ID = ".id";
|
||||
|
||||
private static final String JSON_PATH_PAGED_LIST_CONTENT = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTENT;
|
||||
private static final String JSON_PATH_PAGED_LIST_SIZE = JSON_PATH_ROOT + JSON_PATH_FIELD_SIZE;
|
||||
private static final String JSON_PATH_PAGED_LIST_TOTAL = JSON_PATH_ROOT + JSON_PATH_FIELD_TOTAL;
|
||||
|
||||
private static final String JSON_PATH_ACTION_ID = JSON_PATH_ROOT + JSON_PATH_FIELD_ID;
|
||||
|
||||
@Test
|
||||
@Description("Handles the GET request of retrieving a specific action.")
|
||||
public void getAction() throws Exception {
|
||||
getAction(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the GET request of retrieving a specific action with external reference.")
|
||||
public void getActionExtRef() throws Exception {
|
||||
getAction(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that actions can be filtered based on action status.")
|
||||
void filterActionsByStatus() throws Exception {
|
||||
|
||||
// prepare test
|
||||
final DistributionSet dsA = testdataFactory.createDistributionSet("");
|
||||
assignDistributionSet(dsA, Collections.singletonList(testdataFactory.createTarget("knownTargetId")));
|
||||
|
||||
final String rsqlPendingStatus = "status==pending";
|
||||
final String rsqlFinishedStatus = "status==finished";
|
||||
final String rsqlPendingOrFinishedStatus = rsqlFinishedStatus + "," + rsqlPendingStatus;
|
||||
|
||||
// pending status one result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlPendingStatus))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content[0].status", equalTo("pending")));
|
||||
|
||||
// finished status none result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlFinishedStatus))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(0)))
|
||||
.andExpect(jsonPath("size", equalTo(0)));
|
||||
|
||||
// pending or finished status one result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlPendingOrFinishedStatus))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content[0].status", equalTo("pending")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that actions can be filtered based on the detailed action status.")
|
||||
void filterActionsByDetailStatus() throws Exception {
|
||||
|
||||
// prepare test
|
||||
final DistributionSet dsA = testdataFactory.createDistributionSet("");
|
||||
assignDistributionSet(dsA, Collections.singletonList(testdataFactory.createTarget("knownTargetId")));
|
||||
|
||||
final String rsqlPendingStatus = "detailStatus==running";
|
||||
final String rsqlFinishedStatus = "detailStatus==finished";
|
||||
final String rsqlPendingOrFinishedStatus = rsqlFinishedStatus + "," + rsqlPendingStatus;
|
||||
|
||||
// running status one result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlPendingStatus))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)))
|
||||
.andExpect(jsonPath("content[0].detailStatus", equalTo("running")))
|
||||
.andExpect(jsonPath("content[0].status", equalTo("pending")));
|
||||
|
||||
// finished status none result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlFinishedStatus))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(0)))
|
||||
.andExpect(jsonPath("size", equalTo(0)));
|
||||
|
||||
// running or finished status one result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlPendingOrFinishedStatus))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)))
|
||||
.andExpect(jsonPath("content[0].detailStatus", equalTo("running")))
|
||||
.andExpect(jsonPath("content[0].status", equalTo("pending")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that actions can be filtered based on extRef.")
|
||||
void filterActionsByExternalRef() throws Exception {
|
||||
// prepare test
|
||||
final String knownTargetId = "targetId";
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
|
||||
final Action action0 = actions.get(0);
|
||||
final Action action1 = actions.get(1);
|
||||
|
||||
final List<String> externalRefs = new ArrayList<>(2);
|
||||
externalRefs.add("extRef");
|
||||
externalRefs.add("extRef#123_1");
|
||||
controllerManagement.updateActionExternalRef(action0.getId(), externalRefs.get(0));
|
||||
controllerManagement.updateActionExternalRef(action1.getId(), externalRefs.get(1));
|
||||
|
||||
final String rsqlExtRef = "externalref==extRef";
|
||||
final String rsqlExtRefWildcard = "externalref==extRef*";
|
||||
final String rsqlExtRefNoMatch = "externalref==234extRef";
|
||||
|
||||
// pending status one result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlExtRef))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)))
|
||||
.andExpect(jsonPath("content[0].externalRef", equalTo(externalRefs.get(0))));
|
||||
|
||||
// finished status none result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlExtRefWildcard))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("total", equalTo(2)))
|
||||
.andExpect(jsonPath("size", equalTo(2)));
|
||||
|
||||
// pending or finished status one result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlExtRefNoMatch))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("total", equalTo(0)))
|
||||
.andExpect(jsonPath("size", equalTo(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that actions can be filtered based on the action status code that was reported last.")
|
||||
void filterActionsByLastStatusCode() throws Exception {
|
||||
|
||||
// assign a distribution set to three targets
|
||||
final DistributionSet dsA = testdataFactory.createDistributionSet("");
|
||||
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(dsA,
|
||||
testdataFactory.createTargets("target1", "target2", "target3"));
|
||||
final List<Action> actions = assignmentResult.getAssignedEntity();
|
||||
assertThat(actions).hasSize(3);
|
||||
|
||||
// then simulate a status update with code 200 for the first action
|
||||
final Action action = actions.get(0);
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).code(200)
|
||||
.message("Update succeeded").status(Status.FINISHED));
|
||||
|
||||
// verify that one result is returned if the actions are filtered for
|
||||
// status code 200
|
||||
final String rsqlStatusCode = "lastStatusCode==200";
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlStatusCode))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content[0].status", equalTo("finished")));
|
||||
|
||||
// verify no result is returned if we filter for a non-existing status
|
||||
// code
|
||||
final String rsqlWrongStatusCode = "lastStatusCode==999";
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlWrongStatusCode))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(0)))
|
||||
.andExpect(jsonPath("size", equalTo(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that actions can be filtered based on distribution set fields.")
|
||||
void filterActionsByDistributionSet() throws Exception {
|
||||
|
||||
// prepare test
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||
assignDistributionSet(ds, Collections.singletonList(testdataFactory.createTarget("knownTargetId")));
|
||||
|
||||
final String rsqlDsName = "distributionSet.name==" + ds.getName() + "*";
|
||||
final String rsqlDsVersion = "distributionSet.version==" + ds.getVersion();
|
||||
final String rsqlDsId = "distributionSet.id==" + ds.getId();
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlDsName)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content.[0]._links.distributionset.name",
|
||||
equalTo(ds.getName() + ":" + ds.getVersion())));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlDsVersion))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlDsName + "," + rsqlDsVersion))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=distributionSet.name==FooBar"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(0)))
|
||||
.andExpect(jsonPath("size", equalTo(0)));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlDsId))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that actions can be filtered based on rollout fields.")
|
||||
void filterActionsByRollout() throws Exception {
|
||||
|
||||
// prepare test
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
final Target target0 = testdataFactory.createTarget("t0");
|
||||
|
||||
// manual assignment
|
||||
assignDistributionSet(ds, Collections.singletonList(target0));
|
||||
|
||||
// rollout
|
||||
final Target target1 = testdataFactory.createTarget("t1");
|
||||
final Rollout rollout = testdataFactory.createRolloutByVariables("TestRollout", "TestDesc", 1,
|
||||
"name==" + target1.getName(), ds, "50", "5");
|
||||
rolloutManagement.start(rollout.getId());
|
||||
rolloutHandler.handleAll();
|
||||
|
||||
final String rsqlRolloutName = "rollout.name==" + rollout.getName();
|
||||
final String rsqlRolloutId = "rollout.id==" + rollout.getId();
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlRolloutName)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)))
|
||||
.andExpect(jsonPath("content.[0]._links.target.name", equalTo(target1.getName()))).andExpect(jsonPath(
|
||||
"content.[0]._links.distributionset.name", equalTo(ds.getName() + ":" + ds.getVersion())));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlRolloutId)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)))
|
||||
.andExpect(jsonPath("content.[0]._links.target.name", equalTo(target1.getName()))).andExpect(jsonPath(
|
||||
"content.[0]._links.distributionset.name", equalTo(ds.getName() + ":" + ds.getVersion())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that actions can be filtered based on target fields.")
|
||||
void filterActionsByTargetProperties() throws Exception {
|
||||
|
||||
// prepare test
|
||||
final Target target = testdataFactory.createTarget("knownTargetId", "knownTargetName", "http://0.0.0.0");
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||
assignDistributionSet(ds, Collections.singletonList(target));
|
||||
|
||||
final String rsqlTargetControllerId = "target.controllerId==knownTargetId";
|
||||
final String rsqlTargetName = "target.name==knownTargetName";
|
||||
final String rsqlTargetUpdateStatus = "target.updateStatus==pending";
|
||||
final String rsqlTargetAddress = "target.address==http://0.0.0.0";
|
||||
|
||||
verifyResultsByTargetPropertyFilter(target, ds, rsqlTargetControllerId);
|
||||
verifyResultsByTargetPropertyFilter(target, ds, rsqlTargetName);
|
||||
verifyResultsByTargetPropertyFilter(target, ds, rsqlTargetUpdateStatus);
|
||||
verifyResultsByTargetPropertyFilter(target, ds, rsqlTargetAddress);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that all available actions are returned if the complete collection is requested.")
|
||||
void getActions() throws Exception {
|
||||
getActions(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that all available actions (whit ext refs) are returned if the complete collection is requested.")
|
||||
void getActionsExtRef() throws Exception {
|
||||
getActions(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that a full representation of all actions is returned if the collection is requested for representation mode 'full'.")
|
||||
void getActionsFullRepresentation() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
|
||||
final Action action0 = actions.get(0);
|
||||
final Action action1 = actions.get(1);
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
|
||||
// verify action 1
|
||||
.andExpect(jsonPath("content.[1].id", equalTo(action1.getId().intValue())))
|
||||
.andExpect(jsonPath("content.[1].type", equalTo("update")))
|
||||
.andExpect(jsonPath("content.[1].status", equalTo("pending")))
|
||||
.andExpect(jsonPath("content.[1].detailStatus", equalTo("running")))
|
||||
.andExpect(jsonPath("content.[1]._links.self.href",
|
||||
equalTo(generateActionLink(knownTargetId, action1.getId()))))
|
||||
.andExpect(jsonPath("content.[1]._links.target.href", equalTo(generateTargetLink(knownTargetId))))
|
||||
.andExpect(jsonPath("content.[1]._links.distributionset.href",
|
||||
equalTo(generateDistributionSetLink(action1))))
|
||||
|
||||
// verify action 0
|
||||
.andExpect(jsonPath("content.[0].id", equalTo(action0.getId().intValue())))
|
||||
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
|
||||
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
|
||||
.andExpect(jsonPath("content.[0].detailStatus", equalTo("canceling")))
|
||||
.andExpect(jsonPath("content.[0]._links.self.href",
|
||||
equalTo(generateActionLink(knownTargetId, action0.getId()))))
|
||||
.andExpect(jsonPath("content.[0]._links.target.href", equalTo(generateTargetLink(knownTargetId))))
|
||||
.andExpect(jsonPath("content.[0]._links.distributionset.href",
|
||||
equalTo(generateDistributionSetLink(action0))))
|
||||
|
||||
// verify collection properties
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the get request for actions returns an empty collection if no assignments have been done yet.")
|
||||
void getActionsWithEmptyResult() throws Exception {
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(0)))
|
||||
.andExpect(jsonPath("content", hasSize(0))).andExpect(jsonPath("total", equalTo(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies paging is respected as expected.")
|
||||
void getMultipleActionsWithPagingLimitRequestParameter() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
|
||||
// page 1: one entry
|
||||
final Action action0 = actions.get(0);
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
|
||||
// verify action 0
|
||||
.andExpect(jsonPath("content.[0].id", equalTo(action0.getId().intValue())))
|
||||
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
|
||||
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
|
||||
.andExpect(jsonPath("content.[0].detailStatus", equalTo(action0.getStatus().toString().toLowerCase())))
|
||||
.andExpect(jsonPath("content.[0]._links.self.href",
|
||||
equalTo(generateActionLink(knownTargetId, action0.getId()))))
|
||||
|
||||
// verify collection properties
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
|
||||
|
||||
// page 2: one entry
|
||||
final Action action1 = actions.get(1);
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
|
||||
// verify action 1
|
||||
.andExpect(jsonPath("content.[0].id", equalTo(action1.getId().intValue())))
|
||||
.andExpect(jsonPath("content.[0].type", equalTo("update")))
|
||||
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
|
||||
.andExpect(jsonPath("content.[0].detailStatus", equalTo(action1.getStatus().toString().toLowerCase())))
|
||||
.andExpect(jsonPath("content.[0]._links.self.href",
|
||||
equalTo(generateActionLink(knownTargetId, action1.getId()))))
|
||||
|
||||
// verify collection properties
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the actions resource is read-only.")
|
||||
void invalidRequestsOnActionResource() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
final Long actionId = actions.get(0).getId();
|
||||
|
||||
// not allowed methods
|
||||
mvc.perform(post(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
mvc.perform(put(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
mvc.perform(delete(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the correct action is returned")
|
||||
void shouldRetrieveCorrectActionById() throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
final Long actionId = actions.get(0).getId();
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "/" + actionId))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(JSON_PATH_ACTION_ID, equalTo(actionId.intValue())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that NOT_FOUND is returned when there is no such action.")
|
||||
void requestActionThatDoesNotExistsLeadsToNotFound() throws Exception {
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "/" + 101)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
private static String generateActionLink(final String targetId, final Long actionId) {
|
||||
return "http://localhost" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetId + "/"
|
||||
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId;
|
||||
}
|
||||
|
||||
private static String generateTargetLink(final String targetId) {
|
||||
return "http://localhost" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetId;
|
||||
}
|
||||
|
||||
private static String generateDistributionSetLink(final Action action) {
|
||||
return "http://localhost" + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/"
|
||||
+ action.getDistributionSet().getId();
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyResultsByTargetPropertyFilter(final Target target, final DistributionSet ds,
|
||||
final String rsqlTargetFilter) throws Exception {
|
||||
// pending status one result
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlTargetFilter)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
|
||||
.andExpect(jsonPath("size", equalTo(1)))
|
||||
.andExpect(jsonPath("content.[0]._links.target.name", equalTo(target.getName()))).andExpect(jsonPath(
|
||||
"content.[0]._links.distributionset.name", equalTo(ds.getName() + ":" + ds.getVersion())));
|
||||
}
|
||||
|
||||
private void getActions(final boolean withExternalRef) throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||
|
||||
final Action action0 = actions.get(0);
|
||||
final Action action1 = actions.get(1);
|
||||
|
||||
final List<String> externalRefs = new ArrayList<>(2);
|
||||
if (withExternalRef) {
|
||||
externalRefs.add("extRef#123_0");
|
||||
externalRefs.add("extRef#123_1");
|
||||
controllerManagement.updateActionExternalRef(action0.getId(), externalRefs.get(0));
|
||||
controllerManagement.updateActionExternalRef(action1.getId(), externalRefs.get(1));
|
||||
}
|
||||
|
||||
final ResultActions resultActions =
|
||||
mvc.perform(
|
||||
get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC"))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
// verify action 1
|
||||
.andExpect(jsonPath("content.[1].id", equalTo(action1.getId().intValue())))
|
||||
.andExpect(jsonPath("content.[1].type", equalTo("update")))
|
||||
.andExpect(jsonPath("content.[1].status", equalTo("pending")))
|
||||
.andExpect(jsonPath("content.[1].detailStatus", equalTo("running")))
|
||||
.andExpect(jsonPath("content.[1]._links.self.href",
|
||||
equalTo(generateActionLink(knownTargetId, action1.getId()))))
|
||||
|
||||
// verify action 0
|
||||
.andExpect(jsonPath("content.[0].id", equalTo(action0.getId().intValue())))
|
||||
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
|
||||
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
|
||||
.andExpect(jsonPath("content.[1].detailStatus", equalTo("running")))
|
||||
.andExpect(jsonPath("content.[0]._links.self.href",
|
||||
equalTo(generateActionLink(knownTargetId, action0.getId()))))
|
||||
|
||||
// verify collection properties
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||
|
||||
if (withExternalRef) {
|
||||
resultActions
|
||||
.andExpect(jsonPath("content.[1].externalRef", equalTo(externalRefs.get(1))))
|
||||
.andExpect(jsonPath("content.[0].externalRef", equalTo(externalRefs.get(0))));
|
||||
}
|
||||
}
|
||||
|
||||
private void getAction(final boolean withExternalRef) throws Exception {
|
||||
final String knownTargetId = "targetId";
|
||||
// prepare ds
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
// rollout
|
||||
final Target target = testdataFactory.createTarget(knownTargetId);
|
||||
final Rollout rollout = testdataFactory.createRolloutByVariables("TestRollout", "TestDesc", 1,
|
||||
"name==" + target.getName(), ds, "50", "5");
|
||||
rolloutManagement.start(rollout.getId());
|
||||
rolloutHandler.handleAll();
|
||||
|
||||
final List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE)
|
||||
.getContent();
|
||||
assertThat(actions).hasSize(1);
|
||||
final String externalRef = "externalRef#123";
|
||||
if (withExternalRef) {
|
||||
controllerManagement.updateActionExternalRef(actions.get(0).getId(), externalRef);
|
||||
}
|
||||
|
||||
final ResultActions resultActions =
|
||||
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "/{actionId}", actions.get(0).getId()))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
if (withExternalRef) {
|
||||
resultActions.andExpect(jsonPath("externalRef", equalTo(externalRef)));
|
||||
}
|
||||
}
|
||||
|
||||
private List<Action> generateTargetWithTwoUpdatesWithOneOverride(final String knownTargetId) {
|
||||
return generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(knownTargetId, null, null, null);
|
||||
}
|
||||
|
||||
private List<Action> generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(final String knownTargetId,
|
||||
final String schedule, final String duration, final String timezone) {
|
||||
final Target target = testdataFactory.createTarget(knownTargetId);
|
||||
|
||||
final Iterator<DistributionSet> sets = testdataFactory.createDistributionSets(2).iterator();
|
||||
final DistributionSet one = sets.next();
|
||||
final DistributionSet two = sets.next();
|
||||
|
||||
// Update
|
||||
if (schedule == null) {
|
||||
final List<Target> updatedTargets = assignDistributionSet(one, Collections.singletonList(target))
|
||||
.getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
|
||||
// 2nd update
|
||||
// sleep 10ms to ensure that we can sort by reportedAt
|
||||
Awaitility.await().atMost(Duration.ofMillis(100)).atLeast(5, TimeUnit.MILLISECONDS)
|
||||
.pollInterval(10, TimeUnit.MILLISECONDS)
|
||||
.until(() -> updatedTargets.stream().allMatch(t -> t.getLastModifiedAt() > 0L));
|
||||
assignDistributionSet(two, updatedTargets);
|
||||
} else {
|
||||
final List<Target> updatedTargets = assignDistributionSetWithMaintenanceWindow(one.getId(),
|
||||
target.getControllerId(), schedule, duration, timezone).getAssignedEntity().stream()
|
||||
.map(Action::getTarget).collect(Collectors.toList());
|
||||
// 2nd update
|
||||
// sleep 10ms to ensure that we can sort by reportedAt
|
||||
Awaitility.await().atMost(Duration.ofMillis(100)).atLeast(5, TimeUnit.MILLISECONDS)
|
||||
.pollInterval(10, TimeUnit.MILLISECONDS)
|
||||
.until(() -> updatedTargets.stream().allMatch(t -> t.getLastModifiedAt() > 0L));
|
||||
assignDistributionSetWithMaintenanceWindow(two.getId(), updatedTargets.get(0).getControllerId(), schedule,
|
||||
duration, timezone);
|
||||
}
|
||||
|
||||
// two updates, one cancellation
|
||||
final List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE)
|
||||
.getContent();
|
||||
|
||||
assertThat(actions).hasSize(2);
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||
import org.eclipse.hawkbit.repository.test.TestConfiguration;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.EventVerifier;
|
||||
import org.eclipse.hawkbit.repository.test.util.CleanupTestExecutionListener;
|
||||
import org.eclipse.hawkbit.repository.test.util.JUnitTestLoggerExtension;
|
||||
import org.eclipse.hawkbit.repository.test.util.SharedSqlTestDatabaseExtension;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.RestConfiguration;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Test for {@link MgmtBasicAuthResource}.
|
||||
*/
|
||||
@ActiveProfiles({ "test" })
|
||||
@ExtendWith({ JUnitTestLoggerExtension.class, SharedSqlTestDatabaseExtension.class })
|
||||
@SpringBootTest
|
||||
// destroy the context after each test class because otherwise we get problem
|
||||
// when context is
|
||||
// refreshed we e.g. get two instances of CacheManager which leads to very
|
||||
// strange test failures.
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
|
||||
// Cleaning repository will fire "delete" events. We won't count them to the
|
||||
// test execution. So, the order execution between EventVerifier and Cleanup is
|
||||
// important!
|
||||
@TestExecutionListeners(listeners = { EventVerifier.class, CleanupTestExecutionListener.class },
|
||||
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
|
||||
@TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true")
|
||||
@WebAppConfiguration
|
||||
@AutoConfigureMockMvc
|
||||
@ContextConfiguration(classes = { MgmtApiConfiguration.class, RestConfiguration.class,
|
||||
RepositoryApplicationConfiguration.class, TestConfiguration.class })
|
||||
@Import(TestChannelBinderConfiguration.class)
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Basic auth Userinfo Resource")
|
||||
public class MgmtBasicAuthResourceTest {
|
||||
|
||||
@Autowired
|
||||
protected WebApplicationContext webApplicationContext;
|
||||
@Autowired
|
||||
MockMvc defaultMock;
|
||||
private static final String TEST_USER = "testUser";
|
||||
private static final String DEFAULT = "default";
|
||||
|
||||
@Test
|
||||
@Description("Test of userinfo api with basic auth validation")
|
||||
@WithUser(principal = TEST_USER)
|
||||
public void validateBasicAuthWithUserDetails() throws Exception {
|
||||
withSecurityMock().perform(get(MgmtRestConstants.AUTH_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaTypes.HAL_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.username", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.tenant", equalTo(DEFAULT)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test of userinfo api with invalid basic auth fails")
|
||||
public void validateBasicAuthFailsWithInvalidCredentials() throws Exception {
|
||||
defaultMock.perform(get(MgmtRestConstants.AUTH_V1_REQUEST_MAPPING)
|
||||
.header(HttpHeaders.AUTHORIZATION, getBasicAuth("wrongUser", "wrongSecret")))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
private String getBasicAuth(final String username, final String password) {
|
||||
return "Basic " + Base64Utils.encodeToString((username + ":" + password).getBytes());
|
||||
}
|
||||
|
||||
private MockMvc withSecurityMock() throws Exception {
|
||||
return createMvcWebAppContext(webApplicationContext).build();
|
||||
}
|
||||
|
||||
private DefaultMockMvcBuilder createMvcWebAppContext(final WebApplicationContext context) {
|
||||
return MockMvcBuilders.webAppContextSetup(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.servlet.server.Encoding;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
/**
|
||||
* With Spring Boot 2.2.x the default charset encoding became deprecated. In
|
||||
* hawkBit we want to keep the old behavior for now and still return the charset
|
||||
* in the response, which is achieved through enabling {@link Encoding} via
|
||||
* properties.
|
||||
*/
|
||||
@SpringBootTest(properties = { "server.servlet.encoding.charset=UTF-8", "server.servlet.encoding.force=true" })
|
||||
@Import(HttpEncodingAutoConfiguration.class)
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Response Content-Type")
|
||||
public class MgmtContentTypeTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
private final String dsName = "DS-ö";
|
||||
private DistributionSet ds;
|
||||
|
||||
@BeforeEach
|
||||
public void setupBeforeTest() {
|
||||
ds = testdataFactory.generateDistributionSet(dsName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a POST request shall contain charset=utf-8")
|
||||
public void postDistributionSet_ContentTypeJsonUtf8_woAccept() throws Exception {
|
||||
final MvcResult result = mvc.perform(
|
||||
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isCreated()).andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
|
||||
|
||||
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a POST request shall contain charset=utf-8")
|
||||
public void postDistributionSet_ContentTypeJsonUtf8_wAcceptJson() throws Exception {
|
||||
final MvcResult result = mvc.perform(
|
||||
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
|
||||
|
||||
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a POST request shall contain charset=utf-8")
|
||||
public void postDistributionSet_ContentTypeJsonUtf8_wAcceptJsonUtf8() throws Exception {
|
||||
final MvcResult result = mvc.perform(
|
||||
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON_UTF8))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
|
||||
|
||||
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a POST request shall contain charset=utf-8")
|
||||
public void postDistributionSet_ContentTypeJsonUtf8_wAcceptHalJson() throws Exception {
|
||||
final MvcResult result = mvc.perform(
|
||||
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaTypes.HAL_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
|
||||
|
||||
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a POST request shall contain charset=utf-8")
|
||||
public void postDistributionSet_ContentTypeJson_woAccept() throws Exception {
|
||||
final MvcResult result = mvc.perform(
|
||||
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
|
||||
|
||||
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a POST request shall contain charset=utf-8")
|
||||
public void postDistributionSet_ContentTypeJson_wAcceptJson() throws Exception {
|
||||
final MvcResult result = mvc.perform(
|
||||
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
|
||||
|
||||
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a POST request shall contain charset=utf-8")
|
||||
public void postDistributionSet_ContentTypeJson_wAcceptJsonUtf8() throws Exception {
|
||||
final MvcResult result = mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)
|
||||
.content(JsonBuilder.distributionSets(Arrays.asList(ds))).contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON_UTF8)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
|
||||
|
||||
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a POST request shall contain charset=utf-8")
|
||||
public void postDistributionSet_ContentTypeJson_wAcceptHalJson() throws Exception {
|
||||
final MvcResult result = mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)
|
||||
.content(JsonBuilder.distributionSets(Arrays.asList(ds))).contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaTypes.HAL_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
|
||||
|
||||
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a GET request shall contain charset=utf-8")
|
||||
public void getDistributionSet_woAccept() throws Exception {
|
||||
final MvcResult result = mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a GET request shall contain charset=utf-8")
|
||||
public void getDistributionSet_wAcceptJson() throws Exception {
|
||||
final MvcResult result = mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a GET request shall contain charset=utf-8")
|
||||
public void getDistributionSet_wAcceptJsonUtf8() throws Exception {
|
||||
final MvcResult result = mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON_UTF8))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The response of a GET request shall contain charset=utf-8")
|
||||
public void getDistributionSet_wAcceptHalJson() throws Exception {
|
||||
final MvcResult result = mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).accept(MediaTypes.HAL_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
|
||||
}
|
||||
|
||||
private String getResponseHeaderContentType(MvcResult result) {
|
||||
return result.getResponse().getHeader("Content-Type");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,504 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility;
|
||||
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTagDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Distribution Set Tag Resource")
|
||||
public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
private static final String DISTRIBUTIONSETTAGS_ROOT = "http://localhost"
|
||||
+ MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/";
|
||||
private static final Random RND = new Random();
|
||||
|
||||
@Test
|
||||
@Description("Verfies that a paged result list of DS tags reflects the content on the repository side.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 2) })
|
||||
public void getDistributionSetTags() throws Exception {
|
||||
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
|
||||
final DistributionSetTag assigned = tags.get(0);
|
||||
final DistributionSetTag unassigned = tags.get(1);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(applyBaseEntityMatcherOnPagedResult(assigned))
|
||||
.andExpect(applyBaseEntityMatcherOnPagedResult(unassigned))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(assigned, DISTRIBUTIONSETTAGS_ROOT + assigned.getId()))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(unassigned, DISTRIBUTIONSETTAGS_ROOT + unassigned.getId()))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the GET request of retrieving all distribution set tags based by parameter")
|
||||
public void getDistributionSetTagsWithParameters() throws Exception {
|
||||
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
|
||||
final DistributionSetTag assigned = tags.get(0);
|
||||
final DistributionSetTag unassigned = tags.get(1);
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
|
||||
+ "?limit=10&sort=name:ASC&offset=0&q=name==DsTag"))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that a paged result list of DS tags reflects the content on the repository side when filtered by distribution set id.")
|
||||
public void getDistributionSetTagsByDistributionSetId() throws Exception {
|
||||
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
|
||||
final DistributionSetTag tag1 = tags.get(0);
|
||||
final DistributionSetTag tag2 = tags.get(1);
|
||||
|
||||
final DistributionSet distributionSet1 = testdataFactory.createDistributionSet();
|
||||
final DistributionSet distributionSet2 = testdataFactory.createDistributionSet();
|
||||
distributionSetManagement.assignTag(List.of(distributionSet1.getId(), distributionSet2.getId()), tag1.getId());
|
||||
distributionSetManagement.assignTag(List.of(distributionSet1.getId()), tag2.getId());
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)
|
||||
.queryParam(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "distributionset.id==" + distributionSet1.getId())
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(applyBaseEntityMatcherOnPagedResult(tag1))
|
||||
.andExpect(applyBaseEntityMatcherOnPagedResult(tag2))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, DISTRIBUTIONSETTAGS_ROOT + tag1.getId()))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(tag2, DISTRIBUTIONSETTAGS_ROOT + tag2.getId()))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)
|
||||
.queryParam(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "distributionset.id==" + distributionSet2.getId())
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(applyBaseEntityMatcherOnPagedResult(tag1))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, DISTRIBUTIONSETTAGS_ROOT + tag1.getId()))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(1)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that a paged result list of DS tags reflects the content on the repository side when filtered by distribution set id field AND tag field.")
|
||||
public void getDistributionSetTagsByDistributionSetIdAndTagDescription() throws Exception {
|
||||
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
|
||||
final DistributionSetTag tag1 = tags.get(0);
|
||||
final DistributionSetTag tag2 = tags.get(1);
|
||||
|
||||
final DistributionSet distributionSet1 = testdataFactory.createDistributionSet();
|
||||
final DistributionSet distributionSet2 = testdataFactory.createDistributionSet();
|
||||
distributionSetManagement.assignTag(List.of(distributionSet1.getId(), distributionSet2.getId()), tag1.getId());
|
||||
distributionSetManagement.assignTag(List.of(distributionSet1.getId()), tag2.getId());
|
||||
|
||||
// pass here q directly as a pure string because .queryParam method delimiters the parameters in q with ,
|
||||
// which is logical OR, we want AND here
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
|
||||
+ "?" + MgmtRestConstants.REQUEST_PARAMETER_SEARCH +
|
||||
"=distributionset.id==" + distributionSet1.getId() + ";description==" + tag1.getDescription())
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(applyBaseEntityMatcherOnPagedResult(tag1))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, DISTRIBUTIONSETTAGS_ROOT + tag1.getId()))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(1)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that a single result of a DS tag reflects the content on the repository side.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 2) })
|
||||
public void getDistributionSetTag() throws Exception {
|
||||
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
|
||||
final DistributionSetTag assigned = tags.get(0);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + assigned.getId())
|
||||
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(applyTagMatcherOnSingleResult(assigned))
|
||||
.andExpect(applySelfLinkMatcherOnSingleResult(DISTRIBUTIONSETTAGS_ROOT + assigned.getId()))
|
||||
.andExpect(jsonPath("_links.assignedDistributionSets.href",
|
||||
equalTo(DISTRIBUTIONSETTAGS_ROOT + assigned.getId() + "/assigned?offset=0&limit=50")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that created DS tags are stored in the repository as send to the API.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 2) })
|
||||
public void createDistributionSetTags() throws JSONException, Exception {
|
||||
final Tag tagOne = entityFactory.tag().create().colour("testcol1").description("its a test1").name("thetest1")
|
||||
.build();
|
||||
final Tag tagTwo = entityFactory.tag().create().colour("testcol2").description("its a test2").name("thetest2")
|
||||
.build();
|
||||
|
||||
final ResultActions result = mvc
|
||||
.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)
|
||||
.content(JsonBuilder.tags(Arrays.asList(tagOne, tagTwo)))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
|
||||
|
||||
final Tag createdOne = distributionSetTagManagement.findByRsql(PAGE, "name==thetest1").getContent().get(0);
|
||||
assertThat(createdOne.getName()).isEqualTo(tagOne.getName());
|
||||
assertThat(createdOne.getDescription()).isEqualTo(tagOne.getDescription());
|
||||
assertThat(createdOne.getColour()).isEqualTo(tagOne.getColour());
|
||||
final Tag createdTwo = distributionSetTagManagement.findByRsql(PAGE, "name==thetest2").getContent().get(0);
|
||||
assertThat(createdTwo.getName()).isEqualTo(tagTwo.getName());
|
||||
assertThat(createdTwo.getDescription()).isEqualTo(tagTwo.getDescription());
|
||||
assertThat(createdTwo.getColour()).isEqualTo(tagTwo.getColour());
|
||||
|
||||
result.andExpect(applyTagMatcherOnArrayResult(createdOne)).andExpect(applyTagMatcherOnArrayResult(createdTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an updated DS tag is stored in the repository as send to the API.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetTagUpdatedEvent.class, count = 1) })
|
||||
public void updateDistributionSetTag() throws Exception {
|
||||
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(1);
|
||||
final DistributionSetTag original = tags.get(0);
|
||||
|
||||
final Tag update = entityFactory.tag().create().name("updatedName").colour("updatedCol")
|
||||
.description("updatedDesc").build();
|
||||
|
||||
final ResultActions result = mvc
|
||||
.perform(put(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + original.getId())
|
||||
.content(JsonBuilder.tag(update)).contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
|
||||
|
||||
final Tag updated = distributionSetTagManagement.findByRsql(PAGE, "name==updatedName").getContent().get(0);
|
||||
assertThat(updated.getName()).isEqualTo(update.getName());
|
||||
assertThat(updated.getDescription()).isEqualTo(update.getDescription());
|
||||
assertThat(updated.getColour()).isEqualTo(update.getColour());
|
||||
|
||||
result.andExpect(applyTagMatcherOnArrayResult(updated)).andExpect(applyTagMatcherOnArrayResult(updated));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that the delete call is reflected by the repository.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetTagDeletedEvent.class, count = 1) })
|
||||
public void deleteDistributionSetTag() throws Exception {
|
||||
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(1);
|
||||
final DistributionSetTag original = tags.get(0);
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + original.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
assertThat(distributionSetTagManagement.get(original.getId())).isNotPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that assigned DS to tag in repository are listed with proper paging results.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 5),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 5) })
|
||||
public void getAssignedDistributionSets() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final int setsAssigned = 5;
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
|
||||
distributionSetManagement.assignTag(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(setsAssigned)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(setsAssigned)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(setsAssigned)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that assigned DS to tag in repository are listed with proper paging results with paging limit parameter.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 5),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 5) })
|
||||
public void getAssignedDistributionSetsWithPagingLimitRequestParameter() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final int setsAssigned = 5;
|
||||
final int limitSize = 1;
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
|
||||
distributionSetManagement.assignTag(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(setsAssigned)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that assigned DS to tag in repository are listed with proper paging results with paging limit and offset parameter.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 5),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 5) })
|
||||
public void getAssignedDistributionSetsWithPagingLimitAndOffsetRequestParameter() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final int setsAssigned = 5;
|
||||
final int offsetParam = 2;
|
||||
final int expectedSize = setsAssigned - offsetParam;
|
||||
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
|
||||
distributionSetManagement.assignTag(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(setsAssigned)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(setsAssigned)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that tag assignments done through toggle API command are correctly assigned or unassigned.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 4) })
|
||||
public void toggleTagAssignment() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final int setsAssigned = 2;
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
|
||||
|
||||
// 2 DistributionSetUpdateEvent
|
||||
ResultActions result = toggle(tag, sets);
|
||||
|
||||
List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
|
||||
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
|
||||
.containsAll(sets.stream().map(DistributionSet::getId).collect(Collectors.toList()));
|
||||
|
||||
result.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(0), "assignedDistributionSets"))
|
||||
.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(1), "assignedDistributionSets"));
|
||||
|
||||
// 2 DistributionSetUpdateEvent
|
||||
result = toggle(tag, sets);
|
||||
|
||||
updated = distributionSetManagement.findAll(PAGE).getContent();
|
||||
|
||||
result.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(0), "unassignedDistributionSets"))
|
||||
.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(1), "unassignedDistributionSets"));
|
||||
|
||||
assertThat(distributionSetManagement.findByTag(PAGE, tag.getId())).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 1) })
|
||||
public void assignDistributionSet() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final DistributionSet set = testdataFactory.createDistributionSetsWithoutModules(1).get(0);
|
||||
|
||||
mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/" +
|
||||
set.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
final List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
|
||||
.containsOnly(set.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 2) })
|
||||
public void assignDistributionSets() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(2);
|
||||
|
||||
mvc.perform(
|
||||
put(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(JsonBuilder.toArray(sets.stream().map(DistributionSet::getId).collect(Collectors.toList())))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
final List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
|
||||
.containsAll(sets.stream().map(DistributionSet::getId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag unassignments done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 3) })
|
||||
public void unassignDistributionSet() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final int setsAssigned = 2;
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
|
||||
final DistributionSet assigned = sets.get(0);
|
||||
final DistributionSet unassigned = sets.get(1);
|
||||
|
||||
distributionSetManagement.assignTag(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/" +
|
||||
unassigned.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
final List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
|
||||
.containsOnly(assigned.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag unassignments done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 3),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 5) })
|
||||
public void unassignDistributionSets() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(3);
|
||||
final DistributionSet assigned = sets.get(0);
|
||||
final DistributionSet unassigned0 = sets.get(1);
|
||||
final DistributionSet unassigned1 = sets.get(2);
|
||||
|
||||
distributionSetManagement.assignTag(sets.stream().map(DistributionSet::getId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(JsonBuilder.toArray(List.of(unassigned0.getId(), unassigned1.getId())))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
final List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
|
||||
.containsOnly(assigned.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2) })
|
||||
public void assignDistributionSetsNotFound() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final List<Long> sets = testdataFactory.createDistributionSetsWithoutModules(2).stream().map(DistributionSet::getId).toList();
|
||||
final List<Long> missing = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
while (true) {
|
||||
final long id = Math.abs(RND.nextLong());
|
||||
if (!sets.contains(id)) {
|
||||
missing.add(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(missing);
|
||||
final List<Long> withMissing = new ArrayList<>(sets);
|
||||
withMissing.addAll(missing);
|
||||
|
||||
mvc.perform(
|
||||
put(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(JsonBuilder.toArray(withMissing))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound())
|
||||
.andExpect(handler -> {
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
|
||||
final Map<String, Object> info = exceptionInfo.getInfo();
|
||||
assertThat(info).isNotNull();
|
||||
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(DistributionSet.class.getSimpleName());
|
||||
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
|
||||
Collections.sort(notFound);
|
||||
assertThat(notFound).isEqualTo(missing);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
||||
@Expect(type = DistributionSetUpdatedEvent.class, count = 2) })
|
||||
public void assignDistributionSetsWithRequestBody() throws Exception {
|
||||
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
|
||||
final int setsAssigned = 2;
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
|
||||
|
||||
final ResultActions result = mvc
|
||||
.perform(
|
||||
post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(JsonBuilder
|
||||
.ids(sets.stream().map(DistributionSet::getId).collect(Collectors.toList())))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
|
||||
|
||||
final List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
|
||||
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
|
||||
.containsAll(sets.stream().map(DistributionSet::getId).collect(Collectors.toList()));
|
||||
|
||||
result.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(0)))
|
||||
.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(1)));
|
||||
}
|
||||
|
||||
// DEPRECATED flows
|
||||
|
||||
private ResultActions toggle(final DistributionSetTag tag, final List<DistributionSet> sets) throws Exception {
|
||||
return mvc
|
||||
.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId()
|
||||
+ "/assigned/toggleTagAssignment").content(
|
||||
JsonBuilder.ids(sets.stream().map(DistributionSet::getId).collect(Collectors.toList())))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,694 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Step;
|
||||
import io.qameta.allure.Story;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
/**
|
||||
* Test for {@link MgmtDistributionSetTypeResource}.
|
||||
*/
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Distribution Set Type Resource")
|
||||
public class MgmtDistributionSetTypeResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests.")
|
||||
public void getDistributionSetTypes() throws Exception {
|
||||
|
||||
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
|
||||
.key("test123").name("TestName123").description("Desc123").colour("col12"));
|
||||
testType = distributionSetTypeManagement
|
||||
.update(entityFactory.distributionSetType().update(testType.getId()).description("Desc1234"));
|
||||
|
||||
// 4 types overall (2 hawkbit tenant default, 1 test default and 1
|
||||
// generated in this test)
|
||||
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + standardDsType.getKey() + "')].name",
|
||||
contains(standardDsType.getName())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + standardDsType.getKey() + "')].description",
|
||||
contains(standardDsType.getDescription())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + standardDsType.getKey() + "')].key",
|
||||
contains(standardDsType.getKey())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].id", contains(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].name", contains("TestName123")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].description", contains("Desc1234")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].colour", contains("col12")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].createdBy", contains("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].createdAt", contains(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].lastModifiedBy", contains("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].lastModifiedAt",
|
||||
contains(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].key", contains("test123")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')]._links.self.href",
|
||||
contains("http://localhost/rest/v1/distributionsettypes/" + testType.getId())))
|
||||
.andExpect(jsonPath("$.total", equalTo(5)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with sorting by KEY.")
|
||||
public void getDistributionSetTypesSortedByKey() throws Exception {
|
||||
|
||||
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
|
||||
.key("zzzzz").name("TestName123").description("Desc123").colour("col12"));
|
||||
testType = distributionSetTypeManagement
|
||||
.update(entityFactory.distributionSetType().update(testType.getId()).description("Desc1234"));
|
||||
|
||||
// descending
|
||||
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "KEY:DESC")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[0].id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.content.[0].name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("$.content.[0].description", equalTo("Desc1234")))
|
||||
.andExpect(jsonPath("$.content.[0].colour", equalTo("col12")))
|
||||
.andExpect(jsonPath("$.content.[0].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[0].createdAt", equalTo(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[0].lastModifiedBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[0].lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[0].key", equalTo("zzzzz")))
|
||||
.andExpect(jsonPath("$.total", equalTo(DEFAULT_DS_TYPES + 1)));
|
||||
|
||||
// ascending
|
||||
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "KEY:ASC")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[4].id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.content.[4].name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("$.content.[4].description", equalTo("Desc1234")))
|
||||
.andExpect(jsonPath("$.content.[4].colour", equalTo("col12")))
|
||||
.andExpect(jsonPath("$.content.[4].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[4].createdAt", equalTo(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[4].lastModifiedBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[4].lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[4].key", equalTo("zzzzz")))
|
||||
.andExpect(jsonPath("$.total", equalTo(DEFAULT_DS_TYPES + 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes POST requests.")
|
||||
public void createDistributionSetTypes() throws Exception {
|
||||
|
||||
final List<DistributionSetType> types = createTestDistributionSetTestTypes();
|
||||
|
||||
final MvcResult mvcResult = runPostDistributionSetType(types);
|
||||
|
||||
verifyCreatedDistributionSetTypes(mvcResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes POST requests.")
|
||||
public void addMandatoryModuleToDistributionSetType() throws Exception {
|
||||
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
|
||||
.key("test123").name("TestName123").description("Desc123").colour("col12"));
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(1);
|
||||
|
||||
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType.getId())
|
||||
.content("{\"id\":" + osType.getId() + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
testType = distributionSetTypeManagement.get(testType.getId()).get();
|
||||
assertThat(testType.getLastModifiedBy()).isEqualTo("uploadTester");
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(testType.getMandatoryModuleTypes()).containsExactly(osType);
|
||||
assertThat(testType.getOptionalModuleTypes()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes POST requests.")
|
||||
public void addOptionalModuleToDistributionSetType() throws Exception {
|
||||
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
|
||||
.key("test123").name("TestName123").description("Desc123").colour("col12"));
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(1);
|
||||
|
||||
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
|
||||
.content("{\"id\":" + osType.getId() + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
testType = distributionSetTypeManagement.get(testType.getId()).get();
|
||||
assertThat(testType.getLastModifiedBy()).isEqualTo("uploadTester");
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(testType.getOptionalModuleTypes()).containsExactly(osType);
|
||||
assertThat(testType.getMandatoryModuleTypes()).isEmpty();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Verifies quota enforcement for /rest/v1/distributionsettypes/{ID}/optionalmoduletypes POST requests.")
|
||||
public void assignModuleTypesToDistributionSetTypeUntilQuotaExceeded() throws Exception {
|
||||
|
||||
// create software module types
|
||||
final int maxSoftwareModuleTypes = quotaManagement.getMaxSoftwareModuleTypesPerDistributionSetType();
|
||||
final List<Long> moduleTypeIds = new ArrayList<>();
|
||||
for (int i = 0; i < maxSoftwareModuleTypes + 1; ++i) {
|
||||
final SoftwareModuleTypeCreate smCreate = entityFactory.softwareModuleType().create().name("smType_" + i)
|
||||
.description("smType_" + i).maxAssignments(1).colour("blue").key("smType_" + i);
|
||||
moduleTypeIds.add(softwareModuleTypeManagement.create(smCreate).getId());
|
||||
}
|
||||
|
||||
// verify quota enforcement for optional module types
|
||||
|
||||
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
|
||||
.create().key("testType").name("testType").description("testType").colour("col12"));
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(1);
|
||||
|
||||
for (int i = 0; i < moduleTypeIds.size() - 1; ++i) {
|
||||
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
|
||||
.content("{\"id\":" + moduleTypeIds.get(i) + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
|
||||
.content("{\"id\":" + moduleTypeIds.get(moduleTypeIds.size() - 1) + "}")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
|
||||
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
|
||||
|
||||
// verify quota enforcement for mandatory module types
|
||||
|
||||
final DistributionSetType testType2 = distributionSetTypeManagement.create(entityFactory.distributionSetType()
|
||||
.create().key("testType2").name("testType2").description("testType2").colour("col12"));
|
||||
assertThat(testType2.getOptLockRevision()).isEqualTo(1);
|
||||
|
||||
for (int i = 0; i < moduleTypeIds.size() - 1; ++i) {
|
||||
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType2.getId())
|
||||
.content("{\"id\":" + moduleTypeIds.get(i) + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType2.getId())
|
||||
.content("{\"id\":" + moduleTypeIds.get(moduleTypeIds.size() - 1) + "}")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
|
||||
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes GET requests.")
|
||||
public void getMandatoryModulesOfDistributionSetType() throws Exception {
|
||||
final DistributionSetType testType = generateTestType();
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType.getId())
|
||||
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("[0].name", equalTo(osType.getName())))
|
||||
.andExpect(jsonPath("[0].description", equalTo(osType.getDescription())))
|
||||
.andExpect(jsonPath("[0].maxAssignments", equalTo(1))).andExpect(jsonPath("[0].key", equalTo("os")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes GET requests.")
|
||||
public void getOptionalModulesOfDistributionSetType() throws Exception {
|
||||
final DistributionSetType testType = generateTestType();
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
|
||||
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("[0].name", equalTo(appType.getName())))
|
||||
.andExpect(jsonPath("[0].description", equalTo(appType.getDescription())))
|
||||
.andExpect(jsonPath("[0].maxAssignments", equalTo(Integer.MAX_VALUE)))
|
||||
.andExpect(jsonPath("[0].key", equalTo("application")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes/{ID} GET requests.")
|
||||
public void getMandatoryModuleOfDistributionSetType() throws Exception {
|
||||
final DistributionSetType testType = generateTestType();
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes/{smtId}", testType.getId(),
|
||||
osType.getId()).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.id", equalTo(osType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.name", equalTo(osType.getName())))
|
||||
.andExpect(jsonPath("$.description", equalTo(osType.getDescription())))
|
||||
.andExpect(jsonPath("$.createdBy", equalTo(osType.getCreatedBy())))
|
||||
.andExpect(jsonPath("$.createdAt", equalTo(osType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.lastModifiedBy", equalTo(osType.getLastModifiedBy())))
|
||||
.andExpect(jsonPath("$.lastModifiedAt", equalTo(osType.getLastModifiedAt())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes/{ID} GET requests.")
|
||||
public void getOptionalModuleOfDistributionSetType() throws Exception {
|
||||
final DistributionSetType testType = generateTestType();
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes/{smtId}", testType.getId(),
|
||||
appType.getId()).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.id", equalTo(appType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.name", equalTo(appType.getName())))
|
||||
.andExpect(jsonPath("$.description", equalTo(appType.getDescription())))
|
||||
.andExpect(jsonPath("$.createdBy", equalTo(appType.getCreatedBy())))
|
||||
.andExpect(jsonPath("$.createdAt", equalTo(appType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.lastModifiedBy", equalTo(appType.getLastModifiedBy())))
|
||||
.andExpect(jsonPath("$.lastModifiedAt", equalTo(appType.getLastModifiedAt())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes/{ID} DELETE requests.")
|
||||
public void removeMandatoryModuleToDistributionSetType() throws Exception {
|
||||
DistributionSetType testType = generateTestType();
|
||||
|
||||
mvc.perform(delete("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes/{smtId}", testType.getId(),
|
||||
osType.getId()).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
testType = distributionSetTypeManagement.get(testType.getId()).get();
|
||||
assertThat(testType.getLastModifiedBy()).isEqualTo("uploadTester");
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(testType.getOptionalModuleTypes()).containsExactly(appType);
|
||||
assertThat(testType.getMandatoryModuleTypes()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes/{ID} DELETE requests.")
|
||||
public void removeOptionalModuleToDistributionSetType() throws Exception {
|
||||
DistributionSetType testType = generateTestType();
|
||||
|
||||
mvc.perform(delete("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes/{smtId}", testType.getId(),
|
||||
appType.getId()).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
testType = distributionSetTypeManagement.get(testType.getId()).get();
|
||||
assertThat(testType.getLastModifiedBy()).isEqualTo("uploadTester");
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(testType.getOptionalModuleTypes()).isEmpty();
|
||||
assertThat(testType.getMandatoryModuleTypes()).containsExactly(osType);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} GET requests.")
|
||||
public void getDistributionSetType() throws Exception {
|
||||
|
||||
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
|
||||
.key("test123").name("TestName123").description("Desc123"));
|
||||
testType = distributionSetTypeManagement
|
||||
.update(entityFactory.distributionSetType().update(testType.getId()).description("Desc1234"));
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/{dstId}", testType.getId()).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("$.description", equalTo("Desc1234")))
|
||||
.andExpect(jsonPath("$.colour").doesNotExist())
|
||||
.andExpect(jsonPath("$.createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.lastModifiedBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.deleted", equalTo(testType.isDeleted())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the GET request of retrieving all distribution set types within SP based on parameter.")
|
||||
public void getDistributionSetTypesWithParameter() throws Exception {
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
|
||||
+ "?limit=10&sort=name:ASC&offset=0&q=name==a"))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/DistributionSetTypes/{ID} DELETE requests (hard delete scenario).")
|
||||
public void deleteDistributionSetTypeUnused() throws Exception {
|
||||
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
|
||||
.create().key("test123").name("TestName123").description("Desc123").colour("col12"));
|
||||
|
||||
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES + 1);
|
||||
|
||||
mvc.perform(delete("/rest/v1/distributionsettypes/{dsId}", testType.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that DS type deletion request to API on an entity that does not exist results in NOT_FOUND.")
|
||||
public void deleteDistributionSetTypeThatDoesNotExistLeadsToNotFound() throws Exception {
|
||||
mvc.perform(delete("/rest/v1/distributionsettypes/1234")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/DistributionSetTypes/{ID} DELETE requests (soft delete scenario).")
|
||||
public void deleteDistributionSetTypeUsed() throws Exception {
|
||||
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
|
||||
.create().key("test123").name("TestName123").description("Desc123").colour("col12"));
|
||||
|
||||
distributionSetManagement.create(entityFactory.distributionSet().create().name("sdfsd").description("dsfsdf")
|
||||
.version("1").type(testType));
|
||||
|
||||
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES + 1);
|
||||
assertThat(distributionSetManagement.count()).isEqualTo(1);
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/{dstId}", testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(false)));
|
||||
|
||||
mvc.perform(delete("/rest/v1/distributionsettypes/{dstId}", testType.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/{dstId}", testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(true)));
|
||||
|
||||
assertThat(distributionSetManagement.count()).isEqualTo(1);
|
||||
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} PUT requests.")
|
||||
public void updateDistributionSetTypeColourDescriptionAndNameUntouched() throws Exception {
|
||||
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
|
||||
.create().key("test123").name("TestName123").description("Desc123").colour("col"));
|
||||
|
||||
final String body = new JSONObject().put("id", testType.getId()).put("description", "foobardesc")
|
||||
.put("colour", "updatedColour")
|
||||
.put("name", "nameShouldNotBeChanged").toString();
|
||||
|
||||
mvc.perform(put("/rest/v1/distributionsettypes/{smId}", testType.getId()).content(body)
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.description", equalTo("foobardesc")))
|
||||
.andExpect(jsonPath("$.colour", equalTo("updatedColour")))
|
||||
.andExpect(jsonPath("$.name", equalTo("TestName123"))).andReturn();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the PUT request for a single distribution set type within SP.")
|
||||
public void updateDistributionSetTypeDescriptionAndColor() throws Exception {
|
||||
final DistributionSetType testType = distributionSetTypeManagement.update(entityFactory.distributionSetType()
|
||||
.update(testdataFactory.createDistributionSet().getType().getId()).description("Desc1234"));
|
||||
final String body = new JSONObject()
|
||||
.put("description", "an updated description")
|
||||
.put("colour", "rgb(106,178,83)").toString();
|
||||
|
||||
mvc
|
||||
.perform(put(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING + "/{distributionSetTypeId}",
|
||||
testType.getId()).content(body).contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the update of the deletion flag. It is verfied that the distribution set type can't be marked as deleted through update operation.")
|
||||
public void updateDistributionSetTypeDeletedFlag() throws Exception {
|
||||
final DistributionSetType testType = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("test123").name("TestName123").colour("col"));
|
||||
|
||||
final String body = new JSONObject().put("id", testType.getId()).put("deleted", true).toString();
|
||||
|
||||
mvc.perform(put("/rest/v1/distributionsettypes/{dstId}", testType.getId()).content(body)
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.deleted", equalTo(false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.")
|
||||
public void getDistributionSetTypesWithoutAddtionalRequestParameters() throws Exception {
|
||||
|
||||
// 4 types overall (3 hawkbit tenant default, 1 test default
|
||||
final int types = 4;
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.")
|
||||
public void getDistributionSetTypesWithPagingLimitRequestParameter() throws Exception {
|
||||
|
||||
final int types = DEFAULT_DS_TYPES;
|
||||
final int limitSize = 1;
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.")
|
||||
public void getDistributionSetTypesWithPagingLimitAndOffsetRequestParameter() throws Exception {
|
||||
|
||||
final int types = DEFAULT_DS_TYPES;
|
||||
final int offsetParam = 2;
|
||||
final int expectedSize = types - offsetParam;
|
||||
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(types)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).")
|
||||
public void invalidRequestsOnDistributionSetTypesResource() throws Exception {
|
||||
final SoftwareModuleType testSmType = softwareModuleTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key("test123").name("TestName123"));
|
||||
|
||||
// DST does not exist
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/12345678")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/12345678/mandatorymoduletypes"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/12345678/optionalmoduletypes"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||
|
||||
mvc.perform(delete("/rest/v1/distributionsettypes/12345678")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
// Module types incorrect
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes/565765656"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/565765656"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||
|
||||
mvc.perform(get(
|
||||
"/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes/" + osType.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes/"
|
||||
+ testSmType.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||
|
||||
mvc.perform(get(
|
||||
"/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/" + osType.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||
|
||||
mvc.perform(get(
|
||||
"/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/" + appType.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/"
|
||||
+ testSmType.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||
|
||||
// Modules types at creation time invalid
|
||||
|
||||
final DistributionSetType testNewType = entityFactory.distributionSetType().create().key("test123")
|
||||
.name("TestName123").description("Desc123").colour("col").mandatory(Arrays.asList(osType.getId()))
|
||||
.optional(Collections.emptyList()).build();
|
||||
|
||||
mvc.perform(post("/rest/v1/distributionsettypes")
|
||||
.content(JsonBuilder.distributionSetTypes(Arrays.asList(testNewType)))
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isUnsupportedMediaType());
|
||||
|
||||
// bad request - no content
|
||||
mvc.perform(post("/rest/v1/distributionsettypes").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
|
||||
|
||||
// bad request - bad content
|
||||
mvc.perform(post("/rest/v1/distributionsettypes").content("sdfjsdlkjfskdjf".getBytes())
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
// Missing mandatory field name
|
||||
mvc.perform(post("/rest/v1/distributionsettypes").content("[{\"description\":\"Desc123\",\"key\":\"test123\"}]")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
final DistributionSetType toLongName = entityFactory.distributionSetType().create().key("test123")
|
||||
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1)).build();
|
||||
mvc.perform(post("/rest/v1/distributionsettypes")
|
||||
.content(JsonBuilder.distributionSetTypes(Arrays.asList(toLongName)))
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
// not allowed methods
|
||||
mvc.perform(put("/rest/v1/distributionsettypes")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(delete("/rest/v1/distributionsettypes")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(put("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
|
||||
mvc.perform(put(
|
||||
"/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/" + osType.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Search erquest of software module types.")
|
||||
public void searchDistributionSetTypeRsql() throws Exception {
|
||||
distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("test123").name("TestName123"));
|
||||
distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("test1234").name("TestName1234"));
|
||||
|
||||
final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234";
|
||||
|
||||
mvc.perform(get("/rest/v1/distributionsettypes?q=" + rsqlFindLikeDs1OrDs2)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(2)))
|
||||
.andExpect(jsonPath("total", equalTo(2))).andExpect(jsonPath("content[0].name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("content[1].name", equalTo("TestName1234")));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyCreatedDistributionSetTypes(final MvcResult mvcResult) throws UnsupportedEncodingException {
|
||||
final DistributionSetType created1 = distributionSetTypeManagement.getByKey("testKey1").get();
|
||||
final DistributionSetType created2 = distributionSetTypeManagement.getByKey("testKey2").get();
|
||||
final DistributionSetType created3 = distributionSetTypeManagement.getByKey("testKey3").get();
|
||||
|
||||
assertThat(created1.getMandatoryModuleTypes()).containsOnly(osType);
|
||||
assertThat(created1.getOptionalModuleTypes()).containsOnly(runtimeType);
|
||||
assertThat(created2.getOptionalModuleTypes()).containsOnly(osType, runtimeType, appType);
|
||||
assertThat(created3.getMandatoryModuleTypes()).containsOnly(osType, runtimeType);
|
||||
|
||||
assertThat(
|
||||
JsonPath.compile("[0]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
|
||||
.isEqualTo("http://localhost/rest/v1/distributionsettypes/" + created1.getId());
|
||||
assertThat(
|
||||
JsonPath.compile("[1]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
|
||||
.isEqualTo("http://localhost/rest/v1/distributionsettypes/" + created2.getId());
|
||||
assertThat(
|
||||
JsonPath.compile("[2]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
|
||||
.isEqualTo("http://localhost/rest/v1/distributionsettypes/" + created3.getId());
|
||||
|
||||
assertThat(distributionSetTypeManagement.count()).isEqualTo(7);
|
||||
}
|
||||
|
||||
@Step
|
||||
private MvcResult runPostDistributionSetType(final List<DistributionSetType> types) throws Exception {
|
||||
return mvc
|
||||
.perform(post("/rest/v1/distributionsettypes").content(JsonBuilder.distributionSetTypes(types))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("[0].name", equalTo("TestName1")))
|
||||
.andExpect(jsonPath("[0].key", equalTo("testKey1")))
|
||||
.andExpect(jsonPath("[0].description", equalTo("Desc1")))
|
||||
.andExpect(jsonPath("[0].colour", equalTo("col")))
|
||||
.andExpect(jsonPath("[0].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("[1].name", equalTo("TestName2")))
|
||||
.andExpect(jsonPath("[1].key", equalTo("testKey2")))
|
||||
.andExpect(jsonPath("[1].description", equalTo("Desc2")))
|
||||
.andExpect(jsonPath("[1].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("[2].name", equalTo("TestName3")))
|
||||
.andExpect(jsonPath("[2].key", equalTo("testKey3")))
|
||||
.andExpect(jsonPath("[2].description", equalTo("Desc3")))
|
||||
.andExpect(jsonPath("[2].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("[2].createdAt", not(equalTo(0)))).andReturn();
|
||||
}
|
||||
|
||||
@Step
|
||||
private List<DistributionSetType> createTestDistributionSetTestTypes() {
|
||||
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES);
|
||||
|
||||
return Arrays.asList(
|
||||
entityFactory.distributionSetType().create().key("testKey1").name("TestName1").description("Desc1")
|
||||
.colour("col").mandatory(Arrays.asList(osType.getId()))
|
||||
.optional(Arrays.asList(runtimeType.getId())).build(),
|
||||
entityFactory.distributionSetType().create().key("testKey2").name("TestName2").description("Desc2")
|
||||
.colour("col").optional(Arrays.asList(runtimeType.getId(), osType.getId(), appType.getId()))
|
||||
.build(),
|
||||
entityFactory.distributionSetType().create().key("testKey3").name("TestName3").description("Desc3")
|
||||
.colour("col").mandatory(Arrays.asList(runtimeType.getId(), osType.getId())).build());
|
||||
}
|
||||
|
||||
private DistributionSetType generateTestType() {
|
||||
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
|
||||
.create().key("test123").name("TestName123").description("Desc123").colour("col")
|
||||
.mandatory(Arrays.asList(osType.getId())).optional(Arrays.asList(appType.getId())));
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(1);
|
||||
assertThat(testType.getOptionalModuleTypes()).containsExactly(appType);
|
||||
assertThat(testType.getMandatoryModuleTypes()).containsExactly(osType);
|
||||
return testType;
|
||||
}
|
||||
|
||||
private void createSoftwareModulesAlphabetical(final int amount) {
|
||||
char character = 'a';
|
||||
for (int index = 0; index < amount; index++) {
|
||||
final String str = String.valueOf(character);
|
||||
softwareModuleManagement.create(
|
||||
entityFactory.softwareModule().create().name(str).description(str).vendor(str).version(str));
|
||||
character++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,440 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
/**
|
||||
* Test for {@link MgmtSoftwareModuleTypeResource}.
|
||||
*/
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Software Module Type Resource")
|
||||
public class MgmtSoftwareModuleTypeResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests.")
|
||||
public void getSoftwareModuleTypes() throws Exception {
|
||||
final SoftwareModuleType testType = createTestType();
|
||||
|
||||
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + osType.getKey() + "')].name", contains(osType.getName())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + osType.getKey() + "')].description",
|
||||
contains(osType.getDescription())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + osType.getKey() + "')].colour").doesNotExist())
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + osType.getKey() + "')].maxAssignments", contains(1)))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + osType.getKey() + "')].key", contains("os")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + runtimeType.getKey() + "')].name",
|
||||
contains(runtimeType.getName())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + runtimeType.getKey() + "')].description",
|
||||
contains(runtimeType.getDescription())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + runtimeType.getKey() + "')].maxAssignments", contains(1)))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + runtimeType.getKey() + "')].key", contains("runtime")))
|
||||
.andExpect(
|
||||
jsonPath("$.content.[?(@.key=='" + appType.getKey() + "')].name", contains(appType.getName())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + appType.getKey() + "')].description",
|
||||
contains(appType.getDescription())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + appType.getKey() + "')].colour").doesNotExist())
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + appType.getKey() + "')].maxAssignments",
|
||||
contains(Integer.MAX_VALUE)))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='" + appType.getKey() + "')].key", contains("application")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].id", contains(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].name", contains("TestName123")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].description", contains("Desc1234")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].colour", contains("colour")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].createdBy", contains("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].createdAt", contains(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].lastModifiedBy", contains("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].lastModifiedAt",
|
||||
contains(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].maxAssignments", contains(5)))
|
||||
.andExpect(jsonPath("$.content.[?(@.key=='test123')].key", contains("test123")))
|
||||
.andExpect(jsonPath("$.total", equalTo(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Handles the GET request of retrieving all software module types within SP with parameters. In this case the first 10 result in ascending order by name where the name starts with 'a'.")
|
||||
public void getSoftwareModuleTypesWithParameters() throws Exception {
|
||||
final SoftwareModuleType testType = testdataFactory.findOrCreateSoftwareModuleType("test123");
|
||||
softwareModuleTypeManagement
|
||||
.update(entityFactory.softwareModuleType().update(testType.getId()).description("Desc1234").colour("rgb(106,178,83)"));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==a")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with sorting by MAXASSIGNMENTS field.")
|
||||
public void getSoftwareModuleTypesSortedByMaxAssignments() throws Exception {
|
||||
final SoftwareModuleType testType = createTestType();
|
||||
|
||||
// descending
|
||||
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:DESC"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[1].id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.content.[1].name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("$.content.[1].description", equalTo("Desc1234")))
|
||||
.andExpect(jsonPath("$.content.[1].colour", equalTo("colour")))
|
||||
.andExpect(jsonPath("$.content.[1].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[1].createdAt", equalTo(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[1].lastModifiedBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[1].lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[1].maxAssignments", equalTo(5)))
|
||||
.andExpect(jsonPath("$.content.[1].key", equalTo("test123")))
|
||||
.andExpect(jsonPath("$.total", equalTo(4)));
|
||||
|
||||
// ascending
|
||||
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:ASC"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[2].id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.content.[2].name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("$.content.[2].description", equalTo("Desc1234")))
|
||||
.andExpect(jsonPath("$.content.[2].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[2].createdAt", equalTo(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[2].lastModifiedBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.content.[2].lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[2].maxAssignments", equalTo(5)))
|
||||
.andExpect(jsonPath("$.content.[2].key", equalTo("test123")))
|
||||
.andExpect(jsonPath("$.total", equalTo(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes POST requests when max assignment is smaller than 1")
|
||||
public void createSoftwareModuleTypesInvalidAssignmentBadRequest() throws Exception {
|
||||
|
||||
final List<SoftwareModuleType> types = new ArrayList<>();
|
||||
types.add(entityFactory.softwareModuleType().create().key("test-1").name("TestName-1").maxAssignments(-1)
|
||||
.build());
|
||||
|
||||
mvc.perform(post("/rest/v1/softwaremoduletypes").content(JsonBuilder.softwareModuleTypes(types))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
|
||||
|
||||
types.clear();
|
||||
types.add(entityFactory.softwareModuleType().create().key("test0").name("TestName0").maxAssignments(0).build());
|
||||
|
||||
mvc.perform(post("/rest/v1/softwaremoduletypes").content(JsonBuilder.softwareModuleTypes(types))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes POST requests.")
|
||||
public void createSoftwareModuleTypes() throws Exception {
|
||||
|
||||
final List<SoftwareModuleType> types = Arrays.asList(
|
||||
entityFactory.softwareModuleType().create().key("test1").name("TestName1").description("Desc1")
|
||||
.colour("col1‚").maxAssignments(1).build(),
|
||||
entityFactory.softwareModuleType().create().key("test2").name("TestName2").description("Desc2")
|
||||
.colour("col2‚").maxAssignments(2).build(),
|
||||
entityFactory.softwareModuleType().create().key("test3").name("TestName3").description("Desc3")
|
||||
.colour("col3‚").maxAssignments(3).build());
|
||||
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(post("/rest/v1/softwaremoduletypes").content(JsonBuilder.softwareModuleTypes(types))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("[0].name", equalTo("TestName1"))).andExpect(jsonPath("[0].key", equalTo("test1")))
|
||||
.andExpect(jsonPath("[0].description", equalTo("Desc1")))
|
||||
.andExpect(jsonPath("[0].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("[0].maxAssignments", equalTo(1)))
|
||||
.andExpect(jsonPath("[1].name", equalTo("TestName2"))).andExpect(jsonPath("[1].key", equalTo("test2")))
|
||||
.andExpect(jsonPath("[1].description", equalTo("Desc2")))
|
||||
.andExpect(jsonPath("[1].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("[1].maxAssignments", equalTo(2)))
|
||||
.andExpect(jsonPath("[2].name", equalTo("TestName3"))).andExpect(jsonPath("[2].key", equalTo("test3")))
|
||||
.andExpect(jsonPath("[2].description", equalTo("Desc3")))
|
||||
.andExpect(jsonPath("[2].createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("[2].createdAt", not(equalTo(0))))
|
||||
.andExpect(jsonPath("[2].maxAssignments", equalTo(3))).andReturn();
|
||||
|
||||
final SoftwareModuleType created1 = softwareModuleTypeManagement.getByKey("test1").get();
|
||||
final SoftwareModuleType created2 = softwareModuleTypeManagement.getByKey("test2").get();
|
||||
final SoftwareModuleType created3 = softwareModuleTypeManagement.getByKey("test3").get();
|
||||
|
||||
assertThat(
|
||||
JsonPath.compile("[0]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
|
||||
.isEqualTo("http://localhost/rest/v1/softwaremoduletypes/" + created1.getId());
|
||||
assertThat(
|
||||
JsonPath.compile("[1]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
|
||||
.isEqualTo("http://localhost/rest/v1/softwaremoduletypes/" + created2.getId());
|
||||
assertThat(
|
||||
JsonPath.compile("[2]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
|
||||
.isEqualTo("http://localhost/rest/v1/softwaremoduletypes/" + created3.getId());
|
||||
|
||||
assertThat(softwareModuleTypeManagement.count()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} GET requests.")
|
||||
public void getSoftwareModuleType() throws Exception {
|
||||
final SoftwareModuleType testType = createTestType();
|
||||
|
||||
mvc.perform(get("/rest/v1/softwaremoduletypes/{smtId}", testType.getId()).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("$.description", equalTo("Desc1234")))
|
||||
.andExpect(jsonPath("$.colour", equalTo("colour")))
|
||||
.andExpect(jsonPath("$.maxAssignments", equalTo(5)))
|
||||
.andExpect(jsonPath("$.createdBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.lastModifiedBy", equalTo("uploadTester")))
|
||||
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.deleted", equalTo(testType.isDeleted())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} DELETE requests (hard delete scenario).")
|
||||
public void deleteSoftwareModuleTypeUnused() throws Exception {
|
||||
final SoftwareModuleType testType = createTestType();
|
||||
|
||||
assertThat(softwareModuleTypeManagement.count()).isEqualTo(4);
|
||||
|
||||
mvc.perform(delete("/rest/v1/softwaremoduletypes/{smId}", testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
assertThat(softwareModuleTypeManagement.count()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that module type deletion request to API on an entity that does not exist results in NOT_FOUND.")
|
||||
public void deleteSoftwareModuleTypeThatDoesNotExistLeadsToNotFound() throws Exception {
|
||||
mvc.perform(delete("/rest/v1/softwaremoduletypes/1234")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "uploadTester", allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} DELETE requests (soft delete scenario).")
|
||||
public void deleteSoftwareModuleTypeUsed() throws Exception {
|
||||
final SoftwareModuleType testType = createTestType();
|
||||
softwareModuleManagement
|
||||
.create(entityFactory.softwareModule().create().type(testType).name("name").version("version"));
|
||||
|
||||
assertThat(softwareModuleTypeManagement.count()).isEqualTo(4);
|
||||
|
||||
mvc.perform(get("/rest/v1/softwaremoduletypes/{smtId}", testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(false)));
|
||||
|
||||
mvc.perform(delete("/rest/v1/softwaremoduletypes/{smtId}", testType.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
mvc.perform(get("/rest/v1/softwaremoduletypes/{smtId}", testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(true)));
|
||||
|
||||
assertThat(softwareModuleTypeManagement.count()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} PUT requests.")
|
||||
public void updateSoftwareModuleTypeColourDescriptionAndNameUntouched() throws Exception {
|
||||
final SoftwareModuleType testType = createTestType();
|
||||
|
||||
final String body = new JSONObject().put("id", testType.getId()).put("description", "foobardesc")
|
||||
.put("colour", "updatedColour").put("name", "nameShouldNotBeChanged").toString();
|
||||
|
||||
mvc.perform(put("/rest/v1/softwaremoduletypes/{smId}", testType.getId()).content(body)
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.description", equalTo("foobardesc")))
|
||||
.andExpect(jsonPath("$.colour", equalTo("updatedColour")))
|
||||
.andExpect(jsonPath("$.name", equalTo("TestName123"))).andReturn();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the update of the deletion flag. It is verfied that the software module type can't be marked as deleted through update operation.")
|
||||
public void updateSoftwareModuleTypeDeletedFlag() throws Exception {
|
||||
SoftwareModuleType testType = createTestType();
|
||||
|
||||
final String body = new JSONObject().put("id", testType.getId()).put("deleted", true).toString();
|
||||
|
||||
mvc.perform(put("/rest/v1/softwaremoduletypes/{smtId}", testType.getId()).content(body)
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.deleted", equalTo(false)));
|
||||
|
||||
testType = softwareModuleTypeManagement.get(testType.getId()).get();
|
||||
assertThat(testType.getLastModifiedAt()).isEqualTo(testType.getLastModifiedAt());
|
||||
assertThat(testType.isDeleted()).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with paging.")
|
||||
public void getSoftwareModuleTypesWithoutAddtionalRequestParameters() throws Exception {
|
||||
final int types = 3;
|
||||
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with paging.")
|
||||
public void getSoftwareModuleTypesWithPagingLimitRequestParameter() throws Exception {
|
||||
final int types = 3;
|
||||
final int limitSize = 1;
|
||||
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with paging.")
|
||||
public void getSoftwareModuleTypesWithPagingLimitAndOffsetRequestParameter() throws Exception {
|
||||
final int types = 3;
|
||||
final int offsetParam = 2;
|
||||
final int expectedSize = types - offsetParam;
|
||||
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(types)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).")
|
||||
public void invalidRequestsOnSoftwaremoduleTypesResource() throws Exception {
|
||||
final SoftwareModuleType testType = createTestType();
|
||||
|
||||
final List<SoftwareModuleType> types = Arrays.asList(testType);
|
||||
|
||||
// SM does not exist
|
||||
mvc.perform(get("/rest/v1/softwaremoduletypes/12345678")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
mvc.perform(delete("/rest/v1/softwaremoduletypes/12345678")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
// bad request - no content
|
||||
mvc.perform(post("/rest/v1/softwaremoduletypes").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
|
||||
|
||||
// bad request - bad content
|
||||
mvc.perform(post("/rest/v1/softwaremoduletypes").content("sdfjsdlkjfskdjf".getBytes())
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
mvc.perform(post("/rest/v1/softwaremoduletypes").content(
|
||||
"[{\"description\":\"Desc123\",\"id\":9223372036854775807,\"key\":\"test123\",\"maxAssignments\":5}]")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
final SoftwareModuleType toLongName = entityFactory.softwareModuleType().create().key("test123")
|
||||
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1)).build();
|
||||
mvc.perform(
|
||||
post("/rest/v1/softwaremoduletypes").content(JsonBuilder.softwareModuleTypes(Arrays.asList(toLongName)))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
|
||||
|
||||
// unsupported media type
|
||||
mvc.perform(post("/rest/v1/softwaremoduletypes").content(JsonBuilder.softwareModuleTypes(types))
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isUnsupportedMediaType());
|
||||
|
||||
// not allowed methods
|
||||
mvc.perform(put("/rest/v1/softwaremoduletypes")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(delete("/rest/v1/softwaremoduletypes")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Search erquest of software module types.")
|
||||
public void searchSoftwareModuleTypeRsql() throws Exception {
|
||||
softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create().key("test123")
|
||||
.name("TestName123").description("Desc123").maxAssignments(5));
|
||||
softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create().key("test1234")
|
||||
.name("TestName1234").description("Desc1234").maxAssignments(5));
|
||||
|
||||
final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234";
|
||||
|
||||
mvc.perform(get("/rest/v1/softwaremoduletypes?q=" + rsqlFindLikeDs1OrDs2)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(2)))
|
||||
.andExpect(jsonPath("total", equalTo(2))).andExpect(jsonPath("content[0].name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("content[1].name", equalTo("TestName1234")));
|
||||
|
||||
}
|
||||
|
||||
private SoftwareModuleType createTestType() {
|
||||
SoftwareModuleType testType = softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create()
|
||||
.key("test123").name("TestName123").description("Desc123").colour("colour").maxAssignments(5));
|
||||
testType = softwareModuleTypeManagement
|
||||
.update(entityFactory.softwareModuleType().update(testType.getId()).description("Desc1234"));
|
||||
return testType;
|
||||
}
|
||||
|
||||
private void createSoftwareModulesAlphabetical(final int amount) {
|
||||
char character = 'a';
|
||||
for (int index = 0; index < amount; index++) {
|
||||
final String str = String.valueOf(character);
|
||||
softwareModuleManagement.create(entityFactory.softwareModule().create().type(osType).name(str)
|
||||
.description(str).vendor(str).version(str));
|
||||
character++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,734 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.eclipse.hawkbit.rest.util.MockMvcResultPrinter.print;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Step;
|
||||
import io.qameta.allure.Story;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.DeletedException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
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;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
/**
|
||||
* Spring MVC Tests against the MgmtTargetResource.
|
||||
*/
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Target Filter Query Resource")
|
||||
public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
private static final String JSON_PATH_ROOT = "$";
|
||||
|
||||
// fields, attributes
|
||||
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";
|
||||
// target
|
||||
// $.field
|
||||
static final String JSON_PATH_PAGED_LIST_CONTENT = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTENT;
|
||||
private static final String JSON_PATH_FIELD_SIZE = ".size";
|
||||
static final String JSON_PATH_PAGED_LIST_SIZE = JSON_PATH_ROOT + JSON_PATH_FIELD_SIZE;
|
||||
private static final String JSON_PATH_FIELD_TOTAL = ".total";
|
||||
static final String JSON_PATH_PAGED_LIST_TOTAL = JSON_PATH_ROOT + JSON_PATH_FIELD_TOTAL;
|
||||
private static final String JSON_PATH_FIELD_AUTO_ASSIGN_DS = ".autoAssignDistributionSet";
|
||||
private static final String JSON_PATH_FIELD_AUTO_ASSIGN_ACTION_TYPE = ".autoAssignActionType";
|
||||
private static final String JSON_PATH_FIELD_EXCEPTION_CLASS = ".exceptionClass";
|
||||
private static final String JSON_PATH_FIELD_ERROR_CODE = ".errorCode";
|
||||
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;
|
||||
private static final String JSON_PATH_EXCEPTION_CLASS = JSON_PATH_ROOT + JSON_PATH_FIELD_EXCEPTION_CLASS;
|
||||
private static final String JSON_PATH_ERROR_CODE = JSON_PATH_ROOT + JSON_PATH_FIELD_ERROR_CODE;
|
||||
|
||||
@Test
|
||||
@Description("Handles the GET request of retrieving all target filter queries within SP.")
|
||||
public void getTargetFilterQueries() throws Exception {
|
||||
final String filterName = "filter_01";
|
||||
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name==test_01");
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(MockMvcResultPrinter.print());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the GET request of retrieving all target filter queries within SP based by parameter. Required Permission: READ_TARGET.")
|
||||
public void getTargetFilterQueriesWithParameters() throws Exception {
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==*1"))
|
||||
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the POST request of creating a new target filter query within SP.")
|
||||
public void createTargetFilterQuery() throws Exception {
|
||||
final String name = "test_02";
|
||||
final String filterQuery = "name==test_02";
|
||||
final String body = new JSONObject()
|
||||
.put("name", name)
|
||||
.put("query", filterQuery).toString();
|
||||
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)
|
||||
.contentType(MediaType.APPLICATION_JSON).content(body))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that deletion is executed if permitted.")
|
||||
public void deleteTargetFilterQueryReturnsOK() throws Exception {
|
||||
final String filterName = "filter_01";
|
||||
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name==test_01");
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId()))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
assertThat(targetFilterQueryManagement.get(filterQuery.getId())).isNotPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that deletion is refused with not found if target does not exist.")
|
||||
public void deleteTargetWhichDoesNotExistsLeadsToEntityNotFound() throws Exception {
|
||||
final String notExistingId = "4395";
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + notExistingId))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that update is refused with not found if target does not exist.")
|
||||
public void updateTargetWhichDoesNotExistsLeadsToEntityNotFound() throws Exception {
|
||||
final String notExistingId = "4395";
|
||||
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + notExistingId).content("{}")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that update request is reflected by repository.")
|
||||
public void updateTargetFilterQueryQuery() throws Exception {
|
||||
final String filterName = "filter_02";
|
||||
final String filterQuery = "name==test_02";
|
||||
final String filterQuery2 = "name==test_02_changed";
|
||||
final String body = new JSONObject().put("query", filterQuery2).toString();
|
||||
|
||||
// prepare
|
||||
final TargetFilterQuery tfq = createSingleTargetFilterQuery(filterName, filterQuery);
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()).content(body)
|
||||
.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_CONFIRMATION_REQUIRED).doesNotExist());
|
||||
|
||||
final TargetFilterQuery tfqCheck = targetFilterQueryManagement.get(tfq.getId()).get();
|
||||
assertThat(tfqCheck.getQuery()).isEqualTo(filterQuery2);
|
||||
assertThat(tfqCheck.getName()).isEqualTo(filterName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that update request is reflected by repository.")
|
||||
public void updateTargetFilterQueryName() throws Exception {
|
||||
final String filterName = "filter_03";
|
||||
final String filterName2 = "filter_03_changed";
|
||||
final String filterQuery = "name==test_03";
|
||||
final String body = new JSONObject().put("name", filterName2).toString();
|
||||
|
||||
// prepare
|
||||
final TargetFilterQuery tfq = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name(filterName).query(filterQuery));
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()).content(body)
|
||||
.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_CONFIRMATION_REQUIRED).doesNotExist());
|
||||
;
|
||||
|
||||
final TargetFilterQuery tfqCheck = targetFilterQueryManagement.get(tfq.getId()).get();
|
||||
assertThat(tfqCheck.getQuery()).isEqualTo(filterQuery);
|
||||
assertThat(tfqCheck.getName()).isEqualTo(filterName2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that request returns list of filters in defined format.")
|
||||
public void getTargetFilterQueryWithoutAdditionalRequestParameters() throws Exception {
|
||||
final int knownTargetAmount = 3;
|
||||
final String idA = "a";
|
||||
final String idB = "b";
|
||||
final String idC = "c";
|
||||
final String testQuery = "name==test";
|
||||
|
||||
createSingleTargetFilterQuery(idA, testQuery);
|
||||
createSingleTargetFilterQuery(idB, testQuery);
|
||||
createSingleTargetFilterQuery(idC, testQuery);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)).andExpect(status().isOk()).andDo(print())
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(knownTargetAmount)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(knownTargetAmount)))
|
||||
// idA
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idA + "')].name", contains(idA)))
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idA + "')].query", contains(testQuery)))
|
||||
// idB
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idB + "')].name", contains(idB)))
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idB + "')].query", contains(testQuery)))
|
||||
// idC
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idC + "')].name", contains(idC)))
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idC + "')].query", contains(testQuery)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that request returns list of filters in defined format in size reduced by given limit parameter.")
|
||||
public void getTargetWithPagingLimitRequestParameter() throws Exception {
|
||||
final int limitSize = 1;
|
||||
final int knownTargetAmount = 3;
|
||||
final String idA = "a";
|
||||
final String idB = "b";
|
||||
final String idC = "c";
|
||||
final String testQuery = "name==test";
|
||||
|
||||
createSingleTargetFilterQuery(idA, testQuery);
|
||||
createSingleTargetFilterQuery(idB, testQuery);
|
||||
createSingleTargetFilterQuery(idC, testQuery);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
|
||||
.andExpect(status().isOk()).andDo(print())
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)))
|
||||
// idA
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idA + "')].name", contains(idA)))
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idA + "')].query", contains(testQuery)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkIfFullRepresentationInTargetFilterReturnsDistributionSetHrefWithFilter() throws Exception {
|
||||
final String testQuery = "name==test";
|
||||
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("a", testQuery);
|
||||
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
|
||||
+ filterQuery.getId();
|
||||
final String distributionsetHrefPrefix = "http://localhost" + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING;
|
||||
|
||||
final String dsQuery = "?offset=0&limit=50&q=name==" + set.getName() + ";" + "version==" + set.getVersion();
|
||||
|
||||
mvc.perform(
|
||||
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId() + "/autoAssignDS")
|
||||
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(print()).andExpect(status().isOk());
|
||||
|
||||
final String result = mvc.perform(
|
||||
get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId()))
|
||||
.andExpect(jsonPath("$._links.autoAssignDS.href", equalTo(hrefPrefix + "/autoAssignDS")))
|
||||
.andExpect(jsonPath("$._links.DS.href", startsWith(distributionsetHrefPrefix)))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
final String multipleResult = mvc.perform(
|
||||
get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "?representation=full"))
|
||||
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1)))
|
||||
.andExpect(jsonPath("$.content[0]._links.DS.href", startsWith(distributionsetHrefPrefix)))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
final JSONObject singleJson = new JSONObject(result);
|
||||
final JSONObject multipleJson = new JSONObject(multipleResult);
|
||||
|
||||
final String resultDSURI = singleJson.getJSONObject("_links").getJSONObject("DS").getString("href");
|
||||
final String resultDSURIFromMultipleJson = multipleJson.getJSONArray("content").getJSONObject(0)
|
||||
.getJSONObject("_links").getJSONObject("DS").getString("href");
|
||||
|
||||
Assertions.assertEquals(distributionsetHrefPrefix + dsQuery, UriUtils.decode(resultDSURI, StandardCharsets.UTF_8));
|
||||
Assertions.assertEquals(distributionsetHrefPrefix + dsQuery,
|
||||
UriUtils.decode(resultDSURIFromMultipleJson, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that request returns list of filters in defined format in size reduced by given limit and offset parameter.")
|
||||
public void getTargetWithPagingLimitAndOffsetRequestParameter() throws Exception {
|
||||
final int knownTargetAmount = 5;
|
||||
final int offsetParam = 2;
|
||||
final int expectedSize = knownTargetAmount - offsetParam;
|
||||
final String idC = "c";
|
||||
final String idD = "d";
|
||||
final String idE = "e";
|
||||
final String testQuery = "name==test";
|
||||
|
||||
createSingleTargetFilterQuery("a", testQuery);
|
||||
createSingleTargetFilterQuery("b", testQuery);
|
||||
createSingleTargetFilterQuery(idC, testQuery);
|
||||
createSingleTargetFilterQuery(idD, testQuery);
|
||||
createSingleTargetFilterQuery(idE, testQuery);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(knownTargetAmount)))
|
||||
.andExpect(status().isOk()).andDo(print())
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
|
||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)))
|
||||
// idA
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idC + "')].name", contains(idC)))
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idC + "')].query", contains(testQuery)))
|
||||
// idB
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idD + "')].name", contains(idD)))
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idD + "')].query", contains(testQuery)))
|
||||
// idC
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idE + "')].name", contains(idE)))
|
||||
.andExpect(jsonPath("$.content.[?(@.name=='" + idE + "')].query", contains(testQuery)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that a single target filter query can be retrieved via its id.")
|
||||
public void getSingleTarget() throws Exception {
|
||||
// create first a target which can be retrieved by rest interface
|
||||
final String knownQuery = "name==test01";
|
||||
final String knownName = "someName";
|
||||
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
|
||||
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
|
||||
+ tfq.getId();
|
||||
// test
|
||||
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")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the retrieval of a non-existing target filter query results in a HTTP Not found error (404).")
|
||||
public void getSingleTargetNoExistsResponseNotFound() throws Exception {
|
||||
final String targetIdNotExists = "546546";
|
||||
// test
|
||||
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + targetIdNotExists))
|
||||
.andExpect(status().isNotFound()).andReturn();
|
||||
|
||||
// verify response json exception message
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility
|
||||
.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_REPO_ENTITY_NOT_EXISTS.getKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the creation of a target filter query based on an invalid request payload results in a HTTP Bad Request error (400).")
|
||||
public void createTargetFilterQueryWithBadPayloadBadRequest() throws Exception {
|
||||
final String notJson = "abc";
|
||||
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING).content(notJson)
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(print()).andExpect(status().isBadRequest()).andReturn();
|
||||
|
||||
assertThat(targetFilterQueryManagement.count()).isEqualTo(0);
|
||||
|
||||
// verify response json exception message
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility
|
||||
.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertThat(exceptionInfo.getExceptionClass()).isEqualTo(MessageNotReadableException.class.getName());
|
||||
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_REST_BODY_NOT_READABLE.getKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the creation of a target filter query based on an invalid RSQL query results in a HTTP Bad Request error (400).")
|
||||
public void createTargetFilterWithInvalidQuery() throws Exception {
|
||||
final String invalidQuery = "name=abc";
|
||||
final String body = new JSONObject().put("query", invalidQuery).put("name", "invalidFilter").toString();
|
||||
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING).content(body)
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isBadRequest()).andReturn();
|
||||
|
||||
assertThat(targetFilterQueryManagement.count()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the assignment of an auto-assign distribution set results in a HTTP Forbidden error (403) "
|
||||
+ "if the (existing) query addresses too many targets.")
|
||||
public void setAutoAssignDistributionSetOnFilterQueryThatExceedsQuota() throws Exception {
|
||||
|
||||
// create targets
|
||||
final int maxTargets = quotaManagement.getMaxTargetsPerAutoAssignment();
|
||||
testdataFactory.createTargets(maxTargets + 1, "target");
|
||||
|
||||
// create the filter query and the distribution set
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("1", "controllerId==target*");
|
||||
|
||||
mvc.perform(
|
||||
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId() + "/autoAssignDS")
|
||||
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(print()).andExpect(status().isForbidden())
|
||||
.andExpect(
|
||||
jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(AssignmentQuotaExceededException.class.getName())))
|
||||
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the update of a target filter query results in a HTTP Forbidden error (403) "
|
||||
+ "if the updated query addresses too many targets.")
|
||||
public void updateTargetFilterQueryWithQueryThatExceedsQuota() throws Exception {
|
||||
// create targets
|
||||
final int maxTargets = quotaManagement.getMaxTargetsPerAutoAssignment();
|
||||
testdataFactory.createTargets(maxTargets + 1, "target");
|
||||
|
||||
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("1", "controllerId==target1");
|
||||
|
||||
// create the filter query and the distribution set
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
|
||||
// assign the auto-assign distribution set, this should work
|
||||
mvc.perform(
|
||||
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId() + "/autoAssignDS")
|
||||
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(print()).andExpect(status().isOk());
|
||||
implicitLock(set);
|
||||
|
||||
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(filterQuery.getId()).get();
|
||||
|
||||
assertThat(updatedFilterQuery.getAutoAssignDistributionSet()).isEqualTo(set);
|
||||
assertThat(updatedFilterQuery.getAutoAssignActionType()).isEqualTo(ActionType.FORCED);
|
||||
|
||||
// update the query of the filter query to trigger a quota hit
|
||||
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId())
|
||||
.content("{\"query\":\"controllerId==target*\"}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(print()).andExpect(status().isForbidden())
|
||||
.andExpect(
|
||||
jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(AssignmentQuotaExceededException.class.getName())))
|
||||
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
|
||||
|
||||
}
|
||||
|
||||
@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 TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
|
||||
|
||||
// set will be locked after first assignment
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
|
||||
verifyAutoAssignmentWithoutActionType(tfq, set, confirmationRequired);
|
||||
verifyAutoAssignmentWithForcedActionType(tfq, set, confirmationRequired);
|
||||
verifyAutoAssignmentWithSoftActionType(tfq, set, confirmationRequired);
|
||||
verifyAutoAssignmentWithTimeForcedActionType(tfq, set);
|
||||
verifyAutoAssignmentWithDownloadOnlyActionType(tfq, set, confirmationRequired);
|
||||
verifyAutoAssignmentWithUnknownActionType(tfq, set);
|
||||
verifyAutoAssignmentWithIncompleteDs(tfq);
|
||||
verifyAutoAssignmentWithSoftDeletedDs(tfq);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the GET request of retrieving a the auto assign distribution set of a target filter query within SP.")
|
||||
public void getAssignDS() throws Exception {
|
||||
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("filter_01", "name==test_01");
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("ds");
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDS(entityFactory.targetFilterQuery()
|
||||
.updateAutoAssign(filterQuery.getId()).ds(ds.getId()));
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
|
||||
filterQuery.getId()))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the POST request of setting a distribution set for auto assignment within SP.")
|
||||
public void createAutoAssignDS() throws Exception {
|
||||
enableMultiAssignments();
|
||||
enableConfirmationFlow();
|
||||
|
||||
final String filterName = "filter_01";
|
||||
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name==test_01");
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds");
|
||||
final String autoAssignBody = new JSONObject().put("id", distributionSet.getId())
|
||||
.put("type", MgmtActionType.SOFT.getName()).put("weight", 200).toString();
|
||||
|
||||
mvc
|
||||
.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
|
||||
filterQuery.getId()).contentType(MediaType.APPLICATION_JSON).content(autoAssignBody.toString()))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the DELETE request of deleting the auto assign distribution set from a target filter query within SP.")
|
||||
public void deleteAutoAssignDS() throws Exception {
|
||||
final String filterName = "filter_01";
|
||||
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name==test_01");
|
||||
mvc
|
||||
.perform(delete(
|
||||
MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
|
||||
filterQuery.getId()))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNoContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the deletion of auto-assignment distribution set works as intended, deleting the auto-assignment action type as well")
|
||||
public void deleteAutoAssignDistributionSetOfTargetFilterQuery() throws Exception {
|
||||
final String knownQuery = "name==test06";
|
||||
final String knownName = "filter06";
|
||||
final String dsName = "testDS";
|
||||
|
||||
final DistributionSet set = testdataFactory.createDistributionSet(dsName);
|
||||
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
|
||||
targetFilterQueryManagement
|
||||
.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(tfq.getId()).ds(set.getId()));
|
||||
implicitLock(set);
|
||||
|
||||
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(tfq.getId()).get();
|
||||
|
||||
assertThat(updatedFilterQuery.getAutoAssignDistributionSet()).isEqualTo(set);
|
||||
assertThat(updatedFilterQuery.getAutoAssignActionType()).isEqualTo(ActionType.FORCED);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
|
||||
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(dsName)));
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
|
||||
.andExpect(status().isNoContent());
|
||||
|
||||
final TargetFilterQuery filterQueryWithDeletedDs = targetFilterQueryManagement.get(tfq.getId()).get();
|
||||
|
||||
assertThat(filterQueryWithDeletedDs.getAutoAssignDistributionSet()).isNull();
|
||||
assertThat(filterQueryWithDeletedDs.getAutoAssignActionType()).isNull();
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
|
||||
.andExpect(status().isNoContent());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("An auto assignment containing a weight is only accepted when weight is valide and multi assignment is on.")
|
||||
public void weightValidation() throws Exception {
|
||||
final Long filterId = createSingleTargetFilterQuery("filter1", "name==*").getId();
|
||||
final Long dsId = testdataFactory.createDistributionSet().getId();
|
||||
|
||||
final String invalideWeightRequest = new JSONObject().put("id", dsId).put("weight", Action.WEIGHT_MIN - 1)
|
||||
.toString();
|
||||
final String valideWeightRequest = new JSONObject().put("id", dsId).put("weight", 45).toString();
|
||||
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
|
||||
filterId).content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
|
||||
.andExpect(status().isOk());
|
||||
enableMultiAssignments();
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
|
||||
filterId).content(invalideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
|
||||
filterId).content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
final List<TargetFilterQuery> filters = targetFilterQueryManagement.findAll(PAGE).getContent();
|
||||
assertThat(filters).hasSize(1);
|
||||
assertThat(filters.get(0).getAutoAssignWeight().get()).isEqualTo(45);
|
||||
}
|
||||
|
||||
@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 TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
|
||||
// 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 verifyAutoAssignmentWithoutActionType(final TargetFilterQuery tfq, final DistributionSet set,
|
||||
final Boolean confirmationRequired) throws Exception {
|
||||
verifyAutoAssignmentByActionType(tfq, set, null, confirmationRequired);
|
||||
}
|
||||
|
||||
@Step
|
||||
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, final Boolean confirmationRequired) throws Exception {
|
||||
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
|
||||
+ tfq.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(jsonObject.toString()).contentType(MediaType.APPLICATION_JSON)).andDo(print())
|
||||
.andExpect(status().isOk());
|
||||
implicitLock(set);
|
||||
|
||||
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(tfq.getId()).get();
|
||||
final MgmtActionType expectedActionType = actionType != null ? actionType : MgmtActionType.FORCED;
|
||||
|
||||
assertThat(updatedFilterQuery.getAutoAssignDistributionSet()).isEqualTo(set);
|
||||
assertThat(updatedFilterQuery.getAutoAssignActionType())
|
||||
.isEqualTo(MgmtRestModelMapper.convertActionType(expectedActionType));
|
||||
|
||||
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)))
|
||||
.andExpect(jsonPath("$._links.autoAssignDS.href", equalTo(hrefPrefix + "/autoAssignDS")));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyAutoAssignmentWithTimeForcedActionType(final TargetFilterQuery tfq, final DistributionSet set)
|
||||
throws Exception {
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
|
||||
.content("{\"id\":" + set.getId() + ", \"type\":\"" + MgmtActionType.TIMEFORCED.getName() + "\"}")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS,
|
||||
equalTo(InvalidAutoAssignActionTypeException.class.getName())))
|
||||
.andExpect(jsonPath(JSON_PATH_ERROR_CODE,
|
||||
equalTo(SpServerError.SP_AUTO_ASSIGN_ACTION_TYPE_INVALID.getKey())));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyAutoAssignmentWithDownloadOnlyActionType(final TargetFilterQuery tfq, final DistributionSet set,
|
||||
final Boolean confirmationRequired) throws Exception {
|
||||
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.DOWNLOAD_ONLY, confirmationRequired);
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyAutoAssignmentWithUnknownActionType(final TargetFilterQuery tfq, final DistributionSet set)
|
||||
throws Exception {
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
|
||||
.content("{\"id\":" + set.getId() + ", \"type\":\"unknown\"}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(print()).andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(MessageNotReadableException.class.getName())))
|
||||
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_REST_BODY_NOT_READABLE.getKey())));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyAutoAssignmentWithIncompleteDs(final TargetFilterQuery tfq) throws Exception {
|
||||
final DistributionSet incompleteDistributionSet = distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create().name("incomplete").version("1")
|
||||
.type(testdataFactory.findOrCreateDefaultTestDsType()));
|
||||
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
|
||||
.content("{\"id\":" + incompleteDistributionSet.getId() + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(print()).andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS,
|
||||
equalTo(IncompleteDistributionSetException.class.getName())))
|
||||
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_DS_INCOMPLETE.getKey())));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyAutoAssignmentWithSoftDeletedDs(final TargetFilterQuery tfq) throws Exception {
|
||||
final DistributionSet softDeletedDs = testdataFactory.createDistributionSet("softDeleted");
|
||||
assignDistributionSet(softDeletedDs, testdataFactory.createTarget("forSoftDeletedDs"));
|
||||
distributionSetManagement.delete(softDeletedDs.getId());
|
||||
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
|
||||
.content("{\"id\":" + softDeletedDs.getId() + "}").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(print()).andExpect(status().isNotFound())
|
||||
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(DeletedException.class.getName())))
|
||||
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_DELETED.getKey())));
|
||||
}
|
||||
|
||||
private TargetFilterQuery createSingleTargetFilterQuery(final String name, final String query) {
|
||||
return targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(name).query(query));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,669 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetTagDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
/**
|
||||
* Spring MVC Tests against the MgmtTargetTagResource.
|
||||
*/
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Target Tag Resource")
|
||||
public class MgmtTargetTagResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
private static final String TARGETTAGS_ROOT = "http://localhost" + MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/";
|
||||
private static final Random RND = new Random();
|
||||
|
||||
@Test
|
||||
@Description("Verfies that a paged result list of target tags reflects the content on the repository side.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 2) })
|
||||
public void getTargetTags() throws Exception {
|
||||
final List<TargetTag> tags = testdataFactory.createTargetTags(2, "");
|
||||
final TargetTag assigned = tags.get(0);
|
||||
final TargetTag unassigned = tags.get(1);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(applyTagMatcherOnPagedResult(assigned)).andExpect(applyTagMatcherOnPagedResult(unassigned))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(assigned, TARGETTAGS_ROOT + assigned.getId()))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(unassigned, TARGETTAGS_ROOT + unassigned.getId()))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the GET request of retrieving all targets tags within SP based by parameter")
|
||||
public void getTargetTagsWithParameters() throws Exception {
|
||||
final List<TargetTag> tags = testdataFactory.createTargetTags(2, "");
|
||||
final TargetTag assigned = tags.get(0);
|
||||
final TargetTag unassigned = tags.get(1);
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==targetTag"))
|
||||
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that a page result when listing tags reflects on the content in the repository when filtered by 2 fields - one tag field and one target field")
|
||||
public void getTargetTagsFilteredByColor() throws Exception {
|
||||
final String controllerId1 = "controllerTestId1";
|
||||
final String controllerId2 = "controllerTestId2";
|
||||
testdataFactory.createTarget(controllerId1);
|
||||
testdataFactory.createTarget(controllerId2);
|
||||
|
||||
final List<TargetTag> tags = testdataFactory.createTargetTags(2, "");
|
||||
final TargetTag tag1 = tags.get(0);
|
||||
final TargetTag tag2 = tags.get(1);
|
||||
|
||||
targetManagement.assignTag(List.of(controllerId1, controllerId2), tag1.getId());
|
||||
targetManagement.assignTag(List.of(controllerId2), tag2.getId());
|
||||
|
||||
// pass here q directly as a pure string because .queryParam method delimiters the parameters in q with ,
|
||||
// which is logical OR, we want AND here
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING +
|
||||
"?" + MgmtRestConstants.REQUEST_PARAMETER_SEARCH + "=colour==" + tag2.getColour())
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(applyTagMatcherOnPagedResult(tag2))
|
||||
.andExpect(applySelfLinkMatcherOnPagedResult(tag2, TARGETTAGS_ROOT + tag2.getId()))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(1)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that a single result of a target tag reflects the content on the repository side.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 2) })
|
||||
public void getTargetTag() throws Exception {
|
||||
final List<TargetTag> tags = testdataFactory.createTargetTags(2, "");
|
||||
final TargetTag assigned = tags.get(0);
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + assigned.getId())
|
||||
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(applyTagMatcherOnSingleResult(assigned))
|
||||
.andExpect(applySelfLinkMatcherOnSingleResult(TARGETTAGS_ROOT + assigned.getId()))
|
||||
.andExpect(jsonPath("_links.assignedTargets.href",
|
||||
equalTo(TARGETTAGS_ROOT + assigned.getId() + "/assigned?offset=0&limit=50")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that created target tags are stored in the repository as send to the API.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 2) })
|
||||
public void createTargetTags() throws Exception {
|
||||
final Tag tagOne = entityFactory.tag().create().colour("testcol1").description("its a test1").name("thetest1")
|
||||
.build();
|
||||
final Tag tagTwo = entityFactory.tag().create().colour("testcol2").description("its a test2").name("thetest2")
|
||||
.build();
|
||||
|
||||
final ResultActions result = mvc
|
||||
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING)
|
||||
.content(JsonBuilder.tags(Arrays.asList(tagOne, tagTwo)))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
|
||||
|
||||
final Tag createdOne = targetTagManagement.findByRsql(PAGE, "name==thetest1").getContent().get(0);
|
||||
assertThat(createdOne.getName()).isEqualTo(tagOne.getName());
|
||||
assertThat(createdOne.getDescription()).isEqualTo(tagOne.getDescription());
|
||||
assertThat(createdOne.getColour()).isEqualTo(tagOne.getColour());
|
||||
final Tag createdTwo = targetTagManagement.findByRsql(PAGE, "name==thetest2").getContent().get(0);
|
||||
assertThat(createdTwo.getName()).isEqualTo(tagTwo.getName());
|
||||
assertThat(createdTwo.getDescription()).isEqualTo(tagTwo.getDescription());
|
||||
assertThat(createdTwo.getColour()).isEqualTo(tagTwo.getColour());
|
||||
|
||||
result.andExpect(applyTagMatcherOnArrayResult(createdOne)).andExpect(applyTagMatcherOnArrayResult(createdTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that an updated target tag is stored in the repository as send to the API.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetTagUpdatedEvent.class, count = 1) })
|
||||
public void updateTargetTag() throws Exception {
|
||||
final List<TargetTag> tags = testdataFactory.createTargetTags(1, "");
|
||||
final TargetTag original = tags.get(0);
|
||||
|
||||
final Tag update = entityFactory.tag().create().name("updatedName").colour("updatedCol")
|
||||
.description("updatedDesc").build();
|
||||
|
||||
final ResultActions result = mvc
|
||||
.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + original.getId())
|
||||
.content(JsonBuilder.tag(update)).contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
|
||||
|
||||
final Tag updated = targetTagManagement.findByRsql(PAGE, "name==updatedName").getContent().get(0);
|
||||
assertThat(updated.getName()).isEqualTo(update.getName());
|
||||
assertThat(updated.getDescription()).isEqualTo(update.getDescription());
|
||||
assertThat(updated.getColour()).isEqualTo(update.getColour());
|
||||
|
||||
result.andExpect(applyTagMatcherOnArrayResult(updated)).andExpect(applyTagMatcherOnArrayResult(updated));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that the delete call is reflected by the repository.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetTagDeletedEvent.class, count = 1) })
|
||||
public void deleteTargetTag() throws Exception {
|
||||
final List<TargetTag> tags = testdataFactory.createTargetTags(1, "");
|
||||
final TargetTag original = tags.get(0);
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + original.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
assertThat(targetTagManagement.get(original.getId())).isNotPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that assigned targets to tag in repository are listed with proper paging results.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 5), @Expect(type = TargetUpdatedEvent.class, count = 5) })
|
||||
public void getAssignedTargets() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final int targetsAssigned = 5;
|
||||
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
|
||||
targetManagement.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(targetsAssigned)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(targetsAssigned)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(targetsAssigned)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that assigned DS to tag in repository are listed with proper paging results with paging limit parameter.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 5), @Expect(type = TargetUpdatedEvent.class, count = 5) })
|
||||
public void getAssignedTargetsWithPagingLimitRequestParameter() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final int targetsAssigned = 5;
|
||||
final int limitSize = 1;
|
||||
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
|
||||
targetManagement.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(targetsAssigned)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that assigned targets to tag in repository are listed with proper paging results with paging limit and offset parameter.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 5), @Expect(type = TargetUpdatedEvent.class, count = 5) })
|
||||
public void getAssignedTargetsWithPagingLimitAndOffsetRequestParameter() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final int targetsAssigned = 5;
|
||||
final int offsetParam = 2;
|
||||
final int expectedSize = targetsAssigned - offsetParam;
|
||||
|
||||
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
|
||||
targetManagement.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(targetsAssigned)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(targetsAssigned)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 1) })
|
||||
public void assignTarget() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final Target assigned = testdataFactory.createTargets(1).get(0);
|
||||
|
||||
mvc.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/" +
|
||||
assigned.getControllerId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
final List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
|
||||
.containsOnly(assigned.getControllerId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 2) })
|
||||
public void assignTargets() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<Target> targets = testdataFactory.createTargets(2);
|
||||
final Target assigned0 = targets.get(0);
|
||||
final Target assigned1 = targets.get(1);
|
||||
;
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(JsonBuilder.toArray(Arrays.asList(assigned0.getControllerId(), assigned1.getControllerId())))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
final List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
|
||||
.containsOnly(assigned0.getControllerId(), assigned1.getControllerId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2) })
|
||||
public void assignTargetsNotFound() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
|
||||
final List<String> missing = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
while (true) {
|
||||
final String id = String.valueOf(Math.abs(RND.nextLong()));
|
||||
if (!targets.contains(id)) {
|
||||
missing.add(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(missing);
|
||||
final List<String> withMissing = new ArrayList<>(targets);
|
||||
withMissing.addAll(missing);
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(JsonBuilder.toArray(withMissing))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound())
|
||||
.andExpect(handler -> {
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
|
||||
final Map<String, Object> info = exceptionInfo.getInfo();
|
||||
assertThat(info).isNotNull();
|
||||
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName());
|
||||
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
|
||||
Collections.sort(notFound);
|
||||
assertThat(notFound).isEqualTo(missing);
|
||||
});
|
||||
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 2) })
|
||||
public void assignTargetsNotFoundTagAndFail() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
|
||||
final List<String> missing = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
while (true) {
|
||||
final String id = String.valueOf(Math.abs(RND.nextLong()));
|
||||
if (!targets.contains(id)) {
|
||||
missing.add(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(missing);
|
||||
final List<String> withMissing = new ArrayList<>(targets);
|
||||
withMissing.addAll(missing);
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.param("onNotFoundPolicy", MgmtTargetTagRestApi.OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL.name())
|
||||
.content(JsonBuilder.toArray(withMissing))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound())
|
||||
.andExpect(handler -> {
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
|
||||
final Map<String, Object> info = exceptionInfo.getInfo();
|
||||
assertThat(info).isNotNull();
|
||||
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName());
|
||||
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
|
||||
Collections.sort(notFound);
|
||||
assertThat(notFound).isEqualTo(missing);
|
||||
});
|
||||
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent().stream().map(Target::getControllerId).sorted().toList())
|
||||
.isEqualTo(targets.stream().sorted().toList());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 2) })
|
||||
public void assignTargetsNotFoundTagAndSuccess() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
|
||||
final List<String> missing = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
while (true) {
|
||||
final String id = String.valueOf(Math.abs(RND.nextLong()));
|
||||
if (!targets.contains(id)) {
|
||||
missing.add(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(missing);
|
||||
final List<String> withMissing = new ArrayList<>(targets);
|
||||
withMissing.addAll(missing);
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.param("onNotFoundPolicy", MgmtTargetTagRestApi.OnNotFoundPolicy.ON_WHAT_FOUND_AND_SUCCESS.name())
|
||||
.content(JsonBuilder.toArray(withMissing))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent().stream().map(Target::getControllerId).sorted().toList())
|
||||
.isEqualTo(targets.stream().sorted().toList());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag unassignments done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 3) })
|
||||
public void unassignTarget() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<Target> targets = testdataFactory.createTargets(2);
|
||||
final Target assigned = targets.get(0);
|
||||
final Target unassigned = targets.get(1);
|
||||
|
||||
targetManagement.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/" +
|
||||
unassigned.getControllerId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
final List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
|
||||
.containsOnly(assigned.getControllerId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag unassignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 3),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 5) })
|
||||
public void unassignTargets() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<Target> targets = testdataFactory.createTargets(3);
|
||||
final Target assigned = targets.get(0);
|
||||
final Target unassigned0 = targets.get(1);
|
||||
final Target unassigned1 = targets.get(2);
|
||||
|
||||
targetManagement.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(JsonBuilder.toArray(Arrays.asList(unassigned0.getControllerId(), unassigned1.getControllerId())))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
final List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
|
||||
.containsOnly(assigned.getControllerId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 2) })
|
||||
public void unassignTargetsNotFound() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
|
||||
final List<String> missing = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
while (true) {
|
||||
final String id = String.valueOf(Math.abs(RND.nextLong()));
|
||||
if (!targets.contains(id)) {
|
||||
missing.add(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(missing);
|
||||
final List<String> withMissing = new ArrayList<>(targets);
|
||||
withMissing.addAll(missing);
|
||||
|
||||
targetManagement.assignTag(targets, tag.getId());
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(JsonBuilder.toArray(withMissing))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound())
|
||||
.andExpect(handler -> {
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
|
||||
final Map<String, Object> info = exceptionInfo.getInfo();
|
||||
assertThat(info).isNotNull();
|
||||
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName());
|
||||
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
|
||||
Collections.sort(notFound);
|
||||
assertThat(notFound).isEqualTo(missing);
|
||||
});
|
||||
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent().stream().map(Target::getControllerId).sorted().toList())
|
||||
.isEqualTo(targets.stream().sorted().toList());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 4) })
|
||||
public void unassignTargetsNotFoundUntagAndFail() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
|
||||
final List<String> missing = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
while (true) {
|
||||
final String id = String.valueOf(Math.abs(RND.nextLong()));
|
||||
if (!targets.contains(id)) {
|
||||
missing.add(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(missing);
|
||||
final List<String> withMissing = new ArrayList<>(targets);
|
||||
withMissing.addAll(missing);
|
||||
|
||||
targetManagement.assignTag(targets, tag.getId());
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.param("onNotFoundPolicy", MgmtTargetTagRestApi.OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL.name())
|
||||
.content(JsonBuilder.toArray(withMissing))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound())
|
||||
.andExpect(handler -> {
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
|
||||
final Map<String, Object> info = exceptionInfo.getInfo();
|
||||
assertThat(info).isNotNull();
|
||||
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName());
|
||||
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
|
||||
Collections.sort(notFound);
|
||||
assertThat(notFound).isEqualTo(missing);
|
||||
});
|
||||
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({
|
||||
@Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 4) })
|
||||
public void unassignTargetsNotFoundUntagAndSuccess() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
|
||||
final List<String> missing = new ArrayList<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
while (true) {
|
||||
final String id = String.valueOf(Math.abs(RND.nextLong()));
|
||||
if (!targets.contains(id)) {
|
||||
missing.add(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(missing);
|
||||
final List<String> withMissing = new ArrayList<>(targets);
|
||||
withMissing.addAll(missing);
|
||||
|
||||
targetManagement.assignTag(targets, tag.getId());
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.param("onNotFoundPolicy", MgmtTargetTagRestApi.OnNotFoundPolicy.ON_WHAT_FOUND_AND_SUCCESS.name())
|
||||
.content(JsonBuilder.toArray(withMissing))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent()).isEmpty();
|
||||
}
|
||||
|
||||
// DEPRECATED scenarios
|
||||
@Test
|
||||
@Description("Verifes that tag assignments done through toggle API command are correctly assigned or unassigned.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 4) })
|
||||
public void toggleTagAssignment() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final int targetsAssigned = 2;
|
||||
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
|
||||
|
||||
ResultActions result = toggle(tag, targets);
|
||||
|
||||
List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
|
||||
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
|
||||
.containsAll(targets.stream().map(Target::getControllerId).collect(Collectors.toList()));
|
||||
|
||||
result.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(0), "assignedTargets"))
|
||||
.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(1), "assignedTargets"));
|
||||
|
||||
result = toggle(tag, targets);
|
||||
|
||||
updated = targetManagement.findAll(PAGE).getContent();
|
||||
|
||||
result.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(0), "unassignedTargets"))
|
||||
.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(1), "unassignedTargets"));
|
||||
|
||||
assertThat(targetManagement.findByTag(PAGE, tag.getId())).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verfies that tag assignments done through tag API command are correctly stored in the repository.")
|
||||
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2) })
|
||||
public void assignTargetsByRequestBody() throws Exception {
|
||||
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
|
||||
final int targetsAssigned = 2;
|
||||
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
|
||||
|
||||
final ResultActions result = mvc
|
||||
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
|
||||
.content(controllerIdsOld(
|
||||
targets.stream().map(Target::getControllerId).collect(Collectors.toList())))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
|
||||
|
||||
final List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
|
||||
|
||||
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
|
||||
.containsAll(targets.stream().map(Target::getControllerId).collect(Collectors.toList()));
|
||||
|
||||
result.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(0)))
|
||||
.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(1)));
|
||||
}
|
||||
|
||||
private static String controllerIdsOld(final Collection<String> ids) throws JSONException {
|
||||
final JSONArray list = new JSONArray();
|
||||
for (final String smID : ids) {
|
||||
list.put(new JSONObject().put("controllerId", smID));
|
||||
}
|
||||
|
||||
return list.toString();
|
||||
}
|
||||
|
||||
private ResultActions toggle(final TargetTag tag, final List<Target> targets) throws Exception {
|
||||
return mvc
|
||||
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId()
|
||||
+ "/assigned/toggleTagAssignment")
|
||||
.content(controllerIdsOld(
|
||||
targets.stream().map(Target::getControllerId).collect(Collectors.toList())))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,648 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.hasToString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Step;
|
||||
import io.qameta.allure.Story;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.util.JsonBuilder;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
/**
|
||||
* Spring MVC Tests against the MgmtTargetTypeResource.
|
||||
*/
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Target Type Resource")
|
||||
class MgmtTargetTypeResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
private static final String TARGETTYPES_ENDPOINT = MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING;
|
||||
private static final String TARGETTYPE_SINGLE_ENDPOINT = MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING
|
||||
+ "/{typeid}";
|
||||
private static final String TARGETTYPE_DSTYPES_ENDPOINT = TARGETTYPE_SINGLE_ENDPOINT + "/"
|
||||
+ MgmtRestConstants.TARGETTYPE_V1_DS_TYPES;
|
||||
private static final String TARGETTYPE_DSTYPE_SINGLE_ENDPOINT = TARGETTYPE_DSTYPES_ENDPOINT + "/{dstypeid}";
|
||||
|
||||
private static final String TEST_USER = "targetTypeTester";
|
||||
private static final String SPACE_AND_DESCRIPTION = " description";
|
||||
|
||||
@Test
|
||||
@WithUser(principal = "targetTypeTester", allSpPermissions = true, removeFromAllPermission = { SpPermission.READ_TARGET })
|
||||
@Description("GET targettypes returns Forbidden when permission is missing")
|
||||
void getTargetTypesWithoutPermission() throws Exception {
|
||||
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{id} GET request.")
|
||||
void getTargetType() throws Exception {
|
||||
String typeName = "TestTypeGET";
|
||||
TargetType testType = createTestTargetTypeInDB(typeName);
|
||||
Long typeId = testType.getId();
|
||||
|
||||
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, typeId).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.id", is(typeId), Long.class)).andExpect(jsonPath("$.name", equalTo(typeName)))
|
||||
.andExpect(jsonPath("$.colour", is("#000000")))
|
||||
.andExpect(jsonPath("$.description", equalTo(typeName + SPACE_AND_DESCRIPTION)))
|
||||
.andExpect(jsonPath("$.createdBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.lastModifiedBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$._links.self.href", equalTo("http://localhost/rest/v1/targettypes/" + typeId)))
|
||||
.andExpect(jsonPath("$.deleted", equalTo(false)))
|
||||
.andExpect(jsonPath("$.key", equalTo(typeName + " key")))
|
||||
.andExpect(jsonPath("$._links.compatibledistributionsettypes.href",
|
||||
equalTo("http://localhost/rest/v1/targettypes/" + typeId + "/compatibledistributionsettypes")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests.")
|
||||
void getTargetTypes() throws Exception {
|
||||
String typeName = "TestTypeGET";
|
||||
int count = 5;
|
||||
List<TargetType> testTypes = createTestTargetTypesInDB(typeName, count);
|
||||
|
||||
ResultActions resultActions = mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print());
|
||||
|
||||
for (int index = 0; index < count; index++) {
|
||||
Long typeId = testTypes.get(index).getId();
|
||||
resultActions.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].id", contains(typeId.intValue())))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].name", contains(typeName + index)))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].colour", contains("#000000")))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].description",
|
||||
contains(typeName + SPACE_AND_DESCRIPTION)))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].createdBy", contains(TEST_USER)))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].createdAt",
|
||||
contains(testTypes.get(index).getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].lastModifiedBy", contains(TEST_USER)))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].lastModifiedAt",
|
||||
contains(testTypes.get(index).getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].deleted", contains(false)))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].key", contains(typeName + index + " key")))
|
||||
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')]._links.self.href",
|
||||
contains("http://localhost/rest/v1/targettypes/" + typeId)))
|
||||
.andExpect(
|
||||
jsonPath("$.content.[?(@.id=='" + typeId + "')]._links.compatibledistributionsettypes.href")
|
||||
.doesNotExist())
|
||||
.andExpect(jsonPath("$.total", equalTo(count))).andExpect(jsonPath("$.size", equalTo(count)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests without prior created target types.")
|
||||
void getDefaultTargetTypes() throws Exception {
|
||||
|
||||
// 0 types overall (no default types are created)
|
||||
final int types = 0;
|
||||
mvc.perform(get(TARGETTYPES_ENDPOINT)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with sorting by name.")
|
||||
void getTargetTypesSortedByName() throws Exception {
|
||||
String typeNameA = "ATestTypeGETsorted";
|
||||
String typeNameB = "BTestTypeGETsorted";
|
||||
String typeNameC = "CTestTypeGETsorted";
|
||||
TargetType testTypeB = createTestTargetTypeInDB(typeNameB);
|
||||
TargetType testTypeC = createTestTargetTypeInDB(typeNameC);
|
||||
TargetType testTypeA = createTestTargetTypeInDB(typeNameA);
|
||||
|
||||
testTypeA = targetTypeManagement
|
||||
.update(entityFactory.targetType().update(testTypeA.getId()).description("Updated description"));
|
||||
|
||||
// descending
|
||||
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "name:DESC")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[0].id", equalTo(testTypeC.getId().intValue())))
|
||||
.andExpect(jsonPath("$.content.[0].name", equalTo(typeNameC)))
|
||||
.andExpect(jsonPath("$.content.[0].colour", equalTo("#000000")))
|
||||
.andExpect(jsonPath("$.content.[0].description", equalTo(typeNameC + SPACE_AND_DESCRIPTION)))
|
||||
.andExpect(jsonPath("$.content.[0].createdBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.content.[0].createdAt", equalTo(testTypeC.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[0].lastModifiedBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.content.[0].lastModifiedAt", equalTo(testTypeC.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[0].deleted", equalTo(false)))
|
||||
.andExpect(jsonPath("$.content.[0].key", equalTo(typeNameC + " key")))
|
||||
.andExpect(jsonPath("$.content.[0]._links.self.href",
|
||||
equalTo("http://localhost/rest/v1/targettypes/" + testTypeC.getId())))
|
||||
.andExpect(jsonPath("$.content.[0]._links.compatibledistributionsettypes.href").doesNotExist())
|
||||
.andExpect(jsonPath("$.total", equalTo(3))).andExpect(jsonPath("$.size", equalTo(3)))
|
||||
.andExpect(jsonPath("$.content.[1].name", equalTo(typeNameB)))
|
||||
.andExpect(jsonPath("$.content.[2].name", equalTo(typeNameA)));
|
||||
|
||||
// ascending
|
||||
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "name:ASC")).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.content.[0].id", equalTo(testTypeA.getId().intValue())))
|
||||
.andExpect(jsonPath("$.content.[0].name", equalTo(typeNameA)))
|
||||
.andExpect(jsonPath("$.content.[0].description", equalTo("Updated description")))
|
||||
.andExpect(jsonPath("$.content.[0].colour", equalTo("#000000")))
|
||||
.andExpect(jsonPath("$.content.[0].createdBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.content.[0].createdAt", equalTo(testTypeA.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.content.[0].lastModifiedBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.content.[0].lastModifiedAt", equalTo(testTypeA.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.content.[0].deleted", equalTo(false)))
|
||||
.andExpect(jsonPath("$.content.[0].key", equalTo(typeNameA + " key")))
|
||||
.andExpect(jsonPath("$.content.[0]._links.self.href",
|
||||
equalTo("http://localhost/rest/v1/targettypes/" + testTypeA.getId())))
|
||||
.andExpect(jsonPath("$.content.[0]._links.compatibledistributionsettypes.href").doesNotExist())
|
||||
.andExpect(jsonPath("$.total", equalTo(3))).andExpect(jsonPath("$.size", equalTo(3)))
|
||||
.andExpect(jsonPath("$.content.[1].name", equalTo(typeNameB)))
|
||||
.andExpect(jsonPath("$.content.[2].name", equalTo(typeNameC)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with paging.")
|
||||
void getTargetTypesWithPagingLimitRequestParameter() throws Exception {
|
||||
final String typePrefix = "TestTypeGETPaging";
|
||||
final int count = 10;
|
||||
final int limit = 3;
|
||||
createTestTargetTypesInDB(typePrefix, count);
|
||||
|
||||
mvc.perform(get(TARGETTYPES_ENDPOINT).param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT,
|
||||
String.valueOf(limit))).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(count)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limit)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limit)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with paging and offset.")
|
||||
void getTargetTypesWithPagingLimitAndOffsetRequestParameter() throws Exception {
|
||||
final int count = 10;
|
||||
final int offset = 2;
|
||||
final int expectedSize = count - offset;
|
||||
final String typePrefix = "TestTypeGETPaging";
|
||||
createTestTargetTypesInDB(typePrefix, count);
|
||||
|
||||
mvc.perform(get(TARGETTYPES_ENDPOINT)
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offset))
|
||||
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(count)))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(count)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
|
||||
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} PUT requests.")
|
||||
void updateTargetType() throws Exception {
|
||||
String typeName = "TestTypePUT";
|
||||
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||
final String body = new JSONObject().put("id", testType.getId()).put("description", "updated description")
|
||||
.put("name", "TestTypePUTupdated").put("colour", "#ffffff").toString();
|
||||
|
||||
mvc.perform(
|
||||
put(TARGETTYPE_SINGLE_ENDPOINT, testType.getId()).content(body).contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.description", equalTo("updated description")))
|
||||
.andExpect(jsonPath("$.name", equalTo("TestTypePUTupdated")))
|
||||
.andExpect(jsonPath("$.colour", equalTo("#ffffff"))).andReturn();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{id} GET requests.")
|
||||
void getUpdatedTargetType() throws Exception {
|
||||
final String initialTypeName = "TestTypeGET";
|
||||
TargetType testType = createTestTargetTypeInDB(initialTypeName);
|
||||
final String typeNameUpdated = "TestTypeGETupdated";
|
||||
testType = targetTypeManagement.update(entityFactory.targetType().update(testType.getId()).name(typeNameUpdated)
|
||||
.description("Updated Description").colour("#ffffff"));
|
||||
|
||||
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, testType.getId()).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$.name", equalTo(typeNameUpdated)))
|
||||
.andExpect(jsonPath("$.description", equalTo("Updated Description")))
|
||||
.andExpect(jsonPath("$.colour", equalTo("#ffffff")))
|
||||
.andExpect(jsonPath("$.createdBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
|
||||
.andExpect(jsonPath("$.lastModifiedBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
|
||||
.andExpect(jsonPath("$.deleted", equalTo(false)))
|
||||
.andExpect(jsonPath("$.key", equalTo(initialTypeName + " key")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes POST requests.")
|
||||
void createTargetTypes() throws Exception {
|
||||
String typeName = "TestTypePOST";
|
||||
final List<TargetType> types = buildTestTargetTypesWithoutDsTypes(typeName, 5);
|
||||
|
||||
runPostTargetTypeAndVerify(types);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes POST requests.")
|
||||
void addDistributionSetTypeToTargetType() throws Exception {
|
||||
String typeName = "TestTypeAddDs";
|
||||
TargetType testType = createTestTargetTypeInDB(typeName);
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(1);
|
||||
|
||||
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())
|
||||
.content("[{\"id\":" + standardDsType.getId() + "}]").contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
testType = targetTypeManagement.get(testType.getId()).get();
|
||||
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(testType.getCompatibleDistributionSetTypes()).containsExactly(standardDsType);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes GET requests.")
|
||||
void getDistributionSetsOfTargetType() throws Exception {
|
||||
String typeName = "TestTypeGetDs";
|
||||
final TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
|
||||
|
||||
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$[0].name", equalTo(standardDsType.getName())))
|
||||
.andExpect(jsonPath("$[0].description", equalTo(standardDsType.getDescription())))
|
||||
.andExpect(jsonPath("$[0].key", equalTo("test_default_ds_type")))
|
||||
.andExpect(jsonPath("$[0]._links.self.href",
|
||||
equalTo("http://localhost/rest/v1/distributionsettypes/" + standardDsType.getId())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes/{ID} GET requests.")
|
||||
void getDistributionSetOfTargetTypeReturnsNotAllowed() throws Exception {
|
||||
String typeName = "TestTypeAddDs";
|
||||
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||
|
||||
mvc.perform(get(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), standardDsType.getId())
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes/{ID} DELETE requests.")
|
||||
void removeDsTypeFromTargetType() throws Exception {
|
||||
String typeName = "TestTypeRemoveDs";
|
||||
TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
|
||||
|
||||
mvc.perform(delete(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), standardDsType.getId())
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
testType = targetTypeManagement.get(testType.getId()).get();
|
||||
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(testType.getCompatibleDistributionSetTypes()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} DELETE requests.")
|
||||
void deletingDsTypeRemovesAssignmentFromTargetType() throws Exception {
|
||||
String typeName = "TestTypeRemoveDs";
|
||||
TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
|
||||
assertThat(testType.getCompatibleDistributionSetTypes()).hasSize(1);
|
||||
assertThat(distributionSetTypeManagement.getByKey(standardDsType.getKey())).isNotEmpty();
|
||||
|
||||
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING + "/" + standardDsType.getId()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
testType = targetTypeManagement.get(testType.getId()).get();
|
||||
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
|
||||
assertThat(testType.getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(testType.getCompatibleDistributionSetTypes()).isEmpty();
|
||||
assertThat(distributionSetTypeManagement.getByKey(standardDsType.getKey())).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} DELETE requests - Deletion when not in use.")
|
||||
void deleteTargetTypeUnused() throws Exception {
|
||||
String typeName = "TestTypeUnusedDelete";
|
||||
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||
|
||||
assertThat(targetTypeManagement.count()).isEqualTo(1);
|
||||
|
||||
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
assertThat(targetTypeManagement.count()).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} DELETE requests - Deletion not possible when in use.")
|
||||
void deleteTargetTypeUsed() throws Exception {
|
||||
String typeName = "TestTypeUsedDelete";
|
||||
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||
|
||||
targetManagement.create(entityFactory.target().create().controllerId("target").name("TargetOfTestType")
|
||||
.description("target description").targetType(testType.getId()));
|
||||
|
||||
assertThat(targetTypeManagement.count()).isEqualTo(1);
|
||||
assertThat(targetManagement.count()).isEqualTo(1);
|
||||
|
||||
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isConflict());
|
||||
|
||||
assertThat(targetManagement.count()).isEqualTo(1);
|
||||
assertThat(targetTypeManagement.count()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Ensures that target type deletion request to API on an entity that does not exist results in NOT_FOUND.")
|
||||
void deleteTargetTypeThatDoesNotExistLeadsToNotFound() throws Exception {
|
||||
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, 1234)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Tests the update of the deletion flag. It is verified that the target type can't be marked as deleted through update operation.")
|
||||
void updateTargetTypeDeletedFlag() throws Exception {
|
||||
String typeName = "TestTypePUT";
|
||||
final TargetType testType = createTestTargetTypeInDB(typeName);
|
||||
|
||||
final String body = new JSONObject().put("id", testType.getId()).put("deleted", true).toString();
|
||||
|
||||
mvc.perform(
|
||||
put(TARGETTYPE_SINGLE_ENDPOINT, testType.getId()).content(body).contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
|
||||
.andExpect(jsonPath("$.deleted", equalTo(false))); // don't delete with update
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).")
|
||||
void invalidRequestsOnTargetTypesResource() throws Exception {
|
||||
String typeName = "TestTypeInvalidReq";
|
||||
final TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
|
||||
|
||||
// target type does not exist
|
||||
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, 12345678)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, 123456789)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, 123456789)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
// target types at creation time invalid
|
||||
final TargetType testNewType = createTestTargetTypeInDB(typeName + "Another",
|
||||
Collections.singletonList(standardDsType));
|
||||
|
||||
mvc.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(Collections.singletonList(testNewType)))
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isUnsupportedMediaType());
|
||||
|
||||
// bad request - no content
|
||||
mvc.perform(post(TARGETTYPES_ENDPOINT).contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
|
||||
|
||||
// bad request - bad content
|
||||
mvc.perform(post(TARGETTYPES_ENDPOINT).content("sdfjsdlkjfskdjf".getBytes())
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
// Missing mandatory field name
|
||||
mvc.perform(post(TARGETTYPES_ENDPOINT).content("[{\"description\":\"Desc123\"}]")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
final TargetType tooLongName = entityFactory.targetType().create()
|
||||
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1)).build();
|
||||
mvc.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(Collections.singletonList(tooLongName)))
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
// ds types
|
||||
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
mvc.perform(delete(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
|
||||
|
||||
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).content("{\"id\":1}")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).content("[{\"id\":44456}]")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
// not allowed methods
|
||||
mvc.perform(put(TARGETTYPES_ENDPOINT)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(delete(TARGETTYPES_ENDPOINT)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(put(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(delete(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId(), 565765)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(put(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(post(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765)
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
|
||||
mvc.perform(get(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Search request of target types.")
|
||||
void searchTargetTypeRsql() throws Exception {
|
||||
targetTypeManagement.create(entityFactory.targetType().create().name("TestName123"));
|
||||
targetTypeManagement.create(entityFactory.targetType().create().name("TestName1234"));
|
||||
|
||||
final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234";
|
||||
|
||||
mvc.perform(get(TARGETTYPES_ENDPOINT + "?q=" + rsqlFindLikeDs1OrDs2)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(2)))
|
||||
.andExpect(jsonPath("total", equalTo(2))).andExpect(jsonPath("content[0].name", equalTo("TestName123")))
|
||||
.andExpect(jsonPath("content[1].name", equalTo("TestName1234")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(principal = TEST_USER, allSpPermissions = true)
|
||||
@Description("Verifies quota enforcement for /rest/v1/targettypes/{ID}/compatibledistributionsettypes POST requests.")
|
||||
void assignDistributionSetTypeToTargetTypeUntilQuotaExceeded() throws Exception {
|
||||
final TargetType testType = createTestTargetTypeInDB("TestTypeQuota");
|
||||
|
||||
// create distribution set types
|
||||
final int maxDistributionSetTypes = quotaManagement.getMaxDistributionSetTypesPerTargetType();
|
||||
final List<Long> dsTypeIds = new ArrayList<>();
|
||||
for (int i = 0; i < maxDistributionSetTypes + 1; ++i) {
|
||||
final DistributionSetType ds = testdataFactory.findOrCreateDistributionSetType("dsType_" + i,
|
||||
"dsType_" + i);
|
||||
dsTypeIds.add(ds.getId());
|
||||
}
|
||||
|
||||
// verify quota enforcement for distribution set types
|
||||
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())
|
||||
.content(JsonBuilder.ids(dsTypeIds.subList(0, dsTypeIds.size() - 1)))
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())
|
||||
.content("[{\"id\":" + dsTypeIds.get(dsTypeIds.size() - 1) + "}]")
|
||||
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
|
||||
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
|
||||
}
|
||||
|
||||
@Step
|
||||
private TargetType buildTestTargetTypeBody(String name) {
|
||||
return prepareTestTargetType(name, null).build();
|
||||
}
|
||||
|
||||
private TargetTypeCreate prepareTestTargetType(String name, Collection<DistributionSetType> dsTypes) {
|
||||
TargetTypeCreate create = entityFactory.targetType().create().name(name)
|
||||
.description("Description of the test type").colour("#aaaaaa");
|
||||
if (dsTypes != null && !dsTypes.isEmpty()) {
|
||||
create.compatible(Collections.singletonList(standardDsType.getId()));
|
||||
}
|
||||
return create;
|
||||
}
|
||||
|
||||
@Step
|
||||
private List<TargetType> createTestTargetTypesInDB(String namePrefix, int count) {
|
||||
return testdataFactory.createTargetTypes(namePrefix, count);
|
||||
}
|
||||
|
||||
@Step
|
||||
private TargetType createTestTargetTypeInDB(String name) {
|
||||
return testdataFactory.findOrCreateTargetType(name);
|
||||
}
|
||||
|
||||
@Step
|
||||
private TargetType createTestTargetTypeInDB(String name, List<DistributionSetType> dsTypes) {
|
||||
TargetType targetType = testdataFactory.createTargetType(name, dsTypes);
|
||||
assertThat(targetType.getOptLockRevision()).isEqualTo(1);
|
||||
return targetType;
|
||||
}
|
||||
|
||||
@Step
|
||||
private List<TargetType> buildTestTargetTypesWithoutDsTypes(String namePrefix, int count) {
|
||||
final List<TargetType> types = new ArrayList<>();
|
||||
for (int index = 0; index < count; index++) {
|
||||
types.add(buildTestTargetTypeBody(namePrefix + index));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
@Step
|
||||
private void runPostTargetTypeAndVerify(final List<TargetType> types) throws Exception {
|
||||
int size = types.size();
|
||||
ResultActions resultActions = mvc
|
||||
.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(types))
|
||||
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print());
|
||||
|
||||
for (int index = 0; index < size; index++) {
|
||||
resultActions.andExpect(status().isCreated()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||
.andExpect(jsonPath("$[" + index + "].id").exists())
|
||||
.andExpect(jsonPath("$[" + index + "].name", startsWith("TestTypePOST")))
|
||||
.andExpect(jsonPath("$[" + index + "].colour", hasToString("#aaaaaa")))
|
||||
.andExpect(jsonPath("$[" + index + "].description",
|
||||
equalTo("Description of the test type")))
|
||||
.andExpect(jsonPath("$[" + index + "].createdBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$[" + index + "].createdAt").exists())
|
||||
.andExpect(jsonPath("$[" + index + "].lastModifiedBy", equalTo(TEST_USER)))
|
||||
.andExpect(jsonPath("$[" + index + "].lastModifiedAt").exists())
|
||||
.andExpect(jsonPath("$[" + index + "].deleted", equalTo(false)))
|
||||
.andExpect(jsonPath("$[" + index + "].key", startsWith("TestTypePOST")))
|
||||
.andExpect(jsonPath("$[" + index + "]._links.self.href",
|
||||
startsWith("http://localhost/rest/v1/targettypes/")))
|
||||
.andExpect(
|
||||
jsonPath("$[" + index + "]._links.compatibledistributionsettypes.href")
|
||||
.doesNotExist());
|
||||
}
|
||||
MvcResult mvcResult = resultActions.andReturn();
|
||||
|
||||
for (int index = 0; index < size; index++) {
|
||||
String name = "TestTypePOST" + index;
|
||||
final TargetType created = targetTypeManagement.getByName(name).get();
|
||||
|
||||
assertThat(JsonPath.compile("$[ ?(@.name=='" + name + "') ].id")
|
||||
.read(mvcResult.getResponse().getContentAsString()).toString()).contains(String.valueOf(created.getId()));
|
||||
assertThat(JsonPath.compile("$[ ?(@.name=='" + name + "') ]._links.self.href")
|
||||
.read(mvcResult.getResponse().getContentAsString()).toString()).contains("/" + created.getId());
|
||||
}
|
||||
|
||||
assertThat(targetTypeManagement.count()).isEqualTo(size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValueRequest;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
|
||||
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
||||
/**
|
||||
* Spring MVC Tests against the MgmtTenantManagementResource.
|
||||
*/
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Tenant Management Resource")
|
||||
public class MgmtTenantManagementResourceTest extends AbstractManagementApiIntegrationTest {
|
||||
|
||||
private static final String KEY_MULTI_ASSIGNMENTS = "multi.assignments.enabled";
|
||||
|
||||
private static final String KEY_AUTO_CLOSE = "repository.actions.autoclose.enabled";
|
||||
private static final String ROLLOUT_APPROVAL_ENABLED = "rollout.approval.enabled";
|
||||
|
||||
private static final String AUTHENTICATION_GATEWAYTOKEN_ENABLED = "authentication.gatewaytoken.enabled";
|
||||
|
||||
private static final String AUTHENTICATION_GATEWAYTOKEN_KEY = "authentication.gatewaytoken.key";
|
||||
private static final String DEFAULT_DISTRIBUTION_SET_TYPE_KEY = "default.ds.type";
|
||||
|
||||
@Test
|
||||
@Description("Handles GET request for receiving all tenant specific configurations.")
|
||||
public void getTenantConfigurations() throws Exception {
|
||||
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs"))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
//check for TenantMetadata additional properties
|
||||
.andExpect(jsonPath("$.['" + DEFAULT_DISTRIBUTION_SET_TYPE_KEY + "']").exists())
|
||||
.andExpect(jsonPath("$.['" + DEFAULT_DISTRIBUTION_SET_TYPE_KEY + "'].value", equalTo(getActualDefaultDsType().intValue())));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles GET request for receiving a tenant specific configuration.")
|
||||
public void getTenantConfiguration() throws Exception {
|
||||
//Test TenantConfiguration property
|
||||
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
|
||||
TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles GET request for receiving (TenantMetadata - DefaultDsType) a tenant specific configuration.")
|
||||
public void getTenantMetadata() throws Exception {
|
||||
//Test TenantMetadata property
|
||||
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
|
||||
DEFAULT_DISTRIBUTION_SET_TYPE_KEY))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.value", equalTo(getActualDefaultDsType().intValue())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles PUT request for settings values in tenant specific configuration.")
|
||||
public void putTenantConfiguration() throws Exception {
|
||||
final MgmtSystemTenantConfigurationValueRequest bodyPut = new MgmtSystemTenantConfigurationValueRequest();
|
||||
bodyPut.setValue("exampleToken");
|
||||
final ObjectMapper mapper = new ObjectMapper();
|
||||
final String json = mapper.writeValueAsString(bodyPut);
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
|
||||
TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY).content(json)
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles PUT request for settings values (TenantMetadata - DefaultDsType) in tenant specific configuration, which is TenantMetadata")
|
||||
public void putTenantMetadata() throws Exception {
|
||||
final MgmtSystemTenantConfigurationValueRequest bodyPut = new MgmtSystemTenantConfigurationValueRequest();
|
||||
|
||||
long updatedTestDefaultDsType = createTestDistributionSetType();
|
||||
bodyPut.setValue(updatedTestDefaultDsType);
|
||||
|
||||
final ObjectMapper mapper = new ObjectMapper();
|
||||
final String json = mapper.writeValueAsString(bodyPut);
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
|
||||
DEFAULT_DISTRIBUTION_SET_TYPE_KEY).content(json)
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
//check if after Rest success, value is really changed in TenantMetadata
|
||||
assertEquals(updatedTestDefaultDsType, getActualDefaultDsType(),
|
||||
"Rest endpoint for updating the Default DistributionSetType completed successfully, but the actual value was not changed.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Update DefaultDistributionSetType Fails if given DistributionSetType ID does not exist.")
|
||||
public void putTenantMetadataFails() throws Exception {
|
||||
long oldDefaultDsType = getActualDefaultDsType();
|
||||
//try an invalid input
|
||||
String newDefaultDsType = new JSONObject().put("value", true).toString();
|
||||
assertDefaultDsTypeUpdateBadRequestFails(newDefaultDsType, oldDefaultDsType, status().isBadRequest());
|
||||
//try an invalid input
|
||||
newDefaultDsType = new JSONObject().put("value", "someInvalidInput").toString();
|
||||
assertDefaultDsTypeUpdateBadRequestFails(newDefaultDsType, oldDefaultDsType, status().isBadRequest());
|
||||
//try valid input, but the given DistributionSetType Id does not exist..
|
||||
newDefaultDsType = new JSONObject().put("value", 99999).toString();
|
||||
assertDefaultDsTypeUpdateBadRequestFails(newDefaultDsType, oldDefaultDsType, status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The 'multi.assignments.enabled' property must not be changed to false.")
|
||||
public void deactivateMultiAssignment() throws Exception {
|
||||
final String bodyActivate = new JSONObject().put("value", true).toString();
|
||||
final String bodyDeactivate = new JSONObject().put("value", false).toString();
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS)
|
||||
.content(bodyActivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS)
|
||||
.content(bodyDeactivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The Batch configuration should not be applied, because of invalid TenantConfiguration props")
|
||||
public void changeBatchConfigurationShouldFailOnInvalidTenantConfiguration() throws Exception {
|
||||
//in this scenario
|
||||
// some TenantConfiguration are not valid,
|
||||
// TenantMetadata - DefaultDSType ID is valid,
|
||||
//in the end batch configuration update must fail, and thus, not a single config should be actually changed
|
||||
long testValidDistributionSetType = createTestDistributionSetType();
|
||||
boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue();
|
||||
String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue();
|
||||
//test TenantConfiguration with invalid config value, and a valid TenantMetadata - Default DistributionSetType id
|
||||
assertBatchConfigurationFails(!oldRolloutApprovalConfig, "invalid-config-value", oldAuthGatewayToken + "randomSuffix0",
|
||||
testValidDistributionSetType, status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The Batch configuration should not be applied, because of invalid TenantMetadata (DefaultDistributionSetType)")
|
||||
public void changeBatchConfigurationShouldOnInvalidTenantMetadata() throws Exception {
|
||||
//in this scenario
|
||||
// all TenantConfiguration have valid and new values - using old values, inverted
|
||||
// TenantMetadata - DefaultDSType ID is invalid
|
||||
//in the end batch configuration update must fail, and thus, not a single config should be actually changed.
|
||||
boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue();
|
||||
boolean oldAuthGatewayTokenEnabled = (Boolean) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED)
|
||||
.getValue();
|
||||
String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue();
|
||||
|
||||
//invalid TenantMetadata Default DistributionSetType, it is expected to be a number. Testing invalid type - string
|
||||
//not a single configuration should be changed after the failure
|
||||
Object testInvalidDistributionSetType = "someInvalidInput";
|
||||
assertBatchConfigurationFails(!oldRolloutApprovalConfig, !oldAuthGatewayTokenEnabled, oldAuthGatewayToken + "randomSuffix1",
|
||||
testInvalidDistributionSetType, status().isBadRequest());
|
||||
|
||||
//invalid TenantMetadata Default DistributionSetType, it is expected to be a number. Testing invalid type - bool
|
||||
//not a single configuration should be changed after the failure
|
||||
testInvalidDistributionSetType = true;
|
||||
assertBatchConfigurationFails(!oldRolloutApprovalConfig, !oldAuthGatewayTokenEnabled, oldAuthGatewayToken + "randomSuffix2",
|
||||
testInvalidDistributionSetType, status().isBadRequest());
|
||||
|
||||
//Valid TenantMetadata Default DistributionSetType, it is expected to be a number. Testing valid type - but given DistributionSetType Id does not exist.
|
||||
//not a single configuration should be changed after the failure
|
||||
testInvalidDistributionSetType = 9999;
|
||||
assertBatchConfigurationFails(!oldRolloutApprovalConfig, !oldAuthGatewayTokenEnabled, oldAuthGatewayToken + "randomSuffix2",
|
||||
testInvalidDistributionSetType, status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The Batch configuration should be applied")
|
||||
public void changeBatchConfiguration() throws Exception {
|
||||
long updatedDistributionSetType = createTestDistributionSetType();
|
||||
boolean updatedRolloutApprovalEnabled = true;
|
||||
boolean updatedAuthGatewayTokenEnabled = true;
|
||||
String updatedAuthGatewayTokenKey = "54321";
|
||||
JSONObject configuration = new JSONObject();
|
||||
configuration.put(ROLLOUT_APPROVAL_ENABLED, updatedRolloutApprovalEnabled);
|
||||
configuration.put(AUTHENTICATION_GATEWAYTOKEN_ENABLED, updatedAuthGatewayTokenEnabled);
|
||||
configuration.put(AUTHENTICATION_GATEWAYTOKEN_KEY, updatedAuthGatewayTokenKey);
|
||||
configuration.put(DEFAULT_DISTRIBUTION_SET_TYPE_KEY, updatedDistributionSetType);
|
||||
|
||||
String body = configuration.toString();
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs")
|
||||
.content(body).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
//assert all changes were applied after Rest Success
|
||||
assertEquals(updatedDistributionSetType, getActualDefaultDsType(),
|
||||
"Change BatchConfiguration was successful but TenantMetadata - Default DistributionSetType was not actually changed.");
|
||||
assertEquals(updatedRolloutApprovalEnabled, tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(),
|
||||
"Change BatchConfiguration was successful but TenantConfiguration property was not actually changed.");
|
||||
assertEquals(updatedAuthGatewayTokenEnabled,
|
||||
tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED).getValue(),
|
||||
"Change BatchConfiguration was successful but TenantConfiguration property was not actually changed.");
|
||||
assertEquals(updatedAuthGatewayTokenKey,
|
||||
tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(),
|
||||
"Change BatchConfiguration was successful but TenantConfiguration property was not actually changed.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("The 'repository.actions.autoclose.enabled' property must not be modified if Multi-Assignments is enabled.")
|
||||
public void autoCloseCannotBeModifiedIfMultiAssignmentIsEnabled() throws Exception {
|
||||
final String bodyActivate = new JSONObject().put("value", true).toString();
|
||||
final String bodyDeactivate = new JSONObject().put("value", false).toString();
|
||||
|
||||
// enable Multi-Assignments
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS)
|
||||
.content(bodyActivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
|
||||
// try to enable Auto-Close
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_AUTO_CLOSE)
|
||||
.content(bodyActivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isForbidden());
|
||||
|
||||
// try to disable Auto-Close
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_AUTO_CLOSE)
|
||||
.content(bodyDeactivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles DELETE request deleting a tenant specific configuration.")
|
||||
public void deleteTenantConfiguration() throws Exception {
|
||||
mvc.perform(delete(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
|
||||
TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests DELETE request must Fail for TenantMetadata properties.")
|
||||
public void deleteTenantMetadataFail() throws Exception {
|
||||
mvc.perform(delete(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
|
||||
DEFAULT_DISTRIBUTION_SET_TYPE_KEY))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles GET request for receiving all tenant specific configurations depending on read gateway token permissions.")
|
||||
void getTenantConfigurationReadGWToken() throws Exception {
|
||||
SecurityContextSwitch.runAs(SecurityContextSwitch.withUser("tenant_admin", SpPermission.TENANT_CONFIGURATION), () -> {
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(
|
||||
TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY,
|
||||
"123");
|
||||
return null;
|
||||
});
|
||||
|
||||
// TODO - should be able to read with TENANT_CONFIGURATION but somehow here the role hierarchy doesn't play
|
||||
// checked in mgmt / update server runtime PreAuthorizeEnabledTest
|
||||
SecurityContextSwitch.runAs(
|
||||
SecurityContextSwitch.withUser("tenant_admin", SpPermission.READ_TENANT_CONFIGURATION, SpPermission.READ_GATEWAY_SEC_TOKEN),
|
||||
() -> {
|
||||
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs"))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andDo(m -> System.out.println("-> 1: " + m.getResponse().getContentAsString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "']").exists())
|
||||
.andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "'].value", equalTo("123")));
|
||||
return null;
|
||||
});
|
||||
|
||||
SecurityContextSwitch.runAs(SecurityContextSwitch.withUser("tenant_read", SpPermission.READ_TENANT_CONFIGURATION), () -> {
|
||||
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs"))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andDo(m -> System.out.println("-> 2: " + m.getResponse().getContentAsString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "']").doesNotExist());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private Long createTestDistributionSetType() {
|
||||
DistributionSetType testDefaultDsType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
|
||||
.key("test123").name("TestName123").description("TestDefaultDsType"));
|
||||
testDefaultDsType = distributionSetTypeManagement
|
||||
.update(entityFactory.distributionSetType().update(testDefaultDsType.getId()).description("TestDefaultDsType"));
|
||||
return testDefaultDsType.getId();
|
||||
}
|
||||
|
||||
private void assertDefaultDsTypeUpdateBadRequestFails(String newDefaultDsType, long oldDefaultDsType, ResultMatcher resultMatchers)
|
||||
throws Exception {
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
|
||||
DEFAULT_DISTRIBUTION_SET_TYPE_KEY).content(newDefaultDsType)
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(resultMatchers);
|
||||
assertEquals(oldDefaultDsType, getActualDefaultDsType(),
|
||||
"Rest endpoint for updating DefaultDistributionType failed, but actual value changed unexpectedly.");
|
||||
}
|
||||
|
||||
private void assertBatchConfigurationFails(Object newRolloutApprovalEnabled, Object newAuthGatewayTokenEnabled, Object newGatewayToken,
|
||||
Object newDistributionSetTypeId, ResultMatcher resultMatchers) throws Exception {
|
||||
long oldDefaultDsType = getActualDefaultDsType();
|
||||
boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue();
|
||||
boolean oldAuthGatewayTokenEnabled = (Boolean) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED)
|
||||
.getValue();
|
||||
String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue();
|
||||
|
||||
JSONObject configuration = new JSONObject();
|
||||
configuration.put(ROLLOUT_APPROVAL_ENABLED, newRolloutApprovalEnabled);
|
||||
configuration.put(AUTHENTICATION_GATEWAYTOKEN_ENABLED, newAuthGatewayTokenEnabled);
|
||||
configuration.put(AUTHENTICATION_GATEWAYTOKEN_KEY, newGatewayToken);
|
||||
configuration.put(DEFAULT_DISTRIBUTION_SET_TYPE_KEY, newDistributionSetTypeId);
|
||||
String body = configuration.toString();
|
||||
|
||||
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs")
|
||||
.content(body).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(resultMatchers);
|
||||
//Check if TenantMetadata and TenantConfiguration is not changed as Batch config failed
|
||||
assertEquals(oldDefaultDsType, getActualDefaultDsType(),
|
||||
"Batch configuration update Failed, but TenantMetadata - DistributionSetType was actually changed.");
|
||||
assertEquals(oldRolloutApprovalConfig, tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(),
|
||||
"Batch configuration update Failed, but TenantConfiguration was actually changed.");
|
||||
assertEquals(oldAuthGatewayTokenEnabled,
|
||||
tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED).getValue(),
|
||||
"Batch configuration update Failed, but TenantConfiguration was actually changed.");
|
||||
assertEquals(oldAuthGatewayToken, tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(),
|
||||
"Batch configuration update Failed, but TenantConfiguration was actually changed.");
|
||||
}
|
||||
|
||||
private Long getActualDefaultDsType() {
|
||||
return systemManagement.getTenantMetadata().getDefaultDsType().getId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
|
||||
/**
|
||||
* Utility additions for the REST API tests.
|
||||
*/
|
||||
public final class ResourceUtility {
|
||||
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public static ExceptionInfo convertException(final String jsonExceptionResponse)
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
return mapper.readValue(jsonExceptionResponse, ExceptionInfo.class);
|
||||
}
|
||||
|
||||
public static MgmtArtifact convertArtifactResponse(final String jsonResponse)
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
return mapper.readValue(jsonResponse, MgmtArtifact.class);
|
||||
|
||||
}
|
||||
|
||||
public static <T> PagedList<T> mapResponse(final Class<T> clazz, final String responseBody)
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
return mapper.readValue(responseBody, PagedList.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Story;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterSyntaxErrorException;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedDirectionException;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Sorting parameter")
|
||||
public class SortUtilityTest {
|
||||
|
||||
private static final String SORT_PARAM_1 = "NAME:ASC";
|
||||
private static final String SORT_PARAM_2 = "NAME:ASC, DESCRIPTION:DESC";
|
||||
private static final String SYNTAX_FAILURE_SORT_PARAM = "NAME:ASC DESCRIPTION:DESC";
|
||||
private static final String WRONG_DIRECTION_PARAM = "NAME:ASDF";
|
||||
private static final String CASE_INSENSITIVE_DIRECTION_PARAM = "NaME:ASC";
|
||||
private static final String CASE_INSENSITIVE_DIRECTION_PARAM_1 = "name:ASC";
|
||||
private static final String WRONG_FIELD_PARAM = "ASDF:ASC";
|
||||
|
||||
@Test
|
||||
@Description("Ascending sorting based on name.")
|
||||
public void parseSortParam1() {
|
||||
final List<Order> parse = SortUtility.parse(TargetFields.class, SORT_PARAM_1);
|
||||
assertThat(parse).as("Count of parsing parameter").hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ascending sorting based on name and descending sorting based on description.")
|
||||
public void parseSortParam2() {
|
||||
final List<Order> parse = SortUtility.parse(TargetFields.class, SORT_PARAM_2);
|
||||
assertThat(parse).as("Count of parsing parameter").hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Sorting with wrong syntax leads to SortParameterSyntaxErrorException.")
|
||||
public void parseWrongSyntaxParam() {
|
||||
assertThrows(SortParameterSyntaxErrorException.class,
|
||||
() -> SortUtility.parse(TargetFields.class, SYNTAX_FAILURE_SORT_PARAM));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Sorting based on name with case sensitive is possible.")
|
||||
public void parsingIsNotCaseSensitive() {
|
||||
SortUtility.parse(TargetFields.class, CASE_INSENSITIVE_DIRECTION_PARAM);
|
||||
SortUtility.parse(TargetFields.class, CASE_INSENSITIVE_DIRECTION_PARAM_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Sorting with unknown direction order leads to SortParameterUnsupportedDirectionException.")
|
||||
public void parseWrongDirectionParam() {
|
||||
assertThrows(SortParameterUnsupportedDirectionException.class,
|
||||
() -> SortUtility.parse(TargetFields.class, WRONG_DIRECTION_PARAM));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Sorting with unknown field leads to SortParameterUnsupportedFieldException.")
|
||||
public void parseWrongFieldParam() {
|
||||
assertThrows(SortParameterUnsupportedFieldException.class,
|
||||
() -> SortUtility.parse(TargetFields.class, WRONG_FIELD_PARAM));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# Copyright (c) 2018 Microsoft and others
|
||||
#
|
||||
# This program and the accompanying materials are made
|
||||
# available under the terms of the Eclipse Public License 2.0
|
||||
# which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
#
|
||||
# SPDX-License-Identifier: EPL-2.0
|
||||
#
|
||||
|
||||
# Logging START - activate to see request/response details
|
||||
#logging.level.org.eclipse.hawkbit.rest.util.MockMvcResultPrinter=DEBUG
|
||||
# Logging END
|
||||
|
||||
Reference in New Issue
Block a user