From cf1bd48625392871c93214d3c3e98ab98115bda4 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Tue, 12 Mar 2024 13:32:40 -0700 Subject: [PATCH 1/6] added httpclient wrapper --- .../java/io/split/client/SplitHttpClient.java | 113 ++++++++++++++ .../io/split/client/HttpSplitClientTest.java | 140 ++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 client/src/main/java/io/split/client/SplitHttpClient.java create mode 100644 client/src/test/java/io/split/client/HttpSplitClientTest.java diff --git a/client/src/main/java/io/split/client/SplitHttpClient.java b/client/src/main/java/io/split/client/SplitHttpClient.java new file mode 100644 index 00000000..758817f2 --- /dev/null +++ b/client/src/main/java/io/split/client/SplitHttpClient.java @@ -0,0 +1,113 @@ +package io.split.client; + +import io.split.client.exceptions.UriTooLongException; +import io.split.client.utils.Utils; +import io.split.engine.common.FetchOptions; +import io.split.telemetry.domain.enums.HttpParamsWrapper; +import io.split.telemetry.storage.TelemetryRuntimeProducer; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class SplitHttpClient { + private static final Logger _log = LoggerFactory.getLogger(SplitHttpClient.class); + private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control"; + private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache"; + private final CloseableHttpClient _client; + private final RequestDecorator _requestDecorator; + private final TelemetryRuntimeProducer _telemetryRuntimeProducer; + + public static SplitHttpClient create(CloseableHttpClient client, TelemetryRuntimeProducer telemetryRuntimeProducer, RequestDecorator requestDecorator) + throws URISyntaxException { + return new SplitHttpClient(client, telemetryRuntimeProducer, requestDecorator); + } + + private SplitHttpClient(CloseableHttpClient client, TelemetryRuntimeProducer telemetryRuntimeProducer, RequestDecorator requestDecorator) { + _client = client; + _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); + _requestDecorator = requestDecorator; + } + + public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryParamsWrapper) { + long start = System.currentTimeMillis(); + + CloseableHttpResponse response = null; + + try { + HttpGet request = new HttpGet(uri); + if(options.cacheControlHeadersEnabled()) { + request.setHeader(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE); + } + request = (HttpGet) _requestDecorator.decorateHeaders(request); + + response = _client.execute(request); + + int statusCode = response.getCode(); + + if (_log.isDebugEnabled()) { + _log.debug(String.format("[%s] %s. Status code: %s", request.getMethod(), uri.toURL(), statusCode)); + } + + if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) { + _telemetryRuntimeProducer.recordSyncError(telemetryParamsWrapper.getResourceEnum(), statusCode); + if (statusCode == HttpStatus.SC_REQUEST_URI_TOO_LONG) { + _log.error("The amount of flag sets provided are big causing uri length error."); + throw new UriTooLongException(String.format("Status code: %s. Message: %s", statusCode, response.getReasonPhrase())); + } + _log.warn(String.format("Response status was: %s. Reason: %s", statusCode , response.getReasonPhrase())); + throw new IllegalStateException(String.format("Http get received non-successful return code %s", statusCode)); + } + + return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + } catch (Exception e) { + throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e); + } finally { + _telemetryRuntimeProducer.recordSyncLatency(telemetryParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis()-start); + Utils.forceClose(response); + } + } + + public void post(URI uri, HttpEntity entity, Map additionalHeaders, HttpParamsWrapper telemetryParamsWrapper) throws IOException { + CloseableHttpResponse response = null; + long initTime = System.currentTimeMillis(); + try { + HttpPost request = new HttpPost(uri); + if (additionalHeaders != null) { + for (Map.Entry entry : additionalHeaders.entrySet()) { + request.addHeader(entry.getKey().toString(), entry.getValue()); + } + } + request.setEntity(entity); + request = (HttpPost) _requestDecorator.decorateHeaders(request); + + response = _client.execute(request); + + int status = response.getCode(); + + if (status < HttpStatus.SC_OK || status >= HttpStatus.SC_MULTIPLE_CHOICES) { + _telemetryRuntimeProducer.recordSyncError(telemetryParamsWrapper.getResourceEnum(), status); + _log.warn(String.format("Response status was: %s. Reason: %s", status, response.getReasonPhrase())); + } + _telemetryRuntimeProducer.recordSuccessfulSync(telemetryParamsWrapper.getLastSynchronizationRecordsEnum(), System.currentTimeMillis()); + } catch (Exception e) { + throw new IOException(String.format("Problem in http post operation: %s", e), e); + } finally { + _telemetryRuntimeProducer.recordSyncLatency(telemetryParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis() - initTime); + Utils.forceClose(response); + } + } +} diff --git a/client/src/test/java/io/split/client/HttpSplitClientTest.java b/client/src/test/java/io/split/client/HttpSplitClientTest.java new file mode 100644 index 00000000..ecfb92eb --- /dev/null +++ b/client/src/test/java/io/split/client/HttpSplitClientTest.java @@ -0,0 +1,140 @@ +package io.split.client; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import io.split.TestHelper; +import io.split.client.dtos.KeyImpression; +import io.split.client.dtos.Split; +import io.split.client.dtos.SplitChange; +import io.split.client.dtos.TestImpressions; +import io.split.client.impressions.Impression; +import io.split.client.utils.Json; +import io.split.client.utils.Utils; +import io.split.engine.common.FetchOptions; +import io.split.telemetry.storage.InMemoryTelemetryStorage; +import io.split.telemetry.storage.TelemetryStorage; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.classic.methods.HttpUriRequest; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import io.split.telemetry.domain.enums.HttpParamsWrapper; +import org.apache.hc.core5.http.*; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.mockito.Mockito.verify; + +public class HttpSplitClientTest { + private static final TelemetryStorage TELEMETRY_STORAGE = Mockito.mock(InMemoryTelemetryStorage.class); + + @Test + public void testGetWithSpecialCharacters() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException { + URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); + CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_OK); + RequestDecorator decorator = new RequestDecorator(null); + + SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClientMock, TELEMETRY_STORAGE, decorator); + String change_raw = splitHtpClient.get(rootTarget, + new FetchOptions.Builder().cacheControlHeaders(true).build(), + HttpParamsWrapper.SPLITS + ); + SplitChange change = Json.fromJson(change_raw, SplitChange.class); + + 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(expected = IllegalStateException.class) + public void testGetError() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException { + URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); + CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); + RequestDecorator decorator = new RequestDecorator(null); + + SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClientMock, TELEMETRY_STORAGE, decorator); + String change_raw = splitHtpClient.get(rootTarget, + new FetchOptions.Builder().cacheControlHeaders(true).build(), + HttpParamsWrapper.SPLITS + ); + } + + @Test + public void testPost() throws URISyntaxException, IOException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + URI rootTarget = URI.create("https://kubernetesturl.com/split"); + + // Setup response mock + CloseableHttpClient httpClient = TestHelper.mockHttpClient("", HttpStatus.SC_OK); + RequestDecorator decorator = new RequestDecorator(null); + + SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClient, TELEMETRY_STORAGE, decorator); + + // 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 = new HashMap<>(); + additionalHeaders.put("SplitSDKImpressionsMode", "any"); + splitHtpClient.post(rootTarget, Utils.toJsonEntity(toSend), additionalHeaders, HttpParamsWrapper.IMPRESSIONS); + + // Capture outgoing request and validate it + ArgumentCaptor captor = ArgumentCaptor.forClass(HttpUriRequest.class); + verify(httpClient).execute(captor.capture()); + HttpUriRequest request = captor.getValue(); + assertThat(request.getUri(), is(equalTo(URI.create("https://kubernetesturl.com/split/api/testImpressions/bulk")))); + assertThat(request.getHeaders().length, is(1)); + assertThat(request.getFirstHeader("SplitSDKImpressionsMode").getValue(), is(equalTo("OPTIMIZED"))); + assertThat(request, instanceOf(HttpPost.class)); + HttpPost asPostRequest = (HttpPost) request; + InputStreamReader reader = new InputStreamReader(asPostRequest.getEntity().getContent()); + Gson gson = new Gson(); + List payload = gson.fromJson(reader, new TypeToken>() { }.getType()); + assertThat(payload.size(), is(equalTo(2))); + } + + @Test + public void testPosttNoExceptionOnHttpErrorCode() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException { + URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); + CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); + RequestDecorator decorator = new RequestDecorator(null); + + SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClientMock, TELEMETRY_STORAGE, decorator); + splitHtpClient.post(rootTarget, Utils.toJsonEntity(Arrays.asList( new String[] { "A", "B", "C", "D" })), null, HttpParamsWrapper.IMPRESSIONS); + } + + @Test(expected = IOException.class) + public void testPosttException() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException { + URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); + CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); + + SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClientMock, TELEMETRY_STORAGE, null); + splitHtpClient.post(rootTarget, Utils.toJsonEntity(Arrays.asList( new String[] { "A", "B", "C", "D" })), null, HttpParamsWrapper.IMPRESSIONS); + } +} \ No newline at end of file From a372032d86a84d249bbb57b0c02f114bfe81fd6f Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Tue, 12 Mar 2024 13:45:17 -0700 Subject: [PATCH 2/6] polish --- .../java/io/split/client/SplitHttpClient.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitHttpClient.java b/client/src/main/java/io/split/client/SplitHttpClient.java index 758817f2..71c88d1a 100644 --- a/client/src/main/java/io/split/client/SplitHttpClient.java +++ b/client/src/main/java/io/split/client/SplitHttpClient.java @@ -31,12 +31,18 @@ public final class SplitHttpClient { private final RequestDecorator _requestDecorator; private final TelemetryRuntimeProducer _telemetryRuntimeProducer; - public static SplitHttpClient create(CloseableHttpClient client, TelemetryRuntimeProducer telemetryRuntimeProducer, RequestDecorator requestDecorator) - throws URISyntaxException { + public static SplitHttpClient create( + CloseableHttpClient client, + TelemetryRuntimeProducer telemetryRuntimeProducer, + RequestDecorator requestDecorator + ) throws URISyntaxException { return new SplitHttpClient(client, telemetryRuntimeProducer, requestDecorator); } - private SplitHttpClient(CloseableHttpClient client, TelemetryRuntimeProducer telemetryRuntimeProducer, RequestDecorator requestDecorator) { + private SplitHttpClient + (CloseableHttpClient client, + TelemetryRuntimeProducer telemetryRuntimeProducer, + RequestDecorator requestDecorator) { _client = client; _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); _requestDecorator = requestDecorator; @@ -81,7 +87,11 @@ public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryPara } } - public void post(URI uri, HttpEntity entity, Map additionalHeaders, HttpParamsWrapper telemetryParamsWrapper) throws IOException { + public void post + (URI uri, + HttpEntity entity, + Map additionalHeaders, + HttpParamsWrapper telemetryParamsWrapper) throws IOException { CloseableHttpResponse response = null; long initTime = System.currentTimeMillis(); try { From 5ae5405e96cb9315a75ab69c66679d91cf110b2c Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Tue, 12 Mar 2024 14:20:44 -0700 Subject: [PATCH 3/6] fixed tests and added splithttpclient interface --- .../java/io/split/client/SplitHttpClient.java | 113 +--------------- .../io/split/client/SplitHttpClientImpl.java | 123 ++++++++++++++++++ .../io/split/client/HttpSplitClientTest.java | 14 +- 3 files changed, 134 insertions(+), 116 deletions(-) create mode 100644 client/src/main/java/io/split/client/SplitHttpClientImpl.java diff --git a/client/src/main/java/io/split/client/SplitHttpClient.java b/client/src/main/java/io/split/client/SplitHttpClient.java index 71c88d1a..2ab1a38e 100644 --- a/client/src/main/java/io/split/client/SplitHttpClient.java +++ b/client/src/main/java/io/split/client/SplitHttpClient.java @@ -1,123 +1,18 @@ package io.split.client; -import io.split.client.exceptions.UriTooLongException; -import io.split.client.utils.Utils; import io.split.engine.common.FetchOptions; import io.split.telemetry.domain.enums.HttpParamsWrapper; -import io.split.telemetry.storage.TelemetryRuntimeProducer; -import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.classic.methods.HttpPost; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.apache.hc.core5.http.HttpEntity; -import org.apache.hc.core5.http.HttpStatus; -import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.hc.core5.http.HttpEntity; import java.io.IOException; import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.util.Map; -import static com.google.common.base.Preconditions.checkNotNull; - -public final class SplitHttpClient { - private static final Logger _log = LoggerFactory.getLogger(SplitHttpClient.class); - private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control"; - private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache"; - private final CloseableHttpClient _client; - private final RequestDecorator _requestDecorator; - private final TelemetryRuntimeProducer _telemetryRuntimeProducer; - - public static SplitHttpClient create( - CloseableHttpClient client, - TelemetryRuntimeProducer telemetryRuntimeProducer, - RequestDecorator requestDecorator - ) throws URISyntaxException { - return new SplitHttpClient(client, telemetryRuntimeProducer, requestDecorator); - } - - private SplitHttpClient - (CloseableHttpClient client, - TelemetryRuntimeProducer telemetryRuntimeProducer, - RequestDecorator requestDecorator) { - _client = client; - _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); - _requestDecorator = requestDecorator; - } - - public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryParamsWrapper) { - long start = System.currentTimeMillis(); - - CloseableHttpResponse response = null; - - try { - HttpGet request = new HttpGet(uri); - if(options.cacheControlHeadersEnabled()) { - request.setHeader(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE); - } - request = (HttpGet) _requestDecorator.decorateHeaders(request); - - response = _client.execute(request); - - int statusCode = response.getCode(); - - if (_log.isDebugEnabled()) { - _log.debug(String.format("[%s] %s. Status code: %s", request.getMethod(), uri.toURL(), statusCode)); - } - - if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) { - _telemetryRuntimeProducer.recordSyncError(telemetryParamsWrapper.getResourceEnum(), statusCode); - if (statusCode == HttpStatus.SC_REQUEST_URI_TOO_LONG) { - _log.error("The amount of flag sets provided are big causing uri length error."); - throw new UriTooLongException(String.format("Status code: %s. Message: %s", statusCode, response.getReasonPhrase())); - } - _log.warn(String.format("Response status was: %s. Reason: %s", statusCode , response.getReasonPhrase())); - throw new IllegalStateException(String.format("Http get received non-successful return code %s", statusCode)); - } - - return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); - } catch (Exception e) { - throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e); - } finally { - _telemetryRuntimeProducer.recordSyncLatency(telemetryParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis()-start); - Utils.forceClose(response); - } - } - +public interface SplitHttpClient { + public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryParamsWrapper); public void post (URI uri, HttpEntity entity, Map additionalHeaders, - HttpParamsWrapper telemetryParamsWrapper) throws IOException { - CloseableHttpResponse response = null; - long initTime = System.currentTimeMillis(); - try { - HttpPost request = new HttpPost(uri); - if (additionalHeaders != null) { - for (Map.Entry entry : additionalHeaders.entrySet()) { - request.addHeader(entry.getKey().toString(), entry.getValue()); - } - } - request.setEntity(entity); - request = (HttpPost) _requestDecorator.decorateHeaders(request); - - response = _client.execute(request); - - int status = response.getCode(); - - if (status < HttpStatus.SC_OK || status >= HttpStatus.SC_MULTIPLE_CHOICES) { - _telemetryRuntimeProducer.recordSyncError(telemetryParamsWrapper.getResourceEnum(), status); - _log.warn(String.format("Response status was: %s. Reason: %s", status, response.getReasonPhrase())); - } - _telemetryRuntimeProducer.recordSuccessfulSync(telemetryParamsWrapper.getLastSynchronizationRecordsEnum(), System.currentTimeMillis()); - } catch (Exception e) { - throw new IOException(String.format("Problem in http post operation: %s", e), e); - } finally { - _telemetryRuntimeProducer.recordSyncLatency(telemetryParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis() - initTime); - Utils.forceClose(response); - } - } + HttpParamsWrapper telemetryParamsWrapper) throws IOException; } diff --git a/client/src/main/java/io/split/client/SplitHttpClientImpl.java b/client/src/main/java/io/split/client/SplitHttpClientImpl.java new file mode 100644 index 00000000..ee1dc36a --- /dev/null +++ b/client/src/main/java/io/split/client/SplitHttpClientImpl.java @@ -0,0 +1,123 @@ +package io.split.client; + +import io.split.client.exceptions.UriTooLongException; +import io.split.client.utils.Utils; +import io.split.engine.common.FetchOptions; +import io.split.telemetry.domain.enums.HttpParamsWrapper; +import io.split.telemetry.storage.TelemetryRuntimeProducer; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class SplitHttpClientImpl implements SplitHttpClient { + private static final Logger _log = LoggerFactory.getLogger(SplitHttpClient.class); + private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control"; + private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache"; + private final CloseableHttpClient _client; + private final RequestDecorator _requestDecorator; + private final TelemetryRuntimeProducer _telemetryRuntimeProducer; + + public static SplitHttpClientImpl create( + CloseableHttpClient client, + TelemetryRuntimeProducer telemetryRuntimeProducer, + RequestDecorator requestDecorator + ) throws URISyntaxException { + return new SplitHttpClientImpl(client, telemetryRuntimeProducer, requestDecorator); + } + + private SplitHttpClientImpl + (CloseableHttpClient client, + TelemetryRuntimeProducer telemetryRuntimeProducer, + RequestDecorator requestDecorator) { + _client = client; + _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); + _requestDecorator = requestDecorator; + } + + public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryParamsWrapper) { + long start = System.currentTimeMillis(); + + CloseableHttpResponse response = null; + + try { + HttpGet request = new HttpGet(uri); + if(options.cacheControlHeadersEnabled()) { + request.setHeader(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE); + } + request = (HttpGet) _requestDecorator.decorateHeaders(request); + + response = _client.execute(request); + + int statusCode = response.getCode(); + + if (_log.isDebugEnabled()) { + _log.debug(String.format("[%s] %s. Status code: %s", request.getMethod(), uri.toURL(), statusCode)); + } + + if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) { + _telemetryRuntimeProducer.recordSyncError(telemetryParamsWrapper.getResourceEnum(), statusCode); + if (statusCode == HttpStatus.SC_REQUEST_URI_TOO_LONG) { + _log.error("The amount of flag sets provided are big causing uri length error."); + throw new UriTooLongException(String.format("Status code: %s. Message: %s", statusCode, response.getReasonPhrase())); + } + _log.warn(String.format("Response status was: %s. Reason: %s", statusCode , response.getReasonPhrase())); + throw new IllegalStateException(String.format("Http get received non-successful return code %s", statusCode)); + } + + return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + } catch (Exception e) { + throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e); + } finally { + _telemetryRuntimeProducer.recordSyncLatency(telemetryParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis()-start); + Utils.forceClose(response); + } + } + + public void post + (URI uri, + HttpEntity entity, + Map additionalHeaders, + HttpParamsWrapper telemetryParamsWrapper) throws IOException { + CloseableHttpResponse response = null; + long initTime = System.currentTimeMillis(); + try { + HttpPost request = new HttpPost(uri); + if (additionalHeaders != null) { + for (Map.Entry entry : additionalHeaders.entrySet()) { + request.addHeader(entry.getKey().toString(), entry.getValue()); + } + } + request.setEntity(entity); + request = (HttpPost) _requestDecorator.decorateHeaders(request); + + response = _client.execute(request); + + int status = response.getCode(); + + if (status < HttpStatus.SC_OK || status >= HttpStatus.SC_MULTIPLE_CHOICES) { + _telemetryRuntimeProducer.recordSyncError(telemetryParamsWrapper.getResourceEnum(), status); + _log.warn(String.format("Response status was: %s. Reason: %s", status, response.getReasonPhrase())); + } + _telemetryRuntimeProducer.recordSuccessfulSync(telemetryParamsWrapper.getLastSynchronizationRecordsEnum(), System.currentTimeMillis()); + } catch (Exception e) { + throw new IOException(String.format("Problem in http post operation: %s", e), e); + } finally { + _telemetryRuntimeProducer.recordSyncLatency(telemetryParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis() - initTime); + Utils.forceClose(response); + } + } +} diff --git a/client/src/test/java/io/split/client/HttpSplitClientTest.java b/client/src/test/java/io/split/client/HttpSplitClientTest.java index ecfb92eb..5a9baea2 100644 --- a/client/src/test/java/io/split/client/HttpSplitClientTest.java +++ b/client/src/test/java/io/split/client/HttpSplitClientTest.java @@ -48,7 +48,7 @@ public void testGetWithSpecialCharacters() throws URISyntaxException, Invocation CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_OK); RequestDecorator decorator = new RequestDecorator(null); - SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClientMock, TELEMETRY_STORAGE, decorator); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, TELEMETRY_STORAGE, decorator); String change_raw = splitHtpClient.get(rootTarget, new FetchOptions.Builder().cacheControlHeaders(true).build(), HttpParamsWrapper.SPLITS @@ -73,7 +73,7 @@ public void testGetError() throws URISyntaxException, InvocationTargetException, CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); RequestDecorator decorator = new RequestDecorator(null); - SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClientMock, TELEMETRY_STORAGE, decorator); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, TELEMETRY_STORAGE, decorator); String change_raw = splitHtpClient.get(rootTarget, new FetchOptions.Builder().cacheControlHeaders(true).build(), HttpParamsWrapper.SPLITS @@ -82,13 +82,13 @@ public void testGetError() throws URISyntaxException, InvocationTargetException, @Test public void testPost() throws URISyntaxException, IOException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { - URI rootTarget = URI.create("https://kubernetesturl.com/split"); + URI rootTarget = URI.create("https://kubernetesturl.com/split/api/testImpressions/bulk"); // Setup response mock CloseableHttpClient httpClient = TestHelper.mockHttpClient("", HttpStatus.SC_OK); RequestDecorator decorator = new RequestDecorator(null); - SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClient, TELEMETRY_STORAGE, decorator); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, TELEMETRY_STORAGE, decorator); // Send impressions List toSend = Arrays.asList(new TestImpressions("t1", Arrays.asList( @@ -101,7 +101,7 @@ public void testPost() throws URISyntaxException, IOException, IllegalAccessExce KeyImpression.fromImpression(new Impression("k3", null, "t2", "on", 123L, "r1", 456L, null)) ))); Map additionalHeaders = new HashMap<>(); - additionalHeaders.put("SplitSDKImpressionsMode", "any"); + additionalHeaders.put("SplitSDKImpressionsMode", "OPTIMIZED"); splitHtpClient.post(rootTarget, Utils.toJsonEntity(toSend), additionalHeaders, HttpParamsWrapper.IMPRESSIONS); // Capture outgoing request and validate it @@ -125,7 +125,7 @@ public void testPosttNoExceptionOnHttpErrorCode() throws URISyntaxException, Inv CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); RequestDecorator decorator = new RequestDecorator(null); - SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClientMock, TELEMETRY_STORAGE, decorator); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, TELEMETRY_STORAGE, decorator); splitHtpClient.post(rootTarget, Utils.toJsonEntity(Arrays.asList( new String[] { "A", "B", "C", "D" })), null, HttpParamsWrapper.IMPRESSIONS); } @@ -134,7 +134,7 @@ public void testPosttException() throws URISyntaxException, InvocationTargetExce URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); - SplitHttpClient splitHtpClient = SplitHttpClient.create(httpClientMock, TELEMETRY_STORAGE, null); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, TELEMETRY_STORAGE, null); splitHtpClient.post(rootTarget, Utils.toJsonEntity(Arrays.asList( new String[] { "A", "B", "C", "D" })), null, HttpParamsWrapper.IMPRESSIONS); } } \ No newline at end of file From 1958b82be63548eadbfb38892ba172d37d2d26e9 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Tue, 12 Mar 2024 19:42:27 -0700 Subject: [PATCH 4/6] added splithttpresponse dto --- .../java/io/split/client/SplitHttpClient.java | 8 ++-- .../io/split/client/SplitHttpClientImpl.java | 40 ++++++++--------- .../split/client/dtos/SplitHttpResponse.java | 10 +++++ .../io/split/client/HttpSplitClientTest.java | 45 ++++++++----------- 4 files changed, 51 insertions(+), 52 deletions(-) create mode 100644 client/src/main/java/io/split/client/dtos/SplitHttpResponse.java diff --git a/client/src/main/java/io/split/client/SplitHttpClient.java b/client/src/main/java/io/split/client/SplitHttpClient.java index 2ab1a38e..6d54d768 100644 --- a/client/src/main/java/io/split/client/SplitHttpClient.java +++ b/client/src/main/java/io/split/client/SplitHttpClient.java @@ -2,6 +2,7 @@ import io.split.engine.common.FetchOptions; import io.split.telemetry.domain.enums.HttpParamsWrapper; +import io.split.client.dtos.SplitHttpResponse; import org.apache.hc.core5.http.HttpEntity; import java.io.IOException; @@ -9,10 +10,9 @@ import java.util.Map; public interface SplitHttpClient { - public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryParamsWrapper); - public void post + public SplitHttpResponse get(URI uri, FetchOptions options); + public SplitHttpResponse post (URI uri, HttpEntity entity, - Map additionalHeaders, - HttpParamsWrapper telemetryParamsWrapper) throws IOException; + Map additionalHeaders) throws IOException; } diff --git a/client/src/main/java/io/split/client/SplitHttpClientImpl.java b/client/src/main/java/io/split/client/SplitHttpClientImpl.java index ee1dc36a..b3856297 100644 --- a/client/src/main/java/io/split/client/SplitHttpClientImpl.java +++ b/client/src/main/java/io/split/client/SplitHttpClientImpl.java @@ -1,10 +1,10 @@ package io.split.client; import io.split.client.exceptions.UriTooLongException; +import io.split.client.utils.Json; import io.split.client.utils.Utils; import io.split.engine.common.FetchOptions; -import io.split.telemetry.domain.enums.HttpParamsWrapper; -import io.split.telemetry.storage.TelemetryRuntimeProducer; +import io.split.client.dtos.SplitHttpResponse; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; @@ -21,36 +21,28 @@ import java.nio.charset.StandardCharsets; import java.util.Map; -import static com.google.common.base.Preconditions.checkNotNull; - public final class SplitHttpClientImpl implements SplitHttpClient { private static final Logger _log = LoggerFactory.getLogger(SplitHttpClient.class); private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control"; private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache"; private final CloseableHttpClient _client; private final RequestDecorator _requestDecorator; - private final TelemetryRuntimeProducer _telemetryRuntimeProducer; public static SplitHttpClientImpl create( CloseableHttpClient client, - TelemetryRuntimeProducer telemetryRuntimeProducer, RequestDecorator requestDecorator ) throws URISyntaxException { - return new SplitHttpClientImpl(client, telemetryRuntimeProducer, requestDecorator); + return new SplitHttpClientImpl(client, requestDecorator); } private SplitHttpClientImpl (CloseableHttpClient client, - TelemetryRuntimeProducer telemetryRuntimeProducer, RequestDecorator requestDecorator) { _client = client; - _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); _requestDecorator = requestDecorator; } - public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryParamsWrapper) { - long start = System.currentTimeMillis(); - + public SplitHttpResponse get(URI uri, FetchOptions options) { CloseableHttpResponse response = null; try { @@ -69,7 +61,6 @@ public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryPara } if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) { - _telemetryRuntimeProducer.recordSyncError(telemetryParamsWrapper.getResourceEnum(), statusCode); if (statusCode == HttpStatus.SC_REQUEST_URI_TOO_LONG) { _log.error("The amount of flag sets provided are big causing uri length error."); throw new UriTooLongException(String.format("Status code: %s. Message: %s", statusCode, response.getReasonPhrase())); @@ -77,21 +68,22 @@ public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryPara _log.warn(String.format("Response status was: %s. Reason: %s", statusCode , response.getReasonPhrase())); throw new IllegalStateException(String.format("Http get received non-successful return code %s", statusCode)); } - - return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + SplitHttpResponse httpResponse = new SplitHttpResponse(); + httpResponse.statusCode = statusCode; + httpResponse.body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + httpResponse.statusMessage = ""; + return httpResponse; } catch (Exception e) { throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e); } finally { - _telemetryRuntimeProducer.recordSyncLatency(telemetryParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis()-start); Utils.forceClose(response); } } - public void post + public SplitHttpResponse post (URI uri, HttpEntity entity, - Map additionalHeaders, - HttpParamsWrapper telemetryParamsWrapper) throws IOException { + Map additionalHeaders) throws IOException { CloseableHttpResponse response = null; long initTime = System.currentTimeMillis(); try { @@ -108,15 +100,19 @@ public String get(URI uri, FetchOptions options, HttpParamsWrapper telemetryPara int status = response.getCode(); + String statusMessage = new String(""); if (status < HttpStatus.SC_OK || status >= HttpStatus.SC_MULTIPLE_CHOICES) { - _telemetryRuntimeProducer.recordSyncError(telemetryParamsWrapper.getResourceEnum(), status); + statusMessage = response.getReasonPhrase(); _log.warn(String.format("Response status was: %s. Reason: %s", status, response.getReasonPhrase())); } - _telemetryRuntimeProducer.recordSuccessfulSync(telemetryParamsWrapper.getLastSynchronizationRecordsEnum(), System.currentTimeMillis()); + SplitHttpResponse httpResponse = new SplitHttpResponse(); + httpResponse.statusCode = status; + httpResponse.body = ""; + httpResponse.statusMessage = statusMessage; + return httpResponse; } catch (Exception e) { throw new IOException(String.format("Problem in http post operation: %s", e), e); } finally { - _telemetryRuntimeProducer.recordSyncLatency(telemetryParamsWrapper.getHttpLatenciesEnum(), System.currentTimeMillis() - initTime); Utils.forceClose(response); } } diff --git a/client/src/main/java/io/split/client/dtos/SplitHttpResponse.java b/client/src/main/java/io/split/client/dtos/SplitHttpResponse.java new file mode 100644 index 00000000..a708a464 --- /dev/null +++ b/client/src/main/java/io/split/client/dtos/SplitHttpResponse.java @@ -0,0 +1,10 @@ +package io.split.client.dtos; + +/** + * A structure for returning http call results information + */ +public class SplitHttpResponse { + public Integer statusCode; + public String statusMessage; + public String body; +} diff --git a/client/src/test/java/io/split/client/HttpSplitClientTest.java b/client/src/test/java/io/split/client/HttpSplitClientTest.java index 5a9baea2..91c946ca 100644 --- a/client/src/test/java/io/split/client/HttpSplitClientTest.java +++ b/client/src/test/java/io/split/client/HttpSplitClientTest.java @@ -3,10 +3,7 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import io.split.TestHelper; -import io.split.client.dtos.KeyImpression; -import io.split.client.dtos.Split; -import io.split.client.dtos.SplitChange; -import io.split.client.dtos.TestImpressions; +import io.split.client.dtos.*; import io.split.client.impressions.Impression; import io.split.client.utils.Json; import io.split.client.utils.Utils; @@ -28,10 +25,7 @@ import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; @@ -40,7 +34,6 @@ import static org.mockito.Mockito.verify; public class HttpSplitClientTest { - private static final TelemetryStorage TELEMETRY_STORAGE = Mockito.mock(InMemoryTelemetryStorage.class); @Test public void testGetWithSpecialCharacters() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException { @@ -48,12 +41,11 @@ public void testGetWithSpecialCharacters() throws URISyntaxException, Invocation CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_OK); RequestDecorator decorator = new RequestDecorator(null); - SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, TELEMETRY_STORAGE, decorator); - String change_raw = splitHtpClient.get(rootTarget, - new FetchOptions.Builder().cacheControlHeaders(true).build(), - HttpParamsWrapper.SPLITS - ); - SplitChange change = Json.fromJson(change_raw, SplitChange.class); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, decorator); + + SplitHttpResponse splitHttpResponse = splitHtpClient.get(rootTarget, + new FetchOptions.Builder().cacheControlHeaders(true).build()); + SplitChange change = Json.fromJson(splitHttpResponse.body, SplitChange.class); Assert.assertNotNull(change); Assert.assertEquals(1, change.splits.size()); @@ -73,11 +65,9 @@ public void testGetError() throws URISyntaxException, InvocationTargetException, CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); RequestDecorator decorator = new RequestDecorator(null); - SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, TELEMETRY_STORAGE, decorator); - String change_raw = splitHtpClient.get(rootTarget, - new FetchOptions.Builder().cacheControlHeaders(true).build(), - HttpParamsWrapper.SPLITS - ); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, decorator); + splitHtpClient.get(rootTarget, + new FetchOptions.Builder().cacheControlHeaders(true).build()); } @Test @@ -88,7 +78,7 @@ public void testPost() throws URISyntaxException, IOException, IllegalAccessExce CloseableHttpClient httpClient = TestHelper.mockHttpClient("", HttpStatus.SC_OK); RequestDecorator decorator = new RequestDecorator(null); - SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, TELEMETRY_STORAGE, decorator); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, decorator); // Send impressions List toSend = Arrays.asList(new TestImpressions("t1", Arrays.asList( @@ -102,7 +92,7 @@ public void testPost() throws URISyntaxException, IOException, IllegalAccessExce ))); Map additionalHeaders = new HashMap<>(); additionalHeaders.put("SplitSDKImpressionsMode", "OPTIMIZED"); - splitHtpClient.post(rootTarget, Utils.toJsonEntity(toSend), additionalHeaders, HttpParamsWrapper.IMPRESSIONS); + SplitHttpResponse splitHttpResponse = splitHtpClient.post(rootTarget, Utils.toJsonEntity(toSend), additionalHeaders); // Capture outgoing request and validate it ArgumentCaptor captor = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -117,6 +107,7 @@ public void testPost() throws URISyntaxException, IOException, IllegalAccessExce Gson gson = new Gson(); List payload = gson.fromJson(reader, new TypeToken>() { }.getType()); assertThat(payload.size(), is(equalTo(2))); + Assert.assertEquals(200,(long) splitHttpResponse.statusCode); } @Test @@ -125,8 +116,10 @@ public void testPosttNoExceptionOnHttpErrorCode() throws URISyntaxException, Inv CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); RequestDecorator decorator = new RequestDecorator(null); - SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, TELEMETRY_STORAGE, decorator); - splitHtpClient.post(rootTarget, Utils.toJsonEntity(Arrays.asList( new String[] { "A", "B", "C", "D" })), null, HttpParamsWrapper.IMPRESSIONS); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, decorator); + SplitHttpResponse splitHttpResponse = splitHtpClient.post(rootTarget, Utils.toJsonEntity(Arrays.asList( new String[] { "A", "B", "C", "D" })), null); + Assert.assertEquals(500, (long) splitHttpResponse.statusCode); + } @Test(expected = IOException.class) @@ -134,7 +127,7 @@ public void testPosttException() throws URISyntaxException, InvocationTargetExce URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); - SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, TELEMETRY_STORAGE, null); - splitHtpClient.post(rootTarget, Utils.toJsonEntity(Arrays.asList( new String[] { "A", "B", "C", "D" })), null, HttpParamsWrapper.IMPRESSIONS); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, null); + splitHtpClient.post(rootTarget, Utils.toJsonEntity(Arrays.asList( new String[] { "A", "B", "C", "D" })), null); } } \ No newline at end of file From 33e0454fad492611b617e8d09b776d6037f25cd0 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Wed, 13 Mar 2024 09:42:46 -0700 Subject: [PATCH 5/6] removed exception when status is not 200 --- .../src/main/java/io/split/client/SplitHttpClientImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitHttpClientImpl.java b/client/src/main/java/io/split/client/SplitHttpClientImpl.java index b3856297..a578b191 100644 --- a/client/src/main/java/io/split/client/SplitHttpClientImpl.java +++ b/client/src/main/java/io/split/client/SplitHttpClientImpl.java @@ -60,18 +60,18 @@ public SplitHttpResponse get(URI uri, FetchOptions options) { _log.debug(String.format("[%s] %s. Status code: %s", request.getMethod(), uri.toURL(), statusCode)); } + SplitHttpResponse httpResponse = new SplitHttpResponse(); + httpResponse.statusMessage = ""; if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) { if (statusCode == HttpStatus.SC_REQUEST_URI_TOO_LONG) { _log.error("The amount of flag sets provided are big causing uri length error."); throw new UriTooLongException(String.format("Status code: %s. Message: %s", statusCode, response.getReasonPhrase())); } _log.warn(String.format("Response status was: %s. Reason: %s", statusCode , response.getReasonPhrase())); - throw new IllegalStateException(String.format("Http get received non-successful return code %s", statusCode)); + httpResponse.statusMessage = response.getReasonPhrase(); } - SplitHttpResponse httpResponse = new SplitHttpResponse(); httpResponse.statusCode = statusCode; httpResponse.body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); - httpResponse.statusMessage = ""; return httpResponse; } catch (Exception e) { throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e); From f9a6e9473acda48af89df6ebe6f92761edbf4143 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Wed, 13 Mar 2024 10:31:24 -0700 Subject: [PATCH 6/6] fixed test --- .../java/io/split/client/HttpSplitClientTest.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/client/src/test/java/io/split/client/HttpSplitClientTest.java b/client/src/test/java/io/split/client/HttpSplitClientTest.java index 91c946ca..6a2fd010 100644 --- a/client/src/test/java/io/split/client/HttpSplitClientTest.java +++ b/client/src/test/java/io/split/client/HttpSplitClientTest.java @@ -59,12 +59,24 @@ public void testGetWithSpecialCharacters() throws URISyntaxException, Invocation Assert.assertEquals(2, split.sets.size()); } - @Test(expected = IllegalStateException.class) + @Test public void testGetError() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException { URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); RequestDecorator decorator = new RequestDecorator(null); + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, decorator); + SplitHttpResponse splitHttpResponse = splitHtpClient.get(rootTarget, + new FetchOptions.Builder().cacheControlHeaders(true).build()); + Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, (long) splitHttpResponse.statusCode); + } + + @Test(expected = IllegalStateException.class) + public void testException() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException { + URI rootTarget = URI.create("https://api.split.io/splitChanges?since=1234567"); + CloseableHttpClient httpClientMock = TestHelper.mockHttpClient("split-change-special-characters.json", HttpStatus.SC_INTERNAL_SERVER_ERROR); + RequestDecorator decorator = null; + SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, decorator); splitHtpClient.get(rootTarget, new FetchOptions.Builder().cacheControlHeaders(true).build());