Use new storage API for full restore
This commit is contained in:
parent
674568ca11
commit
23bb385190
7 changed files with 62 additions and 46 deletions
|
@ -12,6 +12,7 @@ import com.stevesoltys.seedvault.header.HeaderReader
|
||||||
import com.stevesoltys.seedvault.header.MAX_SEGMENT_LENGTH
|
import com.stevesoltys.seedvault.header.MAX_SEGMENT_LENGTH
|
||||||
import com.stevesoltys.seedvault.header.UnsupportedVersionException
|
import com.stevesoltys.seedvault.header.UnsupportedVersionException
|
||||||
import com.stevesoltys.seedvault.header.getADForFull
|
import com.stevesoltys.seedvault.header.getADForFull
|
||||||
|
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
|
||||||
import libcore.io.IoUtils.closeQuietly
|
import libcore.io.IoUtils.closeQuietly
|
||||||
import java.io.EOFException
|
import java.io.EOFException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
@ -22,6 +23,7 @@ import java.security.GeneralSecurityException
|
||||||
private class FullRestoreState(
|
private class FullRestoreState(
|
||||||
val version: Byte,
|
val version: Byte,
|
||||||
val token: Long,
|
val token: Long,
|
||||||
|
val name: String,
|
||||||
val packageInfo: PackageInfo
|
val packageInfo: PackageInfo
|
||||||
) {
|
) {
|
||||||
var inputStream: InputStream? = null
|
var inputStream: InputStream? = null
|
||||||
|
@ -31,7 +33,8 @@ private val TAG = FullRestore::class.java.simpleName
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
internal class FullRestore(
|
internal class FullRestore(
|
||||||
private val plugin: FullRestorePlugin,
|
private val plugin: BackupPlugin,
|
||||||
|
private val legacyPlugin: FullRestorePlugin,
|
||||||
private val outputFactory: OutputFactory,
|
private val outputFactory: OutputFactory,
|
||||||
private val headerReader: HeaderReader,
|
private val headerReader: HeaderReader,
|
||||||
private val crypto: Crypto
|
private val crypto: Crypto
|
||||||
|
@ -43,10 +46,13 @@ internal class FullRestore(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if there is data stored for the given package.
|
* Return true if there is data stored for the given package.
|
||||||
|
*
|
||||||
|
* Deprecated. Use only for v0 backups.
|
||||||
*/
|
*/
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
|
@Deprecated("Use BackupPlugin#hasData() instead")
|
||||||
suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean {
|
suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean {
|
||||||
return plugin.hasDataForPackage(token, packageInfo)
|
return legacyPlugin.hasDataForPackage(token, packageInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,8 +61,8 @@ internal class FullRestore(
|
||||||
* It is possible that the system decides to not restore the package.
|
* It is possible that the system decides to not restore the package.
|
||||||
* Then a new state will be initialized right away without calling other methods.
|
* Then a new state will be initialized right away without calling other methods.
|
||||||
*/
|
*/
|
||||||
fun initializeState(version: Byte, token: Long, packageInfo: PackageInfo) {
|
fun initializeState(version: Byte, token: Long, name: String, packageInfo: PackageInfo) {
|
||||||
state = FullRestoreState(version, token, packageInfo)
|
state = FullRestoreState(version, token, name, packageInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,12 +99,16 @@ internal class FullRestore(
|
||||||
if (state.inputStream == null) {
|
if (state.inputStream == null) {
|
||||||
Log.i(TAG, "First Chunk, initializing package input stream.")
|
Log.i(TAG, "First Chunk, initializing package input stream.")
|
||||||
try {
|
try {
|
||||||
val inputStream = plugin.getInputStreamForPackage(state.token, state.packageInfo)
|
if (state.version == 0.toByte()) {
|
||||||
|
val inputStream =
|
||||||
|
legacyPlugin.getInputStreamForPackage(state.token, state.packageInfo)
|
||||||
val version = headerReader.readVersion(inputStream, state.version)
|
val version = headerReader.readVersion(inputStream, state.version)
|
||||||
if (version == 0.toByte()) {
|
@Suppress("deprecation")
|
||||||
crypto.decryptHeader(inputStream, version, packageName)
|
crypto.decryptHeader(inputStream, version, packageName)
|
||||||
state.inputStream = inputStream
|
state.inputStream = inputStream
|
||||||
} else {
|
} else {
|
||||||
|
val inputStream = plugin.getInputStream(state.token, state.name)
|
||||||
|
val version = headerReader.readVersion(inputStream, state.version)
|
||||||
val ad = getADForFull(version, packageName)
|
val ad = getADForFull(version, packageName)
|
||||||
state.inputStream = crypto.newDecryptingStream(inputStream, ad)
|
state.inputStream = crypto.newDecryptingStream(inputStream, ad)
|
||||||
}
|
}
|
||||||
|
@ -135,6 +145,7 @@ internal class FullRestore(
|
||||||
if (state.version == 0.toByte()) {
|
if (state.version == 0.toByte()) {
|
||||||
// read segment from input stream and decrypt it
|
// read segment from input stream and decrypt it
|
||||||
val decrypted = try {
|
val decrypted = try {
|
||||||
|
@Suppress("deprecation")
|
||||||
crypto.decryptSegment(inputStream)
|
crypto.decryptSegment(inputStream)
|
||||||
} catch (e: EOFException) {
|
} catch (e: EOFException) {
|
||||||
Log.i(TAG, " EOF")
|
Log.i(TAG, " EOF")
|
||||||
|
|
|
@ -216,7 +216,7 @@ internal class RestoreCoordinator(
|
||||||
val name = crypto.getNameForPackage(state.backupMetadata.salt, packageName)
|
val name = crypto.getNameForPackage(state.backupMetadata.salt, packageName)
|
||||||
if (plugin.hasData(state.token, name)) {
|
if (plugin.hasData(state.token, name)) {
|
||||||
Log.i(TAG, "Found full backup data for $packageName.")
|
Log.i(TAG, "Found full backup data for $packageName.")
|
||||||
full.initializeState(version, state.token, packageInfo)
|
full.initializeState(version, state.token, name, packageInfo)
|
||||||
state.currentPackage = packageName
|
state.currentPackage = packageName
|
||||||
TYPE_FULL_STREAM
|
TYPE_FULL_STREAM
|
||||||
} else throw IOException("No data found for $packageName. Skipping.")
|
} else throw IOException("No data found for $packageName. Skipping.")
|
||||||
|
@ -232,6 +232,7 @@ internal class RestoreCoordinator(
|
||||||
return RestoreDescription(packageName, type)
|
return RestoreDescription(packageName, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("deprecation")
|
||||||
private suspend fun nextRestorePackageV0(
|
private suspend fun nextRestorePackageV0(
|
||||||
state: RestoreCoordinatorState,
|
state: RestoreCoordinatorState,
|
||||||
packageInfo: PackageInfo
|
packageInfo: PackageInfo
|
||||||
|
@ -248,7 +249,7 @@ internal class RestoreCoordinator(
|
||||||
}
|
}
|
||||||
full.hasDataForPackage(state.token, packageInfo) -> {
|
full.hasDataForPackage(state.token, packageInfo) -> {
|
||||||
Log.i(TAG, "Found full backup data for $packageName.")
|
Log.i(TAG, "Found full backup data for $packageName.")
|
||||||
full.initializeState(0x00, state.token, packageInfo)
|
full.initializeState(0x00, state.token, "", packageInfo)
|
||||||
state.currentPackage = packageName
|
state.currentPackage = packageName
|
||||||
TYPE_FULL_STREAM
|
TYPE_FULL_STREAM
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import org.koin.dsl.module
|
||||||
val restoreModule = module {
|
val restoreModule = module {
|
||||||
single { OutputFactory() }
|
single { OutputFactory() }
|
||||||
single { KVRestore(get<RestorePlugin>().kvRestorePlugin, get(), get(), get()) }
|
single { KVRestore(get<RestorePlugin>().kvRestorePlugin, get(), get(), get()) }
|
||||||
single { FullRestore(get<RestorePlugin>().fullRestorePlugin, get(), get(), get()) }
|
single { FullRestore(get(), get<RestorePlugin>().fullRestorePlugin, get(), get(), get()) }
|
||||||
single {
|
single {
|
||||||
RestoreCoordinator(androidContext(), get(), get(), get(), get(), get(), get(), get(), get())
|
RestoreCoordinator(androidContext(), get(), get(), get(), get(), get(), get(), get(), get())
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
private val kvRestore = KVRestore(kvRestorePlugin, outputFactory, headerReader, cryptoImpl)
|
private val kvRestore = KVRestore(kvRestorePlugin, outputFactory, headerReader, cryptoImpl)
|
||||||
private val fullRestorePlugin = mockk<FullRestorePlugin>()
|
private val fullRestorePlugin = mockk<FullRestorePlugin>()
|
||||||
private val fullRestore =
|
private val fullRestore =
|
||||||
FullRestore(fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
|
FullRestore(backupPlugin, fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
|
||||||
private val restore = RestoreCoordinator(
|
private val restore = RestoreCoordinator(
|
||||||
context,
|
context,
|
||||||
crypto,
|
crypto,
|
||||||
|
@ -122,7 +122,9 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
private val key264 = key2.encodeBase64()
|
private val key264 = key2.encodeBase64()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@Suppress("deprecation")
|
||||||
every { backupPlugin.kvBackupPlugin } returns kvBackupPlugin
|
every { backupPlugin.kvBackupPlugin } returns kvBackupPlugin
|
||||||
|
@Suppress("deprecation")
|
||||||
every { backupPlugin.fullBackupPlugin } returns fullBackupPlugin
|
every { backupPlugin.fullBackupPlugin } returns fullBackupPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,12 +351,7 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
// reverse the backup streams into restore input
|
// reverse the backup streams into restore input
|
||||||
val rInputStream = ByteArrayInputStream(bOutputStream.toByteArray())
|
val rInputStream = ByteArrayInputStream(bOutputStream.toByteArray())
|
||||||
val rOutputStream = ByteArrayOutputStream()
|
val rOutputStream = ByteArrayOutputStream()
|
||||||
coEvery {
|
coEvery { backupPlugin.getInputStream(token, name) } returns rInputStream
|
||||||
fullRestorePlugin.getInputStreamForPackage(
|
|
||||||
token,
|
|
||||||
packageInfo
|
|
||||||
)
|
|
||||||
} returns rInputStream
|
|
||||||
every { outputFactory.getOutputStream(fileDescriptor) } returns rOutputStream
|
every { outputFactory.getOutputStream(fileDescriptor) } returns rOutputStream
|
||||||
|
|
||||||
// restore data
|
// restore data
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.stevesoltys.seedvault.header.UnsupportedVersionException
|
||||||
import com.stevesoltys.seedvault.header.VERSION
|
import com.stevesoltys.seedvault.header.VERSION
|
||||||
import com.stevesoltys.seedvault.header.VersionHeader
|
import com.stevesoltys.seedvault.header.VersionHeader
|
||||||
import com.stevesoltys.seedvault.header.getADForFull
|
import com.stevesoltys.seedvault.header.getADForFull
|
||||||
|
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
|
||||||
import io.mockk.CapturingSlot
|
import io.mockk.CapturingSlot
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
|
@ -32,8 +33,9 @@ import kotlin.random.Random
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
internal class FullRestoreTest : RestoreTest() {
|
internal class FullRestoreTest : RestoreTest() {
|
||||||
|
|
||||||
private val plugin = mockk<FullRestorePlugin>()
|
private val plugin = mockk<BackupPlugin>()
|
||||||
private val restore = FullRestore(plugin, outputFactory, headerReader, crypto)
|
private val legacyPlugin = mockk<FullRestorePlugin>()
|
||||||
|
private val restore = FullRestore(plugin, legacyPlugin, outputFactory, headerReader, crypto)
|
||||||
|
|
||||||
private val encrypted = getRandomByteArray()
|
private val encrypted = getRandomByteArray()
|
||||||
private val outputStream = ByteArrayOutputStream()
|
private val outputStream = ByteArrayOutputStream()
|
||||||
|
@ -45,16 +47,17 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `hasDataForPackage() delegates to plugin`() = runBlocking {
|
@Suppress("deprecation")
|
||||||
|
fun `v0 hasDataForPackage() delegates to plugin`() = runBlocking {
|
||||||
val result = Random.nextBoolean()
|
val result = Random.nextBoolean()
|
||||||
coEvery { plugin.hasDataForPackage(token, packageInfo) } returns result
|
coEvery { legacyPlugin.hasDataForPackage(token, packageInfo) } returns result
|
||||||
assertEquals(result, restore.hasDataForPackage(token, packageInfo))
|
assertEquals(result, restore.hasDataForPackage(token, packageInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `initializing state leaves a state`() {
|
fun `initializing state leaves a state`() {
|
||||||
assertFalse(restore.hasState())
|
assertFalse(restore.hasState())
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
assertTrue(restore.hasState())
|
assertTrue(restore.hasState())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,9 +71,9 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getting InputStream for package when getting first chunk throws`() = runBlocking {
|
fun `getting InputStream for package when getting first chunk throws`() = runBlocking {
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
|
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } throws IOException()
|
coEvery { plugin.getInputStream(token, name) } throws IOException()
|
||||||
every { fileDescriptor.close() } just Runs
|
every { fileDescriptor.close() } just Runs
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -81,9 +84,9 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `reading version header when getting first chunk throws`() = runBlocking {
|
fun `reading version header when getting first chunk throws`() = runBlocking {
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
|
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
coEvery { plugin.getInputStream(token, name) } returns inputStream
|
||||||
every { headerReader.readVersion(inputStream, VERSION) } throws IOException()
|
every { headerReader.readVersion(inputStream, VERSION) } throws IOException()
|
||||||
every { fileDescriptor.close() } just Runs
|
every { fileDescriptor.close() } just Runs
|
||||||
|
|
||||||
|
@ -95,9 +98,9 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `reading unsupported version when getting first chunk`() = runBlocking {
|
fun `reading unsupported version when getting first chunk`() = runBlocking {
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
|
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
coEvery { plugin.getInputStream(token, name) } returns inputStream
|
||||||
every {
|
every {
|
||||||
headerReader.readVersion(inputStream, VERSION)
|
headerReader.readVersion(inputStream, VERSION)
|
||||||
} throws UnsupportedVersionException(unsupportedVersion)
|
} throws UnsupportedVersionException(unsupportedVersion)
|
||||||
|
@ -111,9 +114,9 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getting decrypted stream when getting first chunk throws`() = runBlocking {
|
fun `getting decrypted stream when getting first chunk throws`() = runBlocking {
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
|
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
coEvery { plugin.getInputStream(token, name) } returns inputStream
|
||||||
every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
|
every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
|
||||||
every { crypto.newDecryptingStream(inputStream, ad) } throws IOException()
|
every { crypto.newDecryptingStream(inputStream, ad) } throws IOException()
|
||||||
every { fileDescriptor.close() } just Runs
|
every { fileDescriptor.close() } just Runs
|
||||||
|
@ -127,9 +130,9 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
@Test
|
@Test
|
||||||
fun `getting decrypted stream when getting first chunk throws general security exception`() =
|
fun `getting decrypted stream when getting first chunk throws general security exception`() =
|
||||||
runBlocking {
|
runBlocking {
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
|
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
coEvery { plugin.getInputStream(token, name) } returns inputStream
|
||||||
every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
|
every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
|
||||||
every { crypto.newDecryptingStream(inputStream, ad) } throws GeneralSecurityException()
|
every { crypto.newDecryptingStream(inputStream, ad) } throws GeneralSecurityException()
|
||||||
every { fileDescriptor.close() } just Runs
|
every { fileDescriptor.close() } just Runs
|
||||||
|
@ -139,7 +142,7 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `full chunk gets decrypted`() = runBlocking {
|
fun `full chunk gets decrypted`() = runBlocking {
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
|
|
||||||
initInputStream()
|
initInputStream()
|
||||||
readAndEncryptInputStream(encrypted)
|
readAndEncryptInputStream(encrypted)
|
||||||
|
@ -152,10 +155,11 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Suppress("deprecation")
|
||||||
fun `full chunk gets decrypted from version 0`() = runBlocking {
|
fun `full chunk gets decrypted from version 0`() = runBlocking {
|
||||||
restore.initializeState(0.toByte(), token, packageInfo)
|
restore.initializeState(0.toByte(), token, name, packageInfo)
|
||||||
|
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
coEvery { legacyPlugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
||||||
every { headerReader.readVersion(inputStream, 0.toByte()) } returns 0.toByte()
|
every { headerReader.readVersion(inputStream, 0.toByte()) } returns 0.toByte()
|
||||||
every {
|
every {
|
||||||
crypto.decryptHeader(inputStream, 0.toByte(), packageInfo.packageName)
|
crypto.decryptHeader(inputStream, 0.toByte(), packageInfo.packageName)
|
||||||
|
@ -174,9 +178,9 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `unexpected version aborts with error`() = runBlocking {
|
fun `unexpected version aborts with error`() = runBlocking {
|
||||||
restore.initializeState(Byte.MAX_VALUE, token, packageInfo)
|
restore.initializeState(Byte.MAX_VALUE, token, name, packageInfo)
|
||||||
|
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
coEvery { plugin.getInputStream(token, name) } returns inputStream
|
||||||
every {
|
every {
|
||||||
headerReader.readVersion(inputStream, Byte.MAX_VALUE)
|
headerReader.readVersion(inputStream, Byte.MAX_VALUE)
|
||||||
} throws GeneralSecurityException()
|
} throws GeneralSecurityException()
|
||||||
|
@ -192,9 +196,9 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
fun `three full chunk get decrypted and then return no more data`() = runBlocking {
|
fun `three full chunk get decrypted and then return no more data`() = runBlocking {
|
||||||
val encryptedBytes = Random.nextBytes(MAX_SEGMENT_LENGTH * 2 + 1)
|
val encryptedBytes = Random.nextBytes(MAX_SEGMENT_LENGTH * 2 + 1)
|
||||||
val decryptedInputStream = ByteArrayInputStream(encryptedBytes)
|
val decryptedInputStream = ByteArrayInputStream(encryptedBytes)
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
|
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
coEvery { plugin.getInputStream(token, name) } returns inputStream
|
||||||
every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
|
every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
|
||||||
every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
|
every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
|
||||||
every { outputFactory.getOutputStream(fileDescriptor) } returns outputStream
|
every { outputFactory.getOutputStream(fileDescriptor) } returns outputStream
|
||||||
|
@ -213,7 +217,7 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `aborting full restore closes stream, resets state`() = runBlocking {
|
fun `aborting full restore closes stream, resets state`() = runBlocking {
|
||||||
restore.initializeState(VERSION, token, packageInfo)
|
restore.initializeState(VERSION, token, name, packageInfo)
|
||||||
|
|
||||||
initInputStream()
|
initInputStream()
|
||||||
readAndEncryptInputStream(encrypted)
|
readAndEncryptInputStream(encrypted)
|
||||||
|
@ -227,7 +231,7 @@ internal class FullRestoreTest : RestoreTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initInputStream() {
|
private fun initInputStream() {
|
||||||
coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
|
coEvery { plugin.getInputStream(token, name) } returns inputStream
|
||||||
every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
|
every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
|
||||||
every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
|
every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,13 +242,14 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Suppress("deprecation")
|
||||||
fun `v0 nextRestorePackage() returns full description if no KV data found`() = runBlocking {
|
fun `v0 nextRestorePackage() returns full description if no KV data found`() = runBlocking {
|
||||||
restore.beforeStartRestore(metadata.copy(version = 0x00))
|
restore.beforeStartRestore(metadata.copy(version = 0x00))
|
||||||
restore.startRestore(token, packageInfoArray)
|
restore.startRestore(token, packageInfoArray)
|
||||||
|
|
||||||
coEvery { kv.hasDataForPackage(token, packageInfo) } returns false
|
coEvery { kv.hasDataForPackage(token, packageInfo) } returns false
|
||||||
coEvery { full.hasDataForPackage(token, packageInfo) } returns true
|
coEvery { full.hasDataForPackage(token, packageInfo) } returns true
|
||||||
every { full.initializeState(0x00, token, packageInfo) } just Runs
|
every { full.initializeState(0x00, token, "", packageInfo) } just Runs
|
||||||
|
|
||||||
val expected = RestoreDescription(packageInfo.packageName, TYPE_FULL_STREAM)
|
val expected = RestoreDescription(packageInfo.packageName, TYPE_FULL_STREAM)
|
||||||
assertEquals(expected, restore.nextRestorePackage())
|
assertEquals(expected, restore.nextRestorePackage())
|
||||||
|
@ -276,7 +277,7 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
|
|
||||||
every { crypto.getNameForPackage(metadata.salt, packageInfo2.packageName) } returns name2
|
every { crypto.getNameForPackage(metadata.salt, packageInfo2.packageName) } returns name2
|
||||||
coEvery { plugin.hasData(token, name2) } returns true
|
coEvery { plugin.hasData(token, name2) } returns true
|
||||||
every { full.initializeState(VERSION, token, packageInfo2) } just Runs
|
every { full.initializeState(VERSION, token, name2, packageInfo2) } just Runs
|
||||||
|
|
||||||
val expected = RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
|
val expected = RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
|
||||||
assertEquals(expected, restore.nextRestorePackage())
|
assertEquals(expected, restore.nextRestorePackage())
|
||||||
|
@ -298,7 +299,7 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
|
|
||||||
every { crypto.getNameForPackage(metadata.salt, packageInfo2.packageName) } returns name2
|
every { crypto.getNameForPackage(metadata.salt, packageInfo2.packageName) } returns name2
|
||||||
coEvery { plugin.hasData(token, name2) } returns true
|
coEvery { plugin.hasData(token, name2) } returns true
|
||||||
every { full.initializeState(VERSION, token, packageInfo2) } just Runs
|
every { full.initializeState(VERSION, token, name2, packageInfo2) } just Runs
|
||||||
|
|
||||||
val expected2 =
|
val expected2 =
|
||||||
RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
|
RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
|
||||||
|
@ -308,6 +309,7 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Suppress("deprecation")
|
||||||
fun `v0 nextRestorePackage() returns all packages from startRestore()`() = runBlocking {
|
fun `v0 nextRestorePackage() returns all packages from startRestore()`() = runBlocking {
|
||||||
restore.beforeStartRestore(metadata.copy(version = 0x00))
|
restore.beforeStartRestore(metadata.copy(version = 0x00))
|
||||||
restore.startRestore(token, packageInfoArray2)
|
restore.startRestore(token, packageInfoArray2)
|
||||||
|
@ -320,7 +322,7 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
|
|
||||||
coEvery { kv.hasDataForPackage(token, packageInfo2) } returns false
|
coEvery { kv.hasDataForPackage(token, packageInfo2) } returns false
|
||||||
coEvery { full.hasDataForPackage(token, packageInfo2) } returns true
|
coEvery { full.hasDataForPackage(token, packageInfo2) } returns true
|
||||||
every { full.initializeState(0.toByte(), token, packageInfo2) } just Runs
|
every { full.initializeState(0.toByte(), token, "", packageInfo2) } just Runs
|
||||||
|
|
||||||
val expected2 = RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
|
val expected2 = RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
|
||||||
assertEquals(expected2, restore.nextRestorePackage())
|
assertEquals(expected2, restore.nextRestorePackage())
|
||||||
|
@ -352,6 +354,7 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Suppress("deprecation")
|
||||||
fun `v0 when full#hasDataForPackage() throws, it tries next package`() = runBlocking {
|
fun `v0 when full#hasDataForPackage() throws, it tries next package`() = runBlocking {
|
||||||
restore.beforeStartRestore(metadata.copy(version = 0x00))
|
restore.beforeStartRestore(metadata.copy(version = 0x00))
|
||||||
restore.startRestore(token, packageInfoArray)
|
restore.startRestore(token, packageInfoArray)
|
||||||
|
|
|
@ -52,7 +52,7 @@ internal class RestoreV0IntegrationTest : TransportTest() {
|
||||||
private val kvRestore = KVRestore(kvRestorePlugin, outputFactory, headerReader, cryptoImpl)
|
private val kvRestore = KVRestore(kvRestorePlugin, outputFactory, headerReader, cryptoImpl)
|
||||||
private val fullRestorePlugin = mockk<FullRestorePlugin>()
|
private val fullRestorePlugin = mockk<FullRestorePlugin>()
|
||||||
private val fullRestore =
|
private val fullRestore =
|
||||||
FullRestore(fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
|
FullRestore(backupPlugin, fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
|
||||||
private val restore = RestoreCoordinator(
|
private val restore = RestoreCoordinator(
|
||||||
context,
|
context,
|
||||||
crypto,
|
crypto,
|
||||||
|
|
Loading…
Reference in a new issue