diff --git a/library/core/src/main/java/com/google/android/exoplayer2/database/VersionTable.java b/library/core/src/main/java/com/google/android/exoplayer2/database/VersionTable.java index c01e16e03a..e0a4210136 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/database/VersionTable.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/database/VersionTable.java @@ -31,7 +31,7 @@ import java.lang.annotation.RetentionPolicy; */ public final class VersionTable { - /** Returned by {@link #getVersion(SQLiteDatabase, int)} if the version is unset. */ + /** Returned by {@link #getVersion(SQLiteDatabase, int, String)} if the version is unset. */ public static final int VERSION_UNSET = -1; /** Version of tables used for offline functionality. */ public static final int FEATURE_OFFLINE = 0; @@ -43,18 +43,26 @@ public final class VersionTable { private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Versions"; private static final String COLUMN_FEATURE = "feature"; + private static final String COLUMN_INSTANCE_UID = "instance_uid"; private static final String COLUMN_VERSION = "version"; - private static final String WHERE_FEATURE_EQUALS = COLUMN_FEATURE + " = ?"; + private static final String WHERE_FEATURE_AND_INSTANCE_UID_EQUALS = + COLUMN_FEATURE + " = ? AND " + COLUMN_INSTANCE_UID + " = ?"; + private static final String PRIMARY_KEY = + "PRIMARY KEY (" + COLUMN_FEATURE + ", " + COLUMN_INSTANCE_UID + ")"; private static final String SQL_CREATE_TABLE_IF_NOT_EXISTS = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + COLUMN_FEATURE - + " INTEGER PRIMARY KEY NOT NULL," + + " INTEGER NOT NULL," + + COLUMN_INSTANCE_UID + + " TEXT NOT NULL," + COLUMN_VERSION - + " INTEGER NOT NULL)"; + + " INTEGER NOT NULL," + + PRIMARY_KEY + + ")"; @Documented @Retention(RetentionPolicy.SOURCE) @@ -64,42 +72,51 @@ public final class VersionTable { private VersionTable() {} /** - * Sets the version of the specified feature. + * Sets the version of a specified instance of a specified feature. * * @param writableDatabase The database to update. * @param feature The feature. + * @param instanceUid The unique identifier of the instance of the feature. * @param version The version. */ public static void setVersion( - SQLiteDatabase writableDatabase, @Feature int feature, int version) { + SQLiteDatabase writableDatabase, @Feature int feature, String instanceUid, int version) { writableDatabase.execSQL(SQL_CREATE_TABLE_IF_NOT_EXISTS); ContentValues values = new ContentValues(); values.put(COLUMN_FEATURE, feature); + values.put(COLUMN_INSTANCE_UID, instanceUid); values.put(COLUMN_VERSION, version); writableDatabase.replace(TABLE_NAME, /* nullColumnHack= */ null, values); } /** - * Removes the version of the specified feature. + * Removes the version of a specified instance of a feature. * * @param writableDatabase The database to update. * @param feature The feature. + * @param instanceUid The unique identifier of the instance of the feature. */ - public static void removeVersion(SQLiteDatabase writableDatabase, @Feature int feature) { + public static void removeVersion( + SQLiteDatabase writableDatabase, @Feature int feature, String instanceUid) { if (!tableExists(writableDatabase, TABLE_NAME)) { return; } - writableDatabase.delete(TABLE_NAME, WHERE_FEATURE_EQUALS, featureArgument(feature)); + writableDatabase.delete( + TABLE_NAME, + WHERE_FEATURE_AND_INSTANCE_UID_EQUALS, + featureAndInstanceUidArguments(feature, instanceUid)); } /** - * Returns the version of the specified feature, or {@link #VERSION_UNSET} if no version - * information is available. + * Returns the version of a specified instance of a feature, or {@link #VERSION_UNSET} if no + * version is set. * * @param database The database to query. * @param feature The feature. + * @param instanceUid The unique identifier of the instance of the feature. + * @return The version, or {@link #VERSION_UNSET} if no version is set. */ - public static int getVersion(SQLiteDatabase database, @Feature int feature) { + public static int getVersion(SQLiteDatabase database, @Feature int feature, String instanceUid) { if (!tableExists(database, TABLE_NAME)) { return VERSION_UNSET; } @@ -107,8 +124,8 @@ public final class VersionTable { database.query( TABLE_NAME, new String[] {COLUMN_VERSION}, - WHERE_FEATURE_EQUALS, - featureArgument(feature), + WHERE_FEATURE_AND_INSTANCE_UID_EQUALS, + featureAndInstanceUidArguments(feature, instanceUid), /* groupBy= */ null, /* having= */ null, /* orderBy= */ null)) { @@ -128,7 +145,7 @@ public final class VersionTable { return count > 0; } - private static String[] featureArgument(int feature) { - return new String[] {Integer.toString(feature)}; + private static String[] featureAndInstanceUidArguments(int feature, String instance) { + return new String[] {Integer.toString(feature), instance}; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java index a6dd4131d3..f224258495 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java @@ -37,6 +37,8 @@ public final class DefaultDownloadIndex implements DownloadIndex { @VisibleForTesting /* package */ static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Downloads"; + // TODO: Support multiple instances. Probably using the underlying cache UID. + @VisibleForTesting /* package */ static final String INSTANCE_UID = "singleton"; @VisibleForTesting /* package */ static final int TABLE_VERSION = 1; private static final String COLUMN_ID = "id"; @@ -218,12 +220,14 @@ public final class DefaultDownloadIndex implements DownloadIndex { return; } SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase(); - int version = VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE); + int version = + VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID); if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) { SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); writableDatabase.beginTransaction(); try { - VersionTable.setVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, TABLE_VERSION); + VersionTable.setVersion( + writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID, TABLE_VERSION); writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS); writableDatabase.execSQL(SQL_CREATE_TABLE); writableDatabase.setTransactionSuccessful(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheFileMetadataIndex.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheFileMetadataIndex.java index 96213b4bbc..a370311939 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheFileMetadataIndex.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheFileMetadataIndex.java @@ -20,14 +20,16 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.VersionTable; +import com.google.android.exoplayer2.util.Assertions; import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** Maintains an index of cache file metadata. */ /* package */ final class CacheFileMetadataIndex { - private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "CacheFileMetadata"; + private static final String TABLE_PREFIX = DatabaseProvider.TABLE_PREFIX + "CacheFileMetadata"; private static final int TABLE_VERSION = 1; private static final String COLUMN_NAME = "name"; @@ -44,12 +46,8 @@ import java.util.Set; new String[] { COLUMN_NAME, COLUMN_LENGTH, COLUMN_LAST_ACCESS_TIMESTAMP, }; - - private static final String SQL_DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS " + TABLE_NAME; - private static final String SQL_CREATE_TABLE = - "CREATE TABLE " - + TABLE_NAME - + " (" + private static final String TABLE_SCHEMA = + "(" + COLUMN_NAME + " TEXT PRIMARY KEY NOT NULL," + COLUMN_LENGTH @@ -59,18 +57,42 @@ import java.util.Set; private final DatabaseProvider databaseProvider; - private boolean initialized; + @MonotonicNonNull private String tableName; public CacheFileMetadataIndex(DatabaseProvider databaseProvider) { this.databaseProvider = databaseProvider; } + /** Initializes the index for the given cache UID. */ + public void initialize(long uid) { + String hexUid = Long.toHexString(uid); + tableName = TABLE_PREFIX + hexUid; + SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase(); + int version = + VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_CACHE_FILE_METADATA, hexUid); + if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) { + SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); + writableDatabase.beginTransaction(); + try { + VersionTable.setVersion( + writableDatabase, VersionTable.FEATURE_CACHE_FILE_METADATA, hexUid, TABLE_VERSION); + writableDatabase.execSQL("DROP TABLE IF EXISTS " + tableName); + writableDatabase.execSQL("CREATE TABLE " + tableName + " " + TABLE_SCHEMA); + writableDatabase.setTransactionSuccessful(); + } finally { + writableDatabase.endTransaction(); + } + } else if (version < TABLE_VERSION) { + // There is no previous version currently. + throw new IllegalStateException(); + } + } + /** * Returns all file metadata keyed by file name. The returned map is mutable and may be modified * by the caller. */ public Map getAll() { - ensureInitialized(); try (Cursor cursor = getCursor()) { Map fileMetadata = new HashMap<>(cursor.getCount()); while (cursor.moveToNext()) { @@ -91,13 +113,13 @@ import java.util.Set; * @param lastAccessTimestamp The file last access timestamp. */ public void set(String name, long length, long lastAccessTimestamp) { - ensureInitialized(); + Assertions.checkNotNull(tableName); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(COLUMN_NAME, name); values.put(COLUMN_LENGTH, length); values.put(COLUMN_LAST_ACCESS_TIMESTAMP, lastAccessTimestamp); - writableDatabase.replace(TABLE_NAME, /* nullColumnHack= */ null, values); + writableDatabase.replace(tableName, /* nullColumnHack= */ null, values); } /** @@ -106,9 +128,9 @@ import java.util.Set; * @param name The name of the file whose metadata is to be removed. */ public void remove(String name) { - ensureInitialized(); + Assertions.checkNotNull(tableName); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); - writableDatabase.delete(TABLE_NAME, WHERE_NAME_EQUALS, new String[] {name}); + writableDatabase.delete(tableName, WHERE_NAME_EQUALS, new String[] {name}); } /** @@ -117,12 +139,12 @@ import java.util.Set; * @param names The names of the files whose metadata is to be removed. */ public void removeAll(Set names) { - ensureInitialized(); + Assertions.checkNotNull(tableName); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); writableDatabase.beginTransaction(); try { for (String name : names) { - writableDatabase.delete(TABLE_NAME, WHERE_NAME_EQUALS, new String[] {name}); + writableDatabase.delete(tableName, WHERE_NAME_EQUALS, new String[] {name}); } writableDatabase.setTransactionSuccessful(); } finally { @@ -130,37 +152,12 @@ import java.util.Set; } } - private void ensureInitialized() { - if (initialized) { - return; - } - SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase(); - int version = - VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_CACHE_FILE_METADATA); - if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) { - SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); - writableDatabase.beginTransaction(); - try { - VersionTable.setVersion( - writableDatabase, VersionTable.FEATURE_CACHE_FILE_METADATA, TABLE_VERSION); - writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS); - writableDatabase.execSQL(SQL_CREATE_TABLE); - writableDatabase.setTransactionSuccessful(); - } finally { - writableDatabase.endTransaction(); - } - } else if (version < TABLE_VERSION) { - // There is no previous version currently. - throw new IllegalStateException(); - } - initialized = true; - } - private Cursor getCursor() { + Assertions.checkNotNull(tableName); return databaseProvider .getReadableDatabase() .query( - TABLE_NAME, + tableName, COLUMNS, /* selection */ null, /* selectionArgs= */ null, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java index 3bfed74bf0..6670cee90e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java @@ -159,8 +159,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; } } - /** Loads the index file. */ - public void load() { + /** + * Loads the index file for the given cache UID. + * + * @param uid The UID of the cache whose index is to be loaded. + */ + public void initialize(long uid) { + storage.initialize(uid); + if (previousStorage != null) { + previousStorage.initialize(uid); + } if (!storage.exists() && previousStorage != null && previousStorage.exists()) { // Copy from previous storage into current storage. loadFrom(previousStorage); @@ -383,6 +391,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; /** Interface for the persistent index. */ private interface Storage { + /** Initializes the storage for the given cache UID. */ + void initialize(long uid); + /** Returns whether the persisted index exists. */ boolean exists(); @@ -409,9 +420,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; void storeFully(HashMap content) throws CacheException; /** - * Ensures incremental changes to the index since the last {@link #load()} or {@link - * #storeFully(HashMap)} are persisted. The storage will have been notified of all such changes - * via {@link #onUpdate(CachedContent)} and {@link #onRemove(CachedContent)}. + * Ensures incremental changes to the index since the initial {@link #initialize(long)} or last + * {@link #storeFully(HashMap)} are persisted. The storage will have been notified of all such + * changes via {@link #onUpdate(CachedContent)} and {@link #onRemove(CachedContent)}. * * @param content The key to content map to persist. * @throws CacheException If an error occurs persisting the index. @@ -457,7 +468,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; throw new IllegalStateException(e); // Should never happen. } } else { - Assertions.checkState(!encrypt); + Assertions.checkArgument(!encrypt); } this.encrypt = encrypt; this.cipher = cipher; @@ -466,6 +477,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; atomicFile = new AtomicFile(file); } + @Override + public void initialize(long uid) { + // Do nothing. Legacy storage uses a separate file for each cache. + } + @Override public boolean exists() { return atomicFile.exists(); @@ -665,7 +681,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; /** {@link Storage} implementation that uses an SQL database. */ private static final class DatabaseStorage implements Storage { - private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "CacheContentMetadata"; + private static final String TABLE_PREFIX = DatabaseProvider.TABLE_PREFIX + "CacheIndex"; private static final int TABLE_VERSION = 1; private static final String COLUMN_ID = "id"; @@ -679,12 +695,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; private static final String WHERE_ID_EQUALS = COLUMN_ID + " = ?"; private static final String[] COLUMNS = new String[] {COLUMN_ID, COLUMN_KEY, COLUMN_METADATA}; - - private static final String SQL_DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS " + TABLE_NAME; - private static final String SQL_CREATE_TABLE = - "CREATE TABLE " - + TABLE_NAME - + " (" + private static final String TABLE_SCHEMA = + "(" + COLUMN_ID + " INTEGER PRIMARY KEY NOT NULL," + COLUMN_KEY @@ -695,15 +707,26 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; private final DatabaseProvider databaseProvider; private final SparseArray pendingUpdates; + private String hexUid; + private String tableName; + public DatabaseStorage(DatabaseProvider databaseProvider) { this.databaseProvider = databaseProvider; pendingUpdates = new SparseArray<>(); } + @Override + public void initialize(long uid) { + hexUid = Long.toHexString(uid); + tableName = TABLE_PREFIX + hexUid; + } + @Override public boolean exists() { return VersionTable.getVersion( - databaseProvider.getReadableDatabase(), VersionTable.FEATURE_CACHE_CONTENT_METADATA) + databaseProvider.getReadableDatabase(), + VersionTable.FEATURE_CACHE_CONTENT_METADATA, + hexUid) != VersionTable.VERSION_UNSET; } @@ -712,8 +735,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); writableDatabase.beginTransaction(); try { - VersionTable.removeVersion(writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA); - writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS); + VersionTable.removeVersion( + writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA, hexUid); + dropTable(writableDatabase); writableDatabase.setTransactionSuccessful(); } finally { writableDatabase.endTransaction(); @@ -728,7 +752,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; int version = VersionTable.getVersion( databaseProvider.getReadableDatabase(), - VersionTable.FEATURE_CACHE_CONTENT_METADATA); + VersionTable.FEATURE_CACHE_CONTENT_METADATA, + hexUid); if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) { SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); writableDatabase.beginTransaction(); @@ -821,7 +846,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; return databaseProvider .getReadableDatabase() .query( - TABLE_NAME, + tableName, COLUMNS, /* selection= */ null, /* selectionArgs= */ null, @@ -832,13 +857,17 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; private void initializeTable(SQLiteDatabase writableDatabase) { VersionTable.setVersion( - writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA, TABLE_VERSION); - writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS); - writableDatabase.execSQL(SQL_CREATE_TABLE); + writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA, hexUid, TABLE_VERSION); + dropTable(writableDatabase); + writableDatabase.execSQL("CREATE TABLE " + tableName + " " + TABLE_SCHEMA); + } + + private void dropTable(SQLiteDatabase writableDatabase) { + writableDatabase.execSQL("DROP TABLE IF EXISTS " + tableName); } private void deleteRow(SQLiteDatabase writableDatabase, int key) { - writableDatabase.delete(TABLE_NAME, WHERE_ID_EQUALS, new String[] {Integer.toString(key)}); + writableDatabase.delete(tableName, WHERE_ID_EQUALS, new String[] {Integer.toString(key)}); } private void addOrUpdateRow(SQLiteDatabase writableDatabase, CachedContent cachedContent) @@ -851,7 +880,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; values.put(COLUMN_ID, cachedContent.id); values.put(COLUMN_KEY, cachedContent.key); values.put(COLUMN_METADATA, data); - writableDatabase.replace(TABLE_NAME, /* nullColumnHack= */ null, values); + writableDatabase.replace(tableName, /* nullColumnHack= */ null, values); } } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java index 78e3b405d0..c8e05d21e5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java @@ -254,8 +254,8 @@ public final class SimpleCache implements Cache { } @Override - public synchronized @Nullable SimpleCacheSpan startReadWriteNonBlocking(String key, long position) - throws CacheException { + public synchronized @Nullable SimpleCacheSpan startReadWriteNonBlocking( + String key, long position) { Assertions.checkState(!released); SimpleCacheSpan span = getSpan(key, position); @@ -290,7 +290,7 @@ public final class SimpleCache implements Cache { } @Override - public synchronized File startFile(String key, long position, long length) throws CacheException { + public synchronized File startFile(String key, long position, long length) { Assertions.checkState(!released); CachedContent cachedContent = contentIndex.get(key); Assertions.checkNotNull(cachedContent); @@ -399,7 +399,7 @@ public final class SimpleCache implements Cache { * @param position The position of the span being requested. * @return The corresponding cache {@link SimpleCacheSpan}. */ - private SimpleCacheSpan getSpan(String key, long position) throws CacheException { + private SimpleCacheSpan getSpan(String key, long position) { CachedContent cachedContent = contentIndex.get(key); if (cachedContent == null) { return SimpleCacheSpan.createOpenHole(key, position); @@ -432,9 +432,9 @@ public final class SimpleCache implements Cache { // TODO: Decide how to handle this. } - // TODO: Pass the UID to the index, and use it. - contentIndex.load(); + contentIndex.initialize(uid); if (fileIndex != null) { + fileIndex.initialize(uid); Map fileMetadata = fileIndex.getAll(); loadDirectory(cacheDir, /* isRoot= */ true, files, fileMetadata); fileIndex.removeAll(fileMetadata.keySet()); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/database/VersionTableTest.java b/library/core/src/test/java/com/google/android/exoplayer2/database/VersionTableTest.java index 2e17b25a45..c2d902ebb7 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/database/VersionTableTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/database/VersionTableTest.java @@ -15,77 +15,86 @@ */ package com.google.android.exoplayer2.database; -import static com.google.android.exoplayer2.database.VersionTable.FEATURE_CACHE_CONTENT_METADATA; -import static com.google.android.exoplayer2.database.VersionTable.FEATURE_OFFLINE; import static com.google.common.truth.Truth.assertThat; import android.database.sqlite.SQLiteDatabase; -import org.junit.After; +import com.google.android.exoplayer2.testutil.TestUtil; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; /** Unit tests for {@link VersionTable}. */ @RunWith(RobolectricTestRunner.class) public class VersionTableTest { - private ExoDatabaseProvider databaseProvider; - private SQLiteDatabase readableDatabase; - private SQLiteDatabase writableDatabase; + private static final int FEATURE_1 = 1; + private static final int FEATURE_2 = 2; + private static final String INSTANCE_1 = "1"; + private static final String INSTANCE_2 = "2"; + + private DatabaseProvider databaseProvider; + private SQLiteDatabase database; @Before public void setUp() { - databaseProvider = new ExoDatabaseProvider(RuntimeEnvironment.application); - readableDatabase = databaseProvider.getReadableDatabase(); - writableDatabase = databaseProvider.getWritableDatabase(); - } - - @After - public void tearDown() { - databaseProvider.close(); + databaseProvider = TestUtil.getTestDatabaseProvider(); + database = databaseProvider.getWritableDatabase(); } @Test - public void getVersion_nonExistingTable_returnsVersionUnset() { - int version = VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE); + public void getVersion_unsetFeature_returnsVersionUnset() { + int version = VersionTable.getVersion(database, FEATURE_1, INSTANCE_1); + assertThat(version).isEqualTo(VersionTable.VERSION_UNSET); + } + + @Test + public void getVersion_unsetVersion_returnsVersionUnset() { + VersionTable.setVersion(database, FEATURE_1, INSTANCE_1, 1); + int version = VersionTable.getVersion(database, FEATURE_1, INSTANCE_2); assertThat(version).isEqualTo(VersionTable.VERSION_UNSET); } @Test public void getVersion_returnsSetVersion() { - VersionTable.setVersion(writableDatabase, FEATURE_OFFLINE, 1); - assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)).isEqualTo(1); + VersionTable.setVersion(database, FEATURE_1, INSTANCE_1, 1); + assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(1); - VersionTable.setVersion(writableDatabase, FEATURE_OFFLINE, 10); - assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)).isEqualTo(10); + VersionTable.setVersion(database, FEATURE_1, INSTANCE_1, 2); + assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(2); - VersionTable.setVersion(writableDatabase, FEATURE_CACHE_CONTENT_METADATA, 5); - assertThat(VersionTable.getVersion(readableDatabase, FEATURE_CACHE_CONTENT_METADATA)) - .isEqualTo(5); - assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)).isEqualTo(10); + VersionTable.setVersion(database, FEATURE_2, INSTANCE_1, 3); + assertThat(VersionTable.getVersion(database, FEATURE_2, INSTANCE_1)).isEqualTo(3); + assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(2); + + VersionTable.setVersion(database, FEATURE_2, INSTANCE_2, 4); + assertThat(VersionTable.getVersion(database, FEATURE_2, INSTANCE_2)).isEqualTo(4); + assertThat(VersionTable.getVersion(database, FEATURE_2, INSTANCE_1)).isEqualTo(3); + assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(2); } @Test public void removeVersion_removesSetVersion() { - VersionTable.setVersion(writableDatabase, FEATURE_OFFLINE, 1); - assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)).isEqualTo(1); + VersionTable.setVersion(database, FEATURE_1, INSTANCE_1, 1); + VersionTable.setVersion(database, FEATURE_1, INSTANCE_2, 2); + assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(1); + assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_2)).isEqualTo(2); - VersionTable.removeVersion(writableDatabase, FEATURE_OFFLINE); - assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)) + VersionTable.removeVersion(database, FEATURE_1, INSTANCE_1); + assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)) .isEqualTo(VersionTable.VERSION_UNSET); + assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_2)).isEqualTo(2); } @Test public void doesTableExist_nonExistingTable_returnsFalse() { - assertThat(VersionTable.tableExists(readableDatabase, "NonExistingTable")).isFalse(); + assertThat(VersionTable.tableExists(database, "NonExistingTable")).isFalse(); } @Test public void doesTableExist_existingTable_returnsTrue() { String table = "TestTable"; databaseProvider.getWritableDatabase().execSQL("CREATE TABLE " + table + " (dummy INTEGER)"); - assertThat(VersionTable.tableExists(readableDatabase, table)).isTrue(); + assertThat(VersionTable.tableExists(database, table)).isTrue(); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java index 07254ef7f9..72ef80336b 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.offline; +import static com.google.android.exoplayer2.offline.DefaultDownloadIndex.INSTANCE_UID; import static com.google.common.truth.Truth.assertThat; import android.database.sqlite.SQLiteDatabase; @@ -180,12 +181,14 @@ public class DefaultDownloadIndexTest { @Test public void putDownloadState_setsVersion() { SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase(); - assertThat(VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE)) + assertThat( + VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID)) .isEqualTo(VersionTable.VERSION_UNSET); downloadIndex.putDownloadState(new DownloadStateBuilder("id1").build()); - assertThat(VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE)) + assertThat( + VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID)) .isEqualTo(DefaultDownloadIndex.TABLE_VERSION); } @@ -198,14 +201,16 @@ public class DefaultDownloadIndexTest { cursor.close(); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); - VersionTable.setVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, Integer.MAX_VALUE); + VersionTable.setVersion( + writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID, Integer.MAX_VALUE); downloadIndex = new DefaultDownloadIndex(databaseProvider); cursor = downloadIndex.getDownloadStates(); assertThat(cursor.getCount()).isEqualTo(0); cursor.close(); - assertThat(VersionTable.getVersion(writableDatabase, VersionTable.FEATURE_OFFLINE)) + assertThat( + VersionTable.getVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID)) .isEqualTo(DefaultDownloadIndex.TABLE_VERSION); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndexTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndexTest.java index 6433faa8d5..2b128314fe 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndexTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndexTest.java @@ -160,7 +160,7 @@ public class CachedContentIndexTest { fos.write(testIndexV1File); fos.close(); - index.load(); + index.initialize(/* uid= */ 0); assertThat(index.getAll()).hasSize(2); assertThat(index.assignIdForKey("ABCDE")).isEqualTo(5); @@ -181,7 +181,7 @@ public class CachedContentIndexTest { fos.write(testIndexV2File); fos.close(); - index.load(); + index.initialize(/* uid= */ 0); assertThat(index.getAll()).hasSize(2); assertThat(index.assignIdForKey("ABCDE")).isEqualTo(5); @@ -325,7 +325,7 @@ public class CachedContentIndexTest { index.getOrAdd("ABCDE").applyMetadataMutations(mutations2); index.store(); - index2.load(); + index2.initialize(/* uid= */ 0); Set keys = index.getKeys(); Set keys2 = index2.getKeys(); assertThat(keys2).isEqualTo(keys);