Tests added to validate DefaultRuleChains and EdgeDefaultRuleChains json templates
This commit is contained in:
		
							parent
							
								
									88f10881b2
								
							
						
					
					
						commit
						eaa9a9b9cc
					
				@ -28,7 +28,6 @@ import org.thingsboard.server.common.data.TbResource;
 | 
			
		||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CustomerId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.WidgetTypeId;
 | 
			
		||||
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChain;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
 | 
			
		||||
@ -104,7 +103,7 @@ public class InstallScripts {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ResourceService resourceService;
 | 
			
		||||
 | 
			
		||||
    private Path getTenantRuleChainsDir() {
 | 
			
		||||
    Path getTenantRuleChainsDir() {
 | 
			
		||||
        return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -112,7 +111,7 @@ public class InstallScripts {
 | 
			
		||||
        return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, DEVICE_PROFILE_DIR, "rule_chain_template.json");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Path getEdgeRuleChainsDir() {
 | 
			
		||||
    Path getEdgeRuleChainsDir() {
 | 
			
		||||
        return Paths.get(getDataDir(), JSON_DIR, EDGE_DIR, RULE_CHAINS_DIR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -148,8 +147,8 @@ public class InstallScripts {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void loadRuleChainsFromPath(TenantId tenantId, Path ruleChainsPath) throws IOException {
 | 
			
		||||
        try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(ruleChainsPath, path -> path.toString().endsWith(InstallScripts.JSON_EXT))) {
 | 
			
		||||
            dirStream.forEach(
 | 
			
		||||
        findRuleChainsFromPath(ruleChainsPath)
 | 
			
		||||
                .forEach(
 | 
			
		||||
                    path -> {
 | 
			
		||||
                        try {
 | 
			
		||||
                            createRuleChainFromFile(tenantId, path, null);
 | 
			
		||||
@ -157,9 +156,15 @@ public class InstallScripts {
 | 
			
		||||
                            log.error("Unable to load rule chain from json: [{}]", path.toString());
 | 
			
		||||
                            throw new RuntimeException("Unable to load rule chain from json", e);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            );
 | 
			
		||||
                    });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    List<Path> findRuleChainsFromPath(Path ruleChainsPath) throws IOException {
 | 
			
		||||
        List<Path> paths = new ArrayList<>();
 | 
			
		||||
        try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(ruleChainsPath, path -> path.toString().endsWith(InstallScripts.JSON_EXT))) {
 | 
			
		||||
            dirStream.forEach(paths::add);
 | 
			
		||||
        }
 | 
			
		||||
        return paths;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public RuleChain createDefaultRuleChain(TenantId tenantId, String ruleChainName) throws IOException {
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,111 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2023 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.service.install;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.databind.JsonNode;
 | 
			
		||||
import org.junit.jupiter.api.BeforeEach;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
			
		||||
import org.springframework.boot.test.mock.mockito.MockBean;
 | 
			
		||||
import org.springframework.boot.test.mock.mockito.SpyBean;
 | 
			
		||||
import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.server.common.data.id.RuleChainId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChain;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
 | 
			
		||||
import org.thingsboard.server.dao.dashboard.DashboardService;
 | 
			
		||||
import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
 | 
			
		||||
import org.thingsboard.server.dao.resource.ResourceService;
 | 
			
		||||
import org.thingsboard.server.dao.rule.RuleChainService;
 | 
			
		||||
import org.thingsboard.server.dao.service.validator.RuleChainDataValidator;
 | 
			
		||||
import org.thingsboard.server.dao.tenant.TenantService;
 | 
			
		||||
import org.thingsboard.server.dao.usagerecord.ApiLimitService;
 | 
			
		||||
import org.thingsboard.server.dao.widget.WidgetTypeService;
 | 
			
		||||
import org.thingsboard.server.dao.widget.WidgetsBundleService;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.BDDMockito.willReturn;
 | 
			
		||||
 | 
			
		||||
@SpringBootTest(classes = {InstallScripts.class, RuleChainDataValidator.class})
 | 
			
		||||
class InstallScriptsTest {
 | 
			
		||||
 | 
			
		||||
    @MockBean
 | 
			
		||||
    RuleChainService ruleChainService;
 | 
			
		||||
    @MockBean
 | 
			
		||||
    DashboardService dashboardService;
 | 
			
		||||
    @MockBean
 | 
			
		||||
    WidgetTypeService widgetTypeService;
 | 
			
		||||
    @MockBean
 | 
			
		||||
    WidgetsBundleService widgetsBundleService;
 | 
			
		||||
    @MockBean
 | 
			
		||||
    OAuth2ConfigTemplateService oAuth2TemplateService;
 | 
			
		||||
    @MockBean
 | 
			
		||||
    ResourceService resourceService;
 | 
			
		||||
    @SpyBean
 | 
			
		||||
    InstallScripts installScripts;
 | 
			
		||||
 | 
			
		||||
    @MockBean
 | 
			
		||||
    TenantService tenantService;
 | 
			
		||||
    @MockBean
 | 
			
		||||
    ApiLimitService apiLimitService;
 | 
			
		||||
    @SpyBean
 | 
			
		||||
    RuleChainDataValidator ruleChainValidator;
 | 
			
		||||
    TenantId tenantId = TenantId.fromUUID(UUID.fromString("9ef79cdf-37a8-4119-b682-2e7ed4e018da"));
 | 
			
		||||
 | 
			
		||||
    @BeforeEach
 | 
			
		||||
    void setUp() {
 | 
			
		||||
        willReturn(true).given(tenantService).tenantExists(tenantId);
 | 
			
		||||
        willReturn(true).given(apiLimitService).checkEntitiesLimit(any(), any());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void testDefaultRuleChainsTemplates() throws IOException {
 | 
			
		||||
        Path tenantRuleChainsDir = installScripts.getTenantRuleChainsDir();
 | 
			
		||||
        List<Path> ruleChainsFromPath = installScripts.findRuleChainsFromPath(tenantRuleChainsDir);
 | 
			
		||||
        ruleChainsFromPath.forEach(this::validateRuleChainTemplate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void testDefaultEdgeRuleChainsTemplates() throws IOException {
 | 
			
		||||
        Path edgeChainsDir = installScripts.getEdgeRuleChainsDir();
 | 
			
		||||
        List<Path> ruleChainsFromPath = installScripts.findRuleChainsFromPath(edgeChainsDir);
 | 
			
		||||
        ruleChainsFromPath.forEach(this::validateRuleChainTemplate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateRuleChainTemplate(Path templateFilePath) {
 | 
			
		||||
        JsonNode ruleChainJson = JacksonUtil.toJsonNode(templateFilePath.toFile());
 | 
			
		||||
 | 
			
		||||
        RuleChain ruleChain = JacksonUtil.treeToValue(ruleChainJson.get("ruleChain"), RuleChain.class);
 | 
			
		||||
        ruleChain.setTenantId(tenantId);
 | 
			
		||||
        ruleChainValidator.validate(ruleChain, RuleChain::getTenantId);
 | 
			
		||||
        ruleChain.setId(new RuleChainId(UUID.randomUUID()));
 | 
			
		||||
 | 
			
		||||
        RuleChainMetaData ruleChainMetaData = JacksonUtil.treeToValue(ruleChainJson.get("metadata"), RuleChainMetaData.class);
 | 
			
		||||
        ruleChainMetaData.setRuleChainId(ruleChain.getId());
 | 
			
		||||
        List<Throwable> throwables = RuleChainDataValidator.validateMetaData(ruleChainMetaData);
 | 
			
		||||
 | 
			
		||||
        assertThat(throwables).as("templateFilePath " + templateFilePath)
 | 
			
		||||
                .containsExactlyInAnyOrderElementsOf(Collections.emptyList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -31,7 +31,6 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleNode;
 | 
			
		||||
import org.thingsboard.server.common.data.util.ReflectionUtils;
 | 
			
		||||
import org.thingsboard.server.dao.exception.DataValidationException;
 | 
			
		||||
import org.thingsboard.server.dao.rule.RuleChainDao;
 | 
			
		||||
import org.thingsboard.server.dao.rule.RuleChainService;
 | 
			
		||||
import org.thingsboard.server.dao.service.ConstraintValidator;
 | 
			
		||||
import org.thingsboard.server.dao.service.DataValidator;
 | 
			
		||||
@ -41,15 +40,14 @@ import java.util.HashMap;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class RuleChainDataValidator extends DataValidator<RuleChain> {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RuleChainDao ruleChainDao;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    @Lazy
 | 
			
		||||
    private RuleChainService ruleChainService;
 | 
			
		||||
@ -88,15 +86,19 @@ public class RuleChainDataValidator extends DataValidator<RuleChain> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void validateMetaData(RuleChainMetaData ruleChainMetaData) {
 | 
			
		||||
    public static List<Throwable> validateMetaData(RuleChainMetaData ruleChainMetaData) {
 | 
			
		||||
        ConstraintValidator.validateFields(ruleChainMetaData);
 | 
			
		||||
        ruleChainMetaData.getNodes().forEach(RuleChainDataValidator::validateRuleNode);
 | 
			
		||||
        List<Throwable> throwables = ruleChainMetaData.getNodes().stream()
 | 
			
		||||
                .map(RuleChainDataValidator::validateRuleNode)
 | 
			
		||||
                .filter(Objects::nonNull)
 | 
			
		||||
                .collect(Collectors.toList());
 | 
			
		||||
        if (CollectionUtils.isNotEmpty(ruleChainMetaData.getConnections())) {
 | 
			
		||||
            validateCircles(ruleChainMetaData.getConnections());
 | 
			
		||||
        }
 | 
			
		||||
        return throwables;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void validateRuleNode(RuleNode ruleNode) {
 | 
			
		||||
    public static Throwable validateRuleNode(RuleNode ruleNode) {
 | 
			
		||||
        String errorPrefix = "'" + ruleNode.getName() + "' node configuration is invalid: ";
 | 
			
		||||
        ConstraintValidator.validateFields(ruleNode, errorPrefix);
 | 
			
		||||
        Object nodeConfig;
 | 
			
		||||
@ -104,11 +106,12 @@ public class RuleChainDataValidator extends DataValidator<RuleChain> {
 | 
			
		||||
            Class<Object> nodeConfigType = ReflectionUtils.getAnnotationProperty(ruleNode.getType(),
 | 
			
		||||
                    "org.thingsboard.rule.engine.api.RuleNode", "configClazz");
 | 
			
		||||
            nodeConfig = JacksonUtil.treeToValue(ruleNode.getConfiguration(), nodeConfigType);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            log.warn("Failed to validate node configuration: {}", ExceptionUtils.getRootCauseMessage(e));
 | 
			
		||||
            return;
 | 
			
		||||
        } catch (Throwable t) {
 | 
			
		||||
            log.warn("Failed to validate node configuration: {}", ExceptionUtils.getRootCauseMessage(t));
 | 
			
		||||
            return t;
 | 
			
		||||
        }
 | 
			
		||||
        ConstraintValidator.validateFields(nodeConfig, errorPrefix);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void validateCircles(List<NodeConnectionInfo> connectionInfos) {
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,6 @@ import org.springframework.boot.test.mock.mockito.SpyBean;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChain;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChainType;
 | 
			
		||||
import org.thingsboard.server.dao.rule.RuleChainDao;
 | 
			
		||||
import org.thingsboard.server.dao.rule.RuleChainService;
 | 
			
		||||
import org.thingsboard.server.dao.tenant.TenantService;
 | 
			
		||||
 | 
			
		||||
@ -35,8 +34,6 @@ import static org.mockito.Mockito.verify;
 | 
			
		||||
@SpringBootTest(classes = RuleChainDataValidator.class)
 | 
			
		||||
class RuleChainDataValidatorTest {
 | 
			
		||||
 | 
			
		||||
    @MockBean
 | 
			
		||||
    RuleChainDao ruleChainDao;
 | 
			
		||||
    @MockBean
 | 
			
		||||
    RuleChainService ruleChainService;
 | 
			
		||||
    @MockBean
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user