mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Make a protobuf based backup system (#3936)
* Make a protobuf based backup system * Cleanup * More cleanup * Fix restores always loading the full backup restore, even when legacy restore was used * Make offline the default (cherry picked from commit f6fd8a8ddb90869f3e28fd8fcd81a2125f8e0527) * Find chapter based on the url (cherry picked from commit 326dc2700944a60da381d82cd9782c5f0d335902) * Dont break after finding one chapter (cherry picked from commit f91d1af37398619cf371e4920b60f6d309799c74) * Also apply changes to online restore (cherry picked from commit e7c16cd0d14ea5d50ce4a9a3dfa8ca768be702f2) * Rewrite backup categories (cherry picked from commit f4200e2146a9c540675767206ed4664894aa1216) * Dedupe some code, move over read and bookmarks properly (cherry picked from commit d9ce86aca66945c831670a1523d8bc69966312df) * Move some functions to the abstract backup manager (cherry picked from commit b0c658741a2f506bc31823f1f0347772bc119d2e) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt # app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt * Fix some backup duplication issues (cherry picked from commit a4a1c2827c4537d2d07a0cb589dc1c3be1d65185) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt * Fix a missed bundleOf * So glad this wasnt merged before now, everything should be working with this commit
This commit is contained in:
		| @@ -8,8 +8,9 @@ import com.google.gson.JsonArray | ||||
| import com.google.gson.JsonObject | ||||
| import eu.kanade.tachiyomi.BuildConfig | ||||
| import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner | ||||
| import eu.kanade.tachiyomi.data.backup.models.Backup | ||||
| import eu.kanade.tachiyomi.data.backup.models.DHistory | ||||
| import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupManager | ||||
| import eu.kanade.tachiyomi.data.backup.legacy.models.Backup | ||||
| import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Chapter | ||||
| @@ -37,7 +38,7 @@ import uy.kohesive.injekt.api.InjektRegistrar | ||||
| import uy.kohesive.injekt.api.addSingleton | ||||
|  | ||||
| /** | ||||
|  * Test class for the [BackupManager]. | ||||
|  * Test class for the [LegacyBackupManager]. | ||||
|  * Note that this does not include the backup create/restore services. | ||||
|  */ | ||||
| @Config(constants = BuildConfig::class, sdk = [Build.VERSION_CODES.LOLLIPOP]) | ||||
| @@ -59,7 +60,7 @@ class BackupTest { | ||||
|     lateinit var context: Context | ||||
|     lateinit var source: HttpSource | ||||
|  | ||||
|     lateinit var backupManager: BackupManager | ||||
|     lateinit var legacyBackupManager: LegacyBackupManager | ||||
|  | ||||
|     lateinit var db: DatabaseHelper | ||||
|  | ||||
| @@ -67,8 +68,8 @@ class BackupTest { | ||||
|     fun setup() { | ||||
|         app = RuntimeEnvironment.application | ||||
|         context = app.applicationContext | ||||
|         backupManager = BackupManager(context) | ||||
|         db = backupManager.databaseHelper | ||||
|         legacyBackupManager = LegacyBackupManager(context) | ||||
|         db = legacyBackupManager.databaseHelper | ||||
|  | ||||
|         // Mock the source manager | ||||
|         val module = object : InjektModule { | ||||
| @@ -79,7 +80,7 @@ class BackupTest { | ||||
|         Injekt.importModule(module) | ||||
|  | ||||
|         source = mock(HttpSource::class.java) | ||||
|         `when`(backupManager.sourceManager.get(anyLong())).thenReturn(source) | ||||
|         `when`(legacyBackupManager.sourceManager.get(anyLong())).thenReturn(source) | ||||
|  | ||||
|         root.add(Backup.MANGAS, mangaEntries) | ||||
|         root.add(Backup.CATEGORIES, categoryEntries) | ||||
| @@ -94,10 +95,10 @@ class BackupTest { | ||||
|         initializeJsonTest(2) | ||||
|  | ||||
|         // Create backup of empty database | ||||
|         backupManager.backupCategories(categoryEntries) | ||||
|         legacyBackupManager.backupCategories(categoryEntries) | ||||
|  | ||||
|         // Restore Json | ||||
|         backupManager.restoreCategories(categoryEntries) | ||||
|         legacyBackupManager.restoreCategories(categoryEntries) | ||||
|  | ||||
|         // Check if empty | ||||
|         val dbCats = db.getCategories().executeAsBlocking() | ||||
| @@ -116,10 +117,10 @@ class BackupTest { | ||||
|         val category = addSingleCategory("category") | ||||
|  | ||||
|         // Restore Json | ||||
|         backupManager.restoreCategories(categoryEntries) | ||||
|         legacyBackupManager.restoreCategories(categoryEntries) | ||||
|  | ||||
|         // Check if successful | ||||
|         val dbCats = backupManager.databaseHelper.getCategories().executeAsBlocking() | ||||
|         val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking() | ||||
|         assertThat(dbCats).hasSize(1) | ||||
|         assertThat(dbCats[0].name).isEqualTo(category.name) | ||||
|     } | ||||
| @@ -143,10 +144,10 @@ class BackupTest { | ||||
|         db.insertCategory(category).executeAsBlocking() | ||||
|  | ||||
|         // Restore Json | ||||
|         backupManager.restoreCategories(categoryEntries) | ||||
|         legacyBackupManager.restoreCategories(categoryEntries) | ||||
|  | ||||
|         // Check if successful | ||||
|         val dbCats = backupManager.databaseHelper.getCategories().executeAsBlocking() | ||||
|         val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking() | ||||
|         assertThat(dbCats).hasSize(5) | ||||
|         assertThat(dbCats[0].name).isEqualTo(category.name) | ||||
|         assertThat(dbCats[1].name).isEqualTo(category2.name) | ||||
| @@ -168,27 +169,27 @@ class BackupTest { | ||||
|         manga.viewer = 3 | ||||
|         manga.id = db.insertManga(manga).executeAsBlocking().insertedId() | ||||
|  | ||||
|         var favoriteManga = backupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         var favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         assertThat(favoriteManga).hasSize(1) | ||||
|         assertThat(favoriteManga[0].viewer).isEqualTo(3) | ||||
|  | ||||
|         // Update json with all options enabled | ||||
|         mangaEntries.add(backupManager.backupMangaObject(manga, 1)) | ||||
|         mangaEntries.add(legacyBackupManager.backupMangaObject(manga, 1)) | ||||
|  | ||||
|         // Change manga in database to default values | ||||
|         val dbManga = getSingleManga("One Piece") | ||||
|         dbManga.id = manga.id | ||||
|         db.insertManga(dbManga).executeAsBlocking() | ||||
|  | ||||
|         favoriteManga = backupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         assertThat(favoriteManga).hasSize(1) | ||||
|         assertThat(favoriteManga[0].viewer).isEqualTo(0) | ||||
|  | ||||
|         // Restore local manga | ||||
|         backupManager.restoreMangaNoFetch(manga, dbManga) | ||||
|         legacyBackupManager.restoreMangaNoFetch(manga, dbManga) | ||||
|  | ||||
|         // Test if restore successful | ||||
|         favoriteManga = backupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         assertThat(favoriteManga).hasSize(1) | ||||
|         assertThat(favoriteManga[0].viewer).isEqualTo(3) | ||||
|  | ||||
| @@ -196,28 +197,28 @@ class BackupTest { | ||||
|         clearDatabase() | ||||
|  | ||||
|         // Test if successful | ||||
|         favoriteManga = backupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         assertThat(favoriteManga).hasSize(0) | ||||
|  | ||||
|         // Restore Json | ||||
|         // Create JSON from manga to test parser | ||||
|         val json = backupManager.parser.toJsonTree(manga) | ||||
|         val json = legacyBackupManager.parser.toJsonTree(manga) | ||||
|         // Restore JSON from manga to test parser | ||||
|         val jsonManga = backupManager.parser.fromJson<MangaImpl>(json) | ||||
|         val jsonManga = legacyBackupManager.parser.fromJson<MangaImpl>(json) | ||||
|  | ||||
|         // Restore manga with fetch observable | ||||
|         val networkManga = getSingleManga("One Piece") | ||||
|         networkManga.description = "This is a description" | ||||
|         `when`(source.fetchMangaDetails(jsonManga)).thenReturn(Observable.just(networkManga)) | ||||
|  | ||||
|         val obs = backupManager.restoreMangaFetchObservable(source, jsonManga) | ||||
|         val obs = legacyBackupManager.restoreMangaFetchObservable(source, jsonManga) | ||||
|         val testSubscriber = TestSubscriber<Manga>() | ||||
|         obs.subscribe(testSubscriber) | ||||
|  | ||||
|         testSubscriber.assertNoErrors() | ||||
|  | ||||
|         // Check if restore successful | ||||
|         val dbCats = backupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         val dbCats = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking() | ||||
|         assertThat(dbCats).hasSize(1) | ||||
|         assertThat(dbCats[0].viewer).isEqualTo(3) | ||||
|         assertThat(dbCats[0].description).isEqualTo("This is a description") | ||||
| @@ -233,7 +234,7 @@ class BackupTest { | ||||
|  | ||||
|         // Insert manga | ||||
|         val manga = getSingleManga("One Piece") | ||||
|         manga.id = backupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() | ||||
|         manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() | ||||
|  | ||||
|         // Create restore list | ||||
|         val chapters = mutableListOf<Chapter>() | ||||
| @@ -244,8 +245,8 @@ class BackupTest { | ||||
|         } | ||||
|  | ||||
|         // Check parser | ||||
|         val chaptersJson = backupManager.parser.toJsonTree(chapters) | ||||
|         val restoredChapters = backupManager.parser.fromJson<List<ChapterImpl>>(chaptersJson) | ||||
|         val chaptersJson = legacyBackupManager.parser.toJsonTree(chapters) | ||||
|         val restoredChapters = legacyBackupManager.parser.fromJson<List<ChapterImpl>>(chaptersJson) | ||||
|  | ||||
|         // Fetch chapters from upstream | ||||
|         // Create list | ||||
| @@ -254,13 +255,13 @@ class BackupTest { | ||||
|         `when`(source.fetchChapterList(manga)).thenReturn(Observable.just(chaptersRemote)) | ||||
|  | ||||
|         // Call restoreChapterFetchObservable | ||||
|         val obs = backupManager.restoreChapterFetchObservable(source, manga, restoredChapters) | ||||
|         val obs = legacyBackupManager.restoreChapterFetchObservable(source, manga, restoredChapters) | ||||
|         val testSubscriber = TestSubscriber<Pair<List<Chapter>, List<Chapter>>>() | ||||
|         obs.subscribe(testSubscriber) | ||||
|  | ||||
|         testSubscriber.assertNoErrors() | ||||
|  | ||||
|         val dbCats = backupManager.databaseHelper.getChapters(manga).executeAsBlocking() | ||||
|         val dbCats = legacyBackupManager.databaseHelper.getChapters(manga).executeAsBlocking() | ||||
|         assertThat(dbCats).hasSize(10) | ||||
|         assertThat(dbCats[0].read).isEqualTo(true) | ||||
|     } | ||||
| @@ -274,13 +275,13 @@ class BackupTest { | ||||
|         initializeJsonTest(2) | ||||
|  | ||||
|         val manga = getSingleManga("One Piece") | ||||
|         manga.id = backupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() | ||||
|         manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() | ||||
|  | ||||
|         // Create chapter | ||||
|         val chapter = getSingleChapter("Chapter 1") | ||||
|         chapter.manga_id = manga.id | ||||
|         chapter.read = true | ||||
|         chapter.id = backupManager.databaseHelper.insertChapter(chapter).executeAsBlocking().insertedId() | ||||
|         chapter.id = legacyBackupManager.databaseHelper.insertChapter(chapter).executeAsBlocking().insertedId() | ||||
|  | ||||
|         val historyJson = getSingleHistory(chapter) | ||||
|  | ||||
| @@ -288,13 +289,13 @@ class BackupTest { | ||||
|         historyList.add(historyJson) | ||||
|  | ||||
|         // Check parser | ||||
|         val historyListJson = backupManager.parser.toJsonTree(historyList) | ||||
|         val history = backupManager.parser.fromJson<List<DHistory>>(historyListJson) | ||||
|         val historyListJson = legacyBackupManager.parser.toJsonTree(historyList) | ||||
|         val history = legacyBackupManager.parser.fromJson<List<DHistory>>(historyListJson) | ||||
|  | ||||
|         // Restore categories | ||||
|         backupManager.restoreHistoryForManga(history) | ||||
|         legacyBackupManager.restoreHistoryForManga(history) | ||||
|  | ||||
|         val historyDB = backupManager.databaseHelper.getHistoryByMangaId(manga.id!!).executeAsBlocking() | ||||
|         val historyDB = legacyBackupManager.databaseHelper.getHistoryByMangaId(manga.id!!).executeAsBlocking() | ||||
|         assertThat(historyDB).hasSize(1) | ||||
|         assertThat(historyDB[0].last_read).isEqualTo(1000) | ||||
|     } | ||||
| @@ -310,15 +311,15 @@ class BackupTest { | ||||
|         // Create mangas | ||||
|         val manga = getSingleManga("One Piece") | ||||
|         val manga2 = getSingleManga("Bleach") | ||||
|         manga.id = backupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() | ||||
|         manga2.id = backupManager.databaseHelper.insertManga(manga2).executeAsBlocking().insertedId() | ||||
|         manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId() | ||||
|         manga2.id = legacyBackupManager.databaseHelper.insertManga(manga2).executeAsBlocking().insertedId() | ||||
|  | ||||
|         // Create track and add it to database | ||||
|         // This tests duplicate errors. | ||||
|         val track = getSingleTrack(manga) | ||||
|         track.last_chapter_read = 5 | ||||
|         backupManager.databaseHelper.insertTrack(track).executeAsBlocking() | ||||
|         var trackDB = backupManager.databaseHelper.getTracks(manga).executeAsBlocking() | ||||
|         legacyBackupManager.databaseHelper.insertTrack(track).executeAsBlocking() | ||||
|         var trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking() | ||||
|         assertThat(trackDB).hasSize(1) | ||||
|         assertThat(trackDB[0].last_chapter_read).isEqualTo(5) | ||||
|         track.last_chapter_read = 7 | ||||
| @@ -330,22 +331,22 @@ class BackupTest { | ||||
|         // Check parser and restore already in database | ||||
|         var trackList = listOf(track) | ||||
|         // Check parser | ||||
|         var trackListJson = backupManager.parser.toJsonTree(trackList) | ||||
|         var trackListRestore = backupManager.parser.fromJson<List<TrackImpl>>(trackListJson) | ||||
|         backupManager.restoreTrackForManga(manga, trackListRestore) | ||||
|         var trackListJson = legacyBackupManager.parser.toJsonTree(trackList) | ||||
|         var trackListRestore = legacyBackupManager.parser.fromJson<List<TrackImpl>>(trackListJson) | ||||
|         legacyBackupManager.restoreTrackForManga(manga, trackListRestore) | ||||
|  | ||||
|         // Assert if restore works. | ||||
|         trackDB = backupManager.databaseHelper.getTracks(manga).executeAsBlocking() | ||||
|         trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking() | ||||
|         assertThat(trackDB).hasSize(1) | ||||
|         assertThat(trackDB[0].last_chapter_read).isEqualTo(7) | ||||
|  | ||||
|         // Check parser and restore already in database with lower chapter_read | ||||
|         track.last_chapter_read = 5 | ||||
|         trackList = listOf(track) | ||||
|         backupManager.restoreTrackForManga(manga, trackList) | ||||
|         legacyBackupManager.restoreTrackForManga(manga, trackList) | ||||
|  | ||||
|         // Assert if restore works. | ||||
|         trackDB = backupManager.databaseHelper.getTracks(manga).executeAsBlocking() | ||||
|         trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking() | ||||
|         assertThat(trackDB).hasSize(1) | ||||
|         assertThat(trackDB[0].last_chapter_read).isEqualTo(7) | ||||
|  | ||||
| @@ -353,12 +354,12 @@ class BackupTest { | ||||
|         trackList = listOf(track2) | ||||
|  | ||||
|         // Check parser | ||||
|         trackListJson = backupManager.parser.toJsonTree(trackList) | ||||
|         trackListRestore = backupManager.parser.fromJson<List<TrackImpl>>(trackListJson) | ||||
|         backupManager.restoreTrackForManga(manga2, trackListRestore) | ||||
|         trackListJson = legacyBackupManager.parser.toJsonTree(trackList) | ||||
|         trackListRestore = legacyBackupManager.parser.fromJson<List<TrackImpl>>(trackListJson) | ||||
|         legacyBackupManager.restoreTrackForManga(manga2, trackListRestore) | ||||
|  | ||||
|         // Assert if restore works. | ||||
|         trackDB = backupManager.databaseHelper.getTracks(manga2).executeAsBlocking() | ||||
|         trackDB = legacyBackupManager.databaseHelper.getTracks(manga2).executeAsBlocking() | ||||
|         assertThat(trackDB).hasSize(1) | ||||
|         assertThat(trackDB[0].last_chapter_read).isEqualTo(10) | ||||
|     } | ||||
| @@ -372,12 +373,12 @@ class BackupTest { | ||||
|  | ||||
|     fun initializeJsonTest(version: Int) { | ||||
|         clearJson() | ||||
|         backupManager.setVersion(version) | ||||
|         legacyBackupManager.setVersion(version) | ||||
|     } | ||||
|  | ||||
|     fun addSingleCategory(name: String): Category { | ||||
|         val category = Category.create(name) | ||||
|         val catJson = backupManager.parser.toJsonTree(category) | ||||
|         val catJson = legacyBackupManager.parser.toJsonTree(category) | ||||
|         categoryEntries.add(catJson) | ||||
|         return category | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user