Skip to content

Commit 36ae5b6

Browse files
kristoffSCKrzysztof Chmielewski
authored andcommitted
ESP-98ESP-98_SinkParameters - add unit tests
Signed-off-by: Krzysztof Chmielewski <krzysztof.chmielewski@getindata.com>
1 parent ee0bec9 commit 36ae5b6

File tree

10 files changed

+228
-21
lines changed

10 files changed

+228
-21
lines changed

pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ under the License.
8383
<wiremock.version>2.27.2</wiremock.version>
8484
<jacoco.plugin.version>0.8.7</jacoco.plugin.version>
8585
<maven.shade.plugin.version>3.1.1</maven.shade.plugin.version>
86+
<mockito-inline.version>4.6.1</mockito-inline.version>
8687
</properties>
8788

8889
<repositories>
@@ -264,6 +265,13 @@ under the License.
264265
<version>${wiremock.version}</version>
265266
<scope>test</scope>
266267
</dependency>
268+
269+
<dependency>
270+
<groupId>org.mockito</groupId>
271+
<artifactId>mockito-inline</artifactId>
272+
<version>${mockito-inline.version}</version>
273+
<scope>test</scope>
274+
</dependency>
267275
</dependencies>
268276

269277
<build>

src/main/java/com/getindata/connectors/http/internal/config/ConfigException.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.getindata.connectors.http.internal.config;
22

3-
// TODO EXP-98 add Javadoc
3+
/**
4+
* A Runtime exception throw when there is any issue with configuration properties for Http
5+
* Connector.
6+
*/
47
public class ConfigException extends RuntimeException {
58

69
private static final long serialVersionUID = 1L;

src/main/java/com/getindata/connectors/http/internal/config/HttpConnectorConfigConstants.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,28 @@
22

33
import lombok.AccessLevel;
44
import lombok.NoArgsConstructor;
5+
import lombok.experimental.UtilityClass;
56

6-
// TODO EXP-98 add Javadoc
7+
/**
8+
* A dictionary class containing properties or properties prefixes for Http connector.
9+
*/
10+
@UtilityClass
711
@NoArgsConstructor(access = AccessLevel.NONE)
812
public final class HttpConnectorConfigConstants {
913

14+
/**
15+
* A property prefix for http connector.
16+
*/
1017
public static final String GID_CONNECTOR_HTTP = "gid.connector.http.";
1118

19+
/**
20+
* A property prefix for http connector header properties
21+
*/
1222
public static final String SINK_HEADER_PREFIX = GID_CONNECTOR_HTTP + "sink.header.";
1323

24+
/**
25+
* A property for Content-Type HTTP header.
26+
*/
1427
public static final String CONTENT_TYPE_HEADER = SINK_HEADER_PREFIX + "Content-Type";
1528

1629
}

src/main/java/com/getindata/connectors/http/internal/sink/httpclient/JavaNetSinkHttpClient.java

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
import java.net.http.HttpRequest.Builder;
99
import java.net.http.HttpResponse;
1010
import java.util.ArrayList;
11+
import java.util.Arrays;
1112
import java.util.List;
1213
import java.util.Map;
1314
import java.util.Properties;
1415
import java.util.concurrent.CompletableFuture;
1516
import java.util.stream.Collectors;
16-
import java.util.stream.Stream;
1717

1818
import lombok.extern.slf4j.Slf4j;
19+
import org.apache.flink.annotation.VisibleForTesting;
1920

2021
import com.getindata.connectors.http.internal.SinkHttpClient;
2122
import com.getindata.connectors.http.internal.SinkHttpClientResponse;
@@ -42,22 +43,14 @@ public JavaNetSinkHttpClient(Properties properties) {
4243
Map<String, String> headerMap =
4344
ConfigUtils.propertiesToMap(properties, SINK_HEADER_PREFIX, String.class);
4445

45-
// TODO EXP-98 add tests
46-
headersAndValues = headerMap
47-
.entrySet()
48-
.stream()
49-
.flatMap(entry -> {
50-
String originalKey = entry.getKey();
51-
// TODO EXP-98 extract this to utils and add tests. Wrap with try/catch in Utils
52-
String newKey = ConfigUtils.extractPropertyLastElement(originalKey);
53-
54-
return Stream.of(newKey, entry.getValue());
55-
}).toArray(String[]::new);
46+
// TODO ESP-98 add tests
47+
headersAndValues = ConfigUtils.flatMapToHeaderArray(headerMap);
5648
}
5749

5850
@Override
5951
public CompletableFuture<SinkHttpClientResponse> putRequests(
60-
List<HttpSinkRequestEntry> requestEntries, String endpointUrl) {
52+
List<HttpSinkRequestEntry> requestEntries,
53+
String endpointUrl) {
6154
return submitRequests(requestEntries, endpointUrl).thenApply(
6255
this::prepareSinkHttpClientResponse);
6356
}
@@ -78,8 +71,8 @@ private HttpRequest buildHttpRequest(HttpSinkRequestEntry requestEntry, URI endp
7871
}
7972

8073
private CompletableFuture<List<JavaNetHttpResponseWrapper>> submitRequests(
81-
List<HttpSinkRequestEntry> requestEntries, String endpointUrl
82-
) {
74+
List<HttpSinkRequestEntry> requestEntries,
75+
String endpointUrl) {
8376
var endpointUri = URI.create(endpointUrl);
8477
var responseFutures = new ArrayList<CompletableFuture<JavaNetHttpResponseWrapper>>();
8578

@@ -101,7 +94,7 @@ private CompletableFuture<List<JavaNetHttpResponseWrapper>> submitRequests(
10194
}
10295

10396
private SinkHttpClientResponse prepareSinkHttpClientResponse(
104-
List<JavaNetHttpResponseWrapper> responses) {
97+
List<JavaNetHttpResponseWrapper> responses) {
10598
var successfulResponses = new ArrayList<HttpSinkRequestEntry>();
10699
var failedResponses = new ArrayList<HttpSinkRequestEntry>();
107100

@@ -117,4 +110,9 @@ private SinkHttpClientResponse prepareSinkHttpClientResponse(
117110

118111
return new SinkHttpClientResponse(successfulResponses, failedResponses);
119112
}
113+
114+
@VisibleForTesting
115+
String[] getHeadersAndValues() {
116+
return Arrays.copyOf(headersAndValues, headersAndValues.length);
117+
}
120118
}

src/main/java/com/getindata/connectors/http/internal/table/sink/HttpDynamicSink.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public SinkRuntimeProvider getSinkRuntimeProvider(Context context) {
115115
var insertMethod = tableOptions.get(INSERT_METHOD);
116116
var contentType = getContentTypeFromFormat(tableOptions.get(FactoryUtil.FORMAT));
117117

118-
// TODO EXP-98 add headers to DDL and add tests for this
118+
// TODO ESP-98 add headers to DDL and add tests for this
119119
HttpSinkBuilder<RowData> builder = HttpSink
120120
.<RowData>builder()
121121
.setEndpointUrl(tableOptions.get(URL))

src/main/java/com/getindata/connectors/http/internal/utils/ConfigUtils.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.HashMap;
44
import java.util.Map;
55
import java.util.Properties;
6+
import java.util.stream.Stream;
67

78
import lombok.AccessLevel;
89
import lombok.NoArgsConstructor;
@@ -78,6 +79,31 @@ public static String extractPropertyLastElement(String propertyKay) {
7879
return propertyKay.substring(delimiterLastIndex + 1);
7980
}
8081

82+
/**
83+
* Flat map a given Map of header name and header value map to an array containing both header
84+
* names and values. For example, header map of
85+
* <pre>
86+
* Map.of(
87+
* header1, val1,
88+
* header2, val2
89+
* )
90+
* </pre>
91+
* will be converter to an array of:
92+
* <pre>
93+
* String[] headers = {"header1", "val1", "header2", "val2"};
94+
* </pre>
95+
*/
96+
public static String[] flatMapToHeaderArray(Map<String, String> headerMap) {
97+
return headerMap
98+
.entrySet()
99+
.stream()
100+
.flatMap(entry -> {
101+
String originalKey = entry.getKey();
102+
String newKey = ConfigUtils.extractPropertyLastElement(originalKey);
103+
return Stream.of(newKey, entry.getValue());
104+
}).toArray(String[]::new);
105+
}
106+
81107
private static <T> void tryAddToConfigMap(
82108
Properties properties,
83109
Class<T> clazz, Map<String, T> map,

src/test/java/com/getindata/connectors/http/TestHelper.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import java.net.URI;
44
import java.nio.file.Files;
55
import java.nio.file.Path;
6+
import java.util.Arrays;
67
import java.util.Objects;
78

89
import lombok.AccessLevel;
910
import lombok.NoArgsConstructor;
11+
import org.junit.jupiter.api.Assertions;
12+
import static org.assertj.core.api.Assertions.assertThat;
1013

1114
@NoArgsConstructor(access = AccessLevel.PRIVATE)
1215
public final class TestHelper {
@@ -22,4 +25,25 @@ public static String readTestFile(String pathToFile) {
2225
}
2326
}
2427

28+
public static void assertPropertyArray(
29+
String[] headerArray,
30+
String propertyName,
31+
String expectedValue) {
32+
// important thing is that we have property followed by its value.
33+
for (int i = 0; i < headerArray.length; i++) {
34+
if (headerArray[i].equals(propertyName)) {
35+
assertThat(headerArray[i + 1])
36+
.withFailMessage("Property Array does not contain property name, value pairs.")
37+
.isEqualTo(expectedValue);
38+
return;
39+
}
40+
}
41+
Assertions.fail(
42+
String.format(
43+
"Missing property name [%s] in header array %s.",
44+
propertyName,
45+
Arrays.toString(headerArray))
46+
);
47+
}
48+
2549
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.getindata.connectors.http.internal.sink.httpclient;
2+
3+
import java.net.http.HttpClient;
4+
import java.util.Properties;
5+
6+
import org.junit.jupiter.api.AfterAll;
7+
import org.junit.jupiter.api.BeforeAll;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.extension.ExtendWith;
11+
import org.mockito.Mock;
12+
import org.mockito.MockedStatic;
13+
import org.mockito.Mockito;
14+
import org.mockito.junit.jupiter.MockitoExtension;
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
17+
import com.getindata.connectors.http.internal.config.HttpConnectorConfigConstants;
18+
import static com.getindata.connectors.http.TestHelper.assertPropertyArray;
19+
20+
@ExtendWith(MockitoExtension.class)
21+
class JavaNetSinkHttpClientTest {
22+
23+
private static MockedStatic<HttpClient> httpClientStaticMock;
24+
25+
@Mock
26+
private HttpClient.Builder httpClientBuilder;
27+
28+
@BeforeAll
29+
public static void beforeAll() {
30+
httpClientStaticMock = Mockito.mockStatic(HttpClient.class);
31+
}
32+
33+
@AfterAll
34+
public static void afterAll() {
35+
if (httpClientStaticMock != null) {
36+
httpClientStaticMock.close();
37+
}
38+
}
39+
40+
@BeforeEach
41+
public void setUp() {
42+
httpClientStaticMock.when(HttpClient::newBuilder).thenReturn(httpClientBuilder);
43+
Mockito
44+
.when(httpClientBuilder.followRedirects(Mockito.any()))
45+
.thenReturn(httpClientBuilder);
46+
}
47+
48+
@Test
49+
public void shouldBuildClientWithNoHeader() {
50+
51+
JavaNetSinkHttpClient client = new JavaNetSinkHttpClient(new Properties());
52+
assertThat(client.getHeadersAndValues()).isEmpty();
53+
}
54+
55+
@Test
56+
public void shouldBuildClientWithHeaders() {
57+
58+
// GIVEN
59+
Properties properties = new Properties();
60+
properties.setProperty("property", "val1");
61+
properties.setProperty("my.property", "val2");
62+
properties.setProperty(
63+
HttpConnectorConfigConstants.SINK_HEADER_PREFIX + "Origin",
64+
"https://developer.mozilla.org")
65+
;
66+
properties.setProperty(
67+
HttpConnectorConfigConstants.SINK_HEADER_PREFIX + "Cache-Control",
68+
"no-cache, no-store, max-age=0, must-revalidate"
69+
);
70+
properties.setProperty(
71+
HttpConnectorConfigConstants.SINK_HEADER_PREFIX + "Access-Control-Allow-Origin",
72+
"*"
73+
);
74+
75+
// WHEN
76+
JavaNetSinkHttpClient client = new JavaNetSinkHttpClient(properties);
77+
String[] headersAndValues = client.getHeadersAndValues();
78+
assertThat(headersAndValues).hasSize(6);
79+
80+
// THEN
81+
// assert that we have property followed by its value.
82+
assertPropertyArray(headersAndValues, "Origin", "https://developer.mozilla.org");
83+
assertPropertyArray(
84+
headersAndValues,
85+
"Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"
86+
);
87+
assertPropertyArray(headersAndValues, "Access-Control-Allow-Origin", "*");
88+
}
89+
90+
}

src/test/java/com/getindata/connectors/http/internal/table/sink/HttpDynamicSinkTest.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,31 @@
99
import org.apache.flink.table.types.AtomicDataType;
1010
import org.apache.flink.table.types.logical.BooleanType;
1111
import org.junit.jupiter.api.Test;
12-
import static org.junit.jupiter.api.Assertions.*;
12+
import static org.assertj.core.api.Assertions.assertThat;
13+
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
1315

16+
import com.getindata.connectors.http.internal.table.sink.HttpDynamicSink.HttpDynamicTableSinkBuilder;
1417
import static com.getindata.connectors.http.internal.table.sink.HttpDynamicSinkConnectorOptions.INSERT_METHOD;
1518
import static com.getindata.connectors.http.internal.table.sink.HttpDynamicSinkConnectorOptions.URL;
1619

1720
public class HttpDynamicSinkTest {
1821

22+
@Test
23+
public void testAsSummaryString() {
24+
var mockFormat = new TestFormatFactory.EncodingFormatMock(",", ChangelogMode.insertOnly());
25+
26+
HttpDynamicSink dynamicSink = new HttpDynamicTableSinkBuilder()
27+
.setTableOptions(new Configuration())
28+
.setConsumedDataType(
29+
new AtomicDataType(new BooleanType(false)))
30+
.setEncodingFormat(mockFormat)
31+
.setFormatContentTypeMap(Map.of())
32+
.build();
33+
34+
assertThat(dynamicSink.asSummaryString()).isEqualTo("HttpSink");
35+
}
36+
1937
@Test
2038
public void copyEqualityTest() {
2139
var mockFormat = new TestFormatFactory.EncodingFormatMock(",", ChangelogMode.insertOnly());

0 commit comments

Comments
 (0)