Make PluginTest work for Nextcloud as well
Only issue left was a different maximum file name length for Nextcloud
This commit is contained in:
parent
2958c8fac8
commit
30e66f368e
3 changed files with 59 additions and 14 deletions
|
@ -7,6 +7,8 @@ import com.stevesoltys.seedvault.metadata.MetadataManager
|
||||||
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderBackupPlugin
|
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderBackupPlugin
|
||||||
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderRestorePlugin
|
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderRestorePlugin
|
||||||
import com.stevesoltys.seedvault.plugins.saf.DocumentsStorage
|
import com.stevesoltys.seedvault.plugins.saf.DocumentsStorage
|
||||||
|
import com.stevesoltys.seedvault.plugins.saf.MAX_KEY_LENGTH
|
||||||
|
import com.stevesoltys.seedvault.plugins.saf.MAX_KEY_LENGTH_NEXTCLOUD
|
||||||
import com.stevesoltys.seedvault.plugins.saf.deleteContents
|
import com.stevesoltys.seedvault.plugins.saf.deleteContents
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
|
import com.stevesoltys.seedvault.transport.backup.BackupPlugin
|
||||||
|
@ -25,9 +27,9 @@ import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.koin.core.KoinComponent
|
import org.koin.core.KoinComponent
|
||||||
import org.koin.core.inject
|
import org.koin.core.inject
|
||||||
|
import java.io.IOException
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
class PluginTest : KoinComponent {
|
class PluginTest : KoinComponent {
|
||||||
|
@ -48,7 +50,7 @@ class PluginTest : KoinComponent {
|
||||||
fun setup() {
|
fun setup() {
|
||||||
every { mockedSettingsManager.getStorage() } returns settingsManager.getStorage()
|
every { mockedSettingsManager.getStorage() } returns settingsManager.getStorage()
|
||||||
storage.rootBackupDir?.deleteContents()
|
storage.rootBackupDir?.deleteContents()
|
||||||
?: error("Select a storage location in the app first!")
|
?: error("Select a storage location in the app first!")
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -162,7 +164,7 @@ class PluginTest : KoinComponent {
|
||||||
// define key/value pair records
|
// define key/value pair records
|
||||||
val record1 = Pair(getRandomBase64(23), getRandomByteArray(1337))
|
val record1 = Pair(getRandomBase64(23), getRandomByteArray(1337))
|
||||||
val record2 = Pair(getRandomBase64(42), getRandomByteArray(42 * 1024))
|
val record2 = Pair(getRandomBase64(42), getRandomByteArray(42 * 1024))
|
||||||
val record3 = Pair(getRandomBase64(255), getRandomByteArray(5 * 1024 * 1024))
|
val record3 = Pair(getRandomBase64(128), getRandomByteArray(5 * 1024 * 1024))
|
||||||
|
|
||||||
// write first record
|
// write first record
|
||||||
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
||||||
|
@ -177,7 +179,10 @@ class PluginTest : KoinComponent {
|
||||||
var records = kvRestore.listRecords(token, packageInfo)
|
var records = kvRestore.listRecords(token, packageInfo)
|
||||||
assertEquals(1, records.size)
|
assertEquals(1, records.size)
|
||||||
assertEquals(record1.first, records[0])
|
assertEquals(record1.first, records[0])
|
||||||
assertReadEquals(record1.second, kvRestore.getInputStreamForRecord(token, packageInfo, record1.first))
|
assertReadEquals(
|
||||||
|
record1.second,
|
||||||
|
kvRestore.getInputStreamForRecord(token, packageInfo, record1.first)
|
||||||
|
)
|
||||||
|
|
||||||
// write second and third record
|
// write second and third record
|
||||||
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
||||||
|
@ -187,9 +192,18 @@ class PluginTest : KoinComponent {
|
||||||
// all records for package are found and returned properly
|
// all records for package are found and returned properly
|
||||||
records = kvRestore.listRecords(token, packageInfo)
|
records = kvRestore.listRecords(token, packageInfo)
|
||||||
assertEquals(listOf(record1.first, record2.first, record3.first).sorted(), records.sorted())
|
assertEquals(listOf(record1.first, record2.first, record3.first).sorted(), records.sorted())
|
||||||
assertReadEquals(record1.second, kvRestore.getInputStreamForRecord(token, packageInfo, record1.first))
|
assertReadEquals(
|
||||||
assertReadEquals(record2.second, kvRestore.getInputStreamForRecord(token, packageInfo, record2.first))
|
record1.second,
|
||||||
assertReadEquals(record3.second, kvRestore.getInputStreamForRecord(token, packageInfo, record3.first))
|
kvRestore.getInputStreamForRecord(token, packageInfo, record1.first)
|
||||||
|
)
|
||||||
|
assertReadEquals(
|
||||||
|
record2.second,
|
||||||
|
kvRestore.getInputStreamForRecord(token, packageInfo, record2.first)
|
||||||
|
)
|
||||||
|
assertReadEquals(
|
||||||
|
record3.second,
|
||||||
|
kvRestore.getInputStreamForRecord(token, packageInfo, record3.first)
|
||||||
|
)
|
||||||
|
|
||||||
// delete record3 and ensure that the other two are still found
|
// delete record3 and ensure that the other two are still found
|
||||||
kvBackup.deleteRecord(packageInfo, record3.first)
|
kvBackup.deleteRecord(packageInfo, record3.first)
|
||||||
|
@ -211,13 +225,17 @@ class PluginTest : KoinComponent {
|
||||||
// initialize storage with given token
|
// initialize storage with given token
|
||||||
initStorage(token)
|
initStorage(token)
|
||||||
|
|
||||||
|
// FIXME get Nextcloud to have the same limit
|
||||||
|
val max = if (isNextcloud()) MAX_KEY_LENGTH_NEXTCLOUD else MAX_KEY_LENGTH
|
||||||
|
|
||||||
// define record with maximum key length and one above the maximum
|
// define record with maximum key length and one above the maximum
|
||||||
val recordMax = Pair(getRandomBase64(255), getRandomByteArray(1024))
|
val recordMax = Pair(getRandomBase64(max), getRandomByteArray(1024))
|
||||||
val recordOver = Pair(getRandomBase64(256), getRandomByteArray(1024))
|
val recordOver = Pair(getRandomBase64(max + 1), getRandomByteArray(1024))
|
||||||
|
|
||||||
// write max record
|
// write max record
|
||||||
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
||||||
kvBackup.getOutputStreamForRecord(packageInfo, recordMax.first).writeAndClose(recordMax.second)
|
kvBackup.getOutputStreamForRecord(packageInfo, recordMax.first)
|
||||||
|
.writeAndClose(recordMax.second)
|
||||||
|
|
||||||
// max record is found correctly
|
// max record is found correctly
|
||||||
assertTrue(kvRestore.hasDataForPackage(token, packageInfo))
|
assertTrue(kvRestore.hasDataForPackage(token, packageInfo))
|
||||||
|
@ -226,8 +244,17 @@ class PluginTest : KoinComponent {
|
||||||
|
|
||||||
// write exceeding key length record
|
// write exceeding key length record
|
||||||
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
kvBackup.ensureRecordStorageForPackage(packageInfo)
|
||||||
coAssertThrows(IllegalStateException::class.java) {
|
if (isNextcloud()) {
|
||||||
kvBackup.getOutputStreamForRecord(packageInfo, recordOver.first).writeAndClose(recordOver.second)
|
// Nextcloud simply refuses to write long filenames
|
||||||
|
coAssertThrows(IOException::class.java) {
|
||||||
|
kvBackup.getOutputStreamForRecord(packageInfo, recordOver.first)
|
||||||
|
.writeAndClose(recordOver.second)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
coAssertThrows(IllegalStateException::class.java) {
|
||||||
|
kvBackup.getOutputStreamForRecord(packageInfo, recordOver.first)
|
||||||
|
.writeAndClose(recordOver.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,4 +305,8 @@ class PluginTest : KoinComponent {
|
||||||
assertTrue(backupPlugin.initializeDevice(newToken = token))
|
assertTrue(backupPlugin.initializeDevice(newToken = token))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isNextcloud(): Boolean {
|
||||||
|
return backupPlugin.providerPackageName == "com.nextcloud.client"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ class DocumentsStorageTest : KoinComponent {
|
||||||
fun setup() = runBlocking {
|
fun setup() = runBlocking {
|
||||||
assertNotNull("Select a storage location in the app first!", storage.rootBackupDir)
|
assertNotNull("Select a storage location in the app first!", storage.rootBackupDir)
|
||||||
file = storage.rootBackupDir?.createOrGetFile(context, filename)
|
file = storage.rootBackupDir?.createOrGetFile(context, filename)
|
||||||
?: throw RuntimeException("Could not create test file")
|
?: error("Could not create test file")
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -2,12 +2,16 @@ package com.stevesoltys.seedvault.plugins.saf
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
|
import android.util.Log
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import com.stevesoltys.seedvault.transport.backup.DEFAULT_QUOTA_KEY_VALUE_BACKUP
|
import com.stevesoltys.seedvault.transport.backup.DEFAULT_QUOTA_KEY_VALUE_BACKUP
|
||||||
import com.stevesoltys.seedvault.transport.backup.KVBackupPlugin
|
import com.stevesoltys.seedvault.transport.backup.KVBackupPlugin
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
const val MAX_KEY_LENGTH = 255
|
||||||
|
const val MAX_KEY_LENGTH_NEXTCLOUD = 228
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
internal class DocumentsProviderKVBackup(
|
internal class DocumentsProviderKVBackup(
|
||||||
private val storage: DocumentsStorage,
|
private val storage: DocumentsStorage,
|
||||||
|
@ -37,7 +41,8 @@ internal class DocumentsProviderKVBackup(
|
||||||
override suspend fun removeDataOfPackage(packageInfo: PackageInfo) {
|
override suspend fun removeDataOfPackage(packageInfo: PackageInfo) {
|
||||||
// we cannot use the cached this.packageFile here,
|
// we cannot use the cached this.packageFile here,
|
||||||
// because this can be called before [ensureRecordStorageForPackage]
|
// because this can be called before [ensureRecordStorageForPackage]
|
||||||
val packageFile = storage.currentKvBackupDir?.findFileBlocking(context, packageInfo.packageName) ?: return
|
val packageFile =
|
||||||
|
storage.currentKvBackupDir?.findFileBlocking(context, packageInfo.packageName) ?: return
|
||||||
packageFile.delete()
|
packageFile.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +59,15 @@ internal class DocumentsProviderKVBackup(
|
||||||
packageInfo: PackageInfo,
|
packageInfo: PackageInfo,
|
||||||
key: String
|
key: String
|
||||||
): OutputStream {
|
): OutputStream {
|
||||||
|
check(key.length < MAX_KEY_LENGTH) {
|
||||||
|
"Key $key for ${packageInfo.packageName} is too long: ${key.length} chars."
|
||||||
|
}
|
||||||
|
if (key.length > MAX_KEY_LENGTH_NEXTCLOUD) {
|
||||||
|
Log.e(
|
||||||
|
DocumentsProviderKVBackup::class.simpleName,
|
||||||
|
"Key $key for ${packageInfo.packageName} is too long: ${key.length} chars."
|
||||||
|
)
|
||||||
|
}
|
||||||
val packageFile = this.packageFile ?: throw AssertionError()
|
val packageFile = this.packageFile ?: throw AssertionError()
|
||||||
packageFile.assertRightFile(packageInfo)
|
packageFile.assertRightFile(packageInfo)
|
||||||
val keyFile = packageFile.createOrGetFile(context, key)
|
val keyFile = packageFile.createOrGetFile(context, key)
|
||||||
|
|
Loading…
Reference in a new issue