Merge "Add more test coverage for UrlRequest and ConnectionMigrationOptions."
This commit is contained in:
@@ -18,6 +18,7 @@ package android.net.http.cts
|
||||
|
||||
import android.net.http.ConnectionMigrationOptions
|
||||
import android.net.http.ConnectionMigrationOptions.MIGRATION_OPTION_ENABLED
|
||||
import android.net.http.ConnectionMigrationOptions.MIGRATION_OPTION_UNSPECIFIED
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
@@ -26,6 +27,16 @@ import org.junit.runner.RunWith
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ConnectionMigrationOptionsTest {
|
||||
|
||||
@Test
|
||||
fun testConnectionMigrationOptions_defaultValues() {
|
||||
val options =
|
||||
ConnectionMigrationOptions.Builder().build()
|
||||
|
||||
assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.allowNonDefaultNetworkUsageEnabled)
|
||||
assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.defaultNetworkMigrationEnabled)
|
||||
assertEquals(MIGRATION_OPTION_UNSPECIFIED, options.pathDegradationMigrationEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConnectionMigrationOptions_enableDefaultNetworkMigration_returnSetValue() {
|
||||
val options =
|
||||
@@ -45,4 +56,13 @@ class ConnectionMigrationOptionsTest {
|
||||
|
||||
assertEquals(MIGRATION_OPTION_ENABLED, options.pathDegradationMigrationEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConnectionMigrationOptions_allowNonDefaultNetworkUsage_returnSetValue() {
|
||||
val options =
|
||||
ConnectionMigrationOptions.Builder()
|
||||
.setAllowNonDefaultNetworkUsageEnabled(MIGRATION_OPTION_ENABLED).build()
|
||||
|
||||
assertEquals(MIGRATION_OPTION_ENABLED, options.allowNonDefaultNetworkUsageEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package android.net.http.cts;
|
||||
import static android.net.http.cts.util.TestUtilsKt.assertOKStatusCode;
|
||||
import static android.net.http.cts.util.TestUtilsKt.skipIfNoInternetConnection;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -40,15 +42,19 @@ import android.net.http.cts.util.TestStatusListener;
|
||||
import android.net.http.cts.util.TestUploadDataProvider;
|
||||
import android.net.http.cts.util.TestUrlRequestCallback;
|
||||
import android.net.http.cts.util.TestUrlRequestCallback.ResponseStep;
|
||||
import android.net.http.cts.util.UploadDataProviders;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
@@ -279,6 +285,31 @@ public class UrlRequestTest {
|
||||
assertTrue(e.getCause().getMessage().contains("full"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUrlRequestPost_withRedirect() throws Exception {
|
||||
String body = Strings.repeat(
|
||||
"Hello, this is a really interesting body, so write this 100 times.", 100);
|
||||
|
||||
String redirectUrlParameter =
|
||||
URLEncoder.encode(mTestServer.getEchoBodyUrl(), "UTF-8");
|
||||
createUrlRequestBuilder(
|
||||
String.format(
|
||||
"%s/alt_redirect?dest=%s&statusCode=307",
|
||||
mTestServer.getBaseUri(),
|
||||
redirectUrlParameter))
|
||||
.setHttpMethod("POST")
|
||||
.addHeader("Content-Type", "text/plain")
|
||||
.setUploadDataProvider(
|
||||
UploadDataProviders.create(body.getBytes(StandardCharsets.UTF_8)),
|
||||
mCallback.getExecutor())
|
||||
.build()
|
||||
.start();
|
||||
mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
|
||||
|
||||
assertOKStatusCode(mCallback.mResponseInfo);
|
||||
assertThat(mCallback.mResponseAsString).isEqualTo(body);
|
||||
}
|
||||
|
||||
private static class StubUrlRequestCallback extends UrlRequest.Callback {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* 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 android.net.http.cts.util;
|
||||
|
||||
import android.net.http.UploadDataProvider;
|
||||
import android.net.http.UploadDataSink;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
/**
|
||||
* Provides implementations of {@link UploadDataProvider} for common use cases. Corresponds to
|
||||
* {@code android.net.http.apihelpers.UploadDataProviders} which is not an exposed API.
|
||||
*/
|
||||
public final class UploadDataProviders {
|
||||
/**
|
||||
* Uploads an entire file.
|
||||
*
|
||||
* @param file The file to upload
|
||||
* @return A new UploadDataProvider for the given file
|
||||
*/
|
||||
public static UploadDataProvider create(final File file) {
|
||||
return new FileUploadProvider(() -> new FileInputStream(file).getChannel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an entire file, closing the descriptor when it is no longer needed.
|
||||
*
|
||||
* @param fd The file descriptor to upload
|
||||
* @throws IllegalArgumentException if {@code fd} is not a file.
|
||||
* @return A new UploadDataProvider for the given file descriptor
|
||||
*/
|
||||
public static UploadDataProvider create(final ParcelFileDescriptor fd) {
|
||||
return new FileUploadProvider(() -> {
|
||||
if (fd.getStatSize() != -1) {
|
||||
return new ParcelFileDescriptor.AutoCloseInputStream(fd).getChannel();
|
||||
} else {
|
||||
fd.close();
|
||||
throw new IllegalArgumentException("Not a file: " + fd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads a ByteBuffer, from the current {@code buffer.position()} to {@code buffer.limit()}
|
||||
*
|
||||
* @param buffer The data to upload
|
||||
* @return A new UploadDataProvider for the given buffer
|
||||
*/
|
||||
public static UploadDataProvider create(ByteBuffer buffer) {
|
||||
return new ByteBufferUploadProvider(buffer.slice());
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads {@code length} bytes from {@code data}, starting from {@code offset}
|
||||
*
|
||||
* @param data Array containing data to upload
|
||||
* @param offset Offset within data to start with
|
||||
* @param length Number of bytes to upload
|
||||
* @return A new UploadDataProvider for the given data
|
||||
*/
|
||||
public static UploadDataProvider create(byte[] data, int offset, int length) {
|
||||
return new ByteBufferUploadProvider(ByteBuffer.wrap(data, offset, length).slice());
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the contents of {@code data}
|
||||
*
|
||||
* @param data Array containing data to upload
|
||||
* @return A new UploadDataProvider for the given data
|
||||
*/
|
||||
public static UploadDataProvider create(byte[] data) {
|
||||
return create(data, 0, data.length);
|
||||
}
|
||||
|
||||
private interface FileChannelProvider {
|
||||
FileChannel getChannel() throws IOException;
|
||||
}
|
||||
|
||||
private static final class FileUploadProvider extends UploadDataProvider {
|
||||
private volatile FileChannel mChannel;
|
||||
private final FileChannelProvider mProvider;
|
||||
/** Guards initialization of {@code mChannel} */
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private FileUploadProvider(FileChannelProvider provider) {
|
||||
this.mProvider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() throws IOException {
|
||||
return getChannel().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) throws IOException {
|
||||
if (!byteBuffer.hasRemaining()) {
|
||||
throw new IllegalStateException("Cronet passed a buffer with no bytes remaining");
|
||||
}
|
||||
FileChannel channel = getChannel();
|
||||
int bytesRead = 0;
|
||||
while (bytesRead == 0) {
|
||||
int read = channel.read(byteBuffer);
|
||||
if (read == -1) {
|
||||
break;
|
||||
} else {
|
||||
bytesRead += read;
|
||||
}
|
||||
}
|
||||
uploadDataSink.onReadSucceeded(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind(UploadDataSink uploadDataSink) throws IOException {
|
||||
getChannel().position(0);
|
||||
uploadDataSink.onRewindSucceeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily initializes the channel so that a blocking operation isn't performed
|
||||
* on a non-executor thread.
|
||||
*/
|
||||
private FileChannel getChannel() throws IOException {
|
||||
if (mChannel == null) {
|
||||
synchronized (mLock) {
|
||||
if (mChannel == null) {
|
||||
mChannel = mProvider.getChannel();
|
||||
}
|
||||
}
|
||||
}
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
FileChannel channel = mChannel;
|
||||
if (channel != null) {
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ByteBufferUploadProvider extends UploadDataProvider {
|
||||
private final ByteBuffer mUploadBuffer;
|
||||
|
||||
private ByteBufferUploadProvider(ByteBuffer uploadBuffer) {
|
||||
this.mUploadBuffer = uploadBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return mUploadBuffer.limit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) {
|
||||
if (!byteBuffer.hasRemaining()) {
|
||||
throw new IllegalStateException("Cronet passed a buffer with no bytes remaining");
|
||||
}
|
||||
if (byteBuffer.remaining() >= mUploadBuffer.remaining()) {
|
||||
byteBuffer.put(mUploadBuffer);
|
||||
} else {
|
||||
int oldLimit = mUploadBuffer.limit();
|
||||
mUploadBuffer.limit(mUploadBuffer.position() + byteBuffer.remaining());
|
||||
byteBuffer.put(mUploadBuffer);
|
||||
mUploadBuffer.limit(oldLimit);
|
||||
}
|
||||
uploadDataSink.onReadSucceeded(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rewind(UploadDataSink uploadDataSink) {
|
||||
mUploadBuffer.position(0);
|
||||
uploadDataSink.onRewindSucceeded();
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent instantiation
|
||||
private UploadDataProviders() {}
|
||||
}
|
||||
Reference in New Issue
Block a user