Feature/handle soft deleted type creation (#1335)
* Handle creation of entities from already marked as deleted types * Remove unused comment * Remove wildcard imports * Changes after comments Signed-off-by: Stanislav Trailov <stanislav.trailov@bosch.io>
This commit is contained in:
committed by
GitHub
parent
d567b32280
commit
5af1fa1e1c
@@ -8,14 +8,17 @@
|
||||
*/
|
||||
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 javax.validation.Valid;
|
||||
import javax.validation.ValidationException;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
|
||||
@@ -35,6 +38,7 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
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;
|
||||
@@ -45,6 +49,7 @@ 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.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
||||
@@ -87,6 +92,8 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
private final DistributionSetInvalidationManagement distributionSetInvalidationManagement;
|
||||
@@ -97,7 +104,7 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
||||
final TargetManagement targetManagement, final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final DeploymentManagement deployManagament, final SystemManagement systemManagement,
|
||||
final EntityFactory entityFactory, final DistributionSetManagement distributionSetManagement,
|
||||
final SystemSecurityContext systemSecurityContext,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final SystemSecurityContext systemSecurityContext,
|
||||
final DistributionSetInvalidationManagement distributionSetInvalidationManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
@@ -107,6 +114,7 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
||||
this.systemManagement = systemManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.distributionSetInvalidationManagement = distributionSetInvalidationManagement;
|
||||
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
|
||||
@@ -159,6 +167,18 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
||||
.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));
|
||||
|
||||
|
||||
@@ -10,8 +10,10 @@ 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 org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
|
||||
@@ -26,11 +28,13 @@ 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.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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -47,6 +51,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.validation.ValidationException;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link SoftwareModule} and related
|
||||
* {@link Artifact} CRUD operations.
|
||||
@@ -60,12 +66,15 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtSoftwareModuleResource(final ArtifactManagement artifactManagement,
|
||||
final SoftwareModuleManagement softwareModuleManagement, final EntityFactory entityFactory) {
|
||||
MgmtSoftwareModuleResource(final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareModuleManagement,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement, final EntityFactory entityFactory) {
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@@ -182,6 +191,17 @@ public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
@RequestBody final List<MgmtSoftwareModuleRequestBodyPost> softwareModules) {
|
||||
|
||||
LOG.debug("creating {} softwareModules", softwareModules.size());
|
||||
|
||||
for (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);
|
||||
|
||||
@@ -12,6 +12,8 @@ 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.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
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;
|
||||
@@ -26,6 +28,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
@@ -40,6 +43,7 @@ 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.DistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||
@@ -49,6 +53,7 @@ import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
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;
|
||||
@@ -70,6 +75,9 @@ import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
import io.qameta.allure.Step;
|
||||
import io.qameta.allure.Story;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
|
||||
@Feature("Component Tests - Management API")
|
||||
@Story("Distribution Set Resource")
|
||||
@@ -299,6 +307,44 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
|
||||
// we just need to make sure that no error 500 is returned
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Trying to create a DS from already marked as deleted type - should get as response 400 Bad Request")
|
||||
public void createDsFromAlreadyMarkedAsDeletedType() throws Exception {
|
||||
final SoftwareModule softwareModule = testdataFactory.createSoftwareModule("exampleKey");
|
||||
final DistributionSetType type = testdataFactory.findOrCreateDistributionSetType(
|
||||
"testKey", "testType", Collections.singletonList(softwareModule.getType()),
|
||||
Collections.singletonList(softwareModule.getType()));
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("dsName", "dsVersion", type, Collections.singletonList(softwareModule));
|
||||
final Target target = testdataFactory.createTarget("exampleControllerId");
|
||||
|
||||
assignDistributionSet(ds, target);
|
||||
|
||||
//soft delete ds type
|
||||
distributionSetTypeManagement.delete(type.getId());
|
||||
|
||||
// check if the ds type is marked as deleted
|
||||
final Optional<DistributionSetType> opt = distributionSetTypeManagement.getByKey(type.getKey());
|
||||
if (opt.isEmpty()) {
|
||||
throw new AssertionError("The Optional object of distribution set type should not be empty!");
|
||||
}
|
||||
final DistributionSetType reloaded = opt.get();
|
||||
Assert.isTrue(reloaded.isDeleted(), "Distribution Set Type not marked as deleted!");
|
||||
|
||||
//request for ds creation of type which is already marked as deleted - should return bad request
|
||||
final DistributionSet generated = testdataFactory.generateDistributionSet(
|
||||
"stanTest", "2", reloaded, Collections.singletonList(softwareModule));
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(post("/rest/v1/distributionsets/")
|
||||
.content(JsonBuilder.distributionSets(Arrays.asList(generated)))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isBadRequest()).andReturn();
|
||||
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertEquals("javax.validation.ValidationException", exceptionInfo.getExceptionClass());
|
||||
assertTrue(exceptionInfo.getMessage().contains("Distribution Set Type already deleted"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that multi target assignment is protected by our getMaxTargetDistributionSetAssignmentsPerManualAssignment quota.")
|
||||
public void assignMultipleTargetsToDistributionSetUntilQuotaIsExceeded() throws Exception {
|
||||
@@ -765,7 +811,6 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
|
||||
@Description("Ensures that multipe DS posted to API are created in the repository.")
|
||||
public void createDistributionSets() throws Exception {
|
||||
assertThat(distributionSetManagement.findByCompleted(PAGE, true)).hasSize(0);
|
||||
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_APP);
|
||||
final SoftwareModule jvm = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_RT);
|
||||
final SoftwareModule os = testdataFactory.createSoftwareModule(TestdataFactory.SM_TYPE_OS);
|
||||
|
||||
@@ -14,6 +14,7 @@ import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
@@ -31,6 +32,7 @@ import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -47,8 +49,11 @@ import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
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.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
|
||||
@@ -65,6 +70,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
@@ -350,6 +356,43 @@ class MgmtSoftwareModuleResourceTest extends AbstractManagementApiIntegrationTes
|
||||
assertThat(artifactManagement.getByFilename("customFilename")).as("Local artifact is wrong").isPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Trying to create a SM from already marked as deleted type - should get as response 400 Bad Request")
|
||||
public void createSMFromAlreadyMarkedAsDeletedType() throws Exception {
|
||||
final String SM_TYPE = "someSmType";
|
||||
final SoftwareModule sm = testdataFactory.createSoftwareModule(SM_TYPE);
|
||||
final DistributionSetType t = testdataFactory.findOrCreateDistributionSetType(
|
||||
"testKey", "testType", Collections.singletonList(sm.getType()),
|
||||
Collections.singletonList(sm.getType()));
|
||||
final DistributionSetType type = testdataFactory.findOrCreateDistributionSetType("testKey", "testType");
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("name", "version", type, Collections.singletonList(sm));
|
||||
final Target target = testdataFactory.createTarget("test");
|
||||
|
||||
assignDistributionSet(ds, target);
|
||||
//delete sm type
|
||||
softwareModuleTypeManagement.delete(sm.getType().getId());
|
||||
|
||||
//check if it is marked as deleted
|
||||
final Optional<SoftwareModuleType> opt = softwareModuleTypeManagement.getByKey(SM_TYPE);
|
||||
if (opt.isEmpty()) {
|
||||
throw new AssertionError("The Optional object of software module type should not be empty!");
|
||||
}
|
||||
final SoftwareModuleType smType = opt.get();
|
||||
Assert.isTrue(smType.isDeleted(), "Software Module Type not marked as deleted!");
|
||||
|
||||
//check if we'll get bad request if we try to create module from the deleted type
|
||||
final MvcResult mvcResult = mvc.perform(post("/rest/v1/softwaremodules")
|
||||
.content("[{\"description\":\"someDescription\",\"key\":\"someTestKey\", \"type\":\"" + SM_TYPE + "\"}]")
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(status().isBadRequest())
|
||||
.andReturn();
|
||||
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertEquals("javax.validation.ValidationException", exceptionInfo.getExceptionClass());
|
||||
assertTrue(exceptionInfo.getMessage().contains("Software Module Type already deleted"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the system refuses upload of an artifact where the provided hash sums do not match. Expected result: BAD REQUEST")
|
||||
void uploadArtifactWithHashCheck() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user