Skip to content

Commit 69acf1a

Browse files
authored
feat: onConfigChange method from common jdk (#167)
* feat: onConfigChange method from common jdk * update for Configuration object in the callback * chore: lint
1 parent 994373a commit 69acf1a

File tree

4 files changed

+61
-3
lines changed

4 files changed

+61
-3
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ feature flagging and experimentation for Eppo customers. An API key is required
1212

1313
```groovy
1414
dependencies {
15-
implementation 'cloud.eppo:android-sdk:4.6.0'
15+
implementation 'cloud.eppo:android-sdk:4.7.0'
1616
}
1717
1818
dependencyResolutionManagement {

eppo/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77
}
88

99
group = "cloud.eppo"
10-
version = "4.6.1-SNAPSHOT"
10+
version = "4.7.0"
1111

1212
android {
1313
buildFeatures.buildConfig true
@@ -68,7 +68,7 @@ ext.versions = [
6868
]
6969

7070
dependencies {
71-
api 'cloud.eppo:sdk-common-jvm:3.8.0'
71+
api 'cloud.eppo:sdk-common-jvm:3.9.0'
7272

7373
implementation 'org.slf4j:slf4j-api:2.0.17'
7474

eppo/src/androidTest/java/cloud/eppo/android/EppoClientTest.java

+44
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@
4848
import java.io.InputStream;
4949
import java.lang.reflect.Field;
5050
import java.text.SimpleDateFormat;
51+
import java.util.ArrayList;
5152
import java.util.Date;
5253
import java.util.HashMap;
54+
import java.util.List;
5355
import java.util.Locale;
5456
import java.util.Map;
5557
import java.util.concurrent.CompletableFuture;
@@ -352,6 +354,48 @@ private void testLoadConfigurationHelper(boolean loadAsync)
352354
assertTrue(eppoClient.getBooleanAssignment("bool_flag", "subject1", false));
353355
}
354356

357+
@Test
358+
public void testConfigurationChangeListener() throws ExecutionException, InterruptedException {
359+
List<Configuration> received = new ArrayList<>();
360+
361+
// Set up a changing response from the "server"
362+
EppoHttpClient mockHttpClient = mock(EppoHttpClient.class);
363+
364+
// Mock sync get to return empty
365+
when(mockHttpClient.get(anyString())).thenReturn(EMPTY_CONFIG);
366+
367+
// Mock async get to return empty
368+
CompletableFuture<byte[]> emptyResponse = CompletableFuture.completedFuture(EMPTY_CONFIG);
369+
when(mockHttpClient.getAsync(anyString())).thenReturn(emptyResponse);
370+
371+
setBaseClientHttpClientOverrideField(mockHttpClient);
372+
373+
EppoClient.Builder clientBuilder =
374+
new EppoClient.Builder(DUMMY_API_KEY, ApplicationProvider.getApplicationContext())
375+
.forceReinitialize(true)
376+
.onConfigurationChange(received::add)
377+
.isGracefulMode(false);
378+
379+
// Initialize and no exception should be thrown.
380+
EppoClient eppoClient = clientBuilder.buildAndInitAsync().get();
381+
382+
verify(mockHttpClient, times(1)).getAsync(anyString());
383+
assertEquals(1, received.size());
384+
385+
// Now, return the boolean flag config so that the config has changed.
386+
when(mockHttpClient.get(anyString())).thenReturn(BOOL_FLAG_CONFIG);
387+
388+
// Trigger a reload of the client
389+
eppoClient.loadConfiguration();
390+
391+
assertEquals(2, received.size());
392+
393+
// Reload the client again; the config hasn't changed, but Java doesn't check eTag (yet)
394+
eppoClient.loadConfiguration();
395+
396+
assertEquals(3, received.size());
397+
}
398+
355399
@Test
356400
public void testPollingClient() throws ExecutionException, InterruptedException {
357401
EppoHttpClient mockHttpClient = mock(EppoHttpClient.class);

eppo/src/main/java/cloud/eppo/android/EppoClient.java

+14
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.concurrent.CompletionException;
2424
import java.util.concurrent.ExecutionException;
2525
import java.util.concurrent.atomic.AtomicInteger;
26+
import java.util.function.Consumer;
2627

2728
public class EppoClient extends BaseEppoClient {
2829
private static final String TAG = logTag(EppoClient.class);
@@ -154,6 +155,7 @@ public static class Builder {
154155

155156
// Assignment caching on by default. To disable, call `builder.assignmentCache(null);`
156157
private IAssignmentCache assignmentCache = new LRUAssignmentCache(100);
158+
@Nullable private Consumer<Configuration> configChangeCallback;
157159

158160
public Builder(@NonNull String apiKey, @NonNull Application application) {
159161
this.application = application;
@@ -251,6 +253,14 @@ public Builder pollingJitterMs(long pollingJitterMs) {
251253
return this;
252254
}
253255

256+
/**
257+
* Registers a callback for when a new configuration is applied to the `EppoClient` instance.
258+
*/
259+
public Builder onConfigurationChange(Consumer<Configuration> configChangeCallback) {
260+
this.configChangeCallback = configChangeCallback;
261+
return this;
262+
}
263+
254264
public CompletableFuture<EppoClient> buildAndInitAsync() {
255265
if (application == null) {
256266
throw new MissingApplicationException();
@@ -300,6 +310,10 @@ public CompletableFuture<EppoClient> buildAndInitAsync() {
300310
initialConfiguration,
301311
assignmentCache);
302312

313+
if (configChangeCallback != null) {
314+
instance.onConfigurationChange(configChangeCallback);
315+
}
316+
303317
final CompletableFuture<EppoClient> ret = new CompletableFuture<>();
304318

305319
AtomicInteger failCount = new AtomicInteger(0);

0 commit comments

Comments
 (0)