Skip to content

Commit 0555001

Browse files
author
Josh Deffibaugh
committed
Merge branch 'devel'
2 parents 828ceb0 + e99f1d9 commit 0555001

File tree

38 files changed

+498
-128
lines changed

38 files changed

+498
-128
lines changed

.idea/dictionaries/jdeffibaugh.xml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/inspectionProfiles/Project_Default.xml

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/inspectionProfiles/profiles_settings.xml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ cache:
1717
- $HOME/.gradle/caches/
1818
- $HOME/.gradle/wrapper/
1919
before_script:
20+
- echo $TRAVIS_BRANCH
21+
- echo $TRAVIS_TAG
2022
- echo no | android create avd --force -n test -t android-24 --abi default/armeabi-v7a
2123
- emulator -avd test -no-audio -no-window &
2224
- android-wait-for-emulator
2325
- adb shell input keyevent 82 &
2426
script:
2527
- ./gradlew testAllModules
26-
- if [[ ( "$TRAVIS_BRANCH" == "beta" || "$TRAVIS_BRANCH" == "master" ) && ( -n "$TRAVIS_TAG") ]]; then ./gradlew ship; fi
28+
- if [[ -n $TRAVIS_TAG ]]; then ./gradlew ship; fi
29+

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Optimizely Android X SDK Changelog
2+
3+
### 0.1.3
4+
October 27, 2016
5+
6+
*Bug Fixes*
7+
- Now service intervals can be changed after they are scheduled the first time.
8+
- If a service is scheduled when rescheduling the old service will be unscheduled.
9+
- Now multiple `OptimizelyManager`instances can be created for multiple Optimizely X projects.
10+
- A manager builds `AndroidOptimizely` for the project id it was created with and only that that project id.
11+
- Could run one project in your activites and one in your services.
12+
- Now shows user experiment record logs.
13+
- Turns on more core logs.
14+
15+
*New Features*
16+
- *Exponential Backoff.* Datafile download event dispatching now exmploy exponential backoff.

android-sdk/build.gradle

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ dependencies {
7474
}
7575

7676
uploadArchives {
77-
dependsOn = [':android-sdk:clean', ':android-sdk:releaseJavadocJar']
77+
dependsOn = [':android-sdk:clean', ':android-sdk:releaseJavadocJar', ':android-sdk:releaseSourcesJar']
7878
shouldRunAfter = [':event-handler:uploadArchives', ':user-experiment-record:uploadArchives']
7979
repositories {
8080
mavenDeployer {
@@ -115,4 +115,12 @@ android.libraryVariants.all { variant ->
115115

116116
// Add the Javadoc jar to the project's artifacts. This will allow us to upload it easily later
117117
project.artifacts.add("archives", tasks["${variant.name}JavadocJar"]);
118-
}
118+
}
119+
120+
android.libraryVariants.all { variant ->
121+
task("${variant.name}SourcesJar", type: Jar) {
122+
classifier = 'sources'
123+
from variant.javaCompile.source
124+
}
125+
project.artifacts.add("archives", tasks["${variant.name}SourcesJar"]);
126+
}

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

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,20 @@
2222
import org.junit.Test;
2323
import org.junit.runner.RunWith;
2424
import org.junit.runners.JUnit4;
25+
import org.mockito.ArgumentCaptor;
2526
import org.slf4j.Logger;
2627

2728
import java.io.IOException;
2829
import java.net.HttpURLConnection;
30+
import java.net.MalformedURLException;
2931
import java.net.URL;
3032

33+
import static junit.framework.Assert.assertTrue;
3134
import static org.junit.Assert.assertEquals;
3235
import static org.junit.Assert.assertNull;
3336
import static org.mockito.Matchers.any;
3437
import static org.mockito.Matchers.contains;
38+
import static org.mockito.Matchers.eq;
3539
import static org.mockito.Mockito.doThrow;
3640
import static org.mockito.Mockito.mock;
3741
import static org.mockito.Mockito.verify;
@@ -63,12 +67,22 @@ public void request200() throws IOException {
6367
when(urlConnection.getResponseCode()).thenReturn(200);
6468
when(client.readStream(urlConnection)).thenReturn("{}");
6569

66-
String response = dataFileClient.request(url.toString());
67-
assertEquals(response, "{}");
70+
dataFileClient.request(url.toString());
71+
72+
ArgumentCaptor<Client.Request> captor1 = ArgumentCaptor.forClass(Client.Request.class);
73+
ArgumentCaptor<Integer> captor2 = ArgumentCaptor.forClass(Integer.class);
74+
ArgumentCaptor<Integer> captor3 = ArgumentCaptor.forClass(Integer.class);
75+
verify(client).execute(captor1.capture(), captor2.capture(), captor3.capture());
76+
assertEquals(Integer.valueOf(2), captor2.getValue());
77+
assertEquals(Integer.valueOf(3), captor3.getValue());
78+
Object response = captor1.getValue().execute();
79+
assertTrue(String.class.isInstance(response));
80+
assertEquals("{}", response);
6881

6982
verify(logger).info("Requesting data file from {}", url);
7083
verify(client).saveLastModified(urlConnection);
7184
verify(client).readStream(urlConnection);
85+
verify(urlConnection).disconnect();
7286
}
7387

7488
@Test
@@ -78,12 +92,22 @@ public void request201() throws IOException {
7892
when(urlConnection.getResponseCode()).thenReturn(201);
7993
when(client.readStream(urlConnection)).thenReturn("{}");
8094

81-
String response = dataFileClient.request(url.toString());
82-
assertEquals(response, "{}");
95+
dataFileClient.request(url.toString());
96+
97+
ArgumentCaptor<Client.Request> captor1 = ArgumentCaptor.forClass(Client.Request.class);
98+
ArgumentCaptor<Integer> captor2 = ArgumentCaptor.forClass(Integer.class);
99+
ArgumentCaptor<Integer> captor3 = ArgumentCaptor.forClass(Integer.class);
100+
verify(client).execute(captor1.capture(), captor2.capture(), captor3.capture());
101+
assertEquals(Integer.valueOf(2), captor2.getValue());
102+
assertEquals(Integer.valueOf(3), captor3.getValue());
103+
Object response = captor1.getValue().execute();
104+
assertTrue(String.class.isInstance(response));
105+
assertEquals("{}", response);
83106

84107
verify(logger).info("Requesting data file from {}", url);
85108
verify(client).saveLastModified(urlConnection);
86109
verify(client).readStream(urlConnection);
110+
verify(urlConnection).disconnect();
87111
}
88112

89113
@Test
@@ -93,12 +117,22 @@ public void request299() throws IOException {
93117
when(urlConnection.getResponseCode()).thenReturn(299);
94118
when(client.readStream(urlConnection)).thenReturn("{}");
95119

96-
String response = dataFileClient.request(url.toString());
97-
assertEquals(response, "{}");
120+
dataFileClient.request(url.toString());
121+
122+
ArgumentCaptor<Client.Request> captor1 = ArgumentCaptor.forClass(Client.Request.class);
123+
ArgumentCaptor<Integer> captor2 = ArgumentCaptor.forClass(Integer.class);
124+
ArgumentCaptor<Integer> captor3 = ArgumentCaptor.forClass(Integer.class);
125+
verify(client).execute(captor1.capture(), captor2.capture(), captor3.capture());
126+
assertEquals(Integer.valueOf(2), captor2.getValue());
127+
assertEquals(Integer.valueOf(3), captor3.getValue());
128+
Object response = captor1.getValue().execute();
129+
assertTrue(String.class.isInstance(response));
130+
assertEquals("{}", response);
98131

99132
verify(logger).info("Requesting data file from {}", url);
100133
verify(client).saveLastModified(urlConnection);
101134
verify(client).readStream(urlConnection);
135+
verify(urlConnection).disconnect();
102136
}
103137

104138
@Test
@@ -107,10 +141,18 @@ public void request300() throws IOException {
107141
when(client.openConnection(url)).thenReturn(urlConnection);
108142
when(urlConnection.getResponseCode()).thenReturn(300);
109143

110-
String response = dataFileClient.request(url.toString());
144+
dataFileClient.request(url.toString());
145+
ArgumentCaptor<Client.Request> captor1 = ArgumentCaptor.forClass(Client.Request.class);
146+
ArgumentCaptor<Integer> captor2 = ArgumentCaptor.forClass(Integer.class);
147+
ArgumentCaptor<Integer> captor3 = ArgumentCaptor.forClass(Integer.class);
148+
verify(client).execute(captor1.capture(), captor2.capture(), captor3.capture());
149+
assertEquals(Integer.valueOf(2), captor2.getValue());
150+
assertEquals(Integer.valueOf(3), captor3.getValue());
151+
Object response = captor1.getValue().execute();
111152
assertNull(response);
112153

113154
verify(logger).error("Unexpected response from data file cdn, status: {}", 300);
155+
verify(urlConnection).disconnect();
114156
}
115157

116158
@Test
@@ -120,10 +162,32 @@ public void handlesIOException() throws IOException {
120162
when(urlConnection.getResponseCode()).thenReturn(200);
121163
doThrow(new IOException()).when(client).readStream(urlConnection);
122164

123-
String response = dataFileClient.request(url.toString());
165+
dataFileClient.request(url.toString());
166+
ArgumentCaptor<Client.Request> captor1 = ArgumentCaptor.forClass(Client.Request.class);
167+
ArgumentCaptor<Integer> captor2 = ArgumentCaptor.forClass(Integer.class);
168+
ArgumentCaptor<Integer> captor3 = ArgumentCaptor.forClass(Integer.class);
169+
verify(client).execute(captor1.capture(), captor2.capture(), captor3.capture());
170+
assertEquals(Integer.valueOf(2), captor2.getValue());
171+
assertEquals(Integer.valueOf(3), captor3.getValue());
172+
Object response = captor1.getValue().execute();
124173
assertNull(response);
125174

126175
verify(logger).error(contains("Error making request"), any(IOException.class));
127176
verify(urlConnection).disconnect();
177+
verify(urlConnection).disconnect();
178+
}
179+
180+
@Test
181+
public void handlesNullResponse() throws MalformedURLException {
182+
URL url = new URL(String.format(DataFileLoader.RequestDataFileFromClientTask.FORMAT_CDN_URL, "1"));
183+
when(client.execute(any(Client.Request.class), eq(2), eq(3))).thenReturn(null);
184+
assertNull(dataFileClient.request(url.toString()));
185+
}
186+
187+
@Test
188+
public void handlesEmptyStringResponse() throws MalformedURLException {
189+
URL url = new URL(String.format(DataFileLoader.RequestDataFileFromClientTask.FORMAT_CDN_URL, "1"));
190+
when(client.execute(any(Client.Request.class), eq(2), eq(3))).thenReturn("");
191+
assertNull(dataFileClient.request(url.toString()));
128192
}
129193
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import android.support.test.runner.AndroidJUnit4;
2525

2626
import com.optimizely.ab.android.shared.ServiceScheduler;
27-
import com.optimizely.user_experiment_record.AndroidUserExperimentRecord;
27+
import com.optimizely.ab.android.user_experiment_record.AndroidUserExperimentRecord;
2828

2929
import org.junit.Before;
3030
import org.junit.Test;

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

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,38 +39,50 @@ class DataFileClient {
3939
this.logger = logger;
4040
}
4141

42-
String request(String urlString) {
43-
HttpURLConnection urlConnection = null;
44-
try {
45-
URL url = new URL(urlString);
46-
logger.info("Requesting data file from {}", url);
47-
urlConnection = client.openConnection(url);
42+
String request(final String urlString) {
43+
Client.Request<String> request = new Client.Request<String>() {
44+
@Override
45+
public String execute() {
46+
HttpURLConnection urlConnection = null;
47+
try {
48+
URL url = new URL(urlString);
49+
logger.info("Requesting data file from {}", url);
50+
urlConnection = client.openConnection(url);
4851

49-
client.setIfModifiedSince(urlConnection);
52+
client.setIfModifiedSince(urlConnection);
5053

51-
urlConnection.setConnectTimeout(5 * 1000);
52-
urlConnection.connect();
54+
urlConnection.setConnectTimeout(5 * 1000);
55+
urlConnection.connect();
5356

54-
int status = urlConnection.getResponseCode();
55-
if (status >= 200 && status < 300) {
56-
client.saveLastModified(urlConnection);
57-
return client.readStream(urlConnection);
58-
} else if (status == 304) {
59-
logger.info("Data file has not been modified on the cdn");
60-
return null;
61-
} else {
62-
logger.error("Unexpected response from data file cdn, status: {}", status);
63-
return null;
57+
int status = urlConnection.getResponseCode();
58+
if (status >= 200 && status < 300) {
59+
client.saveLastModified(urlConnection);
60+
return client.readStream(urlConnection);
61+
} else if (status == 304) {
62+
logger.info("Data file has not been modified on the cdn");
63+
return "";
64+
} else {
65+
logger.error("Unexpected response from data file cdn, status: {}", status);
66+
return null;
67+
}
68+
} catch (IOException e) {
69+
logger.error("Error making request", e);
70+
return null;
71+
} finally {
72+
if (urlConnection != null) {
73+
urlConnection.disconnect();
74+
}
75+
}
6476
}
65-
} catch (IOException e) {
66-
logger.error("Error making request", e);
67-
return null;
68-
} finally {
69-
if (urlConnection != null) {
70-
urlConnection.disconnect();
71-
}
72-
}
73-
}
77+
};
7478

79+
// If the response was a 304 Not Modified an empty string is returned
80+
// Consumers of this method expect either a valid datafile or null
81+
String response = client.execute(request, 2, 3);
82+
if (response != null && response.isEmpty()) {
83+
response = null;
84+
}
7585

86+
return response;
87+
}
7688
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import com.optimizely.ab.bucketing.UserExperimentRecord;
4242
import com.optimizely.ab.config.parser.ConfigParseException;
4343
import com.optimizely.ab.event.internal.payload.Event;
44-
import com.optimizely.user_experiment_record.AndroidUserExperimentRecord;
44+
import com.optimizely.ab.android.user_experiment_record.AndroidUserExperimentRecord;
4545

4646
import org.slf4j.Logger;
4747
import org.slf4j.LoggerFactory;
@@ -56,7 +56,7 @@
5656
* Handles loading the Optimizely data file
5757
*/
5858
public class OptimizelyManager {
59-
@NonNull private static AndroidOptimizely androidOptimizely = new AndroidOptimizely(null,
59+
@NonNull private AndroidOptimizely androidOptimizely = new AndroidOptimizely(null,
6060
LoggerFactory.getLogger(AndroidOptimizely.class));
6161
@NonNull private final String projectId;
6262
@NonNull private final Long eventHandlerDispatchInterval;
@@ -266,7 +266,7 @@ protected void onPostExecute(UserExperimentRecord userExperimentRecord) {
266266
serviceScheduler.schedule(intent, dataFileDownloadIntervalTimeUnit.toMillis(dataFileDownloadInterval));
267267

268268
try {
269-
OptimizelyManager.androidOptimizely = buildOptimizely(context, dataFile, userExperimentRecord);
269+
OptimizelyManager.this.androidOptimizely = buildOptimizely(context, dataFile, userExperimentRecord);
270270
OptimizelyManager.this.userExperimentRecord = userExperimentRecord;
271271
logger.info("Sending Optimizely instance to listener");
272272

0 commit comments

Comments
 (0)