From 707df1abd9f6920f65c0083731aa278038f31cb7 Mon Sep 17 00:00:00 2001 From: Avgustin Marinov Date: Thu, 17 Oct 2024 17:06:08 +0300 Subject: [PATCH] Add notFound suppor (& test) for assign REST (#1902) Signed-off-by: Marinov Avgustin --- .../exception/EntityNotFoundException.java | 12 +++-- .../DistributionSetTagManagementTest.java | 4 +- .../management/TargetTagManagementTest.java | 4 +- .../mgmt/rest/api/MgmtTargetTagRestApi.java | 3 ++ .../MgmtDistributionSetTagResourceTest.java | 27 +++++----- .../resource/MgmtTargetTagResourceTest.java | 49 ++++++++++++++++++- 6 files changed, 76 insertions(+), 23 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java index 68a21e211..711f1d478 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/exception/EntityNotFoundException.java @@ -101,7 +101,7 @@ public class EntityNotFoundException extends AbstractServerRtException { * @param key for the {@link MetaData} entry */ public EntityNotFoundException(final Class type, final String entityId, final String key) { - super(type.getSimpleName() + " for given entity {" + entityId + "} and with key {" + key + "} does not exist.", + super(type.getSimpleName() + " for given entity {" + toEntityString(entityId) + "} and with key {" + key + "} does not exist.", THIS_ERROR, Map.of(TYPE, type.getSimpleName(), ENTITY_ID, entityId, KEY, key)); } @@ -115,9 +115,15 @@ public class EntityNotFoundException extends AbstractServerRtException { */ public EntityNotFoundException(final Class type, final Collection expected, final Collection found) { - super(type.getSimpleName() + "s with given identifiers {" + expected.stream().filter(id -> !found.contains(id)) - .map(String::valueOf).collect(Collectors.joining(",")) + "} do not exist.", + super(type.getSimpleName() + "s with given identifiers {" + toEntityString(expected.stream().filter(id -> !found.contains(id)) + .map(String::valueOf).collect(Collectors.joining(","))) + "} do not exist.", THIS_ERROR, Map.of(TYPE, type.getSimpleName(), ENTITY_ID, expected.stream().filter(id -> !found.contains(id)).map(String::valueOf))); } + + private static final int ENTITY_STRING_MAX_LENGTH = 100; + private static String toEntityString(final Object obj) { + final String str = String.valueOf(obj); + return str.length() > ENTITY_STRING_MAX_LENGTH ? str.substring(0, ENTITY_STRING_MAX_LENGTH - 3).concat("...") : str; + } } \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DistributionSetTagManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DistributionSetTagManagementTest.java index a4025868f..dbff3fb4e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DistributionSetTagManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/DistributionSetTagManagementTest.java @@ -206,8 +206,8 @@ public class DistributionSetTagManagementTest extends AbstractJpaIntegrationTest assertThatThrownBy(() -> distributionSetManagement.assignTag(withMissing, tag.getId())) .matches(e -> { if (e instanceof EntityNotFoundException enfe) { - if (enfe.getType().equals(DistributionSet.class)) { - if (enfe.getEntityId() instanceof Collection entityId) { + if (enfe.getInfo().get(EntityNotFoundException.TYPE).equals(DistributionSet.class.getSimpleName())) { + if (enfe.getInfo().get(EntityNotFoundException.ENTITY_ID) instanceof Collection entityId) { return entityId.stream().sorted().toList().equals(missing); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetTagManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetTagManagementTest.java index 743a90d08..39698de2f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetTagManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/management/TargetTagManagementTest.java @@ -202,8 +202,8 @@ class TargetTagManagementTest extends AbstractJpaIntegrationTest { assertThatThrownBy(() -> targetManagement.assignTag(withMissing, tag.getId())) .matches(e -> { if (e instanceof EntityNotFoundException enfe) { - if (enfe.getType().equals(Target.class)) { - if (enfe.getEntityId() instanceof Collection entityId) { + if (enfe.getInfo().get(EntityNotFoundException.TYPE).equals(Target.class.getSimpleName())) { + if (enfe.getInfo().get(EntityNotFoundException.TYPE) instanceof Collection entityId) { return entityId.stream().sorted().toList().equals(missing); } } diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java index d6fc90e94..5e03a530b 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtTargetTagRestApi.java @@ -335,6 +335,9 @@ public interface MgmtTargetTagRestApi { @ApiResponse(responseCode = "401", description = "The request requires user authentication."), @ApiResponse(responseCode = "403", description = "Insufficient permissions, entity is not allowed to be " + "changed (i.e. read-only) or data volume restriction applies."), + @ApiResponse(responseCode = "404", description = "Not Found - e.g. target tag not found. If targets not found - " + + "the body contains a list of ", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource."), @ApiResponse(responseCode = "406", description = "In case accept header is specified and not application/json."), @ApiResponse(responseCode = "409", description = "E.g. in case an entity is created or modified by another " + diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResourceTest.java index 94e2d280d..dfef6d360 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResourceTest.java @@ -348,10 +348,9 @@ public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiInt 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()); + mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/" + + set.getId())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); final List updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent(); assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList())) @@ -368,11 +367,10 @@ public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiInt final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0); final List 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)) + 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 updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent(); @@ -395,7 +393,8 @@ public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiInt 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()); + unassigned.getId())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); final List updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent(); assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList())) @@ -417,11 +416,9 @@ public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiInt 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)) + 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 updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent(); diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResourceTest.java index e2fa9d1ce..cb9cf405b 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetTagResourceTest.java @@ -20,9 +20,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. 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 org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; @@ -31,11 +35,14 @@ 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.jpa.model.JpaTarget; 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; @@ -300,6 +307,45 @@ public class MgmtTargetTagResourceTest extends AbstractManagementApiIntegrationT .containsOnly(assigned0.getControllerId(), assigned1.getControllerId()); } + private static final Random RND = new Random(); + @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 targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList(); + final List missing = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + while (true) { + final String id = String.valueOf(RND.nextLong()); + if (!targets.contains(id)) { + missing.add(id); + break; + } + } + } + Collections.sort(missing); + final List 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 info = exceptionInfo.getInfo(); + assertThat(info).isNotNull(); + assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName()); + final List notFound = (List) info.get(EntityNotFoundException.ENTITY_ID); + Collections.sort(notFound); + assertThat(notFound).isEqualTo(missing); + }); + } + @Test @Description("Verifies that tag unassignments done through tag API command are correctly stored in the repository.") @ExpectEvents({ @@ -315,7 +361,8 @@ public class MgmtTargetTagResourceTest extends AbstractManagementApiIntegrationT 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()); + unassigned.getControllerId())) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); final List updated = targetManagement.findByTag(PAGE, tag.getId()).getContent(); assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))