Improve DocumentsProvider tests against Nextcloud
This commit is contained in:
parent
897fd8473e
commit
740fe53a52
6 changed files with 71 additions and 11 deletions
|
@ -126,7 +126,7 @@ dependencies {
|
|||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-rc03'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
|
||||
lintChecks 'com.github.thirdegg:lint-rules:0.0.4-alpha'
|
||||
lintChecks 'com.github.thirdegg:lint-rules:0.0.5-alpha'
|
||||
|
||||
def junit_version = "5.5.2" // careful, upgrading this can change a Cipher's IV size in tests!?
|
||||
def mockk_version = "1.10.0"
|
||||
|
|
|
@ -141,11 +141,18 @@ class PluginTest : KoinComponent {
|
|||
initStorage(token)
|
||||
|
||||
// write random bytes as APK
|
||||
val apk = getRandomByteArray(1337)
|
||||
backupPlugin.getApkOutputStream(packageInfo).writeAndClose(apk)
|
||||
val apk1 = getRandomByteArray(1337 * 1024)
|
||||
backupPlugin.getApkOutputStream(packageInfo).writeAndClose(apk1)
|
||||
|
||||
// assert that read APK bytes match what was written
|
||||
assertReadEquals(apk, restorePlugin.getApkInputStream(token, packageInfo.packageName))
|
||||
assertReadEquals(apk1, restorePlugin.getApkInputStream(token, packageInfo.packageName))
|
||||
|
||||
// write random bytes as another APK
|
||||
val apk2 = getRandomByteArray(23 * 1024 * 1024)
|
||||
backupPlugin.getApkOutputStream(packageInfo2).writeAndClose(apk2)
|
||||
|
||||
// assert that read APK bytes match what was written
|
||||
assertReadEquals(apk2, restorePlugin.getApkInputStream(token, packageInfo2.packageName))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -226,11 +233,14 @@ class PluginTest : KoinComponent {
|
|||
initStorage(token)
|
||||
|
||||
// FIXME get Nextcloud to have the same limit
|
||||
// Since Nextcloud is using WebDAV and that seems to have undefined lower file name limits
|
||||
// we might have to lower our maximum to accommodate for that.
|
||||
val max = if (isNextcloud()) MAX_KEY_LENGTH_NEXTCLOUD else MAX_KEY_LENGTH
|
||||
val maxOver = if (isNextcloud()) max + 10 else max + 1
|
||||
|
||||
// define record with maximum key length and one above the maximum
|
||||
val recordMax = Pair(getRandomBase64(max), getRandomByteArray(1024))
|
||||
val recordOver = Pair(getRandomBase64(max + 1), getRandomByteArray(1024))
|
||||
val recordOver = Pair(getRandomBase64(maxOver), getRandomByteArray(1024))
|
||||
|
||||
// write max record
|
||||
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
||||
|
@ -306,7 +316,7 @@ class PluginTest : KoinComponent {
|
|||
}
|
||||
|
||||
private fun isNextcloud(): Boolean {
|
||||
return backupPlugin.providerPackageName == "com.nextcloud.client"
|
||||
return backupPlugin.providerPackageName?.startsWith("com.nextcloud") ?: false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -118,6 +118,49 @@ class DocumentsStorageTest : KoinComponent {
|
|||
assertFalse(createdFile.exists())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCreateTwoFiles() = runBlocking {
|
||||
val mimeType = "application/octet-stream"
|
||||
val dir = storage.rootBackupDir!!
|
||||
|
||||
// create test file
|
||||
val name1 = getRandomBase64(Random.nextInt(1, 10))
|
||||
val file1 = requireNotNull(dir.createFile(mimeType, name1))
|
||||
assertTrue(file1.exists())
|
||||
assertEquals(name1, file1.name)
|
||||
assertEquals(0L, file1.length())
|
||||
|
||||
assertReadEquals(getRandomByteArray(0), context.contentResolver.openInputStream(file1.uri))
|
||||
|
||||
// write some data into it
|
||||
val data1 = getRandomByteArray(5 * 1024 * 1024)
|
||||
context.contentResolver.openOutputStream(file1.uri)!!.writeAndClose(data1)
|
||||
assertEquals(data1.size.toLong(), file1.length())
|
||||
|
||||
// data should still be there
|
||||
assertReadEquals(data1, context.contentResolver.openInputStream(file1.uri))
|
||||
|
||||
// create test file
|
||||
val name2 = getRandomBase64(Random.nextInt(1, 10))
|
||||
val file2 = requireNotNull(dir.createFile(mimeType, name2))
|
||||
assertTrue(file2.exists())
|
||||
assertEquals(name2, file2.name)
|
||||
|
||||
// write some data into it
|
||||
val data2 = getRandomByteArray(12 * 1024 * 1024)
|
||||
context.contentResolver.openOutputStream(file2.uri)!!.writeAndClose(data2)
|
||||
assertEquals(data2.size.toLong(), file2.length())
|
||||
|
||||
// data should still be there
|
||||
assertReadEquals(data2, context.contentResolver.openInputStream(file2.uri))
|
||||
|
||||
// delete files again
|
||||
file1.delete()
|
||||
file2.delete()
|
||||
assertFalse(file1.exists())
|
||||
assertFalse(file2.exists())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetLoadedCursor() = runBlocking {
|
||||
// empty cursor extras are like not loading, returns same cursor right away
|
||||
|
|
|
@ -10,7 +10,7 @@ import java.io.IOException
|
|||
import java.io.OutputStream
|
||||
|
||||
const val MAX_KEY_LENGTH = 255
|
||||
const val MAX_KEY_LENGTH_NEXTCLOUD = 228
|
||||
const val MAX_KEY_LENGTH_NEXTCLOUD = 225
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
internal class DocumentsProviderKVBackup(
|
||||
|
@ -59,7 +59,7 @@ internal class DocumentsProviderKVBackup(
|
|||
packageInfo: PackageInfo,
|
||||
key: String
|
||||
): OutputStream {
|
||||
check(key.length < MAX_KEY_LENGTH) {
|
||||
check(key.length <= MAX_KEY_LENGTH) {
|
||||
"Key $key for ${packageInfo.packageName} is too long: ${key.length} chars."
|
||||
}
|
||||
if (key.length > MAX_KEY_LENGTH_NEXTCLOUD) {
|
||||
|
|
|
@ -204,7 +204,9 @@ fun DocumentFile.deleteContents() {
|
|||
}
|
||||
|
||||
fun DocumentFile.assertRightFile(packageInfo: PackageInfo) {
|
||||
if (name != packageInfo.packageName) throw AssertionError()
|
||||
if (name != packageInfo.packageName) {
|
||||
throw AssertionError("Expected ${packageInfo.packageName}, but got $name")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.stevesoltys.seedvault
|
||||
|
||||
import com.stevesoltys.seedvault.plugins.saf.MAX_KEY_LENGTH_NEXTCLOUD
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertEquals
|
||||
|
@ -12,12 +13,14 @@ fun assertContains(stack: String?, needle: String) {
|
|||
if (stack?.contains(needle) != true) throw AssertionError()
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun getRandomByteArray(size: Int = Random.nextInt(1337)) = ByteArray(size).apply {
|
||||
Random.nextBytes(this)
|
||||
}
|
||||
|
||||
private val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9') + '_' + '.'
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun getRandomString(size: Int = Random.nextInt(1, 255)): String {
|
||||
return (1..size)
|
||||
.map { Random.nextInt(0, charPool.size) }
|
||||
|
@ -26,9 +29,10 @@ fun getRandomString(size: Int = Random.nextInt(1, 255)): String {
|
|||
}
|
||||
|
||||
// URL-save version (RFC 4648)
|
||||
private val base64CharPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9') + '+' + '_' + '='
|
||||
private val base64CharPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9') // + '+' + '_' + '='
|
||||
|
||||
fun getRandomBase64(size: Int = Random.nextInt(1, 255)): String {
|
||||
@Suppress("MagicNumber")
|
||||
fun getRandomBase64(size: Int = Random.nextInt(1, MAX_KEY_LENGTH_NEXTCLOUD)): String {
|
||||
return (1..size)
|
||||
.map { Random.nextInt(0, base64CharPool.size) }
|
||||
.map(base64CharPool::get)
|
||||
|
@ -61,6 +65,7 @@ fun assertReadEquals(data: ByteArray, inputStream: InputStream?) = inputStream?.
|
|||
|
||||
fun <T : Throwable> coAssertThrows(clazz: Class<T>, block: suspend () -> Unit) {
|
||||
var thrown = false
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
try {
|
||||
runBlocking {
|
||||
block()
|
||||
|
|
Loading…
Reference in a new issue