Loading build.gradle +3 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,8 @@ android { buildToolsVersion '27.0.3' defaultConfig { minSdkVersion 14 //noinspection MinSdkTooLow minSdkVersion 9 // Android 2.3 targetSdkVersion 27 buildConfigField "String", "version_okhttp", "\"$okhttp_version\"" Loading @@ -58,6 +59,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "com.squareup.okhttp3:okhttp:$okhttp_version" implementation "commons-io:commons-io:2.6" androidTestImplementation "com.squareup.okhttp3:mockwebserver:$okhttp_version" androidTestImplementation 'com.android.support.test:runner:1.0.2' Loading src/androidTest/java/at/bitfire/dav4android/DavCollectionTest.kt +39 −41 Original line number Diff line number Diff line Loading @@ -94,8 +94,7 @@ class DavCollectionTest { " <D:sync-token>http://example.com/ns/sync/1234</D:sync-token>\n" + " </D:multistatus>") ) val changes = collection.reportChanges(null, false, null, GetETag.NAME) collection.reportChanges(null, false, null, GetETag.NAME).use { changes -> assertEquals(3, changes.members.size) val members = changes.members.iterator() val member1 = members.next() Loading @@ -114,6 +113,7 @@ class DavCollectionTest { assertFalse(changes.furtherResults) assertEquals("http://example.com/ns/sync/1234", changes.syncToken!!.token) } } /** * Test sample response for an initial sync-collection report with truncation from RFC 6578 3.10. Loading Loading @@ -158,8 +158,7 @@ class DavCollectionTest { " <D:sync-token>http://example.com/ns/sync/1233</D:sync-token>\n" + " </D:multistatus>") ) val changes = collection.reportChanges(null, false, null, GetETag.NAME) collection.reportChanges(null, false, null, GetETag.NAME).use { changes -> assertEquals(2, changes.members.size) val members = changes.members.iterator() val member1 = members.next() Loading @@ -177,6 +176,7 @@ class DavCollectionTest { assertTrue(changes.furtherResults) assertEquals("http://example.com/ns/sync/1233", changes.syncToken!!.token) } } /** * Test sample response for a sync-collection report with unsupported limit from RFC 6578 3.12. Loading @@ -196,13 +196,11 @@ class DavCollectionTest { ) try { collection.reportChanges("http://example.com/ns/sync/1232", false, 100, GetETag.NAME) collection.reportChanges("http://example.com/ns/sync/1232", false, 100, GetETag.NAME).close() fail("Expected HttpException") } catch (e: HttpException) { assertEquals(507, e.status) return } fail() } } No newline at end of file src/androidTest/java/at/bitfire/dav4android/DavResourceTest.kt +103 −96 Original line number Diff line number Diff line Loading @@ -8,8 +8,8 @@ package at.bitfire.dav4android import at.bitfire.dav4android.exception.DavException import at.bitfire.dav4android.exception.HttpException import at.bitfire.dav4android.exception.InvalidDavResponseException import at.bitfire.dav4android.exception.PreconditionFailedException import at.bitfire.dav4android.property.DisplayName import at.bitfire.dav4android.property.GetContentType Loading Loading @@ -49,6 +49,15 @@ class DavResourceTest { private fun sampleUrl() = mockServer.url("/dav/") @Test fun testFilename() { assertEquals("", DavResource(httpClient, sampleUrl().resolve("/")!!).fileName()) assertEquals("hier1", DavResource(httpClient, sampleUrl().resolve("/hier1")!!).fileName()) assertEquals("", DavResource(httpClient, sampleUrl().resolve("/hier1/")!!).fileName()) assertEquals("hier2", DavResource(httpClient, sampleUrl().resolve("/hier1/hier2")!!).fileName()) assertEquals("", DavResource(httpClient, sampleUrl().resolve("/hier1/hier2/")!!).fileName()) } @Test fun testOptions() { val url = sampleUrl() Loading Loading @@ -81,10 +90,11 @@ class DavResourceTest { .setHeader("ETag", "W/\"My Weak ETag\"") .setHeader("Content-Type", "application/x-test-result") .setBody(sampleText)) val (responseOK, bodyOK) = dav.get("*/*") assertEquals(sampleText, bodyOK.string()) dav.get("*/*").use { responseOK -> assertEquals(sampleText, responseOK.body!!.string()) assertEquals("My Weak ETag", responseOK[GetETag::class.java]?.eTag) assertEquals("application/x-test-result", responseOK[GetContentType::class.java]?.type) } var rq = mockServer.takeRequest() assertEquals("GET", rq.method) Loading @@ -100,9 +110,10 @@ class DavResourceTest { .setResponseCode(HttpURLConnection.HTTP_OK) .setHeader("ETag", "\"StrongETag\"") .setBody(sampleText)) val (response302, body302) = dav.get("*/*") assertEquals(sampleText, body302.string()) dav.get("*/*").use { response302 -> assertEquals(sampleText, response302.body!!.string()) assertEquals("StrongETag", response302[GetETag::class.java]?.eTag) } mockServer.takeRequest() rq = mockServer.takeRequest() Loading @@ -113,8 +124,9 @@ class DavResourceTest { mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_OK) .setBody(sampleText)) val (responseWithoutETag, _) = dav.get("*/*") assertNull(responseWithoutETag[GetETag::class.java]) dav.get("*/*").use { assertNull(it[GetETag::class.java]) } } @Test Loading @@ -128,9 +140,10 @@ class DavResourceTest { mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_CREATED) .setHeader("ETag", "W/\"Weak PUT ETag\"")) val (response201, redirect201) = dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), null, false) assertFalse(redirect201) assertEquals("Weak PUT ETag", response201[GetETag::class.java]?.eTag) dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), null, false).use { assertEquals("Weak PUT ETag", it[GetETag::class.java]?.eTag) assertEquals(it.url, dav.location) } var rq = mockServer.takeRequest() assertEquals("PUT", rq.method) Loading @@ -144,10 +157,10 @@ class DavResourceTest { .setHeader("Location", "/target")) mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)) val (response301_204, redirect301_204) = dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), null, true) assertTrue(redirect301_204) assertEquals(url.resolve("/target"), dav.location) assertNull(response301_204[GetETag::class.java]) dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), null, true).use { assertEquals(url.resolve("/target"), it.url) assertNull("Weak PUT ETag", it[GetETag::class.java]?.eTag) } mockServer.takeRequest() rq = mockServer.takeRequest() Loading @@ -157,13 +170,10 @@ class DavResourceTest { // precondition: If-Match, 412 Precondition Failed mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_PRECON_FAILED)) val (_, _) = try { val pair = dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), "ExistingETag", false) fail() pair } catch(e: PreconditionFailedException) { Pair(null, null) } try { dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), "ExistingETag", false).close() fail("Expected PreconditionFailedException") } catch(e: PreconditionFailedException) {} rq = mockServer.takeRequest() assertEquals("\"ExistingETag\"", rq.getHeader("If-Match")) assertNull(rq.getHeader("If-None-Match")) Loading @@ -179,7 +189,7 @@ class DavResourceTest { // no preconditions, 204 No Content mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)) dav.delete(null) dav.delete(null).close() var rq = mockServer.takeRequest() assertEquals("DELETE", rq.method) Loading @@ -190,7 +200,7 @@ class DavResourceTest { mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_OK) .setBody("Resource has been deleted.")) dav.delete("DeleteOnlyThisETag") dav.delete("DeleteOnlyThisETag").close() rq = mockServer.takeRequest() assertEquals("\"DeleteOnlyThisETag\"", rq.getHeader("If-Match")) Loading @@ -202,7 +212,7 @@ class DavResourceTest { ) mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_OK)) dav.delete(null) dav.delete(null).close() /* NEGATIVE TEST CASES */ Loading @@ -210,11 +220,9 @@ class DavResourceTest { mockServer.enqueue(MockResponse() .setResponseCode(207)) try { dav.delete(null) fail() } catch(e: HttpException) { // treat 207 as an error } dav.delete(null).close() fail("Expected HttpException") } catch(e: HttpException) {} } @Test Loading @@ -228,17 +236,15 @@ class DavResourceTest { // * 500 Internal Server Error mockServer.enqueue(MockResponse().setResponseCode(HttpURLConnection.HTTP_INTERNAL_ERROR)) try { dav.propfind(0, ResourceType.NAME) dav.propfind(0, ResourceType.NAME).close() fail("Expected HttpException") } catch(e: HttpException) { } } catch(e: HttpException) {} // * 200 OK (instead of 207 Multi-Status) mockServer.enqueue(MockResponse().setResponseCode(HttpURLConnection.HTTP_OK)) try { dav.propfind(0, ResourceType.NAME) fail("Expected InvalidDavResponseException") } catch(e: InvalidDavResponseException) { } dav.propfind(0, ResourceType.NAME).close() fail("Expected DavException") } catch(e: DavException) {} // test for invalid multi-status responses: // * non-XML response Loading @@ -247,10 +253,9 @@ class DavResourceTest { .setHeader("Content-Type", "text/html") .setBody("<html></html>")) try { dav.propfind(0, ResourceType.NAME) fail("Expected InvalidDavResponseException") } catch(e: InvalidDavResponseException) { } dav.propfind(0, ResourceType.NAME).close() fail("Expected DavException") } catch(e: DavException) {} // * malformed XML response mockServer.enqueue(MockResponse() Loading @@ -258,10 +263,9 @@ class DavResourceTest { .setHeader("Content-Type", "application/xml; charset=utf-8") .setBody("<malformed-xml>")) try { dav.propfind(0, ResourceType.NAME) fail("Expected InvalidDavResponseException") } catch(e: InvalidDavResponseException) { } dav.propfind(0, ResourceType.NAME).close() fail("Expected DavException") } catch(e: DavException) {} // * response without <multistatus> root element mockServer.enqueue(MockResponse() Loading @@ -269,10 +273,9 @@ class DavResourceTest { .setHeader("Content-Type", "application/xml; charset=utf-8") .setBody("<test></test>")) try { dav.propfind(0, ResourceType.NAME) fail("Expected InvalidDavResponseException") } catch(e: InvalidDavResponseException) { } dav.propfind(0, ResourceType.NAME).close() fail("Expected DavException") } catch(e: DavException) {} // * multi-status response with invalid <status> in <response> mockServer.enqueue(MockResponse() Loading @@ -285,10 +288,9 @@ class DavResourceTest { " </response>" + "</multistatus>")) try { dav.propfind(0, ResourceType.NAME) dav.propfind(0, ResourceType.NAME).close() fail("Expected HttpException") } catch(e: HttpException) { } } catch(e: HttpException) {} // * multi-status response with <response>/<status> element indicating failure mockServer.enqueue(MockResponse() Loading @@ -303,8 +305,7 @@ class DavResourceTest { try { dav.propfind(0, ResourceType.NAME) fail("Expected HttpException") } catch(e: HttpException) { } } catch(e: HttpException) {} // * multi-status response with invalid <status> in <propstat> mockServer.enqueue(MockResponse() Loading @@ -321,8 +322,9 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val invalidStatus = dav.propfind(0, ResourceType.NAME) assertNull(invalidStatus[ResourceType::class.java]) dav.propfind(0, ResourceType.NAME).use { assertNull(it[ResourceType::class.java]) } /*** POSITIVE TESTS ***/ Loading @@ -332,9 +334,10 @@ class DavResourceTest { .setResponseCode(207) .setHeader("Content-Type", "application/xml; charset=utf-8") .setBody("<multistatus xmlns='DAV:'></multistatus>")) val emptyResponse = dav.propfind(0, ResourceType.NAME) assertEquals(0, emptyResponse.properties.size) assertEquals(0, emptyResponse.members.size) dav.propfind(0, ResourceType.NAME).use { assertEquals(0, it.properties.size) assertEquals(0, it.members.size) } // multi-status response with <response>/<status> element indicating success mockServer.enqueue(MockResponse() Loading @@ -346,9 +349,10 @@ class DavResourceTest { " <status>HTTP/1.1 200 OK</status>" + " </response>" + "</multistatus>")) val responseStatus = dav.propfind(0, ResourceType.NAME) assertEquals(0, responseStatus.properties.size) assertEquals(0, responseStatus.members.size) dav.propfind(0, ResourceType.NAME).use { assertEquals(0, it.properties.size) assertEquals(0, it.members.size) } // multi-status response with <response>/<propstat> element mockServer.enqueue(MockResponse() Loading @@ -367,9 +371,10 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val responsePropstat = dav.propfind(0, ResourceType.NAME, DisplayName.NAME) assertEquals("My DAV Collection", responsePropstat[DisplayName::class.java]?.displayName) assertEquals(0, responsePropstat.members.size) dav.propfind(0, ResourceType.NAME, DisplayName.NAME).use { assertEquals("My DAV Collection", it[DisplayName::class.java]?.displayName) assertEquals(0, it.members.size) } // multi-status response for collection with several members; incomplete (not all <resourcetype>s listed) mockServer.enqueue(MockResponse() Loading Loading @@ -433,10 +438,10 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val responseMembers = dav.propfind(1, ResourceType.NAME, DisplayName.NAME) assertEquals(4, responseMembers.members.size) dav.propfind(1, ResourceType.NAME, DisplayName.NAME).use { response -> assertEquals(4, response.members.size) val ok = BooleanArray(4) for (member in responseMembers.members) for (member in response.members) when (member.url) { url.resolve("/dav/subcollection/") -> { assertTrue(member[ResourceType::class.java]!!.types.contains(ResourceType.COLLECTION)) Loading @@ -457,7 +462,7 @@ class DavResourceTest { } } assertTrue(ok.all { it }) } /*** SPECIAL CASES ***/ Loading @@ -483,9 +488,10 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val some404Prop = dav.propfind(0, ResourceType.NAME, DisplayName.NAME) assertTrue(some404Prop[ResourceType::class.java]!!.types.contains(ResourceType.COLLECTION)) assertEquals("My DAV Collection", some404Prop[DisplayName::class.java]?.displayName) dav.propfind(0, ResourceType.NAME, DisplayName.NAME).use { assertTrue(it[ResourceType::class.java]!!.types.contains(ResourceType.COLLECTION)) assertEquals("My DAV Collection", it[DisplayName::class.java]?.displayName) } // multi-status response with <propstat> that doesn't contain <status> (=> assume 200 OK) mockServer.enqueue(MockResponse() Loading @@ -501,8 +507,9 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val propstatWithoutStatus = dav.propfind(0, DisplayName.NAME) assertEquals("Without Status", propstatWithoutStatus[DisplayName::class.java]?.displayName) dav.propfind(0, DisplayName.NAME).use { assertEquals("Without Status", it[DisplayName::class.java]?.displayName) } } } src/main/java/at/bitfire/dav4android/DavAddressBook.kt +4 −13 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ package at.bitfire.dav4android import at.bitfire.dav4android.exception.DavException import at.bitfire.dav4android.exception.HttpException import at.bitfire.dav4android.exception.InvalidDavResponseException import okhttp3.* import java.io.IOException import java.io.StringWriter Loading Loading @@ -62,14 +61,10 @@ class DavAddressBook @JvmOverloads constructor( .header("Depth", "1") .build()).execute() checkStatus(response, false) checkStatus(response) assertMultiStatus(response) response.body()?.charStream()?.use { return processMultiStatus(it) } throw InvalidDavResponseException("Didn't receive 207 Multi-status response on REPORT addressbook-queryys") return processMultiStatus(response.body()?.charStream()!!) } /** Loading Loading @@ -117,14 +112,10 @@ class DavAddressBook @JvmOverloads constructor( .header("Depth", "0") // "The request MUST include a Depth: 0 header [...]" .build()).execute() checkStatus(response, false) checkStatus(response) assertMultiStatus(response) response.body()?.charStream()?.use { return processMultiStatus(it) } throw InvalidDavResponseException("Didn't receive 207 Multi-status response on REPORT addressbook-multiget") return processMultiStatus(response.body()?.charStream()!!) } } src/main/java/at/bitfire/dav4android/DavCalendar.kt +4 −13 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ package at.bitfire.dav4android import at.bitfire.dav4android.exception.DavException import at.bitfire.dav4android.exception.HttpException import at.bitfire.dav4android.exception.InvalidDavResponseException import okhttp3.* import java.io.IOException import java.io.StringWriter Loading Loading @@ -89,14 +88,10 @@ class DavCalendar @JvmOverloads constructor( .header("Depth", "1") .build()).execute() checkStatus(response, false) checkStatus(response) assertMultiStatus(response) response.body()?.charStream()?.use { return processMultiStatus(it) } throw InvalidDavResponseException("Didn't receive 207 Multi-status response on REPORT calendar-query") return processMultiStatus(response.body()?.charStream()!!) } /** Loading Loading @@ -138,14 +133,10 @@ class DavCalendar @JvmOverloads constructor( .method("REPORT", RequestBody.create(MIME_XML, writer.toString())) .build()).execute() checkStatus(response, false) checkStatus(response) assertMultiStatus(response) response.body()?.charStream()?.use { return processMultiStatus(it) } throw InvalidDavResponseException("Didn't receive 207 Multi-status response on REPORT calendar-multiget") return processMultiStatus(response.body()?.charStream()!!) } } Loading
build.gradle +3 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,8 @@ android { buildToolsVersion '27.0.3' defaultConfig { minSdkVersion 14 //noinspection MinSdkTooLow minSdkVersion 9 // Android 2.3 targetSdkVersion 27 buildConfigField "String", "version_okhttp", "\"$okhttp_version\"" Loading @@ -58,6 +59,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "com.squareup.okhttp3:okhttp:$okhttp_version" implementation "commons-io:commons-io:2.6" androidTestImplementation "com.squareup.okhttp3:mockwebserver:$okhttp_version" androidTestImplementation 'com.android.support.test:runner:1.0.2' Loading
src/androidTest/java/at/bitfire/dav4android/DavCollectionTest.kt +39 −41 Original line number Diff line number Diff line Loading @@ -94,8 +94,7 @@ class DavCollectionTest { " <D:sync-token>http://example.com/ns/sync/1234</D:sync-token>\n" + " </D:multistatus>") ) val changes = collection.reportChanges(null, false, null, GetETag.NAME) collection.reportChanges(null, false, null, GetETag.NAME).use { changes -> assertEquals(3, changes.members.size) val members = changes.members.iterator() val member1 = members.next() Loading @@ -114,6 +113,7 @@ class DavCollectionTest { assertFalse(changes.furtherResults) assertEquals("http://example.com/ns/sync/1234", changes.syncToken!!.token) } } /** * Test sample response for an initial sync-collection report with truncation from RFC 6578 3.10. Loading Loading @@ -158,8 +158,7 @@ class DavCollectionTest { " <D:sync-token>http://example.com/ns/sync/1233</D:sync-token>\n" + " </D:multistatus>") ) val changes = collection.reportChanges(null, false, null, GetETag.NAME) collection.reportChanges(null, false, null, GetETag.NAME).use { changes -> assertEquals(2, changes.members.size) val members = changes.members.iterator() val member1 = members.next() Loading @@ -177,6 +176,7 @@ class DavCollectionTest { assertTrue(changes.furtherResults) assertEquals("http://example.com/ns/sync/1233", changes.syncToken!!.token) } } /** * Test sample response for a sync-collection report with unsupported limit from RFC 6578 3.12. Loading @@ -196,13 +196,11 @@ class DavCollectionTest { ) try { collection.reportChanges("http://example.com/ns/sync/1232", false, 100, GetETag.NAME) collection.reportChanges("http://example.com/ns/sync/1232", false, 100, GetETag.NAME).close() fail("Expected HttpException") } catch (e: HttpException) { assertEquals(507, e.status) return } fail() } } No newline at end of file
src/androidTest/java/at/bitfire/dav4android/DavResourceTest.kt +103 −96 Original line number Diff line number Diff line Loading @@ -8,8 +8,8 @@ package at.bitfire.dav4android import at.bitfire.dav4android.exception.DavException import at.bitfire.dav4android.exception.HttpException import at.bitfire.dav4android.exception.InvalidDavResponseException import at.bitfire.dav4android.exception.PreconditionFailedException import at.bitfire.dav4android.property.DisplayName import at.bitfire.dav4android.property.GetContentType Loading Loading @@ -49,6 +49,15 @@ class DavResourceTest { private fun sampleUrl() = mockServer.url("/dav/") @Test fun testFilename() { assertEquals("", DavResource(httpClient, sampleUrl().resolve("/")!!).fileName()) assertEquals("hier1", DavResource(httpClient, sampleUrl().resolve("/hier1")!!).fileName()) assertEquals("", DavResource(httpClient, sampleUrl().resolve("/hier1/")!!).fileName()) assertEquals("hier2", DavResource(httpClient, sampleUrl().resolve("/hier1/hier2")!!).fileName()) assertEquals("", DavResource(httpClient, sampleUrl().resolve("/hier1/hier2/")!!).fileName()) } @Test fun testOptions() { val url = sampleUrl() Loading Loading @@ -81,10 +90,11 @@ class DavResourceTest { .setHeader("ETag", "W/\"My Weak ETag\"") .setHeader("Content-Type", "application/x-test-result") .setBody(sampleText)) val (responseOK, bodyOK) = dav.get("*/*") assertEquals(sampleText, bodyOK.string()) dav.get("*/*").use { responseOK -> assertEquals(sampleText, responseOK.body!!.string()) assertEquals("My Weak ETag", responseOK[GetETag::class.java]?.eTag) assertEquals("application/x-test-result", responseOK[GetContentType::class.java]?.type) } var rq = mockServer.takeRequest() assertEquals("GET", rq.method) Loading @@ -100,9 +110,10 @@ class DavResourceTest { .setResponseCode(HttpURLConnection.HTTP_OK) .setHeader("ETag", "\"StrongETag\"") .setBody(sampleText)) val (response302, body302) = dav.get("*/*") assertEquals(sampleText, body302.string()) dav.get("*/*").use { response302 -> assertEquals(sampleText, response302.body!!.string()) assertEquals("StrongETag", response302[GetETag::class.java]?.eTag) } mockServer.takeRequest() rq = mockServer.takeRequest() Loading @@ -113,8 +124,9 @@ class DavResourceTest { mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_OK) .setBody(sampleText)) val (responseWithoutETag, _) = dav.get("*/*") assertNull(responseWithoutETag[GetETag::class.java]) dav.get("*/*").use { assertNull(it[GetETag::class.java]) } } @Test Loading @@ -128,9 +140,10 @@ class DavResourceTest { mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_CREATED) .setHeader("ETag", "W/\"Weak PUT ETag\"")) val (response201, redirect201) = dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), null, false) assertFalse(redirect201) assertEquals("Weak PUT ETag", response201[GetETag::class.java]?.eTag) dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), null, false).use { assertEquals("Weak PUT ETag", it[GetETag::class.java]?.eTag) assertEquals(it.url, dav.location) } var rq = mockServer.takeRequest() assertEquals("PUT", rq.method) Loading @@ -144,10 +157,10 @@ class DavResourceTest { .setHeader("Location", "/target")) mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)) val (response301_204, redirect301_204) = dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), null, true) assertTrue(redirect301_204) assertEquals(url.resolve("/target"), dav.location) assertNull(response301_204[GetETag::class.java]) dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), null, true).use { assertEquals(url.resolve("/target"), it.url) assertNull("Weak PUT ETag", it[GetETag::class.java]?.eTag) } mockServer.takeRequest() rq = mockServer.takeRequest() Loading @@ -157,13 +170,10 @@ class DavResourceTest { // precondition: If-Match, 412 Precondition Failed mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_PRECON_FAILED)) val (_, _) = try { val pair = dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), "ExistingETag", false) fail() pair } catch(e: PreconditionFailedException) { Pair(null, null) } try { dav.put(RequestBody.create(MediaType.parse("text/plain"), sampleText), "ExistingETag", false).close() fail("Expected PreconditionFailedException") } catch(e: PreconditionFailedException) {} rq = mockServer.takeRequest() assertEquals("\"ExistingETag\"", rq.getHeader("If-Match")) assertNull(rq.getHeader("If-None-Match")) Loading @@ -179,7 +189,7 @@ class DavResourceTest { // no preconditions, 204 No Content mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)) dav.delete(null) dav.delete(null).close() var rq = mockServer.takeRequest() assertEquals("DELETE", rq.method) Loading @@ -190,7 +200,7 @@ class DavResourceTest { mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_OK) .setBody("Resource has been deleted.")) dav.delete("DeleteOnlyThisETag") dav.delete("DeleteOnlyThisETag").close() rq = mockServer.takeRequest() assertEquals("\"DeleteOnlyThisETag\"", rq.getHeader("If-Match")) Loading @@ -202,7 +212,7 @@ class DavResourceTest { ) mockServer.enqueue(MockResponse() .setResponseCode(HttpURLConnection.HTTP_OK)) dav.delete(null) dav.delete(null).close() /* NEGATIVE TEST CASES */ Loading @@ -210,11 +220,9 @@ class DavResourceTest { mockServer.enqueue(MockResponse() .setResponseCode(207)) try { dav.delete(null) fail() } catch(e: HttpException) { // treat 207 as an error } dav.delete(null).close() fail("Expected HttpException") } catch(e: HttpException) {} } @Test Loading @@ -228,17 +236,15 @@ class DavResourceTest { // * 500 Internal Server Error mockServer.enqueue(MockResponse().setResponseCode(HttpURLConnection.HTTP_INTERNAL_ERROR)) try { dav.propfind(0, ResourceType.NAME) dav.propfind(0, ResourceType.NAME).close() fail("Expected HttpException") } catch(e: HttpException) { } } catch(e: HttpException) {} // * 200 OK (instead of 207 Multi-Status) mockServer.enqueue(MockResponse().setResponseCode(HttpURLConnection.HTTP_OK)) try { dav.propfind(0, ResourceType.NAME) fail("Expected InvalidDavResponseException") } catch(e: InvalidDavResponseException) { } dav.propfind(0, ResourceType.NAME).close() fail("Expected DavException") } catch(e: DavException) {} // test for invalid multi-status responses: // * non-XML response Loading @@ -247,10 +253,9 @@ class DavResourceTest { .setHeader("Content-Type", "text/html") .setBody("<html></html>")) try { dav.propfind(0, ResourceType.NAME) fail("Expected InvalidDavResponseException") } catch(e: InvalidDavResponseException) { } dav.propfind(0, ResourceType.NAME).close() fail("Expected DavException") } catch(e: DavException) {} // * malformed XML response mockServer.enqueue(MockResponse() Loading @@ -258,10 +263,9 @@ class DavResourceTest { .setHeader("Content-Type", "application/xml; charset=utf-8") .setBody("<malformed-xml>")) try { dav.propfind(0, ResourceType.NAME) fail("Expected InvalidDavResponseException") } catch(e: InvalidDavResponseException) { } dav.propfind(0, ResourceType.NAME).close() fail("Expected DavException") } catch(e: DavException) {} // * response without <multistatus> root element mockServer.enqueue(MockResponse() Loading @@ -269,10 +273,9 @@ class DavResourceTest { .setHeader("Content-Type", "application/xml; charset=utf-8") .setBody("<test></test>")) try { dav.propfind(0, ResourceType.NAME) fail("Expected InvalidDavResponseException") } catch(e: InvalidDavResponseException) { } dav.propfind(0, ResourceType.NAME).close() fail("Expected DavException") } catch(e: DavException) {} // * multi-status response with invalid <status> in <response> mockServer.enqueue(MockResponse() Loading @@ -285,10 +288,9 @@ class DavResourceTest { " </response>" + "</multistatus>")) try { dav.propfind(0, ResourceType.NAME) dav.propfind(0, ResourceType.NAME).close() fail("Expected HttpException") } catch(e: HttpException) { } } catch(e: HttpException) {} // * multi-status response with <response>/<status> element indicating failure mockServer.enqueue(MockResponse() Loading @@ -303,8 +305,7 @@ class DavResourceTest { try { dav.propfind(0, ResourceType.NAME) fail("Expected HttpException") } catch(e: HttpException) { } } catch(e: HttpException) {} // * multi-status response with invalid <status> in <propstat> mockServer.enqueue(MockResponse() Loading @@ -321,8 +322,9 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val invalidStatus = dav.propfind(0, ResourceType.NAME) assertNull(invalidStatus[ResourceType::class.java]) dav.propfind(0, ResourceType.NAME).use { assertNull(it[ResourceType::class.java]) } /*** POSITIVE TESTS ***/ Loading @@ -332,9 +334,10 @@ class DavResourceTest { .setResponseCode(207) .setHeader("Content-Type", "application/xml; charset=utf-8") .setBody("<multistatus xmlns='DAV:'></multistatus>")) val emptyResponse = dav.propfind(0, ResourceType.NAME) assertEquals(0, emptyResponse.properties.size) assertEquals(0, emptyResponse.members.size) dav.propfind(0, ResourceType.NAME).use { assertEquals(0, it.properties.size) assertEquals(0, it.members.size) } // multi-status response with <response>/<status> element indicating success mockServer.enqueue(MockResponse() Loading @@ -346,9 +349,10 @@ class DavResourceTest { " <status>HTTP/1.1 200 OK</status>" + " </response>" + "</multistatus>")) val responseStatus = dav.propfind(0, ResourceType.NAME) assertEquals(0, responseStatus.properties.size) assertEquals(0, responseStatus.members.size) dav.propfind(0, ResourceType.NAME).use { assertEquals(0, it.properties.size) assertEquals(0, it.members.size) } // multi-status response with <response>/<propstat> element mockServer.enqueue(MockResponse() Loading @@ -367,9 +371,10 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val responsePropstat = dav.propfind(0, ResourceType.NAME, DisplayName.NAME) assertEquals("My DAV Collection", responsePropstat[DisplayName::class.java]?.displayName) assertEquals(0, responsePropstat.members.size) dav.propfind(0, ResourceType.NAME, DisplayName.NAME).use { assertEquals("My DAV Collection", it[DisplayName::class.java]?.displayName) assertEquals(0, it.members.size) } // multi-status response for collection with several members; incomplete (not all <resourcetype>s listed) mockServer.enqueue(MockResponse() Loading Loading @@ -433,10 +438,10 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val responseMembers = dav.propfind(1, ResourceType.NAME, DisplayName.NAME) assertEquals(4, responseMembers.members.size) dav.propfind(1, ResourceType.NAME, DisplayName.NAME).use { response -> assertEquals(4, response.members.size) val ok = BooleanArray(4) for (member in responseMembers.members) for (member in response.members) when (member.url) { url.resolve("/dav/subcollection/") -> { assertTrue(member[ResourceType::class.java]!!.types.contains(ResourceType.COLLECTION)) Loading @@ -457,7 +462,7 @@ class DavResourceTest { } } assertTrue(ok.all { it }) } /*** SPECIAL CASES ***/ Loading @@ -483,9 +488,10 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val some404Prop = dav.propfind(0, ResourceType.NAME, DisplayName.NAME) assertTrue(some404Prop[ResourceType::class.java]!!.types.contains(ResourceType.COLLECTION)) assertEquals("My DAV Collection", some404Prop[DisplayName::class.java]?.displayName) dav.propfind(0, ResourceType.NAME, DisplayName.NAME).use { assertTrue(it[ResourceType::class.java]!!.types.contains(ResourceType.COLLECTION)) assertEquals("My DAV Collection", it[DisplayName::class.java]?.displayName) } // multi-status response with <propstat> that doesn't contain <status> (=> assume 200 OK) mockServer.enqueue(MockResponse() Loading @@ -501,8 +507,9 @@ class DavResourceTest { " </propstat>" + " </response>" + "</multistatus>")) val propstatWithoutStatus = dav.propfind(0, DisplayName.NAME) assertEquals("Without Status", propstatWithoutStatus[DisplayName::class.java]?.displayName) dav.propfind(0, DisplayName.NAME).use { assertEquals("Without Status", it[DisplayName::class.java]?.displayName) } } }
src/main/java/at/bitfire/dav4android/DavAddressBook.kt +4 −13 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ package at.bitfire.dav4android import at.bitfire.dav4android.exception.DavException import at.bitfire.dav4android.exception.HttpException import at.bitfire.dav4android.exception.InvalidDavResponseException import okhttp3.* import java.io.IOException import java.io.StringWriter Loading Loading @@ -62,14 +61,10 @@ class DavAddressBook @JvmOverloads constructor( .header("Depth", "1") .build()).execute() checkStatus(response, false) checkStatus(response) assertMultiStatus(response) response.body()?.charStream()?.use { return processMultiStatus(it) } throw InvalidDavResponseException("Didn't receive 207 Multi-status response on REPORT addressbook-queryys") return processMultiStatus(response.body()?.charStream()!!) } /** Loading Loading @@ -117,14 +112,10 @@ class DavAddressBook @JvmOverloads constructor( .header("Depth", "0") // "The request MUST include a Depth: 0 header [...]" .build()).execute() checkStatus(response, false) checkStatus(response) assertMultiStatus(response) response.body()?.charStream()?.use { return processMultiStatus(it) } throw InvalidDavResponseException("Didn't receive 207 Multi-status response on REPORT addressbook-multiget") return processMultiStatus(response.body()?.charStream()!!) } }
src/main/java/at/bitfire/dav4android/DavCalendar.kt +4 −13 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ package at.bitfire.dav4android import at.bitfire.dav4android.exception.DavException import at.bitfire.dav4android.exception.HttpException import at.bitfire.dav4android.exception.InvalidDavResponseException import okhttp3.* import java.io.IOException import java.io.StringWriter Loading Loading @@ -89,14 +88,10 @@ class DavCalendar @JvmOverloads constructor( .header("Depth", "1") .build()).execute() checkStatus(response, false) checkStatus(response) assertMultiStatus(response) response.body()?.charStream()?.use { return processMultiStatus(it) } throw InvalidDavResponseException("Didn't receive 207 Multi-status response on REPORT calendar-query") return processMultiStatus(response.body()?.charStream()!!) } /** Loading Loading @@ -138,14 +133,10 @@ class DavCalendar @JvmOverloads constructor( .method("REPORT", RequestBody.create(MIME_XML, writer.toString())) .build()).execute() checkStatus(response, false) checkStatus(response) assertMultiStatus(response) response.body()?.charStream()?.use { return processMultiStatus(it) } throw InvalidDavResponseException("Didn't receive 207 Multi-status response on REPORT calendar-multiget") return processMultiStatus(response.body()?.charStream()!!) } }