Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add trackImpressions to DTO #724

Merged
merged 35 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
489bc31
WIP
gthea Nov 27, 2024
a5f7c5e
New tests
gthea Nov 27, 2024
a416b0c
Cleanup
gthea Nov 27, 2024
f5373dc
WIP integration
gthea Nov 29, 2024
ba92544
Merge branch 'SDKS-9072_baseline' into SDKS-9031
gthea Nov 29, 2024
4d0b415
Tests modifications
gthea Nov 29, 2024
428bb5b
WIP
gthea Dec 2, 2024
4532d4a
Refactor
gthea Dec 2, 2024
fb3d56f
Fix tests
gthea Dec 2, 2024
ff03a85
Update tests
gthea Dec 2, 2024
015180d
Track segments sync by Key
gthea Dec 3, 2024
f4ea326
Rollout config
gthea Dec 3, 2024
a9d47fe
Fixes
gthea Dec 3, 2024
c8eefc8
WIP int tests
gthea Dec 4, 2024
f65f0ae
WIP
gthea Dec 4, 2024
48a311f
qMerge branch 'SDKS-9072_baseline' into SDKS-9040
gthea Dec 4, 2024
6234fa7
WIP
gthea Dec 5, 2024
f645892
Remove unused method
gthea Dec 5, 2024
b0b52aa
Remove unused method
gthea Dec 5, 2024
55d3cbb
Rename config
gthea Dec 5, 2024
06ce624
Emit SDK_READY_FROM_CACHE alongside SDK_READY, if not previously emitted
gthea Dec 5, 2024
57c4841
Merge branch 'SDKS-9072_baseline' into SDKS-9079
gthea Dec 5, 2024
910a82e
Fix test
gthea Dec 5, 2024
18779a1
Update version
gthea Dec 6, 2024
034f0cd
Fix test
gthea Dec 9, 2024
9f371a0
WIP
gthea Dec 9, 2024
ed204a7
WIP
gthea Dec 10, 2024
a041c52
WIP
gthea Dec 10, 2024
552b9ec
Minor changes to UC tests
gthea Dec 10, 2024
9f7f97a
Wip test changes
gthea Dec 10, 2024
4c3b592
Update recorder sync helper to handle multiple listeners
gthea Dec 10, 2024
89f2ece
Merge branch 'SDKS-9104_baseline' into SDKS-9095
gthea Dec 11, 2024
8d8e161
Fix test
gthea Dec 12, 2024
872f01e
Add trackImpressions to Split DTO
gthea Dec 11, 2024
3845f39
Add trackImpressions to SplitView
gthea Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
19 changes: 10 additions & 9 deletions src/main/java/io/split/android/client/SplitManagerImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package io.split.android.client;

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import io.split.android.client.api.SplitView;
import io.split.android.client.dtos.Partition;
import io.split.android.client.dtos.Split;
Expand All @@ -13,15 +22,6 @@
import io.split.android.engine.experiments.ParsedSplit;
import io.split.android.engine.experiments.SplitParser;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

public class SplitManagerImpl implements SplitManager {

private final SplitsStorage _splitsStorage;
Expand Down Expand Up @@ -144,6 +144,7 @@ private SplitView toSplitView(ParsedSplit parsedSplit) {
splitView.configs = parsedSplit.configurations();
splitView.sets = new ArrayList<>(parsedSplit.sets() == null ? new HashSet<>() : parsedSplit.sets());
splitView.defaultTreatment = parsedSplit.defaultTreatment();
splitView.trackImpressions = parsedSplit.trackImpressions();

Set<String> treatments = new HashSet<>();
for (ParsedCondition condition : parsedSplit.parsedConditions()) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/io/split/android/client/api/SplitView.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ public class SplitView {
@NonNull
public List<String> sets = new ArrayList<>();
public String defaultTreatment;
public boolean trackImpressions;
}
3 changes: 3 additions & 0 deletions src/main/java/io/split/android/client/dtos/Split.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@ public class Split {
@Nullable
@SerializedName("sets")
public Set<String> sets;

@SerializedName("trackImpressions")
public boolean trackImpressions = true;
}
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
Loading