Ensure a '.' character is allowed to be used in target filter query for metadata key and attribute name (#1186)

* Adapted code to allow '.' inside of metadata key and attribute names


Signed-off-by: Markus Block <markus.block@bosch-si.com>

* added handling of corner cases

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Adapted metadata and attribute tests to check that dot is allowed

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed documentation

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Allow usage of dot in key names for every map attribute, e.g. also for
metadata in distribution set

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed typo

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* adapted test key to ensure a dot can be used

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed typo

Signed-off-by: Markus Block <markus.block@bosch-si.com>
This commit is contained in:
Markus Block
2021-10-18 10:51:04 +02:00
committed by GitHub
parent 998518d8e0
commit be3dfbf617
9 changed files with 138 additions and 33 deletions

View File

@@ -128,7 +128,8 @@ Custom target filter overview and filter management.
The basic syntax to filter is: `field<basic_operator>value <composite_operator> field<basic_operator>value <...>` The basic syntax to filter is: `field<basic_operator>value <composite_operator> field<basic_operator>value <...>`
- `field`: is the name of the resource field. - `field`: is the name of the resource field.
- `value`: is the value of the target field - `value`: is the expected value of the target field.
- Use `*` for wildcard matches.
- `<basic_operator>`: Are operators to do simple queries. Supported basic operators are: - `<basic_operator>`: Are operators to do simple queries. Supported basic operators are:
- `==` : equal - `==` : equal
- `!=` : not equal - `!=` : not equal
@@ -136,8 +137,6 @@ The basic syntax to filter is: `field<basic_operator>value <composite_operator>
- `<composite_operator>`: Are operators to join simple queries: Supported composite operators are: - `<composite_operator>`: Are operators to join simple queries: Supported composite operators are:
- `and` - `and`
- `or` - `or`
- Use `=IN=` for 'in' parameter.(Example: name=IN=(target1,target2).
- Use `*` for wildcard matches.
### Examples ### Examples

View File

@@ -14,6 +14,8 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Optional; import java.util.Optional;
import org.springframework.util.StringUtils;
/** /**
* An interface for declaring the name of the field described in the database * An interface for declaring the name of the field described in the database
* which is used as string representation of the field, e.g. for sorting the * which is used as string representation of the field, e.g. for sorting the
@@ -25,7 +27,7 @@ public interface FieldNameProvider {
/** /**
* Separator for the sub attributes * Separator for the sub attributes
*/ */
String SUB_ATTRIBUTE_SEPERATOR = "."; String SUB_ATTRIBUTE_SEPARATOR = ".";
/** /**
* @return the string representation of the underlying persistence field * @return the string representation of the underlying persistence field
@@ -33,6 +35,26 @@ public interface FieldNameProvider {
*/ */
String getFieldName(); String getFieldName();
/**
* Returns the sub attributes
*
* @param propertyFieldName
* the given field
* @return array consisting of sub attributes
*/
default String[] getSubAttributes(final String propertyFieldName) {
if (isMap()) {
final String[] subAttributes = propertyFieldName.split("\\" + SUB_ATTRIBUTE_SEPARATOR, 2);
// [0] fieldname |[1] keyname
final String mapKeyName = subAttributes.length == 2 ? subAttributes[1] : null;
if (StringUtils.isEmpty(mapKeyName)) {
return new String[] { getFieldName() };
}
return new String[] { getFieldName(), mapKeyName };
}
return propertyFieldName.split("\\" + SUB_ATTRIBUTE_SEPARATOR);
}
/** /**
* Contains the sub entity the given field. * Contains the sub entity the given field.
* *
@@ -47,7 +69,7 @@ public interface FieldNameProvider {
return true; return true;
} }
for (final String attribute : subEntityAttributes) { for (final String attribute : subEntityAttributes) {
final String[] graph = attribute.split("\\" + SUB_ATTRIBUTE_SEPERATOR); final String[] graph = attribute.split("\\" + SUB_ATTRIBUTE_SEPARATOR);
for (final String subAttribute : graph) { for (final String subAttribute : graph) {
if (subAttribute.equalsIgnoreCase(propertyField)) { if (subAttribute.equalsIgnoreCase(propertyField)) {
@@ -74,7 +96,7 @@ public interface FieldNameProvider {
} }
/** /**
* Is the entity field a {@link Map}. * Is the entity field a {@link Map} consisting of key-value pairs.
* *
* @return <code>true</code> is a map <code>false</code> is not a map * @return <code>true</code> is a map <code>false</code> is not a map
*/ */
@@ -84,7 +106,7 @@ public interface FieldNameProvider {
/** /**
* Returns the name of the field, that identifies the entity. * Returns the name of the field, that identifies the entity.
* *
* @return the name of the identifier, by default 'id' * @return the name of the identifier, by default 'id'
*/ */
default String identifierFieldName() { default String identifierFieldName() {

View File

@@ -135,4 +135,4 @@ public enum TargetFields implements FieldNameProvider {
public String getFieldName() { public String getFieldName() {
return fieldName; return fieldName;
} }
} }

View File

@@ -8,15 +8,16 @@
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql; package org.eclipse.hawkbit.repository.jpa.rsql;
import cz.jirutka.rsql.parser.ast.ComparisonNode; import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.FieldNameProvider; import org.eclipse.hawkbit.repository.FieldNameProvider;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Arrays; import cz.jirutka.rsql.parser.ast.ComparisonNode;
import java.util.List;
import java.util.stream.Collectors;
public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldNameProvider> { public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldNameProvider> {
@@ -30,7 +31,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
protected A getFieldEnumByName(final ComparisonNode node) { protected A getFieldEnumByName(final ComparisonNode node) {
String enumName = node.getSelector(); String enumName = node.getSelector();
final String[] graph = getSubAttributesFrom(enumName); final String[] graph = enumName.split("\\" + FieldNameProvider.SUB_ATTRIBUTE_SEPARATOR);
if (graph.length != 0) { if (graph.length != 0) {
enumName = graph[0]; enumName = graph[0];
} }
@@ -42,13 +43,9 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
} }
} }
protected static String[] getSubAttributesFrom(final String property) {
return property.split("\\" + FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR);
}
protected String getAndValidatePropertyFieldName(final A propertyEnum, final ComparisonNode node) { protected String getAndValidatePropertyFieldName(final A propertyEnum, final ComparisonNode node) {
final String[] graph = getSubAttributesFrom(node.getSelector()); final String[] graph = propertyEnum.getSubAttributes(node.getSelector());
validateMapParameter(propertyEnum, node, graph); validateMapParameter(propertyEnum, node, graph);
@@ -62,7 +59,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
for (int i = 1; i < graph.length; i++) { for (int i = 1; i < graph.length; i++) {
final String propertyField = graph[i]; final String propertyField = graph[i];
fieldNameBuilder.append(FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR).append(propertyField); fieldNameBuilder.append(FieldNameProvider.SUB_ATTRIBUTE_SEPARATOR).append(propertyField);
// the key of map is not in the graph // the key of map is not in the graph
if (propertyEnum.isMap() && graph.length == (i + 1)) { if (propertyEnum.isMap() && graph.length == (i + 1)) {
@@ -126,7 +123,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
final String enumFieldName = enumField.name().toLowerCase(); final String enumFieldName = enumField.name().toLowerCase();
if (enumField.isMap()) { if (enumField.isMap()) {
return enumFieldName + FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR + "keyName"; return enumFieldName + FieldNameProvider.SUB_ATTRIBUTE_SEPARATOR + "keyName";
} }
return enumFieldName; return enumFieldName;
@@ -136,7 +133,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
.filter(enumField -> !enumField.getSubEntityAttributes().isEmpty()).flatMap(enumField -> { .filter(enumField -> !enumField.getSubEntityAttributes().isEmpty()).flatMap(enumField -> {
final List<String> subEntity = enumField final List<String> subEntity = enumField
.getSubEntityAttributes().stream().map(fieldName -> enumField.name().toLowerCase() .getSubEntityAttributes().stream().map(fieldName -> enumField.name().toLowerCase()
+ FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR + fieldName) + FieldNameProvider.SUB_ATTRIBUTE_SEPARATOR + fieldName)
.collect(Collectors.toList()); .collect(Collectors.toList());
return subEntity.stream(); return subEntity.stream();

View File

@@ -15,9 +15,9 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -179,7 +179,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Path<Object> getFieldPath(final A enumField, final String finalProperty) { private Path<Object> getFieldPath(final A enumField, final String finalProperty) {
return (Path<Object>) getFieldPath(root, getSubAttributesFrom(finalProperty), enumField.isMap(), return (Path<Object>) getFieldPath(root, enumField.getSubAttributes(finalProperty), enumField.isMap(),
this::getJoinFieldPath).orElseThrow( this::getJoinFieldPath).orElseThrow(
() -> createRSQLParameterUnsupportedException("RSQL field path cannot be empty", null)); () -> createRSQLParameterUnsupportedException("RSQL field path cannot be empty", null));
} }
@@ -377,7 +377,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
private Predicate getOutPredicate(final List<Object> transformedValues, final String finalProperty, private Predicate getOutPredicate(final List<Object> transformedValues, final String finalProperty,
final A enumField, final Path<Object> fieldPath) { final A enumField, final Path<Object> fieldPath) {
final String[] fieldNames = getSubAttributesFrom(finalProperty); final String[] fieldNames = enumField.getSubAttributes(finalProperty);
final List<String> outParams = transformedValues.stream().filter(String.class::isInstance) final List<String> outParams = transformedValues.stream().filter(String.class::isInstance)
.map(String.class::cast).map(String::toUpperCase).collect(Collectors.toList()); .map(String.class::cast).map(String::toUpperCase).collect(Collectors.toList());
@@ -423,7 +423,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
return null; return null;
} }
final String[] graph = getSubAttributesFrom(node.getSelector()); final String[] graph = enumField.getSubAttributes(node.getSelector());
final String keyValue = graph[graph.length - 1]; final String keyValue = graph[graph.length - 1];
if (fieldPath instanceof MapJoin) { if (fieldPath instanceof MapJoin) {
@@ -469,7 +469,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
} }
final String sqlValue = toSQL((String) transformedValue); final String sqlValue = toSQL((String) transformedValue);
final String[] fieldNames = getSubAttributesFrom(finalProperty); final String[] fieldNames = enumField.getSubAttributes(finalProperty);
if (isSimpleField(fieldNames, enumField.isMap())) { if (isSimpleField(fieldNames, enumField.isMap())) {
return toNullOrNotLikePredicate(fieldPath, sqlValue); return toNullOrNotLikePredicate(fieldPath, sqlValue);

View File

@@ -9,12 +9,14 @@
package org.eclipse.hawkbit.repository.jpa.rsql; package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import java.util.Arrays; import java.util.Arrays;
import org.eclipse.hawkbit.repository.DistributionSetFields; import org.eclipse.hawkbit.repository.DistributionSetFields;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTag;
@@ -47,13 +49,13 @@ public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
ds2 = distributionSetManagement.update(entityFactory.distributionSet().update(ds2.getId()).description("DS%")); ds2 = distributionSetManagement.update(entityFactory.distributionSet().update(ds2.getId()).description("DS%"));
createDistributionSetMetadata(ds2.getId(), entityFactory.generateDsMetadata("metaKey", "value")); createDistributionSetMetadata(ds2.getId(), entityFactory.generateDsMetadata("metaKey", "value"));
final DistributionSetTag targetTag = distributionSetTagManagement final DistributionSetTag distSetTag = distributionSetTagManagement
.create(entityFactory.tag().create().name("Tag1")); .create(entityFactory.tag().create().name("Tag1"));
distributionSetTagManagement.create(entityFactory.tag().create().name("Tag2")); distributionSetTagManagement.create(entityFactory.tag().create().name("Tag2"));
distributionSetTagManagement.create(entityFactory.tag().create().name("Tag3")); distributionSetTagManagement.create(entityFactory.tag().create().name("Tag3"));
distributionSetTagManagement.create(entityFactory.tag().create().name("Tag4")); distributionSetTagManagement.create(entityFactory.tag().create().name("Tag4"));
distributionSetManagement.assignTag(Arrays.asList(ds.getId(), ds2.getId()), targetTag.getId()); distributionSetManagement.assignTag(Arrays.asList(ds.getId(), ds2.getId()), distSetTag.getId());
distributionSetManagement distributionSetManagement
.create(entityFactory.distributionSet().create().name("test123").version("noDescription")); .create(entityFactory.distributionSet().create().name("test123").version("noDescription"));
@@ -151,12 +153,27 @@ public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
@Test @Test
@Description("Test filter distribution set by metadata") @Description("Test filter distribution set by metadata")
public void testFilterByMetadata() { public void testFilterByMetadata() {
createDistributionSetWithMetadata("key.dot", "value.dot");
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==metaValue", 1); assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==metaValue", 1);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==*v*", 2); assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==*v*", 2);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==noExist*", 0); assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey==noExist*", 0);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1); assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1); assertRSQLQuery(DistributionSetFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".notExist==metaValue", 0); assertRSQLQuery(DistributionSetFields.METADATA.name() + ".notExist==metaValue", 0);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".key.dot==value.dot", 1);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".key.dot*==value.dot", 0);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".key.*==value.dot", 0);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".key.==value.dot", 0);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".key*==value.dot", 0);
assertRSQLQuery(DistributionSetFields.METADATA.name() + ".*==value.dot", 0);
assertRSQLQuery(DistributionSetFields.METADATA.name() + "..==value.dot", 0);
assertRSQLQueryThrowsException(DistributionSetFields.METADATA.name() + ".==value.dot",
RSQLParameterUnsupportedFieldException.class);
assertRSQLQueryThrowsException(DistributionSetFields.METADATA.name() + "*==value.dot",
RSQLParameterUnsupportedFieldException.class);
assertRSQLQueryThrowsException(DistributionSetFields.METADATA.name() + "==value.dot",
RSQLParameterUnsupportedFieldException.class);
} }
@@ -166,4 +183,19 @@ public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
assertThat(find).as("Founded entity is should not be null").isNotNull(); assertThat(find).as("Founded entity is should not be null").isNotNull();
assertThat(countAll).as("Founded entity size is wrong").isEqualTo(excpectedEntity); assertThat(countAll).as("Founded entity size is wrong").isEqualTo(excpectedEntity);
} }
private <T extends Throwable> void assertRSQLQueryThrowsException(final String rsqlParam,
final Class<T> expectedException) {
assertThatExceptionOfType(expectedException)
.isThrownBy(() -> RSQLUtility.validateRsqlFor(rsqlParam, DistributionSetFields.class));
}
private DistributionSet createDistributionSetWithMetadata(final String metadataKeyName,
final String metadataValue) {
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
createDistributionSetMetadata(distributionSet.getId(),
entityFactory.generateDsMetadata(metadataKeyName, metadataValue));
return distributionSet;
}
} }

View File

@@ -16,6 +16,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.assertj.core.util.Maps;
import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
@@ -148,12 +149,27 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
@Test @Test
@Description("Test filter target by attribute") @Description("Test filter target by attribute")
public void testFilterByAttribute() { public void testFilterByAttribute() {
createTargetWithAttributes("test.dot", "value.dot");
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1.1", 1); assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1.1", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision!=1.1", 1); assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision!=1.1", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1*", 2); assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1*", 2);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==noExist*", 0); assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==noExist*", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=in=(1.1,notexist)", 1); assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=in=(1.1,notexist)", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=out=(1.1)", 1); assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=out=(1.1)", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot==value.dot", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".key.dot*==value.dot", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".key.*==value.dot", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".key.==value.dot", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".key*==value.dot", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".*==value.dot", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + "..==value.dot", 0);
assertRSQLQueryThrowsException(TargetFields.ATTRIBUTE.name() + ".==value.dot",
RSQLParameterUnsupportedFieldException.class);
assertRSQLQueryThrowsException(TargetFields.ATTRIBUTE.name() + "*==value.dot",
RSQLParameterUnsupportedFieldException.class);
assertRSQLQueryThrowsException(TargetFields.ATTRIBUTE.name() + "==value.dot",
RSQLParameterUnsupportedFieldException.class);
} }
@Test @Test
@@ -214,6 +230,8 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
@Test @Test
@Description("Test filter target by metadata") @Description("Test filter target by metadata")
public void testFilterByMetadata() { public void testFilterByMetadata() {
createTargetWithMetadata("key.dot", "value.dot");
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==metaValue", 1); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==*v*", 2); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==*v*", 2);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 0); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 0);
@@ -223,6 +241,19 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=metaValue", 1); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0); assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2);
assertRSQLQuery(TargetFields.METADATA.name() + ".key.dot==value.dot", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".key.dot*==value.dot", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".key.*==value.dot", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".key.==value.dot", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".key*==value.dot", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".*==value.dot", 0);
assertRSQLQuery(TargetFields.METADATA.name() + "..==value.dot", 0);
assertRSQLQueryThrowsException(TargetFields.METADATA.name() + ".==value.dot",
RSQLParameterUnsupportedFieldException.class);
assertRSQLQueryThrowsException(TargetFields.METADATA.name() + "*==value.dot",
RSQLParameterUnsupportedFieldException.class);
assertRSQLQueryThrowsException(TargetFields.METADATA.name() + "==value.dot",
RSQLParameterUnsupportedFieldException.class);
} }
@Test @Test
@@ -259,6 +290,10 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
final String rsql5 = "wrongfield == abcd"; final String rsql5 = "wrongfield == abcd";
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class) assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> RSQLUtility.validateRsqlFor(rsql5, TargetFields.class)); .isThrownBy(() -> RSQLUtility.validateRsqlFor(rsql5, TargetFields.class));
final String rsql6 = "ATTRIBUTE.test.dot == test and ATTRIBUTE.subkey2 == test"
+ " and METADATA.test.dot == abcd and METADATA.metavalue2 == asdfg";
RSQLUtility.validateRsqlFor(rsql6, TargetFields.class);
} }
private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) { private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) {
@@ -267,4 +302,24 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertThat(findTargetPage).isNotNull(); assertThat(findTargetPage).isNotNull();
assertThat(countTargetsAll).isEqualTo(expcetedTargets); assertThat(countTargetsAll).isEqualTo(expcetedTargets);
} }
private <T extends Throwable> void assertRSQLQueryThrowsException(final String rsqlParam,
final Class<T> expectedException) {
assertThatExceptionOfType(expectedException)
.isThrownBy(() -> RSQLUtility.validateRsqlFor(rsqlParam, TargetFields.class));
}
private Target createTargetWithMetadata(final String metadataKeyName, final String metadataValue) {
final Target target = testdataFactory.createTarget();
createTargetMetadata(target.getControllerId(),
entityFactory.generateTargetMetadata(metadataKeyName, metadataValue));
return target;
}
private Target createTargetWithAttributes(final String attributeName, final String attributeValue) {
final Target target = testdataFactory.createTarget();
controllerManagement.updateControllerAttributes(target.getControllerId(),
Maps.newHashMap(attributeName, attributeValue), null);
return target;
}
} }

View File

@@ -1025,7 +1025,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
public void createMetadata() throws Exception { public void createMetadata() throws Exception {
final DistributionSet testDS = testdataFactory.createDistributionSet("one"); final DistributionSet testDS = testdataFactory.createDistributionSet("one");
final String knownKey1 = "knownKey1"; final String knownKey1 = "known.key.1.1";
final String knownKey2 = "knownKey2"; final String knownKey2 = "knownKey2";
final String knownValue1 = "knownValue1"; final String knownValue1 = "knownValue1";

View File

@@ -9,8 +9,8 @@
package org.eclipse.hawkbit.mgmt.rest.resource; package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItem;
@@ -1611,8 +1611,8 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
// create target with attributes // create target with attributes
final String knownTargetId = "targetIdNeedsUpdate"; final String knownTargetId = "targetIdNeedsUpdate";
final Map<String, String> knownControllerAttrs = new HashMap<>(); final Map<String, String> knownControllerAttrs = new HashMap<>();
knownControllerAttrs.put("a", "1"); knownControllerAttrs.put("a.1", "1");
knownControllerAttrs.put("b", "2"); knownControllerAttrs.put("b.2", "2");
testdataFactory.createTarget(knownTargetId); testdataFactory.createTarget(knownTargetId);
controllerManagement.updateControllerAttributes(knownTargetId, knownControllerAttrs, null); controllerManagement.updateControllerAttributes(knownTargetId, knownControllerAttrs, null);
assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isFalse(); assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isFalse();
@@ -1721,7 +1721,7 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
final String knownControllerId = "targetIdWithMetadata"; final String knownControllerId = "targetIdWithMetadata";
testdataFactory.createTarget(knownControllerId); testdataFactory.createTarget(knownControllerId);
final String knownKey1 = "knownKey1"; final String knownKey1 = "known.key.1";
final String knownKey2 = "knownKey2"; final String knownKey2 = "knownKey2";
final String knownValue1 = "knownValue1"; final String knownValue1 = "knownValue1";