Commit 68191926 by olly Committed by Andrew Lewis

Clean up CacheDataSourceTest

PiperOrigin-RevId: 222965111
parent aacb212c
...@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.CacheAsserts; import com.google.android.exoplayer2.testutil.CacheAsserts;
import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData; import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData;
...@@ -47,21 +48,29 @@ public final class CacheDataSourceTest { ...@@ -47,21 +48,29 @@ public final class CacheDataSourceTest {
private static final byte[] TEST_DATA = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; private static final byte[] TEST_DATA = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
private static final int MAX_CACHE_FILE_SIZE = 3; private static final int MAX_CACHE_FILE_SIZE = 3;
private static final String CACHE_KEY_PREFIX = "myCacheKeyFactoryPrefix"; private static final String DATASPEC_KEY = "dataSpecKey";
private Uri testDataUri; private Uri testDataUri;
private String fixedCacheKey; private DataSpec unboundedDataSpec;
private String expectedCacheKey; private DataSpec boundedDataSpec;
private DataSpec unboundedDataSpecWithKey;
private DataSpec boundedDataSpecWithKey;
private String defaultCacheKey;
private String customCacheKey;
private CacheKeyFactory cacheKeyFactory;
private File tempFolder; private File tempFolder;
private SimpleCache cache; private SimpleCache cache;
private CacheKeyFactory cacheKeyFactory;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
testDataUri = Uri.parse("test_data"); testDataUri = Uri.parse("https://www.test.com/data");
fixedCacheKey = CacheUtil.generateKey(testDataUri); unboundedDataSpec = buildDataSpec(/* unbounded= */ true, /* key= */ null);
expectedCacheKey = fixedCacheKey; boundedDataSpec = buildDataSpec(/* unbounded= */ false, /* key= */ null);
cacheKeyFactory = dataSpec -> CACHE_KEY_PREFIX + "." + CacheUtil.generateKey(dataSpec.uri); unboundedDataSpecWithKey = buildDataSpec(/* unbounded= */ true, DATASPEC_KEY);
boundedDataSpecWithKey = buildDataSpec(/* unbounded= */ false, DATASPEC_KEY);
defaultCacheKey = CacheUtil.DEFAULT_CACHE_KEY_FACTORY.buildCacheKey(unboundedDataSpec);
customCacheKey = "customKey." + defaultCacheKey;
cacheKeyFactory = dataSpec -> customCacheKey;
tempFolder = Util.createTempDirectory(RuntimeEnvironment.application, "ExoPlayerTest"); tempFolder = Util.createTempDirectory(RuntimeEnvironment.application, "ExoPlayerTest");
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor()); cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
} }
...@@ -74,7 +83,7 @@ public final class CacheDataSourceTest { ...@@ -74,7 +83,7 @@ public final class CacheDataSourceTest {
@Test @Test
public void testMaxCacheFileSize() throws Exception { public void testMaxCacheFileSize() throws Exception {
CacheDataSource cacheDataSource = createCacheDataSource(false, false); CacheDataSource cacheDataSource = createCacheDataSource(false, false);
assertReadDataContentLength(cacheDataSource, false, false); assertReadDataContentLength(cacheDataSource, boundedDataSpec, false, false);
for (String key : cache.getKeys()) { for (String key : cache.getKeys()) {
for (CacheSpan cacheSpan : cache.getCachedSpans(key)) { for (CacheSpan cacheSpan : cache.getCachedSpans(key)) {
assertThat(cacheSpan.length <= MAX_CACHE_FILE_SIZE).isTrue(); assertThat(cacheSpan.length <= MAX_CACHE_FILE_SIZE).isTrue();
...@@ -85,231 +94,180 @@ public final class CacheDataSourceTest { ...@@ -85,231 +94,180 @@ public final class CacheDataSourceTest {
@Test @Test
public void testCacheAndReadUnboundedRequest() throws Exception { public void testCacheAndReadUnboundedRequest() throws Exception {
assertCacheAndRead(/* unboundedRequest= */ true, /* simulateUnknownLength= */ false); assertCacheAndRead(unboundedDataSpec, /* unknownLength= */ false);
} }
@Test @Test
public void testCacheAndReadUnknownLength() throws Exception { public void testCacheAndReadUnknownLength() throws Exception {
assertCacheAndRead(/* unboundedRequest= */ false, /* simulateUnknownLength= */ true); assertCacheAndRead(boundedDataSpec, /* unknownLength= */ true);
} }
@Test @Test
public void testCacheAndReadUnboundedRequestUnknownLength() throws Exception { public void testCacheAndReadUnboundedRequestUnknownLength() throws Exception {
assertCacheAndRead(/* unboundedRequest= */ true, /* simulateUnknownLength= */ true); assertCacheAndRead(unboundedDataSpec, /* unknownLength= */ true);
} }
@Test @Test
public void testCacheAndRead() throws Exception { public void testCacheAndRead() throws Exception {
assertCacheAndRead(/* unboundedRequest= */ false, /* simulateUnknownLength= */ false); assertCacheAndRead(boundedDataSpec, /* unknownLength= */ false);
} }
@Test @Test
public void testUnsatisfiableRange() throws Exception { public void testUnsatisfiableRange() throws Exception {
// Bounded request but the content length is unknown. This forces all data to be cached but not // Bounded request but the content length is unknown. This forces all data to be cached but not
// the length // the length.
assertCacheAndRead(/* unboundedRequest= */ false, /* simulateUnknownLength= */ true); assertCacheAndRead(boundedDataSpec, /* unknownLength= */ true);
// Now do an unbounded request. This will read all of the data from cache and then try to read // Now do an unbounded request. This will read all of the data from cache and then try to read
// more from upstream which will cause to a 416 so CDS will store the length. // more from upstream which will cause to a 416 so CDS will store the length.
CacheDataSource cacheDataSource = CacheDataSource cacheDataSource =
createCacheDataSource(/* setReadException= */ true, /* simulateUnknownLength= */ true); createCacheDataSource(/* setReadException= */ true, /* unknownLength= */ true);
assertReadDataContentLength( assertReadDataContentLength(
cacheDataSource, /* unboundedRequest= */ true, /* unknownLength= */ true); cacheDataSource, unboundedDataSpec, /* unknownLength= */ true, /* customCacheKey= */ false);
// If the user try to access off range then it should throw an IOException // If the user try to access off range then it should throw an IOException.
try { try {
cacheDataSource = cacheDataSource =
createCacheDataSource(/* setReadException= */ false, /* simulateUnknownLength= */ false); createCacheDataSource(/* setReadException= */ false, /* unknownLength= */ false);
cacheDataSource.open(new DataSpec(testDataUri, TEST_DATA.length, 5, fixedCacheKey)); cacheDataSource.open(buildDataSpec(TEST_DATA.length, /* length= */ 1, defaultCacheKey));
fail(); fail();
} catch (IOException e) { } catch (IOException e) {
// success // Expected.
} }
} }
@Test @Test
public void testCacheAndReadUnboundedRequestWithCacheKeyFactoryWithNullDataSpecCacheKey() public void testCacheAndReadUnboundedRequestWithCacheKeyFactoryWithNullDataSpecCacheKey()
throws Exception { throws Exception {
fixedCacheKey = null; assertCacheAndRead(unboundedDataSpec, /* unknownLength= */ false, cacheKeyFactory);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, /* key= */ null));
assertCacheAndRead(
/* unboundedRequest= */ true, /* simulateUnknownLength= */ false, cacheKeyFactory);
} }
@Test @Test
public void testCacheAndReadUnknownLengthWithCacheKeyFactoryOverridingWithNullDataSpecCacheKey() public void testCacheAndReadUnknownLengthWithCacheKeyFactoryOverridingWithNullDataSpecCacheKey()
throws Exception { throws Exception {
fixedCacheKey = null; assertCacheAndRead(boundedDataSpec, /* unknownLength= */ true, cacheKeyFactory);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, /* key= */ null));
assertCacheAndRead(
/* unboundedRequest= */ false, /* simulateUnknownLength= */ true, cacheKeyFactory);
} }
@Test @Test
public void public void
testCacheAndReadUnboundedRequestUnknownLengthWithCacheKeyFactoryWithNullDataSpecCacheKey() testCacheAndReadUnboundedRequestUnknownLengthWithCacheKeyFactoryWithNullDataSpecCacheKey()
throws Exception { throws Exception {
fixedCacheKey = null; assertCacheAndRead(unboundedDataSpec, /* unknownLength= */ true, cacheKeyFactory);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, /* key= */ null));
assertCacheAndRead(
/* unboundedRequest= */ true, /* simulateUnknownLength= */ true, cacheKeyFactory);
} }
@Test @Test
public void testCacheAndReadWithCacheKeyFactoryWithNullDataSpecCacheKey() throws Exception { public void testCacheAndReadWithCacheKeyFactoryWithNullDataSpecCacheKey() throws Exception {
fixedCacheKey = null; assertCacheAndRead(boundedDataSpec, /* unknownLength= */ false, cacheKeyFactory);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, /* key= */ null));
assertCacheAndRead(
/* unboundedRequest= */ false, /* simulateUnknownLength= */ false, cacheKeyFactory);
} }
@Test @Test
public void testUnsatisfiableRangeWithCacheKeyFactoryNullDataSpecCacheKey() throws Exception { public void testUnsatisfiableRangeWithCacheKeyFactoryNullDataSpecCacheKey() throws Exception {
fixedCacheKey = null;
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, /* key= */ null));
// Bounded request but the content length is unknown. This forces all data to be cached but not // Bounded request but the content length is unknown. This forces all data to be cached but not
// the length // the length.
assertCacheAndRead( assertCacheAndRead(boundedDataSpec, /* unknownLength= */ true, cacheKeyFactory);
/* unboundedRequest= */ false, /* simulateUnknownLength= */ true, cacheKeyFactory);
// Now do an unbounded request. This will read all of the data from cache and then try to read // Now do an unbounded request. This will read all of the data from cache and then try to read
// more from upstream which will cause to a 416 so CDS will store the length. // more from upstream which will cause to a 416 so CDS will store the length.
CacheDataSource cacheDataSource = CacheDataSource cacheDataSource =
createCacheDataSource( createCacheDataSource(
/* setReadException= */ true, /* simulateUnknownLength= */ true, cacheKeyFactory); /* setReadException= */ true, /* unknownLength= */ true, cacheKeyFactory);
assertReadDataContentLength( assertReadDataContentLength(
cacheDataSource, /* unboundedRequest= */ true, /* unknownLength= */ true); cacheDataSource, unboundedDataSpec, /* unknownLength= */ true, /* customCacheKey= */ true);
// If the user try to access off range then it should throw an IOException // If the user try to access off range then it should throw an IOException.
try { try {
cacheDataSource = cacheDataSource =
createCacheDataSource( createCacheDataSource(
/* setReadException= */ false, /* simulateUnknownLength= */ false, cacheKeyFactory); /* setReadException= */ false, /* unknownLength= */ false, cacheKeyFactory);
cacheDataSource.open(new DataSpec(testDataUri, TEST_DATA.length, 5, fixedCacheKey)); cacheDataSource.open(buildDataSpec(TEST_DATA.length, /* length= */ 1, customCacheKey));
fail(); fail();
} catch (IOException e) { } catch (IOException e) {
// success // Expected.
} }
} }
@Test @Test
public void testCacheAndReadUnboundedRequestWithCacheKeyFactoryOverridingDataSpecCacheKey() public void testCacheAndReadUnboundedRequestWithCacheKeyFactoryOverridingDataSpecCacheKey()
throws Exception { throws Exception {
fixedCacheKey = CacheUtil.generateKey(testDataUri); assertCacheAndRead(unboundedDataSpecWithKey, false, cacheKeyFactory);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, fixedCacheKey));
assertCacheAndRead(true, false, cacheKeyFactory);
} }
@Test @Test
public void testCacheAndReadUnknownLengthWithCacheKeyFactoryOverridingDataSpecCacheKey() public void testCacheAndReadUnknownLengthWithCacheKeyFactoryOverridingDataSpecCacheKey()
throws Exception { throws Exception {
fixedCacheKey = CacheUtil.generateKey(testDataUri); assertCacheAndRead(boundedDataSpecWithKey, true, cacheKeyFactory);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, fixedCacheKey));
assertCacheAndRead(false, true, cacheKeyFactory);
} }
@Test @Test
public void public void
testCacheAndReadUnboundedRequestUnknownLengthWithCacheKeyFactoryOverridingDataSpecCacheKey() testCacheAndReadUnboundedRequestUnknownLengthWithCacheKeyFactoryOverridingDataSpecCacheKey()
throws Exception { throws Exception {
fixedCacheKey = CacheUtil.generateKey(testDataUri); assertCacheAndRead(unboundedDataSpecWithKey, /* unknownLength= */ true, cacheKeyFactory);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, fixedCacheKey));
assertCacheAndRead(
/* unboundedRequest= */ true, /* simulateUnknownLength= */ true, cacheKeyFactory);
} }
@Test @Test
public void testCacheAndReadWithCacheKeyFactoryOverridingDataSpecCacheKey() throws Exception { public void testCacheAndReadWithCacheKeyFactoryOverridingDataSpecCacheKey() throws Exception {
fixedCacheKey = CacheUtil.generateKey(testDataUri); assertCacheAndRead(boundedDataSpecWithKey, /* unknownLength= */ false, cacheKeyFactory);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, fixedCacheKey));
assertCacheAndRead(
/* unboundedRequest= */ false, /* simulateUnknownLength= */ false, cacheKeyFactory);
} }
@Test @Test
public void testUnsatisfiableRangeWithCacheKeyFactoryOverridingDataSpecCacheKey() public void testUnsatisfiableRangeWithCacheKeyFactoryOverridingDataSpecCacheKey()
throws Exception { throws Exception {
fixedCacheKey = CacheUtil.generateKey(testDataUri);
expectedCacheKey =
cacheKeyFactory.buildCacheKey(
new DataSpec(testDataUri, TEST_DATA.length, 5, fixedCacheKey));
// Bounded request but the content length is unknown. This forces all data to be cached but not // Bounded request but the content length is unknown. This forces all data to be cached but not
// the length // the length.
assertCacheAndRead( assertCacheAndRead(boundedDataSpecWithKey, /* unknownLength= */ true, cacheKeyFactory);
/* unboundedRequest= */ false, /* simulateUnknownLength= */ true, cacheKeyFactory);
// Now do an unbounded request. This will read all of the data from cache and then try to read // Now do an unbounded request. This will read all of the data from cache and then try to read
// more from upstream which will cause to a 416 so CDS will store the length. // more from upstream which will cause to a 416 so CDS will store the length.
CacheDataSource cacheDataSource = CacheDataSource cacheDataSource =
createCacheDataSource( createCacheDataSource(
/* setReadException= */ true, /* simulateUnknownLength= */ true, cacheKeyFactory); /* setReadException= */ true, /* unknownLength= */ true, cacheKeyFactory);
assertReadDataContentLength( assertReadDataContentLength(
cacheDataSource, /* unboundedRequest= */ true, /* unknownLength= */ true); cacheDataSource,
unboundedDataSpecWithKey,
/* unknownLength= */ true,
/* customCacheKey= */ true);
// If the user try to access off range then it should throw an IOException // If the user try to access off range then it should throw an IOException.
try { try {
cacheDataSource = cacheDataSource =
createCacheDataSource( createCacheDataSource(
/* setReadException= */ false, /* simulateUnknownLength= */ false, cacheKeyFactory); /* setReadException= */ false, /* unknownLength= */ false, cacheKeyFactory);
cacheDataSource.open(new DataSpec(testDataUri, TEST_DATA.length, 5, fixedCacheKey)); cacheDataSource.open(buildDataSpec(TEST_DATA.length, /* length= */ 1, customCacheKey));
fail(); fail();
} catch (IOException e) { } catch (IOException e) {
// success // Expected.
} }
} }
@Test @Test
public void testContentLengthEdgeCases() throws Exception { public void testContentLengthEdgeCases() throws Exception {
// Read partial at EOS but don't cross it so length is unknown DataSpec dataSpec = buildDataSpec(TEST_DATA.length - 2, 2);
// Read partial at EOS but don't cross it so length is unknown.
CacheDataSource cacheDataSource = createCacheDataSource(false, true); CacheDataSource cacheDataSource = createCacheDataSource(false, true);
assertReadData(cacheDataSource, true, TEST_DATA.length - 2, 2); assertReadData(cacheDataSource, dataSpec, true);
assertThat(cache.getContentLength(expectedCacheKey)).isEqualTo(C.LENGTH_UNSET); assertThat(cache.getContentLength(defaultCacheKey)).isEqualTo(C.LENGTH_UNSET);
// Now do an unbounded request for whole data. This will cause a bounded request from upstream. // Now do an unbounded request for whole data. This will cause a bounded request from upstream.
// End of data from upstream shouldn't be mixed up with EOS and cause length set wrong. // End of data from upstream shouldn't be mixed up with EOS and cause length set wrong.
cacheDataSource = createCacheDataSource(false, true); cacheDataSource = createCacheDataSource(false, true);
assertReadDataContentLength(cacheDataSource, true, true); assertReadDataContentLength(cacheDataSource, unboundedDataSpec, true, false);
// Now the length set correctly do an unbounded request with offset // Now the length set correctly do an unbounded request with offset.
assertThat( assertThat(
cacheDataSource.open( cacheDataSource.open(
new DataSpec(testDataUri, TEST_DATA.length - 2, C.LENGTH_UNSET, expectedCacheKey))) buildDataSpec(TEST_DATA.length - 2, C.LENGTH_UNSET, defaultCacheKey)))
.isEqualTo(2); .isEqualTo(2);
// An unbounded request with offset for not cached content // An unbounded request with offset for not cached content.
assertThat( dataSpec =
cacheDataSource.open( new DataSpec(
new DataSpec( Uri.parse("https://www.test.com/other"),
Uri.parse("notCachedUri"), TEST_DATA.length - 2, C.LENGTH_UNSET, null))) TEST_DATA.length - 2,
.isEqualTo(C.LENGTH_UNSET); C.LENGTH_UNSET,
/* key= */ null);
assertThat(cacheDataSource.open(dataSpec)).isEqualTo(C.LENGTH_UNSET);
} }
@Test @Test
...@@ -322,13 +280,12 @@ public final class CacheDataSourceTest { ...@@ -322,13 +280,12 @@ public final class CacheDataSourceTest {
.setSimulateUnknownLength(true); .setSimulateUnknownLength(true);
CacheDataSource cacheDataSource = new CacheDataSource(cache, upstream, 0); CacheDataSource cacheDataSource = new CacheDataSource(cache, upstream, 0);
int flags = DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH; cacheDataSource.open(unboundedDataSpec);
cacheDataSource.open(new DataSpec(testDataUri, 0, C.LENGTH_UNSET, expectedCacheKey, flags));
TestUtil.readToEnd(cacheDataSource); TestUtil.readToEnd(cacheDataSource);
cacheDataSource.close(); cacheDataSource.close();
assertThat(upstream.getAndClearOpenedDataSpecs()).hasLength(1); assertThat(upstream.getAndClearOpenedDataSpecs()).hasLength(1);
assertThat(cache.getContentLength(expectedCacheKey)).isEqualTo(TEST_DATA.length); assertThat(cache.getContentLength(defaultCacheKey)).isEqualTo(TEST_DATA.length);
} }
@Test @Test
...@@ -339,7 +296,7 @@ public final class CacheDataSourceTest { ...@@ -339,7 +296,7 @@ public final class CacheDataSourceTest {
new CacheDataSource( new CacheDataSource(
cache, upstream, CacheDataSource.FLAG_IGNORE_CACHE_FOR_UNSET_LENGTH_REQUESTS); cache, upstream, CacheDataSource.FLAG_IGNORE_CACHE_FOR_UNSET_LENGTH_REQUESTS);
cacheDataSource.open(new DataSpec(testDataUri, 0, C.LENGTH_UNSET, expectedCacheKey)); cacheDataSource.open(unboundedDataSpec);
TestUtil.readToEnd(cacheDataSource); TestUtil.readToEnd(cacheDataSource);
cacheDataSource.close(); cacheDataSource.close();
...@@ -349,7 +306,7 @@ public final class CacheDataSourceTest { ...@@ -349,7 +306,7 @@ public final class CacheDataSourceTest {
@Test @Test
public void testReadOnlyCache() throws Exception { public void testReadOnlyCache() throws Exception {
CacheDataSource cacheDataSource = createCacheDataSource(false, false, 0, null); CacheDataSource cacheDataSource = createCacheDataSource(false, false, 0, null);
assertReadDataContentLength(cacheDataSource, false, false); assertReadDataContentLength(cacheDataSource, boundedDataSpec, false, false);
assertCacheEmpty(cache); assertCacheEmpty(cache);
} }
...@@ -368,13 +325,11 @@ public final class CacheDataSourceTest { ...@@ -368,13 +325,11 @@ public final class CacheDataSourceTest {
new CacheDataSource(cache, upstream, new FileDataSource(), null, 0, null); new CacheDataSource(cache, upstream, new FileDataSource(), null, 0, null);
// Open source and read some data from upstream as the data hasn't cached yet. // Open source and read some data from upstream as the data hasn't cached yet.
DataSpec dataSpec = new DataSpec(testDataUri, 0, C.LENGTH_UNSET, fixedCacheKey); cacheDataSource.open(unboundedDataSpec);
cacheDataSource.open(dataSpec);
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
cacheDataSource.read(buffer, 0, buffer.length); cacheDataSource.read(buffer, 0, buffer.length);
// Cache the data. // Cache the data. Although we use another FakeDataSource instance, it shouldn't matter.
// Although we use another FakeDataSource instance, it shouldn't matter.
FakeDataSource upstream2 = FakeDataSource upstream2 =
new FakeDataSource( new FakeDataSource(
new FakeDataSource() new FakeDataSource()
...@@ -382,7 +337,8 @@ public final class CacheDataSourceTest { ...@@ -382,7 +337,8 @@ public final class CacheDataSourceTest {
.newDefaultData() .newDefaultData()
.appendReadData(1024 * 1024) .appendReadData(1024 * 1024)
.endData()); .endData());
CacheUtil.cache(dataSpec, cache, upstream2, /* counters= */ null, /* isCanceled= */ null); CacheUtil.cache(
unboundedDataSpec, cache, upstream2, /* counters= */ null, /* isCanceled= */ null);
// Read the rest of the data. // Read the rest of the data.
TestUtil.readToEnd(cacheDataSource); TestUtil.readToEnd(cacheDataSource);
...@@ -401,7 +357,7 @@ public final class CacheDataSourceTest { ...@@ -401,7 +357,7 @@ public final class CacheDataSourceTest {
.appendReadData(1); .appendReadData(1);
// Lock the content on the cache. // Lock the content on the cache.
SimpleCacheSpan cacheSpan = cache.startReadWriteNonBlocking(expectedCacheKey, 0); SimpleCacheSpan cacheSpan = cache.startReadWriteNonBlocking(defaultCacheKey, 0);
assertThat(cacheSpan).isNotNull(); assertThat(cacheSpan).isNotNull();
assertThat(cacheSpan.isHoleSpan()).isTrue(); assertThat(cacheSpan.isHoleSpan()).isTrue();
...@@ -409,8 +365,7 @@ public final class CacheDataSourceTest { ...@@ -409,8 +365,7 @@ public final class CacheDataSourceTest {
CacheDataSource cacheDataSource = new CacheDataSource(cache, upstream, 0); CacheDataSource cacheDataSource = new CacheDataSource(cache, upstream, 0);
// Open source and read some data from upstream without writing to cache as the data is locked. // Open source and read some data from upstream without writing to cache as the data is locked.
DataSpec dataSpec = new DataSpec(testDataUri, 0, C.LENGTH_UNSET, fixedCacheKey); cacheDataSource.open(unboundedDataSpec);
cacheDataSource.open(dataSpec);
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
cacheDataSource.read(buffer, 0, buffer.length); cacheDataSource.read(buffer, 0, buffer.length);
...@@ -418,8 +373,7 @@ public final class CacheDataSourceTest { ...@@ -418,8 +373,7 @@ public final class CacheDataSourceTest {
cache.releaseHoleSpan(cacheSpan); cache.releaseHoleSpan(cacheSpan);
assertCacheEmpty(cache); assertCacheEmpty(cache);
// Cache the data. // Cache the data. Although we use another FakeDataSource instance, it shouldn't matter.
// Although we use another FakeDataSource instance, it shouldn't matter.
FakeDataSource upstream2 = FakeDataSource upstream2 =
new FakeDataSource( new FakeDataSource(
new FakeDataSource() new FakeDataSource()
...@@ -427,7 +381,8 @@ public final class CacheDataSourceTest { ...@@ -427,7 +381,8 @@ public final class CacheDataSourceTest {
.newDefaultData() .newDefaultData()
.appendReadData(1024 * 1024) .appendReadData(1024 * 1024)
.endData()); .endData());
CacheUtil.cache(dataSpec, cache, upstream2, /* counters= */ null, /* isCanceled= */ null); CacheUtil.cache(
unboundedDataSpec, cache, upstream2, /* counters= */ null, /* isCanceled= */ null);
// Read the rest of the data. // Read the rest of the data.
TestUtil.readToEnd(cacheDataSource); TestUtil.readToEnd(cacheDataSource);
...@@ -439,10 +394,12 @@ public final class CacheDataSourceTest { ...@@ -439,10 +394,12 @@ public final class CacheDataSourceTest {
throws Exception { throws Exception {
// Create a fake data source with a 1 KB default data. // Create a fake data source with a 1 KB default data.
FakeDataSource upstream = new FakeDataSource(); FakeDataSource upstream = new FakeDataSource();
upstream.getDataSet().newDefaultData().appendReadData(1024).endData(); int dataLength = 1024;
upstream.getDataSet().newDefaultData().appendReadData(dataLength).endData();
// Cache the latter half of the data. // Cache the latter half of the data.
DataSpec dataSpec = new DataSpec(testDataUri, 512, C.LENGTH_UNSET, fixedCacheKey); int halfDataLength = 512;
DataSpec dataSpec = buildDataSpec(halfDataLength, C.LENGTH_UNSET);
CacheUtil.cache(dataSpec, cache, upstream, /* counters= */ null, /* isCanceled= */ null); CacheUtil.cache(dataSpec, cache, upstream, /* counters= */ null, /* isCanceled= */ null);
// Create cache read-only CacheDataSource. // Create cache read-only CacheDataSource.
...@@ -450,12 +407,11 @@ public final class CacheDataSourceTest { ...@@ -450,12 +407,11 @@ public final class CacheDataSourceTest {
new CacheDataSource(cache, upstream, new FileDataSource(), null, 0, null); new CacheDataSource(cache, upstream, new FileDataSource(), null, 0, null);
// Open source and read some data from upstream as the data hasn't cached yet. // Open source and read some data from upstream as the data hasn't cached yet.
dataSpec = new DataSpec(testDataUri, 0, C.LENGTH_UNSET, fixedCacheKey); cacheDataSource.open(unboundedDataSpec);
cacheDataSource.open(dataSpec);
TestUtil.readExactly(cacheDataSource, 100); TestUtil.readExactly(cacheDataSource, 100);
// Delete cached data. // Delete cached data.
CacheUtil.remove(cache, expectedCacheKey); CacheUtil.remove(cache, defaultCacheKey);
assertCacheEmpty(cache); assertCacheEmpty(cache);
// Read the rest of the data. // Read the rest of the data.
...@@ -473,21 +429,20 @@ public final class CacheDataSourceTest { ...@@ -473,21 +429,20 @@ public final class CacheDataSourceTest {
// Cache the latter half of the data. // Cache the latter half of the data.
int halfDataLength = 512; int halfDataLength = 512;
DataSpec dataSpec = new DataSpec(testDataUri, halfDataLength, C.LENGTH_UNSET, fixedCacheKey); DataSpec dataSpec = buildDataSpec(/* position= */ 0, halfDataLength);
CacheUtil.cache(dataSpec, cache, upstream, /* counters= */ null, /* isCanceled= */ null); CacheUtil.cache(dataSpec, cache, upstream, /* counters= */ null, /* isCanceled= */ null);
// Create blocking CacheDataSource. // Create blocking CacheDataSource.
CacheDataSource cacheDataSource = CacheDataSource cacheDataSource =
new CacheDataSource(cache, upstream, CacheDataSource.FLAG_BLOCK_ON_CACHE); new CacheDataSource(cache, upstream, CacheDataSource.FLAG_BLOCK_ON_CACHE);
dataSpec = new DataSpec(testDataUri, 0, C.LENGTH_UNSET, fixedCacheKey); cacheDataSource.open(unboundedDataSpec);
cacheDataSource.open(dataSpec);
// Read the first half from upstream as it hasn't cached yet. // Read the first half from upstream as it hasn't cached yet.
TestUtil.readExactly(cacheDataSource, halfDataLength); TestUtil.readExactly(cacheDataSource, halfDataLength);
// Delete the cached latter half. // Delete the cached latter half.
NavigableSet<CacheSpan> cachedSpans = cache.getCachedSpans(expectedCacheKey); NavigableSet<CacheSpan> cachedSpans = cache.getCachedSpans(defaultCacheKey);
for (CacheSpan cachedSpan : cachedSpans) { for (CacheSpan cachedSpan : cachedSpans) {
if (cachedSpan.position >= halfDataLength) { if (cachedSpan.position >= halfDataLength) {
try { try {
...@@ -503,115 +458,106 @@ public final class CacheDataSourceTest { ...@@ -503,115 +458,106 @@ public final class CacheDataSourceTest {
cacheDataSource.close(); cacheDataSource.close();
} }
private void assertCacheAndRead(boolean unboundedRequest, boolean simulateUnknownLength) private void assertCacheAndRead(DataSpec dataSpec, boolean unknownLength) throws IOException {
throws IOException { assertCacheAndRead(dataSpec, unknownLength, /* cacheKeyFactory= */ null);
// Read all data from upstream and write to cache
CacheDataSource cacheDataSource = createCacheDataSource(false, simulateUnknownLength);
assertReadDataContentLength(cacheDataSource, unboundedRequest, simulateUnknownLength);
// Just read from cache
cacheDataSource = createCacheDataSource(true, simulateUnknownLength);
assertReadDataContentLength(
cacheDataSource,
unboundedRequest,
// Length is already cached.
/* unknownLength= */ false);
} }
private void assertCacheAndRead( private void assertCacheAndRead(
boolean unboundedRequest, boolean simulateUnknownLength, CacheKeyFactory cacheKeyFactory) DataSpec dataSpec, boolean unknownLength, @Nullable CacheKeyFactory cacheKeyFactory)
throws IOException { throws IOException {
// Read all data from upstream and write to cache // Read all data from upstream and write to cache.
CacheDataSource cacheDataSource = CacheDataSource cacheDataSource =
createCacheDataSource( createCacheDataSource(/* setReadException= */ false, unknownLength, cacheKeyFactory);
/* setReadException= */ false, simulateUnknownLength, cacheKeyFactory); assertReadDataContentLength(cacheDataSource, dataSpec, unknownLength, cacheKeyFactory != null);
assertReadDataContentLength(cacheDataSource, unboundedRequest, simulateUnknownLength);
// Just read from cache // Just read from cache.
cacheDataSource = cacheDataSource =
createCacheDataSource(/* setReadException= */ true, simulateUnknownLength, cacheKeyFactory); createCacheDataSource(/* setReadException= */ true, unknownLength, cacheKeyFactory);
assertReadDataContentLength( assertReadDataContentLength(
cacheDataSource, cacheDataSource,
unboundedRequest, dataSpec,
// Length is already cached. /* unknownLength= */ false,
/* unknownLength= */ false); /* customCacheKey= */ cacheKeyFactory != null);
} }
/** /**
* Reads data until EOI and compares it to {@link #TEST_DATA}. Also checks content length returned * Reads data until EOI and compares it to {@link #TEST_DATA}. Also checks content length returned
* from open() call and the cached content length. * from open() call and the cached content length.
*/ */
private void assertReadDataContentLength(CacheDataSource cacheDataSource, private void assertReadDataContentLength(
boolean unboundedRequest, boolean unknownLength) throws IOException { CacheDataSource cacheDataSource,
int length = unboundedRequest ? C.LENGTH_UNSET : TEST_DATA.length; DataSpec dataSpec,
assertReadData(cacheDataSource, unknownLength, 0, length); boolean unknownLength,
// If !unboundedRequest, CacheDataSource doesn't reach EOS so shouldn't cache content length boolean customCacheKey)
assertThat(cache.getContentLength(expectedCacheKey)) throws IOException {
.isEqualTo(!unboundedRequest ? C.LENGTH_UNSET : TEST_DATA.length); assertReadData(cacheDataSource, dataSpec, unknownLength);
} // If the request was unbounded then the content length should be cached, either because the
// content length was known or because EOS was read. If the request was bounded then the content
private void assertReadData(CacheDataSource cacheDataSource, boolean unknownLength, int position, // length will not have been determined.
int length) throws IOException { assertThat(cache.getContentLength(customCacheKey ? this.customCacheKey : defaultCacheKey))
int testDataLength = TEST_DATA.length - position; .isEqualTo(dataSpec.length == C.LENGTH_UNSET ? TEST_DATA.length : C.LENGTH_UNSET);
if (length != C.LENGTH_UNSET) { }
testDataLength = Math.min(testDataLength, length);
private void assertReadData(
CacheDataSource cacheDataSource, DataSpec dataSpec, boolean unknownLength)
throws IOException {
int position = (int) dataSpec.absoluteStreamPosition;
int requestLength = (int) dataSpec.length;
int readLength = TEST_DATA.length - position;
if (requestLength != C.LENGTH_UNSET) {
readLength = Math.min(readLength, requestLength);
} }
DataSpec dataSpec = assertThat(cacheDataSource.open(dataSpec))
new DataSpec( .isEqualTo(unknownLength ? requestLength : readLength);
testDataUri,
position,
length,
fixedCacheKey,
DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH);
assertThat(cacheDataSource.open(dataSpec)).isEqualTo(unknownLength ? length : testDataLength);
cacheDataSource.close(); cacheDataSource.close();
byte[] expected = Arrays.copyOfRange(TEST_DATA, position, position + testDataLength); byte[] expected = Arrays.copyOfRange(TEST_DATA, position, position + readLength);
CacheAsserts.assertReadData(cacheDataSource, dataSpec, expected); CacheAsserts.assertReadData(cacheDataSource, dataSpec, expected);
} }
private CacheDataSource createCacheDataSource(boolean setReadException, private CacheDataSource createCacheDataSource(boolean setReadException, boolean unknownLength) {
boolean simulateUnknownLength) { return createCacheDataSource(
return createCacheDataSource(setReadException, simulateUnknownLength, setReadException, unknownLength, CacheDataSource.FLAG_BLOCK_ON_CACHE);
CacheDataSource.FLAG_BLOCK_ON_CACHE);
} }
private CacheDataSource createCacheDataSource( private CacheDataSource createCacheDataSource(
boolean setReadException, boolean simulateUnknownLength, CacheKeyFactory cacheKeyFactory) { boolean setReadException, boolean unknownLength, CacheKeyFactory cacheKeyFactory) {
return createCacheDataSource( return createCacheDataSource(
setReadException, setReadException,
simulateUnknownLength, unknownLength,
CacheDataSource.FLAG_BLOCK_ON_CACHE, CacheDataSource.FLAG_BLOCK_ON_CACHE,
new CacheDataSink(cache, MAX_CACHE_FILE_SIZE), new CacheDataSink(cache, MAX_CACHE_FILE_SIZE),
cacheKeyFactory); cacheKeyFactory);
} }
private CacheDataSource createCacheDataSource(boolean setReadException, private CacheDataSource createCacheDataSource(
boolean simulateUnknownLength, @CacheDataSource.Flags int flags) { boolean setReadException, boolean unknownLength, @CacheDataSource.Flags int flags) {
return createCacheDataSource(setReadException, simulateUnknownLength, flags, return createCacheDataSource(
new CacheDataSink(cache, MAX_CACHE_FILE_SIZE)); setReadException, unknownLength, flags, new CacheDataSink(cache, MAX_CACHE_FILE_SIZE));
} }
private CacheDataSource createCacheDataSource(boolean setReadException, private CacheDataSource createCacheDataSource(
boolean simulateUnknownLength, @CacheDataSource.Flags int flags, boolean setReadException,
boolean unknownLength,
@CacheDataSource.Flags int flags,
CacheDataSink cacheWriteDataSink) { CacheDataSink cacheWriteDataSink) {
return createCacheDataSource( return createCacheDataSource(
setReadException, setReadException, unknownLength, flags, cacheWriteDataSink, /* cacheKeyFactory= */ null);
simulateUnknownLength,
flags,
cacheWriteDataSink,
/* cacheKeyFactory= */ null);
} }
private CacheDataSource createCacheDataSource( private CacheDataSource createCacheDataSource(
boolean setReadException, boolean setReadException,
boolean simulateUnknownLength, boolean unknownLength,
@CacheDataSource.Flags int flags, @CacheDataSource.Flags int flags,
CacheDataSink cacheWriteDataSink, CacheDataSink cacheWriteDataSink,
CacheKeyFactory cacheKeyFactory) { CacheKeyFactory cacheKeyFactory) {
FakeDataSource upstream = new FakeDataSource(); FakeDataSource upstream = new FakeDataSource();
FakeData fakeData = upstream.getDataSet().newDefaultData() FakeData fakeData =
.setSimulateUnknownLength(simulateUnknownLength).appendReadData(TEST_DATA); upstream
.getDataSet()
.newDefaultData()
.setSimulateUnknownLength(unknownLength)
.appendReadData(TEST_DATA);
if (setReadException) { if (setReadException) {
fakeData.appendReadError(new IOException("Shouldn't read from upstream")); fakeData.appendReadError(new IOException("Shouldn't read from upstream"));
} }
...@@ -625,4 +571,16 @@ public final class CacheDataSourceTest { ...@@ -625,4 +571,16 @@ public final class CacheDataSourceTest {
cacheKeyFactory); cacheKeyFactory);
} }
private DataSpec buildDataSpec(boolean unbounded, @Nullable String key) {
return buildDataSpec(/* position= */ 0, unbounded ? C.LENGTH_UNSET : TEST_DATA.length, key);
}
private DataSpec buildDataSpec(long position, long length) {
return buildDataSpec(position, length, /* key= */ null);
}
private DataSpec buildDataSpec(long position, long length, @Nullable String key) {
return new DataSpec(
testDataUri, position, length, key, DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH);
}
} }
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 sign in to comment