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:
Torsten Grote 2024-10-11 13:55:33 -03:00
parent 1d17adedff
commit a538a64395
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
4 changed files with 26 additions and 77 deletions

View file

@ -9,7 +9,6 @@ import android.content.pm.PackageInfo
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until
import com.stevesoltys.seedvault.e2e.io.BackupDataInputIntercept 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.e2e.screen.impl.BackupScreen
import com.stevesoltys.seedvault.transport.backup.FullBackup import com.stevesoltys.seedvault.transport.backup.FullBackup
import com.stevesoltys.seedvault.transport.backup.InputFactory import com.stevesoltys.seedvault.transport.backup.InputFactory
@ -21,8 +20,10 @@ import io.mockk.every
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeout
import org.calyxos.seedvault.core.toHexString
import org.koin.core.component.get 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 java.util.concurrent.atomic.AtomicBoolean
import kotlin.test.fail import kotlin.test.fail
@ -154,7 +155,8 @@ internal interface LargeBackupTestBase : LargeTestBase {
private fun spyOnFullBackupData(backupResult: SeedvaultLargeTestResult) { private fun spyOnFullBackupData(backupResult: SeedvaultLargeTestResult) {
var packageName: String? = null var packageName: String? = null
var dataIntercept = ByteArrayOutputStream() val messageDigest = MessageDigest.getInstance("SHA-256")
var digestInputStream: DigestInputStream? = null
coEvery { coEvery {
spyFullBackup.performFullBackup(any(), any(), any()) spyFullBackup.performFullBackup(any(), any(), any())
@ -166,20 +168,19 @@ internal interface LargeBackupTestBase : LargeTestBase {
every { every {
spyInputFactory.getInputStream(any()) spyInputFactory.getInputStream(any())
} answers { } answers {
InputStreamIntercept( digestInputStream = DigestInputStream(callOriginal(), messageDigest)
inputStream = callOriginal(), digestInputStream!!
intercept = dataIntercept
)
} }
coEvery { coEvery {
spyFullBackup.finishBackup() spyFullBackup.finishBackup()
} answers { } answers {
val result = callOriginal() val result = callOriginal()
backupResult.full[packageName!!] = dataIntercept.toByteArray().sha256() val digest = digestInputStream?.messageDigest ?: fail("No digestInputStream")
backupResult.full[packageName!!] = digest.digest().toHexString()
packageName = null packageName = null
dataIntercept = ByteArrayOutputStream() digest.reset()
result result
} }
} }

View file

@ -8,7 +8,6 @@ package com.stevesoltys.seedvault.e2e
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import com.stevesoltys.seedvault.e2e.io.BackupDataOutputIntercept 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.RecoveryCodeScreen
import com.stevesoltys.seedvault.e2e.screen.impl.RestoreScreen import com.stevesoltys.seedvault.e2e.screen.impl.RestoreScreen
import com.stevesoltys.seedvault.transport.restore.FullRestore import com.stevesoltys.seedvault.transport.restore.FullRestore
@ -24,8 +23,11 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeout
import org.calyxos.seedvault.core.toHexString
import org.koin.core.component.get 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 { internal interface LargeRestoreTestBase : LargeTestBase {
@ -196,7 +198,8 @@ internal interface LargeRestoreTestBase : LargeTestBase {
private fun spyOnFullRestoreData(restoreResult: SeedvaultLargeTestResult) { private fun spyOnFullRestoreData(restoreResult: SeedvaultLargeTestResult) {
var packageName: String? = null var packageName: String? = null
var dataIntercept = ByteArrayOutputStream() val messageDigest = MessageDigest.getInstance("SHA-256")
var digestOutputStream: DigestOutputStream? = null
clearMocks(spyFullRestore) clearMocks(spyFullRestore)
@ -204,11 +207,13 @@ internal interface LargeRestoreTestBase : LargeTestBase {
packageInfoIndex: Int packageInfoIndex: Int
): MockKAnswerScope<Unit, Unit>.(Call) -> Unit = { ): MockKAnswerScope<Unit, Unit>.(Call) -> Unit = {
packageName?.let { 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 packageName = arg<PackageInfo>(packageInfoIndex).packageName
dataIntercept = ByteArrayOutputStream()
callOriginal() callOriginal()
} }
@ -228,27 +233,26 @@ internal interface LargeRestoreTestBase : LargeTestBase {
every { every {
spyOutputFactory.getOutputStream(any()) spyOutputFactory.getOutputStream(any())
} answers { } answers {
OutputStreamIntercept( digestOutputStream = DigestOutputStream(callOriginal(), messageDigest)
outputStream = callOriginal(), digestOutputStream!!
intercept = dataIntercept
)
} }
every { every {
spyFullRestore.abortFullRestore() spyFullRestore.abortFullRestore()
} answers { } answers {
packageName = null packageName = null
dataIntercept = ByteArrayOutputStream() digestOutputStream?.messageDigest?.reset()
callOriginal() callOriginal()
} }
every { every {
spyFullRestore.finishRestore() spyFullRestore.finishRestore()
} answers { } answers {
restoreResult.full[packageName!!] = dataIntercept.toByteArray().sha256() val digest = digestOutputStream?.messageDigest ?: fail("No digestOutputStream")
restoreResult.full[packageName!!] = digest.digest().toHexString()
packageName = null packageName = null
dataIntercept = ByteArrayOutputStream() digest.reset()
callOriginal() callOriginal()
} }
} }

View file

@ -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
}
}

View file

@ -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)
}
}