ParseApplication/ExternalLibs/Parse-SDK-Android/Parse/src/test/java/com/parse/ParsePushControllerTest.java

394 lines
16 KiB
Java

/*
* Copyright (c) 2015-present, Parse, LLC.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.parse;
import com.parse.http.ParseHttpRequest;
import com.parse.http.ParseHttpResponse;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.skyscreamer.jsonassert.JSONCompareMode;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import bolts.Task;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.skyscreamer.jsonassert.JSONAssert.assertEquals;
// For SSLSessionCache
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION)
public class ParsePushControllerTest {
@Before
public void setUp() throws MalformedURLException {
ParseRESTCommand.server = new URL("https://api.parse.com/1");
}
@After
public void tearDown() {
ParseRESTCommand.server = null;
}
//region testBuildRESTSendPushCommand
@Test
public void testBuildRESTSendPushCommandWithChannelSet() throws Exception {
ParseHttpClient restClient = mock(ParseHttpClient.class);
ParsePushController controller = new ParsePushController(restClient);
// Build PushState
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
List<String> expectedChannelSet = new ArrayList<String>(){{
add("foo");
add("bar");
add("yarr");
}};
ParsePush.State state = new ParsePush.State.Builder()
.data(data)
.channelSet(expectedChannelSet)
.build();
// Build command
ParseRESTCommand pushCommand = controller.buildRESTSendPushCommand(state, "sessionToken");
// Verify command
JSONObject jsonParameters = pushCommand.jsonParameters;
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_PUSH_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_INTERVAL));
// Verify device type and query
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_WHERE));
assertEquals("hello world",
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_DATA)
.getString(ParsePush.KEY_DATA_MESSAGE));
JSONArray pushChannels = jsonParameters.getJSONArray(ParseRESTPushCommand.KEY_CHANNELS);
assertEquals(new JSONArray(expectedChannelSet), pushChannels,
JSONCompareMode.NON_EXTENSIBLE);
}
@Test
public void testBuildRESTSendPushCommandWithExpirationTime() throws Exception {
ParseHttpClient restClient = mock(ParseHttpClient.class);
ParsePushController controller = new ParsePushController(restClient);
// Build PushState
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
ParsePush.State state = new ParsePush.State.Builder()
.data(data)
.expirationTime((long) 1400000000)
.build();
// Build command
ParseRESTCommand pushCommand = controller.buildRESTSendPushCommand(state, "sessionToken");
// Verify command
JSONObject jsonParameters = pushCommand.jsonParameters;
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_PUSH_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_INTERVAL));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_CHANNELS));
// Verify device type and query
assertEquals("{}", jsonParameters.get(ParseRESTPushCommand.KEY_WHERE).toString());
assertEquals("hello world",
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_DATA)
.getString(ParsePush.KEY_DATA_MESSAGE));
assertEquals(1400000000, jsonParameters.getLong(ParseRESTPushCommand.KEY_EXPIRATION_TIME));
}
@Test
public void testBuildRESTSendPushCommandWithPushTime() throws Exception {
ParseHttpClient restClient = mock(ParseHttpClient.class);
ParsePushController controller = new ParsePushController(restClient);
// Build PushState
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
long pushTime = System.currentTimeMillis() / 1000 + 1000;
ParsePush.State state = new ParsePush.State.Builder()
.data(data)
.pushTime(pushTime)
.build();
// Build command
ParseRESTCommand pushCommand = controller.buildRESTSendPushCommand(state, "sessionToken");
// Verify command
JSONObject jsonParameters = pushCommand.jsonParameters;
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_INTERVAL));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_CHANNELS));
// Verify device type and query
assertEquals("{}", jsonParameters.get(ParseRESTPushCommand.KEY_WHERE).toString());
assertEquals("hello world",
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_DATA)
.getString(ParsePush.KEY_DATA_MESSAGE));
assertEquals(pushTime, jsonParameters.getLong(ParseRESTPushCommand.KEY_PUSH_TIME));
}
@Test
public void testBuildRESTSendPushCommandWithExpirationTimeInterval() throws Exception {
ParseHttpClient restClient = mock(ParseHttpClient.class);
ParsePushController controller = new ParsePushController(restClient);
// Build PushState
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
ParsePush.State state = new ParsePush.State.Builder()
.data(data)
.expirationTimeInterval((long) 86400)
.build();
// Build command
ParseRESTCommand pushCommand = controller.buildRESTSendPushCommand(state, "sessionToken");
// Verify command
JSONObject jsonParameters = pushCommand.jsonParameters;
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_PUSH_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_CHANNELS));
// Verify device type and query
assertEquals("{}", jsonParameters.get(ParseRESTPushCommand.KEY_WHERE).toString());
assertEquals("hello world",
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_DATA)
.getString(ParsePush.KEY_DATA_MESSAGE));
assertEquals(86400, jsonParameters.getLong(ParseRESTPushCommand.KEY_EXPIRATION_INTERVAL));
}
@Test
public void testBuildRESTSendPushCommandWithQuery() throws Exception {
ParseHttpClient restClient = mock(ParseHttpClient.class);
ParsePushController controller = new ParsePushController(restClient);
// Build PushState
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
ParseQuery<ParseInstallation> query = ParseInstallation.getQuery();
query.whereEqualTo("language", "en/US");
query.whereLessThan("version", "1.2");
ParsePush.State state = new ParsePush.State.Builder()
.data(data)
.query(query)
.build();
// Build command
ParseRESTCommand pushCommand = controller.buildRESTSendPushCommand(state, "sessionToken");
// Verify command
JSONObject jsonParameters = pushCommand.jsonParameters;
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_PUSH_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_INTERVAL));
assertFalse(jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_WHERE)
.has(ParseRESTPushCommand.KEY_DEVICE_TYPE));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_CHANNELS));
assertEquals("hello world",
jsonParameters
.getJSONObject(ParseRESTPushCommand.KEY_DATA)
.getString(ParsePush.KEY_DATA_MESSAGE));
JSONObject pushQuery = jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_WHERE);
assertEquals("en/US", pushQuery.getString("language"));
JSONObject inequality = pushQuery.getJSONObject("version");
assertEquals("1.2", inequality.getString("$lt"));
}
@Test
public void testBuildRESTSendPushCommandWithPushToAndroid() throws Exception {
ParseHttpClient restClient = mock(ParseHttpClient.class);
ParsePushController controller = new ParsePushController(restClient);
// Build PushState
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
ParsePush.State state = new ParsePush.State.Builder()
.pushToAndroid(true)
.data(data)
.build();
// Build command
ParseRESTCommand pushCommand = controller.buildRESTSendPushCommand(state, "sessionToken");
// Verify command
JSONObject jsonParameters = pushCommand.jsonParameters;
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_PUSH_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_INTERVAL));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_CHANNELS));
assertEquals("hello world",
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_DATA)
.getString(ParsePush.KEY_DATA_MESSAGE));
assertEquals(ParsePushController.DEVICE_TYPE_ANDROID,
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_WHERE)
.optString(ParseRESTPushCommand.KEY_DEVICE_TYPE, null));
}
@Test
public void testBuildRESTSendPushCommandWithPushToIOS() throws Exception {
ParseHttpClient restClient = mock(ParseHttpClient.class);
ParsePushController controller = new ParsePushController(restClient);
// Build PushState
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
ParsePush.State state = new ParsePush.State.Builder()
.pushToIOS(true)
.data(data)
.build();
// Build command
ParseRESTCommand pushCommand = controller.buildRESTSendPushCommand(state, "sessionToken");
// Verify command
JSONObject jsonParameters = pushCommand.jsonParameters;
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_PUSH_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_INTERVAL));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_CHANNELS));
assertEquals("hello world",
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_DATA)
.getString(ParsePush.KEY_DATA_MESSAGE));
assertEquals(ParsePushController.DEVICE_TYPE_IOS,
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_WHERE)
.optString(ParseRESTPushCommand.KEY_DEVICE_TYPE, null));
}
@Test
public void testBuildRESTSendPushCommandWithPushToIOSAndAndroid() throws Exception {
ParseHttpClient restClient = mock(ParseHttpClient.class);
ParsePushController controller = new ParsePushController(restClient);
// Build PushState
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
ParsePush.State state = new ParsePush.State.Builder()
.pushToAndroid(true)
.pushToIOS(true)
.data(data)
.build();
// Build command
ParseRESTCommand pushCommand = controller.buildRESTSendPushCommand(state, "sessionToken");
// Verify command
JSONObject jsonParameters = pushCommand.jsonParameters;
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_PUSH_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_TIME));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_EXPIRATION_INTERVAL));
assertFalse(jsonParameters.has(ParseRESTPushCommand.KEY_CHANNELS));
assertEquals("hello world",
jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_DATA)
.getString(ParsePush.KEY_DATA_MESSAGE));
assertFalse(jsonParameters.getJSONObject(ParseRESTPushCommand.KEY_WHERE)
.has(ParseRESTPushCommand.KEY_DEVICE_TYPE));
}
//endregion
//region testSendInBackground
@Test
public void testSendInBackgroundSuccess() throws Exception {
JSONObject mockResponse = new JSONObject();
mockResponse.put("result", "OK");
ParseHttpClient restClient = mockParseHttpClientWithResponse(mockResponse, 200, "OK");
ParsePushController controller = new ParsePushController(restClient);
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
ParsePush.State state = new ParsePush.State.Builder()
.data(data)
.build();
Task<Void> pushTask= controller.sendInBackground(state, "sessionToken");
// Verify task complete
ParseTaskUtils.wait(pushTask);
// Verify httpclient execute encough times
verify(restClient, times(1)).execute(any(ParseHttpRequest.class));
}
@Test
public void testSendInBackgroundFailWithIOException() throws Exception {
// TODO(mengyan): Remove once we no longer rely on retry logic.
ParseRequest.setDefaultInitialRetryDelay(1L);
ParseHttpClient restClient = mock(ParseHttpClient.class);
when(restClient.execute(any(ParseHttpRequest.class))).thenThrow(new IOException());
ParsePushController controller = new ParsePushController(restClient);
JSONObject data = new JSONObject();
data.put(ParsePush.KEY_DATA_MESSAGE, "hello world");
ParsePush.State state = new ParsePush.State.Builder()
.data(data)
.build();
Task<Void> pushTask= controller.sendInBackground(state, "sessionToken");
// Do not use ParseTaskUtils.wait() since we do not want to throw the exception
pushTask.waitForCompletion();
// Verify httpClient is tried enough times
// TODO(mengyan): Abstract out command runner so we don't have to account for retries.
verify(restClient, times(5)).execute(any(ParseHttpRequest.class));
assertTrue(pushTask.isFaulted());
Exception error = pushTask.getError();
assertThat(error, instanceOf(ParseException.class));
assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) error).getCode());
}
//endregion
private ParseHttpClient mockParseHttpClientWithResponse(JSONObject content, int statusCode,
String reasonPhrase) throws IOException {
byte[] contentBytes = content.toString().getBytes();
ParseHttpResponse response = new ParseHttpResponse.Builder()
.setContent(new ByteArrayInputStream(contentBytes))
.setStatusCode(statusCode)
.setTotalSize(contentBytes.length)
.setContentType("application/json")
.build();
ParseHttpClient client = mock(ParseHttpClient.class);
when(client.execute(any(ParseHttpRequest.class))).thenReturn(response);
return client;
}
private static boolean containsString(JSONArray array, String value) throws JSONException {
for (int i = 0; i < array.length(); i++) {
Object element = array.get(i);
if (element instanceof String && element.equals(value)) {
return true;
}
}
return false;
}
}