Support multiple DataSource configurations in DataSourceContractTest
PiperOrigin-RevId: 650967939
This commit is contained in:
parent
a202fd0c9c
commit
9d4e43cf55
@ -25,6 +25,7 @@ import androidx.media3.test.utils.HttpDataSourceTestEnv;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import org.chromium.net.CronetEngine;
|
import org.chromium.net.CronetEngine;
|
||||||
@ -45,15 +46,16 @@ public class CronetDataSourceContractTest extends DataSourceContractTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DataSource createDataSource() {
|
protected List<DataSource> createDataSources() {
|
||||||
@Nullable
|
@Nullable
|
||||||
CronetEngine cronetEngine =
|
CronetEngine cronetEngine =
|
||||||
CronetUtil.buildCronetEngine(
|
CronetUtil.buildCronetEngine(
|
||||||
ApplicationProvider.getApplicationContext(),
|
ApplicationProvider.getApplicationContext(),
|
||||||
/* userAgent= */ "test-agent",
|
/* userAgent= */ "test-agent",
|
||||||
/* preferGMSCoreCronet= */ false);
|
/* preferGooglePlayServices= */ false);
|
||||||
assertThat(cronetEngine).isNotNull();
|
assertThat(cronetEngine).isNotNull();
|
||||||
return new CronetDataSource.Factory(cronetEngine, executorService).createDataSource();
|
return ImmutableList.of(
|
||||||
|
new CronetDataSource.Factory(cronetEngine, executorService).createDataSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -17,6 +17,7 @@ package androidx.media3.test.utils;
|
|||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
import static androidx.media3.common.util.Util.castNonNull;
|
import static androidx.media3.common.util.Util.castNonNull;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
@ -58,9 +59,10 @@ import org.mockito.Mockito;
|
|||||||
/**
|
/**
|
||||||
* A collection of contract tests for {@link DataSource} implementations.
|
* A collection of contract tests for {@link DataSource} implementations.
|
||||||
*
|
*
|
||||||
* <p>Subclasses should only include the logic necessary to construct the DataSource and allow it to
|
* <p>Subclasses should only include the logic necessary to construct the DataSource (overriding
|
||||||
* successfully read data. They shouldn't include any new {@link Test @Test} methods -
|
* either {@link #createDataSource()} or {@link #createDataSources()}) and allow it to successfully
|
||||||
* implementation-specific tests should be in a separate class.
|
* read data (overriding {@link #getTestResources()}. They shouldn't include any new {@link
|
||||||
|
* Test @Test} methods - implementation-specific tests should be in a separate class.
|
||||||
*
|
*
|
||||||
* <p>Most implementations should pass all these tests. If necessary, subclasses can disable tests
|
* <p>Most implementations should pass all these tests. If necessary, subclasses can disable tests
|
||||||
* by overriding the {@link Test @Test} method with a no-op implementation. It's recommended (but
|
* by overriding the {@link Test @Test} method with a no-op implementation. It's recommended (but
|
||||||
@ -72,8 +74,25 @@ public abstract class DataSourceContractTest {
|
|||||||
|
|
||||||
@Rule public final AdditionalFailureInfo additionalFailureInfo = new AdditionalFailureInfo();
|
@Rule public final AdditionalFailureInfo additionalFailureInfo = new AdditionalFailureInfo();
|
||||||
|
|
||||||
/** Creates and returns an instance of the {@link DataSource}. */
|
/**
|
||||||
protected abstract DataSource createDataSource() throws Exception;
|
* Creates and returns an instance of the {@link DataSource}.
|
||||||
|
*
|
||||||
|
* <p>Only one of {@link #createDataSource()} and {@link #createDataSources()} should be
|
||||||
|
* implemented.
|
||||||
|
*/
|
||||||
|
protected DataSource createDataSource() throws Exception {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a list of instances of the {@link DataSource}.
|
||||||
|
*
|
||||||
|
* <p>Only one of {@link #createDataSource()} and {@link #createDataSources()} should be
|
||||||
|
* implemented.
|
||||||
|
*/
|
||||||
|
protected List<DataSource> createDataSources() throws Exception {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link DataSource} that will be included in the {@link TransferListener} callbacks
|
* Returns the {@link DataSource} that will be included in the {@link TransferListener} callbacks
|
||||||
@ -113,13 +132,8 @@ public abstract class DataSourceContractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void unboundedDataSpec_readUntilEnd() throws Exception {
|
public void unboundedDataSpec_readUntilEnd() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
long length = dataSource.open(new DataSpec(resource.getUri()));
|
long length = dataSource.open(new DataSpec(resource.getUri()));
|
||||||
byte[] data =
|
byte[] data =
|
||||||
@ -134,19 +148,13 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dataSpecWithPosition_readUntilEnd() throws Exception {
|
public void dataSpecWithPosition_readUntilEnd() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
long length =
|
long length =
|
||||||
dataSource.open(
|
dataSource.open(
|
||||||
@ -160,27 +168,23 @@ public abstract class DataSourceContractTest {
|
|||||||
assertThat(length).isEqualTo(resource.getExpectedBytes().length - 3);
|
assertThat(length).isEqualTo(resource.getExpectedBytes().length - 3);
|
||||||
}
|
}
|
||||||
byte[] expectedData =
|
byte[] expectedData =
|
||||||
Arrays.copyOfRange(resource.getExpectedBytes(), 3, resource.getExpectedBytes().length);
|
Arrays.copyOfRange(
|
||||||
|
resource.getExpectedBytes(), 3, resource.getExpectedBytes().length);
|
||||||
assertThat(data).isEqualTo(expectedData);
|
assertThat(data).isEqualTo(expectedData);
|
||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dataSpecWithLength_readExpectedRange() throws Exception {
|
public void dataSpecWithLength_readExpectedRange() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
long length =
|
long length =
|
||||||
dataSource.open(new DataSpec.Builder().setUri(resource.getUri()).setLength(4).build());
|
dataSource.open(
|
||||||
|
new DataSpec.Builder().setUri(resource.getUri()).setLength(4).build());
|
||||||
byte[] data = DataSourceUtil.readToEnd(dataSource);
|
byte[] data = DataSourceUtil.readToEnd(dataSource);
|
||||||
|
|
||||||
assertThat(length).isEqualTo(4);
|
assertThat(length).isEqualTo(4);
|
||||||
@ -189,19 +193,13 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dataSpecWithPositionAndLength_readExpectedRange() throws Exception {
|
public void dataSpecWithPositionAndLength_readExpectedRange() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
long length =
|
long length =
|
||||||
dataSource.open(
|
dataSource.open(
|
||||||
@ -218,20 +216,14 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dataSpecWithPositionAtEnd_readsZeroBytes() throws Exception {
|
public void dataSpecWithPositionAtEnd_readsZeroBytes() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
int resourceLength = resource.getExpectedBytes().length;
|
int resourceLength = resource.getExpectedBytes().length;
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
DataSpec dataSpec =
|
DataSpec dataSpec =
|
||||||
new DataSpec.Builder().setUri(resource.getUri()).setPosition(resourceLength).build();
|
new DataSpec.Builder().setUri(resource.getUri()).setPosition(resourceLength).build();
|
||||||
try {
|
try {
|
||||||
@ -241,9 +233,9 @@ public abstract class DataSourceContractTest {
|
|||||||
? Util.EMPTY_BYTE_ARRAY
|
? Util.EMPTY_BYTE_ARRAY
|
||||||
: DataSourceUtil.readToEnd(dataSource);
|
: DataSourceUtil.readToEnd(dataSource);
|
||||||
|
|
||||||
// The DataSource.open() contract requires the returned length to equal the length in the
|
// The DataSource.open() contract requires the returned length to equal the length in
|
||||||
// DataSpec if set. This is true even though the DataSource implementation may know that
|
// the DataSpec if set. This is true even though the DataSource implementation may know
|
||||||
// fewer bytes will be read in this case.
|
// that fewer bytes will be read in this case.
|
||||||
if (length != C.LENGTH_UNSET) {
|
if (length != C.LENGTH_UNSET) {
|
||||||
assertThat(length).isEqualTo(0);
|
assertThat(length).isEqualTo(0);
|
||||||
}
|
}
|
||||||
@ -251,20 +243,14 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dataSpecWithPositionAtEndAndLength_readsZeroBytes() throws Exception {
|
public void dataSpecWithPositionAtEndAndLength_readsZeroBytes() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
int resourceLength = resource.getExpectedBytes().length;
|
int resourceLength = resource.getExpectedBytes().length;
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
DataSpec dataSpec =
|
DataSpec dataSpec =
|
||||||
new DataSpec.Builder()
|
new DataSpec.Builder()
|
||||||
.setUri(resource.getUri())
|
.setUri(resource.getUri())
|
||||||
@ -278,50 +264,42 @@ public abstract class DataSourceContractTest {
|
|||||||
? Util.EMPTY_BYTE_ARRAY
|
? Util.EMPTY_BYTE_ARRAY
|
||||||
: DataSourceUtil.readToEnd(dataSource);
|
: DataSourceUtil.readToEnd(dataSource);
|
||||||
|
|
||||||
// The DataSource.open() contract requires the returned length to equal the length in the
|
// The DataSource.open() contract requires the returned length to equal the length in
|
||||||
// DataSpec if set. This is true even though the DataSource implementation may know that
|
// the DataSpec if set. This is true even though the DataSource implementation may know
|
||||||
// fewer bytes will be read in this case.
|
// that fewer bytes will be read in this case.
|
||||||
assertThat(length).isEqualTo(1);
|
assertThat(length).isEqualTo(1);
|
||||||
assertThat(data).isEmpty();
|
assertThat(data).isEmpty();
|
||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dataSpecWithPositionOutOfRange_throwsPositionOutOfRangeException() throws Exception {
|
public void dataSpecWithPositionOutOfRange_throwsPositionOutOfRangeException() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
int resourceLength = resource.getExpectedBytes().length;
|
int resourceLength = resource.getExpectedBytes().length;
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
DataSpec dataSpec =
|
DataSpec dataSpec =
|
||||||
new DataSpec.Builder().setUri(resource.getUri()).setPosition(resourceLength + 1).build();
|
new DataSpec.Builder()
|
||||||
|
.setUri(resource.getUri())
|
||||||
|
.setPosition(resourceLength + 1)
|
||||||
|
.build();
|
||||||
try {
|
try {
|
||||||
IOException exception = assertThrows(IOException.class, () -> dataSource.open(dataSpec));
|
IOException exception =
|
||||||
|
assertThrows(IOException.class, () -> dataSource.open(dataSpec));
|
||||||
assertThat(DataSourceException.isCausedByPositionOutOfRange(exception)).isTrue();
|
assertThat(DataSourceException.isCausedByPositionOutOfRange(exception)).isTrue();
|
||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dataSpecWithEndPositionOutOfRange_readsToEnd() throws Exception {
|
public void dataSpecWithEndPositionOutOfRange_readsToEnd() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
int resourceLength = resource.getExpectedBytes().length;
|
int resourceLength = resource.getExpectedBytes().length;
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
DataSpec dataSpec =
|
DataSpec dataSpec =
|
||||||
new DataSpec.Builder()
|
new DataSpec.Builder()
|
||||||
.setUri(resource.getUri())
|
.setUri(resource.getUri())
|
||||||
@ -333,9 +311,9 @@ public abstract class DataSourceContractTest {
|
|||||||
byte[] data = DataSourceUtil.readExactly(dataSource, /* length= */ 1);
|
byte[] data = DataSourceUtil.readExactly(dataSource, /* length= */ 1);
|
||||||
// TODO: Decide what the allowed behavior should be for the next read, and assert it.
|
// TODO: Decide what the allowed behavior should be for the next read, and assert it.
|
||||||
|
|
||||||
// The DataSource.open() contract requires the returned length to equal the length in the
|
// The DataSource.open() contract requires the returned length to equal the length in
|
||||||
// DataSpec if set. This is true even though the DataSource implementation may know that
|
// the DataSpec if set. This is true even though the DataSource implementation may know
|
||||||
// fewer bytes will be read in this case.
|
// that fewer bytes will be read in this case.
|
||||||
assertThat(length).isEqualTo(2);
|
assertThat(length).isEqualTo(2);
|
||||||
byte[] expectedData =
|
byte[] expectedData =
|
||||||
Arrays.copyOfRange(resource.getExpectedBytes(), resourceLength - 1, resourceLength);
|
Arrays.copyOfRange(resource.getExpectedBytes(), resourceLength - 1, resourceLength);
|
||||||
@ -343,8 +321,7 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -354,13 +331,8 @@ public abstract class DataSourceContractTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void unboundedDataSpecWithGzipFlag_readUntilEnd() throws Exception {
|
public void unboundedDataSpecWithGzipFlag_readUntilEnd() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
long length =
|
long length =
|
||||||
dataSource.open(
|
dataSource.open(
|
||||||
@ -380,24 +352,18 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void uriSchemeIsCaseInsensitive() throws Exception {
|
public void uriSchemeIsCaseInsensitive() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
@Nullable String scheme = resource.getUri().getScheme();
|
@Nullable String scheme = resource.getUri().getScheme();
|
||||||
if (scheme == null) {
|
if (scheme == null) {
|
||||||
// No scheme for which to check case-insensitivity.
|
// No scheme for which to check case-insensitivity.
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
Uri uri =
|
Uri uri =
|
||||||
resource
|
resource
|
||||||
.getUri()
|
.getUri()
|
||||||
@ -418,25 +384,22 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resourceNotFound() throws Exception {
|
public void resourceNotFound() throws Exception {
|
||||||
DataSource dataSource = createDataSource();
|
forAllDataSources(
|
||||||
|
dataSource -> {
|
||||||
assertThrows(IOException.class, () -> dataSource.open(new DataSpec(getNotFoundUri())));
|
assertThrows(IOException.class, () -> dataSource.open(new DataSpec(getNotFoundUri())));
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transferListenerCallbacks() throws Exception {
|
public void transferListenerCallbacks() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
FakeTransferListener listener = spy(new FakeTransferListener());
|
FakeTransferListener listener = spy(new FakeTransferListener());
|
||||||
dataSource.addTransferListener(listener);
|
dataSource.addTransferListener(listener);
|
||||||
InOrder inOrder = Mockito.inOrder(listener);
|
InOrder inOrder = Mockito.inOrder(listener);
|
||||||
@ -447,15 +410,16 @@ public abstract class DataSourceContractTest {
|
|||||||
DataSpec reportedDataSpec = null;
|
DataSpec reportedDataSpec = null;
|
||||||
boolean reportedNetwork = false;
|
boolean reportedNetwork = false;
|
||||||
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSpec dataSpec = new DataSpec.Builder().setUri(resource.getUri()).build();
|
DataSpec dataSpec = new DataSpec.Builder().setUri(resource.getUri()).build();
|
||||||
try {
|
try {
|
||||||
dataSource.open(dataSpec);
|
dataSource.open(dataSpec);
|
||||||
|
|
||||||
// Verify onTransferInitializing() and onTransferStart() have been called exactly from
|
// Verify onTransferInitializing() and onTransferStart() have been called exactly from
|
||||||
// DataSource.open().
|
// DataSource.open().
|
||||||
ArgumentCaptor<DataSpec> dataSpecArgumentCaptor = ArgumentCaptor.forClass(DataSpec.class);
|
ArgumentCaptor<DataSpec> dataSpecArgumentCaptor =
|
||||||
ArgumentCaptor<Boolean> isNetworkArgumentCaptor = ArgumentCaptor.forClass(Boolean.class);
|
ArgumentCaptor.forClass(DataSpec.class);
|
||||||
|
ArgumentCaptor<Boolean> isNetworkArgumentCaptor =
|
||||||
|
ArgumentCaptor.forClass(Boolean.class);
|
||||||
inOrder
|
inOrder
|
||||||
.verify(listener)
|
.verify(listener)
|
||||||
.onTransferInitializing(
|
.onTransferInitializing(
|
||||||
@ -474,8 +438,8 @@ public abstract class DataSourceContractTest {
|
|||||||
} else {
|
} else {
|
||||||
DataSourceUtil.readToEnd(dataSource);
|
DataSourceUtil.readToEnd(dataSource);
|
||||||
}
|
}
|
||||||
// Verify sufficient onBytesTransferred() callbacks have been triggered before closing the
|
// Verify sufficient onBytesTransferred() callbacks have been triggered before closing
|
||||||
// DataSource.
|
// the DataSource.
|
||||||
assertThat(listener.bytesTransferred).isAtLeast(resource.getExpectedBytes().length);
|
assertThat(listener.bytesTransferred).isAtLeast(resource.getExpectedBytes().length);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
@ -485,13 +449,13 @@ public abstract class DataSourceContractTest {
|
|||||||
.onTransferEnd(callbackSource, castNonNull(reportedDataSpec), reportedNetwork);
|
.onTransferEnd(callbackSource, castNonNull(reportedDataSpec), reportedNetwork);
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resourceNotFound_transferListenerCallbacks() throws Exception {
|
public void resourceNotFound_transferListenerCallbacks() throws Exception {
|
||||||
DataSource dataSource = createDataSource();
|
forAllDataSources(
|
||||||
|
dataSource -> {
|
||||||
TransferListener listener = mock(TransferListener.class);
|
TransferListener listener = mock(TransferListener.class);
|
||||||
dataSource.addTransferListener(listener);
|
dataSource.addTransferListener(listener);
|
||||||
@Nullable DataSource callbackSource = getTransferListenerDataSource();
|
@Nullable DataSource callbackSource = getTransferListenerDataSource();
|
||||||
@ -507,17 +471,13 @@ public abstract class DataSourceContractTest {
|
|||||||
|
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
verifyNoMoreInteractions(listener);
|
verifyNoMoreInteractions(listener);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getUri_returnsNonNullValueOnlyWhileOpen() throws Exception {
|
public void getUri_returnsNonNullValueOnlyWhileOpen() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
assertThat(dataSource.getUri()).isNull();
|
assertThat(dataSource.getUri()).isNull();
|
||||||
|
|
||||||
@ -528,32 +488,26 @@ public abstract class DataSourceContractTest {
|
|||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
assertThat(dataSource.getUri()).isNull();
|
assertThat(dataSource.getUri()).isNull();
|
||||||
|
});
|
||||||
additionalFailureInfo.setInfo(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getUri_resourceNotFound_returnsNullIfNotOpened() throws Exception {
|
public void getUri_resourceNotFound_returnsNullIfNotOpened() throws Exception {
|
||||||
DataSource dataSource = createDataSource();
|
forAllDataSources(
|
||||||
|
dataSource -> {
|
||||||
assertThat(dataSource.getUri()).isNull();
|
assertThat(dataSource.getUri()).isNull();
|
||||||
|
|
||||||
assertThrows(IOException.class, () -> dataSource.open(new DataSpec(getNotFoundUri())));
|
assertThrows(IOException.class, () -> dataSource.open(new DataSpec(getNotFoundUri())));
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
|
|
||||||
assertThat(dataSource.getUri()).isNull();
|
assertThat(dataSource.getUri()).isNull();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResponseHeaders_noNullKeysOrValues() throws Exception {
|
public void getResponseHeaders_noNullKeysOrValues() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
dataSource.open(new DataSpec(resource.getUri()));
|
dataSource.open(new DataSpec(resource.getUri()));
|
||||||
|
|
||||||
@ -566,19 +520,13 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResponseHeaders_caseInsensitive() throws Exception {
|
public void getResponseHeaders_caseInsensitive() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
dataSource.open(new DataSpec(resource.getUri()));
|
dataSource.open(new DataSpec(resource.getUri()));
|
||||||
|
|
||||||
@ -592,19 +540,13 @@ public abstract class DataSourceContractTest {
|
|||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
additionalFailureInfo.setInfo(null);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResponseHeaders_isEmptyWhileNotOpen() throws Exception {
|
public void getResponseHeaders_isEmptyWhileNotOpen() throws Exception {
|
||||||
ImmutableList<TestResource> resources = getTestResources();
|
forAllTestResourcesAndDataSources(
|
||||||
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
(resource, dataSource) -> {
|
||||||
|
|
||||||
for (int i = 0; i < resources.size(); i++) {
|
|
||||||
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
|
||||||
TestResource resource = resources.get(i);
|
|
||||||
DataSource dataSource = createDataSource();
|
|
||||||
try {
|
try {
|
||||||
assertThat(dataSource.getResponseHeaders()).isEmpty();
|
assertThat(dataSource.getResponseHeaders()).isEmpty();
|
||||||
|
|
||||||
@ -613,34 +555,99 @@ public abstract class DataSourceContractTest {
|
|||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
assertThat(dataSource.getResponseHeaders()).isEmpty();
|
assertThat(dataSource.getResponseHeaders()).isEmpty();
|
||||||
|
});
|
||||||
additionalFailureInfo.setInfo(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getResponseHeaders_resourceNotFound_isEmptyWhileNotOpen() throws Exception {
|
public void getResponseHeaders_resourceNotFound_isEmptyWhileNotOpen() throws Exception {
|
||||||
DataSource dataSource = createDataSource();
|
forAllDataSources(
|
||||||
|
dataSource -> {
|
||||||
assertThat(dataSource.getResponseHeaders()).isEmpty();
|
assertThat(dataSource.getResponseHeaders()).isEmpty();
|
||||||
|
|
||||||
assertThrows(IOException.class, () -> dataSource.open(new DataSpec(getNotFoundUri())));
|
assertThrows(IOException.class, () -> dataSource.open(new DataSpec(getNotFoundUri())));
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
|
|
||||||
assertThat(dataSource.getResponseHeaders()).isEmpty();
|
assertThat(dataSource.getResponseHeaders()).isEmpty();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build a label to make it clear which resource caused a given test failure. */
|
private interface TestResourceAndDataSourceTest {
|
||||||
private static String getFailureLabel(List<TestResource> resources, int i) {
|
void run(TestResource resource, DataSource dataSource) throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface DataSourceTest {
|
||||||
|
void run(DataSource dataSource) throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forAllTestResourcesAndDataSources(TestResourceAndDataSourceTest test)
|
||||||
|
throws Exception {
|
||||||
|
ImmutableList<TestResource> resources = getTestResources();
|
||||||
|
Assertions.checkArgument(!resources.isEmpty(), "Must provide at least one test resource.");
|
||||||
|
for (int i = 0; i < resources.size(); i++) {
|
||||||
|
List<DataSource> dataSources = createDataSourcesInternal();
|
||||||
|
for (int j = 0; j < dataSources.size(); j++) {
|
||||||
|
additionalFailureInfo.setInfo(getFailureLabel(resources, i, dataSources, j));
|
||||||
|
test.run(resources.get(i), dataSources.get(j));
|
||||||
|
additionalFailureInfo.setInfo(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forAllDataSources(DataSourceTest test) throws Exception {
|
||||||
|
List<DataSource> dataSources = createDataSourcesInternal();
|
||||||
|
for (int i = 0; i < dataSources.size(); i++) {
|
||||||
|
additionalFailureInfo.setInfo(getDataSourceLabel(dataSources, i));
|
||||||
|
test.run(dataSources.get(i));
|
||||||
|
additionalFailureInfo.setInfo(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DataSource> createDataSourcesInternal() throws Exception {
|
||||||
|
try {
|
||||||
|
List<DataSource> dataSources = createDataSources();
|
||||||
|
checkState(!dataSources.isEmpty(), "Must provide at least on DataSource");
|
||||||
|
assertThrows(UnsupportedOperationException.class, this::createDataSource);
|
||||||
|
return dataSources;
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
// Expected if createDataSources is not implemented.
|
||||||
|
return ImmutableList.of(createDataSource());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build a label to make it clear which resource and data source caused a given test failure. */
|
||||||
|
private static String getFailureLabel(
|
||||||
|
List<TestResource> resources,
|
||||||
|
int resourceIndex,
|
||||||
|
List<DataSource> dataSources,
|
||||||
|
int dataSourceIndex) {
|
||||||
|
String resourceLabel = getResourceLabel(resources, resourceIndex);
|
||||||
|
String dataSourceLabel = getDataSourceLabel(dataSources, dataSourceIndex);
|
||||||
|
if (resourceLabel.isEmpty()) {
|
||||||
|
return dataSourceLabel;
|
||||||
|
} else if (dataSourceLabel.isEmpty()) {
|
||||||
|
return resourceLabel;
|
||||||
|
} else {
|
||||||
|
return dataSourceLabel + ", " + resourceLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getResourceLabel(List<TestResource> resources, int resourceIndex) {
|
||||||
if (resources.size() == 1) {
|
if (resources.size() == 1) {
|
||||||
return "";
|
return "";
|
||||||
} else if (resources.get(i).getName() != null) {
|
} else if (resources.get(resourceIndex).getName() != null) {
|
||||||
return "resource name: " + resources.get(i).getName();
|
return "resource name: " + resources.get(resourceIndex).getName();
|
||||||
} else {
|
} else {
|
||||||
return String.format("resource[%s]", i);
|
return String.format("resource[%s]", resourceIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getDataSourceLabel(List<DataSource> dataSources, int dataSourceIndex) {
|
||||||
|
if (dataSources.size() == 1) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return String.format("dataSource[%s]", dataSourceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
private static String invertAsciiCaseOfEveryOtherCharacter(String input) {
|
private static String invertAsciiCaseOfEveryOtherCharacter(String input) {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
for (int i = 0; i < input.length(); i++) {
|
for (int i = 0; i < input.length(); i++) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user