Fix not equal operator (#935)

* Use nested query in getNotEqual Predicate
* Refactor RSQL Utility + use identifierField for field enums
* Don't join in case of not equal rsql operator
* Bugfix for automatic cross join + small refactoring
* Fix rsql out operator
* Fix tests for out-operator + extend TargetFieldTest
* Use inner join for subquery
* Don't use subquery for simple rsql queries
* Refactor RSQLUtility
* Change some methods to static
* Only use outer joins when they are needed
* Add tests for empty tag names
* Minor changes and refactoring for RSQLUtility
* Refactor methods to remove duplications

Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com>
This commit is contained in:
Sebastian Firsching
2020-04-15 08:01:54 +02:00
committed by GitHub
parent 6df1e934ee
commit 0d52524202
13 changed files with 322 additions and 103 deletions

View File

@@ -79,12 +79,13 @@ public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==''", 1);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "!=''", 4);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS", 1);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "!=DS", 3);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "!=DS*", 3);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "!=DS", 4);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS*", 2);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS%", 1);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==noExist*", 0);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=in=(DS,notexist)", 1);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=out=(DS,notexist)", 3);
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=out=(DS,notexist)", 4);
}
@Test
@@ -115,12 +116,11 @@ public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
@Description("Test filter distribution set by tag name")
public void testFilterByTag() {
assertRSQLQuery(DistributionSetFields.TAG.name() + "==Tag1", 2);
// does not include untagged sets
assertRSQLQuery(DistributionSetFields.TAG.name() + "!=Tag1", 0);
assertRSQLQuery(DistributionSetFields.TAG.name() + "!=Tag1", 3);
assertRSQLQuery(DistributionSetFields.TAG.name() + "==T*", 2);
assertRSQLQuery(DistributionSetFields.TAG.name() + "==noExist*", 0);
assertRSQLQuery(DistributionSetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
assertRSQLQuery(DistributionSetFields.TAG.name() + "=out=(null)", 2);
assertRSQLQuery(DistributionSetFields.TAG.name() + "=out=(null)", 5);
}
@Test

View File

@@ -65,9 +65,9 @@ public class RSQLDistributionSetMetadataFieldsTest extends AbstractJpaIntegratio
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "==''", 1);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "!=''", 5);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "==1", 1);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "!=1", 4);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "!=1", 5);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=in=(1,2)", 2);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=out=(1,2)", 3);
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=out=(1,2)", 4);
}
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {

View File

@@ -76,10 +76,10 @@ public class RSQLSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==''", 1);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "!=''", 4);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==agent-hub", 1);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "!=agent-hub", 3);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "!=agent-hub", 4);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==noExist*", 0);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=in=(agent-hub,notexist)", 1);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=out=(agent-hub,notexist)", 3);
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=out=(agent-hub,notexist)", 4);
}
@Test

View File

@@ -71,9 +71,9 @@ public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractJpaIntegration
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "==''", 1);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=''", 6);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "==1", 1);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=1", 5);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=1", 6);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=in=(1,2)", 2);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=out=(1,2)", 4);
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=out=(1,2)", 5);
}
@Test

View File

@@ -37,6 +37,9 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
private Target target;
private Target target2;
private static final String OR = ",";
private static final String AND = ";";
@Before
public void setupBeforeTest() throws InterruptedException {
@@ -73,7 +76,8 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
targetManagement.assignTag(Arrays.asList(target3.getControllerId(), target4.getControllerId()),
targetTag2.getId());
targetManagement.assignTag(Arrays.asList(target3.getControllerId(), target4.getControllerId()),
targetManagement.assignTag(
Arrays.asList(target.getControllerId(), target3.getControllerId(), target4.getControllerId()),
targetTag3.getId());
assignDistributionSet(ds.getId(), target.getControllerId());
@@ -85,6 +89,7 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.ID.name() + "==targetId123", 1);
assertRSQLQuery(TargetFields.ID.name() + "==target*", 5);
assertRSQLQuery(TargetFields.ID.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.ID.name() + "!=targetId123", 4);
assertRSQLQuery(TargetFields.ID.name() + "=in=(targetId123,notexist)", 1);
assertRSQLQuery(TargetFields.ID.name() + "=out=(targetId123,notexist)", 4);
}
@@ -95,6 +100,7 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.NAME.name() + "==targetName123", 1);
assertRSQLQuery(TargetFields.NAME.name() + "==target*", 5);
assertRSQLQuery(TargetFields.NAME.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.NAME.name() + "!=targetName123", 4);
assertRSQLQuery(TargetFields.NAME.name() + "=in=(targetName123,notexist)", 1);
assertRSQLQuery(TargetFields.NAME.name() + "=out=(targetName123,notexist)", 4);
}
@@ -105,10 +111,11 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==''", 3);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "!=''", 2);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==targetDesc123", 1);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "!=targetDesc123", 4);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==target*", 2);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=in=(targetDesc123,notexist)", 1);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=out=(targetDesc123,notexist)", 1);
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=out=(targetDesc123,notexist)", 4);
}
@Test
@@ -117,6 +124,7 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==targetId123", 1);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==target*", 5);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "!=targetId123", 4);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "=in=(targetId123,notexist)", 1);
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "=out=(targetId123,notexist)", 4);
}
@@ -154,7 +162,7 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==A*", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==noExist*", 0);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=in=(AssignedDs,notexist)", 1);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=out=(AssignedDs,notexist)", 0);
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=out=(AssignedDs,notexist)", 4);
}
@Test
@@ -166,28 +174,34 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(
TargetFields.ASSIGNEDDS.name() + ".version=in=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 1);
assertRSQLQuery(
TargetFields.ASSIGNEDDS.name() + ".version=out=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 0);
TargetFields.ASSIGNEDDS.name() + ".version=out=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 4);
}
@Test
@Description("Test filter target by tag name")
public void testFilterByTag() {
assertRSQLQuery(TargetFields.TAG.name() + "==Tag1", 2);
assertRSQLQuery(TargetFields.TAG.name() + "!=Tag1", 2);
assertRSQLQuery(TargetFields.TAG.name() + "!=Tag1", 3);
assertRSQLQuery(TargetFields.TAG.name() + "==T*", 4);
assertRSQLQuery(TargetFields.TAG.name() + "!=T*", 1);
assertRSQLQuery(TargetFields.TAG.name() + "==noExist*", 0);
assertRSQLQuery(TargetFields.TAG.name() + "!=notexist", 4);
assertRSQLQuery(TargetFields.TAG.name() + "!=notexist", 5);
assertRSQLQuery(TargetFields.TAG.name() + "==''", 1);
assertRSQLQuery(TargetFields.TAG.name() + "!=''", 4);
assertRSQLQuery(TargetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
assertRSQLQuery(TargetFields.TAG.name() + "=in=(null)", 0);
assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 2);
assertRSQLQuery(TargetFields.TAG.name() + "=out=(null)", 4);
assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 3);
assertRSQLQuery(TargetFields.TAG.name() + "=out=(null)", 5);
assertRSQLQuery(TargetFields.TAG.name() + "==Tag1" + OR + TargetFields.TAG.name() + "==Tag2", 4);
assertRSQLQuery(TargetFields.TAG.name() + "!=Tag2" + AND + TargetFields.TAG.name() + "==Tag3", 1);
assertRSQLQuery(TargetFields.TAG.name() + "!=Tag2" + OR + TargetFields.TAG.name() + "!=Tag3", 3);
}
@Test
@Description("Test filter target by lastTargetQuery")
public void testFilterByLastTargetQuery() throws InterruptedException {
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "==" + target.getLastTargetQuery(), 1);
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "!=" + target.getLastTargetQuery(), 1);
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "!=" + target.getLastTargetQuery(), 4);
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=lt=" + target.getLastTargetQuery(), 0);
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=lt=" + target2.getLastTargetQuery(), 1);
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=gt=" + target.getLastTargetQuery(), 1);
@@ -205,7 +219,19 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
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!=metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2);
}
@Test
@Description("Test filter based on more complex RSQL queries")
public void testFilterByComplexQueries() {
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);
}
private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) {

View File

@@ -80,7 +80,7 @@ public class RSQLTargetFilterQueryFieldsTest extends AbstractJpaIntegrationTest
assertRSQLQuery(TargetFilterQueryFields.AUTOASSIGNDISTRIBUTIONSET.name() + ".name=in=("
+ filter1.getAutoAssignDistributionSet().getName() + ",notexist)", 1);
assertRSQLQuery(TargetFilterQueryFields.AUTOASSIGNDISTRIBUTIONSET.name() + ".name=out=("
+ filter1.getAutoAssignDistributionSet().getName() + ",notexist)", 1);
+ filter1.getAutoAssignDistributionSet().getName() + ",notexist)", 2);
}
@Test
@@ -93,7 +93,7 @@ public class RSQLTargetFilterQueryFieldsTest extends AbstractJpaIntegrationTest
assertRSQLQuery(TargetFilterQueryFields.AUTOASSIGNDISTRIBUTIONSET.name() + ".version=in=("
+ TestdataFactory.DEFAULT_VERSION + ",notexist)", 2);
assertRSQLQuery(TargetFilterQueryFields.AUTOASSIGNDISTRIBUTIONSET.name() + ".version=out=("
+ TestdataFactory.DEFAULT_VERSION + ",notexist)", 0);
+ TestdataFactory.DEFAULT_VERSION + ",notexist)", 1);
}
private void assertRSQLQuery(final String rsqlParam, final long expectedFilterQueriesSize) {

View File

@@ -64,9 +64,9 @@ public class RSQLTargetMetadataFieldsTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "==''", 1);
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "!=''", 5);
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "==1", 1);
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "!=1", 4);
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "!=1", 5);
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "=in=(1,2)", 2);
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "=out=(1,2)", 3);
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "=out=(1,2)", 4);
}
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {

View File

@@ -25,6 +25,7 @@ import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import javax.persistence.metamodel.Attribute;
import org.eclipse.hawkbit.repository.DistributionSetFields;
@@ -75,6 +76,11 @@ public class RSQLUtilityTest {
@Mock
private CriteriaBuilder criteriaBuilderMock;
@Mock
private Subquery<SoftwareModule> subqueryMock;
@Mock
private Root<SoftwareModule> subqueryRootMock;
private final Database testDb = Database.H2;
@Mock
@@ -202,27 +208,54 @@ public class RSQLUtilityTest {
}
@Test
public void correctRsqlBuildsNotLikePredicate() {
public void correctRsqlBuildsSimpleNotLikePredicate() {
reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
final String correctRsql = "name!=abc";
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
when(criteriaBuilderMock.isNull(any(Expression.class))).thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.notLike(any(Expression.class), anyString(), eq('\\')))
.thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class)))
.thenReturn(mock(Predicate.class));
when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock))))
.thenReturn(pathOfString(baseSoftwareModuleRootMock));
// test
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock,
criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).and(any(Predicate.class));
verify(criteriaBuilderMock, times(1)).or(any(Predicate.class), any(Predicate.class));
verify(criteriaBuilderMock, times(1)).isNull(eq(pathOfString(baseSoftwareModuleRootMock)));
verify(criteriaBuilderMock, times(1)).notLike(eq(pathOfString(baseSoftwareModuleRootMock)),
eq("abc".toUpperCase()), eq('\\'));
}
@Test
public void correctRsqlBuildsNotSimpleNotLikePredicate() {
reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
// with this query a subquery has to be made, so it is no simple query
final String correctRsql = "type!=abc";
when(baseSoftwareModuleRootMock.get(anyString())).thenReturn(baseSoftwareModuleRootMock);
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
when(subqueryRootMock.get(anyString())).thenReturn(mock(Path.class));
when(criteriaBuilderMock.and(any(), any())).thenReturn(mock(Predicate.class));
when(criteriaQueryMock.subquery(SoftwareModule.class)).thenReturn(subqueryMock);
when(subqueryMock.from(SoftwareModule.class)).thenReturn(subqueryRootMock);
when(subqueryMock.select(subqueryRootMock)).thenReturn(subqueryMock);
// test
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock,
criteriaQueryMock, criteriaBuilderMock);
// verification
verify(criteriaBuilderMock, times(1)).not(criteriaBuilderMock.exists(eq(subqueryMock)));
}
@Test
public void correctRsqlBuildsLikePredicateWithPercentage() {
reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);