Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
gthea committed Dec 3, 2024
1 parent 015180d commit 18cd746
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 53 deletions.
10 changes: 9 additions & 1 deletion src/androidTest/java/helper/TestableSplitConfigBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.lang.reflect.Constructor;

import io.split.android.client.RolloutCacheConfiguration;
import io.split.android.client.ServiceEndpoints;
import io.split.android.client.SplitClientConfig;
import io.split.android.client.SyncConfig;
Expand Down Expand Up @@ -64,6 +65,7 @@ public class TestableSplitConfigBuilder {
private String mPrefix = "";
private CertificatePinningConfiguration mCertificatePinningConfiguration;
private long mImpressionsDedupeTimeInterval = ServiceConstants.DEFAULT_IMPRESSIONS_DEDUPE_TIME_INTERVAL;
private RolloutCacheConfiguration mRolloutCacheConfiguration = RolloutCacheConfiguration.builder().build();

public TestableSplitConfigBuilder() {
mServiceEndpoints = ServiceEndpoints.builder().build();
Expand Down Expand Up @@ -274,6 +276,11 @@ public TestableSplitConfigBuilder impressionsDedupeTimeInterval(long impressions
return this;
}

public TestableSplitConfigBuilder rolloutCacheConfiguration(RolloutCacheConfiguration rolloutCacheConfiguration) {
this.mRolloutCacheConfiguration = rolloutCacheConfiguration;
return this;
}

public SplitClientConfig build() {
Constructor constructor = SplitClientConfig.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Expand Down Expand Up @@ -329,7 +336,8 @@ public SplitClientConfig build() {
mPrefix,
mObserverCacheExpirationPeriod,
mCertificatePinningConfiguration,
mImpressionsDedupeTimeInterval);
mImpressionsDedupeTimeInterval,
mRolloutCacheConfiguration);

Logger.instance().setLevel(mLogLevel);
return config;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.split.android.client;

import io.split.android.client.service.ServiceConstants;
import io.split.android.client.utils.logger.Logger;

public class RolloutCacheConfiguration {

private final int mExpiration;
private final boolean mClearOnInit;

private RolloutCacheConfiguration(int expiration, boolean clearOnInit) {
mExpiration = expiration;
mClearOnInit = clearOnInit;
}

public int getExpiration() {
return mExpiration;
}

public boolean clearOnInit() {
return mClearOnInit;
}

public static Builder builder() {
return new Builder();
}

public static class Builder {

private static final int MIN_EXPIRATION_DAYS = 1;

private int mExpiration = ServiceConstants.DEFAULT_ROLLOUT_CACHE_EXPIRATION;
private boolean mClearOnInit = false;

private Builder() {

}

/**
* Set the expiration time for the rollout definitions cache, in days. Default is 10 days.
* @param expiration in days
* @return This builder
*/
public Builder expiration(int expiration) {
if (expiration < MIN_EXPIRATION_DAYS) {
Logger.w("Cache expiration must be at least 1 day. Using default value.");
mExpiration = ServiceConstants.DEFAULT_ROLLOUT_CACHE_EXPIRATION;
} else {
mExpiration = expiration;
}

return this;
}

/**
* Set if the rollout definitions cache should be cleared on initialization. Default is false.
* @param clearOnInit whether to clear cache on initialization.
* @return This builder
*/
public Builder clearOnInit(boolean clearOnInit) {
mClearOnInit = clearOnInit;
return this;
}

public RolloutCacheConfiguration build() {
return new RolloutCacheConfiguration(mExpiration, mClearOnInit);
}
}
}
31 changes: 27 additions & 4 deletions src/main/java/io/split/android/client/SplitClientConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ public class SplitClientConfig {
private final long mObserverCacheExpirationPeriod;
private final CertificatePinningConfiguration mCertificatePinningConfiguration;
private final long mImpressionsDedupeTimeInterval;
@NonNull
private final RolloutCacheConfiguration mRolloutCacheConfiguration;

public static Builder builder() {
return new Builder();
Expand Down Expand Up @@ -185,7 +187,8 @@ private SplitClientConfig(String endpoint,
String prefix,
long observerCacheExpirationPeriod,
CertificatePinningConfiguration certificatePinningConfiguration,
long impressionsDedupeTimeInterval) {
long impressionsDedupeTimeInterval,
RolloutCacheConfiguration rolloutCacheConfiguration) {
mEndpoint = endpoint;
mEventsEndpoint = eventsEndpoint;
mTelemetryEndpoint = telemetryEndpoint;
Expand Down Expand Up @@ -243,6 +246,7 @@ private SplitClientConfig(String endpoint,
mObserverCacheExpirationPeriod = observerCacheExpirationPeriod;
mCertificatePinningConfiguration = certificatePinningConfiguration;
mImpressionsDedupeTimeInterval = impressionsDedupeTimeInterval;
mRolloutCacheConfiguration = rolloutCacheConfiguration;
}

public String trafficType() {
Expand Down Expand Up @@ -486,8 +490,8 @@ public long impressionsDedupeTimeInterval() {
return mImpressionsDedupeTimeInterval;
}

public boolean clearOnInit() {
return false; // TODO: to be implemented in the future
public RolloutCacheConfiguration rolloutCacheConfiguration() {
return mRolloutCacheConfiguration;
}

public static final class Builder {
Expand Down Expand Up @@ -566,6 +570,8 @@ public static final class Builder {

private long mImpressionsDedupeTimeInterval = ServiceConstants.DEFAULT_IMPRESSIONS_DEDUPE_TIME_INTERVAL;

private RolloutCacheConfiguration mRolloutCacheConfiguration = RolloutCacheConfiguration.builder().build();

public Builder() {
mServiceEndpoints = ServiceEndpoints.builder().build();
}
Expand Down Expand Up @@ -1106,6 +1112,22 @@ public Builder impressionsDedupeTimeInterval(long impressionsDedupeTimeInterval)
return this;
}

/**
* Configuration for rollout definitions cache.
*
* @param rolloutCacheConfiguration Configuration object
* @return This builder
*/
public Builder rolloutCacheConfiguration(@NonNull RolloutCacheConfiguration rolloutCacheConfiguration) {
if (mRolloutCacheConfiguration == null) {
Logger.w("Rollout cache configuration is null. Setting to default value.");
mRolloutCacheConfiguration = RolloutCacheConfiguration.builder().build();
} else {
mRolloutCacheConfiguration = rolloutCacheConfiguration;
}
return this;
}

public SplitClientConfig build() {
Logger.instance().setLevel(mLogLevel);

Expand Down Expand Up @@ -1237,7 +1259,8 @@ public SplitClientConfig build() {
mPrefix,
mObserverCacheExpirationPeriod,
mCertificatePinningConfiguration,
mImpressionsDedupeTimeInterval);
mImpressionsDedupeTimeInterval,
mRolloutCacheConfiguration);
}

private HttpProxy parseProxyHost(String proxyUri) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class ServiceConstants {
public static final long MIN_INITIAL_DELAY = 5L;
public static final int DEFAULT_RECORDS_PER_PUSH = 100;
public static final long DEFAULT_SPLITS_CACHE_EXPIRATION_IN_SECONDS = TimeUnit.DAYS.toSeconds(10); // 10 days
public static final int DEFAULT_ROLLOUT_CACHE_EXPIRATION = 10; // 10 days

public static final int MAX_ROWS_PER_QUERY = 100;

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.concurrent.TimeUnit;

import io.split.android.client.RolloutCacheConfiguration;
import io.split.android.client.SplitClientConfig;
import io.split.android.client.service.CleanUpDatabaseTask;
import io.split.android.client.service.executor.SplitTask;
Expand All @@ -27,19 +28,20 @@ public class RolloutCacheManagerImpl implements RolloutCacheManager, SplitTask {
@NonNull
private final GeneralInfoStorage mGeneralInfoStorage;
@NonNull
private final RolloutCacheManagerConfig mConfig;
private final RolloutCacheConfiguration mConfig;
@NonNull
private final RolloutDefinitionsCache[] mStorages;
@NonNull
private final CleanUpDatabaseTask mCleanUpDatabaseTask;
@NonNull
private final EncryptionMigrationTask mEncryptionMigrationTask;

public RolloutCacheManagerImpl(@NonNull SplitClientConfig splitClientConfig, @NonNull SplitStorageContainer storageContainer,
public RolloutCacheManagerImpl(@NonNull SplitClientConfig splitClientConfig,
@NonNull SplitStorageContainer storageContainer,
@NonNull CleanUpDatabaseTask cleanUpDatabaseTask,
@NonNull EncryptionMigrationTask encryptionMigrationTask) {
this(storageContainer.getGeneralInfoStorage(),
RolloutCacheManagerConfig.from(splitClientConfig),
splitClientConfig.rolloutCacheConfiguration(),
cleanUpDatabaseTask,
encryptionMigrationTask,
storageContainer.getSplitsStorage(),
Expand All @@ -49,7 +51,7 @@ public RolloutCacheManagerImpl(@NonNull SplitClientConfig splitClientConfig, @No

@VisibleForTesting
RolloutCacheManagerImpl(@NonNull GeneralInfoStorage generalInfoStorage,
@NonNull RolloutCacheManagerConfig config,
@NonNull RolloutCacheConfiguration config,
@NonNull CleanUpDatabaseTask clean,
@NonNull EncryptionMigrationTask encryptionMigrationTask,
@NonNull RolloutDefinitionsCache... storages) {
Expand Down Expand Up @@ -99,10 +101,10 @@ private boolean validateExpiration() {
long lastUpdateTimestamp = mGeneralInfoStorage.getSplitsUpdateTimestamp();
long daysSinceLastUpdate = TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - lastUpdateTimestamp);

if (daysSinceLastUpdate > mConfig.getCacheExpirationInDays()) {
if (daysSinceLastUpdate > mConfig.getExpiration()) {
Logger.v("Clearing rollout definitions cache due to expiration");
return true;
} else if (mConfig.isClearOnInit()) {
} else if (mConfig.clearOnInit()) {
long lastCacheClearTimestamp = mGeneralInfoStorage.getRolloutCacheLastClearTimestamp();
long daysSinceCacheClear = TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - lastCacheClearTimestamp);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.split.android.client.service.synchronizer

import io.split.android.client.RolloutCacheConfiguration
import io.split.android.client.service.CleanUpDatabaseTask
import io.split.android.client.service.executor.SplitTaskExecutionListener
import io.split.android.client.storage.RolloutDefinitionsCache
Expand Down Expand Up @@ -36,7 +37,7 @@ class RolloutCacheManagerTest {

@Test
fun `validateCache calls listener`() {
mRolloutCacheManager = getCacheManager(10L, false)
mRolloutCacheManager = getCacheManager(10, false)

val listener = mock(SplitTaskExecutionListener::class.java)
mRolloutCacheManager.validateCache(listener)
Expand All @@ -46,9 +47,9 @@ class RolloutCacheManagerTest {

@Test
fun `validateCache calls clear on storages when expiration is surpassed`() {
val mockedTimestamp = createMockedTimestamp(10L)
val mockedTimestamp = createMockedTimestamp(10)
`when`(mGeneralInfoStorage.splitsUpdateTimestamp).thenReturn(mockedTimestamp)
mRolloutCacheManager = getCacheManager(9L, false)
mRolloutCacheManager = getCacheManager(9, false)

mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))

Expand All @@ -60,7 +61,7 @@ class RolloutCacheManagerTest {
fun `validateCache does not call clear on storages when expiration is not surpassed and clearOnInit is false`() {
val mockedTimestamp = createMockedTimestamp(1L)
`when`(mGeneralInfoStorage.splitsUpdateTimestamp).thenReturn(mockedTimestamp)
mRolloutCacheManager = getCacheManager(10L, false)
mRolloutCacheManager = getCacheManager(10, false)

mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))

Expand All @@ -72,7 +73,7 @@ class RolloutCacheManagerTest {
fun `validateCache calls clear on storages when expiration is not surpassed and clearOnInit is true`() {
val mockedTimestamp = createMockedTimestamp(1L)
`when`(mGeneralInfoStorage.splitsUpdateTimestamp).thenReturn(mockedTimestamp)
mRolloutCacheManager = getCacheManager(10L, true)
mRolloutCacheManager = getCacheManager(10, true)

mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))

Expand All @@ -85,7 +86,7 @@ class RolloutCacheManagerTest {
val mockedTimestamp = createMockedTimestamp(1L)
`when`(mGeneralInfoStorage.splitsUpdateTimestamp).thenReturn(mockedTimestamp)
`when`(mGeneralInfoStorage.rolloutCacheLastClearTimestamp).thenReturn(0L).thenReturn(TimeUnit.HOURS.toMillis(TimeUnit.MILLISECONDS.toHours(System.currentTimeMillis()) - 1))
mRolloutCacheManager = getCacheManager(10L, true)
mRolloutCacheManager = getCacheManager(10, true)

mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))
mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))
Expand All @@ -99,7 +100,7 @@ class RolloutCacheManagerTest {
val mockedTimestamp = createMockedTimestamp(1L)
`when`(mGeneralInfoStorage.splitsUpdateTimestamp).thenReturn(mockedTimestamp)
`when`(mGeneralInfoStorage.rolloutCacheLastClearTimestamp).thenReturn(0L).thenReturn(TimeUnit.HOURS.toMillis(TimeUnit.MILLISECONDS.toHours(System.currentTimeMillis()) - 1))
mRolloutCacheManager = getCacheManager(10L, true)
mRolloutCacheManager = getCacheManager(10, true)

val listener = mock(SplitTaskExecutionListener::class.java)
`when`(mSplitsCache.clear()).thenThrow(RuntimeException("Exception during clear"))
Expand All @@ -114,7 +115,7 @@ class RolloutCacheManagerTest {
val mockedTimestamp = createMockedTimestamp(1L)
`when`(mGeneralInfoStorage.splitsUpdateTimestamp).thenReturn(mockedTimestamp)
`when`(mGeneralInfoStorage.rolloutCacheLastClearTimestamp).thenReturn(0L).thenReturn(TimeUnit.HOURS.toMillis(TimeUnit.MILLISECONDS.toHours(System.currentTimeMillis()) - 1))
mRolloutCacheManager = getCacheManager(10L, true)
mRolloutCacheManager = getCacheManager(10, true)

mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))

Expand All @@ -126,7 +127,7 @@ class RolloutCacheManagerTest {
val mockedTimestamp = createMockedTimestamp(1L)
`when`(mGeneralInfoStorage.splitsUpdateTimestamp).thenReturn(mockedTimestamp)
`when`(mGeneralInfoStorage.rolloutCacheLastClearTimestamp).thenReturn(0L).thenReturn(TimeUnit.HOURS.toMillis(TimeUnit.MILLISECONDS.toHours(System.currentTimeMillis()) - 1))
mRolloutCacheManager = getCacheManager(10L, false)
mRolloutCacheManager = getCacheManager(10, false)

mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))

Expand All @@ -135,7 +136,7 @@ class RolloutCacheManagerTest {

@Test
fun `validateCache executes cleanUpDatabaseTask`() {
mRolloutCacheManager = getCacheManager(10L, false)
mRolloutCacheManager = getCacheManager(10, false)

mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))

Expand All @@ -144,15 +145,15 @@ class RolloutCacheManagerTest {

@Test
fun `validateCache executes encryptionMigrationTask`() {
mRolloutCacheManager = getCacheManager(10L, false)
mRolloutCacheManager = getCacheManager(10, false)

mRolloutCacheManager.validateCache(mock(SplitTaskExecutionListener::class.java))

verify(mEncryptionMigrationTask).execute()
}

private fun getCacheManager(expiration: Long, clearOnInit: Boolean): RolloutCacheManager {
return RolloutCacheManagerImpl(mGeneralInfoStorage, RolloutCacheManagerConfig(expiration, clearOnInit), mCleanUpDatabaseTask, mEncryptionMigrationTask, mSplitsCache, mSegmentsCache)
private fun getCacheManager(expiration: Int, clearOnInit: Boolean): RolloutCacheManager {
return RolloutCacheManagerImpl(mGeneralInfoStorage, RolloutCacheConfiguration.builder().expiration(expiration).clearOnInit(clearOnInit).build(), mCleanUpDatabaseTask, mEncryptionMigrationTask, mSplitsCache, mSegmentsCache)
}

private fun createMockedTimestamp(period: Long): Long {
Expand Down

0 comments on commit 18cd746

Please sign in to comment.