Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ dependencies {
def apacheCommonsVersion = '3.12.0'
def kotlinVer = '1.5.31'
def mockWebServerVersion = '4.12.0'
def robolectricVersion = '4.16'

def testRulesVersion = '1.4.0'
def jUnitExtVersion = '1.1.3'
Expand Down Expand Up @@ -177,6 +178,8 @@ dependencies {
testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVer"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVer"
testImplementation "com.google.guava:guava:$guavaVersion"
testImplementation "org.robolectric:robolectric:$robolectricVersion"
testImplementation "androidx.work:work-testing:$workVersion"

androidTestImplementation "androidx.test:rules:$testRulesVersion"
androidTestImplementation "androidx.test.ext:junit:$jUnitExtVersion"
Expand Down Expand Up @@ -279,7 +282,6 @@ task printReleaseDependenciesToFile {
preBuild.dependsOn printReleaseDependenciesToFile

tasks.withType(Test) {
systemProperties['junit.jupiter.execution.parallel.enabled'] = true
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
forkEvery = 100
maxHeapSize = "1024m"
Expand Down
29 changes: 21 additions & 8 deletions jacoco.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ tasks.withType(Test) {
jacoco {
includeNoLocationClasses = true
excludes = ['jdk.internal.*']
// Explicitly enable for Robolectric tests
enabled = true
}

// Configure system properties for Robolectric + JaCoCo compatibility
systemProperty 'robolectric.enabledSdks', '28,29,30,31,32,33'

finalizedBy jacocoTestReport
}

Expand All @@ -37,13 +43,18 @@ tasks.register('jacocoTestReport', JacocoReport) {
"${buildDir}/intermediates/javac/debug/classes",
"${buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes",
"${buildDir}/intermediates/runtime_library_classes_dir/debug",
"${buildDir}/intermediates/classes/debug",
"${buildDir}/classes/java/main",
"${buildDir}/tmp/kotlin-classes/debug"
]

possibleClassDirs.each { dirPath ->
def classDir = fileTree(dir: dirPath, excludes: fileFilter)
if (classDir.files.size() > 0) {
classDirectoriesFiles.add(classDir)
def dir = file(dirPath)
if (dir.exists() && dir.isDirectory()) {
def classDir = fileTree(dir: dirPath, excludes: fileFilter)
if (classDir.files.size() > 0) {
classDirectoriesFiles.add(classDir)
}
}
}

Expand All @@ -57,12 +68,14 @@ tasks.register('jacocoTestReport', JacocoReport) {
classDirectories.from = files(classDirectoriesFiles)

// Include execution data files from multiple possible locations
executionData.from(fileTree(dir: "$buildDir", includes: [
def execFiles = fileTree(dir: "$buildDir", includes: [
'jacoco/testDebugUnitTest.exec',
'outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec',
'jacoco/*.exec',
'outputs/**/**.exec'
]))
])

executionData.from = files(execFiles.filter { it.exists() })

outputs.upToDateWhen { false }

Expand All @@ -87,12 +100,12 @@ tasks.register('jacocoTestReport', JacocoReport) {
}

// Log execution data files
def execFiles = executionData.files
def execDataFiles = executionData.files
logger.lifecycle("Execution data files:")
if (execFiles.isEmpty() || !execFiles.any { it.exists() }) {
if (execDataFiles.isEmpty() || !execDataFiles.any { it.exists() }) {
logger.warn(" - No execution data files found - coverage report will be empty")
} else {
execFiles.each { file ->
execDataFiles.each { file ->
if (file.exists()) {
logger.lifecycle(" - Found: $file (${file.length()} bytes)")
} else {
Expand Down
54 changes: 27 additions & 27 deletions src/androidTest/java/tests/storage/SplitsStorageTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public void addSplits() {
splits.add(split);
}
ProcessedSplitChange change = new ProcessedSplitChange(splits, new ArrayList<>(), 1L, 0L);
mSplitsStorage.update(change);
mSplitsStorage.update(change, null);

for (int i = 0; i < 4; i++) {
String splitName = "split-test-" + i;
Expand All @@ -120,7 +120,7 @@ public void updateChangeNumber() {
Long newChangeNumber = INITIAL_CHANGE_NUMBER + 100;
Long initialChangeNumber = mSplitsStorage.getTill();
ProcessedSplitChange change = new ProcessedSplitChange(splits, splits, newChangeNumber, 0L);
mSplitsStorage.update(change);
mSplitsStorage.update(change, null);
Long updatedChangeNumber = mSplitsStorage.getTill();
Assert.assertEquals(INITIAL_CHANGE_NUMBER, initialChangeNumber);
Assert.assertEquals(newChangeNumber, updatedChangeNumber);
Expand All @@ -131,7 +131,7 @@ public void updateEmptySplit() {
mSplitsStorage.loadLocal();
List<Split> splits = new ArrayList<>();
ProcessedSplitChange change = new ProcessedSplitChange(splits, splits, 1L, 0L);
mSplitsStorage.update(change);
mSplitsStorage.update(change, null);

Map<String, Split> loadedSplits = mSplitsStorage.getMany(null);
long changeNumber = mSplitsStorage.getTill();
Expand All @@ -144,7 +144,7 @@ public void updateEmptySplit() {
public void addNullSplitList() {
mSplitsStorage.loadLocal();
ProcessedSplitChange change = new ProcessedSplitChange(null, new ArrayList<>(), 1L, 0L);
mSplitsStorage.update(change);
mSplitsStorage.update(change, null);

Map<String, Split> loadedSplits = mSplitsStorage.getMany(null);
long changeNumber = mSplitsStorage.getTill();
Expand All @@ -157,7 +157,7 @@ public void addNullSplitList() {
public void deleteNullSplitList() {
mSplitsStorage.loadLocal();
ProcessedSplitChange change = new ProcessedSplitChange(new ArrayList<>(), null, 1L, 0L);
mSplitsStorage.update(change);
mSplitsStorage.update(change, null);

Map<String, Split> loadedSplits = mSplitsStorage.getMany(null);
long changeNumber = mSplitsStorage.getTill();
Expand Down Expand Up @@ -220,7 +220,7 @@ public void run() {
}
}
ProcessedSplitChange change = new ProcessedSplitChange(activeSplits, archivedSplits, 1L, 0L);
mSplitsStorage.update(change);
mSplitsStorage.update(change, null);
}
latch.countDown();
}
Expand Down Expand Up @@ -251,7 +251,7 @@ public void run() {
}
}
ProcessedSplitChange change = new ProcessedSplitChange(activeSplits, archivedSplits, 1L, 0L);
mSplitsStorage.update(change);
mSplitsStorage.update(change, null);
}
latch.countDown();
}
Expand Down Expand Up @@ -283,11 +283,11 @@ public void updatedSplitTrafficType() {
Split s2 = newSplit("s2", Status.ACTIVE, "mytt");
Split s2ar = newSplit("s2", Status.ARCHIVED, "mytt");

mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s2), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s2), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s2), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(empty, Arrays.asList(s2ar), 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s2), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s2), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s2), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(empty, Arrays.asList(s2ar), 1L, 0L), null);

assertTrue(mSplitsStorage.isValidTrafficType("tt"));
assertFalse(mSplitsStorage.isValidTrafficType("mytt"));
Expand All @@ -302,10 +302,10 @@ public void changedTrafficTypeForSplit() {
Split s1t1 = newSplit(splitName, Status.ACTIVE, "tt");
Split s1t2 = newSplit(splitName, Status.ACTIVE, "mytt");

mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t2), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t2), empty, 1L, 0L), null);

assertFalse(mSplitsStorage.isValidTrafficType("tt"));
assertTrue(mSplitsStorage.isValidTrafficType("mytt"));
Expand All @@ -321,11 +321,11 @@ public void existingChangedTrafficTypeForSplit() {
Split s1t1 = newSplit(splitName, Status.ACTIVE, "tt");
Split s1t2 = newSplit(splitName, Status.ACTIVE, "mytt");

mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s0), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t2), empty, 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s0), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t1), empty, 1L, 0L), null);
mSplitsStorage.update(new ProcessedSplitChange(Arrays.asList(s1t2), empty, 1L, 0L), null);

assertTrue(mSplitsStorage.isValidTrafficType("tt"));
assertTrue(mSplitsStorage.isValidTrafficType("mytt"));
Expand Down Expand Up @@ -361,7 +361,7 @@ public void loadedFromStorageTrafficTypesAreCorrectlyUpdated() {
mSplitsStorage.loadLocal();

Split updatedSplit = newSplit("split_test", Status.ACTIVE, "new_type");
mSplitsStorage.update(new ProcessedSplitChange(Collections.singletonList(updatedSplit), Collections.emptyList(), 1L, 0L));
mSplitsStorage.update(new ProcessedSplitChange(Collections.singletonList(updatedSplit), Collections.emptyList(), 1L, 0L), null);

assertFalse(mSplitsStorage.isValidTrafficType("test_type"));
assertTrue(mSplitsStorage.isValidTrafficType("new_type"));
Expand Down Expand Up @@ -410,7 +410,7 @@ public void flagSetsAreRemovedWhenUpdating() {

mSplitsStorage.update(new ProcessedSplitChange(
Collections.singletonList(newSplit("split_test", Status.ACTIVE, "test_type")), Collections.emptyList(),
1L, 0L));
1L, 0L), null);

assertFalse(initialSet1.isEmpty());
Assert.assertEquals(Collections.emptySet(), mSplitsStorage.getNamesByFlagSets(Collections.singletonList("set_1")));
Expand Down Expand Up @@ -448,7 +448,7 @@ public void updateReturnsTrueWhenFlagsHaveBeenRemovedFromStorage() {

ArrayList<Split> archivedSplits = new ArrayList<>();
archivedSplits.add(newSplit("split_test", Status.ARCHIVED, "test_type"));
boolean update = mSplitsStorage.update(new ProcessedSplitChange(new ArrayList<>(), archivedSplits, 1L, 0L));
boolean update = mSplitsStorage.update(new ProcessedSplitChange(new ArrayList<>(), archivedSplits, 1L, 0L), null);

assertTrue(update);
}
Expand All @@ -461,7 +461,7 @@ public void updateReturnsTrueWhenFlagsWereAddedToStorage() {

ArrayList<Split> activeSplits = new ArrayList<>();
activeSplits.add(newSplit("split_test_3", Status.ACTIVE, "test_type_2", Collections.singleton("set_2")));
boolean update = mSplitsStorage.update(new ProcessedSplitChange(activeSplits, new ArrayList<>(), 1L, 0L));
boolean update = mSplitsStorage.update(new ProcessedSplitChange(activeSplits, new ArrayList<>(), 1L, 0L), null);

assertTrue(update);
}
Expand All @@ -474,7 +474,7 @@ public void updateReturnsTrueWhenFlagsWereUpdatedInStorage() {

ArrayList<Split> activeSplits = new ArrayList<>();
activeSplits.add(newSplit("split_test", Status.ACTIVE, "test_type", Collections.singleton("set_2")));
boolean update = mSplitsStorage.update(new ProcessedSplitChange(activeSplits, new ArrayList<>(), 1L, 0L));
boolean update = mSplitsStorage.update(new ProcessedSplitChange(activeSplits, new ArrayList<>(), 1L, 0L), null);

assertTrue(update);
}
Expand All @@ -487,7 +487,7 @@ public void updateReturnsFalseWhenFlagsThatAreNotInStorageAreAttemptedToBeRemove

ArrayList<Split> archivedSplits = new ArrayList<>();
archivedSplits.add(newSplit("split_test_3", Status.ACTIVE, "test_type_2", Collections.singleton("set_2")));
boolean update = mSplitsStorage.update(new ProcessedSplitChange(new ArrayList<>(), archivedSplits, 1L, 0L));
boolean update = mSplitsStorage.update(new ProcessedSplitChange(new ArrayList<>(), archivedSplits, 1L, 0L), null);

assertFalse(update);
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/split/android/client/Destroyer.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.split.android.client;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;

Expand Down Expand Up @@ -36,6 +37,7 @@ class Destroyer implements Runnable {
private final SplitManager mSplitManager;
private final SplitTaskExecutor mSplitTaskExecutor;
private final SplitTaskExecutor mSplitSingleThreadTaskExecutor;
private final ExecutorService mInitExecutor;
private final AtomicBoolean mIsTerminated;

Destroyer(
Expand All @@ -56,6 +58,7 @@ class Destroyer implements Runnable {
SplitManager splitManager,
SplitTaskExecutor splitTaskExecutor,
SplitTaskExecutor splitSingleThreadTaskExecutor,
ExecutorService initExecutor,
AtomicBoolean isTerminated
) {
mInitLock = initLock;
Expand All @@ -75,6 +78,7 @@ class Destroyer implements Runnable {
mSplitManager = splitManager;
mSplitTaskExecutor = splitTaskExecutor;
mSplitSingleThreadTaskExecutor = splitSingleThreadTaskExecutor;
mInitExecutor = initExecutor;
mIsTerminated = isTerminated;
}

Expand Down Expand Up @@ -115,6 +119,7 @@ public void run() {
mSplitSingleThreadTaskExecutor.stop();
Logger.d("Successful shutdown of task executor");
mStorageContainer.getAttributesStorageContainer().destroy();
mInitExecutor.shutdown();
Logger.d("Successful shutdown of attributes storage");
mIsTerminated.set(true);
Logger.d("SplitFactory has been destroyed");
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/io/split/android/client/SplitFactoryHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,17 @@ String getDatabaseName(SplitClientConfig config, String apiToken, Context contex
return dbName;
}

private String buildDatabaseName(SplitClientConfig config, String apiToken) {
@Nullable
private String getDbName(SplitClientConfig config, String apiToken, Context context) {
String dbName = buildDatabaseName(config, apiToken);
File dbPath = context.getDatabasePath(dbName);
if (dbPath.exists()) {
return dbName;
}
return null;
}

static String buildDatabaseName(SplitClientConfig config, String apiToken) {
if (apiToken == null) {
throw new IllegalArgumentException("SDK key cannot be null");
}
Expand Down
Loading
Loading