Skip to content

Commit 4bac22b

Browse files
hborisoffe7mac
andauthored
Fix start callback to be invoked on failure. (#402)
Co-authored-by: Mayank Sanganeria <[email protected]>
1 parent bce9853 commit 4bac22b

File tree

6 files changed

+149
-23
lines changed

6 files changed

+149
-23
lines changed

AndroidSDKCore/src/main/java/com/leanplum/Leanplum.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,12 @@ public void response(JSONObject response) {
704704
handleStartResponse(response);
705705
}
706706
});
707+
request.onError(new RequestOld.ErrorCallback() {
708+
@Override
709+
public void error(Exception e) {
710+
handleStartResponse(null);
711+
}
712+
});
707713

708714
if (isBackground) {
709715
request.sendEventually();
@@ -725,9 +731,10 @@ private static void handleStartResponse(final JSONObject response) {
725731
// Load the variables that were stored on the device from the last session.
726732
VarCache.loadDiffs();
727733

728-
triggerStartResponse(false);
729734
} catch (Throwable t) {
730735
Util.handleException(t);
736+
} finally {
737+
triggerStartResponse(success);
731738
}
732739
} else {
733740
try {
@@ -781,7 +788,6 @@ private static void handleStartResponse(final JSONObject response) {
781788
applyContentInResponse(response, true);
782789

783790
VarCache.saveUserAttributes();
784-
triggerStartResponse(true);
785791

786792
if (response.optBoolean(Constants.Keys.SYNC_INBOX, false)) {
787793
LeanplumInbox.getInstance().downloadMessages();
@@ -892,6 +898,8 @@ public void run() {
892898
startHeartbeat();
893899
} catch (Throwable t) {
894900
Util.handleException(t);
901+
} finally {
902+
triggerStartResponse(success);
895903
}
896904
}
897905
}

AndroidSDKCore/src/main/java/com/leanplum/internal/RequestOld.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ public interface NoPendingDownloadsCallback {
361361
* @param responseBody JSONObject with response body from server.
362362
* @param error Exception.
363363
*/
364-
protected void parseResponseBody(JSONObject responseBody, Exception error) {
364+
protected void triggerCallbackManager(JSONObject responseBody, Exception error) {
365365
synchronized (RequestOld.class) {
366366
if (responseBody == null && error != null) {
367367
// Invoke potential error callbacks for all events of this request.
@@ -520,7 +520,7 @@ private void sendRequests() {
520520

521521
if (statusCode >= 200 && statusCode <= 299) {
522522
// Parse response body and trigger callbacks
523-
parseResponseBody(responseBody, null);
523+
triggerCallbackManager(responseBody, null);
524524

525525
// Clear localErrors list.
526526
localErrors.clear();
@@ -534,15 +534,16 @@ private void sendRequests() {
534534
Exception errorException = new Exception("HTTP error " + statusCode);
535535
if (statusCode != -1 && statusCode != 408 && !(statusCode >= 500 && statusCode <= 599)) {
536536
deleteSentRequests(unsentRequests.size());
537-
parseResponseBody(responseBody, errorException);
538537
}
538+
triggerCallbackManager(responseBody, errorException);
539539
}
540540
} catch (JSONException e) {
541541
Log.e("Error parsing JSON response: " + e.toString() + "\n" + Log.getStackTraceString(e));
542542
deleteSentRequests(unsentRequests.size());
543-
parseResponseBody(null, e);
543+
triggerCallbackManager(null, e);
544544
} catch (Exception e) {
545545
Log.e("Unable to send request: " + e.toString() + "\n" + Log.getStackTraceString(e));
546+
triggerCallbackManager(null, e);
546547
} finally {
547548
if (op != null) {
548549
op.disconnect();

AndroidSDKTests/src/test/java/com/leanplum/LeanplumTest.java

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,17 @@
4848
import com.leanplum.models.GeofenceEventType;
4949
import com.leanplum.models.MessageArchiveData;
5050

51+
import java.io.ByteArrayInputStream;
52+
import java.io.ByteArrayOutputStream;
53+
import java.net.HttpURLConnection;
54+
import java.net.URL;
55+
import javax.net.ssl.HttpsURLConnection;
5156
import org.json.JSONArray;
5257
import org.json.JSONException;
5358
import org.json.JSONObject;
5459
import org.junit.Test;
5560
import org.mockito.Mockito;
61+
import org.powermock.api.mockito.PowerMockito;
5662
import org.robolectric.RuntimeEnvironment;
5763

5864
import java.lang.reflect.Method;
@@ -81,6 +87,7 @@
8187
import static org.mockito.Matchers.anyDouble;
8288
import static org.mockito.Matchers.anyInt;
8389
import static org.mockito.Matchers.anyString;
90+
import static org.mockito.Mockito.mock;
8491
import static org.mockito.Mockito.never;
8592
import static org.mockito.Mockito.times;
8693
import static org.mockito.Mockito.when;
@@ -161,6 +168,97 @@ public void onResponse(boolean success) {
161168
assertTrue(Leanplum.hasStarted());
162169
}
163170

171+
/**
172+
* Test to verify that callbacks are invoked when Exception is thrown after https request.
173+
*/
174+
@Test
175+
public void testStartFailWithException() throws Exception {
176+
// Seed response to throw exception.
177+
ResponseHelper.seedJsonResponseException();
178+
179+
// Expected request params.
180+
final HashMap<String, Object> expectedRequestParams = CollectionUtil.newHashMap(
181+
"city", "(detect)",
182+
"country", "(detect)",
183+
"location", "(detect)",
184+
"region", "(detect)",
185+
"locale", "en_US"
186+
);
187+
188+
// Validate request.
189+
RequestHelper.addRequestHandler(new RequestHelper.RequestHandler() {
190+
@Override
191+
public void onRequest(String httpMethod, String apiMethod, Map<String, Object> params) {
192+
assertEquals(Constants.Methods.START, apiMethod);
193+
assertTrue(params.keySet().containsAll(expectedRequestParams.keySet()));
194+
assertTrue(params.values().containsAll(expectedRequestParams.values()));
195+
}
196+
});
197+
198+
class TestStartCallback extends StartCallback {
199+
private boolean onResponseCalled;
200+
private boolean startSuccessfull;
201+
@Override
202+
public void onResponse(boolean success) {
203+
onResponseCalled = true;
204+
startSuccessfull = success;
205+
}
206+
}
207+
208+
TestStartCallback callback = new TestStartCallback();
209+
Leanplum.start(mContext, callback);
210+
211+
assertTrue(Leanplum.hasStarted());
212+
assertTrue(callback.onResponseCalled);
213+
assertFalse(callback.startSuccessfull);
214+
}
215+
216+
/**
217+
* Test to verify that callbacks are invoked when responseCode is 500 after https request.
218+
*/
219+
@Test
220+
public void testStartFailWithInternalServerError() throws Exception {
221+
prepareHttpsURLConnection(500);
222+
223+
ResponseHelper.seedJsonResponseNull();
224+
225+
// Expected request params.
226+
final HashMap<String, Object> expectedRequestParams = CollectionUtil.newHashMap(
227+
"city", "(detect)",
228+
"country", "(detect)",
229+
"location", "(detect)",
230+
"region", "(detect)",
231+
"locale", "en_US"
232+
);
233+
234+
// Validate request.
235+
RequestHelper.addRequestHandler(new RequestHelper.RequestHandler() {
236+
@Override
237+
public void onRequest(String httpMethod, String apiMethod, Map<String, Object> params) {
238+
assertEquals(Constants.Methods.START, apiMethod);
239+
assertTrue(params.keySet().containsAll(expectedRequestParams.keySet()));
240+
assertTrue(params.values().containsAll(expectedRequestParams.values()));
241+
}
242+
});
243+
244+
class TestStartCallback extends StartCallback {
245+
private boolean onResponseCalled;
246+
private boolean startSuccessfull;
247+
@Override
248+
public void onResponse(boolean success) {
249+
onResponseCalled = true;
250+
startSuccessfull = success;
251+
}
252+
}
253+
254+
TestStartCallback callback = new TestStartCallback();
255+
Leanplum.start(mContext, callback);
256+
257+
assertTrue(Leanplum.hasStarted());
258+
assertTrue(callback.onResponseCalled);
259+
assertFalse(callback.startSuccessfull);
260+
}
261+
164262
@Test
165263
public void testStartWithUserAttributes() {
166264
ResponseHelper.seedResponse("/responses/simple_start_response.json");

AndroidSDKTests/src/test/java/com/leanplum/__setup/AbstractTest.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,21 +150,9 @@ public void before() throws Exception {
150150
// Setup the sdk.
151151
LeanplumTestHelper.setUp();
152152

153-
// Mock url connection to work offline.
154-
URL mockedURL = mock(URL.class);
155-
HttpsURLConnection httpsURLConnection = mock(HttpsURLConnection.class);
156-
157153
// To be able to run tests offline and not depend on a server we have to mock URLConnection to
158154
// return proper status code.
159-
whenNew(URL.class).withParameterTypes(String.class).withArguments(anyString())
160-
.thenReturn(mockedURL);
161-
when(mockedURL.openConnection()).thenReturn(httpsURLConnection);
162-
when(httpsURLConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
163-
when(httpsURLConnection.getResponseCode()).thenReturn(200);
164-
// We are just seeding a random file as a InputStream of a mocked httpConnection which will be
165-
// used in FileManager tests other tests depends on Util.getResponse() to mock response.
166-
when(httpsURLConnection.getInputStream()).thenReturn(ResponseHelper
167-
.seedInputStream("/responses/simple_start_response.json"));
155+
prepareHttpsURLConnection(200);
168156

169157
stopLeanplumExceptionHandling();
170158

@@ -202,6 +190,22 @@ protected void resumeLeanplumExceptionHandling() throws Exception {
202190
PowerMockito.doNothing().when(Util.class, "handleException", any(Throwable.class));
203191
}
204192

193+
protected void prepareHttpsURLConnection(int responseCode) throws Exception {
194+
// Mock url connection to work offline.
195+
URL mockedURL = mock(URL.class);
196+
HttpsURLConnection httpsURLConnection = mock(HttpsURLConnection.class);
197+
198+
whenNew(URL.class).withParameterTypes(String.class).withArguments(anyString())
199+
.thenReturn(mockedURL);
200+
when(mockedURL.openConnection()).thenReturn(httpsURLConnection);
201+
when(httpsURLConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
202+
when(httpsURLConnection.getResponseCode()).thenReturn(responseCode);
203+
// We are just seeding a random file as a InputStream of a mocked httpConnection which will be
204+
// used in FileManager tests other tests depends on Util.getResponse() to mock response.
205+
when(httpsURLConnection.getInputStream()).thenReturn(ResponseHelper
206+
.seedInputStream("/responses/simple_start_response.json"));
207+
}
208+
205209
@After
206210
public void after() {
207211
LeanplumTestHelper.tearDown();

AndroidSDKTests/src/test/java/com/leanplum/_whitebox/utilities/RequestHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public void sendEventually() {
7676
}
7777

7878
@Override
79-
protected void parseResponseBody(JSONObject responseBody, Exception error) {
79+
protected void triggerCallbackManager(JSONObject responseBody, Exception error) {
8080
try {
8181
// attach the uuid we generated
8282
JSONArray jsonArray = responseBody.getJSONArray("response");
@@ -87,7 +87,7 @@ protected void parseResponseBody(JSONObject responseBody, Exception error) {
8787
} catch (Exception e) {
8888
// ignore
8989
}
90-
super.parseResponseBody(responseBody, error);
90+
super.triggerCallbackManager(responseBody, error);
9191
}
9292

9393
/**

AndroidSDKTests/src/test/java/com/leanplum/_whitebox/utilities/ResponseHelper.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
import com.leanplum.internal.Util;
2525

2626
import java.io.BufferedReader;
27+
import java.io.IOException;
2728
import java.io.InputStream;
2829
import java.io.InputStreamReader;
2930

3031
import static org.mockito.Matchers.anyObject;
3132
import static org.powermock.api.mockito.PowerMockito.doReturn;
33+
import static org.powermock.api.mockito.PowerMockito.doThrow;
3234

3335
/**
3436
* @author Milos Jakovljevic
@@ -79,13 +81,26 @@ public static void seedResponse(String filename) {
7981
* Seeds the Null response to Util.getResponse method.
8082
*
8183
*/
82-
83-
8484
public static void seedResponseNull() {
8585
try {
8686
doReturn(false).when(Util.class, Util.isConnected());
8787
} catch (Exception e) {
8888
Log.e("ResponseHelper", "Unable to seed response from file: ");
8989
}
9090
}
91+
92+
/**
93+
* Seeds Null response to Util.getJsonResponse method.
94+
*/
95+
public static void seedJsonResponseNull() throws Exception{
96+
doReturn(null).when(Util.class, "getJsonResponse", anyObject());
97+
}
98+
99+
/**
100+
* Seed response to throw an exception.
101+
* Used for testing if request callbacks are invoked in case of exception.
102+
*/
103+
public static void seedJsonResponseException() throws Exception {
104+
doThrow(new IOException()).when(Util.class, "getJsonResponse", anyObject());
105+
}
91106
}

0 commit comments

Comments
 (0)