Contract test for TransferListener callbacks
PiperOrigin-RevId: 357190780
This commit is contained in:
parent
b303eceafd
commit
086d8f3a8e
@ -28,6 +28,7 @@ dependencies {
|
|||||||
androidTestImplementation 'androidx.test:rules:' + androidxTestRulesVersion
|
androidTestImplementation 'androidx.test:rules:' + androidxTestRulesVersion
|
||||||
androidTestImplementation 'androidx.test:runner:' + androidxTestRunnerVersion
|
androidTestImplementation 'androidx.test:runner:' + androidxTestRunnerVersion
|
||||||
androidTestImplementation 'androidx.multidex:multidex:' + androidxMultidexVersion
|
androidTestImplementation 'androidx.multidex:multidex:' + androidxMultidexVersion
|
||||||
|
androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito:' + dexmakerVersion
|
||||||
// Instrumentation tests assume that an app-packaged version of cronet is
|
// Instrumentation tests assume that an app-packaged version of cronet is
|
||||||
// available.
|
// available.
|
||||||
androidTestImplementation 'org.chromium.net:cronet-embedded:72.3626.96'
|
androidTestImplementation 'org.chromium.net:cronet-embedded:72.3626.96'
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.upstream;
|
package com.google.android.exoplayer2.upstream;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
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.android.exoplayer2.testutil.DataSourceContractTest;
|
import com.google.android.exoplayer2.testutil.DataSourceContractTest;
|
||||||
@ -42,12 +43,14 @@ public class CacheDataSourceContractTest extends DataSourceContractTest {
|
|||||||
@Rule public final TemporaryFolder tempFolder = new TemporaryFolder();
|
@Rule public final TemporaryFolder tempFolder = new TemporaryFolder();
|
||||||
|
|
||||||
private Uri simpleUri;
|
private Uri simpleUri;
|
||||||
|
private FileDataSource fileDataSource;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws IOException {
|
public void setUp() throws IOException {
|
||||||
File file = tempFolder.newFile();
|
File file = tempFolder.newFile();
|
||||||
Files.write(Paths.get(file.getAbsolutePath()), DATA);
|
Files.write(Paths.get(file.getAbsolutePath()), DATA);
|
||||||
simpleUri = Uri.fromFile(file);
|
simpleUri = Uri.fromFile(file);
|
||||||
|
fileDataSource = new FileDataSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -71,6 +74,12 @@ public class CacheDataSourceContractTest extends DataSourceContractTest {
|
|||||||
Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
|
Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
|
||||||
SimpleCache cache =
|
SimpleCache cache =
|
||||||
new SimpleCache(tempFolder, new NoOpCacheEvictor(), TestUtil.getInMemoryDatabaseProvider());
|
new SimpleCache(tempFolder, new NoOpCacheEvictor(), TestUtil.getInMemoryDatabaseProvider());
|
||||||
return new CacheDataSource(cache, new FileDataSource());
|
return new CacheDataSource(cache, fileDataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected DataSource getTransferListenerDataSource() {
|
||||||
|
return fileDataSource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,11 @@ package com.google.android.exoplayer2.testutil;
|
|||||||
|
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
|
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -26,6 +29,7 @@ import androidx.annotation.RequiresApi;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
@ -36,6 +40,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of contract tests for {@link DataSource} implementations.
|
* A collection of contract tests for {@link DataSource} implementations.
|
||||||
@ -59,6 +66,15 @@ public abstract class DataSourceContractTest {
|
|||||||
/** Creates and returns an instance of the {@link DataSource}. */
|
/** Creates and returns an instance of the {@link DataSource}. */
|
||||||
protected abstract DataSource createDataSource() throws Exception;
|
protected abstract DataSource createDataSource() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link DataSource} that will be included in the {@link TransferListener} callbacks
|
||||||
|
* if different from the {@link DataSource} under test, otherwise null.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
protected DataSource getTransferListenerDataSource() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link TestResource} instances.
|
* Returns {@link TestResource} instances.
|
||||||
*
|
*
|
||||||
@ -241,6 +257,66 @@ public abstract class DataSourceContractTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void transferListenerCallbacks() 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++) {
|
||||||
|
additionalFailureInfo.setInfo(getFailureLabel(resources, i));
|
||||||
|
DataSource dataSource = createDataSource();
|
||||||
|
FakeTransferListener listener = spy(new FakeTransferListener());
|
||||||
|
dataSource.addTransferListener(listener);
|
||||||
|
InOrder inOrder = Mockito.inOrder(listener);
|
||||||
|
@Nullable DataSource callbackSource = getTransferListenerDataSource();
|
||||||
|
if (callbackSource == null) {
|
||||||
|
callbackSource = dataSource;
|
||||||
|
}
|
||||||
|
DataSpec reportedDataSpec = null;
|
||||||
|
boolean reportedNetwork = false;
|
||||||
|
|
||||||
|
TestResource resource = resources.get(i);
|
||||||
|
DataSpec dataSpec = new DataSpec.Builder().setUri(resource.getUri()).build();
|
||||||
|
try {
|
||||||
|
dataSource.open(dataSpec);
|
||||||
|
|
||||||
|
// Verify onTransferInitializing() and onTransferStart() have been called exactly after
|
||||||
|
// DataSource.open().
|
||||||
|
ArgumentCaptor<DataSpec> dataSpecArgumentCaptor = ArgumentCaptor.forClass(DataSpec.class);
|
||||||
|
ArgumentCaptor<Boolean> isNetworkArgumentCaptor = ArgumentCaptor.forClass(Boolean.class);
|
||||||
|
inOrder
|
||||||
|
.verify(listener)
|
||||||
|
.onTransferInitializing(
|
||||||
|
eq(callbackSource),
|
||||||
|
dataSpecArgumentCaptor.capture(),
|
||||||
|
isNetworkArgumentCaptor.capture());
|
||||||
|
reportedDataSpec = dataSpecArgumentCaptor.getValue();
|
||||||
|
reportedNetwork = isNetworkArgumentCaptor.getValue();
|
||||||
|
inOrder
|
||||||
|
.verify(listener)
|
||||||
|
.onTransferStart(callbackSource, castNonNull(reportedDataSpec), reportedNetwork);
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
if (resource.isEndOfInputExpected()) {
|
||||||
|
Util.readToEnd(dataSource);
|
||||||
|
} else {
|
||||||
|
Util.readExactly(dataSource, resource.getExpectedBytes().length);
|
||||||
|
}
|
||||||
|
// Verify sufficient onBytesTransferred() callbacks have been triggered before closing the
|
||||||
|
// DataSource.
|
||||||
|
assertThat(listener.bytesTransferred).isEqualTo(resource.getExpectedBytes().length);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
dataSource.close();
|
||||||
|
inOrder
|
||||||
|
.verify(listener)
|
||||||
|
.onTransferEnd(callbackSource, castNonNull(reportedDataSpec), reportedNetwork);
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
}
|
||||||
|
additionalFailureInfo.setInfo(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Build a label to make it clear which resource caused a given test failure. */
|
/** Build a label to make it clear which resource caused a given test failure. */
|
||||||
private static String getFailureLabel(List<TestResource> resources, int i) {
|
private static String getFailureLabel(List<TestResource> resources, int i) {
|
||||||
if (resources.size() == 1) {
|
if (resources.size() == 1) {
|
||||||
@ -344,4 +420,24 @@ public abstract class DataSourceContractTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A {@link TransferListener} that only keeps track of the transferred bytes. */
|
||||||
|
public static class FakeTransferListener implements TransferListener {
|
||||||
|
private int bytesTransferred;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTransferInitializing(DataSource source, DataSpec dataSpec, boolean isNetwork) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTransferStart(DataSource source, DataSpec dataSpec, boolean isNetwork) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBytesTransferred(
|
||||||
|
DataSource source, DataSpec dataSpec, boolean isNetwork, int bytesTransferred) {
|
||||||
|
this.bytesTransferred += bytesTransferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTransferEnd(DataSource source, DataSpec dataSpec, boolean isNetwork) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user