From 03ee9a037be0e3feeb9e0a02686736450dbeb960 Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Tue, 5 Apr 2016 23:25:18 +0200 Subject: [PATCH] Various tests --- app/build.gradle | 4 +- .../davdroid/SSLSocketFactoryCompatTest.java | 3 - .../at/bitfire/davdroid/TestConstants.java | 27 --- .../at/bitfire/davdroid/TestDavUtils.java | 24 +++ .../davdroid/model/CollectionInfoTest.java | 110 +++++++++++ .../resource/DavResourceFinderTest.java | 90 --------- .../ui/setup/DavResourceFinderTest.java | 179 ++++++++++++++++++ .../at/bitfire/davdroid/model/ServiceDB.java | 2 +- .../davdroid/ui/setup/DavResourceFinder.java | 9 +- 9 files changed, 325 insertions(+), 123 deletions(-) delete mode 100644 app/src/androidTest/java/at/bitfire/davdroid/TestConstants.java create mode 100644 app/src/androidTest/java/at/bitfire/davdroid/TestDavUtils.java create mode 100644 app/src/androidTest/java/at/bitfire/davdroid/model/CollectionInfoTest.java delete mode 100644 app/src/androidTest/java/at/bitfire/davdroid/resource/DavResourceFinderTest.java create mode 100644 app/src/androidTest/java/at/bitfire/davdroid/ui/setup/DavResourceFinderTest.java diff --git a/app/build.gradle b/app/build.gradle index cdb397eb..a6fffa64 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,7 +73,9 @@ dependencies { compile 'com.github.yukuku:ambilwarna:2.0.1' compile project(':MemorizingTrustManager') - androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.2.0' compile 'dnsjava:dnsjava:2.1.7' compile 'org.apache.commons:commons-lang3:3.4' + + // for tests + androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.2.0' } diff --git a/app/src/androidTest/java/at/bitfire/davdroid/SSLSocketFactoryCompatTest.java b/app/src/androidTest/java/at/bitfire/davdroid/SSLSocketFactoryCompatTest.java index a9def171..feb5e768 100644 --- a/app/src/androidTest/java/at/bitfire/davdroid/SSLSocketFactoryCompatTest.java +++ b/app/src/androidTest/java/at/bitfire/davdroid/SSLSocketFactoryCompatTest.java @@ -11,15 +11,12 @@ package at.bitfire.davdroid; import android.os.Build; import android.test.InstrumentationTestCase; -import junit.framework.TestCase; - import java.io.IOException; import java.net.Socket; import javax.net.ssl.SSLSocket; import de.duenndns.ssl.MemorizingTrustManager; -import okhttp3.OkHttpClient; import okhttp3.mockwebserver.MockWebServer; public class SSLSocketFactoryCompatTest extends InstrumentationTestCase { diff --git a/app/src/androidTest/java/at/bitfire/davdroid/TestConstants.java b/app/src/androidTest/java/at/bitfire/davdroid/TestConstants.java deleted file mode 100644 index 28836104..00000000 --- a/app/src/androidTest/java/at/bitfire/davdroid/TestConstants.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ - -package at.bitfire.davdroid; - -import android.util.Log; - -import java.net.URI; -import java.net.URISyntaxException; - -public class TestConstants { - public static final String ROBOHYDRA_BASE = "http://192.168.0.11:3000/"; - - public static URI roboHydra; - static { - try { - roboHydra = new URI(ROBOHYDRA_BASE); - } catch(URISyntaxException e) { - Log.wtf("davdroid.test.Constants", "Invalid RoboHydra base URL"); - } - } -} diff --git a/app/src/androidTest/java/at/bitfire/davdroid/TestDavUtils.java b/app/src/androidTest/java/at/bitfire/davdroid/TestDavUtils.java new file mode 100644 index 00000000..92549697 --- /dev/null +++ b/app/src/androidTest/java/at/bitfire/davdroid/TestDavUtils.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + */ + +package at.bitfire.davdroid; + +import junit.framework.TestCase; + +public class TestDavUtils extends TestCase { + + private static final String exampleURL = "http://example.com/"; + + public void testLastSegmentOfUrl() { + assertEquals("/", DavUtils.lastSegmentOfUrl(exampleURL)); + assertEquals("dir", DavUtils.lastSegmentOfUrl(exampleURL + "dir")); + assertEquals("dir", DavUtils.lastSegmentOfUrl(exampleURL + "dir/")); + assertEquals("file.html", DavUtils.lastSegmentOfUrl(exampleURL + "dir/file.html")); + } + +} diff --git a/app/src/androidTest/java/at/bitfire/davdroid/model/CollectionInfoTest.java b/app/src/androidTest/java/at/bitfire/davdroid/model/CollectionInfoTest.java new file mode 100644 index 00000000..a4789b94 --- /dev/null +++ b/app/src/androidTest/java/at/bitfire/davdroid/model/CollectionInfoTest.java @@ -0,0 +1,110 @@ +/* + * Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + */ + +package at.bitfire.davdroid.model; + +import android.content.ContentValues; + +import junit.framework.TestCase; + +import java.io.IOException; + +import at.bitfire.dav4android.DavResource; +import at.bitfire.dav4android.exception.DavException; +import at.bitfire.dav4android.exception.HttpException; +import at.bitfire.dav4android.property.ResourceType; +import at.bitfire.davdroid.HttpClient; +import at.bitfire.davdroid.model.ServiceDB.Collections; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +public class CollectionInfoTest extends TestCase { + + MockWebServer server = new MockWebServer(); + + public void testFromDavResource() throws IOException, HttpException, DavException { + // r/w address book + server.enqueue(new MockResponse() + .setResponseCode(207) + .setBody("" + + "" + + " /" + + " " + + " " + + " My Contacts" + + " My Contacts Description" + + " " + + "" + + "")); + + DavResource dav = new DavResource(HttpClient.create(), server.url("/")); + dav.propfind(0, ResourceType.NAME); + CollectionInfo info = CollectionInfo.fromDavResource(dav); + assertEquals(CollectionInfo.Type.ADDRESS_BOOK, info.type); + assertFalse(info.readOnly); + assertEquals("My Contacts", info.displayName); + assertEquals("My Contacts Description", info.description); + + // read-only calendar, no display name + server.enqueue(new MockResponse() + .setResponseCode(207) + .setBody("" + + "" + + " /" + + " " + + " " + + " " + + " My Calendar" + + " tzdata" + + " #ff0000" + + " " + + "" + + "")); + + dav = new DavResource(HttpClient.create(), server.url("/")); + dav.propfind(0, ResourceType.NAME); + info = CollectionInfo.fromDavResource(dav); + assertEquals(CollectionInfo.Type.CALENDAR, info.type); + assertTrue(info.readOnly); + assertNull(info.displayName); + assertEquals("My Calendar", info.description); + assertEquals(0xFFFF0000, (int)info.color); + assertEquals("tzdata", info.timeZone); + assertTrue(info.supportsVEVENT); + assertTrue(info.supportsVTODO); + } + + public void testFromDB() { + ContentValues values = new ContentValues(); + values.put(Collections.ID, 1); + values.put(Collections.SERVICE_ID, 1); + values.put(Collections.URL, "http://example.com"); + values.put(Collections.READ_ONLY, 1); + values.put(Collections.DISPLAY_NAME, "display name"); + values.put(Collections.DESCRIPTION, "description"); + values.put(Collections.COLOR, 0xFFFF0000); + values.put(Collections.TIME_ZONE, "tzdata"); + values.put(Collections.SUPPORTS_VEVENT, 1); + values.put(Collections.SUPPORTS_VTODO, 1); + values.put(Collections.SYNC, 1); + + CollectionInfo info = CollectionInfo.fromDB(values); + assertEquals(1, info.id); + assertEquals(1, (long)info.serviceID); + assertEquals("http://example.com", info.url); + assertTrue(info.readOnly); + assertEquals("display name", info.displayName); + assertEquals("description", info.description); + assertEquals(0xFFFF0000, (int)info.color); + assertEquals("tzdata", info.timeZone); + assertTrue(info.supportsVEVENT); + assertTrue(info.supportsVTODO); + assertTrue(info.selected); + } + +} diff --git a/app/src/androidTest/java/at/bitfire/davdroid/resource/DavResourceFinderTest.java b/app/src/androidTest/java/at/bitfire/davdroid/resource/DavResourceFinderTest.java deleted file mode 100644 index 752c3e06..00000000 --- a/app/src/androidTest/java/at/bitfire/davdroid/resource/DavResourceFinderTest.java +++ /dev/null @@ -1,90 +0,0 @@ -package at.bitfire.davdroid.resource; - -import android.test.InstrumentationTestCase; - -import java.io.IOException; -import java.net.URI; - -import at.bitfire.dav4android.exception.DavException; -import at.bitfire.dav4android.exception.HttpException; -import at.bitfire.davdroid.ui.setup.DavResourceFinder; -import at.bitfire.davdroid.ui.setup.LoginCredentials; -import okhttp3.HttpUrl; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; - -public class DavResourceFinderTest extends InstrumentationTestCase { - - MockWebServer server = new MockWebServer(); - - @Override - protected void setUp() throws Exception { - server.start(); - } - - @Override - protected void tearDown() throws Exception { - server.shutdown(); - } - - - public void testGetCurrentUserPrincipal() throws IOException, HttpException, DavException { - HttpUrl url = server.url("/dav"); - LoginCredentials credentials = new LoginCredentials(url.uri(), "admin", "12345", true); - DavResourceFinder finder = new DavResourceFinder(getInstrumentation().getTargetContext().getApplicationContext(), credentials); - - // positive test case - server.enqueue(new MockResponse() // PROPFIND response - .setResponseCode(207) - .setHeader("Content-Type", "application/xml;charset=utf-8") - .setBody("" + - " " + - " /dav" + - " " + - " " + - " /principals/myself" + - " " + - " HTTP/1.0 200 OK" + - " " + - " " + - "")); - server.enqueue(new MockResponse() // OPTIONS response - .setResponseCode(200) - .setHeader("DAV", "addressbook")); - URI principal = finder.getCurrentUserPrincipal(url, DavResourceFinder.Service.CARDDAV); - assertEquals(url.resolve("/principals/myself").uri(), principal); - - // negative test case: no current-user-principal - server.enqueue(new MockResponse() - .setResponseCode(207) - .setHeader("Content-Type", "application/xml;charset=utf-8") - .setBody("" + - " " + - " /dav" + - " HTTP/1.0 200 OK" + - " " + - "")); - assertNull(finder.getCurrentUserPrincipal(url, DavResourceFinder.Service.CARDDAV)); - - // negative test case: requested service not available - server.enqueue(new MockResponse() // PROPFIND response - .setResponseCode(207) - .setHeader("Content-Type", "application/xml;charset=utf-8") - .setBody("" + - " " + - " /dav" + - " " + - " " + - " /principals/myself" + - " " + - " HTTP/1.0 200 OK" + - " " + - " " + - "")); - server.enqueue(new MockResponse() // OPTIONS response - .setResponseCode(200) - .setHeader("DAV", "addressbook")); - assertNull(finder.getCurrentUserPrincipal(url, DavResourceFinder.Service.CALDAV)); - } - -} diff --git a/app/src/androidTest/java/at/bitfire/davdroid/ui/setup/DavResourceFinderTest.java b/app/src/androidTest/java/at/bitfire/davdroid/ui/setup/DavResourceFinderTest.java new file mode 100644 index 00000000..4070c44e --- /dev/null +++ b/app/src/androidTest/java/at/bitfire/davdroid/ui/setup/DavResourceFinderTest.java @@ -0,0 +1,179 @@ +package at.bitfire.davdroid.ui.setup; + +import android.test.InstrumentationTestCase; + +import java.io.IOException; +import java.net.URI; + +import at.bitfire.dav4android.DavResource; +import at.bitfire.dav4android.exception.DavException; +import at.bitfire.dav4android.exception.HttpException; +import at.bitfire.dav4android.property.AddressbookHomeSet; +import at.bitfire.dav4android.property.ResourceType; +import at.bitfire.davdroid.App; +import at.bitfire.davdroid.HttpClient; +import at.bitfire.davdroid.ui.setup.DavResourceFinder.Configuration.ServiceInfo; +import okhttp3.OkHttpClient; +import okhttp3.mockwebserver.Dispatcher; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; + +public class DavResourceFinderTest extends InstrumentationTestCase { + + MockWebServer server = new MockWebServer(); + + DavResourceFinder finder; + OkHttpClient client; + LoginCredentials credentials; + + private static final String + PATH_NO_DAV = "/nodav", + + PATH_CALDAV = "/caldav", + PATH_CARDDAV = "/carddav", + PATH_CALDAV_AND_CARDDAV = "/both-caldav-carddav", + + SUBPATH_PRINCIPAL = "/principal", + SUBPATH_ADDRESSBOOK_HOMESET = "/addressbooks", + SUBPATH_ADDRESSBOOK = "/addressbooks/private-contacts"; + + @Override + protected void setUp() throws Exception { + server.setDispatcher(new TestDispatcher()); + server.start(); + + credentials = new LoginCredentials(URI.create("/"), "mock", "12345", true); + finder = new DavResourceFinder(getInstrumentation().getContext(), credentials); + + client = HttpClient.create(); + client = HttpClient.addAuthentication(client, credentials.userName, credentials.password, credentials.authPreemptive); + } + + @Override + protected void tearDown() throws Exception { + server.shutdown(); + } + + + public void testRememberIfAddressBookOrHomeset() throws IOException, HttpException, DavException { + ServiceInfo info; + + // before dav.propfind(), no info is available + DavResource dav = new DavResource(client, server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL)); + finder.rememberIfAddressBookOrHomeset(dav, info = new ServiceInfo()); + assertEquals(0, info.collections.size()); + assertEquals(0, info.homeSets.size()); + + // recognize home set + dav.propfind(0, AddressbookHomeSet.NAME); + finder.rememberIfAddressBookOrHomeset(dav, info = new ServiceInfo()); + assertEquals(0, info.collections.size()); + assertEquals(1, info.homeSets.size()); + assertEquals(server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK_HOMESET + "/").uri(), info.homeSets.iterator().next()); + + // recognize address book + dav = new DavResource(client, server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK)); + dav.propfind(0, ResourceType.NAME); + finder.rememberIfAddressBookOrHomeset(dav, info = new ServiceInfo()); + assertEquals(1, info.collections.size()); + assertEquals(server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK + "/").uri(), info.collections.keySet().iterator().next()); + assertEquals(0, info.homeSets.size()); + } + + public void testProvidesService() throws IOException { + assertFalse(finder.providesService(server.url(PATH_NO_DAV), DavResourceFinder.Service.CALDAV)); + assertFalse(finder.providesService(server.url(PATH_NO_DAV), DavResourceFinder.Service.CARDDAV)); + + assertTrue(finder.providesService(server.url(PATH_CALDAV), DavResourceFinder.Service.CALDAV)); + assertFalse(finder.providesService(server.url(PATH_CALDAV), DavResourceFinder.Service.CARDDAV)); + + assertTrue(finder.providesService(server.url(PATH_CARDDAV), DavResourceFinder.Service.CARDDAV)); + assertFalse(finder.providesService(server.url(PATH_CARDDAV), DavResourceFinder.Service.CALDAV)); + + assertTrue(finder.providesService(server.url(PATH_CALDAV_AND_CARDDAV), DavResourceFinder.Service.CALDAV)); + assertTrue(finder.providesService(server.url(PATH_CALDAV_AND_CARDDAV), DavResourceFinder.Service.CARDDAV)); + } + + public void testGetCurrentUserPrincipal() throws IOException, HttpException, DavException { + assertNull(finder.getCurrentUserPrincipal(server.url(PATH_NO_DAV), DavResourceFinder.Service.CALDAV)); + assertNull(finder.getCurrentUserPrincipal(server.url(PATH_NO_DAV), DavResourceFinder.Service.CARDDAV)); + + assertEquals( + server.url(PATH_CALDAV + SUBPATH_PRINCIPAL).uri(), + finder.getCurrentUserPrincipal(server.url(PATH_CALDAV), DavResourceFinder.Service.CALDAV) + ); + assertNull(finder.getCurrentUserPrincipal(server.url(PATH_CALDAV), DavResourceFinder.Service.CARDDAV)); + + assertEquals( + server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL).uri(), + finder.getCurrentUserPrincipal(server.url(PATH_CARDDAV), DavResourceFinder.Service.CARDDAV) + ); + assertNull(finder.getCurrentUserPrincipal(server.url(PATH_CARDDAV), DavResourceFinder.Service.CALDAV)); + } + + + // mock server + + public class TestDispatcher extends Dispatcher { + + @Override + public MockResponse dispatch(RecordedRequest rq) throws InterruptedException { + if (!checkAuth(rq)) + return new MockResponse().setResponseCode(401); + + String path = rq.getPath(); + + if ("OPTIONS".equalsIgnoreCase(rq.getMethod())) { + String dav = null; + if (path.startsWith(PATH_CALDAV)) + dav = "calendar-access"; + else if (path.startsWith(PATH_CARDDAV)) + dav = "addressbook"; + else if (path.startsWith(PATH_CALDAV_AND_CARDDAV)) + dav = "calendar-access, addressbook"; + MockResponse response = new MockResponse().setResponseCode(200); + if (dav != null) + response.addHeader("DAV", dav); + return response; + + } else if ("PROPFIND".equalsIgnoreCase(rq.getMethod())) { + String props = null; + switch (path) { + case PATH_CALDAV: + case PATH_CARDDAV: + props = "" + path + SUBPATH_PRINCIPAL + ""; + break; + + case PATH_CARDDAV + SUBPATH_PRINCIPAL: + props = "" + + " " + PATH_CARDDAV + SUBPATH_ADDRESSBOOK_HOMESET + "" + + ""; + break; + case PATH_CARDDAV + SUBPATH_ADDRESSBOOK: + props = "" + + " " + + " " + + ""; + break; + } + App.log.info("Sending props: " + props); + return new MockResponse() + .setResponseCode(207) + .setBody("" + + "" + + " " + rq.getPath() + "" + + " " + props + "" + + "" + + ""); + } + + return new MockResponse().setResponseCode(404); + } + + private boolean checkAuth(RecordedRequest rq) { + return "Basic bW9jazoxMjM0NQ==".equals(rq.getHeader("Authorization")); + } + } + +} diff --git a/app/src/main/java/at/bitfire/davdroid/model/ServiceDB.java b/app/src/main/java/at/bitfire/davdroid/model/ServiceDB.java index 2ac5b5f1..86d623a4 100644 --- a/app/src/main/java/at/bitfire/davdroid/model/ServiceDB.java +++ b/app/src/main/java/at/bitfire/davdroid/model/ServiceDB.java @@ -122,7 +122,7 @@ public class ServiceDB { Collections.DISPLAY_NAME + " TEXT NULL," + Collections.DESCRIPTION + " TEXT NULL," + Collections.COLOR + " INTEGER NULL," + - Collections.TIME_ZONE + " TEXt NULL," + + Collections.TIME_ZONE + " TEXT NULL," + Collections.SUPPORTS_VEVENT + " INTEGER NULL," + Collections.SUPPORTS_VTODO + " INTEGER NULL," + Collections.SYNC + " INTEGER DEFAULT 0 NOT NULL" + diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.java b/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.java index bf208585..ffb12036 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.java @@ -190,6 +190,13 @@ public class DavResourceFinder { } } + /** + * If #dav is an address book or an address book home set, it will added to + * config.collections or config.homesets. Only evaluates already known properties, + * does not call dav.propfind()! URLs will be stored with trailing "/". + * @param dav resource whose properties are evaluated + * @param config structure where the address book (collection) and/or home set is stored into (if found) + */ protected void rememberIfAddressBookOrHomeset(@NonNull DavResource dav, @NonNull Configuration.ServiceInfo config) { // Is the collection an address book? ResourceType resourceType = (ResourceType)dav.properties.get(ResourceType.NAME); @@ -223,7 +230,7 @@ public class DavResourceFinder { } - boolean providesService(HttpUrl url, Service service) throws IOException { + protected boolean providesService(HttpUrl url, Service service) throws IOException { DavResource davPrincipal = new DavResource(httpClient, url, log); try { davPrincipal.options();