extract encoded uri building to the method, add unit tests for this method and fix http client test

This commit is contained in:
ivankozka 2022-04-05 23:24:44 +03:00
parent a72534f461
commit b299ee0730
3 changed files with 138 additions and 42 deletions

View File

@ -136,6 +136,17 @@
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>5.13.1</version>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-client-java</artifactId>
<version>5.13.1</version>
</dependency>
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit</artifactId>

View File

@ -191,7 +191,7 @@ public class TbHttpClient {
entity = new HttpEntity<>(msg.getData(), headers);
}
URI uri = UriComponentsBuilder.fromUriString(endpointUrl).build().encode().toUri();
URI uri = buildEncodedUri(endpointUrl);
ListenableFuture<ResponseEntity<String>> future = httpClient.exchange(
uri, method, entity, String.class);
future.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
@ -217,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());

View File

@ -18,19 +18,15 @@ 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.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.AsyncResult;
import org.mockito.Mockito;
import org.mockserver.integration.ClientAndServer;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
@ -38,7 +34,9 @@ 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;
@ -49,15 +47,15 @@ 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 {
EventLoopGroup eventLoop;
TbHttpClient client;
private final String ENDPOINT_URL = "http://localhost/api?data=[{\\\"test\\\":\\\"test\\\"}]";
private final String GET_METHOD = "GET";
@Before
public void setUp() throws Exception {
client = mock(TbHttpClient.class);
@ -83,29 +81,61 @@ public class TbHttpClientTest {
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(GET_METHOD);
config.setRestEndpointUrlPattern(ENDPOINT_URL);
config.setRequestMethod(method);
config.setRestEndpointUrlPattern(endpointUrl);
config.setUseSimpleClientHttpFactory(true);
var asyncRestTemplate = mock(AsyncRestTemplate.class);
var uriCaptor = ArgumentCaptor.forClass(URI.class);
var responseEntity = new ResponseEntity<>(
"{}",
new HttpHeaders(),
HttpStatus.OK
);
when(asyncRestTemplate.exchange(
uriCaptor.capture(),
any(),
any(),
eq(String.class)
)).thenReturn(new AsyncResult<>(responseEntity));
var asyncRestTemplate = new AsyncRestTemplate();
var httpClient = new TbHttpClient(config, eventLoop);
httpClient.setHttpClient(asyncRestTemplate);
@ -127,18 +157,51 @@ public class TbHttpClientTest {
eq(msg.getData())
)).thenReturn(successMsg);
httpClient.processMessage(ctx, msg);
var capturedData = ArgumentCaptor.forClass(String.class);
verify(ctx, times(1)).transformMsg(
when(ctx.transformMsg(
eq(msg), eq(msg.getType()),
eq(msg.getOriginator()),
eq(msg.getMetaData()),
eq(msg.getData())
);
verify(ctx, times(1))
.tellSuccess(eq(successMsg));
any(),
capturedData.capture()
)).thenReturn(successMsg);
URI uri = UriComponentsBuilder.fromUriString(ENDPOINT_URL).build().encode().toUri();
Assert.assertEquals("URI encoding was not performed!!", uri, uriCaptor.getValue());
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)
);
}
}