diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java index a81d7ffdc2..1203758e71 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java @@ -19,7 +19,6 @@ import com.google.android.exoplayer2.offline.DownloadAction.UnsupportedActionExc import com.google.android.exoplayer2.util.AtomicFile; import com.google.android.exoplayer2.util.Util; import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -30,8 +29,7 @@ import java.util.ArrayList; */ public final class ActionFile { - private static final String TAG = "ActionFile"; - /* package */ static final int VERSION = 0; + private static final int VERSION = 0; private final AtomicFile atomicFile; @@ -75,29 +73,6 @@ public final class ActionFile { } } - /** - * Stores {@link DownloadAction}s to file. - * - * @param downloadActions DownloadActions to store to file. - * @throws IOException If there is an error during storing. - */ - public void store(DownloadAction... downloadActions) throws IOException { - DataOutputStream output = null; - try { - output = new DataOutputStream(atomicFile.startWrite()); - output.writeInt(VERSION); - output.writeInt(downloadActions.length); - for (DownloadAction action : downloadActions) { - action.serializeToStream(output); - } - atomicFile.endWrite(output); - // Avoid calling close twice. - output = null; - } finally { - Util.closeQuietly(output); - } - } - /** Returns whether the file or its backup exists. */ public boolean exists() { return atomicFile.exists(); diff --git a/library/core/src/test/assets/offline/action_file_for_download_index_upgrade.exi b/library/core/src/test/assets/offline/action_file_for_download_index_upgrade.exi new file mode 100644 index 0000000000..888ba4af44 Binary files /dev/null and b/library/core/src/test/assets/offline/action_file_for_download_index_upgrade.exi differ diff --git a/library/core/src/test/assets/offline/action_file_incomplete_header.exi b/library/core/src/test/assets/offline/action_file_incomplete_header.exi new file mode 100644 index 0000000000..593f4708db Binary files /dev/null and b/library/core/src/test/assets/offline/action_file_incomplete_header.exi differ diff --git a/library/core/src/test/assets/offline/action_file_no_data.exi b/library/core/src/test/assets/offline/action_file_no_data.exi new file mode 100644 index 0000000000..e69de29bb2 diff --git a/library/core/src/test/assets/offline/action_file_one_action.exi b/library/core/src/test/assets/offline/action_file_one_action.exi new file mode 100644 index 0000000000..a196d8a322 Binary files /dev/null and b/library/core/src/test/assets/offline/action_file_one_action.exi differ diff --git a/library/core/src/test/assets/offline/action_file_two_actions.exi b/library/core/src/test/assets/offline/action_file_two_actions.exi new file mode 100644 index 0000000000..35c9b35e1e Binary files /dev/null and b/library/core/src/test/assets/offline/action_file_two_actions.exi differ diff --git a/library/core/src/test/assets/offline/action_file_unsupported_version.exi b/library/core/src/test/assets/offline/action_file_unsupported_version.exi new file mode 100644 index 0000000000..25e0dee842 Binary files /dev/null and b/library/core/src/test/assets/offline/action_file_unsupported_version.exi differ diff --git a/library/core/src/test/assets/offline/action_file_zero_actions.exi b/library/core/src/test/assets/offline/action_file_zero_actions.exi new file mode 100644 index 0000000000..1b1cb4d44c Binary files /dev/null and b/library/core/src/test/assets/offline/action_file_zero_actions.exi differ diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/ActionFileTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/ActionFileTest.java index 9d1a6093fc..0d38337dfb 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/ActionFileTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/ActionFileTest.java @@ -22,7 +22,6 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.util.Util; -import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -38,22 +37,16 @@ import org.junit.runner.RunWith; public class ActionFileTest { private File tempFile; - private DownloadAction action1; - private DownloadAction action2; + private DownloadAction expectedAction1; + private DownloadAction expectedAction2; @Before public void setUp() throws Exception { tempFile = Util.createTempFile(ApplicationProvider.getApplicationContext(), "ExoPlayerTest"); - action1 = - buildAction( - DownloadAction.TYPE_PROGRESSIVE, - Uri.parse("http://test1.uri"), - TestUtil.buildTestData(16)); - action2 = - buildAction( - DownloadAction.TYPE_PROGRESSIVE, - Uri.parse("http://test2.uri"), - TestUtil.buildTestData(32)); + expectedAction1 = + buildExpectedAction(Uri.parse("http://test1.uri"), TestUtil.buildTestData(16)); + expectedAction2 = + buildExpectedAction(Uri.parse("http://test2.uri"), TestUtil.buildTestData(32)); } @After @@ -63,8 +56,9 @@ public class ActionFileTest { @Test public void testLoadNoDataThrowsIOException() throws Exception { + ActionFile actionFile = getActionFile("offline/action_file_no_data.exi"); try { - loadActions(new Object[] {}); + actionFile.load(); Assert.fail(); } catch (IOException e) { // Expected exception. @@ -73,8 +67,9 @@ public class ActionFileTest { @Test public void testLoadIncompleteHeaderThrowsIOException() throws Exception { + ActionFile actionFile = getActionFile("offline/action_file_incomplete_header.exi"); try { - loadActions(new Object[] {ActionFile.VERSION}); + actionFile.load(); Assert.fail(); } catch (IOException e) { // Expected exception. @@ -82,95 +77,59 @@ public class ActionFileTest { } @Test - public void testLoadCompleteHeaderZeroAction() throws Exception { - DownloadAction[] actions = loadActions(new Object[] {ActionFile.VERSION, 0}); + public void testLoadZeroActions() throws Exception { + ActionFile actionFile = getActionFile("offline/action_file_zero_actions.exi"); + DownloadAction[] actions = actionFile.load(); assertThat(actions).isNotNull(); assertThat(actions).hasLength(0); } @Test - public void testLoadAction() throws Exception { - DownloadAction[] actions = - loadActions( - new Object[] { - ActionFile.VERSION, - 1, // Action count - action1 - }); - assertThat(actions).isNotNull(); + public void testLoadOneAction() throws Exception { + ActionFile actionFile = getActionFile("offline/action_file_one_action.exi"); + DownloadAction[] actions = actionFile.load(); assertThat(actions).hasLength(1); - assertThat(actions[0]).isEqualTo(action1); + assertThat(actions[0]).isEqualTo(expectedAction1); } @Test - public void testLoadActions() throws Exception { - DownloadAction[] actions = - loadActions( - new Object[] { - ActionFile.VERSION, - 2, // Action count - action1, - action2, - }); - assertThat(actions).isNotNull(); + public void testLoadTwoActions() throws Exception { + ActionFile actionFile = getActionFile("offline/action_file_two_actions.exi"); + DownloadAction[] actions = actionFile.load(); assertThat(actions).hasLength(2); - assertThat(actions[0]).isEqualTo(action1); - assertThat(actions[1]).isEqualTo(action2); + assertThat(actions[0]).isEqualTo(expectedAction1); + assertThat(actions[1]).isEqualTo(expectedAction2); } @Test - public void testLoadNotSupportedVersion() throws Exception { + public void testLoadUnsupportedVersion() throws Exception { + ActionFile actionFile = getActionFile("offline/action_file_unsupported_version.exi"); try { - loadActions( - new Object[] { - ActionFile.VERSION + 1, - 1, // Action count - action1, - }); + actionFile.load(); Assert.fail(); } catch (IOException e) { // Expected exception. } } - @Test - public void testStoreAndLoadNoActions() throws Exception { - doTestSerializationRoundTrip(); - } - - @Test - public void testStoreAndLoadActions() throws Exception { - doTestSerializationRoundTrip(action1, action2); - } - - private void doTestSerializationRoundTrip(DownloadAction... actions) throws IOException { - ActionFile actionFile = new ActionFile(tempFile); - actionFile.store(actions); - assertThat(actionFile.load()).isEqualTo(actions); - } - - // TODO: Remove this method and add assets for invalid and legacy serialized action files. - private DownloadAction[] loadActions(Object[] values) throws IOException { - FileOutputStream fileOutputStream = new FileOutputStream(tempFile); - DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); - try { - for (Object value : values) { - if (value instanceof Integer) { - dataOutputStream.writeInt((Integer) value); - } else if (value instanceof DownloadAction) { - ((DownloadAction) value).serializeToStream(dataOutputStream); - } else { - throw new IllegalArgumentException(); - } - } - } finally { - dataOutputStream.close(); + private ActionFile getActionFile(String fileName) throws IOException { + // Copy the test data from the asset to where the ActionFile expects it to be. + byte[] actionFileBytes = + TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), fileName); + try (FileOutputStream output = new FileOutputStream(tempFile)) { + output.write(actionFileBytes); } - return new ActionFile(tempFile).load(); + // Load the action file. + return new ActionFile(tempFile); } - private static DownloadAction buildAction(String type, Uri uri, byte[] data) { + private static DownloadAction buildExpectedAction(Uri uri, byte[] data) { return DownloadAction.createDownloadAction( - "id", type, uri, /* keys= */ Collections.emptyList(), /* customCacheKey= */ null, data); + /* id= */ uri.toString(), + DownloadAction.TYPE_PROGRESSIVE, + uri, + /* keys= */ Collections.emptyList(), + /* customCacheKey= */ null, + data); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadIndexUtilTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadIndexUtilTest.java index b752d83bf0..17f3d38ba1 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadIndexUtilTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadIndexUtilTest.java @@ -22,8 +22,10 @@ import android.net.Uri; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.database.ExoDatabaseProvider; +import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.util.Util; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -110,39 +112,45 @@ public class DownloadIndexUtilTest { @Test public void upgradeActionFile_createsDownloadStates() throws IOException { - ActionFile actionFile = new ActionFile(tempFile); - StreamKey streamKey1 = + // Copy the test asset to a file. + byte[] actionFileBytes = + TestUtil.getByteArray( + ApplicationProvider.getApplicationContext(), + "offline/action_file_for_download_index_upgrade.exi"); + try (FileOutputStream output = new FileOutputStream(tempFile)) { + output.write(actionFileBytes); + } + + StreamKey expectedStreamKey1 = new StreamKey(/* periodIndex= */ 3, /* groupIndex= */ 4, /* trackIndex= */ 5); - StreamKey streamKey2 = + StreamKey expectedStreamKey2 = new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 1, /* trackIndex= */ 2); - DownloadAction action1 = + DownloadAction expectedAction1 = DownloadAction.createDownloadAction( - "id1", + "key123", TYPE_DASH, Uri.parse("https://www.test.com/download1"), - asList(streamKey1), + asList(expectedStreamKey1), /* customCacheKey= */ "key123", new byte[] {1, 2, 3, 4}); - DownloadAction action2 = + DownloadAction expectedAction2 = DownloadAction.createDownloadAction( - "id2", + "key234", TYPE_DASH, Uri.parse("https://www.test.com/download2"), - asList(streamKey2), + asList(expectedStreamKey2), /* customCacheKey= */ "key234", new byte[] {5, 4, 3, 2, 1}); - actionFile.store(action1, action2); + ActionFile actionFile = new ActionFile(tempFile); DownloadIndexUtil.upgradeActionFile(actionFile, downloadIndex, /* downloadIdProvider= */ null); - - assertDownloadIndexContainsAction(action1, DownloadState.STATE_QUEUED); - assertDownloadIndexContainsAction(action2, DownloadState.STATE_QUEUED); + assertDownloadIndexContainsAction(expectedAction1, DownloadState.STATE_QUEUED); + assertDownloadIndexContainsAction(expectedAction2, DownloadState.STATE_QUEUED); } private void assertDownloadIndexContainsAction(DownloadAction action, int state) throws IOException { DownloadState downloadState = downloadIndex.getDownloadState(action.id); - assertThat(downloadState).isNotNull(); assertThat(downloadState.type).isEqualTo(action.type); assertThat(downloadState.cacheKey).isEqualTo(action.customCacheKey); assertThat(downloadState.customMetadata).isEqualTo(action.data);