Skip to content

Commit d14da5c

Browse files
committed
add tests
1 parent 1a25c13 commit d14da5c

File tree

3 files changed

+148
-1
lines changed

3 files changed

+148
-1
lines changed

client/src/test/java/io/split/client/HttpSegmentChangeFetcherTest.java

+34-1
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,21 @@
66
import io.split.engine.metrics.Metrics;
77
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
88
import org.apache.hc.client5.http.impl.classic.HttpClients;
9-
import org.apache.hc.core5.http.HttpStatus;
9+
import org.apache.hc.core5.http.*;
1010
import org.hamcrest.Matchers;
1111
import org.junit.Assert;
1212
import org.junit.Test;
13+
import org.mockito.ArgumentCaptor;
14+
import org.mockito.Mockito;
1315

1416
import java.io.IOException;
17+
import java.io.StringBufferInputStream;
1518
import java.lang.reflect.InvocationTargetException;
1619
import java.net.URI;
1720
import java.net.URISyntaxException;
21+
import java.util.List;
22+
23+
import static org.mockito.Mockito.when;
1824

1925
public class HttpSegmentChangeFetcherTest {
2026
@Test
@@ -70,4 +76,31 @@ public void testFetcherWithSpecialCharacters() throws URISyntaxException, IOExce
7076
Assert.assertEquals(1, change.removed.size());
7177
Assert.assertEquals("other_user", change.removed.get(0));
7278
}
79+
80+
@Test
81+
public void testFetcherWithCDNBypassOption() throws IOException, URISyntaxException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
82+
URI rootTarget = URI.create("https://api.split.io");
83+
84+
HttpEntity entityMock = Mockito.mock(HttpEntity.class);
85+
when(entityMock.getContent()).thenReturn(new StringBufferInputStream("{\"till\": 1}"));
86+
ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
87+
when(response.getCode()).thenReturn(200);
88+
when(response.getEntity()).thenReturn(entityMock);
89+
when(response.getHeaders()).thenReturn(new Header[0]);
90+
91+
ArgumentCaptor<ClassicHttpRequest> requestCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
92+
CloseableHttpClient httpClientMock = Mockito.mock(CloseableHttpClient.class);
93+
when(httpClientMock.execute(requestCaptor.capture())).thenReturn(TestHelper.classicResponseToCloseableMock(response));
94+
95+
Metrics.NoopMetrics metrics = new Metrics.NoopMetrics();
96+
HttpSegmentChangeFetcher fetcher = HttpSegmentChangeFetcher.create(httpClientMock, rootTarget, metrics);
97+
98+
fetcher.fetch("someSegment", -1, new FetchOptions.Builder().targetChangeNumber(123).build());
99+
fetcher.fetch("someSegment2",-1, new FetchOptions.Builder().build());
100+
List<ClassicHttpRequest> captured = requestCaptor.getAllValues();
101+
Assert.assertEquals(captured.size(), 2);
102+
Assert.assertTrue(captured.get(0).getUri().toString().contains("till=123"));
103+
Assert.assertFalse(captured.get(1).getUri().toString().contains("till="));
104+
}
105+
73106
}

client/src/test/java/io/split/engine/common/SynchronizerTest.java

+59
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,63 @@ public void testCDNBypassRequestLimitAndBackoff() throws NoSuchFieldException, I
173173
Assert.assertTrue((after - before) > minDiffExpected);
174174
}
175175

176+
@Test
177+
public void testCDNBypassRequestLimitAndForSegmentsBackoff() throws NoSuchFieldException, IllegalAccessException {
178+
179+
SplitCache cache = new InMemoryCacheImp();
180+
Synchronizer imp = new SynchronizerImp(_refreshableSplitFetcherTask,
181+
_splitFetcher,
182+
_segmentFetcher,
183+
cache,
184+
_segmentCache,
185+
50,
186+
3,
187+
1,
188+
true);
189+
190+
SegmentFetcher fetcher = Mockito.mock(SegmentFetcher.class);
191+
when(_segmentFetcher.getFetcher("someSegment")).thenReturn(fetcher);
192+
193+
ArgumentCaptor<FetchOptions> optionsCaptor = ArgumentCaptor.forClass(FetchOptions.class);
194+
AtomicInteger calls = new AtomicInteger();
195+
Mockito.doAnswer(invocationOnMock -> {
196+
calls.getAndIncrement();
197+
switch (calls.get()) {
198+
case 14: Assert.assertTrue(false); // should never get here
199+
}
200+
return null;
201+
}).when(fetcher).fetch(optionsCaptor.capture());
202+
203+
// Before executing, we'll update the backoff via reflection, to avoid waiting minutes for the test to run.
204+
Field backoffBase = SynchronizerImp.class.getDeclaredField("ON_DEMAND_FETCH_BACKOFF_BASE_MS");
205+
backoffBase.setAccessible(true);
206+
Field modifiersField = Field.class.getDeclaredField("modifiers");
207+
modifiersField.setAccessible(true);
208+
modifiersField.setInt(backoffBase, backoffBase.getModifiers() & ~Modifier.FINAL);
209+
backoffBase.set(imp, 1); // 1ms
210+
211+
long before = System.currentTimeMillis();
212+
imp.refreshSegment("someSegment",1);
213+
long after = System.currentTimeMillis();
214+
215+
List<FetchOptions> options = optionsCaptor.getAllValues();
216+
Assert.assertEquals(options.size(), 13);
217+
Assert.assertFalse(options.get(0).hasCustomCN());
218+
Assert.assertFalse(options.get(1).hasCustomCN());
219+
Assert.assertFalse(options.get(2).hasCustomCN());
220+
Assert.assertTrue(options.get(3).hasCustomCN());
221+
Assert.assertTrue(options.get(4).hasCustomCN());
222+
Assert.assertTrue(options.get(5).hasCustomCN());
223+
Assert.assertTrue(options.get(6).hasCustomCN());
224+
Assert.assertTrue(options.get(7).hasCustomCN());
225+
Assert.assertTrue(options.get(8).hasCustomCN());
226+
Assert.assertTrue(options.get(9).hasCustomCN());
227+
Assert.assertTrue(options.get(10).hasCustomCN());
228+
Assert.assertTrue(options.get(11).hasCustomCN());
229+
Assert.assertTrue(options.get(12).hasCustomCN());
230+
231+
Assert.assertEquals(calls.get(), 13);
232+
long minDiffExpected = 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256;
233+
Assert.assertTrue((after - before) > minDiffExpected);
234+
}
176235
}

client/src/test/java/io/split/engine/segments/SegmentFetcherImpTest.java

+55
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
package io.split.engine.segments;
22

33
import com.google.common.collect.Sets;
4+
import io.split.cache.InMemoryCacheImp;
45
import io.split.cache.SegmentCache;
56
import io.split.cache.SegmentCacheInMemoryImpl;
7+
import io.split.cache.SplitCache;
68
import io.split.client.dtos.SegmentChange;
9+
import io.split.client.dtos.SplitChange;
710
import io.split.engine.SDKReadinessGates;
11+
import io.split.engine.common.FetchOptions;
12+
import io.split.engine.experiments.SplitChangeFetcher;
13+
import io.split.engine.experiments.SplitFetcherImp;
14+
import io.split.engine.experiments.SplitParser;
15+
import org.junit.Assert;
816
import org.junit.Test;
17+
import org.mockito.ArgumentCaptor;
918
import org.mockito.Mockito;
1019
import org.slf4j.Logger;
1120
import org.slf4j.LoggerFactory;
@@ -21,6 +30,7 @@
2130
import static org.junit.Assert.assertNotNull;
2231
import static org.junit.Assert.assertEquals;
2332
import static org.junit.Assert.assertThat;
33+
import static org.mockito.Mockito.when;
2434

2535
/**
2636
* Tests for RefreshableSegmentFetcher.
@@ -138,6 +148,51 @@ public void does_not_work_if_sdk_readiness_gates_are_null() {
138148
SegmentFetcher fetcher = new SegmentFetcherImp(SEGMENT_NAME, segmentChangeFetcher, null, segmentCache);
139149
}
140150

151+
@Test
152+
public void testBypassCdnClearedAfterFirstHit() {
153+
SegmentChangeFetcher mockFetcher = Mockito.mock(SegmentChangeFetcher.class);
154+
SegmentSynchronizationTask segmentSynchronizationTaskMock = Mockito.mock(SegmentSynchronizationTask.class);
155+
SegmentCache segmentCacheMock = new SegmentCacheInMemoryImpl();
156+
SDKReadinessGates mockGates = Mockito.mock(SDKReadinessGates.class);
157+
SegmentFetcher fetcher = new SegmentFetcherImp("someSegment", mockFetcher, mockGates, segmentCacheMock);
158+
159+
160+
SegmentChange response1 = new SegmentChange();
161+
response1.name = "someSegment";
162+
response1.added = new ArrayList<>();
163+
response1.removed = new ArrayList<>();
164+
response1.since = -1;
165+
response1.till = 1;
166+
167+
SegmentChange response2 = new SegmentChange();
168+
response2.name = "someSegment";
169+
response2.added = new ArrayList<>();
170+
response2.removed = new ArrayList<>();
171+
response2.since = 1;
172+
response1.till = 1;
173+
174+
ArgumentCaptor<FetchOptions> optionsCaptor = ArgumentCaptor.forClass(FetchOptions.class);
175+
ArgumentCaptor<Long> cnCaptor = ArgumentCaptor.forClass(Long.class);
176+
when(mockFetcher.fetch(Mockito.eq("someSegment"), cnCaptor.capture(), optionsCaptor.capture())).thenReturn(response1, response2);
177+
178+
FetchOptions originalOptions = new FetchOptions.Builder().targetChangeNumber(123).build();
179+
fetcher.fetch(originalOptions);
180+
List<Long> capturedCNs = cnCaptor.getAllValues();
181+
List<FetchOptions> capturedOptions = optionsCaptor.getAllValues();
182+
183+
Assert.assertEquals(capturedOptions.size(), 2);
184+
Assert.assertEquals(capturedCNs.size(), 2);
185+
186+
Assert.assertEquals(capturedCNs.get(0), Long.valueOf(-1));
187+
Assert.assertEquals(capturedCNs.get(1), Long.valueOf(1));
188+
189+
Assert.assertEquals(capturedOptions.get(0).targetCN(), 123);
190+
Assert.assertEquals(capturedOptions.get(1).targetCN(), -1);
191+
192+
// Ensure that the original value hasn't been modified
193+
Assert.assertEquals(originalOptions.targetCN(), 123);
194+
}
195+
141196
private SegmentChange getSegmentChange(long since, long till){
142197
SegmentChange segmentChange = new SegmentChange();
143198
segmentChange.name = SEGMENT_NAME;

0 commit comments

Comments
 (0)