Skip to content

Commit

Permalink
Impression manager with two strategies (#723)
Browse files Browse the repository at this point in the history
  • Loading branch information
gthea authored Dec 12, 2024
1 parent 3fbd789 commit 6c522e6
Show file tree
Hide file tree
Showing 28 changed files with 382 additions and 589 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package tests.integration.streaming;

import static java.lang.Thread.sleep;

import android.content.Context;

import androidx.core.util.Pair;
Expand Down Expand Up @@ -140,7 +138,7 @@ public void testCleanUp() throws IOException, InterruptedException {
.streamingEnabled(true)
.impressionsRefreshRate(999999999)
.eventFlushInterval(99999999)
.logLevel(SplitLogLevel.DEBUG)
.logLevel(SplitLogLevel.VERBOSE)
.trafficType("account")
.build();

Expand All @@ -155,11 +153,12 @@ public void testCleanUp() throws IOException, InterruptedException {
mClient.on(SplitEvent.SDK_READY, readyTask);

latch.await(40, TimeUnit.SECONDS);

// wait to allow cleanup to run
sleep(5000);
Thread.sleep(1000);

// Load all records again after cleanup
List<UniqueKeyEntity> remainingKeys = mUniqueKeysDao.getBy(0, StorageRecordStatus.ACTIVE, 10);
remainingKeys.addAll(mUniqueKeysDao.getBy(0, StorageRecordStatus.DELETED, 10));

List<EventEntity> remainingEvents = mEventDao.getBy(0, StorageRecordStatus.ACTIVE, 10);
remainingEvents.addAll(mEventDao.getBy(0, StorageRecordStatus.DELETED, 10));

Expand All @@ -169,8 +168,6 @@ public void testCleanUp() throws IOException, InterruptedException {
List<ImpressionsCountEntity> remainingCounts = mImpressionsCountDao.getBy(0, StorageRecordStatus.ACTIVE, 10);
remainingCounts.addAll(mImpressionsCountDao.getBy(0, StorageRecordStatus.DELETED, 10));

List<UniqueKeyEntity> remainingKeys = mUniqueKeysDao.getBy(0, StorageRecordStatus.ACTIVE, 10);
remainingKeys.addAll(mUniqueKeysDao.getBy(0, StorageRecordStatus.DELETED, 10));

List<ImpressionsObserverCacheEntity> remainingImpressionsObserverCacheEntities = mImpressionsObserverCacheDao.getAll(3);

Expand All @@ -184,7 +181,6 @@ public void testCleanUp() throws IOException, InterruptedException {
Assert.assertEquals(1, remainingCounts.size());
Assert.assertEquals(1, remainingKeys.size());
Assert.assertEquals(1, remainingImpressionsObserverCacheEntities.size());

}

private EventEntity createEventEntity(long createdAt, int status, String name) {
Expand Down Expand Up @@ -258,7 +254,7 @@ public HttpResponseMock getResponse(URI uri, HttpMethod method, String body) {
} else if (uri.getPath().contains("/bulk")) {
return createResponse(500, "");
} else {
return new HttpResponseMock(200);
return new HttpResponseMock(404);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ class UserConsentModeDebugTest {
mEventDao = splitRoomDatabase.eventDao()
val dispatcher: HttpResponseMockDispatcher = buildDispatcher()
val config = TestableSplitConfigBuilder().ready(30000)
.trafficType("client")
.trafficType("account")
.enableDebug()
.impressionsMode(ImpressionsMode.DEBUG)
.impressionsRefreshRate(3)
.eventFlushInterval(3)
Expand All @@ -224,7 +225,7 @@ class UserConsentModeDebugTest {
return HttpStreamResponseMock(200, null)
}

override fun getResponse(uri: URI, method: HttpMethod, body: String): HttpResponseMock {
override fun getResponse(uri: URI, method: HttpMethod, body: String?): HttpResponseMock {
println(uri.path)
return if (uri.path.contains("/" + IntegrationHelper.ServicePath.MEMBERSHIPS)) {
HttpResponseMock(200, IntegrationHelper.emptyAllSegments())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ class UserConsentModeNoneTest {
mKeysLatch?.await(10, TimeUnit.SECONDS)
mCountLatch?.await(10, TimeUnit.SECONDS)

Assert.assertTrue(mKeysPosted)
Assert.assertTrue(mCountPosted)
Assert.assertTrue(mKeysPosted)
}

@Test
Expand Down Expand Up @@ -202,11 +202,12 @@ class UserConsentModeNoneTest {
mCountDao = splitRoomDatabase.impressionsCountDao()
val dispatcher: HttpResponseMockDispatcher = buildDispatcher()
val config = TestableSplitConfigBuilder().ready(30000)
.trafficType("client")
.trafficType("account")
.impressionsMode(ImpressionsMode.NONE)
.impressionsRefreshRate(3)
.eventFlushInterval(3)
.mtkRefreshRate(3)
.enableDebug()
.userConsent(userConsent)
.build()

Expand All @@ -228,7 +229,7 @@ class UserConsentModeNoneTest {
return HttpStreamResponseMock(200, null)
}

override fun getResponse(uri: URI, method: HttpMethod, body: String): HttpResponseMock {
override fun getResponse(uri: URI, method: HttpMethod, body: String?): HttpResponseMock {
println(uri.path)
return if (uri.path.contains("/" + IntegrationHelper.ServicePath.MEMBERSHIPS)) {
HttpResponseMock(200, IntegrationHelper.emptyAllSegments())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,12 @@ class UserConsentModeOptimizedTest {
mCountDao = splitRoomDatabase.impressionsCountDao()
val dispatcher: HttpResponseMockDispatcher = buildDispatcher()
val config = TestableSplitConfigBuilder().ready(30000)
.trafficType("client")
.trafficType("account")
.impressionsMode(ImpressionsMode.OPTIMIZED)
.impressionsRefreshRate(3)
.impressionsCountersRefreshRate(3)
.mtkRefreshRate(3)
.enableDebug()
.eventFlushInterval(3)
.userConsent(userConsent)
.build()
Expand All @@ -236,7 +237,7 @@ class UserConsentModeOptimizedTest {
return HttpStreamResponseMock(200, null)
}

override fun getResponse(uri: URI, method: HttpMethod, body: String): HttpResponseMock {
override fun getResponse(uri: URI, method: HttpMethod, body: String?): HttpResponseMock {
println(uri.path)
return if (uri.path.contains("/" + IntegrationHelper.ServicePath.MEMBERSHIPS)) {
HttpResponseMock(200, IntegrationHelper.emptyAllSegments())
Expand Down
12 changes: 5 additions & 7 deletions src/main/java/io/split/android/client/SplitFactoryHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import io.split.android.client.service.http.mysegments.MySegmentsFetcherFactoryImpl;
import io.split.android.client.service.impressions.strategy.ImpressionStrategyConfig;
import io.split.android.client.service.impressions.strategy.ImpressionStrategyProvider;
import io.split.android.client.service.impressions.strategy.ProcessStrategy;
import io.split.android.client.service.mysegments.AllSegmentsResponseParser;
import io.split.android.client.service.sseclient.EventStreamParser;
import io.split.android.client.service.sseclient.ReconnectBackoffCounter;
Expand Down Expand Up @@ -387,10 +386,10 @@ public StreamingComponents buildStreamingComponents(@NonNull SplitTaskExecutor s
syncGuardian);
}

public ProcessStrategy getImpressionStrategy(SplitTaskExecutor splitTaskExecutor,
SplitTaskFactory splitTaskFactory,
SplitStorageContainer splitStorageContainer,
SplitClientConfig config) {
public ImpressionStrategyProvider getImpressionStrategyProvider(SplitTaskExecutor splitTaskExecutor,
SplitTaskFactory splitTaskFactory,
SplitStorageContainer splitStorageContainer,
SplitClientConfig config) {
return new ImpressionStrategyProvider(splitTaskExecutor,
splitStorageContainer,
splitTaskFactory,
Expand All @@ -402,8 +401,7 @@ public ProcessStrategy getImpressionStrategy(SplitTaskExecutor splitTaskExecutor
config.impressionsCounterRefreshRate(),
config.mtkRefreshRate(),
config.userConsent() == UserConsent.GRANTED,
config.impressionsDedupeTimeInterval()))
.getStrategy(config.impressionsMode());
config.impressionsDedupeTimeInterval()));
}

@Nullable
Expand Down
13 changes: 6 additions & 7 deletions src/main/java/io/split/android/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
import io.split.android.client.service.executor.SplitTaskExecutorImpl;
import io.split.android.client.service.executor.SplitTaskFactory;
import io.split.android.client.service.executor.SplitTaskFactoryImpl;
import io.split.android.client.service.impressions.ImpressionManager;
import io.split.android.client.service.impressions.StrategyImpressionManager;
import io.split.android.client.service.impressions.strategy.ImpressionStrategyProvider;
import io.split.android.client.service.impressions.strategy.PeriodicTracker;
import io.split.android.client.service.impressions.strategy.ProcessStrategy;
import io.split.android.client.service.sseclient.sseclient.StreamingComponents;
import io.split.android.client.service.synchronizer.SyncManager;
import io.split.android.client.service.synchronizer.Synchronizer;
Expand Down Expand Up @@ -185,7 +187,9 @@ private SplitFactoryImpl(@NonNull String apiToken, @NonNull Key key, @NonNull Sp
SplitSingleThreadTaskExecutor splitSingleThreadTaskExecutor = new SplitSingleThreadTaskExecutor();
splitSingleThreadTaskExecutor.pause();

ImpressionManager impressionManager = new StrategyImpressionManager(factoryHelper.getImpressionStrategy(splitTaskExecutor, splitTaskFactory, mStorageContainer, config));
ImpressionStrategyProvider impressionStrategyProvider = factoryHelper.getImpressionStrategyProvider(splitTaskExecutor, splitTaskFactory, mStorageContainer, config);
Pair<ProcessStrategy, PeriodicTracker> noneComponents = impressionStrategyProvider.getNoneComponents();
StrategyImpressionManager impressionManager = new StrategyImpressionManager(noneComponents, impressionStrategyProvider.getStrategy(config.impressionsMode()));
final RetryBackoffCounterTimerFactory retryBackoffCounterTimerFactory = new RetryBackoffCounterTimerFactory();

StreamingComponents streamingComponents = factoryHelper.buildStreamingComponents(splitTaskExecutor,
Expand Down Expand Up @@ -409,11 +413,6 @@ private void setupValidations(SplitClientConfig splitClientConfig) {
ValidationConfig.getInstance().setTrackEventNamePattern(splitClientConfig.trackEventNamePattern());
}

private void cleanUpDabase(SplitTaskExecutor splitTaskExecutor,
SplitTaskFactory splitTaskFactory) {
splitTaskExecutor.submit(splitTaskFactory.createCleanUpDatabaseTask(System.currentTimeMillis() / 1000), null);
}

private EventsTracker buildEventsTracker() {
EventValidator eventsValidator = new EventValidatorImpl(new KeyValidatorImpl(), mStorageContainer.getSplitsStorage());
return new EventsTrackerImpl(eventsValidator, new ValidationMessageLoggerImpl(), mStorageContainer.getTelemetryStorage(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package io.split.android.client.service.impressions;

import io.split.android.client.impressions.Impression;
import io.split.android.client.service.impressions.strategy.PeriodicTracker;

public interface ImpressionManager extends PeriodicTracker {
public interface ImpressionManager {

void enableTracking(boolean enable);

void pushImpression(Impression impression);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,34 @@

import static io.split.android.client.utils.Utils.checkNotNull;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.core.util.Pair;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import io.split.android.client.impressions.Impression;
import io.split.android.client.service.impressions.strategy.PeriodicTracker;
import io.split.android.client.service.impressions.strategy.ProcessStrategy;
import io.split.android.client.utils.logger.Logger;

public class StrategyImpressionManager implements ImpressionManager {
public class StrategyImpressionManager implements ImpressionManager, PeriodicTracker {

private final AtomicBoolean isTrackingEnabled = new AtomicBoolean(true);
private final ProcessStrategy mProcessStrategy;
private final PeriodicTracker mPeriodicTracker;
private final ProcessStrategy mNoneStrategy;
private final Set<PeriodicTracker> mPeriodicTrackers;

public StrategyImpressionManager(@NonNull ProcessStrategy processStrategy) {
this(processStrategy, processStrategy);
public StrategyImpressionManager(Pair<ProcessStrategy, PeriodicTracker> noneComponents, Pair<ProcessStrategy, PeriodicTracker> strategy) {
this(noneComponents.first, noneComponents.second, strategy.first, strategy.second);
}

@VisibleForTesting
StrategyImpressionManager(@NonNull ProcessStrategy processStrategy, @NonNull PeriodicTracker periodicTracker) {
mProcessStrategy = checkNotNull(processStrategy);
mPeriodicTracker = checkNotNull(periodicTracker);
}

@Override
public void enableTracking(boolean enable) {
isTrackingEnabled.set(enable);
StrategyImpressionManager(ProcessStrategy noneStrategy, PeriodicTracker noneTracker, ProcessStrategy strategy, PeriodicTracker strategyTracker) {
mProcessStrategy = checkNotNull(strategy);
mNoneStrategy = checkNotNull(noneStrategy);
mPeriodicTrackers = new HashSet<>();
mPeriodicTrackers.add(noneTracker);
mPeriodicTrackers.add(strategyTracker);
}

@Override
Expand All @@ -40,21 +39,40 @@ public void pushImpression(Impression impression) {
return;
}

mProcessStrategy.apply(impression);
if (track(impression)) {
mProcessStrategy.apply(impression);
} else {
mNoneStrategy.apply(impression);
}
}

@Override
public void enableTracking(boolean enable) {
isTrackingEnabled.set(enable);
}

@Override
public void flush() {
mPeriodicTracker.flush();
for (PeriodicTracker tracker : mPeriodicTrackers) {
tracker.flush();
}
}

@Override
public void startPeriodicRecording() {
mPeriodicTracker.startPeriodicRecording();
for (PeriodicTracker tracker : mPeriodicTrackers) {
tracker.startPeriodicRecording();
}
}

@Override
public void stopPeriodicRecording() {
mPeriodicTracker.stopPeriodicRecording();
for (PeriodicTracker tracker : mPeriodicTrackers) {
tracker.stopPeriodicRecording();
}
}

private static boolean track(Impression impression) {
return true; // TODO: Placeholder method
}
}
Loading

0 comments on commit 6c522e6

Please sign in to comment.