/*
* 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.net;
import android.content.Context;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.format.DateUtils;
import java.util.List;
import java.util.Map;
/**
* Helper to increase visibility to {@link LevelUpConnection} test-only methods.
*/
public final class LevelUpConnectionHelper {
/**
* The amount of milliseconds to sleep between loop iterations in
* {@link #waitForRequest}.
*/
private static final int WAIT_SLEEP_MILLIS = 20;
/**
* The default time to wait for a request.
*/
public static final long DEFAULT_WAIT_MILLIS = 4 * DateUtils.SECOND_IN_MILLIS;
/**
* Creates a new {@link LevelUpResponse} with the data and the {@link LevelUpStatus} passed and
* sets it as the next response that {@link LevelUpConnection#send(AbstractRequest)} will
* return.
*
* @param context Application context.
* @param data the data that the request should return.
* @param status the {@link LevelUpStatus} to return in the response.
* @return the {@link LevelUpConnection} that has the response set on it.
*/
@NonNull
public static LevelUpConnection setNextResponse(@NonNull final Context context,
@NonNull final String data, @NonNull final LevelUpStatus status) {
final LevelUpConnection connection = getTestLevelUpConnection(context);
connection.setNextResponse(null, new LevelUpResponse(data, status));
return connection;
}
/**
* Creates a new {@link LevelUpResponse} with the data and the {@link LevelUpStatus} passed and
* sets it as the next response that {@link LevelUpConnection#send(AbstractRequest)} will
* return.
*
* @param context Application context.
* @param data the data that the request should return.
* @param status the {@link LevelUpStatus} to return in the response.
* @param headers optional HTTP headers.
* @return the {@link LevelUpConnection} that has the response set on it.
*/
@NonNull
public static LevelUpConnection setNextResponse(@NonNull final Context context,
@NonNull final String data, @NonNull final LevelUpStatus status,
@Nullable final Map<String, List<String>> headers) {
final LevelUpConnection connection = getTestLevelUpConnection(context);
connection.setNextResponse(null, new LevelUpResponse(data, status, headers, null));
return connection;
}
/**
* Creates a new {@link LevelUpResponse} with the data and the {@link LevelUpStatus} passed and
* sets it as the next response that {@link LevelUpConnection#send(AbstractRequest)} will
* return.
*
* @param context Application context.
* @param requestUrl the URL that the response should be for.
* @param data the data that the request should return.
* @param status the {@link LevelUpStatus} to return in the response.
* @param headers optional HTTP headers.
* @return the {@link LevelUpConnection} that has the response set on it.
*/
@NonNull
public static LevelUpConnection setNextResponse(@NonNull final Context context,
@NonNull final String requestUrl, @NonNull final String data,
@NonNull final LevelUpStatus status, @Nullable final Map<String, List<String>> headers) {
final LevelUpConnection connection = getTestLevelUpConnection(context);
connection.setNextResponse(requestUrl, new LevelUpResponse(data, status, headers, null));
return connection;
}
/**
* Creates a new {@link LevelUpResponse} with the data and the {@link LevelUpStatus} passed and
* sets it as the next response that {@link LevelUpConnection#send(AbstractRequest)} will
* return.
*
* @param context Application context.
* @param requestUrl the URL that the response should be for.
* @param data the data that the request should return.
* @param statusCode the HTTP status code to return in the response.
* @param headers optional HTTP headers.
* @return the {@link LevelUpConnection} that has the response set on it.
*/
@NonNull
public static LevelUpConnection setNextResponse(@NonNull final Context context,
@NonNull final String requestUrl, @NonNull final String data, final int statusCode,
@Nullable final Map<String, List<String>> headers) {
final LevelUpConnection connection = getTestLevelUpConnection(context);
connection
.setNextResponse(requestUrl, new LevelUpResponse(data, statusCode, headers, null));
return connection;
}
/**
* Creates a new {@link LevelUpResponse} with the data and the {@link LevelUpStatus} passed and
* sets it as the next response that {@link LevelUpConnection#send(AbstractRequest)} will
* return.
*
* @param context Application context.
* @param data the data that the request should return.
* @param statusCode the HTTP status code to return in the response.
* @param headers optional HTTP headers.
* @return the {@link LevelUpConnection} that has the response set on it.
*/
@NonNull
public static LevelUpConnection setNextResponse(@NonNull final Context context,
@NonNull final String data, final int statusCode,
@Nullable final Map<String, List<String>> headers) {
final LevelUpConnection connection = getTestLevelUpConnection(context);
connection.setNextResponse(null, new LevelUpResponse(data, statusCode, headers, null));
return connection;
}
/**
* Creates a new {@link LevelUpResponse} with the data and the {@link LevelUpStatus} passed and
* sets it as the next response that {@link LevelUpConnection#send(AbstractRequest)} will return
* for the URL passed. If URL is null, the response will be returned regardless of the requested
* URL.
*
* @param context Application context.
* @param url the URL that this response should be returned for (null sets the response for any
* request).
* @param data the data that the request should return.
* @param status the {@link LevelUpStatus} to return in the response.
* @return the {@link LevelUpConnection} that has the response set on it.
*/
@NonNull
public static LevelUpConnection setNextResponse(@NonNull final Context context,
@Nullable final String url, @NonNull final String data,
@NonNull final LevelUpStatus status) {
final LevelUpConnection connection = getTestLevelUpConnection(context);
connection.setNextResponse(url, new LevelUpResponse(data, status));
return connection;
}
/**
* Adds a new {@link LevelUpResponse} with the data and the {@link LevelUpStatus} passed and
* sets it as the next response that {@link LevelUpConnection#send(AbstractRequest)} will for
* the URL string passed.
*
* @param connection the {@link LevelUpConnection} to add the response to.
* @param url the full URL to use.
* @param data the data that the request should return.
* @param status the {@link LevelUpStatus} to return in the response.
* @param headers HTTP headers.
* @return the {@link LevelUpConnection} that has the response set on it.
*/
@NonNull
public static LevelUpConnection addResponse(@NonNull final LevelUpConnection connection,
@Nullable final String url, @NonNull final String data,
@NonNull final LevelUpStatus status, @NonNull final Map<String, List<String>> headers) {
connection.setNextResponse(url, new LevelUpResponse(data, status, headers, null));
return connection;
}
/**
* Adds a new {@link LevelUpResponse} with the data and the {@link LevelUpStatus} passed and
* sets it as the next response that {@link LevelUpConnection#send(AbstractRequest)} will for
* the URL string passed.
*
* @param connection the {@link LevelUpConnection} to add the response to.
* @param url the full URL to use.
* @param data the data that the request should return.
* @param status the {@link LevelUpStatus} to return in the response.
* @return the {@link LevelUpConnection} that has the response set on it.
*/
@NonNull
public static LevelUpConnection addResponse(@NonNull final LevelUpConnection connection,
@Nullable final String url, @NonNull final String data,
@NonNull final LevelUpStatus status) {
connection.setNextResponse(url, new LevelUpResponse(data, status));
return connection;
}
/**
* @param requestUrl the URL of the expected request.
* @param connection An instance of {@link LevelUpConnection} returned by
* {@link #setNextResponse(Context, String, LevelUpStatus)}.
* @return the last request made for the URL passed.
*/
@Nullable
public static AbstractRequest getLastRequest(@NonNull final String requestUrl,
@NonNull final LevelUpConnection connection) {
return connection.getLastRequest(requestUrl);
}
/**
* @param connection An instance of {@link LevelUpConnection} returned by
* {@link #setNextResponse(Context, String, LevelUpStatus)}.
* @return the last request made for the connection passed.
*/
@Nullable
public static AbstractRequest getLastRequest(@NonNull final LevelUpConnection connection) {
return connection.getLastRequest(null);
}
/**
* Clears the last request for the URL passed.
*
* @param connection An instance of {@link LevelUpConnection} returned by
* {@link #setNextResponse(Context, String, LevelUpStatus)}.
* @param url the URL of the request to remove from the map.
*/
public static void clearLastRequest(@NonNull final LevelUpConnection connection,
@NonNull final String url) {
connection.setLastRequest(url, null);
}
/**
* Set the next {@link LevelUpConnection} instance that will be used by clients and return it so
* it can be modified.
*
* @param context Application context
* @return the instance of {@link LevelUpConnection} that was set as the next instance
*/
@NonNull
private static LevelUpConnection getTestLevelUpConnection(@NonNull final Context context) {
final LevelUpConnection connection = new LevelUpConnection(context);
LevelUpConnection.setNextInstance(connection);
return connection;
}
/**
* Sets if network connections are enabled for the {@link LevelUpConnection} instance passed.
*
* @param enabled if true, network is enabled. If false, network connections that do not have
* pre-created responses will throw a {@link RuntimeException}.
*/
public static void setNetworkEnabled(final boolean enabled) {
LevelUpConnection.setNetworkEnabled(enabled);
}
/**
* Waits for a request to be enqueued to the {@link LevelUpConnection} passed.
*
* @param requestUrl the URL of the request to wait for or null to wait for any request.
* @param connection the {@link LevelUpConnection} instance to monitor for requests.
* @param waitMillis the time in milliseconds to wait for the request.
* @return true if a request was detected, false of timeout occurred.
*/
public static boolean waitForRequest(@Nullable final String requestUrl,
@NonNull final LevelUpConnection connection, final long waitMillis) {
final long endTime = SystemClock.elapsedRealtime() + (waitMillis);
boolean result = true;
while (true) {
if (null != connection.getLastRequest(requestUrl)) {
break;
}
if (SystemClock.elapsedRealtime() >= endTime) {
result = false;
break;
}
SystemClock.sleep(WAIT_SLEEP_MILLIS);
}
return result;
}
/**
* Waits for a request to be enqueued to the {@link LevelUpConnection} passed. Waits
* {@link #DEFAULT_WAIT_MILLIS} for the request, if you need a different timeout length, use
* {@link #waitForRequest(String, LevelUpConnection, long)}. Waits for a request for the URL
* specified.
*
* @param requestUrl the URL of the request to wait for or null to wait for any request.
* @param connection the {@link LevelUpConnection} instance to monitor for requests.
* @return true if a request was detected, false of timeout occurred.
*/
public static boolean waitForRequest(@Nullable final String requestUrl,
@NonNull final LevelUpConnection connection) {
return waitForRequest(requestUrl, connection, DEFAULT_WAIT_MILLIS);
}
/**
* Clear the cached instance of {@link LevelUpConnection}.
*/
public static void clearInstance() {
LevelUpConnection.setNextInstance(null);
}
/**
* Private constructor to prevent instantiation.
*/
private LevelUpConnectionHelper() {
throw new UnsupportedOperationException("This class is non-instantiable.");
}
}