v1.0.65: chunked upload for large files (>100MB) on Nextcloud
Build & Release APK / build (push) Successful in 12m58s
Build & Release APK / build (push) Successful in 12m58s
Big-file testing found single-PUT uploads 413 above the server's per-request cap (Apache LimitRequestBody / PHP post_max_size / proxy limits). NextcloudProvider now uploads files >chunkSize (100MB) via the dav/uploads chunked API: MKCOL a session, PUT N chunks, then MOVE .file onto the destination (atomic assemble). Bypasses any per-request cap so multi-GB files back up. Verified byte-exact (multi-chunk) against live Nextcloud. SFTP already streams; single-PUT path unchanged for <=100MB.
This commit is contained in:
@@ -13,6 +13,7 @@ import com.syncflow.domain.sync.LocalFileInfo
|
||||
import com.syncflow.domain.sync.SyncDecision
|
||||
import com.syncflow.domain.sync.syncDecide
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
@@ -114,4 +115,27 @@ class NextcloudIntegrationTest {
|
||||
runCatching { p.deleteFile(dir) } // best-effort cleanup of the test folder
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun chunkedUpload_assemblesLargeFileByteExact() = runBlocking {
|
||||
assumeTrue("ncUrl/ncUser/ncPass required", url != null && user != null && pass != null)
|
||||
// Tiny chunk size exercises multi-chunk assembly without needing a multi-GB file.
|
||||
val account = CloudAccount(
|
||||
id = 1, displayName = "IT", email = user, providerType = ProviderType.NEXTCLOUD,
|
||||
credentialJson = """{"username":"$user","password":"$pass"}""", serverUrl = url, port = null,
|
||||
)
|
||||
val p = NextcloudProvider(account, chunkSize = 1L * 1024 * 1024) // 1 MB chunks
|
||||
val dir = "SyncFlowChunk_${System.currentTimeMillis()}"
|
||||
try {
|
||||
p.createDirectory(dir).getOrThrow()
|
||||
val payload = ByteArray(5 * 1024 * 1024 + 7).also { java.util.Random(7).nextBytes(it) } // ~5 MB -> 6 chunks
|
||||
val up = p.uploadFile(ByteArrayInputStream(payload), "$dir/big.bin", payload.size.toLong())
|
||||
assertTrue("chunked upload failed: ${up.exceptionOrNull()}", up.isSuccess)
|
||||
assertEquals(payload.size.toLong(), p.listFiles(dir).getOrThrow().first { it.name == "big.bin" }.sizeBytes)
|
||||
val out = ByteArrayOutputStream(); p.downloadFile("$dir/big.bin", out).getOrThrow()
|
||||
assertArrayEquals("chunk-assembled content must equal the original bytes", payload, out.toByteArray())
|
||||
} finally {
|
||||
runCatching { p.deleteFile(dir) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user