Use DigestInputStream to spy on backup data
this is to save memory to prevent OOM errors we saw on CI
This commit is contained in:
parent
1d17adedff
commit
a538a64395
4 changed files with 26 additions and 77 deletions
|
@ -9,7 +9,6 @@ import android.content.pm.PackageInfo
|
|||
import android.os.ParcelFileDescriptor
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.stevesoltys.seedvault.e2e.io.BackupDataInputIntercept
|
||||
import com.stevesoltys.seedvault.e2e.io.InputStreamIntercept
|
||||
import com.stevesoltys.seedvault.e2e.screen.impl.BackupScreen
|
||||
import com.stevesoltys.seedvault.transport.backup.FullBackup
|
||||
import com.stevesoltys.seedvault.transport.backup.InputFactory
|
||||
|
@ -21,8 +20,10 @@ import io.mockk.every
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.calyxos.seedvault.core.toHexString
|
||||
import org.koin.core.component.get
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.security.DigestInputStream
|
||||
import java.security.MessageDigest
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.test.fail
|
||||
|
||||
|
@ -154,7 +155,8 @@ internal interface LargeBackupTestBase : LargeTestBase {
|
|||
|
||||
private fun spyOnFullBackupData(backupResult: SeedvaultLargeTestResult) {
|
||||
var packageName: String? = null
|
||||
var dataIntercept = ByteArrayOutputStream()
|
||||
val messageDigest = MessageDigest.getInstance("SHA-256")
|
||||
var digestInputStream: DigestInputStream? = null
|
||||
|
||||
coEvery {
|
||||
spyFullBackup.performFullBackup(any(), any(), any())
|
||||
|
@ -166,20 +168,19 @@ internal interface LargeBackupTestBase : LargeTestBase {
|
|||
every {
|
||||
spyInputFactory.getInputStream(any())
|
||||
} answers {
|
||||
InputStreamIntercept(
|
||||
inputStream = callOriginal(),
|
||||
intercept = dataIntercept
|
||||
)
|
||||
digestInputStream = DigestInputStream(callOriginal(), messageDigest)
|
||||
digestInputStream!!
|
||||
}
|
||||
|
||||
coEvery {
|
||||
spyFullBackup.finishBackup()
|
||||
} answers {
|
||||
val result = callOriginal()
|
||||
backupResult.full[packageName!!] = dataIntercept.toByteArray().sha256()
|
||||
val digest = digestInputStream?.messageDigest ?: fail("No digestInputStream")
|
||||
backupResult.full[packageName!!] = digest.digest().toHexString()
|
||||
|
||||
packageName = null
|
||||
dataIntercept = ByteArrayOutputStream()
|
||||
digest.reset()
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ package com.stevesoltys.seedvault.e2e
|
|||
import android.content.pm.PackageInfo
|
||||
import android.os.ParcelFileDescriptor
|
||||
import com.stevesoltys.seedvault.e2e.io.BackupDataOutputIntercept
|
||||
import com.stevesoltys.seedvault.e2e.io.OutputStreamIntercept
|
||||
import com.stevesoltys.seedvault.e2e.screen.impl.RecoveryCodeScreen
|
||||
import com.stevesoltys.seedvault.e2e.screen.impl.RestoreScreen
|
||||
import com.stevesoltys.seedvault.transport.restore.FullRestore
|
||||
|
@ -24,8 +23,11 @@ import kotlinx.coroutines.delay
|
|||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.calyxos.seedvault.core.toHexString
|
||||
import org.koin.core.component.get
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.security.DigestOutputStream
|
||||
import java.security.MessageDigest
|
||||
import kotlin.test.fail
|
||||
|
||||
internal interface LargeRestoreTestBase : LargeTestBase {
|
||||
|
||||
|
@ -196,7 +198,8 @@ internal interface LargeRestoreTestBase : LargeTestBase {
|
|||
|
||||
private fun spyOnFullRestoreData(restoreResult: SeedvaultLargeTestResult) {
|
||||
var packageName: String? = null
|
||||
var dataIntercept = ByteArrayOutputStream()
|
||||
val messageDigest = MessageDigest.getInstance("SHA-256")
|
||||
var digestOutputStream: DigestOutputStream? = null
|
||||
|
||||
clearMocks(spyFullRestore)
|
||||
|
||||
|
@ -204,11 +207,13 @@ internal interface LargeRestoreTestBase : LargeTestBase {
|
|||
packageInfoIndex: Int
|
||||
): MockKAnswerScope<Unit, Unit>.(Call) -> Unit = {
|
||||
packageName?.let {
|
||||
restoreResult.full[it] = dataIntercept.toByteArray().sha256()
|
||||
// sometimes finishRestore() doesn't get called, so get data from last package here
|
||||
digestOutputStream?.messageDigest?.let { digest ->
|
||||
restoreResult.full[packageName!!] = digest.digest().toHexString()
|
||||
}
|
||||
}
|
||||
|
||||
packageName = arg<PackageInfo>(packageInfoIndex).packageName
|
||||
dataIntercept = ByteArrayOutputStream()
|
||||
|
||||
callOriginal()
|
||||
}
|
||||
|
@ -228,27 +233,26 @@ internal interface LargeRestoreTestBase : LargeTestBase {
|
|||
every {
|
||||
spyOutputFactory.getOutputStream(any())
|
||||
} answers {
|
||||
OutputStreamIntercept(
|
||||
outputStream = callOriginal(),
|
||||
intercept = dataIntercept
|
||||
)
|
||||
digestOutputStream = DigestOutputStream(callOriginal(), messageDigest)
|
||||
digestOutputStream!!
|
||||
}
|
||||
|
||||
every {
|
||||
spyFullRestore.abortFullRestore()
|
||||
} answers {
|
||||
packageName = null
|
||||
dataIntercept = ByteArrayOutputStream()
|
||||
digestOutputStream?.messageDigest?.reset()
|
||||
callOriginal()
|
||||
}
|
||||
|
||||
every {
|
||||
spyFullRestore.finishRestore()
|
||||
} answers {
|
||||
restoreResult.full[packageName!!] = dataIntercept.toByteArray().sha256()
|
||||
val digest = digestOutputStream?.messageDigest ?: fail("No digestOutputStream")
|
||||
restoreResult.full[packageName!!] = digest.digest().toHexString()
|
||||
|
||||
packageName = null
|
||||
dataIntercept = ByteArrayOutputStream()
|
||||
digest.reset()
|
||||
callOriginal()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The Calyx Institute
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.stevesoltys.seedvault.e2e.io
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
|
||||
class InputStreamIntercept(
|
||||
private val inputStream: InputStream,
|
||||
private val intercept: ByteArrayOutputStream
|
||||
) : InputStream() {
|
||||
|
||||
override fun read(): Int {
|
||||
val byte = inputStream.read()
|
||||
if (byte != -1) {
|
||||
intercept.write(byte)
|
||||
}
|
||||
return byte
|
||||
}
|
||||
|
||||
override fun read(buffer: ByteArray, offset: Int, length: Int): Int {
|
||||
val bytesRead = inputStream.read(buffer, offset, length)
|
||||
if (bytesRead != -1) {
|
||||
intercept.write(buffer, offset, bytesRead)
|
||||
}
|
||||
return bytesRead
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The Calyx Institute
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.stevesoltys.seedvault.e2e.io
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
class OutputStreamIntercept(
|
||||
private val outputStream: OutputStream,
|
||||
private val intercept: ByteArrayOutputStream
|
||||
) : OutputStream() {
|
||||
|
||||
override fun write(byte: Int) {
|
||||
intercept.write(byte)
|
||||
outputStream.write(byte)
|
||||
}
|
||||
|
||||
override fun write(buffer: ByteArray, offset: Int, length: Int) {
|
||||
intercept.write(buffer, offset, length)
|
||||
outputStream.write(buffer, offset, length)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue