Update to latest dav4jvm (uses Java 8 Time API) (bitfireAT/davx5#329)

Fixes WebDAV file timestamps always being null (see bitfireAT/dav4jvm#22)
This commit is contained in:
Ricki Hirner 2023-07-14 22:59:53 +02:00
parent c62874a34b
commit 162c9effe0
9 changed files with 37 additions and 23 deletions

View file

@ -18,12 +18,11 @@ import at.bitfire.dav4jvm.PropStat
import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.Response.HrefRelation
import at.bitfire.dav4jvm.property.GetETag
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.db.Credentials
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.NotificationUtils
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
@ -33,6 +32,7 @@ import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.*
import org.junit.Assert.*
import java.time.Instant
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@ -67,9 +67,6 @@ class SyncManagerTest {
val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
@Inject
lateinit var settingsManager: SettingsManager
@Inject
lateinit var workerFactory: HiltWorkerFactory
@ -92,14 +89,14 @@ class SyncManagerTest {
}
private fun syncManager(collection: LocalTestCollection) =
private fun syncManager(collection: LocalTestCollection, syncResult: SyncResult = SyncResult()) =
TestSyncManager(
context,
account,
arrayOf(),
"TestAuthority",
HttpClient.Builder(InstrumentationRegistry.getInstrumentation().targetContext).build(),
SyncResult(),
syncResult,
collection,
server
)
@ -137,6 +134,23 @@ class SyncManagerTest {
return response
}
@Test
fun testPerformSync_503RetryAfter_DelaySeconds() {
server.enqueue(MockResponse()
.setResponseCode(503)
.setHeader("Retry-After", "60")) // 60 seconds
val result = SyncResult()
val syncManager = syncManager(LocalTestCollection(), result)
syncManager.performSync()
val expected = Instant.now()
.plusSeconds(60)
.toEpochMilli()
// 5 sec tolerance for test
assertTrue(result.delayUntil > (expected - 5000) && result.delayUntil < (expected + 5000))
}
@Test
fun testPerformSync_FirstSync_Empty() {
val collection = LocalTestCollection() /* no last known ctag */

View file

@ -35,6 +35,8 @@ import java.io.ByteArrayOutputStream
import java.io.Reader
import java.io.StringReader
import java.time.Duration
import java.time.Instant
import java.time.ZonedDateTime
import java.util.*
import java.util.logging.Level
@ -102,11 +104,8 @@ class CalendarSyncManager(
override fun listAllRemote(callback: MultiResponseCallback) {
// calculate time range limits
var limitStart: Date? = null
accountSettings.getTimeRangePastDays()?.let { pastDays ->
val calendar = Calendar.getInstance()
calendar.add(Calendar.DAY_OF_MONTH, -pastDays)
limitStart = calendar.time
val limitStart = accountSettings.getTimeRangePastDays()?.let { pastDays ->
ZonedDateTime.now().minusDays(pastDays.toLong()).toInstant()
}
return remoteExceptionContext { remote ->

View file

@ -275,8 +275,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
is ServiceUnavailableException -> {
Logger.log.log(Level.WARNING, "Got 503 Service unavailable, trying again later", e)
e.retryAfter?.let { retryAfter ->
// how many seconds to wait? getTime() returns ms, so divide by 1000
syncResult.delayUntil = (retryAfter.time - Date().time) / 1000
syncResult.delayUntil = retryAfter.toEpochMilli()
}
}

View file

@ -626,7 +626,7 @@ class DavDocumentsProvider: DocumentsProvider() {
if (!getETag.weak)
resource.eTag = resource.eTag
}
resource.lastModified = response[GetLastModified::class.java]?.lastModified
resource.lastModified = response[GetLastModified::class.java]?.lastModified?.toInstant()?.toEpochMilli()
resource.size = response[GetContentLength::class.java]?.contentLength
val privs = response[CurrentUserPrivilegeSet::class.java]

View file

@ -5,11 +5,11 @@
package at.bitfire.davdroid.webdav
import at.bitfire.davdroid.webdav.cache.CacheUtils
import java.util.*
import java.time.Instant
data class DocumentState(
val eTag: String? = null,
val lastModified: Date? = null
val lastModified: Instant? = null
) {
init {

View file

@ -9,6 +9,7 @@ import at.bitfire.dav4jvm.HttpUtils
import at.bitfire.dav4jvm.property.GetETag
import at.bitfire.davdroid.network.HttpClient
import okhttp3.HttpUrl
import java.time.Instant
import java.util.*
import java.util.concurrent.Callable
@ -20,7 +21,7 @@ class HeadInfoDownloader(
override fun call(): HeadResponse {
var size: Long? = null
var eTag: String? = null
var lastModified: Date? = null
var lastModified: Instant? = null
var supportsPartial: Boolean? = null
DavResource(client.okHttpClient, url).head { response ->
@ -30,7 +31,7 @@ class HeadInfoDownloader(
eTag = getETag.eTag
}
response.header("Last-Modified", null)?.let {
lastModified = HttpUtils.parseDate(it)
lastModified = HttpUtils.parseDate(it)?.toInstant()
}
response.headers["Content-Length"]?.let {
size = it.toLong()

View file

@ -4,7 +4,7 @@
package at.bitfire.davdroid.webdav
import java.util.*
import java.time.Instant
/**
* Represents the information that was retrieved via a HEAD request before
@ -13,7 +13,7 @@ import java.util.*
data class HeadResponse(
val size: Long? = null,
val eTag: String? = null,
val lastModified: Date? = null,
val lastModified: Instant? = null,
val supportsPartial: Boolean? = null
) {

View file

@ -8,6 +8,7 @@ import android.util.LruCache
import at.bitfire.davdroid.db.WebDavDocument
import at.bitfire.davdroid.webdav.DocumentState
import at.bitfire.davdroid.webdav.HeadResponse
import java.time.Instant
import java.util.*
class HeadResponseCache {
@ -28,7 +29,7 @@ class HeadResponseCache {
fun get(doc: WebDavDocument, generate: () -> HeadResponse): HeadResponse {
var key: Key? = null
if (doc.eTag != null || doc.lastModified != null) {
key = Key(doc.id, DocumentState(doc.eTag, doc.lastModified?.let { ts -> Date(ts) }))
key = Key(doc.id, DocumentState(doc.eTag, doc.lastModified?.let { ts -> Instant.ofEpochMilli(ts) }))
cache.get(key)?.let { info ->
return info
}

View file

@ -17,7 +17,7 @@ buildscript {
commonsText: '1.3',
// own libraries
cert4android: 'c87a7e9',
dav4jvm: '47dd6a9',
dav4jvm: 'eba95ea',
ical4android: '0b1a068',
vcard4android: 'c2f201a'
]