Additional tag filtering by target ID and Distribution Set ID

Additional tag filtering by target ID and Distribution Set ID
This commit is contained in:
Stanislav Trailov
2023-06-29 15:23:57 +03:00
committed by GitHub
7 changed files with 275 additions and 3 deletions

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2023 Bosch.IO GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Describing the fields of the Tag model which can be used in the REST API e.g.
* for sorting etc.
* Additionally here were added fields for DistributionSet in order
* filtering over distribution set fields also.
*/
public enum DistributionSetTagFields implements FieldNameProvider {
/**
* The id field.
*/
ID(TagFields.ID.getFieldName()),
/**
* The name field.
*/
NAME(TagFields.NAME.getFieldName()),
/**
* The description field.
*/
DESCRIPTION(TagFields.DESCRIPTION.getFieldName()),
/**
* The controllerId field.
*/
COLOUR(TagFields.COLOUR.getFieldName()),
/**
* Distribution set fields
*/
DISTRIBUTIONSET("assignedToDistributionSet",
DistributionSetFields.ID.getFieldName(), DistributionSetFields.NAME.getFieldName());
private final String fieldName;
private final List<String> subEntityAttributes;
private DistributionSetTagFields(final String fieldName) {
this.fieldName = fieldName;
this.subEntityAttributes = Collections.emptyList();
}
private DistributionSetTagFields(final String fieldName, final String... subEntityAttributes) {
this.fieldName = fieldName;
this.subEntityAttributes = Arrays.asList(subEntityAttributes);
}
@Override
public List<String> getSubEntityAttributes() {
return Collections.unmodifiableList(subEntityAttributes);
}
@Override
public String getFieldName() {
return fieldName;
}
}

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2023 Bosch.IO GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Describing the fields of the Tag model which can be used in the REST API e.g.
* for sorting etc.
* Additionally here were added fields for Target in order
* filtering over target fields also.
*/
public enum TargetTagFields implements FieldNameProvider {
/**
* The id field.
*/
ID(TagFields.ID.getFieldName()),
/**
* The name field.
*/
NAME(TagFields.NAME.getFieldName()),
/**
* The description field.
*/
DESCRIPTION(TagFields.DESCRIPTION.getFieldName()),
/**
* The controllerId field.
*/
COLOUR(TagFields.COLOUR.getFieldName()),
/**
* Target fields
*/
TARGET("assignedToTargets",
TargetFields.ID.getFieldName(), TargetFields.NAME.getFieldName());
private final String fieldName;
private final List<String> subEntityAttributes;
private TargetTagFields(final String fieldName) {
this.fieldName = fieldName;
this.subEntityAttributes = Collections.emptyList();
}
private TargetTagFields(final String fieldName, final String... subEntityAttributes) {
this.fieldName = fieldName;
this.subEntityAttributes = Arrays.asList(subEntityAttributes);
}
@Override
public List<String> getSubEntityAttributes() {
return Collections.unmodifiableList(subEntityAttributes);
}
@Override
public String getFieldName() {
return fieldName;
}
}

View File

@@ -14,6 +14,7 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.DistributionSetTagFields;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.TagFields;
import org.eclipse.hawkbit.repository.TargetTagManagement;
@@ -129,7 +130,7 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
@Override
public Page<DistributionSetTag> findByRsql(final Pageable pageable, final String rsqlParam) {
final Specification<JpaDistributionSetTag> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, TagFields.class,
final Specification<JpaDistributionSetTag> spec = RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTagFields.class,
virtualPropertyReplacer, database);
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, pageable,

View File

@@ -15,6 +15,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.TagFields;
import org.eclipse.hawkbit.repository.TargetTagFields;
import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.builder.GenericTagUpdate;
import org.eclipse.hawkbit.repository.builder.TagCreate;
@@ -105,7 +106,7 @@ public class JpaTargetTagManagement implements TargetTagManagement {
@Override
public Page<TargetTag> findByRsql(final Pageable pageable, final String rsqlParam) {
return JpaManagementHelper.findAllWithCountBySpec(targetTagRepository, pageable, Collections.singletonList(
RSQLUtility.buildRsqlSpecification(rsqlParam, TagFields.class, virtualPropertyReplacer, database)));
RSQLUtility.buildRsqlSpecification(rsqlParam, TargetTagFields.class, virtualPropertyReplacer, database)));
}
@Override

View File

@@ -33,7 +33,6 @@ import org.eclipse.hawkbit.utils.TenantConfigHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
@@ -86,6 +85,7 @@ public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
} else {
findTargetsAll = this.tagManagement.findByRsql(pageable, rsqlParam);
}
final List<MgmtTag> rest = MgmtTagMapper.toResponse(findTargetsAll.getContent());

View File

@@ -73,6 +73,70 @@ public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiInt
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
}
@Test
@Description("Verfies 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.toggleTagAssignment(List.of(distributionSet1.getId(), distributionSet2.getId()), tag1.getName());
distributionSetManagement.toggleTagAssignment(List.of(distributionSet1.getId()), tag2.getName());
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.toggleTagAssignment(List.of(distributionSet1.getId(), distributionSet2.getId()), tag1.getName());
distributionSetManagement.toggleTagAssignment(List.of(distributionSet1.getId()), tag2.getName());
// 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) })

View File

@@ -75,6 +75,74 @@ public class MgmtTargetTagResourceTest extends AbstractManagementApiIntegrationT
}
@Test
@Description("Verfies that a paged result list of target tags reflects on the content of assigned tags for specific controller/target ID")
public void getTargetTagsByTargetId() 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.toggleTagAssignment(List.of(controllerId1, controllerId2), tag1.getName());
targetManagement.toggleTagAssignment(List.of(controllerId2), tag2.getName());
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING)
.queryParam(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "target.controllerId==" + controllerId2)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(applyTagMatcherOnPagedResult(tag1))
.andExpect(applyTagMatcherOnPagedResult(tag2))
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, TARGETTAGS_ROOT + tag1.getId()))
.andExpect(applySelfLinkMatcherOnPagedResult(tag2, TARGETTAGS_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.TARGET_TAG_V1_REQUEST_MAPPING)
.queryParam(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "target.controllerId==" + controllerId1)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(applyTagMatcherOnPagedResult(tag1))
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, TARGETTAGS_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("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 getTargetTagsFilteredByColorAndTargetId() 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.toggleTagAssignment(List.of(controllerId1, controllerId2), tag1.getName());
targetManagement.toggleTagAssignment(List.of(controllerId2), tag2.getName());
// 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 + "=target.controllerId==" + controllerId2 + ";colour==" + tag1.getColour())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(applyTagMatcherOnPagedResult(tag1))
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, TARGETTAGS_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 target tag reflects the content on the repository side.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 2) })