/*
* Copyright (C) 2014 SCVNGR, Inc. d/b/a LevelUp
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.scvngr.levelup.core.service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.test.suitebuilder.annotation.SmallTest;
import com.scvngr.levelup.core.net.AbstractRequest;
import com.scvngr.levelup.core.net.AbstractRequest.BadRequestException;
import com.scvngr.levelup.core.net.HttpMethod;
import com.scvngr.levelup.core.net.LevelUpConnection;
import com.scvngr.levelup.core.net.LevelUpConnectionHelper;
import com.scvngr.levelup.core.net.LevelUpRequest;
import com.scvngr.levelup.core.net.LevelUpResponse;
import com.scvngr.levelup.core.net.LevelUpStatus;
import com.scvngr.levelup.core.test.SupportAndroidTestCase;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Tests {@link com.scvngr.levelup.core.service.AbstractNetworkRequestService}.
*/
public final class AbstractNetworkRequestServiceTest extends SupportAndroidTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
// Clear anything in the LocalBroadcastManager's queue.
LocalBroadcastManager.getInstance(getContext()).sendBroadcastSync(new Intent());
}
/**
* Tests {@link com.scvngr.levelup.core.service.AbstractNetworkRequestServiceTest.NetworkRequestServiceUnderTest#performRequest(android.content.Context, android.content.Intent)}
* with no request passed.
*/
@SmallTest
public void testSendRequest_withNullRequest() {
final Intent intent = new Intent(getContext(), NetworkRequestServiceUnderTest.class);
/**
* This test passes if no error is thrown. Errors could be thrown if: A Network connection
* occurs (see LevelUpConnection#setNetworkEnabled(boolean)). Or the service tries
* an operation on a null request.
*/
final NetworkRequestServiceUnderTest service = new NetworkRequestServiceUnderTest();
service.performRequest(getContext(), intent);
}
/**
* Tests {@link com.scvngr.levelup.core.service.AbstractNetworkRequestServiceTest.NetworkRequestServiceUnderTest#performRequest(android.content.Context, android.content.Intent)} with a valid
* request passed.
*
* @throws InterruptedException on interruption
* @throws com.scvngr.levelup.core.net.AbstractRequest.BadRequestException on a bad request
*/
@SmallTest
public void testSendRequest_withValidRequest() throws InterruptedException, BadRequestException {
final Context context = getContext();
final String token = AbstractNetworkRequestService.getToken();
final TestReceiver receiver =
new TestReceiver(new LevelUpResponse("", LevelUpStatus.OK), false, token);
LocalBroadcastManager.getInstance(getContext()).registerReceiver(receiver,
new IntentFilter(AbstractNetworkRequestService.ACTION_REQUEST_FINISHED));
try {
final LevelUpRequest requestToSend =
new LevelUpRequest(getContext(), HttpMethod.GET,
LevelUpRequest.API_VERSION_CODE_V14, "test", null,
null);
final Intent intent = new Intent(context, NetworkRequestServiceUnderTest.class);
intent.putExtra(NetworkRequestServiceUnderTest.EXTRA_PARCELABLE_REQUEST, requestToSend);
intent.putExtra(NetworkRequestServiceUnderTest.EXTRA_STRING_TOKEN, token);
final LevelUpConnection connection =
LevelUpConnectionHelper.setNextResponse(context, "", LevelUpStatus.OK);
final NetworkRequestServiceUnderTest service = new NetworkRequestServiceUnderTest();
service.performRequest(context, intent);
final AbstractRequest requestSent =
LevelUpConnectionHelper.getLastRequest(
requestToSend.getUrl(getContext()).toString(), connection);
assertNotNull(requestSent);
assertEquals(requestToSend, requestSent);
// Make sure Handle response was called.
assertTrue(service.latch.await(2, TimeUnit.SECONDS));
// Make sure onRequestFinished was called with the proper data.
assertTrue(receiver.latch.await(2, TimeUnit.SECONDS));
} finally {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(receiver);
}
}
/**
* Tests {@link com.scvngr.levelup.core.service.AbstractNetworkRequestService#getRequest(android.content.Intent)}.
*/
@SmallTest
public void testGetRequest() {
final NetworkRequestServiceUnderTest service = new NetworkRequestServiceUnderTest();
{
final Intent intent = new Intent();
assertNull(service.getRequest(intent));
}
{
final Intent intent = new Intent();
final LevelUpRequest request =
new LevelUpRequest(getContext(), HttpMethod.GET,
LevelUpRequest.API_VERSION_CODE_V14, "test", null,
null);
intent.putExtra(AbstractNetworkRequestService.EXTRA_PARCELABLE_REQUEST, request);
assertEquals(request, service.getRequest(intent));
}
}
/**
* Tests {@link com.scvngr.levelup.core.service.AbstractNetworkRequestService#getToken()}. NOTE: this test is obviously not
* perfect, but it serves as a small smoke test to make sure that we appear to be generating
* unique tokens.
*/
@SmallTest
public void testGetToken() {
final int tokenCount = 100;
final ArrayList<String> tokens = new ArrayList<String>(tokenCount);
for (int i = 0; i < tokenCount; i++) {
final String token = AbstractNetworkRequestService.getToken();
if (tokens.contains(token)) {
fail("duplicate token created");
}
tokens.add(token);
}
}
/**
* Tests
* {@link com.scvngr.levelup.core.service.AbstractNetworkRequestService#onRequestFinished(android.content.Context, android.content.Intent, com.scvngr.levelup.core.net.LevelUpResponse, boolean)}
* .
*
* @throws InterruptedException on interruption
*/
@SmallTest
public void testOnRequestFinished() throws InterruptedException {
final Context context = getContext();
final String token = AbstractNetworkRequestService.getToken();
final LevelUpResponse response =
new LevelUpResponse("testing this", LevelUpStatus.ERROR_SERVER);
final TestReceiver receiver = new TestReceiver(response, true, token);
LocalBroadcastManager.getInstance(getContext()).registerReceiver(receiver,
new IntentFilter(AbstractNetworkRequestService.ACTION_REQUEST_FINISHED));
try {
final Intent intent = new Intent();
intent.putExtra(AbstractNetworkRequestService.EXTRA_STRING_TOKEN, token);
AbstractNetworkRequestService.onRequestFinished(context, intent, response, true);
assertTrue(receiver.latch.await(2, TimeUnit.SECONDS));
} finally {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(receiver);
}
}
/**
* Tests
* {@link com.scvngr.levelup.core.service.AbstractNetworkRequestService#onRequestFinished(android.content.Context, android.content.Intent, com.scvngr.levelup.core.net.LevelUpResponse, boolean)}
* .
*
* @throws InterruptedException on interruption
*/
@SmallTest
public void testOnRequestFinished_nullToken() throws InterruptedException {
final Context context = getContext();
final LevelUpResponse response =
new LevelUpResponse("testing this", LevelUpStatus.ERROR_SERVER);
final TestReceiver receiver = new TestReceiver(response, true, null);
LocalBroadcastManager.getInstance(getContext()).registerReceiver(receiver,
new IntentFilter(AbstractNetworkRequestService.ACTION_REQUEST_FINISHED));
try {
final Intent intent = new Intent();
AbstractNetworkRequestService.onRequestFinished(context, intent, response, true);
assertTrue(receiver.latch.await(2, TimeUnit.SECONDS));
} finally {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(receiver);
}
}
/**
* A concrete implementation of {@link com.scvngr.levelup.core.service.AbstractNetworkRequestService} which counts calls to
* {@link #handleResponse(android.content.Context, com.scvngr.levelup.core.net.LevelUpResponse)}.
*/
private static final class NetworkRequestServiceUnderTest extends AbstractNetworkRequestService {
final CountDownLatch latch = new CountDownLatch(1);
@Override
protected boolean handleResponse(@NonNull final Context context,
@NonNull final LevelUpResponse response) {
latch.countDown();
return false;
}
}
/**
* BroadcastRecevier for handling broadcasts from the service.
*/
private final class TestReceiver extends BroadcastReceiver {
final CountDownLatch latch = new CountDownLatch(1);
final LevelUpResponse expectedResponse;
final boolean expectedStatus;
final String expectedToken;
private TestReceiver(final LevelUpResponse response, final boolean status,
final String token) {
expectedResponse = response;
expectedStatus = status;
expectedToken = token;
}
@Override
public void onReceive(final Context context, final Intent intent) {
assertEquals(AbstractNetworkRequestService.ACTION_REQUEST_FINISHED, intent.getAction());
assertTrue(intent.hasExtra(AbstractNetworkRequestService.EXTRA_PARCELABLE_RESPONSE));
final LevelUpResponse response =
intent.getParcelableExtra(AbstractNetworkRequestService.EXTRA_PARCELABLE_RESPONSE);
assertEquals(expectedResponse, response);
assertEquals(expectedStatus, intent.getBooleanExtra(
AbstractNetworkRequestService.EXTRA_BOOLEAN_IS_REQUEST_SUCCESSFUL,
!expectedStatus));
assertEquals(expectedToken,
intent.getStringExtra(AbstractNetworkRequestService.EXTRA_STRING_TOKEN));
latch.countDown();
}
}
}