2021-06-21 15:51:23 +02:00
|
|
|
package org.schabi.newpipe.database
|
|
|
|
|
|
|
|
import android.content.ContentValues
|
|
|
|
import android.database.sqlite.SQLiteDatabase
|
|
|
|
import androidx.room.Room
|
|
|
|
import androidx.room.testing.MigrationTestHelper
|
|
|
|
import androidx.test.core.app.ApplicationProvider
|
|
|
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
|
|
import androidx.test.platform.app.InstrumentationRegistry
|
|
|
|
import org.junit.Assert.assertEquals
|
2023-08-16 21:24:55 +02:00
|
|
|
import org.junit.Assert.assertNotEquals
|
2021-06-21 15:51:23 +02:00
|
|
|
import org.junit.Assert.assertNull
|
|
|
|
import org.junit.Rule
|
|
|
|
import org.junit.Test
|
|
|
|
import org.junit.runner.RunWith
|
2022-04-17 14:20:20 +02:00
|
|
|
import org.schabi.newpipe.database.playlist.model.PlaylistEntity
|
|
|
|
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity
|
2023-08-16 22:18:53 +02:00
|
|
|
import org.schabi.newpipe.extractor.ServiceList
|
2021-06-21 15:51:23 +02:00
|
|
|
import org.schabi.newpipe.extractor.stream.StreamType
|
|
|
|
|
|
|
|
@RunWith(AndroidJUnit4::class)
|
2021-11-02 22:43:23 +01:00
|
|
|
class DatabaseMigrationTest {
|
2021-06-21 15:51:23 +02:00
|
|
|
companion object {
|
|
|
|
private const val DEFAULT_SERVICE_ID = 0
|
|
|
|
private const val DEFAULT_URL = "https://www.youtube.com/watch?v=cDphUib5iG4"
|
|
|
|
private const val DEFAULT_TITLE = "Test Title"
|
2022-04-17 14:20:20 +02:00
|
|
|
private const val DEFAULT_NAME = "Test Name"
|
2021-06-21 15:51:23 +02:00
|
|
|
private val DEFAULT_TYPE = StreamType.VIDEO_STREAM
|
|
|
|
private const val DEFAULT_DURATION = 480L
|
|
|
|
private const val DEFAULT_UPLOADER_NAME = "Uploader Test"
|
|
|
|
private const val DEFAULT_THUMBNAIL = "https://example.com/example.jpg"
|
|
|
|
|
2022-04-17 14:20:20 +02:00
|
|
|
private const val DEFAULT_SECOND_SERVICE_ID = 1
|
2021-06-21 15:51:23 +02:00
|
|
|
private const val DEFAULT_SECOND_URL = "https://www.youtube.com/watch?v=ncQU6iBn5Fc"
|
2022-04-17 14:20:20 +02:00
|
|
|
|
|
|
|
private const val DEFAULT_THIRD_SERVICE_ID = 2
|
|
|
|
private const val DEFAULT_THIRD_URL = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
2021-06-21 15:51:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@get:Rule
|
|
|
|
val testHelper = MigrationTestHelper(
|
|
|
|
InstrumentationRegistry.getInstrumentation(),
|
2023-07-18 03:09:21 +02:00
|
|
|
AppDatabase::class.java
|
2021-06-21 15:51:23 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun migrateDatabaseFrom2to3() {
|
|
|
|
val databaseInV2 = testHelper.createDatabase(AppDatabase.DATABASE_NAME, Migrations.DB_VER_2)
|
|
|
|
|
|
|
|
databaseInV2.run {
|
|
|
|
insert(
|
2022-12-09 22:40:54 +01:00
|
|
|
"streams",
|
|
|
|
SQLiteDatabase.CONFLICT_FAIL,
|
2021-06-21 15:51:23 +02:00
|
|
|
ContentValues().apply {
|
|
|
|
put("service_id", DEFAULT_SERVICE_ID)
|
|
|
|
put("url", DEFAULT_URL)
|
|
|
|
put("title", DEFAULT_TITLE)
|
|
|
|
put("stream_type", DEFAULT_TYPE.name)
|
|
|
|
put("duration", DEFAULT_DURATION)
|
|
|
|
put("uploader", DEFAULT_UPLOADER_NAME)
|
|
|
|
put("thumbnail_url", DEFAULT_THUMBNAIL)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
insert(
|
2022-12-09 22:40:54 +01:00
|
|
|
"streams",
|
|
|
|
SQLiteDatabase.CONFLICT_FAIL,
|
2021-06-21 15:51:23 +02:00
|
|
|
ContentValues().apply {
|
|
|
|
put("service_id", DEFAULT_SECOND_SERVICE_ID)
|
|
|
|
put("url", DEFAULT_SECOND_URL)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
insert(
|
2022-12-09 22:40:54 +01:00
|
|
|
"streams",
|
|
|
|
SQLiteDatabase.CONFLICT_FAIL,
|
2021-06-21 15:51:23 +02:00
|
|
|
ContentValues().apply {
|
|
|
|
put("service_id", DEFAULT_SERVICE_ID)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
close()
|
|
|
|
}
|
|
|
|
|
|
|
|
testHelper.runMigrationsAndValidate(
|
2022-12-09 22:40:54 +01:00
|
|
|
AppDatabase.DATABASE_NAME,
|
|
|
|
Migrations.DB_VER_3,
|
|
|
|
true,
|
|
|
|
Migrations.MIGRATION_2_3
|
2021-06-21 15:51:23 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
testHelper.runMigrationsAndValidate(
|
2022-12-09 22:40:54 +01:00
|
|
|
AppDatabase.DATABASE_NAME,
|
|
|
|
Migrations.DB_VER_4,
|
|
|
|
true,
|
|
|
|
Migrations.MIGRATION_3_4
|
2021-06-21 15:51:23 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
testHelper.runMigrationsAndValidate(
|
2022-12-09 22:40:54 +01:00
|
|
|
AppDatabase.DATABASE_NAME,
|
|
|
|
Migrations.DB_VER_5,
|
|
|
|
true,
|
|
|
|
Migrations.MIGRATION_4_5
|
|
|
|
)
|
|
|
|
|
|
|
|
testHelper.runMigrationsAndValidate(
|
|
|
|
AppDatabase.DATABASE_NAME,
|
|
|
|
Migrations.DB_VER_6,
|
|
|
|
true,
|
|
|
|
Migrations.MIGRATION_5_6
|
2021-06-21 15:51:23 +02:00
|
|
|
)
|
|
|
|
|
2023-02-05 20:32:34 +01:00
|
|
|
testHelper.runMigrationsAndValidate(
|
|
|
|
AppDatabase.DATABASE_NAME,
|
|
|
|
Migrations.DB_VER_7,
|
|
|
|
true,
|
|
|
|
Migrations.MIGRATION_6_7
|
|
|
|
)
|
|
|
|
|
2023-08-16 21:24:55 +02:00
|
|
|
testHelper.runMigrationsAndValidate(
|
2023-08-16 22:01:58 +02:00
|
|
|
AppDatabase.DATABASE_NAME,
|
|
|
|
Migrations.DB_VER_8,
|
|
|
|
true,
|
|
|
|
Migrations.MIGRATION_7_8
|
2021-06-21 15:51:23 +02:00
|
|
|
)
|
|
|
|
|
2022-04-13 13:41:07 +02:00
|
|
|
testHelper.runMigrationsAndValidate(
|
|
|
|
AppDatabase.DATABASE_NAME, Migrations.DB_VER_6,
|
|
|
|
true, Migrations.MIGRATION_5_6
|
|
|
|
)
|
|
|
|
|
2021-06-21 15:51:23 +02:00
|
|
|
val migratedDatabaseV3 = getMigratedDatabase()
|
|
|
|
val listFromDB = migratedDatabaseV3.streamDAO().all.blockingFirst()
|
|
|
|
|
|
|
|
// Only expect 2, the one with the null url will be ignored
|
|
|
|
assertEquals(2, listFromDB.size)
|
|
|
|
|
|
|
|
val streamFromMigratedDatabase = listFromDB[0]
|
|
|
|
assertEquals(DEFAULT_SERVICE_ID, streamFromMigratedDatabase.serviceId)
|
|
|
|
assertEquals(DEFAULT_URL, streamFromMigratedDatabase.url)
|
|
|
|
assertEquals(DEFAULT_TITLE, streamFromMigratedDatabase.title)
|
|
|
|
assertEquals(DEFAULT_TYPE, streamFromMigratedDatabase.streamType)
|
|
|
|
assertEquals(DEFAULT_DURATION, streamFromMigratedDatabase.duration)
|
|
|
|
assertEquals(DEFAULT_UPLOADER_NAME, streamFromMigratedDatabase.uploader)
|
|
|
|
assertEquals(DEFAULT_THUMBNAIL, streamFromMigratedDatabase.thumbnailUrl)
|
|
|
|
assertNull(streamFromMigratedDatabase.viewCount)
|
|
|
|
assertNull(streamFromMigratedDatabase.textualUploadDate)
|
|
|
|
assertNull(streamFromMigratedDatabase.uploadDate)
|
|
|
|
assertNull(streamFromMigratedDatabase.isUploadDateApproximation)
|
|
|
|
|
|
|
|
val secondStreamFromMigratedDatabase = listFromDB[1]
|
|
|
|
assertEquals(DEFAULT_SECOND_SERVICE_ID, secondStreamFromMigratedDatabase.serviceId)
|
|
|
|
assertEquals(DEFAULT_SECOND_URL, secondStreamFromMigratedDatabase.url)
|
|
|
|
assertEquals("", secondStreamFromMigratedDatabase.title)
|
|
|
|
// Should fallback to VIDEO_STREAM
|
|
|
|
assertEquals(StreamType.VIDEO_STREAM, secondStreamFromMigratedDatabase.streamType)
|
|
|
|
assertEquals(0, secondStreamFromMigratedDatabase.duration)
|
|
|
|
assertEquals("", secondStreamFromMigratedDatabase.uploader)
|
|
|
|
assertEquals("", secondStreamFromMigratedDatabase.thumbnailUrl)
|
|
|
|
assertNull(secondStreamFromMigratedDatabase.viewCount)
|
|
|
|
assertNull(secondStreamFromMigratedDatabase.textualUploadDate)
|
|
|
|
assertNull(secondStreamFromMigratedDatabase.uploadDate)
|
|
|
|
assertNull(secondStreamFromMigratedDatabase.isUploadDateApproximation)
|
|
|
|
}
|
|
|
|
|
2022-04-17 14:20:20 +02:00
|
|
|
@Test
|
2023-08-16 22:01:58 +02:00
|
|
|
fun migrateDatabaseFrom7to8() {
|
|
|
|
val databaseInV7 = testHelper.createDatabase(AppDatabase.DATABASE_NAME, Migrations.DB_VER_7)
|
|
|
|
|
|
|
|
val defaultSearch1 = " abc "
|
|
|
|
val defaultSearch2 = " abc"
|
2023-08-16 21:24:55 +02:00
|
|
|
|
2023-08-16 22:18:53 +02:00
|
|
|
val serviceId = DEFAULT_SERVICE_ID // YouTube
|
|
|
|
// Use id different to YouTube because two searches with the same query
|
|
|
|
// but different service are considered not equal.
|
|
|
|
val otherServiceId = ServiceList.SoundCloud.serviceId
|
|
|
|
|
2023-08-16 22:01:58 +02:00
|
|
|
databaseInV7.run {
|
2023-08-16 21:24:55 +02:00
|
|
|
insert(
|
|
|
|
"search_history", SQLiteDatabase.CONFLICT_FAIL,
|
|
|
|
ContentValues().apply {
|
2023-08-16 22:18:53 +02:00
|
|
|
put("service_id", serviceId)
|
2022-05-04 14:20:19 +02:00
|
|
|
put("search", defaultSearch1)
|
2023-08-16 21:24:55 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
insert(
|
|
|
|
"search_history", SQLiteDatabase.CONFLICT_FAIL,
|
|
|
|
ContentValues().apply {
|
2023-08-16 22:18:53 +02:00
|
|
|
put("service_id", serviceId)
|
2022-05-04 14:20:19 +02:00
|
|
|
put("search", defaultSearch2)
|
2023-08-16 21:24:55 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
insert(
|
|
|
|
"search_history", SQLiteDatabase.CONFLICT_FAIL,
|
|
|
|
ContentValues().apply {
|
2023-08-16 22:18:53 +02:00
|
|
|
put("service_id", otherServiceId)
|
2022-05-04 14:20:19 +02:00
|
|
|
put("search", defaultSearch1)
|
2023-08-16 21:24:55 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
insert(
|
|
|
|
"search_history", SQLiteDatabase.CONFLICT_FAIL,
|
|
|
|
ContentValues().apply {
|
2023-08-16 22:18:53 +02:00
|
|
|
put("service_id", otherServiceId)
|
2022-05-04 14:20:19 +02:00
|
|
|
put("search", defaultSearch2)
|
2023-08-16 21:24:55 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
close()
|
|
|
|
}
|
|
|
|
|
|
|
|
testHelper.runMigrationsAndValidate(
|
2023-08-16 22:01:58 +02:00
|
|
|
AppDatabase.DATABASE_NAME, Migrations.DB_VER_8,
|
|
|
|
true, Migrations.MIGRATION_7_8
|
2023-08-16 21:24:55 +02:00
|
|
|
)
|
|
|
|
|
2023-08-16 22:01:58 +02:00
|
|
|
val migratedDatabaseV8 = getMigratedDatabase()
|
|
|
|
val listFromDB = migratedDatabaseV8.searchHistoryDAO().all.blockingFirst()
|
2023-08-16 21:24:55 +02:00
|
|
|
|
|
|
|
assertEquals(2, listFromDB.size)
|
|
|
|
assertEquals("abc", listFromDB[0].search)
|
|
|
|
assertEquals("abc", listFromDB[1].search)
|
|
|
|
assertNotEquals(listFromDB[0].serviceId, listFromDB[1].serviceId)
|
|
|
|
}
|
|
|
|
|
2024-03-29 16:09:13 +01:00
|
|
|
@Test
|
|
|
|
fun migrateDatabaseFrom8to9() {
|
2022-04-17 14:20:20 +02:00
|
|
|
val databaseInV5 = testHelper.createDatabase(AppDatabase.DATABASE_NAME, Migrations.DB_VER_5)
|
|
|
|
|
|
|
|
val localUid1: Long
|
|
|
|
val localUid2: Long
|
|
|
|
val remoteUid1: Long
|
|
|
|
val remoteUid2: Long
|
|
|
|
databaseInV5.run {
|
|
|
|
localUid1 = insert(
|
|
|
|
"playlists", SQLiteDatabase.CONFLICT_FAIL,
|
|
|
|
ContentValues().apply {
|
|
|
|
put("name", DEFAULT_NAME + "1")
|
|
|
|
put("thumbnail_url", DEFAULT_THUMBNAIL)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
localUid2 = insert(
|
|
|
|
"playlists", SQLiteDatabase.CONFLICT_FAIL,
|
|
|
|
ContentValues().apply {
|
|
|
|
put("name", DEFAULT_NAME + "2")
|
|
|
|
put("thumbnail_url", DEFAULT_THUMBNAIL)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
delete(
|
|
|
|
"playlists", "uid = ?",
|
|
|
|
Array(1) { localUid1 }
|
|
|
|
)
|
|
|
|
remoteUid1 = insert(
|
|
|
|
"remote_playlists", SQLiteDatabase.CONFLICT_FAIL,
|
|
|
|
ContentValues().apply {
|
|
|
|
put("service_id", DEFAULT_SERVICE_ID)
|
|
|
|
put("url", DEFAULT_URL)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
remoteUid2 = insert(
|
|
|
|
"remote_playlists", SQLiteDatabase.CONFLICT_FAIL,
|
|
|
|
ContentValues().apply {
|
|
|
|
put("service_id", DEFAULT_SECOND_SERVICE_ID)
|
|
|
|
put("url", DEFAULT_SECOND_URL)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
delete(
|
|
|
|
"remote_playlists", "uid = ?",
|
|
|
|
Array(1) { remoteUid2 }
|
|
|
|
)
|
|
|
|
close()
|
|
|
|
}
|
|
|
|
|
|
|
|
testHelper.runMigrationsAndValidate(
|
|
|
|
AppDatabase.DATABASE_NAME, Migrations.DB_VER_6,
|
|
|
|
true, Migrations.MIGRATION_5_6
|
|
|
|
)
|
|
|
|
|
|
|
|
val migratedDatabaseV6 = getMigratedDatabase()
|
|
|
|
var localListFromDB = migratedDatabaseV6.playlistDAO().all.blockingFirst()
|
|
|
|
var remoteListFromDB = migratedDatabaseV6.playlistRemoteDAO().all.blockingFirst()
|
|
|
|
|
|
|
|
assertEquals(1, localListFromDB.size)
|
|
|
|
assertEquals(localUid2, localListFromDB[0].uid)
|
|
|
|
assertEquals(0, localListFromDB[0].displayIndex)
|
|
|
|
assertEquals(1, remoteListFromDB.size)
|
|
|
|
assertEquals(remoteUid1, remoteListFromDB[0].uid)
|
|
|
|
assertEquals(0, remoteListFromDB[0].displayIndex)
|
|
|
|
|
|
|
|
val localUid3 = migratedDatabaseV6.playlistDAO().insert(
|
|
|
|
PlaylistEntity(DEFAULT_NAME + "3", DEFAULT_THUMBNAIL, -1)
|
|
|
|
)
|
|
|
|
val remoteUid3 = migratedDatabaseV6.playlistRemoteDAO().insert(
|
|
|
|
PlaylistRemoteEntity(
|
|
|
|
DEFAULT_THIRD_SERVICE_ID, DEFAULT_NAME, DEFAULT_THIRD_URL,
|
|
|
|
DEFAULT_THUMBNAIL, DEFAULT_UPLOADER_NAME, -1, 10
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
localListFromDB = migratedDatabaseV6.playlistDAO().all.blockingFirst()
|
|
|
|
remoteListFromDB = migratedDatabaseV6.playlistRemoteDAO().all.blockingFirst()
|
|
|
|
assertEquals(2, localListFromDB.size)
|
|
|
|
assertEquals(localUid3, localListFromDB[1].uid)
|
|
|
|
assertEquals(-1, localListFromDB[1].displayIndex)
|
|
|
|
assertEquals(2, remoteListFromDB.size)
|
|
|
|
assertEquals(remoteUid3, remoteListFromDB[1].uid)
|
|
|
|
assertEquals(-1, remoteListFromDB[1].displayIndex)
|
|
|
|
}
|
|
|
|
|
2021-06-21 15:51:23 +02:00
|
|
|
private fun getMigratedDatabase(): AppDatabase {
|
|
|
|
val database: AppDatabase = Room.databaseBuilder(
|
|
|
|
ApplicationProvider.getApplicationContext(),
|
2022-12-09 22:40:54 +01:00
|
|
|
AppDatabase::class.java,
|
|
|
|
AppDatabase.DATABASE_NAME
|
2021-06-21 15:51:23 +02:00
|
|
|
)
|
|
|
|
.build()
|
|
|
|
testHelper.closeWhenFinished(database)
|
|
|
|
return database
|
|
|
|
}
|
|
|
|
}
|