Refactor Storage Plugin API

This commit is contained in:
Torsten Grote 2021-09-23 14:56:01 +02:00 committed by Chirayu Desai
parent 50066f0317
commit 3c5e4120c7
30 changed files with 219 additions and 268 deletions

View file

@ -3,18 +3,14 @@ package com.stevesoltys.seedvault
import androidx.test.core.content.pm.PackageInfoBuilder
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderBackupPlugin
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderFullRestorePlugin
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderKVRestorePlugin
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderRestorePlugin
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderStoragePlugin
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderLegacyPlugin
import com.stevesoltys.seedvault.plugins.saf.DocumentsStorage
import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA
import com.stevesoltys.seedvault.plugins.saf.deleteContents
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin
import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin
import com.stevesoltys.seedvault.transport.restore.RestorePlugin
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.Dispatchers
@ -39,14 +35,10 @@ class PluginTest : KoinComponent {
private val mockedSettingsManager: SettingsManager = mockk()
private val storage = DocumentsStorage(context, mockedSettingsManager)
private val backupPlugin: BackupPlugin = DocumentsProviderBackupPlugin(context, storage)
private val kvRestorePlugin: KVRestorePlugin =
DocumentsProviderKVRestorePlugin(context, storage)
private val fullRestorePlugin: FullRestorePlugin =
DocumentsProviderFullRestorePlugin(context, storage)
private val restorePlugin: RestorePlugin =
DocumentsProviderRestorePlugin(context, storage, kvRestorePlugin, fullRestorePlugin)
private val storagePlugin: StoragePlugin = DocumentsProviderStoragePlugin(context, storage)
@Suppress("Deprecation")
private val legacyStoragePlugin: LegacyStoragePlugin =
DocumentsProviderLegacyPlugin(context, storage)
private val token = System.currentTimeMillis() - 365L * 24L * 60L * 60L * 1000L
private val packageInfo = PackageInfoBuilder.newBuilder().setPackageName("org.example").build()
@ -67,7 +59,7 @@ class PluginTest : KoinComponent {
@Test
fun testProviderPackageName() {
assertNotNull(backupPlugin.providerPackageName)
assertNotNull(storagePlugin.providerPackageName)
}
/**
@ -80,38 +72,38 @@ class PluginTest : KoinComponent {
@Test
fun testInitializationAndRestoreSets() = runBlocking(Dispatchers.IO) {
// no backups available initially
assertEquals(0, backupPlugin.getAvailableBackups()?.toList()?.size)
assertEquals(0, storagePlugin.getAvailableBackups()?.toList()?.size)
val uri = settingsManager.getStorage()?.getDocumentFile(context)?.uri ?: error("no storage")
assertFalse(backupPlugin.hasBackup(uri))
assertFalse(storagePlugin.hasBackup(uri))
// prepare returned tokens requested when initializing device
every { mockedSettingsManager.getToken() } returnsMany listOf(token, token + 1, token + 1)
// start new restore set and initialize device afterwards
backupPlugin.startNewRestoreSet(token)
backupPlugin.initializeDevice()
storagePlugin.startNewRestoreSet(token)
storagePlugin.initializeDevice()
// write metadata (needed for backup to be recognized)
backupPlugin.getOutputStream(token, FILE_BACKUP_METADATA)
storagePlugin.getOutputStream(token, FILE_BACKUP_METADATA)
.writeAndClose(getRandomByteArray())
// one backup available now
assertEquals(1, backupPlugin.getAvailableBackups()?.toList()?.size)
assertTrue(backupPlugin.hasBackup(uri))
assertEquals(1, storagePlugin.getAvailableBackups()?.toList()?.size)
assertTrue(storagePlugin.hasBackup(uri))
// initializing again (with another restore set) does add a restore set
backupPlugin.startNewRestoreSet(token + 1)
backupPlugin.initializeDevice()
backupPlugin.getOutputStream(token + 1, FILE_BACKUP_METADATA)
storagePlugin.startNewRestoreSet(token + 1)
storagePlugin.initializeDevice()
storagePlugin.getOutputStream(token + 1, FILE_BACKUP_METADATA)
.writeAndClose(getRandomByteArray())
assertEquals(2, backupPlugin.getAvailableBackups()?.toList()?.size)
assertTrue(backupPlugin.hasBackup(uri))
assertEquals(2, storagePlugin.getAvailableBackups()?.toList()?.size)
assertTrue(storagePlugin.hasBackup(uri))
// initializing again (without new restore set) doesn't change number of restore sets
backupPlugin.initializeDevice()
backupPlugin.getOutputStream(token + 1, FILE_BACKUP_METADATA)
storagePlugin.initializeDevice()
storagePlugin.getOutputStream(token + 1, FILE_BACKUP_METADATA)
.writeAndClose(getRandomByteArray())
assertEquals(2, backupPlugin.getAvailableBackups()?.toList()?.size)
assertEquals(2, storagePlugin.getAvailableBackups()?.toList()?.size)
// ensure that the new backup dir exist
assertTrue(storage.currentSetDir!!.exists())
@ -121,15 +113,15 @@ class PluginTest : KoinComponent {
fun testMetadataWriteRead() = runBlocking(Dispatchers.IO) {
every { mockedSettingsManager.getToken() } returns token
backupPlugin.startNewRestoreSet(token)
backupPlugin.initializeDevice()
storagePlugin.startNewRestoreSet(token)
storagePlugin.initializeDevice()
// write metadata
val metadata = getRandomByteArray()
backupPlugin.getOutputStream(token, FILE_BACKUP_METADATA).writeAndClose(metadata)
storagePlugin.getOutputStream(token, FILE_BACKUP_METADATA).writeAndClose(metadata)
// get available backups, expect only one with our token and no error
var availableBackups = backupPlugin.getAvailableBackups()?.toList()
var availableBackups = storagePlugin.getAvailableBackups()?.toList()
check(availableBackups != null)
assertEquals(1, availableBackups.size)
assertEquals(token, availableBackups[0].token)
@ -138,9 +130,9 @@ class PluginTest : KoinComponent {
assertReadEquals(metadata, availableBackups[0].inputStreamRetriever())
// initializing again (without changing storage) keeps restore set with same token
backupPlugin.initializeDevice()
backupPlugin.getOutputStream(token, FILE_BACKUP_METADATA).writeAndClose(metadata)
availableBackups = backupPlugin.getAvailableBackups()?.toList()
storagePlugin.initializeDevice()
storagePlugin.getOutputStream(token, FILE_BACKUP_METADATA).writeAndClose(metadata)
availableBackups = storagePlugin.getAvailableBackups()?.toList()
check(availableBackups != null)
assertEquals(1, availableBackups.size)
assertEquals(token, availableBackups[0].token)
@ -157,22 +149,25 @@ class PluginTest : KoinComponent {
// write random bytes as APK
val apk1 = getRandomByteArray(1337 * 1024)
backupPlugin.getOutputStream(token, "${packageInfo.packageName}.apk").writeAndClose(apk1)
storagePlugin.getOutputStream(token, "${packageInfo.packageName}.apk").writeAndClose(apk1)
// assert that read APK bytes match what was written
assertReadEquals(apk1, restorePlugin.getApkInputStream(token, packageInfo.packageName, ""))
assertReadEquals(
apk1,
legacyStoragePlugin.getApkInputStream(token, packageInfo.packageName, "")
)
// write random bytes as another APK
val suffix2 = getRandomBase64(23)
val apk2 = getRandomByteArray(23 * 1024 * 1024)
backupPlugin.getOutputStream(token, "${packageInfo2.packageName}$suffix2.apk")
storagePlugin.getOutputStream(token, "${packageInfo2.packageName}$suffix2.apk")
.writeAndClose(apk2)
// assert that read APK bytes match what was written
assertReadEquals(
apk2,
restorePlugin.getApkInputStream(token, packageInfo2.packageName, suffix2)
legacyStoragePlugin.getApkInputStream(token, packageInfo2.packageName, suffix2)
)
}
@ -185,41 +180,41 @@ class PluginTest : KoinComponent {
val name2 = getRandomBase64()
// no data available initially
assertFalse(backupPlugin.hasData(token, name1))
assertFalse(backupPlugin.hasData(token, name2))
assertFalse(storagePlugin.hasData(token, name1))
assertFalse(storagePlugin.hasData(token, name2))
// write full backup data
val data = getRandomByteArray(5 * 1024 * 1024)
backupPlugin.getOutputStream(token, name1).writeAndClose(data)
storagePlugin.getOutputStream(token, name1).writeAndClose(data)
// data is available now, but only this token
assertTrue(backupPlugin.hasData(token, name1))
assertFalse(backupPlugin.hasData(token + 1, name1))
assertTrue(storagePlugin.hasData(token, name1))
assertFalse(storagePlugin.hasData(token + 1, name1))
// restore data matches backed up data
assertReadEquals(data, backupPlugin.getInputStream(token, name1))
assertReadEquals(data, storagePlugin.getInputStream(token, name1))
// write and check data for second package
val data2 = getRandomByteArray(5 * 1024 * 1024)
backupPlugin.getOutputStream(token, name2).writeAndClose(data2)
assertTrue(backupPlugin.hasData(token, name2))
assertReadEquals(data2, backupPlugin.getInputStream(token, name2))
storagePlugin.getOutputStream(token, name2).writeAndClose(data2)
assertTrue(storagePlugin.hasData(token, name2))
assertReadEquals(data2, storagePlugin.getInputStream(token, name2))
// remove data of first package again and ensure that no more data is found
backupPlugin.removeData(token, name1)
assertFalse(backupPlugin.hasData(token, name1))
storagePlugin.removeData(token, name1)
assertFalse(storagePlugin.hasData(token, name1))
// second package is still there
assertTrue(backupPlugin.hasData(token, name2))
assertTrue(storagePlugin.hasData(token, name2))
// ensure that it gets deleted as well
backupPlugin.removeData(token, name2)
assertFalse(backupPlugin.hasData(token, name2))
storagePlugin.removeData(token, name2)
assertFalse(storagePlugin.hasData(token, name2))
}
private fun initStorage(token: Long) = runBlocking {
every { mockedSettingsManager.getToken() } returns token
backupPlugin.initializeDevice()
storagePlugin.initializeDevice()
}
}

View file

@ -1,10 +1,11 @@
package com.stevesoltys.seedvault.transport.restore
package com.stevesoltys.seedvault.plugins
import android.content.pm.PackageInfo
import java.io.IOException
import java.io.InputStream
interface KVRestorePlugin {
@Deprecated("Only for old v0 backup format")
interface LegacyStoragePlugin {
/**
* Return true if there is data stored for the given package.
@ -36,4 +37,19 @@ interface KVRestorePlugin {
key: String
): InputStream
/**
* Return true if there is data stored for the given package.
*/
@Throws(IOException::class)
suspend fun hasDataForFullPackage(token: Long, packageInfo: PackageInfo): Boolean
@Throws(IOException::class)
suspend fun getInputStreamForPackage(token: Long, packageInfo: PackageInfo): InputStream
/**
* Returns an [InputStream] for the given token, for reading an APK that is to be restored.
*/
@Throws(IOException::class)
suspend fun getApkInputStream(token: Long, packageName: String, suffix: String): InputStream
}

View file

@ -1,4 +1,4 @@
package com.stevesoltys.seedvault.transport.backup
package com.stevesoltys.seedvault.plugins
import android.app.backup.RestoreSet
import android.net.Uri
@ -7,7 +7,7 @@ import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
interface BackupPlugin {
interface StoragePlugin {
/**
* Start a new [RestoreSet] with the given token.

View file

@ -1,33 +0,0 @@
package com.stevesoltys.seedvault.plugins.saf
import android.content.Context
import android.content.pm.PackageInfo
import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin
import java.io.IOException
import java.io.InputStream
@Suppress("BlockingMethodInNonBlockingContext", "Deprecation")
@Deprecated("Use only for v0 restore")
internal class DocumentsProviderFullRestorePlugin(
private val context: Context,
private val documentsStorage: DocumentsStorage
) : FullRestorePlugin {
@Throws(IOException::class)
override suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean {
val backupDir = documentsStorage.getFullBackupDir(token) ?: return false
return backupDir.findFileBlocking(context, packageInfo.packageName) != null
}
@Throws(IOException::class)
override suspend fun getInputStreamForPackage(
token: Long,
packageInfo: PackageInfo
): InputStream {
val backupDir = documentsStorage.getFullBackupDir(token) ?: throw IOException()
val packageFile =
backupDir.findFileBlocking(context, packageInfo.packageName) ?: throw IOException()
return documentsStorage.getInputStream(packageFile)
}
}

View file

@ -2,17 +2,19 @@ package com.stevesoltys.seedvault.plugins.saf
import android.content.Context
import android.content.pm.PackageInfo
import androidx.annotation.WorkerThread
import androidx.documentfile.provider.DocumentFile
import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
@Suppress("BlockingMethodInNonBlockingContext", "Deprecation")
@Deprecated("Use only for v0 restore")
internal class DocumentsProviderKVRestorePlugin(
@WorkerThread
@Suppress("BlockingMethodInNonBlockingContext", "Deprecation") // all methods do I/O
internal class DocumentsProviderLegacyPlugin(
private val context: Context,
private val storage: DocumentsStorage
) : KVRestorePlugin {
) : LegacyStoragePlugin {
private var packageDir: DocumentFile? = null
private var packageChildren: List<DocumentFile>? = null
@ -59,4 +61,33 @@ internal class DocumentsProviderKVRestorePlugin(
return storage.getInputStream(keyFile)
}
@Throws(IOException::class)
override suspend fun hasDataForFullPackage(token: Long, packageInfo: PackageInfo): Boolean {
val backupDir = storage.getFullBackupDir(token) ?: return false
return backupDir.findFileBlocking(context, packageInfo.packageName) != null
}
@Throws(IOException::class)
override suspend fun getInputStreamForPackage(
token: Long,
packageInfo: PackageInfo
): InputStream {
val backupDir = storage.getFullBackupDir(token) ?: throw IOException()
val packageFile =
backupDir.findFileBlocking(context, packageInfo.packageName) ?: throw IOException()
return storage.getInputStream(packageFile)
}
@Throws(IOException::class)
override suspend fun getApkInputStream(
token: Long,
packageName: String,
suffix: String
): InputStream {
val setDir = storage.getSetDir(token) ?: throw IOException()
val file = setDir.findFileBlocking(context, "$packageName$suffix.apk")
?: throw FileNotFoundException()
return storage.getInputStream(file)
}
}

View file

@ -1,18 +1,14 @@
package com.stevesoltys.seedvault.plugins.saf
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin
import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin
import com.stevesoltys.seedvault.transport.restore.RestorePlugin
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module
val documentsProviderModule = module {
single { DocumentsStorage(androidContext(), get()) }
single<BackupPlugin> { DocumentsProviderBackupPlugin(androidContext(), get()) }
single<KVRestorePlugin> { DocumentsProviderKVRestorePlugin(androidContext(), get()) }
single<FullRestorePlugin> { DocumentsProviderFullRestorePlugin(androidContext(), get()) }
single<RestorePlugin> { DocumentsProviderRestorePlugin(androidContext(), get(), get(), get()) }
single<StoragePlugin> { DocumentsProviderStoragePlugin(androidContext(), get()) }
@Suppress("Deprecation")
single<LegacyStoragePlugin> { DocumentsProviderLegacyPlugin(androidContext(), get()) }
}

View file

@ -1,33 +0,0 @@
package com.stevesoltys.seedvault.plugins.saf
import android.content.Context
import androidx.annotation.WorkerThread
import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin
import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin
import com.stevesoltys.seedvault.transport.restore.RestorePlugin
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
@WorkerThread
@Suppress("BlockingMethodInNonBlockingContext") // all methods do I/O
internal class DocumentsProviderRestorePlugin(
private val context: Context,
private val storage: DocumentsStorage,
override val kvRestorePlugin: KVRestorePlugin,
override val fullRestorePlugin: FullRestorePlugin
) : RestorePlugin {
@Throws(IOException::class)
override suspend fun getApkInputStream(
token: Long,
packageName: String,
suffix: String
): InputStream {
val setDir = storage.getSetDir(token) ?: throw IOException()
val file = setDir.findFileBlocking(context, "$packageName$suffix.apk")
?: throw FileNotFoundException()
return storage.getInputStream(file)
}
}

View file

@ -5,20 +5,20 @@ import android.content.pm.PackageManager
import android.net.Uri
import android.util.Log
import androidx.documentfile.provider.DocumentFile
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.backup.EncryptedMetadata
import com.stevesoltys.seedvault.plugins.EncryptedMetadata
import com.stevesoltys.seedvault.plugins.StoragePlugin
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
private val TAG = DocumentsProviderBackupPlugin::class.java.simpleName
private val TAG = DocumentsProviderStoragePlugin::class.java.simpleName
@Suppress("BlockingMethodInNonBlockingContext")
internal class DocumentsProviderBackupPlugin(
internal class DocumentsProviderStoragePlugin(
private val context: Context,
private val storage: DocumentsStorage
) : BackupPlugin {
) : StoragePlugin {
private val packageManager: PackageManager = context.packageManager

View file

@ -8,16 +8,16 @@ import android.util.Log
import com.stevesoltys.seedvault.crypto.Crypto
import com.stevesoltys.seedvault.metadata.ApkSplit
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.restore.RestorableBackup
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.backup.copyStreamsAndGetHash
import com.stevesoltys.seedvault.transport.backup.getSignatures
import com.stevesoltys.seedvault.transport.backup.isSystemApp
import com.stevesoltys.seedvault.transport.restore.RestorePlugin
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.flow
@ -28,8 +28,9 @@ private val TAG = ApkRestore::class.java.simpleName
internal class ApkRestore(
private val context: Context,
private val backupPlugin: BackupPlugin,
private val restorePlugin: RestorePlugin,
private val storagePlugin: StoragePlugin,
@Suppress("Deprecation")
private val legacyStoragePlugin: LegacyStoragePlugin,
private val crypto: Crypto,
private val splitCompatChecker: ApkSplitCompatibilityChecker,
private val apkInstaller: ApkInstaller
@ -157,7 +158,7 @@ internal class ApkRestore(
}
/**
* Retrieves APK splits from [RestorePlugin] and caches them locally.
* Retrieves APK splits from [StoragePlugin] and caches them locally.
*
* @throws SecurityException if a split has an unexpected SHA-256 hash.
* @return a list of all APKs that need to be installed
@ -195,7 +196,7 @@ internal class ApkRestore(
}
/**
* Retrieves an APK from the [RestorePlugin] and caches it locally
* Retrieves an APK from the [StoragePlugin] and caches it locally
* while calculating its SHA-256 hash.
*
* @return a [Pair] of the cached [File] and SHA-256 hash.
@ -214,10 +215,10 @@ internal class ApkRestore(
// copy APK to cache file and calculate SHA-256 hash while we are at it
val inputStream = if (version == 0.toByte()) {
@Suppress("Deprecation")
restorePlugin.getApkInputStream(token, packageName, suffix)
legacyStoragePlugin.getApkInputStream(token, packageName, suffix)
} else {
val name = crypto.getNameForApk(salt, packageName, suffix)
backupPlugin.getInputStream(token, name)
storagePlugin.getInputStream(token, name)
}
val sha256 = copyStreamsAndGetHash(inputStream, cachedApk.outputStream())
return Pair(cachedApk, sha256)

View file

@ -29,6 +29,7 @@ import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED
import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR
import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
@ -64,7 +65,7 @@ private class CoordinatorState(
@Suppress("BlockingMethodInNonBlockingContext")
internal class BackupCoordinator(
private val context: Context,
private val plugin: BackupPlugin,
private val plugin: StoragePlugin,
private val kv: KVBackup,
private val full: FullBackup,
private val apkBackup: ApkBackup,
@ -508,7 +509,7 @@ internal class BackupCoordinator(
}
}
private suspend fun BackupPlugin.getMetadataOutputStream(token: Long? = null): OutputStream {
private suspend fun StoragePlugin.getMetadataOutputStream(token: Long? = null): OutputStream {
val t = token ?: settingsManager.getToken() ?: throw IOException("no current token")
return getOutputStream(t, FILE_BACKUP_METADATA)
}

View file

@ -11,6 +11,7 @@ import android.util.Log
import com.stevesoltys.seedvault.crypto.Crypto
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.getADForFull
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.settings.SettingsManager
import libcore.io.IoUtils.closeQuietly
import java.io.EOFException
@ -38,7 +39,7 @@ private val TAG = FullBackup::class.java.simpleName
@Suppress("BlockingMethodInNonBlockingContext")
internal class FullBackup(
private val plugin: BackupPlugin,
private val plugin: StoragePlugin,
private val settingsManager: SettingsManager,
private val inputFactory: InputFactory,
private val crypto: Crypto

View file

@ -12,6 +12,7 @@ import android.util.Log
import com.stevesoltys.seedvault.crypto.Crypto
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.getADForKV
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.settings.SettingsManager
import java.io.IOException
import java.util.zip.GZIPOutputStream
@ -31,7 +32,7 @@ private val TAG = KVBackup::class.java.simpleName
@Suppress("BlockingMethodInNonBlockingContext")
internal class KVBackup(
private val plugin: BackupPlugin,
private val plugin: StoragePlugin,
private val settingsManager: SettingsManager,
private val inputFactory: InputFactory,
private val crypto: Crypto,

View file

@ -12,7 +12,8 @@ import com.stevesoltys.seedvault.header.HeaderReader
import com.stevesoltys.seedvault.header.MAX_SEGMENT_LENGTH
import com.stevesoltys.seedvault.header.UnsupportedVersionException
import com.stevesoltys.seedvault.header.getADForFull
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import libcore.io.IoUtils.closeQuietly
import java.io.EOFException
import java.io.IOException
@ -33,8 +34,9 @@ private val TAG = FullRestore::class.java.simpleName
@Suppress("BlockingMethodInNonBlockingContext")
internal class FullRestore(
private val plugin: BackupPlugin,
private val legacyPlugin: FullRestorePlugin,
private val plugin: StoragePlugin,
@Suppress("Deprecation")
private val legacyPlugin: LegacyStoragePlugin,
private val outputFactory: OutputFactory,
private val headerReader: HeaderReader,
private val crypto: Crypto
@ -52,7 +54,7 @@ internal class FullRestore(
@Throws(IOException::class)
@Deprecated("Use BackupPlugin#hasData() instead")
suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean {
return legacyPlugin.hasDataForPackage(token, packageInfo)
return legacyPlugin.hasDataForFullPackage(token, packageInfo)
}
/**

View file

@ -1,18 +0,0 @@
package com.stevesoltys.seedvault.transport.restore
import android.content.pm.PackageInfo
import java.io.IOException
import java.io.InputStream
interface FullRestorePlugin {
/**
* Return true if there is data stored for the given package.
*/
@Throws(IOException::class)
suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean
@Throws(IOException::class)
suspend fun getInputStreamForPackage(token: Long, packageInfo: PackageInfo): InputStream
}

View file

@ -15,7 +15,8 @@ import com.stevesoltys.seedvault.header.HeaderReader
import com.stevesoltys.seedvault.header.UnsupportedVersionException
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.getADForKV
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.transport.backup.KVDb
import com.stevesoltys.seedvault.transport.backup.KvDbManager
import libcore.io.IoUtils.closeQuietly
@ -41,8 +42,9 @@ private val TAG = KVRestore::class.java.simpleName
@Suppress("BlockingMethodInNonBlockingContext")
internal class KVRestore(
private val plugin: BackupPlugin,
private val legacyPlugin: KVRestorePlugin,
private val plugin: StoragePlugin,
@Suppress("Deprecation")
private val legacyPlugin: LegacyStoragePlugin,
private val outputFactory: OutputFactory,
private val headerReader: HeaderReader,
private val crypto: Crypto,

View file

@ -21,7 +21,7 @@ import com.stevesoltys.seedvault.metadata.DecryptionFailedException
import com.stevesoltys.seedvault.metadata.MetadataManager
import com.stevesoltys.seedvault.metadata.MetadataReader
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import java.io.IOException
@ -46,7 +46,7 @@ internal class RestoreCoordinator(
private val settingsManager: SettingsManager,
private val metadataManager: MetadataManager,
private val notificationManager: BackupNotificationManager,
private val plugin: BackupPlugin,
private val plugin: StoragePlugin,
private val kv: KVRestore,
private val full: FullRestore,
private val metadataReader: MetadataReader

View file

@ -5,8 +5,8 @@ import org.koin.dsl.module
val restoreModule = module {
single { OutputFactory() }
single { KVRestore(get(), get<RestorePlugin>().kvRestorePlugin, get(), get(), get(), get()) }
single { FullRestore(get(), get<RestorePlugin>().fullRestorePlugin, get(), get(), get()) }
single { KVRestore(get(), get(), get(), get(), get(), get()) }
single { FullRestore(get(), get(), get(), get(), get()) }
single {
RestoreCoordinator(androidContext(), get(), get(), get(), get(), get(), get(), get(), get())
}

View file

@ -1,19 +0,0 @@
package com.stevesoltys.seedvault.transport.restore
import java.io.IOException
import java.io.InputStream
interface RestorePlugin {
val kvRestorePlugin: KVRestorePlugin
val fullRestorePlugin: FullRestorePlugin
/**
* Returns an [InputStream] for the given token, for reading an APK that is to be restored.
*/
@Throws(IOException::class)
@Deprecated("Use only for v0 restores")
suspend fun getApkInputStream(token: Long, packageName: String, suffix: String): InputStream
}

View file

@ -7,7 +7,7 @@ import androidx.lifecycle.viewModelScope
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.plugins.saf.DIRECTORY_ROOT
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.IOException
@ -16,7 +16,7 @@ private val TAG = RestoreStorageViewModel::class.java.simpleName
internal class RestoreStorageViewModel(
private val app: Application,
private val backupPlugin: BackupPlugin,
private val storagePlugin: StoragePlugin,
settingsManager: SettingsManager
) : StorageViewModel(app, settingsManager) {
@ -25,7 +25,7 @@ internal class RestoreStorageViewModel(
override fun onLocationSet(uri: Uri) {
viewModelScope.launch(Dispatchers.IO) {
val hasBackup = try {
backupPlugin.hasBackup(uri)
storagePlugin.hasBackup(uri)
} catch (e: IOException) {
Log.e(TAG, "Error reading URI: $uri", e)
false

View file

@ -12,11 +12,11 @@ import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
@Suppress("BlockingMethodInNonBlockingContext")
internal class BackupPluginTest : BackupTest() {
internal class StoragePluginTest : BackupTest() {
private val storage = mockk<DocumentsStorage>()
private val plugin = DocumentsProviderBackupPlugin(context, storage)
private val plugin = DocumentsProviderStoragePlugin(context, storage)
private val setDir: DocumentFile = mockk()
private val backupFile: DocumentFile = mockk()

View file

@ -11,11 +11,11 @@ import com.stevesoltys.seedvault.metadata.ApkSplit
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
import com.stevesoltys.seedvault.metadata.PackageState
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.restore.RestorableBackup
import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.transport.backup.ApkBackup
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.restore.RestorePlugin
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
@ -46,16 +46,17 @@ internal class ApkBackupRestoreTest : TransportTest() {
private val strictContext: Context = mockk<Context>().apply {
every { packageManager } returns pm
}
private val backupPlugin: BackupPlugin = mockk()
private val restorePlugin: RestorePlugin = mockk()
@Suppress("Deprecation")
private val legacyStoragePlugin: LegacyStoragePlugin = mockk()
private val storagePlugin: StoragePlugin = mockk()
private val splitCompatChecker: ApkSplitCompatibilityChecker = mockk()
private val apkInstaller: ApkInstaller = mockk()
private val apkBackup = ApkBackup(pm, crypto, settingsManager, metadataManager)
private val apkRestore: ApkRestore = ApkRestore(
context = strictContext,
backupPlugin = backupPlugin,
restorePlugin = restorePlugin,
storagePlugin = storagePlugin,
legacyStoragePlugin = legacyStoragePlugin,
crypto = crypto,
splitCompatChecker = splitCompatChecker,
apkInstaller = apkInstaller
@ -129,7 +130,7 @@ internal class ApkBackupRestoreTest : TransportTest() {
every { strictContext.cacheDir } returns tmpFile
every { crypto.getNameForApk(salt, packageName, "") } returns name
coEvery { backupPlugin.getInputStream(token, name) } returns inputStream
coEvery { storagePlugin.getInputStream(token, name) } returns inputStream
every { pm.getPackageArchiveInfo(capture(apkPath), any()) } returns packageInfo
every {
@Suppress("UNRESOLVED_REFERENCE")
@ -143,7 +144,7 @@ internal class ApkBackupRestoreTest : TransportTest() {
splitCompatChecker.isCompatible(metadata.deviceName, listOf(splitName))
} returns true
every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName
coEvery { backupPlugin.getInputStream(token, suffixName) } returns splitInputStream
coEvery { storagePlugin.getInputStream(token, suffixName) } returns splitInputStream
coEvery {
apkInstaller.install(capture(cacheFiles), packageName, installerName, any())
} returns MutableInstallResult(1).apply {

View file

@ -14,6 +14,8 @@ import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.ApkSplit
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.restore.RestorableBackup
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
@ -21,8 +23,6 @@ import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.restore.RestorePlugin
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
@ -50,15 +50,15 @@ internal class ApkRestoreTest : TransportTest() {
private val strictContext: Context = mockk<Context>().apply {
every { packageManager } returns pm
}
private val backupPlugin: BackupPlugin = mockk()
private val restorePlugin: RestorePlugin = mockk()
private val storagePlugin: StoragePlugin = mockk()
private val legacyStoragePlugin: LegacyStoragePlugin = mockk()
private val splitCompatChecker: ApkSplitCompatibilityChecker = mockk()
private val apkInstaller: ApkInstaller = mockk()
private val apkRestore: ApkRestore = ApkRestore(
strictContext,
backupPlugin,
restorePlugin,
storagePlugin,
legacyStoragePlugin,
crypto,
splitCompatChecker,
apkInstaller
@ -96,7 +96,7 @@ internal class ApkRestoreTest : TransportTest() {
every { strictContext.cacheDir } returns File(tmpDir.toString())
every { crypto.getNameForApk(salt, packageName, "") } returns name
coEvery { backupPlugin.getInputStream(token, name) } returns apkInputStream
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedFailFinished(i, value)
@ -110,7 +110,7 @@ internal class ApkRestoreTest : TransportTest() {
every { strictContext.cacheDir } returns File(tmpDir.toString())
every { crypto.getNameForApk(salt, packageName, "") } returns name
coEvery { backupPlugin.getInputStream(token, name) } returns apkInputStream
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo
apkRestore.restore(backup).collectIndexed { i, value ->
@ -169,7 +169,9 @@ internal class ApkRestoreTest : TransportTest() {
every { strictContext.cacheDir } returns File(tmpDir.toString())
@Suppress("Deprecation")
coEvery { restorePlugin.getApkInputStream(token, packageName, "") } returns apkInputStream
coEvery {
legacyStoragePlugin.getApkInputStream(token, packageName, "")
} returns apkInputStream
every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo
every {
@Suppress("UNRESOLVED_REFERENCE")
@ -299,7 +301,7 @@ internal class ApkRestoreTest : TransportTest() {
every { splitCompatChecker.isCompatible(deviceName, listOf(splitName)) } returns true
every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName
coEvery {
backupPlugin.getInputStream(token, suffixName)
storagePlugin.getInputStream(token, suffixName)
} returns ByteArrayInputStream(getRandomByteArray())
apkRestore.restore(backup).collectIndexed { i, value ->
@ -322,7 +324,7 @@ internal class ApkRestoreTest : TransportTest() {
every { splitCompatChecker.isCompatible(deviceName, listOf(splitName)) } returns true
every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName
coEvery { backupPlugin.getInputStream(token, suffixName) } throws IOException()
coEvery { storagePlugin.getInputStream(token, suffixName) } throws IOException()
apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedProgressFailFinished(i, value)
@ -358,9 +360,9 @@ internal class ApkRestoreTest : TransportTest() {
val suffixName1 = getRandomString()
val suffixName2 = getRandomString()
every { crypto.getNameForApk(salt, packageName, split1Name) } returns suffixName1
coEvery { backupPlugin.getInputStream(token, suffixName1) } returns split1InputStream
coEvery { storagePlugin.getInputStream(token, suffixName1) } returns split1InputStream
every { crypto.getNameForApk(salt, packageName, split2Name) } returns suffixName2
coEvery { backupPlugin.getInputStream(token, suffixName2) } returns split2InputStream
coEvery { storagePlugin.getInputStream(token, suffixName2) } returns split2InputStream
coEvery {
apkInstaller.install(match { it.size == 3 }, packageName, installerName, any())
@ -387,7 +389,7 @@ internal class ApkRestoreTest : TransportTest() {
private fun cacheBaseApkAndGetInfo(tmpDir: Path) {
every { strictContext.cacheDir } returns File(tmpDir.toString())
every { crypto.getNameForApk(salt, packageName, "") } returns name
coEvery { backupPlugin.getInputStream(token, name) } returns apkInputStream
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo
every {
@Suppress("UNRESOLVED_REFERENCE")

View file

@ -16,19 +16,18 @@ import com.stevesoltys.seedvault.metadata.BackupType
import com.stevesoltys.seedvault.metadata.MetadataReaderImpl
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA
import com.stevesoltys.seedvault.transport.backup.ApkBackup
import com.stevesoltys.seedvault.transport.backup.BackupCoordinator
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.backup.FullBackup
import com.stevesoltys.seedvault.transport.backup.InputFactory
import com.stevesoltys.seedvault.transport.backup.KVBackup
import com.stevesoltys.seedvault.transport.backup.PackageService
import com.stevesoltys.seedvault.transport.backup.TestKvDbManager
import com.stevesoltys.seedvault.transport.restore.FullRestore
import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin
import com.stevesoltys.seedvault.transport.restore.KVRestore
import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin
import com.stevesoltys.seedvault.transport.restore.OutputFactory
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
@ -61,7 +60,9 @@ internal class CoordinatorIntegrationTest : TransportTest() {
private val notificationManager = mockk<BackupNotificationManager>()
private val dbManager = TestKvDbManager()
private val backupPlugin = mockk<BackupPlugin>()
@Suppress("Deprecation")
private val legacyPlugin = mockk<LegacyStoragePlugin>()
private val backupPlugin = mockk<StoragePlugin>()
private val kvBackup =
KVBackup(backupPlugin, settingsManager, inputFactory, cryptoImpl, dbManager)
private val fullBackup = FullBackup(backupPlugin, settingsManager, inputFactory, cryptoImpl)
@ -80,18 +81,16 @@ internal class CoordinatorIntegrationTest : TransportTest() {
notificationManager
)
private val kvRestorePlugin = mockk<KVRestorePlugin>()
private val kvRestore = KVRestore(
backupPlugin,
kvRestorePlugin,
legacyPlugin,
outputFactory,
headerReader,
cryptoImpl,
dbManager
)
private val fullRestorePlugin = mockk<FullRestorePlugin>()
private val fullRestore =
FullRestore(backupPlugin, fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
FullRestore(backupPlugin, legacyPlugin, outputFactory, headerReader, cryptoImpl)
private val restore = RestoreCoordinator(
context,
crypto,

View file

@ -22,6 +22,7 @@ import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED
import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR
import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA
import com.stevesoltys.seedvault.settings.Storage
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
@ -44,7 +45,7 @@ import kotlin.random.Random
@Suppress("BlockingMethodInNonBlockingContext")
internal class BackupCoordinatorTest : BackupTest() {
private val plugin = mockk<BackupPlugin>()
private val plugin = mockk<StoragePlugin>()
private val kv = mockk<KVBackup>()
private val full = mockk<FullBackup>()
private val apkBackup = mockk<ApkBackup>()

View file

@ -6,6 +6,7 @@ import android.app.backup.BackupTransport.TRANSPORT_PACKAGE_REJECTED
import android.app.backup.BackupTransport.TRANSPORT_QUOTA_EXCEEDED
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.getADForFull
import com.stevesoltys.seedvault.plugins.StoragePlugin
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.every
@ -23,7 +24,7 @@ import kotlin.random.Random
@Suppress("BlockingMethodInNonBlockingContext")
internal class FullBackupTest : BackupTest() {
private val plugin = mockk<BackupPlugin>()
private val plugin = mockk<StoragePlugin>()
private val backup = FullBackup(plugin, settingsManager, inputFactory, crypto)
private val bytes = ByteArray(23).apply { Random.nextBytes(this) }

View file

@ -12,6 +12,7 @@ import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.header.MAX_KEY_LENGTH_SIZE
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.getADForKV
import com.stevesoltys.seedvault.plugins.StoragePlugin
import io.mockk.CapturingSlot
import io.mockk.Runs
import io.mockk.coEvery
@ -31,7 +32,7 @@ import kotlin.random.Random
@Suppress("BlockingMethodInNonBlockingContext")
internal class KVBackupTest : BackupTest() {
private val plugin = mockk<BackupPlugin>()
private val plugin = mockk<StoragePlugin>()
private val dataInput = mockk<BackupDataInput>()
private val dbManager = mockk<KvDbManager>()

View file

@ -11,7 +11,8 @@ import com.stevesoltys.seedvault.header.UnsupportedVersionException
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.VersionHeader
import com.stevesoltys.seedvault.header.getADForFull
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.plugins.StoragePlugin
import io.mockk.CapturingSlot
import io.mockk.Runs
import io.mockk.coEvery
@ -33,8 +34,8 @@ import kotlin.random.Random
@Suppress("BlockingMethodInNonBlockingContext")
internal class FullRestoreTest : RestoreTest() {
private val plugin = mockk<BackupPlugin>()
private val legacyPlugin = mockk<FullRestorePlugin>()
private val plugin = mockk<StoragePlugin>()
private val legacyPlugin = mockk<LegacyStoragePlugin>()
private val restore = FullRestore(plugin, legacyPlugin, outputFactory, headerReader, crypto)
private val encrypted = getRandomByteArray()
@ -50,7 +51,7 @@ internal class FullRestoreTest : RestoreTest() {
@Suppress("deprecation")
fun `v0 hasDataForPackage() delegates to plugin`() = runBlocking {
val result = Random.nextBoolean()
coEvery { legacyPlugin.hasDataForPackage(token, packageInfo) } returns result
coEvery { legacyPlugin.hasDataForFullPackage(token, packageInfo) } returns result
assertEquals(result, restore.hasDataForPackage(token, packageInfo))
}

View file

@ -10,9 +10,10 @@ import com.stevesoltys.seedvault.header.UnsupportedVersionException
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.VersionHeader
import com.stevesoltys.seedvault.header.getADForKV
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.transport.backup.KVDb
import com.stevesoltys.seedvault.transport.backup.KvDbManager
import com.stevesoltys.seedvault.plugins.StoragePlugin
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.every
@ -35,8 +36,8 @@ import kotlin.random.Random
@Suppress("BlockingMethodInNonBlockingContext")
internal class KVRestoreTest : RestoreTest() {
private val plugin = mockk<BackupPlugin>()
private val legacyPlugin = mockk<KVRestorePlugin>()
private val plugin = mockk<StoragePlugin>()
private val legacyPlugin = mockk<LegacyStoragePlugin>()
private val dbManager = mockk<KvDbManager>()
private val output = mockk<BackupDataOutput>()
private val restore =

View file

@ -16,8 +16,8 @@ import com.stevesoltys.seedvault.metadata.MetadataReader
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.settings.Storage
import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.backup.EncryptedMetadata
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.plugins.EncryptedMetadata
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import io.mockk.Runs
import io.mockk.coEvery
@ -39,7 +39,7 @@ import kotlin.random.Random
internal class RestoreCoordinatorTest : TransportTest() {
private val notificationManager: BackupNotificationManager = mockk()
private val plugin = mockk<BackupPlugin>()
private val plugin = mockk<StoragePlugin>()
private val kv = mockk<KVRestore>()
private val full = mockk<FullRestore>()
private val metadataReader = mockk<MetadataReader>()

View file

@ -13,10 +13,11 @@ import com.stevesoltys.seedvault.crypto.KeyManagerTestImpl
import com.stevesoltys.seedvault.encodeBase64
import com.stevesoltys.seedvault.header.HeaderReaderImpl
import com.stevesoltys.seedvault.metadata.MetadataReaderImpl
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
import com.stevesoltys.seedvault.toByteArrayFromHex
import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
import com.stevesoltys.seedvault.transport.backup.KvDbManager
import com.stevesoltys.seedvault.plugins.StoragePlugin
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import io.mockk.coEvery
import io.mockk.every
@ -49,19 +50,19 @@ internal class RestoreV0IntegrationTest : TransportTest() {
private val metadataReader = MetadataReaderImpl(cryptoImpl)
private val notificationManager = mockk<BackupNotificationManager>()
private val backupPlugin = mockk<BackupPlugin>()
private val kvRestorePlugin = mockk<KVRestorePlugin>()
@Suppress("Deprecation")
private val legacyPlugin = mockk<LegacyStoragePlugin>()
private val backupPlugin = mockk<StoragePlugin>()
private val kvRestore = KVRestore(
backupPlugin,
kvRestorePlugin,
legacyPlugin,
outputFactory,
headerReader,
cryptoImpl,
dbManager
)
private val fullRestorePlugin = mockk<FullRestorePlugin>()
private val fullRestore =
FullRestore(backupPlugin, fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
FullRestore(backupPlugin, legacyPlugin, outputFactory, headerReader, cryptoImpl)
private val restore = RestoreCoordinator(
context,
crypto,
@ -161,7 +162,7 @@ internal class RestoreV0IntegrationTest : TransportTest() {
assertEquals(TRANSPORT_OK, restore.startRestore(token, arrayOf(packageInfo)))
// find data for K/V backup
coEvery { kvRestorePlugin.hasDataForPackage(token, packageInfo) } returns true
coEvery { legacyPlugin.hasDataForPackage(token, packageInfo) } returns true
val restoreDescription = restore.nextRestorePackage() ?: fail()
assertEquals(packageInfo.packageName, restoreDescription.packageName)
@ -171,10 +172,10 @@ internal class RestoreV0IntegrationTest : TransportTest() {
val backupDataOutput = mockk<BackupDataOutput>()
val rInputStream = ByteArrayInputStream(encryptedAppData)
val rInputStream2 = ByteArrayInputStream(encryptedAppData2)
coEvery { kvRestorePlugin.listRecords(token, packageInfo) } returns listOf(key64, key264)
coEvery { legacyPlugin.listRecords(token, packageInfo) } returns listOf(key64, key264)
every { outputFactory.getBackupDataOutput(fileDescriptor) } returns backupDataOutput
coEvery {
kvRestorePlugin.getInputStreamForRecord(
legacyPlugin.getInputStreamForRecord(
token,
packageInfo,
key64
@ -183,7 +184,7 @@ internal class RestoreV0IntegrationTest : TransportTest() {
every { backupDataOutput.writeEntityHeader(key, appData.size) } returns 1137
every { backupDataOutput.writeEntityData(appData, appData.size) } returns appData.size
coEvery {
kvRestorePlugin.getInputStreamForRecord(
legacyPlugin.getInputStreamForRecord(
token,
packageInfo,
key264
@ -212,8 +213,8 @@ internal class RestoreV0IntegrationTest : TransportTest() {
assertEquals(TRANSPORT_OK, restore.startRestore(token, arrayOf(packageInfo)))
// find data only for full backup
coEvery { kvRestorePlugin.hasDataForPackage(token, packageInfo) } returns false
coEvery { fullRestorePlugin.hasDataForPackage(token, packageInfo) } returns true
coEvery { legacyPlugin.hasDataForPackage(token, packageInfo) } returns false
coEvery { legacyPlugin.hasDataForFullPackage(token, packageInfo) } returns true
val restoreDescription = restore.nextRestorePackage() ?: fail()
assertEquals(packageInfo.packageName, restoreDescription.packageName)
@ -223,7 +224,7 @@ internal class RestoreV0IntegrationTest : TransportTest() {
val inputStream = ByteArrayInputStream(encryptedData)
val outputStream = ByteArrayOutputStream()
coEvery {
fullRestorePlugin.getInputStreamForPackage(
legacyPlugin.getInputStreamForPackage(
token,
packageInfo
)