[#2176] RSQL filtering with exist/not-exist support (#2396)

* [#2176] RSQL filtering with exist/not-exist support

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>

* [#2176] Big Refactoring

* RSQL: all maps with joins with on

---------

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-05-16 16:13:04 +03:00
committed by GitHub
parent c0e89fbbee
commit 12140e468d
24 changed files with 518 additions and 616 deletions

View File

@@ -15,6 +15,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.util.Arrays;
import java.util.Collections;
import jakarta.persistence.EntityManager;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
@@ -23,20 +25,29 @@ import org.eclipse.hawkbit.repository.SoftwareModuleFields;
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.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.orm.jpa.vendor.Database;
@Feature("Component Tests - Repository")
@Story("RSQL filter distribution set")
@SuppressWarnings("java:S6813") // constructor injects are not possible for test classes
class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
@Autowired
protected VirtualPropertyReplacer virtualPropertyReplacer;
@Autowired
protected EntityManager entityManager;
private DistributionSet ds;
private SoftwareModule sm;
@@ -190,11 +201,14 @@ class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
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",
assertRSQLQueryThrowsException(
DistributionSetFields.METADATA.name() + ".==value.dot",
RSQLParameterUnsupportedFieldException.class);
assertRSQLQueryThrowsException(DistributionSetFields.METADATA.name() + "*==value.dot",
assertRSQLQueryThrowsException(
DistributionSetFields.METADATA.name() + "*==value.dot",
RSQLParameterUnsupportedFieldException.class);
assertRSQLQueryThrowsException(DistributionSetFields.METADATA.name() + "==value.dot",
assertRSQLQueryThrowsException(
DistributionSetFields.METADATA.name() + "==value.dot",
RSQLParameterUnsupportedFieldException.class);
}
@@ -206,18 +220,15 @@ class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
assertThat(countAll).as("Found entity size is wrong").isEqualTo(expectedEntity);
}
private <T extends Throwable> void assertRSQLQueryThrowsException(final String rsqlParam,
final Class<T> expectedException) {
private <T extends Throwable> void assertRSQLQueryThrowsException(final String rsqlParam, final Class<T> expectedException) {
assertThatExceptionOfType(expectedException)
.isThrownBy(() -> RSQLUtility.validateRsqlFor(rsqlParam, DistributionSetFields.class));
.isThrownBy(() -> RSQLUtility.validateRsqlFor(
rsqlParam, DistributionSetFields.class, JpaDistributionSet.class, virtualPropertyReplacer, entityManager));
}
private DistributionSet createDistributionSetWithMetadata(final String metadataKeyName,
final String metadataValue) {
private DistributionSet createDistributionSetWithMetadata(final String metadataKeyName, final String metadataValue) {
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
createDistributionSetMetadata(distributionSet.getId(),
entityFactory.generateDsMetadata(metadataKeyName, metadataValue));
createDistributionSetMetadata(distributionSet.getId(), entityFactory.generateDsMetadata(metadataKeyName, metadataValue));
return distributionSet;
}
}
}

View File

@@ -11,35 +11,44 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
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 java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import jakarta.persistence.EntityManager;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.assertj.core.util.Maps;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TargetTypeFields;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Slice;
@Feature("Component Tests - Repository")
@Story("RSQL filter target")
@SuppressWarnings("java:S6813") // constructor injects are not possible for test classes
class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
private static final String OR = ",";
private static final String AND = ";";
@Autowired
protected VirtualPropertyReplacer virtualPropertyReplacer;
@Autowired
protected EntityManager entityManager;
private Target target;
private Target target2;
private TargetType targetType1;
@@ -47,45 +56,6 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
@BeforeEach
void setupBeforeTest() {
final DistributionSet ds = testdataFactory.createDistributionSet("AssignedDs");
final Map<String, String> attributes = new HashMap<>();
target = targetManagement.create(entityFactory.target().create().controllerId("targetId123")
.name("targetName123").description("targetDesc123"));
attributes.put("revision", "1.1");
target = controllerManagement.updateControllerAttributes(target.getControllerId(), attributes, null);
target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(target.getControllerId(), LOCALHOST);
createTargetMetadata(target.getControllerId(), entityFactory.generateTargetMetadata("metaKey", "metaValue"));
target2 = targetManagement
.create(entityFactory.target().create().controllerId("targetId1234").description("targetId1234"));
attributes.put("revision", "1.2");
target2 = controllerManagement.updateControllerAttributes(target2.getControllerId(), attributes, null);
target2 = controllerManagement.findOrRegisterTargetIfItDoesNotExist(target2.getControllerId(), LOCALHOST);
createTargetMetadata(target2.getControllerId(), entityFactory.generateTargetMetadata("metaKey", "value"));
final Target target3 = testdataFactory.createTarget("targetId1235");
final Target target4 = testdataFactory.createTarget("targetId1236");
testdataFactory.createTarget("targetId1237");
final TargetTag targetTag = targetTagManagement.create(entityFactory.tag().create().name("Tag1"));
final TargetTag targetTag2 = targetTagManagement.create(entityFactory.tag().create().name("Tag2"));
final TargetTag targetTag3 = targetTagManagement.create(entityFactory.tag().create().name("Tag3"));
targetTagManagement.create(entityFactory.tag().create().name("Tag4"));
targetManagement.assignTag(Arrays.asList(target.getControllerId(), target2.getControllerId()),
targetTag.getId());
targetManagement.assignTag(Arrays.asList(target3.getControllerId(), target4.getControllerId()),
targetTag2.getId());
targetManagement.assignTag(
Arrays.asList(target.getControllerId(), target3.getControllerId(), target4.getControllerId()),
targetTag3.getId());
assignDistributionSet(ds.getId(), target.getControllerId());
targetType1 = targetTypeManagement
.create(entityFactory.targetType().create()
.name("Type1").description("Desc. Type1")
@@ -95,8 +65,43 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
.name("Type2").description("Desc. Type2")
.key("Type2.key"));
final DistributionSet ds = testdataFactory.createDistributionSet("AssignedDs");
final TargetTag targetTag = targetTagManagement.create(entityFactory.tag().create().name("Tag1"));
final TargetTag targetTag2 = targetTagManagement.create(entityFactory.tag().create().name("Tag2"));
final TargetTag targetTag3 = targetTagManagement.create(entityFactory.tag().create().name("Tag3"));
targetTagManagement.create(entityFactory.tag().create().name("Tag4"));
target = targetManagement.create(
entityFactory.target().create()
.controllerId("targetId123")
.name("targetName123")
.description("targetDesc123"));
target = controllerManagement.updateControllerAttributes(target.getControllerId(), Map.of("revision", "1.1"), null);
target = controllerManagement.findOrRegisterTargetIfItDoesNotExist(target.getControllerId(), LOCALHOST);
createTargetMetadata(target.getControllerId(), entityFactory.generateTargetMetadata("metaKey", "metaValue"));
assignDistributionSet(ds.getId(), target.getControllerId());
targetManagement.assignType(target.getControllerId(), targetType1.getId());
target2 = targetManagement.create(
entityFactory.target().create()
.controllerId("targetId1234")
.description("targetId1234"));
target2 = controllerManagement.updateControllerAttributes(target2.getControllerId(), Map.of("revision", "1.2"), null);
targetManagement.assignType(target2.getControllerId(), targetType2.getId());
createTargetMetadata(target2.getControllerId(), entityFactory.generateTargetMetadata("metaKey", "value"));
target2 = controllerManagement.findOrRegisterTargetIfItDoesNotExist(target2.getControllerId(), LOCALHOST);
targetManagement.assignTag(Arrays.asList(target.getControllerId(), target2.getControllerId()), targetTag.getId());
final Target target3 = testdataFactory.createTarget("targetId1235");
final Target target4 = testdataFactory.createTarget("targetId1236");
testdataFactory.createTarget("targetId1237");
targetManagement.assignTag(Arrays.asList(target3.getControllerId(), target4.getControllerId()), targetTag2.getId());
targetManagement.assignTag(
Arrays.asList(target.getControllerId(), target3.getControllerId(), target4.getControllerId()),
targetTag3.getId());
}
@Test
@@ -159,8 +164,38 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
@Test
@Description("Test filter target by attribute")
void testFilterByAttribute() {
controllerManagement.updateControllerAttributes(testdataFactory.createTarget().getControllerId(),
Maps.newHashMap("test.dot", "value.dot"), null);
controllerManagement.updateControllerAttributes(
testdataFactory.createTarget().getControllerId(),
Map.of(
"test.dot", "value.dot",
"test.null", "null"),
null);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot>=value.dos", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot==value.dot", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null==null", 1); // "null" check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a==null", 0); // "null" check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=is=value.dot", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=is=null", 5); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=is=null", 1 + 5); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=eq=value.dot", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=eq=null", 5); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=eq=null", 1 + 5); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot!=value.dot", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null!=null", 0); // "null" check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null!=null2", 1); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a!=null", 0); // "null" check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=not=value.dot", 5);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null", 1); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null2", 1 + 5); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=not=null", 0); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=ne=value.dot", 5);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null", 1); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null2", 1 + 5); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=ne=null", 0); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1.1", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision!=1.1", 1);
@@ -168,7 +203,6 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==noExist*", 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision=in=(1.1,notexist)", 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);
@@ -196,10 +230,8 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==" + TestdataFactory.DEFAULT_VERSION, 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==*1*", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version==noExist*", 0);
assertRSQLQuery(
TargetFields.ASSIGNEDDS.name() + ".version=in=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 1);
assertRSQLQuery(
TargetFields.ASSIGNEDDS.name() + ".version=out=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 4);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version=in=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".version=out=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 4);
}
@Test
@@ -238,18 +270,41 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
@Test
@Description("Test filter target by metadata")
void testFilterByMetadata() {
createTargetMetadata(testdataFactory.createTarget().getControllerId(),
entityFactory.generateTargetMetadata("key.dot", "value.dot"));
createTargetMetadata(testdataFactory.createTarget().getControllerId(), entityFactory.generateTargetMetadata("key.dot", "value.dot"));
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==null", 0); // "null" check
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==*v*", 2);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist==metaValue", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=null", 4); // null check (1 of the initial five has)
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=*v*", 2);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=noExist*", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist=is=null", 1 + 5); // null check
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=eq=metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=eq=null", 4); // null check (1 of the initial five has)
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=eq=*v*", 2);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=eq=noExist*", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist=eq=null", 1 + 5); // null check
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=null", 2);
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2);
//
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=metaValue", 1 + 4);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=null", 2); // null check (2 of the initial five)
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist=not=metaValue", 1 + 5);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=notExist", 1 + 5);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=metaValue", 1 + 4);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=null", 2); // null check (2 of the initial five)
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist=ne=metaValue", 1 + 5);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=notExist", 1 + 5);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
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);
@@ -265,41 +320,37 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
@Test
@Description("Test filter based on more complex RSQL queries")
void testFilterByComplexQueries() {
assertRSQLQuery(TargetFields.NAME.name() + "!=targetName123" + AND + TargetFields.METADATA.name() + ".metaKey!=value", 0);
assertRSQLQuery(
TargetFields.NAME.name() + "!=targetName123" + AND + TargetFields.METADATA.name() + ".metaKey!=value",
0);
assertRSQLQuery("(" + TargetFields.TAG.name() + "!=TAG1" + OR + TargetFields.TAG.name() + "!=TAG2)" + AND
+ TargetFields.CONTROLLERID.name() + "!=targetId1235", 4);
"(" + TargetFields.TAG.name() + "!=TAG1" + OR + TargetFields.TAG.name() + "!=TAG2)" +
AND + TargetFields.CONTROLLERID.name() + "!=targetId1235", 4);
}
@Test
@Description("Testing allowed RSQL keys based on TargetFields definition")
void rsqlValidTargetFields() {
final String rsql1 = "ID == '0123' and NAME == abcd and DESCRIPTION == absd"
+ " and CREATEDAT =lt= 0123 and LASTMODIFIEDAT =gt= 0123"
+ " and CONTROLLERID == 0123 and UPDATESTATUS == PENDING"
+ " and IPADDRESS == 0123 and LASTCONTROLLERREQUESTAT == 0123" + " and tag == beta";
RSQLUtility.validateRsqlFor(
"ID == '0123' and NAME == abcd and DESCRIPTION == absd and CREATEDAT =lt= 0123 and LASTMODIFIEDAT =gt= 0123" +
" and CONTROLLERID == 0123 and UPDATESTATUS == PENDING and IPADDRESS == 0123 and LASTCONTROLLERREQUESTAT == 0123" +
" and tag == beta",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RSQLUtility.validateRsqlFor(
"ASSIGNEDDS.name == abcd and ASSIGNEDDS.version == 0123 and INSTALLEDDS.name == abcd and INSTALLEDDS.version == 0123",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RSQLUtility.validateRsqlFor(
"ATTRIBUTE.subkey1 == test and ATTRIBUTE.subkey2 == test and METADATA.metakey1 == abcd and METADATA.metavalue2 == asdfg",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RSQLUtility.validateRsqlFor(
"CREATEDAT =lt= ${NOW_TS} and LASTMODIFIEDAT =ge= ${OVERDUE_TS}",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RSQLUtility.validateRsqlFor(
"ATTRIBUTE.test.dot == test and ATTRIBUTE.subkey2 == test and METADATA.test.dot == abcd and METADATA.metavalue2 == asdfg",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
RSQLUtility.validateRsqlFor(rsql1, TargetFields.class);
final String rsql2 = "ASSIGNEDDS.name == abcd and ASSIGNEDDS.version == 0123"
+ " and INSTALLEDDS.name == abcd and INSTALLEDDS.version == 0123";
RSQLUtility.validateRsqlFor(rsql2, TargetFields.class);
final String rsql3 = "ATTRIBUTE.subkey1 == test and ATTRIBUTE.subkey2 == test"
+ " and METADATA.metakey1 == abcd and METADATA.metavalue2 == asdfg";
RSQLUtility.validateRsqlFor(rsql3, TargetFields.class);
final String rsql4 = "CREATEDAT =lt= ${NOW_TS} and LASTMODIFIEDAT =ge= ${OVERDUE_TS}";
RSQLUtility.validateRsqlFor(rsql4, TargetFields.class);
final String rsql5 = "wrongfield == abcd";
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.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);
.isThrownBy(() -> RSQLUtility.validateRsqlFor(
"wrongfield == abcd",
TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager));
}
@Test
@@ -338,6 +389,7 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
private void assertRSQLQueryThrowsException(final String rsqlParam) {
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> RSQLUtility.validateRsqlFor(rsqlParam, TargetFields.class));
.isThrownBy(() -> RSQLUtility.validateRsqlFor(
rsqlParam, TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager));
}
}
}

View File

@@ -57,12 +57,12 @@ class RSQLToSQLTest {
print(JpaTarget.class, TargetFields.class, "controllerId==ctrlr1");
// reference - fk to a table
print(JpaTarget.class, TargetFields.class, "assignedds.name==x and assignedds.version==y");
// list (map table that refers main)
print(JpaTarget.class, TargetFields.class, "metadata.key1==value1");
// map (map table that refers main)
print(JpaTarget.class, TargetFields.class, "attribute.key1==value1");
// list of non-simple (with mapping table)
print(JpaTarget.class, TargetFields.class, "tag==tag1");
// list (map table that refers main)
print(JpaTarget.class, TargetFields.class, "attribute.key1==value1");
// map (map table that refers main)
print(JpaTarget.class, TargetFields.class, "metadata.key1==value1");
}
@Test

View File

@@ -44,14 +44,12 @@ import org.eclipse.hawkbit.repository.RsqlQueryField;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
import org.eclipse.hawkbit.repository.rsql.RsqlVisitorFactory;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
import org.eclipse.hawkbit.security.SystemSecurityContext;
@@ -88,8 +86,6 @@ class RSQLUtilityTest {
private TenantConfigurationManagement confMgmt;
@MockitoBean
private SystemSecurityContext securityContext;
@MockitoBean
private RsqlVisitorFactory rsqlVisitorFactory;
@Mock
private Root<Object> baseSoftwareModuleRootMock;
@Mock
@@ -109,63 +105,6 @@ class RSQLUtilityTest {
setupRoot(subqueryRootMock);
}
@Test
@Description("Testing throwing exception in case of not allowed RSQL key")
void rsqlUnsupportedFieldExceptionTest() {
final String rsql1 = "wrongfield == abcd";
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> validateRsqlForTestFields(rsql1));
final String rsql2 = "wrongfield == abcd or TESTFIELD_WITH_SUB_ENTITIES.subentity11 == 0123";
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> validateRsqlForTestFields(rsql2));
}
@Test
@Description("Testing exception in case of not allowed subkey")
void rsqlUnsupportedSubkeyThrowException() {
final String rsql1 = "TESTFIELD_WITH_SUB_ENTITIES.unsupported == abcd and TESTFIELD_WITH_SUB_ENTITIES.subentity22 == 0123";
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> validateRsqlForTestFields(rsql1));
final String rsql2 = "TESTFIELD_WITH_SUB_ENTITIES.unsupported == abcd or TESTFIELD_WITH_SUB_ENTITIES.subentity22 == 0123";
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> validateRsqlForTestFields(rsql2));
final String rsql3 = "TESTFIELD == abcd or TESTFIELD_WITH_SUB_ENTITIES.unsupported == 0123";
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> validateRsqlForTestFields(rsql3));
}
@Test
@Description("Testing valid RSQL keys based on TestFieldEnum.class")
void rsqlFieldValidation() {
final String rsql1 = "TESTFIELD_WITH_SUB_ENTITIES.subentity11 == abcd and TESTFIELD_WITH_SUB_ENTITIES.subentity22 == 0123";
final String rsql2 = "TESTFIELD_WITH_SUB_ENTITIES.subentity11 == abcd or TESTFIELD_WITH_SUB_ENTITIES.subentity22 == 0123";
final String rsql3 = "TESTFIELD_WITH_SUB_ENTITIES.subentity11 == abcd and TESTFIELD_WITH_SUB_ENTITIES.subentity22 == 0123 and TESTFIELD == any";
validateRsqlForTestFields(rsql1);
validateRsqlForTestFields(rsql2);
validateRsqlForTestFields(rsql3);
}
@Test
@Description("Verify that RSQL expressions are validated case insensitive")
void mixedCaseRsqlFieldValidation() {
when(rsqlVisitorFactory.validationRsqlVisitor(TargetFields.class)).thenReturn(new FieldValidationRsqlVisitor<>(TargetFields.class));
final String rsqlWithMixedCase = "name==b And name==c aND Name==d OR NAME=iN=y oR nAme=IN=z";
RSQLUtility.validateRsqlFor(rsqlWithMixedCase, TargetFields.class);
}
@Test
void wrongRsqlSyntaxThrowSyntaxException() {
final Specification<Object> rsqlSpecification = RSQLUtility.buildRsqlSpecification("name==abc;d", SoftwareModuleFields.class, null, testDb);
assertThatExceptionOfType(RSQLParameterSyntaxException.class)
.as("RSQLParameterSyntaxException because of wrong RSQL syntax")
.isThrownBy(() -> rsqlSpecification.toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock));
}
@Test
void wrongFieldThrowUnsupportedFieldException() {
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
@@ -481,12 +420,6 @@ class RSQLUtilityTest {
return (Path<Y>) path;
}
private void validateRsqlForTestFields(final String rsql) {
when(rsqlVisitorFactory.validationRsqlVisitor(TestFieldEnum.class)).thenReturn(
new FieldValidationRsqlVisitor<>(TestFieldEnum.class));
RSQLUtility.validateRsqlFor(rsql, TestFieldEnum.class);
}
private void reset0(final Object... mocks) {
reset(mocks);
if (Arrays.asList(mocks).contains(baseSoftwareModuleRootMock)) {
@@ -553,8 +486,8 @@ class RSQLUtilityTest {
}
@Bean
RsqlConfigHolder rsqlVisitorFactoryHolder() {
RsqlConfigHolder rsqlConfigHolder() {
return RsqlConfigHolder.getInstance();
}
}
}
}

View File

@@ -12,10 +12,10 @@
logging.level.org.eclipse.persistence=ERROR
## Uncomment to see the debug of persistence, e.g. to see the generated SQLs
#logging.level.org.eclipse.persistence=DEBUG
#spring.jpa.properties.eclipselink.logging.level=FINE
#spring.jpa.properties.eclipselink.logging.level.sql=FINE
#spring.jpa.properties.eclipselink.logging.parameters=true
logging.level.org.eclipse.persistence=DEBUG
spring.jpa.properties.eclipselink.logging.level=FINE
spring.jpa.properties.eclipselink.logging.level.sql=FINE
spring.jpa.properties.eclipselink.logging.parameters=true
## Enable EclipseLink performance monitor (monitoring and profile)
#spring.jpa.properties.eclipselink.profiler=PerformanceMonitor