From a68d2ebcb42f5ce18ff6d448b483d3964688a78f Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 11 Oct 2024 13:55:33 -0300 Subject: [PATCH] Use DigestInputStream to spy on backup data this is to save memory to prevent OOM errors we saw on CI --- .../seedvault/e2e/LargeBackupTestBase.kt | 19 ++++++------ .../seedvault/e2e/LargeRestoreTestBase.kt | 28 ++++++++++------- .../seedvault/e2e/io/InputStreamIntercept.kt | 31 ------------------- .../seedvault/e2e/io/OutputStreamIntercept.kt | 25 --------------- 4 files changed, 26 insertions(+), 77 deletions(-) delete mode 100644 app/src/androidTest/java/com/stevesoltys/seedvault/e2e/io/InputStreamIntercept.kt delete mode 100644 app/src/androidTest/java/com/stevesoltys/seedvault/e2e/io/OutputStreamIntercept.kt diff --git a/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/LargeBackupTestBase.kt b/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/LargeBackupTestBase.kt index 95d05d839..45eb730a8 100644 --- a/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/LargeBackupTestBase.kt +++ b/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/LargeBackupTestBase.kt @@ -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 } } diff --git a/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/LargeRestoreTestBase.kt b/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/LargeRestoreTestBase.kt index d104d3ed2..133a27d2d 100644 --- a/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/LargeRestoreTestBase.kt +++ b/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/LargeRestoreTestBase.kt @@ -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.(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(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() } } diff --git a/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/io/InputStreamIntercept.kt b/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/io/InputStreamIntercept.kt deleted file mode 100644 index 30c4fdf50..000000000 --- a/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/io/InputStreamIntercept.kt +++ /dev/null @@ -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 - } -} diff --git a/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/io/OutputStreamIntercept.kt b/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/io/OutputStreamIntercept.kt deleted file mode 100644 index d82f0b060..000000000 --- a/app/src/androidTest/java/com/stevesoltys/seedvault/e2e/io/OutputStreamIntercept.kt +++ /dev/null @@ -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) - } -}