Merge branch 'restApiCallNodeJsonVarFix' of github.com:desoliture1/thingsboard into develop/3.4
This commit is contained in:
		
						commit
						6f78d8245a
					
				
							
								
								
									
										13
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								pom.xml
									
									
									
									
									
								
							@ -128,6 +128,7 @@
 | 
			
		||||
        <java-websocket.version>1.5.2</java-websocket.version>
 | 
			
		||||
        <jupiter.version>5.8.2</jupiter.version> <!-- keep the same version as spring-boot-starter-test depend on jupiter-->
 | 
			
		||||
        <json-path.version>2.6.0</json-path.version>
 | 
			
		||||
        <mock-server.version>5.13.1</mock-server.version>
 | 
			
		||||
        <spring-test-dbunit.version>1.3.0</spring-test-dbunit.version> <!-- 2016 -->
 | 
			
		||||
        <takari-cpsuite.version>1.2.7</takari-cpsuite.version> <!-- 2015 -->
 | 
			
		||||
        <!--      BLACKBOX TEST SCOPE     -->
 | 
			
		||||
@ -1877,6 +1878,18 @@
 | 
			
		||||
                <version>${zeroturnaround.version}</version>
 | 
			
		||||
                <scope>test</scope>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.mock-server</groupId>
 | 
			
		||||
                <artifactId>mockserver-netty</artifactId>
 | 
			
		||||
                <version>${mock-server.version}</version>
 | 
			
		||||
                <scope>test</scope>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.mock-server</groupId>
 | 
			
		||||
                <artifactId>mockserver-client-java</artifactId>
 | 
			
		||||
                <version>${mock-server.version}</version>
 | 
			
		||||
                <scope>test</scope>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.opensmpp</groupId>
 | 
			
		||||
                <artifactId>opensmpp-core</artifactId>
 | 
			
		||||
 | 
			
		||||
@ -136,6 +136,15 @@
 | 
			
		||||
            <artifactId>awaitility</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.mock-server</groupId>
 | 
			
		||||
            <artifactId>mockserver-netty</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.mock-server</groupId>
 | 
			
		||||
            <artifactId>mockserver-client-java</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.cassandraunit</groupId>
 | 
			
		||||
            <artifactId>cassandra-unit</artifactId>
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ import org.springframework.util.concurrent.ListenableFuture;
 | 
			
		||||
import org.springframework.util.concurrent.ListenableFutureCallback;
 | 
			
		||||
import org.springframework.web.client.AsyncRestTemplate;
 | 
			
		||||
import org.springframework.web.client.HttpClientErrorException;
 | 
			
		||||
import org.springframework.web.util.UriComponentsBuilder;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbContext;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbNodeException;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbRelationTypes;
 | 
			
		||||
@ -54,6 +55,7 @@ import javax.net.ssl.SSLContext;
 | 
			
		||||
import javax.net.ssl.SSLException;
 | 
			
		||||
import java.net.Authenticator;
 | 
			
		||||
import java.net.PasswordAuthentication;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.nio.charset.StandardCharsets;
 | 
			
		||||
import java.security.NoSuchAlgorithmException;
 | 
			
		||||
import java.util.Deque;
 | 
			
		||||
@ -189,8 +191,9 @@ public class TbHttpClient {
 | 
			
		||||
            entity = new HttpEntity<>(msg.getData(), headers);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        URI uri = buildEncodedUri(endpointUrl);
 | 
			
		||||
        ListenableFuture<ResponseEntity<String>> future = httpClient.exchange(
 | 
			
		||||
                endpointUrl, method, entity, String.class);
 | 
			
		||||
                uri, method, entity, String.class);
 | 
			
		||||
        future.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onFailure(Throwable throwable) {
 | 
			
		||||
@ -214,6 +217,28 @@ public class TbHttpClient {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public URI buildEncodedUri(String endpointUrl) {
 | 
			
		||||
        if (endpointUrl == null) {
 | 
			
		||||
            throw new RuntimeException("Url string cannot be null!");
 | 
			
		||||
        }
 | 
			
		||||
        if (endpointUrl.isEmpty()) {
 | 
			
		||||
            throw new RuntimeException("Url string cannot be empty!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        URI uri = UriComponentsBuilder.fromUriString(endpointUrl).build().encode().toUri();
 | 
			
		||||
        if (uri.getScheme() == null || uri.getScheme().isEmpty()) {
 | 
			
		||||
            throw new RuntimeException("Transport scheme(protocol) must be provided!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        boolean authorityNotValid = uri.getAuthority() == null || uri.getAuthority().isEmpty();
 | 
			
		||||
        boolean hostNotValid = uri.getHost() == null || uri.getHost().isEmpty();
 | 
			
		||||
        if (authorityNotValid || hostNotValid) {
 | 
			
		||||
            throw new RuntimeException("Url string is invalid!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return uri;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private TbMsg processResponse(TbContext ctx, TbMsg origMsg, ResponseEntity<String> response) {
 | 
			
		||||
        TbMsgMetaData metaData = origMsg.getMetaData();
 | 
			
		||||
        metaData.putValue(STATUS, response.getStatusCode().name());
 | 
			
		||||
 | 
			
		||||
@ -18,16 +18,38 @@ package org.thingsboard.rule.engine.rest;
 | 
			
		||||
 | 
			
		||||
import io.netty.channel.EventLoopGroup;
 | 
			
		||||
import io.netty.channel.nio.NioEventLoopGroup;
 | 
			
		||||
import org.awaitility.Awaitility;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.mockito.ArgumentCaptor;
 | 
			
		||||
import org.mockito.Mockito;
 | 
			
		||||
import org.mockserver.integration.ClientAndServer;
 | 
			
		||||
import org.springframework.web.client.AsyncRestTemplate;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbContext;
 | 
			
		||||
import org.thingsboard.server.common.data.id.DeviceId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.msg.TbMsg;
 | 
			
		||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
 | 
			
		||||
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
 | 
			
		||||
import static org.hamcrest.MatcherAssert.assertThat;
 | 
			
		||||
import static org.hamcrest.Matchers.instanceOf;
 | 
			
		||||
import static org.hamcrest.Matchers.is;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.BDDMockito.willCallRealMethod;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.times;
 | 
			
		||||
import static org.mockito.Mockito.verify;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
 | 
			
		||||
import static org.mockserver.model.HttpRequest.request;
 | 
			
		||||
import static org.mockserver.model.HttpResponse.response;
 | 
			
		||||
 | 
			
		||||
public class TbHttpClientTest {
 | 
			
		||||
 | 
			
		||||
@ -58,4 +80,128 @@ public class TbHttpClientTest {
 | 
			
		||||
        eventLoop = client.getSharedOrCreateEventLoopGroup(null);
 | 
			
		||||
        assertThat(eventLoop, instanceOf(NioEventLoopGroup.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testBuildSimpleUri() {
 | 
			
		||||
        Mockito.when(client.buildEncodedUri(any())).thenCallRealMethod();
 | 
			
		||||
        String url = "http://localhost:8080/";
 | 
			
		||||
        URI uri = client.buildEncodedUri(url);
 | 
			
		||||
        Assert.assertEquals(url, uri.toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testBuildUriWithoutProtocol() {
 | 
			
		||||
        Mockito.when(client.buildEncodedUri(any())).thenCallRealMethod();
 | 
			
		||||
        String url = "localhost:8080/";
 | 
			
		||||
        assertThatThrownBy(() -> client.buildEncodedUri(url));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testBuildInvalidUri() {
 | 
			
		||||
        Mockito.when(client.buildEncodedUri(any())).thenCallRealMethod();
 | 
			
		||||
        String url = "aaa";
 | 
			
		||||
        assertThatThrownBy(() -> client.buildEncodedUri(url));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testBuildUriWithSpecialSymbols() {
 | 
			
		||||
        Mockito.when(client.buildEncodedUri(any())).thenCallRealMethod();
 | 
			
		||||
        String url = "http://192.168.1.1/data?d={\"a\": 12}";
 | 
			
		||||
        String expected = "http://192.168.1.1/data?d=%7B%22a%22:%2012%7D";
 | 
			
		||||
        URI uri = client.buildEncodedUri(url);
 | 
			
		||||
        Assert.assertEquals(expected, uri.toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testProcessMessageWithJsonInUrlVariable() throws Exception {
 | 
			
		||||
        String host = "localhost";
 | 
			
		||||
        String path = "/api";
 | 
			
		||||
        String paramKey = "data";
 | 
			
		||||
        String paramVal = "[{\"test\":\"test\"}]";
 | 
			
		||||
        String successResponseBody = "SUCCESS";
 | 
			
		||||
 | 
			
		||||
        var server = setUpDummyServer(host, path, paramKey, paramVal, successResponseBody);
 | 
			
		||||
 | 
			
		||||
        String endpointUrl = String.format(
 | 
			
		||||
                "http://%s:%d%s?%s=%s",
 | 
			
		||||
                host, server.getPort(), path, paramKey, paramVal
 | 
			
		||||
        );
 | 
			
		||||
        String method = "GET";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        var config = new TbRestApiCallNodeConfiguration()
 | 
			
		||||
                .defaultConfiguration();
 | 
			
		||||
        config.setRequestMethod(method);
 | 
			
		||||
        config.setRestEndpointUrlPattern(endpointUrl);
 | 
			
		||||
        config.setUseSimpleClientHttpFactory(true);
 | 
			
		||||
 | 
			
		||||
        var asyncRestTemplate = new AsyncRestTemplate();
 | 
			
		||||
 | 
			
		||||
        var httpClient = new TbHttpClient(config, eventLoop);
 | 
			
		||||
        httpClient.setHttpClient(asyncRestTemplate);
 | 
			
		||||
 | 
			
		||||
        var msg = TbMsg.newMsg(
 | 
			
		||||
                "Main", "GET", new DeviceId(EntityId.NULL_UUID),
 | 
			
		||||
                TbMsgMetaData.EMPTY, "{}"
 | 
			
		||||
        );
 | 
			
		||||
        var successMsg = TbMsg.newMsg(
 | 
			
		||||
                "SUCCESS", msg.getOriginator(),
 | 
			
		||||
                msg.getMetaData(), msg.getData()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        var ctx = mock(TbContext.class);
 | 
			
		||||
        when(ctx.transformMsg(
 | 
			
		||||
                eq(msg), eq(msg.getType()),
 | 
			
		||||
                eq(msg.getOriginator()),
 | 
			
		||||
                eq(msg.getMetaData()),
 | 
			
		||||
                eq(msg.getData())
 | 
			
		||||
        )).thenReturn(successMsg);
 | 
			
		||||
 | 
			
		||||
        var capturedData = ArgumentCaptor.forClass(String.class);
 | 
			
		||||
 | 
			
		||||
        when(ctx.transformMsg(
 | 
			
		||||
                eq(msg), eq(msg.getType()),
 | 
			
		||||
                eq(msg.getOriginator()),
 | 
			
		||||
                any(),
 | 
			
		||||
                capturedData.capture()
 | 
			
		||||
        )).thenReturn(successMsg);
 | 
			
		||||
 | 
			
		||||
        httpClient.processMessage(ctx, msg);
 | 
			
		||||
 | 
			
		||||
        Awaitility.await()
 | 
			
		||||
                .atMost(30, TimeUnit.SECONDS)
 | 
			
		||||
                .until(() -> {
 | 
			
		||||
                    try {
 | 
			
		||||
                        verify(ctx, times(1)).tellSuccess(any());
 | 
			
		||||
                        return true;
 | 
			
		||||
                    } catch (Exception e) {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
        verify(ctx, times(1)).tellSuccess(any());
 | 
			
		||||
        verify(ctx, times(0)).tellFailure(any(), any());
 | 
			
		||||
        Assert.assertEquals(successResponseBody, capturedData.getValue());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ClientAndServer setUpDummyServer(String host, String path, String paramKey, String paramVal, String successResponseBody) {
 | 
			
		||||
        var server = startClientAndServer(host, 1080);
 | 
			
		||||
        createGetMethodExpectations(server, path, paramKey, paramVal, successResponseBody);
 | 
			
		||||
        return server;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void createGetMethodExpectations(ClientAndServer server, String path, String paramKey, String paramVal, String successResponseBody) {
 | 
			
		||||
        server.when(
 | 
			
		||||
                request()
 | 
			
		||||
                        .withMethod("GET")
 | 
			
		||||
                        .withPath(path)
 | 
			
		||||
                        .withQueryStringParameter(paramKey, paramVal)
 | 
			
		||||
        ).respond(
 | 
			
		||||
                response()
 | 
			
		||||
                        .withStatusCode(200)
 | 
			
		||||
                        .withBody(successResponseBody)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user