fix: SAF delete crash, getFileMetadata drop-first, MKCOL before upload
- LocalAccessor.Saf.delete() now uses docIdCache (same as openInputStream) and catches IllegalStateException from DocumentsContract.deleteDocument instead of propagating it through awaitAll() and crashing the whole sync - WebDavProvider.getFileMetadata() passes dropFirst=false to parsePropfind since Depth:0 returns exactly 1 result (the file); drop(1) was discarding it - SyncEngine.performSync() calls ensureRemoteDirs() before each upload so MKCOL is issued for any missing parent directories (405=exists is success) - Bump version to 1.0.11 (code 12) Verified against live Nextcloud: baseline ↑0 ↓0 ✗0, upload detection ↑1 ↓0 ✗0, download detection ↑0 ↓1 ✗0. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -116,6 +116,29 @@ class SyncDecideTest {
|
||||
assertEquals(SyncDecision.SKIP,
|
||||
decide(local(), null, state(), dir = SyncDirection.UPLOAD_ONLY))
|
||||
|
||||
@Test fun `local deleted TWO_WAY MIRROR deletes remote`() =
|
||||
assertEquals(SyncDecision.DELETE_REMOTE, decide(null, remote(), state(), delete = DeleteBehavior.MIRROR))
|
||||
|
||||
@Test fun `local deleted TWO_WAY KEEP skips`() =
|
||||
assertEquals(SyncDecision.SKIP, decide(null, remote(), state(), delete = DeleteBehavior.KEEP))
|
||||
|
||||
@Test fun `local deleted DOWNLOAD_ONLY skips remote deletion`() =
|
||||
assertEquals(SyncDecision.SKIP,
|
||||
decide(null, remote(), state(), dir = SyncDirection.DOWNLOAD_ONLY))
|
||||
|
||||
// ── first-seen SKIP saves baseline so later deletions are detected ────────
|
||||
|
||||
@Test fun `first sync both exist same mtime uploads local wins tie`() =
|
||||
assertEquals(SyncDecision.UPLOAD, decide(local(MS), remote(MS, etag = "abc")))
|
||||
|
||||
@Test fun `after first-seen skip local deleted deletes remote`() {
|
||||
// Simulate: first sync saw both sides identical → SKIP (state saved by engine).
|
||||
// Then local file deleted → known is now present → DELETE_REMOTE.
|
||||
val known = state(localMs = MS, remoteMs = MS, etag = "abc")
|
||||
assertEquals(SyncDecision.DELETE_REMOTE,
|
||||
decide(null, remote(MS, etag = "abc"), known, delete = DeleteBehavior.MIRROR))
|
||||
}
|
||||
|
||||
// ── directions ────────────────────────────────────────────────────────────
|
||||
|
||||
@Test fun `UPLOAD_ONLY ignores remote changes`() =
|
||||
|
||||
Reference in New Issue
Block a user