From caa9bb3d01a14423bb5c9f82357d3ebbd27acf26 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Tue, 27 Oct 2015 09:13:15 +0100 Subject: [PATCH 1/4] Added test for GetRemoteShareesOperation --- .../lib/test_project/test/GetShareesTest.java | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 test_client/tests/src/com/owncloud/android/lib/test_project/test/GetShareesTest.java diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetShareesTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetShareesTest.java new file mode 100644 index 00000000..80bcd107 --- /dev/null +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/GetShareesTest.java @@ -0,0 +1,228 @@ +/* ownCloud Android Library is available under MIT license + * @author David A. Velasco + * Copyright (C) 2015 ownCloud Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.test_project.test; + +import java.security.GeneralSecurityException; + +import junit.framework.AssertionFailedError; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.json.JSONException; +import org.json.JSONObject; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientFactory; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; +import com.owncloud.android.lib.common.network.NetworkUtils; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation; +import com.owncloud.android.lib.test_project.R; +import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; + +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +/** + * Class to test GetRemoteShareesOperation + * + * With this TestCase we are experimenting a bit to improve the test suite design, in two aspects: + * + * - Reduce the dependency from the set of test cases on the "test project" needed to + * have an instrumented APK to install in the device, as required by the testing framework + * provided by Android. To get there, this class avoids calling TestActivity methods in the test + * method. + * + * - Reduce the impact of creating a remote fixture over the Internet, while the structure of the + * TestCase is kept easy to maintain. To get this, all the tests are done in a single test method, + * granting this way that setUp and tearDown are run only once. + * + */ + +public class GetShareesTest extends RemoteTest { + + private static final String LOG_TAG = GetShareesTest.class.getCanonicalName(); + + String mServerUri, mUser, mPass; + OwnCloudClient mClient = null; + + public GetShareesTest() { + super(); + + Protocol pr = Protocol.getProtocol("https"); + if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { + try { + ProtocolSocketFactory psf = new SelfSignedConfidentSslSocketFactory(); + Protocol.registerProtocol( + "https", + new Protocol("https", psf, 443)); + + } catch (GeneralSecurityException e) { + throw new AssertionFailedError( + "Self-signed confident SSL context could not be loaded"); + } + } + + } + + + protected Context getContext() { + return getActivity(); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Next initialization cannot be done in the constructor because getContext() is not + // ready yet, returns NULL. + initAccessToServer(getContext()); + + Log.v(LOG_TAG, "Setting up the remote fixture..."); + + Log.v(LOG_TAG, "Remote fixture created."); + + } + + + /** + * Test get sharees + * + * Requires OC server 8.2 or later + */ + public void testGetRemoteShareesOperation() { + Log.v(LOG_TAG, "testGetRemoteSharees in"); + + /// successful cases + + // search for sharees including "a" + GetRemoteShareesOperation getShareesOperation = new GetRemoteShareesOperation("a", 1, 50); + RemoteOperationResult result = getShareesOperation.execute(mClient); + JSONObject resultItem; + JSONObject value; + byte type; + int userCount = 0, groupCount = 0; + assertTrue(result.isSuccess() && result.getData().size() == 3); + try { + for (int i=0; i<3; i++) { + resultItem = (JSONObject) result.getData().get(i); + value = resultItem.getJSONObject(GetRemoteShareesOperation.NODE_VALUE); + type = (byte) value.getInt(GetRemoteShareesOperation.PROPERTY_SHARE_TYPE); + if (GetRemoteShareesOperation.GROUP_TYPE.equals(type)) { + groupCount++; + } else { + userCount++; + } + } + assertEquals(userCount, 2); + assertEquals(groupCount, 1); + } catch (JSONException e) { + AssertionFailedError afe = new AssertionFailedError(e.getLocalizedMessage()); + afe.setStackTrace(e.getStackTrace()); + throw afe; + } + + // search for sharees including "ad" + getShareesOperation = new GetRemoteShareesOperation("ad", 1, 50); + result = getShareesOperation.execute(mClient); + assertTrue(result.isSuccess() && result.getData().size() == 2); + userCount = 0; groupCount = 0; + try { + for (int i=0; i<2; i++) { + resultItem = (JSONObject) result.getData().get(i); + value = resultItem.getJSONObject(GetRemoteShareesOperation.NODE_VALUE); + type = (byte) value.getInt(GetRemoteShareesOperation.PROPERTY_SHARE_TYPE); + if (GetRemoteShareesOperation.GROUP_TYPE.equals(type)) { + groupCount++; + } else { + userCount++; + } + } + assertEquals(userCount, 1); + assertEquals(groupCount, 1); + } catch (JSONException e) { + AssertionFailedError afe = new AssertionFailedError(e.getLocalizedMessage()); + afe.setStackTrace(e.getStackTrace()); + throw afe; + } + + + // search for sharees including "b" + getShareesOperation = new GetRemoteShareesOperation("b", 1, 50); + result = getShareesOperation.execute(mClient); + assertTrue(result.isSuccess() && result.getData().size() == 0); + + + /// failed cases + + // search for sharees including wrong page values + getShareesOperation = new GetRemoteShareesOperation("a", 0, 50); + result = getShareesOperation.execute(mClient); + assertTrue(!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_BAD_REQUEST); + + getShareesOperation = new GetRemoteShareesOperation("a", 1, 0); + result = getShareesOperation.execute(mClient); + assertTrue(!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_BAD_REQUEST); + } + + @Override + protected void tearDown() throws Exception { + Log.v(LOG_TAG, "Deleting remote fixture..."); + super.tearDown(); + Log.v(LOG_TAG, "Remote fixture delete."); + } + + + private void initAccessToServer(Context context) { + Log.v(LOG_TAG, "Setting up client instance to access OC server..."); + + mServerUri = context.getString(R.string.server_base_url); + mUser = context.getString(R.string.username); + mPass = context.getString(R.string.password); + + mClient = new OwnCloudClient( + Uri.parse(mServerUri), + NetworkUtils.getMultiThreadedConnManager() + ); + mClient.setDefaultTimeouts( + OwnCloudClientFactory.DEFAULT_DATA_TIMEOUT, + OwnCloudClientFactory.DEFAULT_CONNECTION_TIMEOUT); + mClient.setFollowRedirects(true); + mClient.setCredentials( + OwnCloudCredentialsFactory.newBasicCredentials( + mUser, + mPass + ) + ); + + Log.v(LOG_TAG, "Client instance set up."); + + } + + +} From 96825b43b93a0ee771649f6a8097ad722ab6cb82 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 29 Oct 2015 18:29:49 +0100 Subject: [PATCH 2/4] Updated test server --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8ccad6c8..fe5cb9c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,8 @@ script: - ./gradlew clean build env: global: - - secure: HxHoqnC8mauCKi87zlo7pQcSsSw0W5MtW+iUcB8T11quwTBgUPWIOmycXv2FcmwpST0E43Ct+dhE+mttm+6P+5PSB33HQNLq00hfTVIJ4ttcb/5eWW8MnP7L+kPK8d0EtfDG6GQto7QktaybeG4+sNKKD336ZlFfM7xgPtPv+tg= - - secure: WQMw0ciloe8i2ApGhePhuTmmH8UgAV1Ri10C1qhUH9hVOJAr+/1X5A93VPYGrgJ2EH5MdiL6f2XMDCYAgb9efuvZIUKNE0J92xh8m/yRa8nAVWNBE0PBdS4+OycoHpIQfMcUghooERXjP4GUYd/ZwICvWA+sXdOYWDdKjODUgl4= - - secure: QPxKT8vC7sm1b/hYJcfkQkLgpwNRBvVKk8S8S0t43mmqPJfs94FJTQHH4kZaGSwOeuDkRQbGuKzYtXOnGOKX2hhUBqKJd1idpJnUID8id8Kqo6VutjG017+XxZQp0hPHmfmDxYkDvlaLeoZpP2NkpwZ1p4TL2MSCr2Ibl6uTWvc= + - secure: a21NrzTCQnkTKtRGo7B1lyF2WWbpBT2N64V2Tf+oUcRLOUx3XM/mDi60mAdGd0WXV9tHD8GGmu0tQ7LGZ2VsIxixVxjzEYwX4HRTodewYez6WxBMjVEHHy+3jmc1zU4k3AAqr+uW7L4BKa5r9tH+nq9ecJMDMgW8o9MKXuP7Vso= + - secure: UVnaC5Qzat2C8WlMMb8aycz1ChZKjP8Kz89qBbVcqYK+PLAGKpUNxFa39/2oA5jkMyyOcXYC9bX1ZYzHLH7nJ8LbQgaxXMT4gvgvN0l6KezjDavIW60idD9BbugkwzNj/cjoU/DdxBykPsTn4vSRaESVNTdEbM27YU4FBPzTANY= + - secure: XEQY8s7p65lWWOuKbVDdTh6ZJtRTJ74Zw3H/+2Ms6vjZhFZsdUJjGo66LW6YvlhmYDXgiPB9piYQGcrGgT3hXJwXoge6n1pdixnV250J0T0dIZMbXYTWTARxDsyq48+LgUuF3pgqvqDWhBcemrePWv48q7fs/mwzuFSOyc8QwLk= matrix: - ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a From b5074f4381217ff9acbc52cbbaba9c3331df3735 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 29 Oct 2015 18:52:14 +0100 Subject: [PATCH 3/4] Migrate Travis build to container-based infrastructure --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index fe5cb9c1..d12be4a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +sudo: false language: android android: components: From 5c48817712be36262002605c25abd0b41d02fb80 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Mon, 2 Nov 2015 14:59:01 +0100 Subject: [PATCH 4/4] Update unit tests with cases for creating private shares --- .../test_project/test/CreateShareTest.java | 151 +++++++++++++++++- 1 file changed, 148 insertions(+), 3 deletions(-) diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/CreateShareTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/CreateShareTest.java index 782c06d8..8d08dd81 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/CreateShareTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/CreateShareTest.java @@ -31,6 +31,9 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCo import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.test_project.TestActivity; +/** + * Test Create Share: the server must support SHARE API + */ public class CreateShareTest extends RemoteTest { private static final String LOG_TAG = CreateShareTest.class.getCanonicalName(); @@ -38,15 +41,20 @@ public class CreateShareTest extends RemoteTest { /* File to share.*/ private static final String FILE_TO_SHARE = "/fileToShare.txt"; + /* Non-existent file*/ + private static final String NON_EXISTENT_FILE = "/nonExistentFile.txt"; + private TestActivity mActivity; private String mFullPath2FileToShare; + private String mFullPath2NonExistentFile; @Override protected void setUp() throws Exception { super.setUp(); setActivityInitialTouchMode(false); mActivity = getActivity(); - mFullPath2FileToShare = mBaseFolderPath + FILE_TO_SHARE; + mFullPath2FileToShare = mBaseFolderPath + FILE_TO_SHARE; + mFullPath2NonExistentFile = mBaseFolderPath + NON_EXISTENT_FILE; File textFile = mActivity.extractAsset(TestActivity.ASSETS__TEXT_FILE_NAME); RemoteOperationResult result = mActivity.uploadFile( @@ -57,11 +65,13 @@ public class CreateShareTest extends RemoteTest { Utils.logAndThrow(LOG_TAG, result); } } - + /** - * Test Create Share: the server must support SHARE API + * Test creation of public shares */ public void testCreatePublicShare() { + + /// Successful cases RemoteOperationResult result = mActivity.createShare( mFullPath2FileToShare, ShareType.PUBLIC_LINK, @@ -70,6 +80,141 @@ public class CreateShareTest extends RemoteTest { "", 1); assertTrue(result.isSuccess()); + + /// Failed cases + + // file doesn't exist + result = mActivity.createShare( + mFullPath2NonExistentFile, + ShareType.PUBLIC_LINK, + "", + false, + "", + 1); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_NOT_FOUND, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + + } + + + /** + * Test creation of private shares with groups + */ + public void testCreatePrivateShareWithUser() { + + /// Successful cases + RemoteOperationResult result = mActivity.createShare( + mFullPath2FileToShare, + ShareType.USER, + "admin", + false, + "", + 31); + assertTrue(result.isSuccess()); + + + /// Failed cases + + // sharee doesn't exist + result = mActivity.createShare( + mFullPath2FileToShare, + ShareType.USER, + "no_exist", + false, + "", + 31); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + + // file doesn't exist + result = mActivity.createShare( + mFullPath2NonExistentFile, + ShareType.USER, + "admin", + false, + "", + 31); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_NOT_FOUND, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + + } + + + /** + * Test creation of private shares with groups + */ + public void testCreatePrivateShareWithGroup() { + + /// Successful cases + RemoteOperationResult result = mActivity.createShare( + mFullPath2FileToShare, + ShareType.GROUP, + "admin", + false, + "", + 1); + assertTrue(result.isSuccess()); + + + /// Failed cases + + // sharee doesn't exist + result = mActivity.createShare( + mFullPath2FileToShare, + ShareType.GROUP, + "no_exist", + false, + "", + 31); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_WRONG_PARAMETER, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + + // file doesn't exist + result = mActivity.createShare( + mFullPath2NonExistentFile, + ShareType.GROUP, + "admin", + false, + "", + 31); + assertFalse(result.isSuccess()); + assertEquals( + RemoteOperationResult.ResultCode.SHARE_NOT_FOUND, + result.getCode() + ); + assertTrue( // error message from server as part of the result + result.getData().size() == 1 && + result.getData().get(0) instanceof String + ); + }