diff --git a/client/pom.xml b/client/pom.xml
index b8d94bba..6bd936d6 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -5,7 +5,7 @@
io.split.client
java-client-parent
- 4.12.1
+ 4.13.0-rc1
java-client
jar
diff --git a/client/src/main/java/io/split/client/SplitClientConfig.java b/client/src/main/java/io/split/client/SplitClientConfig.java
index 2f29c171..ec4e49cf 100644
--- a/client/src/main/java/io/split/client/SplitClientConfig.java
+++ b/client/src/main/java/io/split/client/SplitClientConfig.java
@@ -6,6 +6,7 @@
import io.split.integrations.IntegrationsConfig;
import io.split.storages.enums.OperationMode;
import io.split.storages.enums.StorageMode;
+import io.split.service.HttpAuthScheme;
import org.apache.hc.core5.http.HttpHost;
import pluggable.CustomStorageWrapper;
@@ -91,6 +92,7 @@ public class SplitClientConfig {
private final HashSet _flagSetsFilter;
private final int _invalidSets;
private final CustomHeaderDecorator _customHeaderDecorator;
+ private final HttpAuthScheme _authScheme;
public static Builder builder() {
@@ -148,7 +150,8 @@ private SplitClientConfig(String endpoint,
ThreadFactory threadFactory,
HashSet flagSetsFilter,
int invalidSets,
- CustomHeaderDecorator customHeaderDecorator) {
+ CustomHeaderDecorator customHeaderDecorator,
+ HttpAuthScheme authScheme) {
_endpoint = endpoint;
_eventsEndpoint = eventsEndpoint;
_featuresRefreshRate = pollForFeatureChangesEveryNSeconds;
@@ -201,6 +204,7 @@ private SplitClientConfig(String endpoint,
_flagSetsFilter = flagSetsFilter;
_invalidSets = invalidSets;
_customHeaderDecorator = customHeaderDecorator;
+ _authScheme = authScheme;
Properties props = new Properties();
try {
@@ -408,6 +412,9 @@ public int getInvalidSets() {
public CustomHeaderDecorator customHeaderDecorator() {
return _customHeaderDecorator;
}
+ public HttpAuthScheme authScheme() {
+ return _authScheme;
+ }
public static final class Builder {
@@ -466,6 +473,7 @@ public static final class Builder {
private HashSet _flagSetsFilter = new HashSet<>();
private int _invalidSetsCount = 0;
private CustomHeaderDecorator _customHeaderDecorator = null;
+ private HttpAuthScheme _authScheme = null;
public Builder() {
}
@@ -960,6 +968,17 @@ public Builder customHeaderDecorator(CustomHeaderDecorator customHeaderDecorator
return this;
}
+ /**
+ * Authentication Scheme
+ *
+ * @param authScheme
+ * @return this builder
+ */
+ public Builder authScheme(HttpAuthScheme authScheme) {
+ _authScheme = authScheme;
+ return this;
+ }
+
/**
* Thread Factory
*
@@ -1120,7 +1139,8 @@ public SplitClientConfig build() {
_threadFactory,
_flagSetsFilter,
_invalidSetsCount,
- _customHeaderDecorator);
+ _customHeaderDecorator,
+ _authScheme);
}
}
}
\ No newline at end of file
diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java
index a783b144..68eeba67 100644
--- a/client/src/main/java/io/split/client/SplitFactoryImpl.java
+++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java
@@ -57,8 +57,10 @@
import io.split.engine.segments.SegmentChangeFetcher;
import io.split.engine.segments.SegmentSynchronizationTaskImp;
import io.split.integrations.IntegrationsConfig;
+import io.split.service.HttpAuthScheme;
import io.split.service.SplitHttpClient;
import io.split.service.SplitHttpClientImpl;
+import io.split.service.SplitHttpClientKerberosImpl;
import io.split.storages.SegmentCache;
import io.split.storages.SegmentCacheConsumer;
import io.split.storages.SegmentCacheProducer;
@@ -525,6 +527,13 @@ private static SplitHttpClient buildSplitHttpClient(String apiToken, SplitClient
httpClientbuilder = setupProxy(httpClientbuilder, config);
}
+ if (config.authScheme() == HttpAuthScheme.KERBEROS) {
+ return SplitHttpClientKerberosImpl.create(
+ requestDecorator,
+ apiToken,
+ sdkMetadata);
+
+ }
return SplitHttpClientImpl.create(httpClientbuilder.build(),
requestDecorator,
apiToken,
diff --git a/client/src/main/java/io/split/service/HttpAuthScheme.java b/client/src/main/java/io/split/service/HttpAuthScheme.java
new file mode 100644
index 00000000..1753f736
--- /dev/null
+++ b/client/src/main/java/io/split/service/HttpAuthScheme.java
@@ -0,0 +1,5 @@
+package io.split.service;
+
+public enum HttpAuthScheme {
+ KERBEROS
+}
diff --git a/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java
new file mode 100644
index 00000000..82dd9a35
--- /dev/null
+++ b/client/src/main/java/io/split/service/SplitHttpClientKerberosImpl.java
@@ -0,0 +1,211 @@
+package io.split.service;
+
+import io.split.client.RequestDecorator;
+import io.split.client.dtos.SplitHttpResponse;
+import io.split.client.utils.SDKMetadata;
+import io.split.engine.common.FetchOptions;
+
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class SplitHttpClientKerberosImpl implements SplitHttpClient {
+
+ private static final Logger _log = LoggerFactory.getLogger(SplitHttpClientKerberosImpl.class);
+ private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control";
+ private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache";
+ private static final String HEADER_API_KEY = "Authorization";
+ private static final String HEADER_CLIENT_KEY = "SplitSDKClientKey";
+ private static final String HEADER_CLIENT_MACHINE_NAME = "SplitSDKMachineName";
+ private static final String HEADER_CLIENT_MACHINE_IP = "SplitSDKMachineIP";
+ private static final String HEADER_CLIENT_VERSION = "SplitSDKVersion";
+
+ private final RequestDecorator _requestDecorator;
+ private final String _apikey;
+ private final SDKMetadata _metadata;
+
+ public static SplitHttpClientKerberosImpl create(RequestDecorator requestDecorator,
+ String apikey,
+ SDKMetadata metadata) {
+ return new SplitHttpClientKerberosImpl(requestDecorator, apikey, metadata);
+ }
+
+ SplitHttpClientKerberosImpl(RequestDecorator requestDecorator,
+ String apikey,
+ SDKMetadata metadata) {
+ _requestDecorator = requestDecorator;
+ _apikey = apikey;
+ _metadata = metadata;
+ }
+
+ public synchronized SplitHttpResponse get(URI uri, FetchOptions options, Map> additionalHeaders) {
+ HttpURLConnection getHttpURLConnection = null;
+ try {
+ getHttpURLConnection = (HttpURLConnection) uri.toURL().openConnection();
+ return doGet(getHttpURLConnection, options, additionalHeaders);
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e);
+ } finally {
+ try {
+ if (getHttpURLConnection != null) {
+ getHttpURLConnection.disconnect();
+ }
+ } catch (Exception e) {
+ _log.error(String.format("Could not close HTTP URL Connection: %s", e), e);
+ }
+ }
+ }
+ public SplitHttpResponse doGet(HttpURLConnection getHttpURLConnection, FetchOptions options, Map> additionalHeaders) {
+ try {
+ getHttpURLConnection.setRequestMethod("GET");
+ setBasicHeaders(getHttpURLConnection);
+ setAdditionalAndDecoratedHeaders(getHttpURLConnection, additionalHeaders);
+
+ if (options.cacheControlHeadersEnabled()) {
+ getHttpURLConnection.setRequestProperty(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE);
+ }
+
+ _log.debug(String.format("Request Headers: %s", getHttpURLConnection.getRequestProperties()));
+
+ int responseCode = getHttpURLConnection.getResponseCode();
+
+ if (_log.isDebugEnabled()) {
+ _log.debug(String.format("[%s] %s. Status code: %s",
+ getHttpURLConnection.getRequestMethod(),
+ getHttpURLConnection.getURL().toString(),
+ responseCode));
+ }
+
+ String statusMessage = "";
+ if (responseCode < HttpURLConnection.HTTP_OK || responseCode >= HttpURLConnection.HTTP_MULT_CHOICE) {
+ _log.warn(String.format("Response status was: %s. Reason: %s", responseCode,
+ getHttpURLConnection.getResponseMessage()));
+ statusMessage = getHttpURLConnection.getResponseMessage();
+ }
+
+ InputStreamReader inputStreamReader = new InputStreamReader(getHttpURLConnection.getInputStream());
+ BufferedReader br = new BufferedReader(inputStreamReader);
+ String strCurrentLine;
+ StringBuilder bld = new StringBuilder();
+ while ((strCurrentLine = br.readLine()) != null) {
+ bld.append(strCurrentLine);
+ }
+ String responseBody = bld.toString();
+ inputStreamReader.close();
+ return new SplitHttpResponse(responseCode,
+ statusMessage,
+ responseBody,
+ getResponseHeaders(getHttpURLConnection));
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e);
+ }
+ }
+
+ public synchronized SplitHttpResponse post(URI uri, HttpEntity entity, Map> additionalHeaders) throws IOException {
+ HttpURLConnection postHttpURLConnection = null;
+ try {
+ postHttpURLConnection = (HttpURLConnection) uri.toURL().openConnection();
+ return doPost(postHttpURLConnection, entity, additionalHeaders);
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format("Problem in http post operation: %s", e), e);
+ } finally {
+ try {
+ if (postHttpURLConnection != null) {
+ postHttpURLConnection.disconnect();
+ }
+ } catch (Exception e) {
+ _log.error(String.format("Could not close URL Connection: %s", e), e);
+ }
+ }
+ }
+
+ public SplitHttpResponse doPost(HttpURLConnection postHttpURLConnection,
+ HttpEntity entity,
+ Map> additionalHeaders) {
+ try {
+ postHttpURLConnection.setRequestMethod("POST");
+ setBasicHeaders(postHttpURLConnection);
+ setAdditionalAndDecoratedHeaders(postHttpURLConnection, additionalHeaders);
+
+ postHttpURLConnection.setRequestProperty("Accept-Encoding", "gzip");
+ postHttpURLConnection.setRequestProperty("Content-Type", "application/json");
+ _log.debug(String.format("Request Headers: %s", postHttpURLConnection.getRequestProperties()));
+
+ postHttpURLConnection.setDoOutput(true);
+ String postBody = EntityUtils.toString(entity);
+ OutputStream os = postHttpURLConnection.getOutputStream();
+ os.write(postBody.getBytes(StandardCharsets.UTF_8));
+ os.flush();
+ os.close();
+ _log.debug(String.format("Posting: %s", postBody));
+
+ int responseCode = postHttpURLConnection.getResponseCode();
+ String statusMessage = "";
+ if (responseCode < HttpURLConnection.HTTP_OK || responseCode >= HttpURLConnection.HTTP_MULT_CHOICE) {
+ statusMessage = postHttpURLConnection.getResponseMessage();
+ _log.warn(String.format("Response status was: %s. Reason: %s", responseCode,
+ statusMessage));
+ }
+ return new SplitHttpResponse(responseCode, statusMessage, "", getResponseHeaders(postHttpURLConnection));
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format("Problem in http post operation: %s", e), e);
+ }
+ }
+
+ private void setBasicHeaders(HttpURLConnection urlConnection) {
+ urlConnection.setRequestProperty(HEADER_API_KEY, "Bearer " + _apikey);
+ urlConnection.setRequestProperty(HEADER_CLIENT_VERSION, _metadata.getSdkVersion());
+ urlConnection.setRequestProperty(HEADER_CLIENT_MACHINE_IP, _metadata.getMachineIp());
+ urlConnection.setRequestProperty(HEADER_CLIENT_MACHINE_NAME, _metadata.getMachineName());
+ urlConnection.setRequestProperty(HEADER_CLIENT_KEY, _apikey.length() > 4
+ ? _apikey.substring(_apikey.length() - 4)
+ : _apikey);
+ }
+
+ private void setAdditionalAndDecoratedHeaders(HttpURLConnection urlConnection, Map> additionalHeaders) {
+ if (additionalHeaders != null) {
+ for (Map.Entry> entry : additionalHeaders.entrySet()) {
+ for (String value : entry.getValue()) {
+ urlConnection.setRequestProperty(entry.getKey(), value);
+ }
+ }
+ }
+ HttpRequest request = new HttpGet("");
+ _requestDecorator.decorateHeaders(request);
+ for (Header header : request.getHeaders()) {
+ urlConnection.setRequestProperty(header.getName(), header.getValue());
+ }
+ }
+
+ private Header[] getResponseHeaders(HttpURLConnection urlConnection) {
+ List responseHeaders = new ArrayList<>();
+ Map> map = urlConnection.getHeaderFields();
+ for (Map.Entry> entry : map.entrySet()) {
+ if (entry.getKey() != null) {
+ BasicHeader responseHeader = new BasicHeader(entry.getKey(), entry.getValue());
+ responseHeaders.add(responseHeader);
+ }
+ }
+ return responseHeaders.toArray(new Header[0]);
+ }
+ @Override
+ public void close() throws IOException {
+ // Added for compatibility with HttpSplitClient, no action needed as URLConnection objects are closed.
+ }
+}
diff --git a/client/src/test/java/io/split/client/SplitClientConfigTest.java b/client/src/test/java/io/split/client/SplitClientConfigTest.java
index 1b640071..86b18541 100644
--- a/client/src/test/java/io/split/client/SplitClientConfigTest.java
+++ b/client/src/test/java/io/split/client/SplitClientConfigTest.java
@@ -6,6 +6,7 @@
import io.split.client.impressions.ImpressionsManager;
import io.split.client.dtos.RequestContext;
import io.split.integrations.IntegrationsConfig;
+import io.split.service.HttpAuthScheme;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
@@ -254,4 +255,16 @@ public Map> getHeaderOverrides(RequestContext context) {
Assert.assertNull(config2.customHeaderDecorator());
}
+
+ @Test
+ public void checkExpectedAuthScheme() {
+ SplitClientConfig cfg = SplitClientConfig.builder()
+ .authScheme(HttpAuthScheme.KERBEROS)
+ .build();
+ Assert.assertEquals(HttpAuthScheme.KERBEROS, cfg.authScheme());
+
+ cfg = SplitClientConfig.builder()
+ .build();
+ Assert.assertEquals(null, cfg.authScheme());
+ }
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/client/SplitFactoryImplTest.java b/client/src/test/java/io/split/client/SplitFactoryImplTest.java
index 2d548f9e..57441ced 100644
--- a/client/src/test/java/io/split/client/SplitFactoryImplTest.java
+++ b/client/src/test/java/io/split/client/SplitFactoryImplTest.java
@@ -2,7 +2,10 @@
import io.split.client.impressions.ImpressionsManager;
import io.split.client.utils.FileTypeEnum;
+import io.split.client.utils.SDKMetadata;
import io.split.integrations.IntegrationsConfig;
+import io.split.service.HttpAuthScheme;
+import io.split.service.SplitHttpClientKerberosImpl;
import io.split.storages.enums.OperationMode;
import io.split.storages.pluggable.domain.UserStorageWrapper;
import io.split.telemetry.storage.TelemetryStorage;
@@ -22,6 +25,8 @@
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
+import static io.split.client.SplitClientConfig.splitSdkVersion;
+
public class SplitFactoryImplTest extends TestCase {
public static final String API_KEY ="29013ionasdasd09u";
public static final String ENDPOINT = "https://sdk.split-stage.io";
@@ -344,4 +349,19 @@ public void testLocalhosJsonInputStreamNullAndFileTypeNull() throws URISyntaxExc
Object splitChangeFetcher = method.invoke(splitFactory, splitClientConfig);
Assert.assertTrue(splitChangeFetcher instanceof LegacyLocalhostSplitChangeFetcher);
}
+
+ @Test
+ public void testFactoryKerberosInstance() throws URISyntaxException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ SplitClientConfig splitClientConfig = SplitClientConfig.builder()
+ .setBlockUntilReadyTimeout(10000)
+ .authScheme(HttpAuthScheme.KERBEROS)
+ .build();
+ SplitFactoryImpl splitFactory = new SplitFactoryImpl("asdf", splitClientConfig);
+
+ Method method = SplitFactoryImpl.class.getDeclaredMethod("buildSplitHttpClient", String.class,
+ SplitClientConfig.class, SDKMetadata.class, RequestDecorator.class);
+ method.setAccessible(true);
+ Object SplitHttpClient = method.invoke(splitFactory, "asdf", splitClientConfig, new SDKMetadata(splitSdkVersion, "", ""), new RequestDecorator(null));
+ Assert.assertTrue(SplitHttpClient instanceof SplitHttpClientKerberosImpl);
+ }
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java b/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java
new file mode 100644
index 00000000..4f814c31
--- /dev/null
+++ b/client/src/test/java/io/split/service/HttpSplitClientKerberosTest.java
@@ -0,0 +1,214 @@
+package io.split.service;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+import io.split.TestHelper;
+import io.split.client.RequestDecorator;
+import io.split.client.dtos.*;
+import io.split.client.impressions.Impression;
+import io.split.client.utils.Json;
+import io.split.client.utils.SDKMetadata;
+import io.split.client.utils.Utils;
+import io.split.engine.common.FetchOptions;
+
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.*;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.net.*;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+public class HttpSplitClientKerberosTest {
+
+ @Test
+ public void testGetWithSpecialCharacters() throws URISyntaxException, IOException {
+ Map> responseHeaders = new HashMap>();
+ responseHeaders.put((HttpHeaders.VIA), Arrays.asList("HTTP/1.1 s_proxy_rio1"));
+
+ HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class);
+ when(mockHttpURLConnection.getHeaderFields()).thenReturn(responseHeaders);
+
+ RequestDecorator decorator = new RequestDecorator(null);
+
+ Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+ ByteArrayInputStream stubInputStream = new ByteArrayInputStream(Files.asCharSource(
+ new File("src/test/resources/split-change-special-characters.json"), Charsets.UTF_8).read().getBytes(Charsets.UTF_8));
+ when(mockHttpURLConnection.getInputStream()).thenReturn(stubInputStream);
+
+ SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata());
+
+ Map> additionalHeaders = Collections.singletonMap("AdditionalHeader",
+ Collections.singletonList("add"));
+
+ SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doGet(mockHttpURLConnection,
+ new FetchOptions.Builder().cacheControlHeaders(true).build(), additionalHeaders);
+ SplitChange change = Json.fromJson(splitHttpResponse.body(), SplitChange.class);
+
+ Header[] headers = splitHttpResponse.responseHeaders();
+ assertThat(headers[0].getName(), is(equalTo("Via")));
+ assertThat(headers[0].getValue(), is(equalTo("[HTTP/1.1 s_proxy_rio1]")));
+ Assert.assertNotNull(change);
+ Assert.assertEquals(1, change.splits.size());
+ Assert.assertNotNull(change.splits.get(0));
+
+ Split split = change.splits.get(0);
+ Map configs = split.configurations;
+ Assert.assertEquals(2, configs.size());
+ Assert.assertEquals("{\"test\": \"blue\",\"grüne Straße\": 13}", configs.get("on"));
+ Assert.assertEquals("{\"test\": \"blue\",\"size\": 15}", configs.get("off"));
+ Assert.assertEquals(2, split.sets.size());
+ }
+
+ @Test
+ public void testGetParameters() throws URISyntaxException, MalformedURLException {
+ URI uri = new URI("https://api.split.io/splitChanges?since=1234567");
+ FetchOptions options = new FetchOptions.Builder().cacheControlHeaders(true).build();
+ SplitHttpClientKerberosImpl splitHtpClientKerberos = Mockito.mock(SplitHttpClientKerberosImpl.class);
+ when(splitHtpClientKerberos.get(uri, options, null)).thenCallRealMethod();
+
+ SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.get(uri, options, null);
+
+ ArgumentCaptor connectionCaptor = ArgumentCaptor.forClass(HttpURLConnection.class);
+ ArgumentCaptor optionsCaptor = ArgumentCaptor.forClass(FetchOptions.class);
+ ArgumentCaptor headersCaptor = ArgumentCaptor.forClass(HashMap.class);
+ verify(splitHtpClientKerberos).doGet(connectionCaptor.capture(), optionsCaptor.capture(), headersCaptor.capture());
+
+ assertThat(connectionCaptor.getValue().getRequestMethod(), is(equalTo("GET")));
+ assertThat(connectionCaptor.getValue().getURL().toString(), is(equalTo(new URL("https://api.split.io/splitChanges?since=1234567").toString())));
+
+ assertThat(optionsCaptor.getValue().cacheControlHeadersEnabled(), is(equalTo(true)));
+ }
+
+ @Test
+ public void testGetError() throws URISyntaxException, IOException {
+ HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class);
+ RequestDecorator decorator = new RequestDecorator(null);
+
+ Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_INTERNAL_ERROR);
+ ByteArrayInputStream stubInputStream = new ByteArrayInputStream(Files.asCharSource(
+ new File("src/test/resources/split-change-special-characters.json"), Charsets.UTF_8).read().getBytes(Charsets.UTF_8));
+ when(mockHttpURLConnection.getInputStream()).thenReturn(stubInputStream);
+
+ SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata());
+ SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doGet(mockHttpURLConnection,
+ new FetchOptions.Builder().cacheControlHeaders(true).build(), null);
+ Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, (long) splitHttpResponse.statusCode());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testException() throws URISyntaxException, InvocationTargetException, NoSuchMethodException,
+ IllegalAccessException, IOException {
+ HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class);
+ RequestDecorator decorator = null;
+
+ Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_INTERNAL_ERROR);
+ ByteArrayInputStream stubInputStream = new ByteArrayInputStream(Files.asCharSource(
+ new File("src/test/resources/split-change-special-characters.json"), Charsets.UTF_8).read().getBytes(Charsets.UTF_8));
+ when(mockHttpURLConnection.getInputStream()).thenReturn(stubInputStream);
+
+ SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata());
+ SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doGet(mockHttpURLConnection,
+ new FetchOptions.Builder().cacheControlHeaders(true).build(), null);
+ }
+
+ @Test
+ public void testPost() throws URISyntaxException, IOException, ParseException {
+ HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class);
+ RequestDecorator decorator = new RequestDecorator(null);
+ Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+
+ SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata());
+
+ // Send impressions
+ List toSend = Arrays.asList(new TestImpressions("t1", Arrays.asList(
+ KeyImpression.fromImpression(new Impression("k1", null, "t1", "on", 123L, "r1", 456L, null)),
+ KeyImpression.fromImpression(new Impression("k2", null, "t1", "on", 123L, "r1", 456L, null)),
+ KeyImpression.fromImpression(new Impression("k3", null, "t1", "on", 123L, "r1", 456L, null)))),
+ new TestImpressions("t2", Arrays.asList(
+ KeyImpression.fromImpression(new Impression("k1", null, "t2", "on", 123L, "r1", 456L, null)),
+ KeyImpression.fromImpression(new Impression("k2", null, "t2", "on", 123L, "r1", 456L, null)),
+ KeyImpression.fromImpression(new Impression("k3", null, "t2", "on", 123L, "r1", 456L, null)))));
+
+ Map> additionalHeaders = Collections.singletonMap("SplitSDKImpressionsMode",
+ Collections.singletonList("OPTIMIZED"));
+ when(mockHttpURLConnection.getHeaderFields()).thenReturn(additionalHeaders);
+
+ ByteArrayOutputStream mockOs = Mockito.mock( ByteArrayOutputStream.class);
+ when(mockHttpURLConnection.getOutputStream()).thenReturn(mockOs);
+
+ SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doPost(mockHttpURLConnection, Utils.toJsonEntity(toSend),
+ additionalHeaders);
+
+ // Capture outgoing request and validate it
+ ArgumentCaptor captor = ArgumentCaptor.forClass(byte[].class);
+ verify(mockOs).write(captor.capture());
+ String postBody = EntityUtils.toString(Utils.toJsonEntity(toSend));
+ assertThat(captor.getValue(), is(equalTo(postBody.getBytes(StandardCharsets.UTF_8))));
+
+ Header[] headers = splitHttpResponse.responseHeaders();
+ assertThat(headers[0].getName(), is(equalTo("SplitSDKImpressionsMode")));
+ assertThat(headers[0].getValue(), is(equalTo("[OPTIMIZED]")));
+
+ Assert.assertEquals(200, (long) splitHttpResponse.statusCode());
+ }
+
+ @Test
+ public void testPotParameters() throws URISyntaxException, IOException {
+ URI uri = new URI("https://kubernetesturl.com/split/api/testImpressions/bulk");
+ SplitHttpClientKerberosImpl splitHtpClientKerberos = Mockito.mock(SplitHttpClientKerberosImpl.class);
+ when(splitHtpClientKerberos.post(uri, null, null)).thenCallRealMethod();
+
+ SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.post(uri, null, null);
+
+ ArgumentCaptor connectionCaptor = ArgumentCaptor.forClass(HttpURLConnection.class);
+ ArgumentCaptor entityCaptor = ArgumentCaptor.forClass(HttpEntity.class);
+ ArgumentCaptor headersCaptor = ArgumentCaptor.forClass(HashMap.class);
+ verify(splitHtpClientKerberos).doPost(connectionCaptor.capture(), entityCaptor.capture(), headersCaptor.capture());
+
+ assertThat(connectionCaptor.getValue().getURL().toString(), is(equalTo(new URL("https://kubernetesturl.com/split/api/testImpressions/bulk").toString())));
+ }
+
+ @Test
+ public void testPosttError() throws URISyntaxException, IOException {
+ HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class);
+ RequestDecorator decorator = new RequestDecorator(null);
+ ByteArrayOutputStream mockOs = Mockito.mock( ByteArrayOutputStream.class);
+ Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_INTERNAL_ERROR);
+ when(mockHttpURLConnection.getOutputStream()).thenReturn(mockOs);
+
+ SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata());
+ SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doPost(mockHttpURLConnection,
+ Utils.toJsonEntity(Arrays.asList(new String[] { "A", "B", "C", "D" })), null);
+
+ Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, (long) splitHttpResponse.statusCode());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testPosttException() throws URISyntaxException, IOException {
+ HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class);
+ RequestDecorator decorator = null;
+ Mockito.when(mockHttpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+
+ SplitHttpClientKerberosImpl splitHtpClientKerberos = SplitHttpClientKerberosImpl.create(decorator, "qwerty", metadata());
+ SplitHttpResponse splitHttpResponse = splitHtpClientKerberos.doPost(mockHttpURLConnection,
+ Utils.toJsonEntity(Arrays.asList(new String[] { "A", "B", "C", "D" })), null);
+ }
+
+ private SDKMetadata metadata() {
+ return new SDKMetadata("java-1.2.3", "1.2.3.4", "someIP");
+ }
+
+}
diff --git a/pluggable-storage/pom.xml b/pluggable-storage/pom.xml
index f643564f..39128cb9 100644
--- a/pluggable-storage/pom.xml
+++ b/pluggable-storage/pom.xml
@@ -6,7 +6,7 @@
java-client-parent
io.split.client
- 4.12.1
+ 4.13.0-rc1
2.1.0
diff --git a/pom.xml b/pom.xml
index 3dc7d33f..bf2f4cb0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
io.split.client
java-client-parent
- 4.12.1
+ 4.13.0-rc1
diff --git a/redis-wrapper/pom.xml b/redis-wrapper/pom.xml
index a8ce195f..e0a3c838 100644
--- a/redis-wrapper/pom.xml
+++ b/redis-wrapper/pom.xml
@@ -6,7 +6,7 @@
java-client-parent
io.split.client
- 4.12.1
+ 4.13.0-rc1
redis-wrapper
3.1.0
diff --git a/testing/pom.xml b/testing/pom.xml
index 2240c94d..556d98af 100644
--- a/testing/pom.xml
+++ b/testing/pom.xml
@@ -5,7 +5,7 @@
io.split.client
java-client-parent
- 4.12.1
+ 4.13.0-rc1
java-client-testing
jar