Added tests & temporary removed RelationQueryDynamicSourceConfiguration from interface

This commit is contained in:
dshvaika 2025-10-02 13:35:51 +03:00
parent 909497703a
commit 2cb05c9d2b
4 changed files with 183 additions and 11 deletions

View File

@ -26,7 +26,6 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
property = "type"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = RelationQueryDynamicSourceConfiguration.class, name = "RELATION_QUERY"),
@JsonSubTypes.Type(value = RelationPathQueryDynamicSourceConfiguration.class, name = "RELATION_PATH_QUERY")
})
@JsonIgnoreProperties(ignoreUnknown = true)

View File

@ -0,0 +1,126 @@
/**
* Copyright © 2016-2025 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.cf.configuration;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.mockito.junit.jupiter.MockitoExtension;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationPathLevel;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class RelationPathQueryDynamicSourceConfigurationTest {
@Test
void typeShouldBeRelationQuery() {
var cfg = new RelationPathQueryDynamicSourceConfiguration();
assertThat(cfg.getType()).isEqualTo(CFArgumentDynamicSourceType.RELATION_PATH_QUERY);
}
@ParameterizedTest
@NullAndEmptySource
void validateShouldThrowWhenLevelsIsNull(List<RelationPathLevel> levels) {
var cfg = new RelationPathQueryDynamicSourceConfiguration();
cfg.setLevels(levels);
assertThatThrownBy(cfg::validate)
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("At least one relation level must be specified!");
}
@Test
void validateShouldCallValidateForPathLevels() {
List<RelationPathLevel> levels = new ArrayList<>();
RelationPathLevel lvl1 = mock(RelationPathLevel.class);
RelationPathLevel lvl2 = mock(RelationPathLevel.class);
levels.add(lvl1);
levels.add(lvl2);
var cfg = new RelationPathQueryDynamicSourceConfiguration();
cfg.setLevels(levels);
assertThatCode(cfg::validate).doesNotThrowAnyException();
verify(lvl1).validate();
verify(lvl2).validate();
}
@Test
void resolveEntityIds_whenDirectionFROM_thenReturnsToIds() {
List<RelationPathLevel> levels = new ArrayList<>();
RelationPathLevel lvl1 = mock(RelationPathLevel.class);
RelationPathLevel lvl2 = mock(RelationPathLevel.class);
levels.add(lvl1);
levels.add(lvl2);
when(lvl2.direction()).thenReturn(EntitySearchDirection.FROM);
EntityRelation rel1 = mock(EntityRelation.class);
EntityRelation rel2 = mock(EntityRelation.class);
when(rel1.getTo()).thenReturn(mock(EntityId.class));
when(rel2.getTo()).thenReturn(mock(EntityId.class));
var cfg = new RelationPathQueryDynamicSourceConfiguration();
cfg.setLevels(levels);
var out = cfg.resolveEntityIds(List.of(rel1, rel2));
assertThat(out).containsExactly(rel1.getTo(), rel2.getTo());
}
@Test
void resolveEntityIds_whenDirectionTO_thenReturnsFromIds() {
List<RelationPathLevel> levels = new ArrayList<>();
RelationPathLevel lvl1 = mock(RelationPathLevel.class);
RelationPathLevel lvl2 = mock(RelationPathLevel.class);
levels.add(lvl1);
levels.add(lvl2);
when(lvl2.direction()).thenReturn(EntitySearchDirection.TO);
EntityRelation rel1 = mock(EntityRelation.class);
EntityRelation rel2 = mock(EntityRelation.class);
when(rel1.getFrom()).thenReturn(mock(EntityId.class));
when(rel2.getFrom()).thenReturn(mock(EntityId.class));
var cfg = new RelationPathQueryDynamicSourceConfiguration();
cfg.setLevels(levels);
var out = cfg.resolveEntityIds(List.of(rel1, rel2));
assertThat(out).containsExactly(rel1.getFrom(), rel2.getFrom());
}
}

View File

@ -123,9 +123,8 @@ public class RelationQueryDynamicSourceConfigurationTest {
.hasMessage("Relation query dynamic source configuration relation type must be specified!");
}
@ParameterizedTest
@NullAndEmptySource
void isSimpleRelationTrueWhenLevelIsOneAndEntityTypesEmptyOrNull(List<EntityType> entityTypes) {
@Test
void isSimpleRelationTrueWhenLevelIsOneAndEntityTypesEmptyOrNull() {
var cfg = new RelationQueryDynamicSourceConfiguration();
cfg.setMaxLevel(1);
assertThat(cfg.isSimpleRelation()).isTrue();
@ -138,9 +137,8 @@ public class RelationQueryDynamicSourceConfigurationTest {
assertThat(cfg.isSimpleRelation()).isFalse();
}
@ParameterizedTest
@NullAndEmptySource
void toEntityRelationsQueryShouldThrowForSimpleRelation(List<EntityType> entityTypes) {
@Test
void toEntityRelationsQueryShouldThrowForSimpleRelation() {
var cfg = new RelationQueryDynamicSourceConfiguration();
cfg.setMaxLevel(1);
cfg.setFetchLastLevelOnly(false);
@ -177,7 +175,7 @@ public class RelationQueryDynamicSourceConfigurationTest {
}
@Test
void resolveEntityIdsFromDirectionFROMReturnsToIds() {
void resolveEntityIds_whenDirectionFROM_thenReturnsToIds() {
when(rel1.getTo()).thenReturn(mock(EntityId.class));
when(rel2.getTo()).thenReturn(mock(EntityId.class));
@ -190,7 +188,7 @@ public class RelationQueryDynamicSourceConfigurationTest {
}
@Test
void resolveEntityIdsFromDirectionTOReturnsFromIds() {
void resolveEntityIds_whenDirectionTO_thenReturnsFromIds() {
when(rel1.getFrom()).thenReturn(mock(EntityId.class));
when(rel2.getFrom()).thenReturn(mock(EntityId.class));

View File

@ -28,9 +28,11 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntityRelationPathQuery;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter;
import org.thingsboard.server.common.data.relation.RelationPathLevel;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
import org.thingsboard.server.dao.exception.DataValidationException;
@ -42,6 +44,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static org.assertj.core.api.Assertions.assertThat;
@DaoSqlTest
public class RelationServiceTest extends AbstractServiceTest {
@ -348,14 +352,14 @@ public class RelationServiceTest extends AbstractServiceTest {
query.setFilters(Collections.singletonList(new RelationEntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.singletonList(EntityType.ASSET))));
List<EntityRelation> relations = relationService.findByQuery(SYSTEM_TENANT_ID, query).get();
Assert.assertEquals(expected.size(), relations.size());
for(EntityRelation r : expected){
for (EntityRelation r : expected) {
Assert.assertTrue(relations.contains(r));
}
//Test from cache
relations = relationService.findByQuery(SYSTEM_TENANT_ID, query).get();
Assert.assertEquals(expected.size(), relations.size());
for(EntityRelation r : expected){
for (EntityRelation r : expected) {
Assert.assertTrue(relations.contains(r));
}
}
@ -623,6 +627,51 @@ public class RelationServiceTest extends AbstractServiceTest {
Assert.assertTrue(relations.contains(relationF));
}
@Test
public void testFindByPathQuery() throws Exception {
/*
A
[firstLevel, TO] B
[secondLevel, TO] C
[thirdLevel, FROM] D
[thirdLevel, FROM] E
[thirdLevel, FROM] F
*/
// rootEntity
AssetId assetA = new AssetId(Uuids.timeBased());
// firstLevelEntity
AssetId assetB = new AssetId(Uuids.timeBased());
// secondLevelEntity
AssetId assetC = new AssetId(Uuids.timeBased());
// thirdLevelEntities
AssetId assetD = new AssetId(Uuids.timeBased());
AssetId assetE = new AssetId(Uuids.timeBased());
AssetId assetF = new AssetId(Uuids.timeBased());
EntityRelation firstLevelRelation = new EntityRelation(assetB, assetA, "firstLevel");
EntityRelation secondLevelRelation = new EntityRelation(assetC, assetB, "secondLevel");
EntityRelation thirdLevelRelation1 = new EntityRelation(assetC, assetD, "thirdLevel");
EntityRelation thirdLevelRelation2 = new EntityRelation(assetC, assetE, "thirdLevel");
EntityRelation thirdLevelRelation3 = new EntityRelation(assetC, assetF, "thirdLevel");
firstLevelRelation = saveRelation(firstLevelRelation);
secondLevelRelation = saveRelation(secondLevelRelation);
thirdLevelRelation1 = saveRelation(thirdLevelRelation1);
thirdLevelRelation2 = saveRelation(thirdLevelRelation2);
thirdLevelRelation3 = saveRelation(thirdLevelRelation3);
List<EntityRelation> expectedRelations = List.of(thirdLevelRelation1, thirdLevelRelation2, thirdLevelRelation3);
EntityRelationPathQuery relationPathQuery = new EntityRelationPathQuery(assetA, List.of(
new RelationPathLevel(EntitySearchDirection.TO, "firstLevel"),
new RelationPathLevel(EntitySearchDirection.TO, "secondLevel"),
new RelationPathLevel(EntitySearchDirection.FROM, "thirdLevel")
));
List<EntityRelation> entityRelations = relationService.findByRelationPathQueryAsync(tenantId, relationPathQuery).get();
assertThat(expectedRelations).containsExactlyInAnyOrderElementsOf(entityRelations);
}
@Test
public void testFindByQueryLargeHierarchyFetchAllWithUnlimLvl() throws Exception {
AssetId rootAsset = new AssetId(Uuids.timeBased());