Commit 17901b95 authored by Caleb Raitto's avatar Caleb Raitto Committed by Commit Bot

Implement request body in FakeUrlRequest

Create FakeDataSink class to retrieve request body from
UploadDataProvider. Add request body byte array as a parameter to
ResponseMatcher.getResponse(). Added ResponseMatchers should
verify the body of the request if that is necessary for the test
before responding.

Patched from original CL: crrev.com/c/1742515 (kirchman@'s internship
ended).

Bug: 669707
Change-Id: I3be8a95e80e82cf74edd7bd5e23e5adf2e5e04cf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1784978
Commit-Queue: Paul Jensen <pauljensen@chromium.org>
Reviewed-by: default avatarPaul Jensen <pauljensen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#699875}
parent 6572a39c
...@@ -925,6 +925,7 @@ if (!is_component_build) { ...@@ -925,6 +925,7 @@ if (!is_component_build) {
android_library("cronet_common_javatests") { android_library("cronet_common_javatests") {
testonly = true testonly = true
java_files = [ java_files = [
"test/javatests/src/org/chromium/net/TestUploadDataProvider.java",
"test/javatests/src/org/chromium/net/TestUrlRequestCallback.java", "test/javatests/src/org/chromium/net/TestUrlRequestCallback.java",
"test/javatests/src/org/chromium/net/CronetTestRule.java", "test/javatests/src/org/chromium/net/CronetTestRule.java",
] ]
...@@ -1005,7 +1006,6 @@ if (!is_component_build) { ...@@ -1005,7 +1006,6 @@ if (!is_component_build) {
"test/javatests/src/org/chromium/net/TestDrivenDataProvider.java", "test/javatests/src/org/chromium/net/TestDrivenDataProvider.java",
"test/javatests/src/org/chromium/net/TestNetworkQualityRttListener.java", "test/javatests/src/org/chromium/net/TestNetworkQualityRttListener.java",
"test/javatests/src/org/chromium/net/TestNetworkQualityThroughputListener.java", "test/javatests/src/org/chromium/net/TestNetworkQualityThroughputListener.java",
"test/javatests/src/org/chromium/net/TestUploadDataProvider.java",
"test/javatests/src/org/chromium/net/UploadDataProvidersTest.java", "test/javatests/src/org/chromium/net/UploadDataProvidersTest.java",
"test/javatests/src/org/chromium/net/urlconnection/CronetBufferedOutputStreamTest.java", "test/javatests/src/org/chromium/net/urlconnection/CronetBufferedOutputStreamTest.java",
"test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java", "test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java",
......
...@@ -178,14 +178,15 @@ public final class FakeCronetController { ...@@ -178,14 +178,15 @@ public final class FakeCronetController {
* @param url the URL that the {@link UrlRequest} is connecting to * @param url the URL that the {@link UrlRequest} is connecting to
* @param httpMethod the HTTP method that the {@link UrlRequest} is using to connect with * @param httpMethod the HTTP method that the {@link UrlRequest} is using to connect with
* @param headers the headers supplied by the {@link UrlRequest} * @param headers the headers supplied by the {@link UrlRequest}
* @param body the body of the fake HTTP request
* @return a {@link FakeUrlResponse} if there is one, or a failed "404" response if none found * @return a {@link FakeUrlResponse} if there is one, or a failed "404" response if none found
*/ */
FakeUrlResponse getResponse( FakeUrlResponse getResponse(
String url, String httpMethod, List<Map.Entry<String, String>> headers) { String url, String httpMethod, List<Map.Entry<String, String>> headers, byte[] body) {
synchronized (mResponseMatchers) { synchronized (mResponseMatchers) {
for (ResponseMatcher responseMatcher : mResponseMatchers) { for (ResponseMatcher responseMatcher : mResponseMatchers) {
FakeUrlResponse matchedResponse = FakeUrlResponse matchedResponse =
responseMatcher.getMatchingResponse(url, httpMethod, headers); responseMatcher.getMatchingResponse(url, httpMethod, headers, body);
if (matchedResponse != null) { if (matchedResponse != null) {
return matchedResponse; return matchedResponse;
} }
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
package org.chromium.net.test; package org.chromium.net.test;
import android.util.Log;
import androidx.annotation.GuardedBy; import androidx.annotation.GuardedBy;
import androidx.annotation.VisibleForTesting;
import org.chromium.net.CronetException; import org.chromium.net.CronetException;
import org.chromium.net.InlineExecutionProhibitedException; import org.chromium.net.InlineExecutionProhibitedException;
...@@ -12,6 +15,8 @@ import org.chromium.net.UploadDataProvider; ...@@ -12,6 +15,8 @@ import org.chromium.net.UploadDataProvider;
import org.chromium.net.UrlResponseInfo; import org.chromium.net.UrlResponseInfo;
import org.chromium.net.impl.CallbackExceptionImpl; import org.chromium.net.impl.CallbackExceptionImpl;
import org.chromium.net.impl.CronetExceptionImpl; import org.chromium.net.impl.CronetExceptionImpl;
import org.chromium.net.impl.JavaUploadDataSinkBase;
import org.chromium.net.impl.JavaUrlRequestUtils;
import org.chromium.net.impl.JavaUrlRequestUtils.CheckedRunnable; import org.chromium.net.impl.JavaUrlRequestUtils.CheckedRunnable;
import org.chromium.net.impl.JavaUrlRequestUtils.DirectPreventingExecutor; import org.chromium.net.impl.JavaUrlRequestUtils.DirectPreventingExecutor;
import org.chromium.net.impl.JavaUrlRequestUtils.State; import org.chromium.net.impl.JavaUrlRequestUtils.State;
...@@ -19,6 +24,8 @@ import org.chromium.net.impl.Preconditions; ...@@ -19,6 +24,8 @@ import org.chromium.net.impl.Preconditions;
import org.chromium.net.impl.UrlRequestBase; import org.chromium.net.impl.UrlRequestBase;
import org.chromium.net.impl.UrlResponseInfoImpl; import org.chromium.net.impl.UrlResponseInfoImpl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.AbstractMap; import java.util.AbstractMap;
...@@ -28,12 +35,16 @@ import java.util.HashMap; ...@@ -28,12 +35,16 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
/** /**
* Fake UrlRequest that retrieves responses from the associated FakeCronetController. Used for * Fake UrlRequest that retrieves responses from the associated FakeCronetController. Used for
* testing Cronet usage on Android. * testing Cronet usage on Android.
*/ */
final class FakeUrlRequest extends UrlRequestBase { final class FakeUrlRequest extends UrlRequestBase {
private static final int DEFAULT_UPLOAD_BUFFER_SIZE = 8192;
// Used for logging errors.
private static final String TAG = FakeUrlRequest.class.getSimpleName();
// Callback used to report responses to the client. // Callback used to report responses to the client.
private final Callback mCallback; private final Callback mCallback;
// The {@link Executor} provided by the user to be used for callbacks. // The {@link Executor} provided by the user to be used for callbacks.
...@@ -46,6 +57,8 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -46,6 +57,8 @@ final class FakeUrlRequest extends UrlRequestBase {
private final FakeCronetEngine mFakeCronetEngine; private final FakeCronetEngine mFakeCronetEngine;
// Source of thread safety for this class. // Source of thread safety for this class.
private final Object mLock = new Object(); private final Object mLock = new Object();
// True if direct execution is allowed for this request.
private final boolean mAllowDirectExecutor;
// The chain of URL's this request has received. // The chain of URL's this request has received.
@GuardedBy("mLock") @GuardedBy("mLock")
private final List<String> mUrlChain = new ArrayList<>(); private final List<String> mUrlChain = new ArrayList<>();
...@@ -58,6 +71,19 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -58,6 +71,19 @@ final class FakeUrlRequest extends UrlRequestBase {
// The {@link FakeUrlResponse} for the current URL. // The {@link FakeUrlResponse} for the current URL.
@GuardedBy("mLock") @GuardedBy("mLock")
private FakeUrlResponse mCurrentFakeResponse; private FakeUrlResponse mCurrentFakeResponse;
// The body of the request from UploadDataProvider.
@GuardedBy("mLock")
private byte[] mRequestBody;
// The {@link UploadDataProvider} to retrieve a request body from.
@GuardedBy("mLock")
private UploadDataProvider mUploadDataProvider;
// The executor to call the {@link UploadDataProvider}'s callback methods with.
@GuardedBy("mLock")
private Executor mUploadExecutor;
// The {@link UploadDataSink} for the {@link UploadDataProvider}.
@GuardedBy("mLock")
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
FakeDataSink mFakeDataSink;
// The {@link UrlResponseInfo} for the current request. // The {@link UrlResponseInfo} for the current request.
@GuardedBy("mLock") @GuardedBy("mLock")
private UrlResponseInfo mUrlResponseInfo; private UrlResponseInfo mUrlResponseInfo;
...@@ -66,7 +92,10 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -66,7 +92,10 @@ final class FakeUrlRequest extends UrlRequestBase {
private ByteBuffer mResponse; private ByteBuffer mResponse;
// The HTTP method used by this request to establish a connection. // The HTTP method used by this request to establish a connection.
@GuardedBy("mLock") @GuardedBy("mLock")
private String mHttpMethod = "GET"; private String mHttpMethod;
// True after the {@link UploadDataProvider} for this request has been closed.
@GuardedBy("mLock")
private boolean mUploadProviderClosed;
@GuardedBy("mLock") @GuardedBy("mLock")
@State @State
...@@ -84,7 +113,7 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -84,7 +113,7 @@ final class FakeUrlRequest extends UrlRequestBase {
/** /**
* Used to map from HTTP status codes to the corresponding human-readable text. * Used to map from HTTP status codes to the corresponding human-readable text.
*/ */
private final static Map<Integer, String> HTTP_STATUS_CODE_TO_TEXT; private static final Map<Integer, String> HTTP_STATUS_CODE_TO_TEXT;
static { static {
Map<Integer, String> httpCodeMap = new HashMap<>(); Map<Integer, String> httpCodeMap = new HashMap<>();
httpCodeMap.put(100, "Continue"); httpCodeMap.put(100, "Continue");
...@@ -172,13 +201,26 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -172,13 +201,26 @@ final class FakeUrlRequest extends UrlRequestBase {
mCurrentUrl = url; mCurrentUrl = url;
mFakeCronetController = fakeCronetController; mFakeCronetController = fakeCronetController;
mFakeCronetEngine = fakeCronetEngine; mFakeCronetEngine = fakeCronetEngine;
mAllowDirectExecutor = allowDirectExecutor;
} }
@Override @Override
public void setUploadDataProvider(UploadDataProvider uploadDataProvider, Executor executor) { public void setUploadDataProvider(UploadDataProvider uploadDataProvider, Executor executor) {
if (uploadDataProvider == null) {
throw new NullPointerException("Invalid UploadDataProvider.");
}
synchronized (mLock) { synchronized (mLock) {
if (!checkHasContentTypeHeader()) {
throw new IllegalArgumentException(
"Requests with upload data must have a Content-Type.");
}
checkNotStarted(); checkNotStarted();
// TODO(kirchman) Implement UploadDataProvider. if (mHttpMethod == null) {
mHttpMethod = "POST";
}
mUploadExecutor =
mAllowDirectExecutor ? executor : new DirectPreventingExecutor(executor);
mUploadDataProvider = uploadDataProvider;
} }
} }
...@@ -229,11 +271,17 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -229,11 +271,17 @@ final class FakeUrlRequest extends UrlRequestBase {
transitionedState = true; transitionedState = true;
} finally { } finally {
if (!transitionedState) { if (!transitionedState) {
mFakeCronetEngine.onRequestDestroyed(); cleanup();
} }
} }
mUrlChain.add(mCurrentUrl); mUrlChain.add(mCurrentUrl);
fakeConnect(); if (mUploadDataProvider != null) {
mFakeDataSink =
new FakeDataSink(mUploadExecutor, mExecutor, mUploadDataProvider);
mFakeDataSink.start(/* firstTime= */ true);
} else {
fakeConnect();
}
} else { } else {
throw new IllegalStateException("This request's CronetEngine is already shutdown."); throw new IllegalStateException("This request's CronetEngine is already shutdown.");
} }
...@@ -247,8 +295,8 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -247,8 +295,8 @@ final class FakeUrlRequest extends UrlRequestBase {
@GuardedBy("mLock") @GuardedBy("mLock")
private void fakeConnect() { private void fakeConnect() {
mAdditionalStatusDetails = Status.WAITING_FOR_RESPONSE; mAdditionalStatusDetails = Status.WAITING_FOR_RESPONSE;
mCurrentFakeResponse = mCurrentFakeResponse = mFakeCronetController.getResponse(
mFakeCronetController.getResponse(mCurrentUrl, mHttpMethod, mAllHeadersList); mCurrentUrl, mHttpMethod, mAllHeadersList, mRequestBody);
int responseCode = mCurrentFakeResponse.getHttpStatusCode(); int responseCode = mCurrentFakeResponse.getHttpStatusCode();
mUrlResponseInfo = new UrlResponseInfoImpl( mUrlResponseInfo = new UrlResponseInfoImpl(
Collections.unmodifiableList(new ArrayList<>(mUrlChain)), responseCode, Collections.unmodifiableList(new ArrayList<>(mUrlChain)), responseCode,
...@@ -261,6 +309,7 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -261,6 +309,7 @@ final class FakeUrlRequest extends UrlRequestBase {
if (responseCode >= 300 && responseCode < 400) { if (responseCode >= 300 && responseCode < 400) {
processRedirectResponse(); processRedirectResponse();
} else { } else {
closeUploadDataProvider();
final UrlResponseInfo info = mUrlResponseInfo; final UrlResponseInfo info = mUrlResponseInfo;
transitionStates(State.STARTED, State.AWAITING_READ); transitionStates(State.STARTED, State.AWAITING_READ);
executeCheckedRunnable(new CheckedRunnable() { executeCheckedRunnable(new CheckedRunnable() {
...@@ -373,7 +422,12 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -373,7 +422,12 @@ final class FakeUrlRequest extends UrlRequestBase {
public void followRedirect() { public void followRedirect() {
synchronized (mLock) { synchronized (mLock) {
transitionStates(State.AWAITING_FOLLOW_REDIRECT, State.STARTED); transitionStates(State.AWAITING_FOLLOW_REDIRECT, State.STARTED);
fakeConnect(); if (mFakeDataSink != null) {
mFakeDataSink = new FakeDataSink(mUploadExecutor, mExecutor, mUploadDataProvider);
mFakeDataSink.start(/* firstTime= */ false);
} else {
fakeConnect();
}
} }
} }
...@@ -395,7 +449,7 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -395,7 +449,7 @@ final class FakeUrlRequest extends UrlRequestBase {
@Override @Override
public void getStatus(final StatusListener listener) { public void getStatus(final StatusListener listener) {
synchronized (mLock) { synchronized (mLock) {
int extraStatus = this.mAdditionalStatusDetails; int extraStatus = mAdditionalStatusDetails;
@StatusValues @StatusValues
final int status; final int status;
...@@ -478,7 +532,7 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -478,7 +532,7 @@ final class FakeUrlRequest extends UrlRequestBase {
* *
* @param checkedRunnable the runnable to execute * @param checkedRunnable the runnable to execute
*/ */
private void executeCheckedRunnable(CheckedRunnable checkedRunnable) { private void executeCheckedRunnable(JavaUrlRequestUtils.CheckedRunnable checkedRunnable) {
try { try {
mUserExecutor.execute(new Runnable() { mUserExecutor.execute(new Runnable() {
@Override @Override
...@@ -493,7 +547,8 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -493,7 +547,8 @@ final class FakeUrlRequest extends UrlRequestBase {
}); });
} catch (InlineExecutionProhibitedException e) { } catch (InlineExecutionProhibitedException e) {
// Don't try to fail using the {@code mUserExecutor} because it produced this error. // Don't try to fail using the {@code mUserExecutor} because it produced this error.
tryToFailWithException(new CronetExceptionImpl("Direct executor not allowed", e)); tryToFailWithException(
new CronetExceptionImpl("Exception posting task to executor", e));
} }
} }
...@@ -517,10 +572,166 @@ final class FakeUrlRequest extends UrlRequestBase { ...@@ -517,10 +572,166 @@ final class FakeUrlRequest extends UrlRequestBase {
return false; // Already in a terminal state return false; // Already in a terminal state
default: { default: {
mState = terminalState; mState = terminalState;
mFakeCronetEngine.onRequestDestroyed(); cleanup();
return true;
}
}
}
@GuardedBy("mLock")
private void cleanup() {
closeUploadDataProvider();
mFakeCronetEngine.onRequestDestroyed();
}
/**
* Executed only once after the request has finished using the {@link UploadDataProvider}.
* Closes the {@link UploadDataProvider} if it exists and has not already been closed.
*/
@GuardedBy("mLock")
private void closeUploadDataProvider() {
if (mUploadDataProvider != null && !mUploadProviderClosed) {
try {
mUploadExecutor.execute(uploadErrorSetting(new CheckedRunnable() {
@Override
public void run() throws Exception {
synchronized (mLock) {
mUploadDataProvider.close();
mUploadProviderClosed = true;
}
}
}));
} catch (RejectedExecutionException e) {
Log.e(TAG, "Exception when closing uploadDataProvider", e);
}
}
}
/**
* Wraps a {@link CheckedRunnable} in a runnable that will attempt to fail the request if there
* is an exception.
*
* @param delegate the {@link CheckedRunnable} to try to run
* @return a {@link Runnable} that wraps the delegate runnable.
*/
private Runnable uploadErrorSetting(final CheckedRunnable delegate) {
return new Runnable() {
@Override
public void run() {
try {
delegate.run();
} catch (Throwable t) {
enterUploadErrorState(t);
}
}
};
}
/**
* Fails the request with an error. Called when uploading the request body using an
* {@link UploadDataProvider} fails.
*
* @param error the error that caused this request to fail which should be returned to the
* {@link UrlRequest.Callback}
*/
private void enterUploadErrorState(final Throwable error) {
synchronized (mLock) {
mUserExecutor.execute(new Runnable() {
@Override
public void run() {
tryToFailWithException(new CronetExceptionImpl(
"Exception received from UploadDataProvider", error));
}
});
}
}
/**
* Adapted from {@link JavaUrlRequest.OutputStreamDataSink}. Stores the received message in a
* {@link ByteArrayOutputStream} and transfers it to the {@code mRequestBody} when the response
* has been fully acquired.
*/
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
final class FakeDataSink extends JavaUploadDataSinkBase {
private final ByteArrayOutputStream mTotalUploadStream = new ByteArrayOutputStream();
FakeDataSink(final Executor userExecutor, Executor executor, UploadDataProvider provider) {
super(userExecutor, executor, provider);
}
@Override
public Runnable getErrorSettingRunnable(JavaUrlRequestUtils.CheckedRunnable runnable) {
return new Runnable() {
@Override
public void run() {
try {
runnable.run();
} catch (Throwable t) {
mUserExecutor.execute(new Runnable() {
@Override
public void run() {
tryToFailWithException(new CronetExceptionImpl("System error", t));
}
});
}
}
};
}
@Override
protected Runnable getUploadErrorSettingRunnable(
JavaUrlRequestUtils.CheckedRunnable runnable) {
return uploadErrorSetting(runnable);
}
@Override
protected void processUploadError(final Throwable error) {
enterUploadErrorState(error);
}
@Override
protected int processSuccessfulRead(ByteBuffer buffer) throws IOException {
mTotalUploadStream.write(buffer.array(), buffer.arrayOffset(), buffer.remaining());
return buffer.remaining();
}
/**
* Terminates the upload stage of the request. Writes the received bytes to the byte array:
* {@code mRequestBody}. Connects to the current URL for this request.
*/
@Override
protected void finish() throws IOException {
synchronized (mLock) {
mRequestBody = mTotalUploadStream.toByteArray();
fakeConnect();
}
}
@Override
protected void initializeRead() throws IOException {
// Nothing to do before every read in this implementation.
}
@Override
protected void initializeStart(long totalBytes) {
// Nothing to do to initialize the upload in this implementation.
}
}
/**
* Verifies that the "content-type" header is present. Must be checked before an
* {@link UploadDataProvider} is premitted to be set.
*
* @return true if the "content-type" header is present in the request headers.
*/
@GuardedBy("mLock")
private boolean checkHasContentTypeHeader() {
for (Map.Entry<String, String> entry : mAllHeadersList) {
if (entry.getKey().equalsIgnoreCase("content-type")) {
return true; return true;
} }
} }
return false;
} }
/** /**
......
...@@ -110,7 +110,7 @@ public class FakeUrlResponse { ...@@ -110,7 +110,7 @@ public class FakeUrlResponse {
* Sets the HTTP status code. The default value is 200. * Sets the HTTP status code. The default value is 200.
* *
* @param httpStatusCode for {@link UrlResponseInfo.getHttpStatusCode()} * @param httpStatusCode for {@link UrlResponseInfo.getHttpStatusCode()}
* @return a builder with the corresponding HTTP status code set * @return the builder with the corresponding HTTP status code set
*/ */
public Builder setHttpStatusCode(int httpStatusCode) { public Builder setHttpStatusCode(int httpStatusCode) {
mHttpStatusCode = httpStatusCode; mHttpStatusCode = httpStatusCode;
...@@ -122,7 +122,7 @@ public class FakeUrlResponse { ...@@ -122,7 +122,7 @@ public class FakeUrlResponse {
* *
* @param name the name of the header key, for example, "location" for a redirect header * @param name the name of the header key, for example, "location" for a redirect header
* @param value the header value * @param value the header value
* @return a builder with the corresponding header set * @return the builder with the corresponding header set
*/ */
public Builder addHeader(String name, String value) { public Builder addHeader(String name, String value) {
mAllHeadersList.add(new AbstractMap.SimpleEntry<>(name, value)); mAllHeadersList.add(new AbstractMap.SimpleEntry<>(name, value));
...@@ -133,7 +133,7 @@ public class FakeUrlResponse { ...@@ -133,7 +133,7 @@ public class FakeUrlResponse {
* Sets result of {@link UrlResponseInfo.wasCached()}. The default wasCached value is false. * Sets result of {@link UrlResponseInfo.wasCached()}. The default wasCached value is false.
* *
* @param wasCached for {@link UrlResponseInfo.wasCached()} * @param wasCached for {@link UrlResponseInfo.wasCached()}
* @return a builder with the corresponding wasCached field set * @return the builder with the corresponding wasCached field set
*/ */
public Builder setWasCached(boolean wasCached) { public Builder setWasCached(boolean wasCached) {
mWasCached = wasCached; mWasCached = wasCached;
...@@ -145,7 +145,7 @@ public class FakeUrlResponse { ...@@ -145,7 +145,7 @@ public class FakeUrlResponse {
* protocol is an empty string. * protocol is an empty string.
* *
* @param negotiatedProtocol for {@link UrlResponseInfo.getNegotiatedProtocol()} * @param negotiatedProtocol for {@link UrlResponseInfo.getNegotiatedProtocol()}
* @return a builder with the corresponding negotiatedProtocol field set * @return the builder with the corresponding negotiatedProtocol field set
*/ */
public Builder setNegotiatedProtocol(String negotiatedProtocol) { public Builder setNegotiatedProtocol(String negotiatedProtocol) {
mNegotiatedProtocol = negotiatedProtocol; mNegotiatedProtocol = negotiatedProtocol;
...@@ -157,7 +157,7 @@ public class FakeUrlResponse { ...@@ -157,7 +157,7 @@ public class FakeUrlResponse {
* empty string. * empty string.
* *
* @param proxyServer for {@link UrlResponseInfo.getProxyServer()} * @param proxyServer for {@link UrlResponseInfo.getProxyServer()}
* @return a builder with the corresponding proxyServer field set * @return the builder with the corresponding proxyServer field set
*/ */
public Builder setProxyServer(String proxyServer) { public Builder setProxyServer(String proxyServer) {
mProxyServer = proxyServer; mProxyServer = proxyServer;
...@@ -167,8 +167,8 @@ public class FakeUrlResponse { ...@@ -167,8 +167,8 @@ public class FakeUrlResponse {
/** /**
* Sets the response body for a response. The default response body is an empty byte array. * Sets the response body for a response. The default response body is an empty byte array.
* *
* @param responseBody all the information the server returns * @param body all the information the server returns
* @return a builder with the corresponding responseBody field set * @return the builder with the corresponding responseBody field set
*/ */
public Builder setResponseBody(byte[] body) { public Builder setResponseBody(byte[] body) {
mResponseBody = body; mResponseBody = body;
......
...@@ -21,9 +21,10 @@ public interface ResponseMatcher { ...@@ -21,9 +21,10 @@ public interface ResponseMatcher {
* @param url the URL the {@link UrlRequest} is connecting to * @param url the URL the {@link UrlRequest} is connecting to
* @param httpMethod the HTTP method the {@link UrlRequest} is connecting with * @param httpMethod the HTTP method the {@link UrlRequest} is connecting with
* @param headers the {@link UrlRequest} headers * @param headers the {@link UrlRequest} headers
* @param body the body of the request
* @return a {@link FakeUrlResponse} if there is a matching response, or {@code null} otherwise * @return a {@link FakeUrlResponse} if there is a matching response, or {@code null} otherwise
*/ */
@Nullable @Nullable
FakeUrlResponse getMatchingResponse( FakeUrlResponse getMatchingResponse(
String url, String httpMethod, List<Map.Entry<String, String>> headers); String url, String httpMethod, List<Map.Entry<String, String>> headers, byte[] body);
} }
...@@ -35,7 +35,7 @@ public class UrlResponseMatcher implements ResponseMatcher { ...@@ -35,7 +35,7 @@ public class UrlResponseMatcher implements ResponseMatcher {
@Override @Override
public FakeUrlResponse getMatchingResponse( public FakeUrlResponse getMatchingResponse(
String url, String httpMethod, List<Map.Entry<String, String>> headers) { String url, String httpMethod, List<Map.Entry<String, String>> headers, byte[] body) {
return mUrl.equals(url) ? mResponse : null; return mUrl.equals(url) ? mResponse : null;
} }
} }
...@@ -140,7 +140,7 @@ public class FakeCronetControllerTest { ...@@ -140,7 +140,7 @@ public class FakeCronetControllerTest {
mFakeCronetController.addSuccessResponse(url, "different text".getBytes()); mFakeCronetController.addSuccessResponse(url, "different text".getBytes());
FakeUrlResponse foundResponse = FakeUrlResponse foundResponse =
mFakeCronetController.getResponse(new String(url), null, null); mFakeCronetController.getResponse(new String(url), null, null, null);
assertEquals(response, foundResponse); assertEquals(response, foundResponse);
} }
...@@ -155,7 +155,7 @@ public class FakeCronetControllerTest { ...@@ -155,7 +155,7 @@ public class FakeCronetControllerTest {
mFakeCronetController.addResponseMatcher(matcher); mFakeCronetController.addResponseMatcher(matcher);
mFakeCronetController.removeResponseMatcher(matcher); mFakeCronetController.removeResponseMatcher(matcher);
FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null); FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null, null);
assertEquals(404, foundResponse.getHttpStatusCode()); assertEquals(404, foundResponse.getHttpStatusCode());
assertNotEquals(response, foundResponse); assertNotEquals(response, foundResponse);
...@@ -171,7 +171,7 @@ public class FakeCronetControllerTest { ...@@ -171,7 +171,7 @@ public class FakeCronetControllerTest {
mFakeCronetController.addResponseMatcher(matcher); mFakeCronetController.addResponseMatcher(matcher);
mFakeCronetController.clearResponseMatchers(); mFakeCronetController.clearResponseMatchers();
FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null); FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null, null);
assertEquals(404, foundResponse.getHttpStatusCode()); assertEquals(404, foundResponse.getHttpStatusCode());
assertNotEquals(response, foundResponse); assertNotEquals(response, foundResponse);
...@@ -185,7 +185,7 @@ public class FakeCronetControllerTest { ...@@ -185,7 +185,7 @@ public class FakeCronetControllerTest {
new FakeUrlResponse.Builder().setResponseBody("body text".getBytes()).build(); new FakeUrlResponse.Builder().setResponseBody("body text".getBytes()).build();
mFakeCronetController.addResponseForUrl(response, url); mFakeCronetController.addResponseForUrl(response, url);
FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null); FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null, null);
assertEquals(foundResponse, response); assertEquals(foundResponse, response);
} }
...@@ -193,7 +193,7 @@ public class FakeCronetControllerTest { ...@@ -193,7 +193,7 @@ public class FakeCronetControllerTest {
@Test @Test
@SmallTest @SmallTest
public void testDefaultResponseIs404() { public void testDefaultResponseIs404() {
FakeUrlResponse foundResponse = mFakeCronetController.getResponse("url", null, null); FakeUrlResponse foundResponse = mFakeCronetController.getResponse("url", null, null, null);
assertEquals(404, foundResponse.getHttpStatusCode()); assertEquals(404, foundResponse.getHttpStatusCode());
} }
...@@ -205,7 +205,7 @@ public class FakeCronetControllerTest { ...@@ -205,7 +205,7 @@ public class FakeCronetControllerTest {
String location = "/TEST_REDIRECT_LOCATION"; String location = "/TEST_REDIRECT_LOCATION";
mFakeCronetController.addRedirectResponse(location, url); mFakeCronetController.addRedirectResponse(location, url);
FakeUrlResponse foundResponse = mFakeCronetController.getResponse("url", null, null); FakeUrlResponse foundResponse = mFakeCronetController.getResponse("url", null, null, null);
Map.Entry<String, String> headerEntry = new AbstractMap.SimpleEntry<>("location", location); Map.Entry<String, String> headerEntry = new AbstractMap.SimpleEntry<>("location", location);
assertTrue(foundResponse.getAllHeadersList().contains(headerEntry)); assertTrue(foundResponse.getAllHeadersList().contains(headerEntry));
...@@ -220,7 +220,7 @@ public class FakeCronetControllerTest { ...@@ -220,7 +220,7 @@ public class FakeCronetControllerTest {
int httpStatusCode = 400; int httpStatusCode = 400;
mFakeCronetController.addHttpErrorResponse(httpStatusCode, url); mFakeCronetController.addHttpErrorResponse(httpStatusCode, url);
FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null); FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null, null);
assertEquals(foundResponse.getHttpStatusCode(), httpStatusCode); assertEquals(foundResponse.getHttpStatusCode(), httpStatusCode);
} }
...@@ -245,7 +245,7 @@ public class FakeCronetControllerTest { ...@@ -245,7 +245,7 @@ public class FakeCronetControllerTest {
String body = "TEST_BODY"; String body = "TEST_BODY";
mFakeCronetController.addSuccessResponse(url, body.getBytes()); mFakeCronetController.addSuccessResponse(url, body.getBytes());
FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null); FakeUrlResponse foundResponse = mFakeCronetController.getResponse(url, null, null, null);
assertTrue(foundResponse.getHttpStatusCode() >= 200); assertTrue(foundResponse.getHttpStatusCode() >= 200);
assertTrue(foundResponse.getHttpStatusCode() < 300); assertTrue(foundResponse.getHttpStatusCode() < 300);
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
package org.chromium.net.test; package org.chromium.net.test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.chromium.net.CronetTestRule.assertContains;
import static org.chromium.net.TestUrlRequestCallback.ResponseStep.ON_CANCELED; import static org.chromium.net.TestUrlRequestCallback.ResponseStep.ON_CANCELED;
import android.content.Context; import android.content.Context;
...@@ -27,11 +29,17 @@ import org.mockito.Mockito; ...@@ -27,11 +29,17 @@ import org.mockito.Mockito;
import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DisabledTest;
import org.chromium.net.CronetEngine; import org.chromium.net.CronetEngine;
import org.chromium.net.InlineExecutionProhibitedException; import org.chromium.net.InlineExecutionProhibitedException;
import org.chromium.net.TestUploadDataProvider;
import org.chromium.net.TestUrlRequestCallback; import org.chromium.net.TestUrlRequestCallback;
import org.chromium.net.UploadDataProvider;
import org.chromium.net.UploadDataProviders;
import org.chromium.net.UploadDataSink;
import org.chromium.net.UrlRequest.Status; import org.chromium.net.UrlRequest.Status;
import org.chromium.net.UrlRequest.StatusListener; import org.chromium.net.UrlRequest.StatusListener;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -39,6 +47,7 @@ import java.util.Map; ...@@ -39,6 +47,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* Test functionality of FakeUrlRequest. * Test functionality of FakeUrlRequest.
*/ */
...@@ -63,6 +72,27 @@ public class FakeUrlRequestTest { ...@@ -63,6 +72,27 @@ public class FakeUrlRequestTest {
foundStatus.block(); foundStatus.block();
} }
private class EchoBodyResponseMatcher implements ResponseMatcher {
private final String mUrl;
EchoBodyResponseMatcher(String url) {
mUrl = url;
}
EchoBodyResponseMatcher() {
this(null);
}
@Override
public FakeUrlResponse getMatchingResponse(String url, String httpMethod,
List<Map.Entry<String, String>> headers, byte[] body) {
if (mUrl == null || mUrl.equals(url)) {
return new FakeUrlResponse.Builder().setResponseBody(body).build();
}
return null;
}
}
@Before @Before
public void setUp() { public void setUp() {
mFakeCronetController = new FakeCronetController(); mFakeCronetController = new FakeCronetController();
...@@ -170,14 +200,15 @@ public class FakeUrlRequestTest { ...@@ -170,14 +200,15 @@ public class FakeUrlRequestTest {
(FakeUrlRequest) mFakeCronetEngine (FakeUrlRequest) mFakeCronetEngine
.newUrlRequestBuilder("url", callback, callback.getExecutor()) .newUrlRequestBuilder("url", callback, callback.getExecutor())
.build(); .build();
String testMethod = "POST"; String testMethod = "PUT";
// Use an atomic because it is set in an inner class. We do not actually need atomic for a
// multi-threaded operation here.
AtomicBoolean foundMethod = new AtomicBoolean(); AtomicBoolean foundMethod = new AtomicBoolean();
mFakeCronetController.addResponseMatcher(new ResponseMatcher() { mFakeCronetController.addResponseMatcher(new ResponseMatcher() {
@Override @Override
public FakeUrlResponse getMatchingResponse( public FakeUrlResponse getMatchingResponse(String url, String httpMethod,
String url, String httpMethod, List<Map.Entry<String, String>> headers) { List<Map.Entry<String, String>> headers, byte[] body) {
assertEquals(testMethod, httpMethod); assertEquals(testMethod, httpMethod);
foundMethod.set(true); foundMethod.set(true);
// It doesn't matter if a response is actually returned. // It doesn't matter if a response is actually returned.
...@@ -206,11 +237,13 @@ public class FakeUrlRequestTest { ...@@ -206,11 +237,13 @@ public class FakeUrlRequestTest {
String headerKey = "HEADERNAME"; String headerKey = "HEADERNAME";
String headerValue = "HEADERVALUE"; String headerValue = "HEADERVALUE";
request.addHeader(headerKey, headerValue); request.addHeader(headerKey, headerValue);
// Use an atomic because it is set in an inner class. We do not actually need atomic for a
// multi-threaded operation here.
AtomicBoolean foundEntry = new AtomicBoolean(); AtomicBoolean foundEntry = new AtomicBoolean();
mFakeCronetController.addResponseMatcher(new ResponseMatcher() { mFakeCronetController.addResponseMatcher(new ResponseMatcher() {
@Override @Override
public FakeUrlResponse getMatchingResponse( public FakeUrlResponse getMatchingResponse(String url, String httpMethod,
String url, String httpMethod, List<Map.Entry<String, String>> headers) { List<Map.Entry<String, String>> headers, byte[] body) {
assertEquals(1, headers.size()); assertEquals(1, headers.size());
assertEquals(headerKey, headers.get(0).getKey()); assertEquals(headerKey, headers.get(0).getKey());
assertEquals(headerValue, headers.get(0).getValue()); assertEquals(headerValue, headers.get(0).getValue());
...@@ -463,15 +496,19 @@ public class FakeUrlRequestTest { ...@@ -463,15 +496,19 @@ public class FakeUrlRequestTest {
TestUrlRequestCallback callback = Mockito.spy(new TestUrlRequestCallback()); TestUrlRequestCallback callback = Mockito.spy(new TestUrlRequestCallback());
FakeUrlRequest request = (FakeUrlRequest) mFakeCronetEngine FakeUrlRequest request = (FakeUrlRequest) mFakeCronetEngine
.newUrlRequestBuilder("", callback, callback.getExecutor()) .newUrlRequestBuilder("", callback, callback.getExecutor())
.addHeader("Content-Type", "useless/string")
.build(); .build();
request.setUploadDataProvider(null, null); String body = "body";
request.setUploadDataProvider(
UploadDataProviders.create(body.getBytes()), callback.getExecutor());
request.start(); request.start();
// Must wait for the request to prevent a race in the State since it is reported in the // Must wait for the request to prevent a race in the State since it is reported in the
// error. // error.
callback.blockForDone(); callback.blockForDone();
try { try {
request.setUploadDataProvider(null, null); request.setUploadDataProvider(
UploadDataProviders.create(body.getBytes()), callback.getExecutor());
fail("UploadDataProvider cannot be changed after request has started"); fail("UploadDataProvider cannot be changed after request has started");
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
assertEquals("Request is already started. State is: 7", e.getMessage()); assertEquals("Request is already started. State is: 7", e.getMessage());
...@@ -777,4 +814,783 @@ public class FakeUrlRequestTest { ...@@ -777,4 +814,783 @@ public class FakeUrlRequestTest {
assertEquals(404, callback.mResponseInfo.getHttpStatusCode()); assertEquals(404, callback.mResponseInfo.getHttpStatusCode());
} }
@Test
@SmallTest
public void testUploadSetDataProviderChecksForNullUploadDataProvider() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
try {
builder.setUploadDataProvider(null, callback.getExecutor());
fail("Exception not thrown");
} catch (NullPointerException e) {
assertEquals("Invalid UploadDataProvider.", e.getMessage());
}
}
@Test
@SmallTest
public void testUploadSetDataProviderChecksForContentTypeHeader() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
try {
builder.build().start();
fail("Exception not thrown");
} catch (IllegalArgumentException e) {
assertEquals("Requests with upload data must have a Content-Type.", e.getMessage());
}
}
@Test
@SmallTest
public void testUploadWithEmptyBody() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
assertNotNull(callback.mResponseInfo);
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("", callback.mResponseAsString);
dataProvider.assertClosed();
}
@Test
@SmallTest
public void testUploadSync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
String body = "test";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
dataProvider.addRead(body.getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(4, dataProvider.getUploadedLength());
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("test", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadSyncReadWrongState() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
String body = "test";
callback.setAutoAdvance(false);
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
// Add a redirect response so the request keeps the UploadDataProvider open while waiting
// to follow the redirect.
mFakeCronetController.addRedirectResponse("newUrl", url);
dataProvider.addRead(body.getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
FakeUrlRequest request = (FakeUrlRequest) builder.build();
request.start();
callback.waitForNextStep();
try {
request.mFakeDataSink.onReadSucceeded(false);
fail("Cannot read before upload has started");
} catch (IllegalStateException e) {
assertEquals("onReadSucceeded() called when not awaiting a read result; in state: 2",
e.getMessage());
}
request.cancel();
}
@Test
@SmallTest
public void testUploadSyncRewindWrongState() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
String body = "test";
callback.setAutoAdvance(false);
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
// Add a redirect response so the request keeps the UploadDataProvider open while waiting
// to follow the redirect.
mFakeCronetController.addRedirectResponse("newUrl", url);
dataProvider.addRead(body.getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
FakeUrlRequest request = (FakeUrlRequest) builder.build();
request.start();
callback.waitForNextStep();
try {
request.mFakeDataSink.onRewindSucceeded();
fail("Cannot rewind before upload has started");
} catch (IllegalStateException e) {
assertEquals("onRewindSucceeded() called when not awaiting a rewind; in state: 2",
e.getMessage());
}
request.cancel();
}
@Test
@SmallTest
public void testUploadMultiplePiecesSync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
dataProvider.addRead("Y".getBytes());
dataProvider.addRead("et ".getBytes());
dataProvider.addRead("another ".getBytes());
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(16, dataProvider.getUploadedLength());
assertEquals(4, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("Yet another test", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadMultiplePiecesAsync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.ASYNC, callback.getExecutor());
dataProvider.addRead("Y".getBytes());
dataProvider.addRead("et ".getBytes());
dataProvider.addRead("another ".getBytes());
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(16, dataProvider.getUploadedLength());
assertEquals(4, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("Yet another test", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadChangesDefaultMethod() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new ResponseMatcher() {
@Override
public FakeUrlResponse getMatchingResponse(String url, String httpMethod,
List<Map.Entry<String, String>> headers, byte[] body) {
return new FakeUrlResponse.Builder().setResponseBody(httpMethod.getBytes()).build();
}
});
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("POST", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadWithSetMethod() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new ResponseMatcher() {
@Override
public FakeUrlResponse getMatchingResponse(String url, String httpMethod,
List<Map.Entry<String, String>> headers, byte[] body) {
return new FakeUrlResponse.Builder().setResponseBody(httpMethod.getBytes()).build();
}
});
final String method = "PUT";
builder.setHttpMethod(method);
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("PUT", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadRedirectSync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String redirectUrl = "redirectUrl";
String echoBodyUrl = "echobody";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
redirectUrl, callback, callback.getExecutor());
mFakeCronetController.addRedirectResponse(echoBodyUrl, redirectUrl);
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher(echoBodyUrl));
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
// 1 read call before the rewind, 1 after.
assertEquals(2, dataProvider.getNumReadCalls());
assertEquals(1, dataProvider.getNumRewindCalls());
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("test", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadRedirectAsync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String redirectUrl = "redirectUrl";
String echoBodyUrl = "echobody";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
redirectUrl, callback, callback.getExecutor());
mFakeCronetController.addRedirectResponse(echoBodyUrl, redirectUrl);
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher(echoBodyUrl));
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.ASYNC, callback.getExecutor());
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
// 1 read call before the rewind, 1 after.
assertEquals(2, dataProvider.getNumReadCalls());
assertEquals(1, dataProvider.getNumRewindCalls());
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("test", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadWithBadLength() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor()) {
@Override
public long getLength() throws IOException {
return 1;
}
@Override
public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer)
throws IOException {
byteBuffer.put("12".getBytes());
uploadDataSink.onReadSucceeded(false);
}
};
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Read upload data length 2 exceeds expected length 1",
callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
@Test
@SmallTest
public void testUploadWithBadLengthBufferAligned() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor()) {
@Override
public long getLength() throws IOException {
return 8191;
}
@Override
public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer)
throws IOException {
byteBuffer.put("0123456789abcdef".getBytes());
uploadDataSink.onReadSucceeded(false);
}
};
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Read upload data length 8192 exceeds expected length 8191",
callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
@Test
@SmallTest
public void testUploadLengthFailSync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.setLengthFailure();
// This will never be read, but if the length is 0, read may never be
// called.
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(0, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Sync length failure", callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
@Test
@SmallTest
public void testUploadReadFailSync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.setReadFailure(
/* readFailIndex= */ 0, TestUploadDataProvider.FailMode.CALLBACK_SYNC);
// This will never be read, but if the length is 0, read may never be
// called.
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Sync read failure", callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
@Test
@SmallTest
public void testUploadReadFailAsync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.setReadFailure(
/* readFailIndex= */ 0, TestUploadDataProvider.FailMode.CALLBACK_ASYNC);
// This will never be read, but if the length is 0, read may never be
// called.
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Async read failure", callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
@Test
@SmallTest
public void testUploadReadFailThrown() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.setReadFailure(/* readFailIndex= */ 0, TestUploadDataProvider.FailMode.THROWN);
// This will never be read, but if the length is 0, read may never be
// called.
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Thrown read failure", callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
/** This test uses a direct executor for upload, and non direct for callbacks */
@Test
@SmallTest
public void testDirectExecutorUploadProhibitedByDefault() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
Executor myExecutor = new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, myExecutor);
// This will never be read, but if the length is 0, read may never be
// called.
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, myExecutor);
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
assertEquals(0, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Inline execution is prohibited for this request",
callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
/** This test uses a direct executor for callbacks, and non direct for upload */
@Test
@SmallTest
public void testDirectExecutorProhibitedByDefault() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
Executor myExecutor = new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, myExecutor);
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
// This will never be read, but if the length is 0, read may never be
// called.
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals(0, dataProvider.getNumRewindCalls());
assertContains("Exception posting task to executor", callback.mError.getMessage());
assertContains("Inline execution is prohibited for this request",
callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
dataProvider.assertClosed();
}
@Test
@SmallTest
public void testDirectExecutorAllowed() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
callback.setAllowDirectExecutor(true);
Executor myExecutor = new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
UploadDataProvider dataProvider = UploadDataProviders.create("test".getBytes());
builder.setUploadDataProvider(dataProvider, myExecutor);
builder.addHeader("Content-Type", "useless/string");
builder.allowDirectExecutor();
builder.build().start();
callback.blockForDone();
if (callback.mOnErrorCalled) {
throw callback.mError;
}
assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
assertEquals("test", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadRewindFailSync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String redirectUrl = "redirectUrl";
String echoBodyUrl = "echobody";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
redirectUrl, callback, callback.getExecutor());
mFakeCronetController.addRedirectResponse(echoBodyUrl, redirectUrl);
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher(echoBodyUrl));
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.setRewindFailure(TestUploadDataProvider.FailMode.CALLBACK_SYNC);
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals(1, dataProvider.getNumRewindCalls());
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Sync rewind failure", callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
@Test
@SmallTest
public void testUploadRewindFailAsync() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String redirectUrl = "redirectUrl";
String echoBodyUrl = "echobody";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
redirectUrl, callback, callback.getExecutor());
mFakeCronetController.addRedirectResponse(echoBodyUrl, redirectUrl);
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher(echoBodyUrl));
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.ASYNC, callback.getExecutor());
dataProvider.setRewindFailure(TestUploadDataProvider.FailMode.CALLBACK_ASYNC);
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals(1, dataProvider.getNumRewindCalls());
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Async rewind failure", callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
@Test
@SmallTest
public void testUploadRewindFailThrown() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String redirectUrl = "redirectUrl";
String echoBodyUrl = "echobody";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
redirectUrl, callback, callback.getExecutor());
mFakeCronetController.addRedirectResponse(echoBodyUrl, redirectUrl);
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher(echoBodyUrl));
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.setRewindFailure(TestUploadDataProvider.FailMode.THROWN);
dataProvider.addRead("test".getBytes());
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals(1, dataProvider.getNumRewindCalls());
assertContains("Exception received from UploadDataProvider", callback.mError.getMessage());
assertContains("Thrown rewind failure", callback.mError.getCause().getMessage());
assertEquals(null, callback.mResponseInfo);
}
@Test
@SmallTest
public void testUploadChunked() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
dataProvider.addRead("test hello".getBytes());
dataProvider.setChunked(true);
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
assertEquals(-1, dataProvider.getUploadedLength());
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
// 1 read call for one data chunk.
assertEquals(1, dataProvider.getNumReadCalls());
assertEquals("test hello", callback.mResponseAsString);
}
@Test
@SmallTest
public void testUploadChunkedLastReadZeroLengthBody() throws Exception {
TestUrlRequestCallback callback = new TestUrlRequestCallback();
String url = "url";
FakeUrlRequest.Builder builder =
(FakeUrlRequest.Builder) mFakeCronetEngine.newUrlRequestBuilder(
url, callback, callback.getExecutor());
mFakeCronetController.addResponseMatcher(new EchoBodyResponseMatcher());
TestUploadDataProvider dataProvider = new TestUploadDataProvider(
TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
// Add 3 reads. The last read has a 0-length body.
dataProvider.addRead("hello there".getBytes());
dataProvider.addRead("!".getBytes());
dataProvider.addRead("".getBytes());
dataProvider.setChunked(true);
builder.setUploadDataProvider(dataProvider, callback.getExecutor());
builder.addHeader("Content-Type", "useless/string");
assertEquals(-1, dataProvider.getUploadedLength());
builder.build().start();
callback.blockForDone();
dataProvider.assertClosed();
// 2 read call for the first two data chunks, and 1 for final chunk.
assertEquals(3, dataProvider.getNumReadCalls());
assertEquals("hello there!", callback.mResponseAsString);
}
} }
...@@ -51,7 +51,7 @@ public class UrlResponseMatcherTest { ...@@ -51,7 +51,7 @@ public class UrlResponseMatcherTest {
new FakeUrlResponse.Builder().setResponseBody("TestBody".getBytes()).build(); new FakeUrlResponse.Builder().setResponseBody("TestBody".getBytes()).build();
ResponseMatcher matcher = new UrlResponseMatcher(url, response); ResponseMatcher matcher = new UrlResponseMatcher(url, response);
FakeUrlResponse found = matcher.getMatchingResponse(url, null, null); FakeUrlResponse found = matcher.getMatchingResponse(url, null, null, null);
assertNotNull(found); assertNotNull(found);
assertEquals(found, response); assertEquals(found, response);
...@@ -66,7 +66,8 @@ public class UrlResponseMatcherTest { ...@@ -66,7 +66,8 @@ public class UrlResponseMatcherTest {
new FakeUrlResponse.Builder().setResponseBody("TestBody".getBytes()).build(); new FakeUrlResponse.Builder().setResponseBody("TestBody".getBytes()).build();
ResponseMatcher matcher = new UrlResponseMatcher(url, response); ResponseMatcher matcher = new UrlResponseMatcher(url, response);
FakeUrlResponse notFound = matcher.getMatchingResponse(urlWithoutResponse, null, null); FakeUrlResponse notFound =
matcher.getMatchingResponse(urlWithoutResponse, null, null, null);
assertNull(notFound); assertNull(notFound);
} }
......
...@@ -16,22 +16,14 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -16,22 +16,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* An UploadDataProvider implementation used in tests. * An UploadDataProvider implementation used in tests.
*/ */
class TestUploadDataProvider extends UploadDataProvider { public class TestUploadDataProvider extends UploadDataProvider {
// Indicates whether all success callbacks are synchronous or asynchronous. // Indicates whether all success callbacks are synchronous or asynchronous.
// Doesn't apply to errors. // Doesn't apply to errors.
enum SuccessCallbackMode { public enum SuccessCallbackMode { SYNC, ASYNC }
SYNC,
ASYNC
};
// Indicates whether failures should throw exceptions, invoke callbacks // Indicates whether failures should throw exceptions, invoke callbacks
// synchronously, or invoke callback asynchronously. // synchronously, or invoke callback asynchronously.
enum FailMode { public enum FailMode { NONE, THROWN, CALLBACK_SYNC, CALLBACK_ASYNC }
NONE,
THROWN,
CALLBACK_SYNC,
CALLBACK_ASYNC
};
private ArrayList<byte[]> mReads = new ArrayList<byte[]>(); private ArrayList<byte[]> mReads = new ArrayList<byte[]>();
private final SuccessCallbackMode mSuccessCallbackMode; private final SuccessCallbackMode mSuccessCallbackMode;
...@@ -61,7 +53,8 @@ class TestUploadDataProvider extends UploadDataProvider { ...@@ -61,7 +53,8 @@ class TestUploadDataProvider extends UploadDataProvider {
private AtomicBoolean mClosed = new AtomicBoolean(false); private AtomicBoolean mClosed = new AtomicBoolean(false);
private ConditionVariable mAwaitingClose = new ConditionVariable(false); private ConditionVariable mAwaitingClose = new ConditionVariable(false);
TestUploadDataProvider(SuccessCallbackMode successCallbackMode, final Executor executor) { public TestUploadDataProvider(
SuccessCallbackMode successCallbackMode, final Executor executor) {
mSuccessCallbackMode = successCallbackMode; mSuccessCallbackMode = successCallbackMode;
mExecutor = executor; mExecutor = executor;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment