Skip to content

Commit 708ecbf

Browse files
authored
unschedule background polling worker when interval is not set (#397)
- This fixes the bug that a polling worker scheduled before is not disabled when Optimizely is initialized again with polling disabled. - When Optimizely is initialized, stop the previous worker and then restart it again only when polling is enabled.
1 parent 409f345 commit 708ecbf

File tree

5 files changed

+106
-51
lines changed

5 files changed

+106
-51
lines changed

android-sdk/src/androidTest/java/com/optimizely/ab/android/sdk/OptimizelyManagerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public void getDatafile() {
218218
assertNotNull(optimizelyManager.getDatafileHandler());
219219
}
220220

221-
@Test
221+
@Test
222222
public void initializeAsyncWithEnvironment() {
223223
Logger logger = mock(Logger.class);
224224
DatafileHandler datafileHandler = mock(DefaultDatafileHandler.class);
@@ -377,7 +377,7 @@ public void injectOptimizely() {
377377
}
378378

379379
@Test
380-
public void injectOptimizelyWithDatafileLisener() {
380+
public void injectOptimizelyWithDatafileListener() {
381381
Context context = mock(Context.class);
382382
UserProfileService userProfileService = mock(UserProfileService.class);
383383
OptimizelyStartListener startListener = mock(OptimizelyStartListener.class);

android-sdk/src/main/java/com/optimizely/ab/android/sdk/OptimizelyManager.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,9 @@ private boolean datafileDownloadEnabled() {
501501
}
502502

503503
private void startDatafileHandler(Context context) {
504+
// if already running, stop it first.
505+
datafileHandler.stopBackgroundUpdates(context, datafileConfig);
506+
504507
if (!datafileDownloadEnabled()) {
505508
logger.debug("Invalid download interval, ignoring background updates.");
506509
return;
@@ -612,7 +615,7 @@ protected ErrorHandler getErrorHandler(Context context) {
612615
return errorHandler;
613616
}
614617

615-
private boolean isAndroidVersionSupported() {
618+
protected boolean isAndroidVersionSupported() {
616619
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
617620
return true;
618621
} else {

android-sdk/src/test/java/com/optimizely/ab/android/sdk/OptimizelyManagerBuilderTest.java

Lines changed: 98 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,35 @@
1919
import android.content.Context;
2020

2121
import com.optimizely.ab.android.datafile_handler.DatafileHandler;
22+
import com.optimizely.ab.android.datafile_handler.DefaultDatafileHandler;
23+
import com.optimizely.ab.android.shared.WorkerScheduler;
2224
import com.optimizely.ab.android.user_profile.DefaultUserProfileService;
2325
import com.optimizely.ab.error.ErrorHandler;
2426
import com.optimizely.ab.event.EventHandler;
2527

28+
import org.junit.Before;
2629
import org.junit.Test;
2730
import org.junit.runner.RunWith;
2831
import org.mockito.runners.MockitoJUnitRunner;
2932
import org.slf4j.Logger;
3033

3134
import static junit.framework.Assert.assertEquals;
35+
import static org.mockito.Matchers.any;
36+
import static org.mockito.Matchers.eq;
3237
import static org.mockito.Mockito.mock;
38+
import static org.mockito.Mockito.never;
39+
import static org.mockito.Mockito.spy;
40+
import static org.mockito.Mockito.verify;
3341
import static org.mockito.Mockito.when;
3442

43+
import java.sql.Time;
44+
import java.util.concurrent.TimeUnit;
45+
3546
@RunWith(MockitoJUnitRunner.class)
3647
public class OptimizelyManagerBuilderTest {
3748

3849
private String testProjectId = "7595190003";
50+
private String testSdkKey = "1234";
3951
private Logger logger;
4052

4153
private String minDatafile = "{\n" +
@@ -49,78 +61,71 @@ public class OptimizelyManagerBuilderTest {
4961
"events: [ ],\n" +
5062
"revision: \"1\"\n" +
5163
"}";
52-
/**
53-
* Verify that building the {@link OptimizelyManager} with a polling interval less than 60
54-
* seconds defaults to 60 seconds.
55-
*/
56-
// @Test
57-
// public void testBuildWithInvalidPollingInterval() {
58-
// Context appContext = mock(Context.class);
59-
// when(appContext.getApplicationContext()).thenReturn(appContext);
60-
// OptimizelyManager manager = OptimizelyManager.builder("1")
61-
// .withDatafileDownloadInterval(5L)
62-
// .build(appContext);
63-
//
64-
// assertEquals(900L, manager.getDatafileDownloadInterval().longValue());
65-
// }
64+
65+
private Context mockContext;
66+
private DefaultDatafileHandler mockDatafileHandler;
67+
68+
@Before
69+
public void setup() throws Exception {
70+
mockContext = mock(Context.class);
71+
when(mockContext.getApplicationContext()).thenReturn(mockContext);
72+
mockDatafileHandler = mock(DefaultDatafileHandler.class);
73+
}
6674

6775
/**
6876
* Verify that building the {@link OptimizelyManager} with a polling interval greater than 60
6977
* seconds is properly registered.
7078
*/
7179
@Test
7280
public void testBuildWithValidPollingInterval() {
73-
Context appContext = mock(Context.class);
74-
when(appContext.getApplicationContext()).thenReturn(appContext);
75-
OptimizelyManager manager = OptimizelyManager.builder("1")
76-
.withDatafileDownloadInterval(901L)
77-
.build(appContext);
81+
Long interval = 16L;
82+
TimeUnit timeUnit = TimeUnit.MINUTES;
7883

79-
assertEquals(901L, manager.getDatafileDownloadInterval().longValue());
84+
OptimizelyManager manager = OptimizelyManager.builder()
85+
.withSDKKey(testSdkKey)
86+
.withDatafileDownloadInterval(interval, timeUnit)
87+
.build(mockContext);
88+
89+
assertEquals(interval * 60L, manager.getDatafileDownloadInterval().longValue());
8090
}
8191

8292
@Test
8393
public void testBuildWithEventHandler() {
84-
Context appContext = mock(Context.class);
85-
when(appContext.getApplicationContext()).thenReturn(appContext);
8694
EventHandler eventHandler = mock(EventHandler.class);
87-
OptimizelyManager manager = OptimizelyManager.builder(testProjectId)
88-
.withDatafileDownloadInterval(901L)
95+
OptimizelyManager manager = OptimizelyManager.builder()
96+
.withSDKKey(testSdkKey)
97+
.withDatafileDownloadInterval(901L, TimeUnit.SECONDS)
8998
.withEventHandler(eventHandler)
90-
.build(appContext);
99+
.build(mockContext);
91100

92101
assertEquals(901L, manager.getDatafileDownloadInterval().longValue());
93-
assertEquals(manager.getEventHandler(appContext), eventHandler);
94-
95-
102+
assertEquals(manager.getEventHandler(mockContext), eventHandler);
96103
}
97104

98105
@Test
99106
public void testBuildWithErrorHandler() {
100-
Context appContext = mock(Context.class);
101-
when(appContext.getApplicationContext()).thenReturn(appContext);
102107
ErrorHandler errorHandler = mock(ErrorHandler.class);
103-
OptimizelyManager manager = OptimizelyManager.builder(testProjectId)
104-
.withDatafileDownloadInterval(61L)
108+
OptimizelyManager manager = OptimizelyManager.builder()
109+
.withSDKKey(testSdkKey)
110+
.withDatafileDownloadInterval(61L, TimeUnit.SECONDS)
105111
.withErrorHandler(errorHandler)
106-
.build(appContext);
112+
.build(mockContext);
107113

108-
manager.initialize(appContext, minDatafile);
114+
manager.initialize(mockContext, minDatafile);
109115

110-
assertEquals(manager.getErrorHandler(appContext), errorHandler);
116+
assertEquals(manager.getErrorHandler(mockContext), errorHandler);
111117
}
112118

113119
@Test
114120
public void testBuildWithDatafileHandler() {
115-
Context appContext = mock(Context.class);
116-
when(appContext.getApplicationContext()).thenReturn(appContext);
117-
DatafileHandler dfHandler = mock(DatafileHandler.class);
118-
OptimizelyManager manager = OptimizelyManager.builder(testProjectId)
119-
.withDatafileDownloadInterval(61L)
121+
DefaultDatafileHandler dfHandler = mock(DefaultDatafileHandler.class);
122+
OptimizelyManager manager = OptimizelyManager.builder()
123+
.withSDKKey(testSdkKey)
124+
.withDatafileDownloadInterval(61L, TimeUnit.SECONDS)
120125
.withDatafileHandler(dfHandler)
121-
.build(appContext);
126+
.build(mockContext);
122127

123-
manager.initialize(appContext, minDatafile);
128+
manager.initialize(mockContext, minDatafile);
124129

125130
assertEquals(manager.getDatafileHandler(), dfHandler);
126131
}
@@ -130,13 +135,62 @@ public void testBuildWithUserProfileService() {
130135
Context appContext = mock(Context.class);
131136
when(appContext.getApplicationContext()).thenReturn(appContext);
132137
DefaultUserProfileService ups = mock(DefaultUserProfileService.class);
133-
OptimizelyManager manager = OptimizelyManager.builder(testProjectId)
134-
.withDatafileDownloadInterval(61L)
138+
OptimizelyManager manager = OptimizelyManager.builder()
139+
.withSDKKey(testSdkKey)
140+
.withDatafileDownloadInterval(61L, TimeUnit.SECONDS)
135141
.withUserProfileService(ups)
136142
.build(appContext);
137143

138144
manager.initialize(appContext, minDatafile);
139145

140146
assertEquals(manager.getUserProfileService(), ups);
141147
}
148+
149+
// BackgroundDatafile worker tests
150+
151+
@Test
152+
public void testBuildWithDatafileDownloadInterval_workerScheduled() throws Exception {
153+
long goodNumber = 1;
154+
OptimizelyManager manager = OptimizelyManager.builder()
155+
.withSDKKey(testSdkKey)
156+
.withDatafileHandler(mockDatafileHandler)
157+
.withDatafileDownloadInterval(goodNumber, TimeUnit.MINUTES)
158+
.build(mockContext);
159+
OptimizelyManager spyManager = spy(manager);
160+
when(spyManager.isAndroidVersionSupported()).thenReturn(true);
161+
spyManager.initialize(mockContext, "");
162+
163+
verify(mockDatafileHandler).stopBackgroundUpdates(any(), any());
164+
verify(mockDatafileHandler).startBackgroundUpdates(any(), any(), eq(goodNumber * 60L), any());
165+
}
166+
167+
@Test
168+
public void testBuildWithDatafileDownloadInterval_workerCancelledWhenIntervalIsNotPositive() throws Exception {
169+
OptimizelyManager manager = OptimizelyManager.builder()
170+
.withSDKKey(testSdkKey)
171+
.withDatafileHandler(mockDatafileHandler)
172+
.withDatafileDownloadInterval(-1, TimeUnit.MINUTES)
173+
.build(mockContext);
174+
OptimizelyManager spyManager = spy(manager);
175+
when(spyManager.isAndroidVersionSupported()).thenReturn(true);
176+
spyManager.initialize(mockContext, "");
177+
178+
verify(mockDatafileHandler).stopBackgroundUpdates(any(), any());
179+
verify(mockDatafileHandler, never()).startBackgroundUpdates(any(), any(), any(), any());
180+
}
181+
182+
@Test
183+
public void testBuildWithDatafileDownloadInterval_workerCancelledWhenNoIntervalProvided() throws Exception {
184+
OptimizelyManager manager = OptimizelyManager.builder()
185+
.withSDKKey(testSdkKey)
186+
.withDatafileHandler(mockDatafileHandler)
187+
.build(mockContext);
188+
OptimizelyManager spyManager = spy(manager);
189+
when(spyManager.isAndroidVersionSupported()).thenReturn(true);
190+
spyManager.initialize(mockContext, "");
191+
192+
verify(mockDatafileHandler).stopBackgroundUpdates(any(), any());
193+
verify(mockDatafileHandler, never()).startBackgroundUpdates(any(), any(), any(), any());
194+
}
195+
142196
}

datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/DefaultDatafileHandler.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,6 @@ public void downloadDatafileToCache(final Context context, DatafileConfig datafi
118118
* @param updateInterval frequency of updates in seconds
119119
*/
120120
public void startBackgroundUpdates(Context context, DatafileConfig datafileConfig, Long updateInterval, DatafileLoadedListener listener) {
121-
// if already running, stop it
122-
stopBackgroundUpdates(context, datafileConfig);
123-
124121
long updateIntervalInMinutes = updateInterval / 60;
125122

126123
// save the project id background start is set. If we get a reboot or a replace, we can restart via the

shared/src/main/java/com/optimizely/ab/android/shared/WorkerScheduler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ public static void unscheduleService(Context context, String workerId) {
6060
* @return An (WorkRequest, Operation) that can be used for tracing work state
6161
*/
6262
public static AbstractMap.SimpleEntry<WorkRequest, Operation> scheduleService(Context context, String workerId, Class clazz, Data data, long interval) {
63-
WorkManager.getInstance(context).cancelAllWorkByTag(workerId);
63+
unscheduleService(context, workerId);
64+
6465
long minutes = interval < 15 ? 15 : interval;
6566

6667
WorkRequest.Builder workRequestBuilder = new PeriodicWorkRequest.Builder(clazz, minutes, TimeUnit.MINUTES)

0 commit comments

Comments
 (0)