Add CaldavSynchronizer tests

pull/1381/head
Alex Baker 3 years ago
parent 6619a8f3fa
commit e9dafefbb0

@ -228,6 +228,7 @@ dependencies {
androidTestImplementation("androidx.test:rules:${Versions.androidx_test}")
androidTestImplementation("androidx.test.ext:junit:1.1.2")
androidTestImplementation("androidx.annotation:annotation:1.1.0")
androidTestImplementation("com.squareup.okhttp3:mockwebserver:${Versions.okhttp}")
testImplementation("junit:junit:4.13.1")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2")

@ -0,0 +1,219 @@
package org.tasks.caldav
import com.natpryce.makeiteasy.MakeItEasy.with
import com.todoroo.astrid.helper.UUIDHelper
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import org.tasks.R
import org.tasks.data.CaldavAccount
import org.tasks.data.CaldavCalendar
import org.tasks.data.CaldavDao
import org.tasks.data.TaskDao
import org.tasks.injection.InjectingTestCase
import org.tasks.injection.ProductionModule
import org.tasks.makers.CaldavTaskMaker.CALENDAR
import org.tasks.makers.CaldavTaskMaker.ETAG
import org.tasks.makers.CaldavTaskMaker.OBJECT
import org.tasks.makers.CaldavTaskMaker.newCaldavTask
import org.tasks.preferences.Preferences
import org.tasks.security.KeyStoreEncryption
import javax.inject.Inject
@UninstallModules(ProductionModule::class)
@HiltAndroidTest
class CaldavSynchronizerTest : InjectingTestCase() {
@Inject lateinit var synchronizer: CaldavSynchronizer
@Inject lateinit var encryption: KeyStoreEncryption
@Inject lateinit var preferences: Preferences
@Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var taskDao: TaskDao
private val server = MockWebServer()
lateinit var account: CaldavAccount
@Before
override fun setUp() = runBlocking {
super.setUp()
preferences.setBoolean(R.string.p_debug_pro, true)
server.start()
account = CaldavAccount().apply {
uuid = UUIDHelper.newUUID()
username = "username"
password = encryption.encrypt("password")
url = server.url("/remote.php/dav/calendars/user1/").toString()
id = caldavDao.insert(this)
}
}
@After
fun after() = server.shutdown()
@Test
fun setMessageOnError() = runBlocking {
enqueueFailure(500)
synchronizer.sync(account)
assertEquals("HTTP 500 Server Error", caldavDao.getAccounts().first().error)
}
@Test
fun dontFetchCalendarIfCtagMatches() = runBlocking {
caldavDao.insert(CaldavCalendar().apply {
account = this@CaldavSynchronizerTest.account.uuid
ctag = "http://sabre.io/ns/sync/1"
url = "${this@CaldavSynchronizerTest.account.url}test-shared/"
})
enqueue(OC_SHARE_PROPFIND)
enqueueFailure()
synchronizer.sync(account)
assertFalse(caldavDao.getAccountByUuid(account.uuid!!)!!.hasError)
}
@Test
fun dontFetchTaskIfEtagMatches() = runBlocking {
val calendar = CaldavCalendar().apply {
account = this@CaldavSynchronizerTest.account.uuid
uuid = UUIDHelper.newUUID()
url = "${this@CaldavSynchronizerTest.account.url}test-shared/"
caldavDao.insert(this)
}
caldavDao.insert(newCaldavTask(
with(OBJECT, "3164728546640386952.ics"),
with(ETAG, "43b3ffaac5131880e4dd07a79adba82a"),
with(CALENDAR, calendar.uuid)
))
enqueue(OC_SHARE_PROPFIND, OC_SHARE_REPORT)
enqueueFailure()
synchronizer.sync(account)
assertFalse(caldavDao.getAccountByUuid(account.uuid!!)!!.hasError)
}
@Test
fun syncNewTask() = runBlocking {
enqueue(OC_SHARE_PROPFIND, OC_SHARE_REPORT, OC_SHARE_TASK)
synchronizer.sync(account)
val calendar = caldavDao.getCalendars().takeIf { it.size == 1 }!!.first()
val caldavTask = caldavDao.getTaskByRemoteId(calendar.uuid!!, "3164728546640386952")!!
assertEquals("Test task", taskDao.fetch(caldavTask.task)!!.title)
}
private fun enqueue(vararg responses: String) = responses.forEach {
server.enqueue(
MockResponse()
.setResponseCode(207)
.setHeader("Content-Type", "text/xml; charset=\"utf-8\"")
.setBody(it)
)
}
private fun enqueueFailure(code: Int = 500) =
server.enqueue(MockResponse().setResponseCode(code))
companion object {
private val OC_SHARE_PROPFIND = """
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:cal="urn:ietf:params:xml:ns:caldav"
xmlns:cs="http://calendarserver.org/ns/" xmlns:oc="http://owncloud.org/ns">
<d:response>
<d:href>/remote.php/dav/calendars/user1/test-shared/</d:href>
<d:propstat>
<d:prop>
<d:resourcetype>
<d:collection />
<cal:calendar />
</d:resourcetype>
<d:displayname>Test shared</d:displayname>
<cal:supported-calendar-component-set>
<cal:comp name="VTODO" />
</cal:supported-calendar-component-set>
<cs:getctag>http://sabre.io/ns/sync/1</cs:getctag>
<x1:calendar-color xmlns:x1="http://apple.com/ns/ical/">#0082c9</x1:calendar-color>
<d:sync-token>http://sabre.io/ns/sync/1</d:sync-token>
<oc:owner-principal>principals/users/user1</oc:owner-principal>
<oc:invite>
<oc:user>
<d:href>principal:principals/users/user2</d:href>
<oc:common-name>user2</oc:common-name>
<oc:invite-accepted />
<oc:access>
<oc:read />
</oc:access>
</oc:user>
</oc:invite>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
<d:propstat>
<d:prop>
<d:share-access />
<d:invite />
</d:prop>
<d:status>HTTP/1.1 404 Not Found</d:status>
</d:propstat>
</d:response>
</d:multistatus>
""".trimIndent()
private val OC_SHARE_REPORT = """
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:">
<d:response>
<d:href>/remote.php/dav/calendars/user1/test-shared/3164728546640386952.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>&quot;43b3ffaac5131880e4dd07a79adba82a&quot;</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
""".trimIndent()
private val OC_SHARE_TASK = """
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:cal="urn:ietf:params:xml:ns:caldav">
<d:response>
<d:href>/remote.php/dav/calendars/user1/test-shared/3164728546640386952.ics</d:href>
<d:propstat>
<d:prop>
<d:getcontenttype>text/calendar; charset=utf-8; component=vtodo</d:getcontenttype>
<d:getetag>&quot;43b3ffaac5131880e4dd07a79adba82a&quot;</d:getetag>
<cal:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:+//IDN tasks.org//android-110500//EN
BEGIN:VTODO
DTSTAMP:20210223T154147Z
UID:3164728546640386952
CREATED:20210223T154134Z
LAST-MODIFIED:20210223T154140Z
SUMMARY:Test task
PRIORITY:9
END:VTODO
END:VCALENDAR</cal:calendar-data>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
<d:propstat>
<d:prop>
<cal:schedule-tag />
</d:prop>
<d:status>HTTP/1.1 404 Not Found</d:status>
</d:propstat>
</d:response>
</d:multistatus>
""".trimIndent()
}
}

@ -14,6 +14,8 @@ object CaldavTaskMaker {
val REMOTE_PARENT: Property<CaldavTask, String?> = newProperty()
val REMOTE_ORDER: Property<CaldavTask, Long?> = newProperty()
val VTODO: Property<CaldavTask, String?> = newProperty()
val ETAG: Property<CaldavTask, String?> = newProperty()
val OBJECT: Property<CaldavTask, String?> = newProperty()
private val instantiator = Instantiator<CaldavTask> {
val task = CaldavTask(it.valueOf(TASK, 1L), it.valueOf(CALENDAR, "calendar"))
@ -21,6 +23,8 @@ object CaldavTaskMaker {
task.remoteParent = it.valueOf(REMOTE_PARENT, null as String?)
task.vtodo = it.valueOf(VTODO, null as String?)
task.order = it.valueOf(REMOTE_ORDER, null as Long?)
task.etag = it.valueOf(ETAG, null as String?)
task.`object` = it.valueOf(OBJECT, task.remoteId?.let { id -> "$id.ics" })
task
}

@ -105,7 +105,7 @@ class CaldavSynchronizer @Inject constructor(
}
}
setError(account, message)
} catch (e: DavException) {
} catch (e: Exception) {
setError(account, e.message)
firebase.reportException(e)
}

Loading…
Cancel
Save