Use new storage API for full backups
This commit is contained in:
parent
4bdaaa0ce9
commit
674568ca11
9 changed files with 93 additions and 59 deletions
|
@ -219,6 +219,9 @@ internal class MetadataManager(
|
||||||
private val mLastBackupTime = MutableLiveData<Long>()
|
private val mLastBackupTime = MutableLiveData<Long>()
|
||||||
internal val lastBackupTime: LiveData<Long> = mLastBackupTime.distinctUntilChanged()
|
internal val lastBackupTime: LiveData<Long> = mLastBackupTime.distinctUntilChanged()
|
||||||
|
|
||||||
|
internal val salt: String
|
||||||
|
@Synchronized get() = metadata.salt
|
||||||
|
|
||||||
internal val isLegacyFormat: Boolean
|
internal val isLegacyFormat: Boolean
|
||||||
@Synchronized get() = metadata.version < VERSION
|
@Synchronized get() = metadata.version < VERSION
|
||||||
|
|
||||||
|
|
|
@ -310,7 +310,9 @@ internal class BackupCoordinator(
|
||||||
flags: Int
|
flags: Int
|
||||||
): Int {
|
): Int {
|
||||||
state.cancelReason = UNKNOWN_ERROR
|
state.cancelReason = UNKNOWN_ERROR
|
||||||
return full.performFullBackup(targetPackage, fileDescriptor, flags)
|
val token = settingsManager.getToken() ?: error("no token in performFullBackup")
|
||||||
|
val salt = metadataManager.salt
|
||||||
|
return full.performFullBackup(targetPackage, fileDescriptor, flags, token, salt)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendBackupData(numBytes: Int) = full.sendBackupData(numBytes)
|
suspend fun sendBackupData(numBytes: Int) = full.sendBackupData(numBytes)
|
||||||
|
@ -336,7 +338,9 @@ internal class BackupCoordinator(
|
||||||
" because of ${state.cancelReason}"
|
" because of ${state.cancelReason}"
|
||||||
)
|
)
|
||||||
onPackageBackupError(packageInfo, BackupType.FULL)
|
onPackageBackupError(packageInfo, BackupType.FULL)
|
||||||
full.cancelFullBackup()
|
val token = settingsManager.getToken() ?: error("no token in cancelFullBackup")
|
||||||
|
val salt = metadataManager.salt
|
||||||
|
full.cancelFullBackup(token, salt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear and Finish
|
// Clear and Finish
|
||||||
|
@ -353,6 +357,8 @@ internal class BackupCoordinator(
|
||||||
suspend fun clearBackupData(packageInfo: PackageInfo): Int {
|
suspend fun clearBackupData(packageInfo: PackageInfo): Int {
|
||||||
val packageName = packageInfo.packageName
|
val packageName = packageInfo.packageName
|
||||||
Log.i(TAG, "Clear Backup Data of $packageName.")
|
Log.i(TAG, "Clear Backup Data of $packageName.")
|
||||||
|
val token = settingsManager.getToken() ?: error("no token in clearBackupData")
|
||||||
|
val salt = metadataManager.salt
|
||||||
try {
|
try {
|
||||||
kv.clearBackupData(packageInfo)
|
kv.clearBackupData(packageInfo)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
|
@ -360,7 +366,7 @@ internal class BackupCoordinator(
|
||||||
return TRANSPORT_ERROR
|
return TRANSPORT_ERROR
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
full.clearBackupData(packageInfo)
|
full.clearBackupData(packageInfo, token, salt)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Log.w(TAG, "Error clearing full backup data for $packageName", e)
|
Log.w(TAG, "Error clearing full backup data for $packageName", e)
|
||||||
return TRANSPORT_ERROR
|
return TRANSPORT_ERROR
|
||||||
|
|
|
@ -29,7 +29,7 @@ val backupModule = module {
|
||||||
}
|
}
|
||||||
single {
|
single {
|
||||||
FullBackup(
|
FullBackup(
|
||||||
plugin = get<BackupPlugin>().fullBackupPlugin,
|
plugin = get(),
|
||||||
settingsManager = get(),
|
settingsManager = get(),
|
||||||
inputFactory = get(),
|
inputFactory = get(),
|
||||||
crypto = get()
|
crypto = get()
|
||||||
|
|
|
@ -38,7 +38,7 @@ private val TAG = FullBackup::class.java.simpleName
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
internal class FullBackup(
|
internal class FullBackup(
|
||||||
private val plugin: FullBackupPlugin,
|
private val plugin: BackupPlugin,
|
||||||
private val settingsManager: SettingsManager,
|
private val settingsManager: SettingsManager,
|
||||||
private val inputFactory: InputFactory,
|
private val inputFactory: InputFactory,
|
||||||
private val crypto: Crypto
|
private val crypto: Crypto
|
||||||
|
@ -51,7 +51,7 @@ internal class FullBackup(
|
||||||
fun getCurrentPackage() = state?.packageInfo
|
fun getCurrentPackage() = state?.packageInfo
|
||||||
|
|
||||||
fun getQuota(): Long {
|
fun getQuota(): Long {
|
||||||
return if (settingsManager.isQuotaUnlimited()) Long.MAX_VALUE else plugin.getQuota()
|
return if (settingsManager.isQuotaUnlimited()) Long.MAX_VALUE else DEFAULT_QUOTA_FULL_BACKUP
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkFullBackupSize(size: Long): Int {
|
fun checkFullBackupSize(size: Long): Int {
|
||||||
|
@ -101,20 +101,24 @@ internal class FullBackup(
|
||||||
suspend fun performFullBackup(
|
suspend fun performFullBackup(
|
||||||
targetPackage: PackageInfo,
|
targetPackage: PackageInfo,
|
||||||
socket: ParcelFileDescriptor,
|
socket: ParcelFileDescriptor,
|
||||||
@Suppress("UNUSED_PARAMETER") flags: Int = 0
|
@Suppress("UNUSED_PARAMETER") flags: Int = 0,
|
||||||
|
token: Long,
|
||||||
|
salt: String
|
||||||
): Int {
|
): Int {
|
||||||
if (state != null) throw AssertionError()
|
if (state != null) throw AssertionError()
|
||||||
Log.i(TAG, "Perform full backup for ${targetPackage.packageName}.")
|
val packageName = targetPackage.packageName
|
||||||
|
Log.i(TAG, "Perform full backup for $packageName.")
|
||||||
|
|
||||||
// create new state
|
// create new state
|
||||||
val inputStream = inputFactory.getInputStream(socket)
|
val inputStream = inputFactory.getInputStream(socket)
|
||||||
state = FullBackupState(targetPackage, socket, inputStream) {
|
state = FullBackupState(targetPackage, socket, inputStream) {
|
||||||
Log.d(TAG, "Initializing OutputStream for ${targetPackage.packageName}.")
|
Log.d(TAG, "Initializing OutputStream for $packageName.")
|
||||||
|
val name = crypto.getNameForPackage(salt, packageName)
|
||||||
// get OutputStream to write backup data into
|
// get OutputStream to write backup data into
|
||||||
val outputStream = try {
|
val outputStream = try {
|
||||||
plugin.getOutputStream(targetPackage)
|
plugin.getOutputStream(token, name)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
"Error getting OutputStream for full backup of ${targetPackage.packageName}".let {
|
"Error getting OutputStream for full backup of $packageName".let {
|
||||||
Log.e(TAG, it, e)
|
Log.e(TAG, it, e)
|
||||||
}
|
}
|
||||||
throw(e)
|
throw(e)
|
||||||
|
@ -167,15 +171,16 @@ internal class FullBackup(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
suspend fun clearBackupData(packageInfo: PackageInfo) {
|
suspend fun clearBackupData(packageInfo: PackageInfo, token: Long, salt: String) {
|
||||||
plugin.removeDataOfPackage(packageInfo)
|
val name = crypto.getNameForPackage(salt, packageInfo.packageName)
|
||||||
|
plugin.removeData(token, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun cancelFullBackup() {
|
suspend fun cancelFullBackup(token: Long, salt: String) {
|
||||||
Log.i(TAG, "Cancel full backup")
|
Log.i(TAG, "Cancel full backup")
|
||||||
val state = this.state ?: throw AssertionError("No state when canceling")
|
val state = this.state ?: throw AssertionError("No state when canceling")
|
||||||
try {
|
try {
|
||||||
plugin.removeDataOfPackage(state.packageInfo)
|
clearBackupData(state.packageInfo, token, salt)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Log.w(TAG, "Error cancelling full backup for ${state.packageName}", e)
|
Log.w(TAG, "Error cancelling full backup for ${state.packageName}", e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
)
|
)
|
||||||
private val fullBackupPlugin = mockk<FullBackupPlugin>()
|
private val fullBackupPlugin = mockk<FullBackupPlugin>()
|
||||||
private val fullBackup = FullBackup(
|
private val fullBackup = FullBackup(
|
||||||
plugin = fullBackupPlugin,
|
plugin = backupPlugin,
|
||||||
settingsManager = settingsManager,
|
settingsManager = settingsManager,
|
||||||
inputFactory = inputFactory,
|
inputFactory = inputFactory,
|
||||||
crypto = cryptoImpl
|
crypto = cryptoImpl
|
||||||
|
@ -295,11 +295,13 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
val packageMetadata = metadata.packageMetadataMap[packageInfo.packageName]!!
|
val packageMetadata = metadata.packageMetadataMap[packageInfo.packageName]!!
|
||||||
metadata.packageMetadataMap[packageInfo.packageName] =
|
metadata.packageMetadataMap[packageInfo.packageName] =
|
||||||
packageMetadata.copy(backupType = BackupType.FULL)
|
packageMetadata.copy(backupType = BackupType.FULL)
|
||||||
|
// as we use real crypto, we need a real name for packageInfo
|
||||||
|
val name = cryptoImpl.getNameForPackage(salt, packageInfo.packageName)
|
||||||
|
|
||||||
// return streams from plugin and app data
|
// return streams from plugin and app data
|
||||||
val bOutputStream = ByteArrayOutputStream()
|
val bOutputStream = ByteArrayOutputStream()
|
||||||
val bInputStream = ByteArrayInputStream(appData)
|
val bInputStream = ByteArrayInputStream(appData)
|
||||||
coEvery { fullBackupPlugin.getOutputStream(packageInfo) } returns bOutputStream
|
coEvery { backupPlugin.getOutputStream(token, name) } returns bOutputStream
|
||||||
every { inputFactory.getInputStream(fileDescriptor) } returns bInputStream
|
every { inputFactory.getInputStream(fileDescriptor) } returns bInputStream
|
||||||
every { settingsManager.isQuotaUnlimited() } returns false
|
every { settingsManager.isQuotaUnlimited() } returns false
|
||||||
every { fullBackupPlugin.getQuota() } returns DEFAULT_QUOTA_FULL_BACKUP
|
every { fullBackupPlugin.getQuota() } returns DEFAULT_QUOTA_FULL_BACKUP
|
||||||
|
@ -311,6 +313,7 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
)
|
)
|
||||||
} returns packageMetadata
|
} returns packageMetadata
|
||||||
every { settingsManager.getToken() } returns token
|
every { settingsManager.getToken() } returns token
|
||||||
|
every { metadataManager.salt } returns salt
|
||||||
coEvery {
|
coEvery {
|
||||||
backupPlugin.getOutputStream(token, FILE_BACKUP_METADATA)
|
backupPlugin.getOutputStream(token, FILE_BACKUP_METADATA)
|
||||||
} returns metadataOutputStream
|
} returns metadataOutputStream
|
||||||
|
@ -336,7 +339,7 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
assertEquals(TRANSPORT_OK, restore.startRestore(token, arrayOf(packageInfo)))
|
assertEquals(TRANSPORT_OK, restore.startRestore(token, arrayOf(packageInfo)))
|
||||||
|
|
||||||
// finds data for full backup
|
// finds data for full backup
|
||||||
every { crypto.getNameForPackage(metadata.salt, packageInfo.packageName) } returns name
|
every { crypto.getNameForPackage(salt, packageInfo.packageName) } returns name
|
||||||
coEvery { backupPlugin.hasData(token, name) } returns true
|
coEvery { backupPlugin.hasData(token, name) } returns true
|
||||||
|
|
||||||
val restoreDescription = restore.nextRestorePackage() ?: fail()
|
val restoreDescription = restore.nextRestorePackage() ?: fail()
|
||||||
|
|
|
@ -58,6 +58,7 @@ internal abstract class TransportTest {
|
||||||
put(packageInfo.packageName, PackageMetadata(backupType = BackupType.KV))
|
put(packageInfo.packageName, PackageMetadata(backupType = BackupType.KV))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
protected val salt = metadata.salt
|
||||||
protected val name = getRandomString(12)
|
protected val name = getRandomString(12)
|
||||||
protected val name2 = getRandomString(23)
|
protected val name2 = getRandomString(23)
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,8 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clearing KV backup data throws`() = runBlocking {
|
fun `clearing KV backup data throws`() = runBlocking {
|
||||||
|
every { settingsManager.getToken() } returns token
|
||||||
|
every { metadataManager.salt } returns salt
|
||||||
coEvery { kv.clearBackupData(packageInfo) } throws IOException()
|
coEvery { kv.clearBackupData(packageInfo) } throws IOException()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_ERROR, backup.clearBackupData(packageInfo))
|
assertEquals(TRANSPORT_ERROR, backup.clearBackupData(packageInfo))
|
||||||
|
@ -227,16 +229,20 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clearing full backup data throws`() = runBlocking {
|
fun `clearing full backup data throws`() = runBlocking {
|
||||||
|
every { settingsManager.getToken() } returns token
|
||||||
|
every { metadataManager.salt } returns salt
|
||||||
coEvery { kv.clearBackupData(packageInfo) } just Runs
|
coEvery { kv.clearBackupData(packageInfo) } just Runs
|
||||||
coEvery { full.clearBackupData(packageInfo) } throws IOException()
|
coEvery { full.clearBackupData(packageInfo, token, salt) } throws IOException()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_ERROR, backup.clearBackupData(packageInfo))
|
assertEquals(TRANSPORT_ERROR, backup.clearBackupData(packageInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clearing backup data succeeds`() = runBlocking {
|
fun `clearing backup data succeeds`() = runBlocking {
|
||||||
|
every { settingsManager.getToken() } returns token
|
||||||
|
every { metadataManager.salt } returns salt
|
||||||
coEvery { kv.clearBackupData(packageInfo) } just Runs
|
coEvery { kv.clearBackupData(packageInfo) } just Runs
|
||||||
coEvery { full.clearBackupData(packageInfo) } just Runs
|
coEvery { full.clearBackupData(packageInfo, token, salt) } just Runs
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.clearBackupData(packageInfo))
|
assertEquals(TRANSPORT_OK, backup.clearBackupData(packageInfo))
|
||||||
|
|
||||||
|
@ -288,7 +294,11 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `metadata does not get updated when no APK was backed up`() = runBlocking {
|
fun `metadata does not get updated when no APK was backed up`() = runBlocking {
|
||||||
coEvery { full.performFullBackup(packageInfo, fileDescriptor, 0) } returns TRANSPORT_OK
|
every { settingsManager.getToken() } returns token
|
||||||
|
every { metadataManager.salt } returns salt
|
||||||
|
coEvery {
|
||||||
|
full.performFullBackup(packageInfo, fileDescriptor, 0, token, salt)
|
||||||
|
} returns TRANSPORT_OK
|
||||||
coEvery { apkBackup.backupApkIfNecessary(packageInfo, UNKNOWN_ERROR, any()) } returns null
|
coEvery { apkBackup.backupApkIfNecessary(packageInfo, UNKNOWN_ERROR, any()) } returns null
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, fileDescriptor, 0))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, fileDescriptor, 0))
|
||||||
|
@ -296,7 +306,11 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `app exceeding quota gets cancelled and reason written to metadata`() = runBlocking {
|
fun `app exceeding quota gets cancelled and reason written to metadata`() = runBlocking {
|
||||||
coEvery { full.performFullBackup(packageInfo, fileDescriptor, 0) } returns TRANSPORT_OK
|
every { settingsManager.getToken() } returns token
|
||||||
|
every { metadataManager.salt } returns salt
|
||||||
|
coEvery {
|
||||||
|
full.performFullBackup(packageInfo, fileDescriptor, 0, token, salt)
|
||||||
|
} returns TRANSPORT_OK
|
||||||
expectApkBackupAndMetadataWrite()
|
expectApkBackupAndMetadataWrite()
|
||||||
every { full.getQuota() } returns DEFAULT_QUOTA_FULL_BACKUP
|
every { full.getQuota() } returns DEFAULT_QUOTA_FULL_BACKUP
|
||||||
every {
|
every {
|
||||||
|
@ -311,7 +325,7 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
BackupType.FULL
|
BackupType.FULL
|
||||||
)
|
)
|
||||||
} just Runs
|
} just Runs
|
||||||
coEvery { full.cancelFullBackup() } just Runs
|
coEvery { full.cancelFullBackup(token, metadata.salt) } just Runs
|
||||||
every { settingsManager.getStorage() } returns storage
|
every { settingsManager.getStorage() } returns storage
|
||||||
every { metadataOutputStream.close() } just Runs
|
every { metadataOutputStream.close() } just Runs
|
||||||
|
|
||||||
|
@ -343,7 +357,11 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `app with no data gets cancelled and reason written to metadata`() = runBlocking {
|
fun `app with no data gets cancelled and reason written to metadata`() = runBlocking {
|
||||||
coEvery { full.performFullBackup(packageInfo, fileDescriptor, 0) } returns TRANSPORT_OK
|
every { settingsManager.getToken() } returns token
|
||||||
|
every { metadataManager.salt } returns salt
|
||||||
|
coEvery {
|
||||||
|
full.performFullBackup(packageInfo, fileDescriptor, 0, token, salt)
|
||||||
|
} returns TRANSPORT_OK
|
||||||
expectApkBackupAndMetadataWrite()
|
expectApkBackupAndMetadataWrite()
|
||||||
every { full.getQuota() } returns DEFAULT_QUOTA_FULL_BACKUP
|
every { full.getQuota() } returns DEFAULT_QUOTA_FULL_BACKUP
|
||||||
every { full.checkFullBackupSize(0) } returns TRANSPORT_PACKAGE_REJECTED
|
every { full.checkFullBackupSize(0) } returns TRANSPORT_PACKAGE_REJECTED
|
||||||
|
@ -356,7 +374,7 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
BackupType.FULL
|
BackupType.FULL
|
||||||
)
|
)
|
||||||
} just Runs
|
} just Runs
|
||||||
coEvery { full.cancelFullBackup() } just Runs
|
coEvery { full.cancelFullBackup(token, metadata.salt) } just Runs
|
||||||
every { settingsManager.getStorage() } returns storage
|
every { settingsManager.getStorage() } returns storage
|
||||||
every { metadataOutputStream.close() } just Runs
|
every { metadataOutputStream.close() } just Runs
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,6 @@ internal abstract class BackupTest : TransportTest() {
|
||||||
protected val outputStream = mockk<OutputStream>()
|
protected val outputStream = mockk<OutputStream>()
|
||||||
protected val encryptedOutputStream = mockk<OutputStream>()
|
protected val encryptedOutputStream = mockk<OutputStream>()
|
||||||
|
|
||||||
protected val quota = 42L
|
protected val quota = DEFAULT_QUOTA_FULL_BACKUP
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import kotlin.random.Random
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
internal class FullBackupTest : BackupTest() {
|
internal class FullBackupTest : BackupTest() {
|
||||||
|
|
||||||
private val plugin = mockk<FullBackupPlugin>()
|
private val plugin = mockk<BackupPlugin>()
|
||||||
private val backup = FullBackup(plugin, settingsManager, inputFactory, crypto)
|
private val backup = FullBackup(plugin, settingsManager, inputFactory, crypto)
|
||||||
|
|
||||||
private val bytes = ByteArray(23).apply { Random.nextBytes(this) }
|
private val bytes = ByteArray(23).apply { Random.nextBytes(this) }
|
||||||
|
@ -38,9 +38,8 @@ internal class FullBackupTest : BackupTest() {
|
||||||
@Test
|
@Test
|
||||||
fun `checkFullBackupSize exceeds quota`() {
|
fun `checkFullBackupSize exceeds quota`() {
|
||||||
every { settingsManager.isQuotaUnlimited() } returns false
|
every { settingsManager.isQuotaUnlimited() } returns false
|
||||||
every { plugin.getQuota() } returns quota
|
|
||||||
|
|
||||||
assertEquals(TRANSPORT_QUOTA_EXCEEDED, backup.checkFullBackupSize(quota + 1))
|
assertEquals(TRANSPORT_QUOTA_EXCEEDED, backup.checkFullBackupSize(DEFAULT_QUOTA_FULL_BACKUP + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -63,7 +62,6 @@ internal class FullBackupTest : BackupTest() {
|
||||||
@Test
|
@Test
|
||||||
fun `checkFullBackupSize accepts min data`() {
|
fun `checkFullBackupSize accepts min data`() {
|
||||||
every { settingsManager.isQuotaUnlimited() } returns false
|
every { settingsManager.isQuotaUnlimited() } returns false
|
||||||
every { plugin.getQuota() } returns quota
|
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.checkFullBackupSize(1))
|
assertEquals(TRANSPORT_OK, backup.checkFullBackupSize(1))
|
||||||
}
|
}
|
||||||
|
@ -71,7 +69,6 @@ internal class FullBackupTest : BackupTest() {
|
||||||
@Test
|
@Test
|
||||||
fun `checkFullBackupSize accepts max data`() {
|
fun `checkFullBackupSize accepts max data`() {
|
||||||
every { settingsManager.isQuotaUnlimited() } returns false
|
every { settingsManager.isQuotaUnlimited() } returns false
|
||||||
every { plugin.getQuota() } returns quota
|
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.checkFullBackupSize(quota))
|
assertEquals(TRANSPORT_OK, backup.checkFullBackupSize(quota))
|
||||||
}
|
}
|
||||||
|
@ -81,7 +78,7 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputFactory.getInputStream(data) } returns inputStream
|
every { inputFactory.getInputStream(data) } returns inputStream
|
||||||
expectClearState()
|
expectClearState()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
||||||
assertFalse(backup.hasState())
|
assertFalse(backup.hasState())
|
||||||
|
@ -96,7 +93,7 @@ internal class FullBackupTest : BackupTest() {
|
||||||
expectSendData(numBytes)
|
expectSendData(numBytes)
|
||||||
expectClearState()
|
expectClearState()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_QUOTA_EXCEEDED, backup.sendBackupData(numBytes))
|
assertEquals(TRANSPORT_QUOTA_EXCEEDED, backup.sendBackupData(numBytes))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
|
@ -115,7 +112,7 @@ internal class FullBackupTest : BackupTest() {
|
||||||
expectSendData(numBytes2)
|
expectSendData(numBytes2)
|
||||||
expectClearState()
|
expectClearState()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_OK, backup.sendBackupData(numBytes1))
|
assertEquals(TRANSPORT_OK, backup.sendBackupData(numBytes1))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
|
@ -130,12 +127,11 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputFactory.getInputStream(data) } returns inputStream
|
every { inputFactory.getInputStream(data) } returns inputStream
|
||||||
expectInitializeOutputStream()
|
expectInitializeOutputStream()
|
||||||
every { settingsManager.isQuotaUnlimited() } returns false
|
every { settingsManager.isQuotaUnlimited() } returns false
|
||||||
every { plugin.getQuota() } returns quota
|
|
||||||
every { crypto.newEncryptingStream(outputStream, ad) } returns encryptedOutputStream
|
every { crypto.newEncryptingStream(outputStream, ad) } returns encryptedOutputStream
|
||||||
every { inputStream.read(any(), any(), bytes.size) } throws IOException()
|
every { inputStream.read(any(), any(), bytes.size) } throws IOException()
|
||||||
expectClearState()
|
expectClearState()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_ERROR, backup.sendBackupData(bytes.size))
|
assertEquals(TRANSPORT_ERROR, backup.sendBackupData(bytes.size))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
|
@ -148,11 +144,11 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputFactory.getInputStream(data) } returns inputStream
|
every { inputFactory.getInputStream(data) } returns inputStream
|
||||||
|
|
||||||
every { settingsManager.isQuotaUnlimited() } returns false
|
every { settingsManager.isQuotaUnlimited() } returns false
|
||||||
every { plugin.getQuota() } returns quota
|
every { crypto.getNameForPackage(salt, packageInfo.packageName) } returns name
|
||||||
coEvery { plugin.getOutputStream(packageInfo) } throws IOException()
|
coEvery { plugin.getOutputStream(token, name) } throws IOException()
|
||||||
expectClearState()
|
expectClearState()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_ERROR, backup.sendBackupData(bytes.size))
|
assertEquals(TRANSPORT_ERROR, backup.sendBackupData(bytes.size))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
|
@ -165,13 +161,13 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputFactory.getInputStream(data) } returns inputStream
|
every { inputFactory.getInputStream(data) } returns inputStream
|
||||||
|
|
||||||
every { settingsManager.isQuotaUnlimited() } returns false
|
every { settingsManager.isQuotaUnlimited() } returns false
|
||||||
every { plugin.getQuota() } returns quota
|
every { crypto.getNameForPackage(salt, packageInfo.packageName) } returns name
|
||||||
coEvery { plugin.getOutputStream(packageInfo) } returns outputStream
|
coEvery { plugin.getOutputStream(token, name) } returns outputStream
|
||||||
every { inputFactory.getInputStream(data) } returns inputStream
|
every { inputFactory.getInputStream(data) } returns inputStream
|
||||||
every { outputStream.write(ByteArray(1) { VERSION }) } throws IOException()
|
every { outputStream.write(ByteArray(1) { VERSION }) } throws IOException()
|
||||||
expectClearState()
|
expectClearState()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_ERROR, backup.sendBackupData(bytes.size))
|
assertEquals(TRANSPORT_ERROR, backup.sendBackupData(bytes.size))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
|
@ -185,13 +181,12 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputFactory.getInputStream(data) } returns inputStream
|
every { inputFactory.getInputStream(data) } returns inputStream
|
||||||
expectInitializeOutputStream()
|
expectInitializeOutputStream()
|
||||||
every { settingsManager.isQuotaUnlimited() } returns false
|
every { settingsManager.isQuotaUnlimited() } returns false
|
||||||
every { plugin.getQuota() } returns quota
|
|
||||||
every { crypto.newEncryptingStream(outputStream, ad) } returns encryptedOutputStream
|
every { crypto.newEncryptingStream(outputStream, ad) } returns encryptedOutputStream
|
||||||
every { inputStream.read(any(), any(), bytes.size) } returns bytes.size
|
every { inputStream.read(any(), any(), bytes.size) } returns bytes.size
|
||||||
every { encryptedOutputStream.write(any<ByteArray>()) } throws IOException()
|
every { encryptedOutputStream.write(any<ByteArray>()) } throws IOException()
|
||||||
expectClearState()
|
expectClearState()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_ERROR, backup.sendBackupData(bytes.size))
|
assertEquals(TRANSPORT_ERROR, backup.sendBackupData(bytes.size))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
|
@ -210,7 +205,7 @@ internal class FullBackupTest : BackupTest() {
|
||||||
expectSendData(numBytes2)
|
expectSendData(numBytes2)
|
||||||
expectClearState()
|
expectClearState()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_OK, backup.sendBackupData(numBytes1))
|
assertEquals(TRANSPORT_OK, backup.sendBackupData(numBytes1))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
|
@ -222,9 +217,10 @@ internal class FullBackupTest : BackupTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clearBackupData delegates to plugin`() = runBlocking {
|
fun `clearBackupData delegates to plugin`() = runBlocking {
|
||||||
coEvery { plugin.removeDataOfPackage(packageInfo) } just Runs
|
every { crypto.getNameForPackage(salt, packageInfo.packageName) } returns name
|
||||||
|
coEvery { plugin.removeData(token, name) } just Runs
|
||||||
|
|
||||||
backup.clearBackupData(packageInfo)
|
backup.clearBackupData(packageInfo, token, salt)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -232,11 +228,12 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputFactory.getInputStream(data) } returns inputStream
|
every { inputFactory.getInputStream(data) } returns inputStream
|
||||||
expectInitializeOutputStream()
|
expectInitializeOutputStream()
|
||||||
expectClearState()
|
expectClearState()
|
||||||
coEvery { plugin.removeDataOfPackage(packageInfo) } just Runs
|
every { crypto.getNameForPackage(salt, packageInfo.packageName) } returns name
|
||||||
|
coEvery { plugin.removeData(token, name) } just Runs
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
backup.cancelFullBackup()
|
backup.cancelFullBackup(token, salt)
|
||||||
assertFalse(backup.hasState())
|
assertFalse(backup.hasState())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,11 +242,12 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputFactory.getInputStream(data) } returns inputStream
|
every { inputFactory.getInputStream(data) } returns inputStream
|
||||||
expectInitializeOutputStream()
|
expectInitializeOutputStream()
|
||||||
expectClearState()
|
expectClearState()
|
||||||
coEvery { plugin.removeDataOfPackage(packageInfo) } throws IOException()
|
every { crypto.getNameForPackage(salt, packageInfo.packageName) } returns name
|
||||||
|
coEvery { plugin.removeData(token, name) } throws IOException()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
backup.cancelFullBackup()
|
backup.cancelFullBackup(token, salt)
|
||||||
assertFalse(backup.hasState())
|
assertFalse(backup.hasState())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +260,7 @@ internal class FullBackupTest : BackupTest() {
|
||||||
expectSendData(numBytes)
|
expectSendData(numBytes)
|
||||||
every { encryptedOutputStream.flush() } throws IOException()
|
every { encryptedOutputStream.flush() } throws IOException()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_OK, backup.sendBackupData(numBytes))
|
assertEquals(TRANSPORT_OK, backup.sendBackupData(numBytes))
|
||||||
assertEquals(TRANSPORT_ERROR, backup.finishBackup())
|
assertEquals(TRANSPORT_ERROR, backup.finishBackup())
|
||||||
|
@ -278,7 +276,7 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputStream.close() } just Runs
|
every { inputStream.close() } just Runs
|
||||||
every { data.close() } just Runs
|
every { data.close() } just Runs
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
||||||
assertFalse(backup.hasState())
|
assertFalse(backup.hasState())
|
||||||
|
@ -293,7 +291,7 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputStream.close() } throws IOException()
|
every { inputStream.close() } throws IOException()
|
||||||
every { data.close() } just Runs
|
every { data.close() } just Runs
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
||||||
assertFalse(backup.hasState())
|
assertFalse(backup.hasState())
|
||||||
|
@ -308,19 +306,19 @@ internal class FullBackupTest : BackupTest() {
|
||||||
every { inputStream.close() } just Runs
|
every { inputStream.close() } just Runs
|
||||||
every { data.close() } throws IOException()
|
every { data.close() } throws IOException()
|
||||||
|
|
||||||
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data))
|
assertEquals(TRANSPORT_OK, backup.performFullBackup(packageInfo, data, 0, token, salt))
|
||||||
assertTrue(backup.hasState())
|
assertTrue(backup.hasState())
|
||||||
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
||||||
assertFalse(backup.hasState())
|
assertFalse(backup.hasState())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun expectInitializeOutputStream() {
|
private fun expectInitializeOutputStream() {
|
||||||
coEvery { plugin.getOutputStream(packageInfo) } returns outputStream
|
every { crypto.getNameForPackage(salt, packageInfo.packageName) } returns name
|
||||||
|
coEvery { plugin.getOutputStream(token, name) } returns outputStream
|
||||||
every { outputStream.write(ByteArray(1) { VERSION }) } just Runs
|
every { outputStream.write(ByteArray(1) { VERSION }) } just Runs
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun expectSendData(numBytes: Int, readBytes: Int = numBytes) {
|
private fun expectSendData(numBytes: Int, readBytes: Int = numBytes) {
|
||||||
every { plugin.getQuota() } returns quota
|
|
||||||
every { inputStream.read(any(), any(), numBytes) } returns readBytes
|
every { inputStream.read(any(), any(), numBytes) } returns readBytes
|
||||||
every { crypto.newEncryptingStream(outputStream, ad) } returns encryptedOutputStream
|
every { crypto.newEncryptingStream(outputStream, ad) } returns encryptedOutputStream
|
||||||
every { encryptedOutputStream.write(any<ByteArray>()) } just Runs
|
every { encryptedOutputStream.write(any<ByteArray>()) } just Runs
|
||||||
|
|
Loading…
Reference in a new issue