Add unit tests for re-installing apps with APK splits
This commit is contained in:
parent
608e67cb65
commit
0f0f198228
1 changed files with 120 additions and 0 deletions
|
@ -8,7 +8,10 @@ import android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import com.stevesoltys.seedvault.getRandomBase64
|
||||||
|
import com.stevesoltys.seedvault.getRandomByteArray
|
||||||
import com.stevesoltys.seedvault.getRandomString
|
import com.stevesoltys.seedvault.getRandomString
|
||||||
|
import com.stevesoltys.seedvault.metadata.ApkSplit
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
||||||
|
@ -33,6 +36,7 @@ import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.io.TempDir
|
import org.junit.jupiter.api.io.TempDir
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
@ -206,6 +210,122 @@ internal class ApkRestoreTest : TransportTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `incompatible splits cause FAILED state`(@TempDir tmpDir: Path) = runBlocking {
|
||||||
|
// add one APK split to metadata
|
||||||
|
val split1Name = getRandomString()
|
||||||
|
val split2Name = getRandomString()
|
||||||
|
packageMetadataMap[packageName] = packageMetadataMap[packageName]!!.copy(
|
||||||
|
splits = listOf(
|
||||||
|
ApkSplit(split1Name, getRandomBase64()),
|
||||||
|
ApkSplit(split2Name, getRandomBase64())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// cache APK and get icon as well as app name
|
||||||
|
cacheBaseApkAndGetInfo(tmpDir)
|
||||||
|
|
||||||
|
// splits are NOT compatible
|
||||||
|
every { splitCompatChecker.isCompatible(listOf(split1Name, split2Name)) } returns false
|
||||||
|
|
||||||
|
apkRestore.restore(token, packageMetadataMap).collectIndexed { i, value ->
|
||||||
|
assertQueuedProgressFailFinished(i, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `split signature mismatch causes FAILED state`(@TempDir tmpDir: Path) = runBlocking {
|
||||||
|
// add one APK split to metadata
|
||||||
|
val splitName = getRandomString()
|
||||||
|
val sha256 = getRandomBase64(23)
|
||||||
|
packageMetadataMap[packageName] = packageMetadataMap[packageName]!!.copy(
|
||||||
|
splits = listOf(ApkSplit(splitName, sha256))
|
||||||
|
)
|
||||||
|
|
||||||
|
// cache APK and get icon as well as app name
|
||||||
|
cacheBaseApkAndGetInfo(tmpDir)
|
||||||
|
|
||||||
|
every { splitCompatChecker.isCompatible(listOf(splitName)) } returns true
|
||||||
|
coEvery {
|
||||||
|
restorePlugin.getApkInputStream(token, packageName, "_$sha256")
|
||||||
|
} returns ByteArrayInputStream(getRandomByteArray())
|
||||||
|
|
||||||
|
apkRestore.restore(token, packageMetadataMap).collectIndexed { i, value ->
|
||||||
|
assertQueuedProgressFailFinished(i, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `exception while getting split data causes FAILED state`(@TempDir tmpDir: Path) =
|
||||||
|
runBlocking {
|
||||||
|
// add one APK split to metadata
|
||||||
|
val splitName = getRandomString()
|
||||||
|
val sha256 = getRandomBase64(23)
|
||||||
|
packageMetadataMap[packageName] = packageMetadataMap[packageName]!!.copy(
|
||||||
|
splits = listOf(ApkSplit(splitName, sha256))
|
||||||
|
)
|
||||||
|
|
||||||
|
// cache APK and get icon as well as app name
|
||||||
|
cacheBaseApkAndGetInfo(tmpDir)
|
||||||
|
|
||||||
|
every { splitCompatChecker.isCompatible(listOf(splitName)) } returns true
|
||||||
|
coEvery {
|
||||||
|
restorePlugin.getApkInputStream(token, packageName, "_$sha256")
|
||||||
|
} throws IOException()
|
||||||
|
|
||||||
|
apkRestore.restore(token, packageMetadataMap).collectIndexed { i, value ->
|
||||||
|
assertQueuedProgressFailFinished(i, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `splits get installed along with base APK`(@TempDir tmpDir: Path) = runBlocking {
|
||||||
|
// add one APK split to metadata
|
||||||
|
val split1Name = getRandomString()
|
||||||
|
val split2Name = getRandomString()
|
||||||
|
val split1sha256 = "A5BYxvLAy0ksUzsKTRTvd8wPeKvMztUofYShogEc-4E"
|
||||||
|
val split2sha256 = "ZqZ1cVH47lXbEncWx-Pc4L6AdLZOIO2lQuXB5GypxB4"
|
||||||
|
packageMetadataMap[packageName] = packageMetadataMap[packageName]!!.copy(
|
||||||
|
splits = listOf(
|
||||||
|
ApkSplit(split1Name, split1sha256),
|
||||||
|
ApkSplit(split2Name, split2sha256)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// cache APK and get icon as well as app name
|
||||||
|
cacheBaseApkAndGetInfo(tmpDir)
|
||||||
|
|
||||||
|
every { splitCompatChecker.isCompatible(listOf(split1Name, split2Name)) } returns true
|
||||||
|
|
||||||
|
// define bytes of splits and return them as stream (matches above hashes)
|
||||||
|
val split1Bytes = byteArrayOf(0x01, 0x02, 0x03)
|
||||||
|
val split2Bytes = byteArrayOf(0x07, 0x08, 0x09)
|
||||||
|
val split1InputStream = ByteArrayInputStream(split1Bytes)
|
||||||
|
val split2InputStream = ByteArrayInputStream(split2Bytes)
|
||||||
|
coEvery {
|
||||||
|
restorePlugin.getApkInputStream(token, packageName, "_$split1sha256")
|
||||||
|
} returns split1InputStream
|
||||||
|
coEvery {
|
||||||
|
restorePlugin.getApkInputStream(token, packageName, "_$split2sha256")
|
||||||
|
} returns split2InputStream
|
||||||
|
|
||||||
|
coEvery {
|
||||||
|
apkInstaller.install(match { it.size == 3 }, packageName, installerName, any())
|
||||||
|
} returns MutableInstallResult(1).apply {
|
||||||
|
set(
|
||||||
|
packageName, ApkInstallResult(
|
||||||
|
packageName,
|
||||||
|
progress = 1,
|
||||||
|
state = SUCCEEDED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
apkRestore.restore(token, packageMetadataMap).collectIndexed { i, value ->
|
||||||
|
assertQueuedProgressSuccessFinished(i, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun cacheBaseApkAndGetInfo(tmpDir: Path) {
|
private fun cacheBaseApkAndGetInfo(tmpDir: Path) {
|
||||||
every { strictContext.cacheDir } returns File(tmpDir.toString())
|
every { strictContext.cacheDir } returns File(tmpDir.toString())
|
||||||
coEvery { restorePlugin.getApkInputStream(token, packageName, "") } returns apkInputStream
|
coEvery { restorePlugin.getApkInputStream(token, packageName, "") } returns apkInputStream
|
||||||
|
|
Loading…
Add table
Reference in a new issue