com.parse.ParsePushControllerTest.java Source code

Java tutorial

Introduction

Here is the source code for com.parse.ParsePushControllerTest.java

Source

/*
 * 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.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import org.skyscreamer.jsonassert.JSONCompareMode;

import java.io.ByteArrayInputStream;
import java.io.IOException;
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(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class ParsePushControllerTest {

    //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_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_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 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_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_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_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_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_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;
    }
}