From 3ad6db969a767e767e6723eb3663c3864774a874 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Tue, 22 Apr 2025 14:56:59 -0700 Subject: [PATCH 01/16] Added old spec support in splitfetcher --- client/src/main/java/io/split/Spec.java | 1 + .../split/client/HttpSplitChangeFetcher.java | 91 +++++++++++++---- .../io/split/client/SplitClientConfig.java | 4 + .../io/split/client/SplitFactoryImpl.java | 6 +- .../client/HttpSplitChangeFetcherTest.java | 98 +++++++++++++++---- 5 files changed, 158 insertions(+), 42 deletions(-) diff --git a/client/src/main/java/io/split/Spec.java b/client/src/main/java/io/split/Spec.java index 79f9a4bc..37c544fe 100644 --- a/client/src/main/java/io/split/Spec.java +++ b/client/src/main/java/io/split/Spec.java @@ -8,6 +8,7 @@ private Spec() { // TODO: Change the schema to 1.3 when updating splitclient public static final String SPEC_1_3 = "1.3"; + public static final String SPEC_1_2 = "1.2"; public static final String SPEC_1_1 = "1.1"; public static String SPEC_VERSION = SPEC_1_3; } diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index 466ffb67..8a834878 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -1,7 +1,9 @@ package io.split.client; import com.google.common.annotations.VisibleForTesting; +import com.google.gson.JsonObject; +import io.split.Spec; import io.split.client.dtos.SplitChange; import io.split.client.dtos.SplitHttpResponse; import io.split.client.exceptions.UriTooLongException; @@ -23,6 +25,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import static io.split.Spec.SPEC_VERSION; +import static io.split.Spec.SPEC_1_3; +import static io.split.Spec.SPEC_1_2; /** * Created by adilaijaz on 5/30/15. @@ -30,25 +34,31 @@ public final class HttpSplitChangeFetcher implements SplitChangeFetcher { private static final Logger _log = LoggerFactory.getLogger(HttpSplitChangeFetcher.class); + private final Object _lock = new Object(); private static final String SINCE = "since"; private static final String RB_SINCE = "rbSince"; private static final String TILL = "till"; private static final String SETS = "sets"; private static final String SPEC = "s"; + private int PROXY_CHECK_INTERVAL_MINUTES_SS = 24 * 60; + private Long _lastProxyCheckTimestamp = 0L; private final SplitHttpClient _client; private final URI _target; private final TelemetryRuntimeProducer _telemetryRuntimeProducer; + private final boolean _rootURIOverriden; - public static HttpSplitChangeFetcher create(SplitHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer) + public static HttpSplitChangeFetcher create(SplitHttpClient client, URI root, TelemetryRuntimeProducer telemetryRuntimeProducer, + boolean rootURIOverriden) throws URISyntaxException { - return new HttpSplitChangeFetcher(client, Utils.appendPath(root, "api/splitChanges"), telemetryRuntimeProducer); + return new HttpSplitChangeFetcher(client, Utils.appendPath(root, "api/splitChanges"), telemetryRuntimeProducer, rootURIOverriden); } - private HttpSplitChangeFetcher(SplitHttpClient client, URI uri, TelemetryRuntimeProducer telemetryRuntimeProducer) { + private HttpSplitChangeFetcher(SplitHttpClient client, URI uri, TelemetryRuntimeProducer telemetryRuntimeProducer, boolean rootURIOverriden) { _client = client; _target = uri; checkNotNull(_target); _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); + _rootURIOverriden = rootURIOverriden; } long makeRandomTill() { @@ -59,27 +69,68 @@ long makeRandomTill() { @Override public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { long start = System.currentTimeMillis(); - try { - URI uri = buildURL(options, since, sinceRBS); - SplitHttpResponse response = _client.get(uri, options, null); - - if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) { - if (response.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", response.statusCode(), response.statusMessage())); + SplitHttpResponse response; + while (true) { + try { + if (SPEC_VERSION.equals(SPEC_1_2) && (System.currentTimeMillis() - _lastProxyCheckTimestamp >= PROXY_CHECK_INTERVAL_MINUTES_SS)) { + _log.info("Switching to new Feature flag spec ({}) and fetching.", SPEC_1_3); + SPEC_VERSION = SPEC_1_3; } + URI uri = buildURL(options, since, sinceRBS); + response = _client.get(uri, options, null); + if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) { + if (response.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", response.statusCode(), response.statusMessage())); + } - _telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode()); - throw new IllegalStateException( - String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode()) - ); + if (response.statusCode() == HttpStatus.SC_BAD_REQUEST && SPEC_VERSION.equals(Spec.SPEC_1_3) && _rootURIOverriden) { + SPEC_VERSION = Spec.SPEC_1_2; + _log.warn("Detected proxy without support for Feature flags spec {} version, will switch to spec version {}", + SPEC_1_3, SPEC_1_2); + _lastProxyCheckTimestamp = System.currentTimeMillis(); + continue; + } + + _telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode()); + throw new IllegalStateException( + String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode()) + ); + } + break; + } catch (Exception e) { + throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e); + } finally { + _telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start); } - return Json.fromJson(response.body(), SplitChange.class); - } catch (Exception e) { - throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e); - } finally { - _telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start); } + + String body = response.body(); + if (SPEC_VERSION.equals(Spec.SPEC_1_2)) { + body = convertBodyToOldSpec(body); + _lastProxyCheckTimestamp = System.currentTimeMillis(); + } + return Json.fromJson(body, SplitChange.class); + } + + public Long getLastProxyCheckTimestamp() { + return _lastProxyCheckTimestamp; + } + + public void setLastProxyCheckTimestamp(long lastProxyCheckTimestamp) { + synchronized (_lock) { + _lastProxyCheckTimestamp = lastProxyCheckTimestamp; + } + } + + private String convertBodyToOldSpec(String body) { + JsonObject targetBody = Json.fromJson("{\"ff\": {\"t\":-1, \"s\": -1}," + + "\"rbs\": {\"d\":[], \"t\":-1, \"s\": -1}}", JsonObject.class); + JsonObject jsonBody = Json.fromJson(body, JsonObject.class); + targetBody.getAsJsonObject("ff").add("d", jsonBody.getAsJsonArray("splits")); + targetBody.getAsJsonObject("ff").add("s", jsonBody.get("since")); + targetBody.getAsJsonObject("ff").add("t", jsonBody.get("till")); + return Json.toJson(targetBody); } private URI buildURL(FetchOptions options, long since, long sinceRBS) throws URISyntaxException { diff --git a/client/src/main/java/io/split/client/SplitClientConfig.java b/client/src/main/java/io/split/client/SplitClientConfig.java index 8787c106..fa73ef8c 100644 --- a/client/src/main/java/io/split/client/SplitClientConfig.java +++ b/client/src/main/java/io/split/client/SplitClientConfig.java @@ -412,6 +412,10 @@ public CustomHeaderDecorator customHeaderDecorator() { return _customHeaderDecorator; } + public boolean isRootURIOverriden() { + return _endpoint == SDK_ENDPOINT; + } + public CustomHttpModule alternativeHTTPModule() { return _alternativeHTTPModule; } public static final class Builder { diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 8e38d408..dfe82c6a 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -225,7 +225,7 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser(); // SplitFetcher _splitFetcher = buildSplitFetcher(splitCache, splitParser, flagSetsFilter, - ruleBasedSegmentParser, ruleBasedSegmentCache); + ruleBasedSegmentParser, ruleBasedSegmentCache, config.isRootURIOverriden()); // SplitSynchronizationTask _splitSynchronizationTask = new SplitSynchronizationTask(_splitFetcher, @@ -623,9 +623,9 @@ private SegmentSynchronizationTaskImp buildSegments(SplitClientConfig config, private SplitFetcher buildSplitFetcher(SplitCacheProducer splitCacheProducer, SplitParser splitParser, FlagSetsFilter flagSetsFilter, RuleBasedSegmentParser ruleBasedSegmentParser, - RuleBasedSegmentCacheProducer ruleBasedSegmentCache) throws URISyntaxException { + RuleBasedSegmentCacheProducer ruleBasedSegmentCache, boolean isRootURIOverriden) throws URISyntaxException { SplitChangeFetcher splitChangeFetcher = HttpSplitChangeFetcher.create(_splitHttpClient, _rootTarget, - _telemetryStorageProducer); + _telemetryStorageProducer, isRootURIOverriden); return new SplitFetcherImp(splitChangeFetcher, splitParser, splitCacheProducer, _telemetryStorageProducer, flagSetsFilter, ruleBasedSegmentParser, ruleBasedSegmentCache); } diff --git a/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java b/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java index d503a4b2..3b3f41b2 100644 --- a/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java +++ b/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java @@ -4,6 +4,7 @@ import io.split.TestHelper; import io.split.client.dtos.Split; import io.split.client.dtos.SplitChange; +import io.split.client.utils.Json; import io.split.client.utils.SDKMetadata; import io.split.engine.common.FetchOptions; import io.split.engine.metrics.Metrics; @@ -20,13 +21,13 @@ import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.HttpStatus; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; @@ -47,7 +48,7 @@ public void testDefaultURL() throws URISyntaxException { SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, new RequestDecorator(null), "qwerty", metadata()); - HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE); + HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE, false); Assert.assertEquals("https://api.split.io/api/splitChanges", fetcher.getTarget().toString()); } @@ -58,7 +59,7 @@ public void testCustomURLNoPathNoBackslash() throws URISyntaxException { SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, new RequestDecorator(null), "qwerty", metadata()); - HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE); + HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE, false); Assert.assertEquals("https://kubernetesturl.com/split/api/splitChanges", fetcher.getTarget().toString()); } @@ -68,7 +69,7 @@ public void testCustomURLAppendingPath() throws URISyntaxException { CloseableHttpClient httpClient = HttpClients.custom().build(); SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, new RequestDecorator(null), "qwerty", metadata()); - HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE); + HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE, false); Assert.assertEquals("https://kubernetesturl.com/split/api/splitChanges", fetcher.getTarget().toString()); } @@ -78,7 +79,7 @@ public void testCustomURLAppendingPathNoBackslash() throws URISyntaxException { CloseableHttpClient httpClient = HttpClients.custom().build(); SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, new RequestDecorator(null), "qwerty", metadata()); - HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE); + HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE, false); Assert.assertEquals("https://kubernetesturl.com/split/api/splitChanges", fetcher.getTarget().toString()); } @@ -93,7 +94,7 @@ public void testFetcherWithSpecialCharacters() throws URISyntaxException, Invoca "qwerty", metadata()); - HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE); + HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, TELEMETRY_STORAGE, false); SplitChange change = fetcher.fetch(1234567, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); @@ -131,7 +132,7 @@ public void testFetcherWithCDNBypassOption() throws IOException, URISyntaxExcept "qwerty", metadata()); HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, - Mockito.mock(TelemetryRuntimeProducer.class)); + Mockito.mock(TelemetryRuntimeProducer.class), false); fetcher.fetch(-1, -1, new FetchOptions.Builder().targetChangeNumber(123).build()); // TODO: Fix the test with integration tests update @@ -149,7 +150,7 @@ public void testRandomNumberGeneration() throws URISyntaxException { SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, new RequestDecorator(null), "qwerty", metadata()); HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, - Mockito.mock(TelemetryRuntimeProducer.class)); + Mockito.mock(TelemetryRuntimeProducer.class), false); Set seen = new HashSet<>(); long min = (long) Math.pow(2, 63) * (-1); @@ -183,7 +184,7 @@ public void testURLTooLong() throws IOException, URISyntaxException, IllegalAcce SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, new RequestDecorator(null), "qwerty", metadata()); HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, - Mockito.mock(TelemetryRuntimeProducer.class)); + Mockito.mock(TelemetryRuntimeProducer.class), false); List sets = new ArrayList(); for (Integer i = 0; i < 100; i++) { sets.add("set" + i.toString()); @@ -194,42 +195,101 @@ public void testURLTooLong() throws IOException, URISyntaxException, IllegalAcce fetcher.fetch(-1, -1, new FetchOptions.Builder().flagSetsFilter(result).cacheControlHeaders(false).build()); } - // TODO: enable when switching to old spec is added - @Ignore @Test public void testSwitchingToOldSpec() throws URISyntaxException, InvocationTargetException, - NoSuchMethodException, IllegalAccessException, IOException { + NoSuchMethodException, IllegalAccessException, IOException, NoSuchFieldException, InterruptedException { Spec.SPEC_VERSION = Spec.SPEC_1_3; URI rootTarget = URI.create("https://api.split.io"); CloseableHttpClient httpClientMock = Mockito.mock(CloseableHttpClient.class); HttpEntity entityMock = Mockito.mock(HttpEntity.class); when(entityMock.getContent()) .thenReturn(new ByteArrayInputStream("{\"till\": -1, \"since\": -1, \"splits\": []}".getBytes(StandardCharsets.UTF_8))); - + HttpEntity entityMock2 = Mockito.mock(HttpEntity.class); + when(entityMock2.getContent()) + .thenReturn(new ByteArrayInputStream("{\"till\": 123, \"since\": 122, \"splits\": [{\"name\":\"some\"}, {\"name\":\"some2\"}]}".getBytes(StandardCharsets.UTF_8))); + HttpEntity entityMock3 = Mockito.mock(HttpEntity.class); + when(entityMock3.getContent()) + .thenReturn(new ByteArrayInputStream("{\"till\": 123, \"since\": 122, \"splits\": [{\"name\":\"some\"}, {\"name\":\"some2\"}]}".getBytes(StandardCharsets.UTF_8))); + HttpEntity entityMock4 = Mockito.mock(HttpEntity.class); + when(entityMock4.getContent()) + .thenReturn(new ByteArrayInputStream("{\"ff\":{\"t\": 123, \"s\": 122, \"d\": [{\"name\":\"some\"}, {\"name\":\"some2\"}]}, \"rbs\":{\"t\": -1, \"s\": -1, \"d\": []}}".getBytes(StandardCharsets.UTF_8))); ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class); when(response1.getCode()).thenReturn(HttpStatus.SC_BAD_REQUEST); - when(response1.getReasonPhrase()).thenReturn("unknown spec"); when(response1.getEntity()).thenReturn(entityMock); when(response1.getHeaders()).thenReturn(new Header[0]); + ClassicHttpResponse response2 = Mockito.mock(ClassicHttpResponse.class); + when(response2.getCode()).thenReturn(HttpStatus.SC_OK); + when(response2.getEntity()).thenReturn(entityMock2); + when(response2.getHeaders()).thenReturn(new Header[0]); + + ClassicHttpResponse response3 = Mockito.mock(ClassicHttpResponse.class); + when(response3.getCode()).thenReturn(HttpStatus.SC_OK); + when(response3.getEntity()).thenReturn(entityMock3); + when(response3.getHeaders()).thenReturn(new Header[0]); + + ClassicHttpResponse response4 = Mockito.mock(ClassicHttpResponse.class); + when(response4.getCode()).thenReturn(HttpStatus.SC_OK); + when(response4.getEntity()).thenReturn(entityMock4); + when(response4.getHeaders()).thenReturn(new Header[0]); + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class); when(httpClientMock.execute(requestCaptor.capture())) - .thenReturn(TestHelper.classicResponseToCloseableMock(response1)); + .thenReturn(TestHelper.classicResponseToCloseableMock(response1)) + .thenReturn(TestHelper.classicResponseToCloseableMock(response2)) + .thenReturn(TestHelper.classicResponseToCloseableMock(response1)) + .thenReturn(TestHelper.classicResponseToCloseableMock(response3)) + .thenReturn(TestHelper.classicResponseToCloseableMock(response4)); SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClientMock, new RequestDecorator(null), "qwerty", metadata()); - HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, - Mockito.mock(TelemetryRuntimeProducer.class)); + Mockito.mock(TelemetryRuntimeProducer.class), true); SplitChange change = fetcher.fetch(-1, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); - Assert.assertEquals(Spec.SPEC_1_1, Spec.SPEC_VERSION); + Assert.assertEquals(Spec.SPEC_1_2, Spec.SPEC_VERSION); List captured = requestCaptor.getAllValues(); Assert.assertEquals(captured.size(), 2); Assert.assertTrue(captured.get(0).getUri().toString().contains("s=1.3")); - Assert.assertTrue(captured.get(1).getUri().toString().contains("s=1.1")); + Assert.assertTrue(captured.get(1).getUri().toString().contains("s=1.2")); + Assert.assertEquals(122, change.featureFlags.s); + Assert.assertEquals(123, change.featureFlags.t); + Assert.assertEquals(2, change.featureFlags.d.size()); + Assert.assertEquals(Json.fromJson("{\"name\":\"some\"}", Split.class).name, change.featureFlags.d.get(0).name); + Assert.assertEquals(Json.fromJson("{\"name\":\"some2\"}", Split.class).name, change.featureFlags.d.get(1).name); + Assert.assertEquals(0, change.ruleBasedSegments.d.size()); + Assert.assertEquals(-1, change.ruleBasedSegments.s); + Assert.assertEquals(-1, change.ruleBasedSegments.t); + Assert.assertTrue(fetcher.getLastProxyCheckTimestamp() > 0); + + // Set proxy interval to low number to force check for spec 1.3 + Field proxyInterval = fetcher.getClass().getDeclaredField("PROXY_CHECK_INTERVAL_MINUTES_SS"); + proxyInterval.setAccessible(true); + proxyInterval.set(fetcher, 5); + Thread.sleep(1000); + change = fetcher.fetch(-1, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); + + Assert.assertEquals(Spec.SPEC_1_2, Spec.SPEC_VERSION); + Assert.assertTrue(captured.get(2).getUri().toString().contains("s=1.3")); + Assert.assertTrue(captured.get(3).getUri().toString().contains("s=1.2")); + Assert.assertEquals(122, change.featureFlags.s); + Assert.assertEquals(123, change.featureFlags.t); + Assert.assertEquals(2, change.featureFlags.d.size()); + Assert.assertEquals(Json.fromJson("{\"name\":\"some\"}", Split.class).name, change.featureFlags.d.get(0).name); + Assert.assertEquals(Json.fromJson("{\"name\":\"some2\"}", Split.class).name, change.featureFlags.d.get(1).name); + + // test if proxy is upgraded and spec 1.3 now works. + Thread.sleep(1000); + change = fetcher.fetch(-1, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); + Assert.assertEquals(Spec.SPEC_1_3, Spec.SPEC_VERSION); + Assert.assertTrue(captured.get(4).getUri().toString().contains("s=1.3")); + Assert.assertEquals(122, change.featureFlags.s); + Assert.assertEquals(123, change.featureFlags.t); + Assert.assertEquals(2, change.featureFlags.d.size()); + Assert.assertEquals(Json.fromJson("{\"name\":\"some\"}", Split.class).name, change.featureFlags.d.get(0).name); + Assert.assertEquals(Json.fromJson("{\"name\":\"some2\"}", Split.class).name, change.featureFlags.d.get(1).name); } private SDKMetadata metadata() { From 57777ab792e88b6a4859005bf8d713021504a19d Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Tue, 22 Apr 2025 21:06:07 -0700 Subject: [PATCH 02/16] Polish --- client/src/main/java/io/split/Spec.java | 1 - .../split/client/HttpSplitChangeFetcher.java | 95 ++++++++++--------- .../dtos/SplitChangesOldPayloadDto.java | 25 +++++ .../client/HttpSplitChangeFetcherTest.java | 8 +- 4 files changed, 79 insertions(+), 50 deletions(-) create mode 100644 client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java diff --git a/client/src/main/java/io/split/Spec.java b/client/src/main/java/io/split/Spec.java index 37c544fe..79f9a4bc 100644 --- a/client/src/main/java/io/split/Spec.java +++ b/client/src/main/java/io/split/Spec.java @@ -8,7 +8,6 @@ private Spec() { // TODO: Change the schema to 1.3 when updating splitclient public static final String SPEC_1_3 = "1.3"; - public static final String SPEC_1_2 = "1.2"; public static final String SPEC_1_1 = "1.1"; public static String SPEC_VERSION = SPEC_1_3; } diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index 8a834878..e621fc57 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -1,11 +1,14 @@ package io.split.client; import com.google.common.annotations.VisibleForTesting; -import com.google.gson.JsonObject; import io.split.Spec; import io.split.client.dtos.SplitChange; import io.split.client.dtos.SplitHttpResponse; +import io.split.client.dtos.RuleBasedSegment; +import io.split.client.dtos.SplitChangesOldPayloadDto; +import io.split.client.dtos.ChangeDto; +import io.split.client.dtos.Split; import io.split.client.exceptions.UriTooLongException; import io.split.client.utils.Json; import io.split.client.utils.Utils; @@ -22,11 +25,12 @@ import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import static com.google.common.base.Preconditions.checkNotNull; import static io.split.Spec.SPEC_VERSION; import static io.split.Spec.SPEC_1_3; -import static io.split.Spec.SPEC_1_2; +import static io.split.Spec.SPEC_1_1; /** * Created by adilaijaz on 5/30/15. @@ -40,7 +44,7 @@ public final class HttpSplitChangeFetcher implements SplitChangeFetcher { private static final String TILL = "till"; private static final String SETS = "sets"; private static final String SPEC = "s"; - private int PROXY_CHECK_INTERVAL_MINUTES_SS = 24 * 60; + private int PROXY_CHECK_INTERVAL_MILLISECONDS_SS = 24 * 60 * 60 * 1000; private Long _lastProxyCheckTimestamp = 0L; private final SplitHttpClient _client; private final URI _target; @@ -70,47 +74,47 @@ long makeRandomTill() { public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { long start = System.currentTimeMillis(); SplitHttpResponse response; - while (true) { - try { - if (SPEC_VERSION.equals(SPEC_1_2) && (System.currentTimeMillis() - _lastProxyCheckTimestamp >= PROXY_CHECK_INTERVAL_MINUTES_SS)) { - _log.info("Switching to new Feature flag spec ({}) and fetching.", SPEC_1_3); - SPEC_VERSION = SPEC_1_3; + try { + if (SPEC_VERSION.equals(SPEC_1_1) && (System.currentTimeMillis() - _lastProxyCheckTimestamp >= PROXY_CHECK_INTERVAL_MILLISECONDS_SS)) { + _log.info("Switching to new Feature flag spec ({}) and fetching.", SPEC_1_3); + SPEC_VERSION = SPEC_1_3; + } + URI uri = buildURL(options, since, sinceRBS); + response = _client.get(uri, options, null); + if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) { + if (response.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", response.statusCode(), response.statusMessage())); } - URI uri = buildURL(options, since, sinceRBS); - response = _client.get(uri, options, null); - if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) { - if (response.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", response.statusCode(), response.statusMessage())); - } - - if (response.statusCode() == HttpStatus.SC_BAD_REQUEST && SPEC_VERSION.equals(Spec.SPEC_1_3) && _rootURIOverriden) { - SPEC_VERSION = Spec.SPEC_1_2; - _log.warn("Detected proxy without support for Feature flags spec {} version, will switch to spec version {}", - SPEC_1_3, SPEC_1_2); - _lastProxyCheckTimestamp = System.currentTimeMillis(); - continue; - } - - _telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode()); - throw new IllegalStateException( - String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode()) - ); + + if (response.statusCode() == HttpStatus.SC_BAD_REQUEST && SPEC_VERSION.equals(Spec.SPEC_1_3) && _rootURIOverriden) { + SPEC_VERSION = Spec.SPEC_1_1; + _log.warn("Detected proxy without support for Feature flags spec {} version, will switch to spec version {}", + SPEC_1_3, SPEC_1_1); + _lastProxyCheckTimestamp = System.currentTimeMillis(); + return fetch(since, sinceRBS, options); } - break; - } catch (Exception e) { - throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e); - } finally { - _telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start); + + _telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode()); + throw new IllegalStateException( + String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode()) + ); } + } catch (Exception e) { + throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e); + } finally { + _telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start); } - String body = response.body(); - if (SPEC_VERSION.equals(Spec.SPEC_1_2)) { - body = convertBodyToOldSpec(body); + SplitChange splitChange = new SplitChange(); + if (SPEC_VERSION.equals(Spec.SPEC_1_1)) { + splitChange.featureFlags = convertBodyToOldSpec(response.body()); + splitChange.ruleBasedSegments = createEmptyDTO(); _lastProxyCheckTimestamp = System.currentTimeMillis(); + } else { + splitChange = Json.fromJson(response.body(), SplitChange.class); } - return Json.fromJson(body, SplitChange.class); + return splitChange; } public Long getLastProxyCheckTimestamp() { @@ -123,14 +127,15 @@ public void setLastProxyCheckTimestamp(long lastProxyCheckTimestamp) { } } - private String convertBodyToOldSpec(String body) { - JsonObject targetBody = Json.fromJson("{\"ff\": {\"t\":-1, \"s\": -1}," + - "\"rbs\": {\"d\":[], \"t\":-1, \"s\": -1}}", JsonObject.class); - JsonObject jsonBody = Json.fromJson(body, JsonObject.class); - targetBody.getAsJsonObject("ff").add("d", jsonBody.getAsJsonArray("splits")); - targetBody.getAsJsonObject("ff").add("s", jsonBody.get("since")); - targetBody.getAsJsonObject("ff").add("t", jsonBody.get("till")); - return Json.toJson(targetBody); + private ChangeDto createEmptyDTO() { + ChangeDto dto = new ChangeDto<>(); + dto.d = new ArrayList<>(); + dto.t = -1; + dto.s = -1; + return dto; + } + private ChangeDto convertBodyToOldSpec(String body) { + return Json.fromJson(body, SplitChangesOldPayloadDto.class).toChangeDTO(); } private URI buildURL(FetchOptions options, long since, long sinceRBS) throws URISyntaxException { diff --git a/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java b/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java new file mode 100644 index 00000000..1fd9f313 --- /dev/null +++ b/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java @@ -0,0 +1,25 @@ +package io.split.client.dtos; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class SplitChangesOldPayloadDto { + @SerializedName("since") + public long s; + + @SerializedName("till") + public long t; + + @SerializedName("splits") + public List d; + + public ChangeDto toChangeDTO() { + ChangeDto dto = new ChangeDto<>(); + dto.s = this.s; + dto.t = this.t; + dto.d = this.d; + return dto; + + } +} diff --git a/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java b/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java index 3b3f41b2..47b2cc1f 100644 --- a/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java +++ b/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java @@ -249,11 +249,11 @@ public void testSwitchingToOldSpec() throws URISyntaxException, InvocationTarget SplitChange change = fetcher.fetch(-1, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); - Assert.assertEquals(Spec.SPEC_1_2, Spec.SPEC_VERSION); + Assert.assertEquals(Spec.SPEC_1_1, Spec.SPEC_VERSION); List captured = requestCaptor.getAllValues(); Assert.assertEquals(captured.size(), 2); Assert.assertTrue(captured.get(0).getUri().toString().contains("s=1.3")); - Assert.assertTrue(captured.get(1).getUri().toString().contains("s=1.2")); + Assert.assertTrue(captured.get(1).getUri().toString().contains("s=1.1")); Assert.assertEquals(122, change.featureFlags.s); Assert.assertEquals(123, change.featureFlags.t); Assert.assertEquals(2, change.featureFlags.d.size()); @@ -271,9 +271,9 @@ public void testSwitchingToOldSpec() throws URISyntaxException, InvocationTarget Thread.sleep(1000); change = fetcher.fetch(-1, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); - Assert.assertEquals(Spec.SPEC_1_2, Spec.SPEC_VERSION); + Assert.assertEquals(Spec.SPEC_1_1, Spec.SPEC_VERSION); Assert.assertTrue(captured.get(2).getUri().toString().contains("s=1.3")); - Assert.assertTrue(captured.get(3).getUri().toString().contains("s=1.2")); + Assert.assertTrue(captured.get(3).getUri().toString().contains("s=1.1")); Assert.assertEquals(122, change.featureFlags.s); Assert.assertEquals(123, change.featureFlags.t); Assert.assertEquals(2, change.featureFlags.d.size()); From 652ea96d97216cf3743bfcca703aada9c1010079 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Tue, 22 Apr 2025 21:06:56 -0700 Subject: [PATCH 03/16] polish --- .../test/java/io/split/client/HttpSplitChangeFetcherTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java b/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java index 47b2cc1f..37c52cd8 100644 --- a/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java +++ b/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java @@ -265,7 +265,7 @@ public void testSwitchingToOldSpec() throws URISyntaxException, InvocationTarget Assert.assertTrue(fetcher.getLastProxyCheckTimestamp() > 0); // Set proxy interval to low number to force check for spec 1.3 - Field proxyInterval = fetcher.getClass().getDeclaredField("PROXY_CHECK_INTERVAL_MINUTES_SS"); + Field proxyInterval = fetcher.getClass().getDeclaredField("PROXY_CHECK_INTERVAL_MILLISECONDS_SS"); proxyInterval.setAccessible(true); proxyInterval.set(fetcher, 5); Thread.sleep(1000); From 56082ef1a5aa8482141c02ee500e70202ada487c Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Tue, 22 Apr 2025 22:07:34 -0700 Subject: [PATCH 04/16] polish --- client/src/main/java/io/split/client/HttpSplitChangeFetcher.java | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index e621fc57..1b084e24 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -110,7 +110,6 @@ public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { if (SPEC_VERSION.equals(Spec.SPEC_1_1)) { splitChange.featureFlags = convertBodyToOldSpec(response.body()); splitChange.ruleBasedSegments = createEmptyDTO(); - _lastProxyCheckTimestamp = System.currentTimeMillis(); } else { splitChange = Json.fromJson(response.body(), SplitChange.class); } From 682ba450e5f1553844b55b0c65fe2ad07c134ccc Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:28:47 -0700 Subject: [PATCH 05/16] Update client/src/main/java/io/split/client/HttpSplitChangeFetcher.java Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- .../src/main/java/io/split/client/HttpSplitChangeFetcher.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index 1b084e24..9d69b256 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -133,9 +133,6 @@ private ChangeDto createEmptyDTO() { dto.s = -1; return dto; } - private ChangeDto convertBodyToOldSpec(String body) { - return Json.fromJson(body, SplitChangesOldPayloadDto.class).toChangeDTO(); - } private URI buildURL(FetchOptions options, long since, long sinceRBS) throws URISyntaxException { URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + SPEC_VERSION); From fabf7874f4d0eb74ec902226d0cdd10673b68848 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:29:04 -0700 Subject: [PATCH 06/16] Update client/src/main/java/io/split/client/HttpSplitChangeFetcher.java Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- .../java/io/split/client/HttpSplitChangeFetcher.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index 9d69b256..e52cced1 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -106,14 +106,11 @@ public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { _telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start); } - SplitChange splitChange = new SplitChange(); if (SPEC_VERSION.equals(Spec.SPEC_1_1)) { - splitChange.featureFlags = convertBodyToOldSpec(response.body()); - splitChange.ruleBasedSegments = createEmptyDTO(); - } else { - splitChange = Json.fromJson(response.body(), SplitChange.class); + return Json.fromJson(body, SplitChangesOldPayloadDto.class).toSplitChange(); } - return splitChange; + + return Json.fromJson(response.body(), SplitChange.class); } public Long getLastProxyCheckTimestamp() { From 0b14464c2fe6c9f237007166be68f7febb6473df Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:29:13 -0700 Subject: [PATCH 07/16] Update client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- .../dtos/SplitChangesOldPayloadDto.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java b/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java index 1fd9f313..a48edb0d 100644 --- a/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java +++ b/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java @@ -14,12 +14,20 @@ public class SplitChangesOldPayloadDto { @SerializedName("splits") public List d; - public ChangeDto toChangeDTO() { - ChangeDto dto = new ChangeDto<>(); - dto.s = this.s; - dto.t = this.t; - dto.d = this.d; - return dto; - + public SplitChange toSplitChange() { + SplitChange splitChange = new SplitChange(); + ChangeDto ff = new ChangeDto<>(); + ff.s = this.s; + ff.t = this.t; + ff.d = this.d; + ChangeDto rbs = new ChangeDto<>(); + rbs.d = new ArrayList<>(); + rbs.t = -1; + rbs.s = -1; + + splitChange.ff = ff; + splitChange.rbs = rbs; + + return splitChange; } } From b86ac7528125c4cf7116af3015da282c7d0baba4 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:30:45 -0700 Subject: [PATCH 08/16] Update client/src/main/java/io/split/client/SplitClientConfig.java Co-authored-by: gthea --- client/src/main/java/io/split/client/SplitClientConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitClientConfig.java b/client/src/main/java/io/split/client/SplitClientConfig.java index fa73ef8c..fd312c3b 100644 --- a/client/src/main/java/io/split/client/SplitClientConfig.java +++ b/client/src/main/java/io/split/client/SplitClientConfig.java @@ -412,8 +412,8 @@ public CustomHeaderDecorator customHeaderDecorator() { return _customHeaderDecorator; } - public boolean isRootURIOverriden() { - return _endpoint == SDK_ENDPOINT; + public boolean isSdkEndpointOverridden() { + return !_endpoint.equals(SDK_ENDPOINT); } public CustomHttpModule alternativeHTTPModule() { return _alternativeHTTPModule; } From 94ac3ed68fbc8a7090f74645279031ed00714769 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 25 Apr 2025 12:36:56 -0700 Subject: [PATCH 09/16] removed spec_version global var --- client/src/main/java/io/split/Spec.java | 1 - .../split/client/HttpSplitChangeFetcher.java | 19 ++++++++++--------- .../io/split/client/SplitFactoryImpl.java | 2 +- .../dtos/SplitChangesOldPayloadDto.java | 5 +++-- .../io/split/engine/sse/AuthApiClientImp.java | 4 ++-- .../client/HttpSplitChangeFetcherTest.java | 8 ++++---- .../SegmentSynchronizationTaskImpTest.java | 1 - 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/client/src/main/java/io/split/Spec.java b/client/src/main/java/io/split/Spec.java index 79f9a4bc..05d73aba 100644 --- a/client/src/main/java/io/split/Spec.java +++ b/client/src/main/java/io/split/Spec.java @@ -9,6 +9,5 @@ private Spec() { // TODO: Change the schema to 1.3 when updating splitclient public static final String SPEC_1_3 = "1.3"; public static final String SPEC_1_1 = "1.1"; - public static String SPEC_VERSION = SPEC_1_3; } diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index e52cced1..4ee2f22e 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import static com.google.common.base.Preconditions.checkNotNull; -import static io.split.Spec.SPEC_VERSION; import static io.split.Spec.SPEC_1_3; import static io.split.Spec.SPEC_1_1; @@ -44,6 +43,7 @@ public final class HttpSplitChangeFetcher implements SplitChangeFetcher { private static final String TILL = "till"; private static final String SETS = "sets"; private static final String SPEC = "s"; + private String specVersion = SPEC_1_3; private int PROXY_CHECK_INTERVAL_MILLISECONDS_SS = 24 * 60 * 60 * 1000; private Long _lastProxyCheckTimestamp = 0L; private final SplitHttpClient _client; @@ -75,9 +75,9 @@ public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { long start = System.currentTimeMillis(); SplitHttpResponse response; try { - if (SPEC_VERSION.equals(SPEC_1_1) && (System.currentTimeMillis() - _lastProxyCheckTimestamp >= PROXY_CHECK_INTERVAL_MILLISECONDS_SS)) { + if (specVersion.equals(SPEC_1_1) && (System.currentTimeMillis() - _lastProxyCheckTimestamp >= PROXY_CHECK_INTERVAL_MILLISECONDS_SS)) { _log.info("Switching to new Feature flag spec ({}) and fetching.", SPEC_1_3); - SPEC_VERSION = SPEC_1_3; + specVersion = SPEC_1_3; } URI uri = buildURL(options, since, sinceRBS); response = _client.get(uri, options, null); @@ -87,12 +87,12 @@ public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { throw new UriTooLongException(String.format("Status code: %s. Message: %s", response.statusCode(), response.statusMessage())); } - if (response.statusCode() == HttpStatus.SC_BAD_REQUEST && SPEC_VERSION.equals(Spec.SPEC_1_3) && _rootURIOverriden) { - SPEC_VERSION = Spec.SPEC_1_1; + if (response.statusCode() == HttpStatus.SC_BAD_REQUEST && specVersion.equals(Spec.SPEC_1_3) && _rootURIOverriden) { + specVersion = Spec.SPEC_1_1; _log.warn("Detected proxy without support for Feature flags spec {} version, will switch to spec version {}", SPEC_1_3, SPEC_1_1); _lastProxyCheckTimestamp = System.currentTimeMillis(); - return fetch(since, sinceRBS, options); + return fetch(since, 0, options); } _telemetryRuntimeProducer.recordSyncError(ResourceEnum.SPLIT_SYNC, response.statusCode()); @@ -106,11 +106,12 @@ public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { _telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start); } - if (SPEC_VERSION.equals(Spec.SPEC_1_1)) { + String body = response.body(); + if (specVersion.equals(Spec.SPEC_1_1)) { return Json.fromJson(body, SplitChangesOldPayloadDto.class).toSplitChange(); } - return Json.fromJson(response.body(), SplitChange.class); + return Json.fromJson(body, SplitChange.class); } public Long getLastProxyCheckTimestamp() { @@ -132,7 +133,7 @@ private ChangeDto createEmptyDTO() { } private URI buildURL(FetchOptions options, long since, long sinceRBS) throws URISyntaxException { - URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + SPEC_VERSION); + URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + specVersion); uriBuilder.addParameter(SINCE, "" + since); uriBuilder.addParameter(RB_SINCE, "" + sinceRBS); if (!options.flagSetsFilter().isEmpty()) { diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index dfe82c6a..f367f7a1 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -225,7 +225,7 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser(); // SplitFetcher _splitFetcher = buildSplitFetcher(splitCache, splitParser, flagSetsFilter, - ruleBasedSegmentParser, ruleBasedSegmentCache, config.isRootURIOverriden()); + ruleBasedSegmentParser, ruleBasedSegmentCache, config.isSdkEndpointOverridden()); // SplitSynchronizationTask _splitSynchronizationTask = new SplitSynchronizationTask(_splitFetcher, diff --git a/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java b/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java index a48edb0d..aa292f91 100644 --- a/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java +++ b/client/src/main/java/io/split/client/dtos/SplitChangesOldPayloadDto.java @@ -2,6 +2,7 @@ import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; import java.util.List; public class SplitChangesOldPayloadDto { @@ -25,8 +26,8 @@ public SplitChange toSplitChange() { rbs.t = -1; rbs.s = -1; - splitChange.ff = ff; - splitChange.rbs = rbs; + splitChange.featureFlags = ff; + splitChange.ruleBasedSegments = rbs; return splitChange; } diff --git a/client/src/main/java/io/split/engine/sse/AuthApiClientImp.java b/client/src/main/java/io/split/engine/sse/AuthApiClientImp.java index 28464ebd..5c45e1b7 100644 --- a/client/src/main/java/io/split/engine/sse/AuthApiClientImp.java +++ b/client/src/main/java/io/split/engine/sse/AuthApiClientImp.java @@ -1,6 +1,7 @@ package io.split.engine.sse; import com.google.gson.JsonObject; +import io.split.Spec; import io.split.client.dtos.SplitHttpResponse; import io.split.client.utils.Json; import io.split.engine.common.FetchOptions; @@ -18,7 +19,6 @@ import java.net.URI; import static com.google.common.base.Preconditions.checkNotNull; -import static io.split.Spec.SPEC_VERSION; public class AuthApiClientImp implements AuthApiClient { private static final Logger _log = LoggerFactory.getLogger(AuthApiClientImp.class); @@ -38,7 +38,7 @@ public AuthApiClientImp(String url, SplitHttpClient httpClient, TelemetryRuntime public AuthenticationResponse Authenticate() { try { long initTime = System.currentTimeMillis(); - URI uri = new URIBuilder(_target).addParameter(SPEC, "" + SPEC_VERSION).build(); + URI uri = new URIBuilder(_target).addParameter(SPEC, "" + Spec.SPEC_1_3).build(); SplitHttpResponse response = _httpClient.get(uri, new FetchOptions.Builder().cacheControlHeaders(false).build(), null); Integer statusCode = response.statusCode(); diff --git a/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java b/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java index 37c52cd8..7bb30e80 100644 --- a/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java +++ b/client/src/test/java/io/split/client/HttpSplitChangeFetcherTest.java @@ -198,7 +198,6 @@ public void testURLTooLong() throws IOException, URISyntaxException, IllegalAcce @Test public void testSwitchingToOldSpec() throws URISyntaxException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException, NoSuchFieldException, InterruptedException { - Spec.SPEC_VERSION = Spec.SPEC_1_3; URI rootTarget = URI.create("https://api.split.io"); CloseableHttpClient httpClientMock = Mockito.mock(CloseableHttpClient.class); HttpEntity entityMock = Mockito.mock(HttpEntity.class); @@ -247,9 +246,12 @@ public void testSwitchingToOldSpec() throws URISyntaxException, InvocationTarget HttpSplitChangeFetcher fetcher = HttpSplitChangeFetcher.create(splitHtpClient, rootTarget, Mockito.mock(TelemetryRuntimeProducer.class), true); + Field specVersion = fetcher.getClass().getDeclaredField("specVersion"); + specVersion.setAccessible(true); + specVersion.set(fetcher, Spec.SPEC_1_1); + SplitChange change = fetcher.fetch(-1, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); - Assert.assertEquals(Spec.SPEC_1_1, Spec.SPEC_VERSION); List captured = requestCaptor.getAllValues(); Assert.assertEquals(captured.size(), 2); Assert.assertTrue(captured.get(0).getUri().toString().contains("s=1.3")); @@ -271,7 +273,6 @@ public void testSwitchingToOldSpec() throws URISyntaxException, InvocationTarget Thread.sleep(1000); change = fetcher.fetch(-1, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); - Assert.assertEquals(Spec.SPEC_1_1, Spec.SPEC_VERSION); Assert.assertTrue(captured.get(2).getUri().toString().contains("s=1.3")); Assert.assertTrue(captured.get(3).getUri().toString().contains("s=1.1")); Assert.assertEquals(122, change.featureFlags.s); @@ -283,7 +284,6 @@ public void testSwitchingToOldSpec() throws URISyntaxException, InvocationTarget // test if proxy is upgraded and spec 1.3 now works. Thread.sleep(1000); change = fetcher.fetch(-1, -1, new FetchOptions.Builder().cacheControlHeaders(true).build()); - Assert.assertEquals(Spec.SPEC_1_3, Spec.SPEC_VERSION); Assert.assertTrue(captured.get(4).getUri().toString().contains("s=1.3")); Assert.assertEquals(122, change.featureFlags.s); Assert.assertEquals(123, change.featureFlags.t); diff --git a/client/src/test/java/io/split/engine/segments/SegmentSynchronizationTaskImpTest.java b/client/src/test/java/io/split/engine/segments/SegmentSynchronizationTaskImpTest.java index 5270c65a..ae33691e 100644 --- a/client/src/test/java/io/split/engine/segments/SegmentSynchronizationTaskImpTest.java +++ b/client/src/test/java/io/split/engine/segments/SegmentSynchronizationTaskImpTest.java @@ -171,7 +171,6 @@ public void testLocalhostSegmentChangeFetcher() throws InterruptedException, Fil ruleBasedSegmentParser, ruleBasedSegmentCacheProducer); SplitSynchronizationTask splitSynchronizationTask = new SplitSynchronizationTask(splitFetcher, splitCacheProducer, 1000, null); - Spec.SPEC_VERSION = Spec.SPEC_1_1; // check old spec splitSynchronizationTask.start(); From 9117c38e5dfbdb9ec28d230d0fd3279cd548a45e Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 25 Apr 2025 12:39:05 -0700 Subject: [PATCH 10/16] polish --- .../src/main/java/io/split/client/HttpSplitChangeFetcher.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index 4ee2f22e..dcf537a4 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -135,7 +135,9 @@ private ChangeDto createEmptyDTO() { private URI buildURL(FetchOptions options, long since, long sinceRBS) throws URISyntaxException { URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + specVersion); uriBuilder.addParameter(SINCE, "" + since); - uriBuilder.addParameter(RB_SINCE, "" + sinceRBS); + if (specVersion.equals(SPEC_1_3)) { + uriBuilder.addParameter(RB_SINCE, "" + sinceRBS); + } if (!options.flagSetsFilter().isEmpty()) { uriBuilder.addParameter(SETS, "" + options.flagSetsFilter()); } From 37a7f98cf325364315532d1318bc9a135565ae06 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 25 Apr 2025 12:56:27 -0700 Subject: [PATCH 11/16] moved block --- .../io/split/client/HttpSplitChangeFetcher.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index dcf537a4..ae0dcb01 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -100,18 +100,19 @@ public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode()) ); } + + String body = response.body(); + if (specVersion.equals(Spec.SPEC_1_1)) { + return Json.fromJson(body, SplitChangesOldPayloadDto.class).toSplitChange(); + } + + return Json.fromJson(body, SplitChange.class); + } catch (Exception e) { throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e); } finally { _telemetryRuntimeProducer.recordSyncLatency(HTTPLatenciesEnum.SPLITS, System.currentTimeMillis() - start); } - - String body = response.body(); - if (specVersion.equals(Spec.SPEC_1_1)) { - return Json.fromJson(body, SplitChangesOldPayloadDto.class).toSplitChange(); - } - - return Json.fromJson(body, SplitChange.class); } public Long getLastProxyCheckTimestamp() { From 6d5ccb26cbd28447c99245337b4416b210665535 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 25 Apr 2025 18:41:00 -0700 Subject: [PATCH 12/16] fix tests --- .../client/SplitClientIntegrationTest.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java index 51d55135..ecc97496 100644 --- a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java +++ b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java @@ -1,11 +1,13 @@ package io.split.client; import io.split.SSEMockServer; +import io.split.Spec; import io.split.SplitMockServer; import io.split.client.api.SplitView; import io.split.client.dtos.EvaluationOptions; import io.split.client.impressions.ImpressionsManager; import io.split.client.utils.CustomDispatcher; +import io.split.engine.experiments.SplitFetcherImp; import io.split.storages.enums.OperationMode; import io.split.storages.enums.StorageMode; import io.split.storages.pluggable.CustomStorageWrapperImp; @@ -24,6 +26,7 @@ import javax.ws.rs.sse.OutboundSseEvent; import java.io.IOException; +import java.lang.reflect.Field; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -246,13 +249,14 @@ public void managerSplitsWithStreamingEnabled() throws Exception { splitServer.stop(); sseServer.stop(); + factory.destroy(); } @Test public void splitClientOccupancyNotifications() throws Exception { - MockResponse response = new MockResponse().setBody("{\"ff\":{\"d\": [], \"s\":1585948850109, \"t\":1585948850109}, \"rbs\":{\"d\":[],\"s\":-1,\"t\":-1}}"); - MockResponse response2 = new MockResponse().setBody("{\"ff\":{\"d\": [], \"s\":1585948850110, \"t\":1585948850110}, \"rbs\":{\"d\":[],\"s\":-1,\"t\":-1}}"); - MockResponse response3 = new MockResponse().setBody("{\"ff\":{\"d\": [], \"s\":1585948850111, \"t\":1585948850111}, \"rbs\":{\"d\":[],\"s\":-1,\"t\":-1}}"); + MockResponse response = new MockResponse().setBody("{\"ff\":{\"d\": [], \"s\":1585948850109, \"t\":1585948850109}, \"rbs\":{\"d\":[],\"s\":1585948850109,\"t\":1585948850109}}"); + MockResponse response2 = new MockResponse().setBody("{\"ff\":{\"d\": [], \"s\":1585948850110, \"t\":1585948850110}, \"rbs\":{\"d\":[],\"s\":1585948850110,\"t\":1585948850110}}"); + MockResponse response3 = new MockResponse().setBody("{\"ff\":{\"d\": [], \"s\":1585948850111, \"t\":1585948850111}, \"rbs\":{\"d\":[],\"s\":1585948850111,\"t\":1585948850111}}"); Queue responses = new LinkedList<>(); responses.add(response); Queue responses2 = new LinkedList<>(); @@ -420,7 +424,7 @@ public void splitClientControlNotifications() throws Exception { @Test public void splitClientMultiFactory() throws Exception { - MockResponse response = new MockResponse().setBody("{\"ff\":{\"d\": [], \"s\":1585948850109, \"t\":1585948850109}, \"rbs\":{\"d\":[],\"s\":-1,\"t\":-1}}"); + MockResponse response = new MockResponse().setBody("{\"ff\":{\"d\":[],\"s\":1585948850109, \"t\":1585948850109},\"rbs\":{\"d\":[],\"s\":1585948850109,\"t\":1585948850109}}"); Queue responses = new LinkedList<>(); responses.add(response); responses.add(response); @@ -573,9 +577,10 @@ public void keepAlive() throws Exception { Queue responses = new LinkedList<>(); responses.add(response); - SplitMockServer splitServer = new SplitMockServer(CustomDispatcher.builder() + CustomDispatcher dispatcher = CustomDispatcher.builder() .path(CustomDispatcher.SINCE_1585948850109, responses) - .build()); + .build(); + SplitMockServer splitServer = new SplitMockServer(dispatcher); //plitMockServer splitServer = new SplitMockServer(CustomDispatcher.builder().build()); SSEMockServer.SseEventQueue eventQueue = new SSEMockServer.SseEventQueue(); @@ -594,7 +599,6 @@ public void keepAlive() throws Exception { // wait to check keep alive notification. Thread.sleep(50000); - // must reconnect and after the second syncAll the result must be different Awaitility.await() .atMost(1L, TimeUnit.MINUTES) @@ -641,6 +645,7 @@ public void testConnectionClosedByRemoteHostIsProperlyHandled() throws Exception Thread.sleep(1000); result = client.getTreatment("admin", "push_test"); Assert.assertNotEquals("on_whitelist", result); + client.destroy(); } @Test @@ -677,6 +682,7 @@ public void testConnectionClosedIsProperlyHandled() throws Exception { Thread.sleep(1000); result = client.getTreatment("admin", "push_test"); Assert.assertNotEquals("on_whitelist", result); + client.destroy(); } @Test @@ -745,15 +751,15 @@ public void testPluggableMode() throws IOException, URISyntaxException { Assert.assertNotNull(customStorageWrapper.getConfig()); String key = customStorageWrapper.getConfig().keySet().stream().collect(Collectors.toList()).get(0); Assert.assertTrue(customStorageWrapper.getConfig().get(key).contains(StorageMode.PLUGGABLE.name())); - + client.destroy(); } catch (TimeoutException | InterruptedException e) { } } @Test public void getTreatmentFlagSetWithPolling() throws Exception { - MockResponse response = new MockResponse().setBody("{\"splits\":[{\"trafficTypeName\":\"client\",\"name\":\"workm\",\"trafficAllocation\":100,\"trafficAllocationSeed\":147392224,\"seed\":524417105,\"status\":\"ACTIVE\",\"killed\":false,\"defaultTreatment\":\"on\",\"changeNumber\":1602796638344,\"algo\":2,\"configurations\":{},\"sets\":[\"set1\",\"set2\"],\"conditions\":[{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"client\",\"attribute\":null},\"matcherType\":\"IN_SEGMENT\",\"negate\":false,\"userDefinedSegmentMatcherData\":{\"segmentName\":\"new_segment\"},\"whitelistMatcherData\":null,\"unaryNumericMatcherData\":null,\"betweenMatcherData\":null,\"booleanMatcherData\":null,\"dependencyMatcherData\":null,\"stringMatcherData\":null}]},\"partitions\":[{\"treatment\":\"on\",\"size\":0},{\"treatment\":\"off\",\"size\":0},{\"treatment\":\"free\",\"size\":100},{\"treatment\":\"conta\",\"size\":0}],\"label\":\"in segment new_segment\"},{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"client\",\"attribute\":null},\"matcherType\":\"ALL_KEYS\",\"negate\":false,\"userDefinedSegmentMatcherData\":null,\"whitelistMatcherData\":null,\"unaryNumericMatcherData\":null,\"betweenMatcherData\":null,\"booleanMatcherData\":null,\"dependencyMatcherData\":null,\"stringMatcherData\":null}]},\"partitions\":[{\"treatment\":\"on\",\"size\":100},{\"treatment\":\"off\",\"size\":0},{\"treatment\":\"free\",\"size\":0},{\"treatment\":\"conta\",\"size\":0}],\"label\":\"default rule\"}]},{\"trafficTypeName\":\"client\",\"name\":\"workm_set_3\",\"trafficAllocation\":100,\"trafficAllocationSeed\":147392224,\"seed\":524417105,\"status\":\"ACTIVE\",\"killed\":false,\"defaultTreatment\":\"on\",\"changeNumber\":1602796638344,\"algo\":2,\"configurations\":{},\"sets\":[\"set3\"],\"conditions\":[{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"client\",\"attribute\":null},\"matcherType\":\"IN_SEGMENT\",\"negate\":false,\"userDefinedSegmentMatcherData\":{\"segmentName\":\"new_segment\"},\"whitelistMatcherData\":null,\"unaryNumericMatcherData\":null,\"betweenMatcherData\":null,\"booleanMatcherData\":null,\"dependencyMatcherData\":null,\"stringMatcherData\":null}]},\"partitions\":[{\"treatment\":\"on\",\"size\":0},{\"treatment\":\"off\",\"size\":0},{\"treatment\":\"free\",\"size\":100},{\"treatment\":\"conta\",\"size\":0}],\"label\":\"in segment new_segment\"},{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"client\",\"attribute\":null},\"matcherType\":\"ALL_KEYS\",\"negate\":false,\"userDefinedSegmentMatcherData\":null,\"whitelistMatcherData\":null,\"unaryNumericMatcherData\":null,\"betweenMatcherData\":null,\"booleanMatcherData\":null,\"dependencyMatcherData\":null,\"stringMatcherData\":null}]},\"partitions\":[{\"treatment\":\"on\",\"size\":100},{\"treatment\":\"off\",\"size\":0},{\"treatment\":\"free\",\"size\":0},{\"treatment\":\"conta\",\"size\":0}],\"label\":\"default rule\"}]}],\"since\":-1,\"till\":1602796638344}"); - MockResponse responseFlag = new MockResponse().setBody("{\"splits\": [], \"since\":1602796638344, \"till\":1602796638344}"); + MockResponse response = new MockResponse().setBody("{\"ff\":{\"d\":[{\"trafficTypeName\":\"client\",\"name\":\"workm\",\"trafficAllocation\":100,\"trafficAllocationSeed\":147392224,\"seed\":524417105,\"status\":\"ACTIVE\",\"killed\":false,\"defaultTreatment\":\"on\",\"changeNumber\":1602796638344,\"algo\":2,\"configurations\":{},\"sets\":[\"set1\",\"set2\"],\"conditions\":[{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"client\",\"attribute\":null},\"matcherType\":\"IN_SEGMENT\",\"negate\":false,\"userDefinedSegmentMatcherData\":{\"segmentName\":\"new_segment\"},\"whitelistMatcherData\":null,\"unaryNumericMatcherData\":null,\"betweenMatcherData\":null,\"booleanMatcherData\":null,\"dependencyMatcherData\":null,\"stringMatcherData\":null}]},\"partitions\":[{\"treatment\":\"on\",\"size\":0},{\"treatment\":\"off\",\"size\":0},{\"treatment\":\"free\",\"size\":100},{\"treatment\":\"conta\",\"size\":0}],\"label\":\"in segment new_segment\"},{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"client\",\"attribute\":null},\"matcherType\":\"ALL_KEYS\",\"negate\":false,\"userDefinedSegmentMatcherData\":null,\"whitelistMatcherData\":null,\"unaryNumericMatcherData\":null,\"betweenMatcherData\":null,\"booleanMatcherData\":null,\"dependencyMatcherData\":null,\"stringMatcherData\":null}]},\"partitions\":[{\"treatment\":\"on\",\"size\":100},{\"treatment\":\"off\",\"size\":0},{\"treatment\":\"free\",\"size\":0},{\"treatment\":\"conta\",\"size\":0}],\"label\":\"default rule\"}]},{\"trafficTypeName\":\"client\",\"name\":\"workm_set_3\",\"trafficAllocation\":100,\"trafficAllocationSeed\":147392224,\"seed\":524417105,\"status\":\"ACTIVE\",\"killed\":false,\"defaultTreatment\":\"on\",\"changeNumber\":1602796638344,\"algo\":2,\"configurations\":{},\"sets\":[\"set3\"],\"conditions\":[{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"client\",\"attribute\":null},\"matcherType\":\"IN_SEGMENT\",\"negate\":false,\"userDefinedSegmentMatcherData\":{\"segmentName\":\"new_segment\"},\"whitelistMatcherData\":null,\"unaryNumericMatcherData\":null,\"betweenMatcherData\":null,\"booleanMatcherData\":null,\"dependencyMatcherData\":null,\"stringMatcherData\":null}]},\"partitions\":[{\"treatment\":\"on\",\"size\":0},{\"treatment\":\"off\",\"size\":0},{\"treatment\":\"free\",\"size\":100},{\"treatment\":\"conta\",\"size\":0}],\"label\":\"in segment new_segment\"},{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"client\",\"attribute\":null},\"matcherType\":\"ALL_KEYS\",\"negate\":false,\"userDefinedSegmentMatcherData\":null,\"whitelistMatcherData\":null,\"unaryNumericMatcherData\":null,\"betweenMatcherData\":null,\"booleanMatcherData\":null,\"dependencyMatcherData\":null,\"stringMatcherData\":null}]},\"partitions\":[{\"treatment\":\"on\",\"size\":100},{\"treatment\":\"off\",\"size\":0},{\"treatment\":\"free\",\"size\":0},{\"treatment\":\"conta\",\"size\":0}],\"label\":\"default rule\"}]}],\"s\":-1,\"t\":1602796638344},\"rbs\":{\"d\":[],\"t\":-1,\"s\":-1}}"); + MockResponse responseFlag = new MockResponse().setBody("{\"ff\":{\"d\":[],\"s\":1602796638344,\"t\":1602796638344},\"rbs\":{\"d\":[],\"t\":-1,\"s\":-1}}"); MockResponse segmentResponse = new MockResponse().setBody("{\"name\":\"new_segment\",\"added\":[\"user-1\"],\"removed\":[\"user-2\",\"user-3\"],\"since\":-1,\"till\":-1}"); Queue responses = new LinkedList<>(); responses.add(response); From 4a07bc65c3752760533610ce57cbef5a77f75166 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 25 Apr 2025 18:51:27 -0700 Subject: [PATCH 13/16] fix build error --- .../java/io/split/engine/experiments/SplitFetcherImpTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/test/java/io/split/engine/experiments/SplitFetcherImpTest.java b/client/src/test/java/io/split/engine/experiments/SplitFetcherImpTest.java index d2680413..3a1b0b99 100644 --- a/client/src/test/java/io/split/engine/experiments/SplitFetcherImpTest.java +++ b/client/src/test/java/io/split/engine/experiments/SplitFetcherImpTest.java @@ -164,7 +164,7 @@ public void testFetchingSplitsAndRuleBasedSegments() throws Exception { _sdkMetadata); URI _rootTarget = URI.create(config.endpoint()); SplitChangeFetcher splitChangeFetcher = HttpSplitChangeFetcher.create(_splitHttpClient, _rootTarget, - _telemetryStorageProducer); + _telemetryStorageProducer, config.isSdkEndpointOverridden()); SplitFetcherImp splitFetcher = new SplitFetcherImp(splitChangeFetcher, splitParser, splitCache, _telemetryStorageProducer, flagSetsFilter, ruleBasedSegmentParser, ruleBasedSegmentCache); From 8a6cdf18438d626065da3df9fc684f6e808a4d6a Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Mon, 28 Apr 2025 08:25:42 -0700 Subject: [PATCH 14/16] Update client/src/main/java/io/split/client/HttpSplitChangeFetcher.java Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- .../main/java/io/split/client/HttpSplitChangeFetcher.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index ae0dcb01..ed273a61 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -125,13 +125,6 @@ public void setLastProxyCheckTimestamp(long lastProxyCheckTimestamp) { } } - private ChangeDto createEmptyDTO() { - ChangeDto dto = new ChangeDto<>(); - dto.d = new ArrayList<>(); - dto.t = -1; - dto.s = -1; - return dto; - } private URI buildURL(FetchOptions options, long since, long sinceRBS) throws URISyntaxException { URIBuilder uriBuilder = new URIBuilder(_target).addParameter(SPEC, "" + specVersion); From 0669fa1ebdaccef31dff626879c4ba7e4f9bf61f Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Mon, 28 Apr 2025 08:26:11 -0700 Subject: [PATCH 15/16] Update client/src/main/java/io/split/client/HttpSplitChangeFetcher.java Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- client/src/main/java/io/split/client/HttpSplitChangeFetcher.java | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index ed273a61..8e8404f6 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -73,7 +73,6 @@ long makeRandomTill() { @Override public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { long start = System.currentTimeMillis(); - SplitHttpResponse response; try { if (specVersion.equals(SPEC_1_1) && (System.currentTimeMillis() - _lastProxyCheckTimestamp >= PROXY_CHECK_INTERVAL_MILLISECONDS_SS)) { _log.info("Switching to new Feature flag spec ({}) and fetching.", SPEC_1_3); From de79368c16063bfdedf777234d167e429efe891b Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Mon, 28 Apr 2025 08:26:19 -0700 Subject: [PATCH 16/16] Update client/src/main/java/io/split/client/HttpSplitChangeFetcher.java Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- .../src/main/java/io/split/client/HttpSplitChangeFetcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index 8e8404f6..ea54c0eb 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -79,7 +79,7 @@ public SplitChange fetch(long since, long sinceRBS, FetchOptions options) { specVersion = SPEC_1_3; } URI uri = buildURL(options, since, sinceRBS); - response = _client.get(uri, options, null); + SplitHttpResponse response = _client.get(uri, options, null); if (response.statusCode() < HttpStatus.SC_OK || response.statusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) { if (response.statusCode() == HttpStatus.SC_REQUEST_URI_TOO_LONG) { _log.error("The amount of flag sets provided are big causing uri length error.");