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

View file

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

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