From b4e974491e31e08f6909c650d4037f94567d5971 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 21 Aug 2014 17:36:16 +0200 Subject: [PATCH 1/9] Added operation to move remote files --- .../operations/RemoteOperationResult.java | 4 +- .../files/MoveRemoteFileOperation.java | 213 ++++++++++++++++++ 2 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 9bb0d4c7..86537a70 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -101,7 +101,9 @@ public class RemoteOperationResult implements Serializable { LOCAL_STORAGE_NOT_REMOVED, FORBIDDEN, SHARE_FORBIDDEN, - OK_REDIRECT_TO_NON_SECURE_CONNECTION + OK_REDIRECT_TO_NON_SECURE_CONNECTION, + INVALID_MOVE_INTO_DESCENDANT, + PARTIAL_MOVE_DONE } private boolean mSuccess = false; diff --git a/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java new file mode 100644 index 00000000..258087c3 --- /dev/null +++ b/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java @@ -0,0 +1,213 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 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.resources.files; + +import java.io.IOException; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.jackrabbit.webdav.DavException; +import org.apache.jackrabbit.webdav.MultiStatusResponse; +import org.apache.jackrabbit.webdav.Status; +import org.apache.jackrabbit.webdav.client.methods.MoveMethod; + +import android.util.Log; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.network.WebdavUtils; +import com.owncloud.android.lib.common.operations.RemoteOperation; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; + + +/** + * Remote operation moving a remote file or folder in the ownCloud server to a different folder + * in the same account. + * + * Allows renaming the moving file/folder at the same time. + * + * @author David A. Velasco + */ +public class MoveRemoteFileOperation extends RemoteOperation { + + private static final String TAG = MoveRemoteFileOperation.class.getSimpleName(); + + private static final int RENAME_READ_TIMEOUT = 10000; + private static final int RENAME_CONNECTION_TIMEOUT = 5000; + + private String mSrcRemotePath; + private String mTargetRemotePath; + + private boolean mOverwrite; + + + /** + * Constructor. + * + * TODO Paths should finish in "/" in the case of folders. ? + * + * @param srcRemotePath Remote path of the file/folder to move. + * @param targetRemotePath Remove path desired for the file/folder after moving it. + */ + public MoveRemoteFileOperation( + String srcRemotePath, String targetRemotePath, boolean overwrite + ) { + + mSrcRemotePath = srcRemotePath; + mTargetRemotePath = targetRemotePath; + mOverwrite = overwrite; + } + + + /** + * Performs the rename operation. + * + * @param client Client object to communicate with the remote ownCloud server. + */ + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + + /// check parameters + if (!FileUtils.isValidPath(mTargetRemotePath)) { + return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME); + } + + if (mTargetRemotePath.equals(mSrcRemotePath)) { + // nothing to do! + return new RemoteOperationResult(ResultCode.OK); + } + + if (mTargetRemotePath.startsWith(mSrcRemotePath)) { + return new RemoteOperationResult(ResultCode.INVALID_MOVE_INTO_DESCENDANT); + } + + + /// perform remote operation + //LocalMoveMethod move = null; + MoveMethod move = null; + RemoteOperationResult result = null; + try { + move = new MoveMethod( + client.getWebdavUri() + WebdavUtils.encodePath(mSrcRemotePath), + client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath), + mOverwrite + ); + int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT); + + /// process response + if (status == HttpStatus.SC_MULTI_STATUS) { + result = processPartialError(move); + + } else if (status == HttpStatus.SC_PRECONDITION_FAILED && !mOverwrite) { + + result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE); + client.exhaustResponse(move.getResponseBodyAsStream()); + + + /// for other errors that could be explicitly handled, check first: + /// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4 + + } else { + + result = new RemoteOperationResult( + isSuccess(status), // move.succeeded()? trustful? + status, + move.getResponseHeaders() + ); + client.exhaustResponse(move.getResponseBodyAsStream()); + } + + Log.i(TAG, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + + result.getLogMessage()); + + } catch (Exception e) { + result = new RemoteOperationResult(e); + Log.e(TAG, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + + result.getLogMessage(), e); + + } finally { + if (move != null) + move.releaseConnection(); + } + + return result; + } + + + /** + * Analyzes a multistatus response from the OC server to generate an appropriate result. + * + * In WebDAV, a MOVE request on collections (folders) can be PARTIALLY successful: some + * children are moved, some other aren't. + * + * According to the WebDAV specification, a multistatus response SHOULD NOT include partial + * successes (201, 204) nor for descendants of already failed children (424) in the response + * entity. But SHOULD NOT != MUST NOT, so take carefully. + * + * @param move Move operation just finished with a multistatus response + * @return A result for the {@link MoveRemoteFileOperation} caller + * + * @throws IOException If the response body could not be parsed + * @throws DavException If the status code is other than MultiStatus or if obtaining + * the response XML document fails + */ + private RemoteOperationResult processPartialError(MoveMethod move) + throws IOException, DavException { + // Adding a list of failed descendants to the result could be interesting; or maybe not. + // For the moment, let's take the easy way. + + /// check that some error really occurred + MultiStatusResponse[] responses = move.getResponseBodyAsMultiStatus().getResponses(); + Status[] status = null; + boolean failFound = false; + for (int i = 0; i < responses.length && !failFound; i++ ) { + status = responses[i].getStatus(); + failFound = ( + status != null && + status.length > 0 && + status[0].getStatusCode() > 299 + ); + } + + RemoteOperationResult result; + if (failFound) { + result = new RemoteOperationResult(ResultCode.PARTIAL_MOVE_DONE); + } else { + result = new RemoteOperationResult( + true, + HttpStatus.SC_MULTI_STATUS, + move.getResponseHeaders() + ); + } + + return result; + + } + + + protected boolean isSuccess(int status) { + return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT; + } + +} From d4af8a6a33bd048bb2aba8749228639036613039 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 21 Aug 2014 17:37:16 +0200 Subject: [PATCH 2/9] Added unit tests for MoveRemoteFileOperation (WIP), with new approach dependant on AndroidTest instead of InstrumentationActivityTest --- .../lib/test_project/TestActivity.java | 119 +++++++++---- .../lib/test_project/test/MoveFileTest.java | 167 ++++++++++++++++++ 2 files changed, 254 insertions(+), 32 deletions(-) create mode 100644 test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java diff --git a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java index 66ff274e..905fa511 100644 --- a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java +++ b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java @@ -33,16 +33,24 @@ import java.security.GeneralSecurityException; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; -import com.owncloud.android.lib.common.OwnCloudClientFactory; +import android.app.Activity; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.util.Log; +import android.view.Menu; + 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.resources.files.RemoteFile; import com.owncloud.android.lib.common.network.NetworkUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation; import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation; import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation; import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation; +import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation; import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation; import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation; @@ -50,14 +58,6 @@ import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation; import com.owncloud.android.lib.resources.shares.GetRemoteSharesOperation; import com.owncloud.android.lib.resources.shares.RemoveRemoteShareOperation; import com.owncloud.android.lib.resources.shares.ShareType; -import com.owncloud.android.lib.test_project.R; - -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.app.Activity; -import android.util.Log; -import android.view.Menu; /** * Activity to test OC framework @@ -72,7 +72,6 @@ public class TestActivity extends Activity { private String mServerUri; private String mUser; private String mPass; - private boolean mChunked; private static final int BUFFER_SIZE = 1024; @@ -91,7 +90,6 @@ public class TestActivity extends Activity { mServerUri = getString(R.string.server_base_url); mUser = getString(R.string.username); mPass = getString(R.string.password); - mChunked = getResources().getBoolean(R.bool.chunked); Protocol pr = Protocol.getProtocol("https"); if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { @@ -133,14 +131,32 @@ public class TestActivity extends Activity { /** * Access to the library method to Create a Folder * @param remotePath Full path to the new directory to create in the remote server. - * @param createFullPath 'True' means that all the ancestor folders should be created if don't exist yet. + * @param createFullPath 'True' means that all the ancestor folders should be created if + * don't exist yet. * * @return */ public RemoteOperationResult createFolder(String remotePath, boolean createFullPath) { - CreateRemoteFolderOperation createOperation = new CreateRemoteFolderOperation(remotePath, createFullPath); - RemoteOperationResult result = createOperation.execute(mClient); + return TestActivity.createFolder(remotePath, createFullPath, mClient); + } + + /** + * Access to the library method to Create a Folder + * @param remotePath Full path to the new directory to create in the remote server. + * @param createFullPath 'True' means that all the ancestor folders should be created if + * don't exist yet. + * @param client Client instance configured to access the target OC server. + * + * @return Result of the operation + */ + public static RemoteOperationResult createFolder( + String remotePath, boolean createFullPath, OwnCloudClient client + ) { + + CreateRemoteFolderOperation createOperation = + new CreateRemoteFolderOperation(remotePath, createFullPath); + RemoteOperationResult result = createOperation.execute(client); return result; } @@ -170,13 +186,24 @@ public class TestActivity extends Activity { * @return */ public RemoteOperationResult removeFile(String remotePath) { - RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath); RemoteOperationResult result = removeOperation.execute(mClient); - + return TestActivity.removeFile(remotePath, mClient); + } + + /** + * Access to the library method to Remove a File or Folder + * + * @param remotePath Remote path of the file or folder in the server. + * @return + */ + public static RemoteOperationResult removeFile(String remotePath, OwnCloudClient client) { + RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath); + RemoteOperationResult result = removeOperation.execute(client); return result; } + /** * Access to the library method to Read a Folder (PROPFIND DEPTH 1) * @param remotePath @@ -217,21 +244,39 @@ public class TestActivity extends Activity { * * @return */ - public RemoteOperationResult uploadFile(String storagePath, String remotePath, String mimeType) { - - UploadRemoteFileOperation uploadOperation; - if ( mChunked && (new File(storagePath)).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) { - uploadOperation = new ChunkedUploadRemoteFileOperation(storagePath, remotePath, mimeType); - } else { - uploadOperation = new UploadRemoteFileOperation(storagePath, remotePath, mimeType); - } - - RemoteOperationResult result = uploadOperation.execute(mClient); - - return result; + public RemoteOperationResult uploadFile( + String storagePath, String remotePath, String mimeType + ) { + return TestActivity.uploadFile(storagePath, remotePath, mimeType, mClient); } + /** Access to the library method to Upload a File + * @param storagePath + * @param remotePath + * @param mimeType + * @param client Client instance configured to access the target OC server. + * + * @return + */ + public static RemoteOperationResult uploadFile( + String storagePath, String remotePath, String mimeType, OwnCloudClient client + ) { + UploadRemoteFileOperation uploadOperation; + if ((new File(storagePath)).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) { + uploadOperation = new ChunkedUploadRemoteFileOperation( + storagePath, remotePath, mimeType + ); + } else { + uploadOperation = new UploadRemoteFileOperation( + storagePath, remotePath, mimeType + ); + } + + RemoteOperationResult result = uploadOperation.execute(client); + return result; + } + /** Access to the library method to Get Shares * * @return @@ -295,11 +340,22 @@ public class TestActivity extends Activity { * @return File instance of the extracted file. */ public File extractAsset(String fileName) throws IOException { - File extractedFile = new File(getCacheDir() + File.separator + fileName); + return TestActivity.extractAsset(fileName, this); + } + + /** + * Extracts file from AssetManager to cache folder. + * + * @param fileName Name of the asset file to extract. + * @param context Android context to access assets and file system. + * @return File instance of the extracted file. + */ + public static File extractAsset(String fileName, Context context) throws IOException { + File extractedFile = new File(context.getCacheDir() + File.separator + fileName); if (!extractedFile.exists()) { InputStream in = null; FileOutputStream out = null; - in = getAssets().open(fileName); + in = context.getAssets().open(fileName); out = new FileOutputStream(extractedFile); byte[] buffer = new byte[BUFFER_SIZE]; int readCount; @@ -312,7 +368,6 @@ public class TestActivity extends Activity { } return extractedFile; } - } diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java new file mode 100644 index 00000000..985e20bb --- /dev/null +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -0,0 +1,167 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 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 java.util.Vector; + +import junit.framework.AssertionFailedError; + +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; + +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.files.MoveRemoteFileOperation; +import com.owncloud.android.lib.test_project.R; +import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; +import com.owncloud.android.lib.test_project.TestActivity; + +import android.net.Uri; +import android.test.AndroidTestCase; +import android.util.Log; + +/** + * Class to test MoveRemoteFileOperation + * + * @author David A. Velasco + */ + +public class MoveFileTest extends AndroidTestCase { + + private static final String LOG_TAG = MoveFileTest.class.getCanonicalName(); + + /* Paths for tests on folders */ + private static final String SRC_FOLDER_NAME = "folderToMove"; + private static final String SRC_FOLDER_PARENT_PATH = "/src/"; + private static final String SRC_FOLDER_PATH = SRC_FOLDER_PARENT_PATH + SRC_FOLDER_NAME; + private static final String TARGET_FOLDER_PARENT_PATH = "/target/"; + private static final String TARGET_FOLDER_PATH = TARGET_FOLDER_PARENT_PATH + SRC_FOLDER_NAME; + + private static boolean mGlobalSetupDone = false; + + String mServerUri, mUser, mPass; + OwnCloudClient mClient = null; + + private Vector mToCleanUpInServer = new Vector(2); + + public MoveFileTest() { + super(); + + mGlobalSetupDone = false; + + 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"); + } + } + + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + if (!mGlobalSetupDone) { + + mServerUri = getContext().getString(R.string.server_base_url); + mUser = getContext().getString(R.string.username); + mPass = getContext().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, "Starting global set up"); + RemoteOperationResult result = + TestActivity.createFolder(SRC_FOLDER_PATH, true, mClient); + if (!result.isSuccess()) { + Utils.logAndThrow(LOG_TAG, result); + } + result = TestActivity.createFolder(TARGET_FOLDER_PARENT_PATH, true, mClient); + if (!result.isSuccess()) { + Utils.logAndThrow(LOG_TAG, result); + } + + Log.v(LOG_TAG, "Global set up done"); + + mGlobalSetupDone = true; + } + } + + /** + * Test move folder + */ + public void testMoveFolder() { + + mToCleanUpInServer.add(SRC_FOLDER_PARENT_PATH); + mToCleanUpInServer.add(TARGET_FOLDER_PARENT_PATH); + + MoveRemoteFileOperation renameOperation = new MoveRemoteFileOperation( + SRC_FOLDER_PATH, + TARGET_FOLDER_PATH, + false + ); + + RemoteOperationResult result = renameOperation.execute(mClient); + assertTrue(result.isSuccess()); + } + + @Override + protected void tearDown() throws Exception { + for (String path : mToCleanUpInServer) { + RemoteOperationResult removeResult = + TestActivity.removeFile(path, mClient); + if (!removeResult.isSuccess()) { + Utils.logAndThrow(LOG_TAG, removeResult); + } + } + mToCleanUpInServer.clear(); + super.tearDown(); + } + +} From dc2639264711ad43c240ca088a12185b722493aa Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 21 Aug 2014 18:04:14 +0200 Subject: [PATCH 3/9] Fixed MoveFileTest.java --- test_client/res/values/setup.xml | 4 +- .../lib/test_project/test/MoveFileTest.java | 38 +++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/test_client/res/values/setup.xml b/test_client/res/values/setup.xml index aeb08218..ac5cedde 100644 --- a/test_client/res/values/setup.xml +++ b/test_client/res/values/setup.xml @@ -24,9 +24,7 @@ --> - - /remote.php/webdav + - true diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java index 985e20bb..26912616 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -95,27 +95,27 @@ public class MoveFileTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); + mServerUri = getContext().getString(R.string.server_base_url); + mUser = getContext().getString(R.string.username); + mPass = getContext().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 + ) + ); + if (!mGlobalSetupDone) { - mServerUri = getContext().getString(R.string.server_base_url); - mUser = getContext().getString(R.string.username); - mPass = getContext().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, "Starting global set up"); RemoteOperationResult result = TestActivity.createFolder(SRC_FOLDER_PATH, true, mClient); From 9d286636d5674f348a456cb697962f1c78fa306a Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Fri, 22 Aug 2014 15:29:20 +0200 Subject: [PATCH 4/9] Added success cases to MoveFileTest --- .../lib/test_project/test/MoveFileTest.java | 338 ++++++++++++++---- 1 file changed, 270 insertions(+), 68 deletions(-) diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java index 26912616..5008fe98 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -24,8 +24,8 @@ package com.owncloud.android.lib.test_project.test; +import java.io.File; import java.security.GeneralSecurityException; -import java.util.Vector; import junit.framework.AssertionFailedError; @@ -42,38 +42,130 @@ import com.owncloud.android.lib.test_project.R; import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; import com.owncloud.android.lib.test_project.TestActivity; +import android.content.Context; import android.net.Uri; -import android.test.AndroidTestCase; +import android.test.ActivityInstrumentationTestCase2; +//import android.test.AndroidTestCase; import android.util.Log; /** * Class to test MoveRemoteFileOperation + * + * 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. + * + * * @author David A. Velasco */ -public class MoveFileTest extends AndroidTestCase { - +//public class MoveFileTest extends AndroidTestCase { +public class MoveFileTest extends ActivityInstrumentationTestCase2 { + private static final String LOG_TAG = MoveFileTest.class.getCanonicalName(); - /* Paths for tests on folders */ - private static final String SRC_FOLDER_NAME = "folderToMove"; - private static final String SRC_FOLDER_PARENT_PATH = "/src/"; - private static final String SRC_FOLDER_PATH = SRC_FOLDER_PARENT_PATH + SRC_FOLDER_NAME; - private static final String TARGET_FOLDER_PARENT_PATH = "/target/"; - private static final String TARGET_FOLDER_PATH = TARGET_FOLDER_PARENT_PATH + SRC_FOLDER_NAME; - private static boolean mGlobalSetupDone = false; + /// Paths to files and folders in fixture + + private static final String SRC_BASE_FOLDER = "/src/"; + private static final String TARGET_BASE_FOLDER = "/target/"; + private static final String FILE1 = "file1.txt"; + private static final String FILE2 = "file2.txt"; + private static final String FILE3 = "file3.txt"; + private static final String FILE4 = "file4.txt"; + private static final String EMPTY = "empty/"; + private static final String FOLDER1 = "folder1/"; + private static final String FOLDER2 = "folder2/"; + private static final String FOLDER3 = "folder3/"; + + private static final String SRC_PATH_TO_FILE_1 = SRC_BASE_FOLDER + FILE1; + private static final String TARGET_PATH_TO_FILE_1 = TARGET_BASE_FOLDER + FILE1; + + private static final String SRC_PATH_TO_FILE_2 = SRC_BASE_FOLDER + FILE2; + private static final String TARGET_PATH_TO_FILE_2_RENAMED = + TARGET_BASE_FOLDER + "renamed_" + FILE2; + + private static final String SRC_PATH_TO_FILE_3 = SRC_BASE_FOLDER + FILE3; + private static final String SRC_PATH_TO_FILE_3_RENAMED = SRC_BASE_FOLDER + "renamed_" + FILE3; + + private static final String SRC_PATH_TO_FILE_4 = SRC_BASE_FOLDER + FILE4; + + private static final String SRC_PATH_TO_EMPTY_FOLDER = SRC_BASE_FOLDER + EMPTY; + private static final String TARGET_PATH_TO_EMPTY_FOLDER = TARGET_BASE_FOLDER + EMPTY; + + private static final String SRC_PATH_TO_FULL_FOLDER_1 = SRC_BASE_FOLDER + FOLDER1; + private static final String TARGET_PATH_TO_FULL_FOLDER_1 = TARGET_BASE_FOLDER + FOLDER1; + + private static final String SRC_PATH_TO_FULL_FOLDER_2 = SRC_BASE_FOLDER + FOLDER2; + + private static final String TARGET_PATH_TO_FULL_FOLDER_2_RENAMED = + TARGET_BASE_FOLDER + "renamed_" + FOLDER2; + + private static final String SRC_PATH_TO_FULL_FOLDER_3 = SRC_BASE_FOLDER + FOLDER3; + + private static final String SRC_PATH_TO_FULL_FOLDER_3_RENAMED = + SRC_BASE_FOLDER + "renamed_" + FOLDER3; + + + private static final String[] FOLDERS_IN_FIXTURE = { + SRC_PATH_TO_EMPTY_FOLDER, + + SRC_PATH_TO_FULL_FOLDER_1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER2, + + SRC_PATH_TO_FULL_FOLDER_2, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER2, + + SRC_PATH_TO_FULL_FOLDER_3, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2, + + TARGET_BASE_FOLDER + }; + + private static final String[] FILES_IN_FIXTURE = { + SRC_PATH_TO_FILE_1, + SRC_PATH_TO_FILE_2, + SRC_PATH_TO_FILE_3, + SRC_PATH_TO_FILE_4, + + SRC_PATH_TO_FULL_FOLDER_1 + FILE1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FILE2, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER2 + FILE2, + + SRC_PATH_TO_FULL_FOLDER_2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FILE2, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER2 + FILE2, + + SRC_PATH_TO_FULL_FOLDER_3 + FILE1, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE2, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2 + FILE2, + }; + String mServerUri, mUser, mPass; OwnCloudClient mClient = null; - private Vector mToCleanUpInServer = new Vector(2); - public MoveFileTest() { - super(); - - mGlobalSetupDone = false; + super(TestActivity.class); Protocol pr = Protocol.getProtocol("https"); if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { @@ -90,14 +182,169 @@ public class MoveFileTest extends AndroidTestCase { } } + + + protected Context getContext() { + return getActivity(); + } @Override - protected void setUp() throws Exception { + 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()); - mServerUri = getContext().getString(R.string.server_base_url); - mUser = getContext().getString(R.string.username); - mPass = getContext().getString(R.string.password); + Log.v(LOG_TAG, "Setting up the remote fixture..."); + + RemoteOperationResult result = null; + for (String folderPath : FOLDERS_IN_FIXTURE) { + result = TestActivity.createFolder(folderPath, true, mClient); + if (!result.isSuccess()) { + Utils.logAndThrow(LOG_TAG, result); + } + } + + File txtFile = TestActivity.extractAsset( + TestActivity.ASSETS__TEXT_FILE_NAME, getContext() + ); + for (String filePath : FILES_IN_FIXTURE) { + result = TestActivity.uploadFile( + txtFile.getAbsolutePath(), filePath, "txt/plain", mClient + ); + if (!result.isSuccess()) { + Utils.logAndThrow(LOG_TAG, result); + } + } + + Log.v(LOG_TAG, "Remote fixture created."); + + } + + + /** + * Test move folder + */ + public void testMoveRemoteFileOperation() { + Log.v(LOG_TAG, "testMoveFolder in"); + + /// successful cases + + // move file + MoveRemoteFileOperation moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_1, + TARGET_PATH_TO_FILE_1, + false + ); + RemoteOperationResult result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move & rename file, different location + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_2, + TARGET_PATH_TO_FILE_2_RENAMED, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move & rename file, same location (rename file) + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_3, + SRC_PATH_TO_FILE_3_RENAMED, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move empty folder + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_EMPTY_FOLDER, + TARGET_PATH_TO_EMPTY_FOLDER, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move non-empty folder + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_1, + TARGET_PATH_TO_FULL_FOLDER_1, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move & rename folder, different location + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_2, + TARGET_PATH_TO_FULL_FOLDER_2_RENAMED, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move & rename folder, same location (rename folder) + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_3, + SRC_PATH_TO_FULL_FOLDER_3_RENAMED, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move for nothing (success, but no interaction with network) + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_4, + SRC_PATH_TO_FILE_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + + /// TODO failed cases + + // file to move does not exist + + // folder to move into does no exist + + // target location (renaming) has invalid characters + + // name collision + + } + + @Override + protected void tearDown() throws Exception { + Log.v(LOG_TAG, "Deleting remote fixture..."); + + String[] mPathsToCleanUp = { + SRC_BASE_FOLDER, + TARGET_BASE_FOLDER + }; + + for (String path : mPathsToCleanUp) { + RemoteOperationResult removeResult = + TestActivity.removeFile(path, mClient); + if (!removeResult.isSuccess()) { + Utils.logAndThrow(LOG_TAG, removeResult); + } + } + + 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), @@ -113,55 +360,10 @@ public class MoveFileTest extends AndroidTestCase { mPass ) ); - - if (!mGlobalSetupDone) { - - Log.v(LOG_TAG, "Starting global set up"); - RemoteOperationResult result = - TestActivity.createFolder(SRC_FOLDER_PATH, true, mClient); - if (!result.isSuccess()) { - Utils.logAndThrow(LOG_TAG, result); - } - result = TestActivity.createFolder(TARGET_FOLDER_PARENT_PATH, true, mClient); - if (!result.isSuccess()) { - Utils.logAndThrow(LOG_TAG, result); - } - - Log.v(LOG_TAG, "Global set up done"); - - mGlobalSetupDone = true; - } + + Log.v(LOG_TAG, "Client instance set up."); + } - /** - * Test move folder - */ - public void testMoveFolder() { - - mToCleanUpInServer.add(SRC_FOLDER_PARENT_PATH); - mToCleanUpInServer.add(TARGET_FOLDER_PARENT_PATH); - - MoveRemoteFileOperation renameOperation = new MoveRemoteFileOperation( - SRC_FOLDER_PATH, - TARGET_FOLDER_PATH, - false - ); - - RemoteOperationResult result = renameOperation.execute(mClient); - assertTrue(result.isSuccess()); - } - - @Override - protected void tearDown() throws Exception { - for (String path : mToCleanUpInServer) { - RemoteOperationResult removeResult = - TestActivity.removeFile(path, mClient); - if (!removeResult.isSuccess()) { - Utils.logAndThrow(LOG_TAG, removeResult); - } - } - mToCleanUpInServer.clear(); - super.tearDown(); - } } From e5010c1a6b6e7f23824e0f07e93030cabc05b593 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 27 Aug 2014 12:18:56 +0200 Subject: [PATCH 5/9] Fixed library demo client --- .../com/owncloud/android/lib/sampleclient/MainActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java b/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java index 8e24c15e..06210073 100644 --- a/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java +++ b/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudClient; @@ -79,7 +78,7 @@ public class MainActivity extends Activity implements OnRemoteOperationListener, mHandler = new Handler(); - Uri serverUri = Uri.parse(getString(R.string.server_base_url) + AccountUtils.WEBDAV_PATH_4_0); + Uri serverUri = Uri.parse(getString(R.string.server_base_url)); mClient = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true); mClient.setCredentials( OwnCloudCredentialsFactory.newBasicCredentials( From 3a5df9dcdf3a5d3a4f4c5dbe83783feec01cabf1 Mon Sep 17 00:00:00 2001 From: jabarros Date: Wed, 27 Aug 2014 17:17:04 +0200 Subject: [PATCH 6/9] Add failed test cases into moving file test --- .../lib/test_project/test/MoveFileTest.java | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java index 5008fe98..175fc230 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -37,6 +37,7 @@ 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.common.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation; import com.owncloud.android.lib.test_project.R; import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; @@ -75,15 +76,19 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 /// Paths to files and folders in fixture private static final String SRC_BASE_FOLDER = "/src/"; + private static final String SRC_BASE_FOLDER_NON_CREATED = "/src_non_created/"; private static final String TARGET_BASE_FOLDER = "/target/"; private static final String FILE1 = "file1.txt"; private static final String FILE2 = "file2.txt"; private static final String FILE3 = "file3.txt"; private static final String FILE4 = "file4.txt"; + private static final String FILE5 = "file5.txt"; private static final String EMPTY = "empty/"; private static final String FOLDER1 = "folder1/"; private static final String FOLDER2 = "folder2/"; private static final String FOLDER3 = "folder3/"; + private static final String FOLDER4 = "folder4/"; + private static final String FOLDER5 = "folder5/"; private static final String SRC_PATH_TO_FILE_1 = SRC_BASE_FOLDER + FILE1; private static final String TARGET_PATH_TO_FILE_1 = TARGET_BASE_FOLDER + FILE1; @@ -97,6 +102,8 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 private static final String SRC_PATH_TO_FILE_4 = SRC_BASE_FOLDER + FILE4; + private static final String SRC_PATH_TO_FILE_NON_EXISTS = SRC_BASE_FOLDER + FILE5; + private static final String SRC_PATH_TO_EMPTY_FOLDER = SRC_BASE_FOLDER + EMPTY; private static final String TARGET_PATH_TO_EMPTY_FOLDER = TARGET_BASE_FOLDER + EMPTY; @@ -109,10 +116,18 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 TARGET_BASE_FOLDER + "renamed_" + FOLDER2; private static final String SRC_PATH_TO_FULL_FOLDER_3 = SRC_BASE_FOLDER + FOLDER3; + private static final String SRC_PATH_TO_FULL_FOLDER_4 = SRC_BASE_FOLDER + FOLDER4; + private static final String SRC_PATH_TO_FULL_FOLDER_5 = SRC_BASE_FOLDER + FOLDER5; private static final String SRC_PATH_TO_FULL_FOLDER_3_RENAMED = SRC_BASE_FOLDER + "renamed_" + FOLDER3; + private static final String SRC_PATH_TO_FULL_FOLDER_4_RENAMED_INVALID_CHARS = + SRC_BASE_FOLDER + "renamed:??_" + FOLDER4; + + private static final String SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4 = SRC_BASE_FOLDER + + FOLDER4 + FOLDER5; + private static final String[] FOLDERS_IN_FIXTURE = { SRC_PATH_TO_EMPTY_FOLDER, @@ -135,7 +150,10 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER1, SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2, - TARGET_BASE_FOLDER + SRC_PATH_TO_FULL_FOLDER_5, + SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + + TARGET_BASE_FOLDER, }; private static final String[] FILES_IN_FIXTURE = { @@ -303,16 +321,62 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 result = moveOperation.execute(mClient); assertTrue(result.isSuccess()); - - /// TODO failed cases + // move to the same name folder but overwrite it + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_5, + SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + true + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + + // Failed cases // file to move does not exist - + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_NON_EXISTS, + SRC_PATH_TO_FULL_FOLDER_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + // folder to move into does no exist - + moveOperation = new MoveRemoteFileOperation( + SRC_BASE_FOLDER_NON_CREATED, + SRC_PATH_TO_FILE_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + // target location (renaming) has invalid characters - + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_4, + SRC_PATH_TO_FULL_FOLDER_4_RENAMED_INVALID_CHARS, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME); + // name collision + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_5, + SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + + // move a folder into a descendant + moveOperation = new MoveRemoteFileOperation( + SRC_BASE_FOLDER, + SRC_PATH_TO_FULL_FOLDER_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_MOVE_INTO_DESCENDANT); } From 80cbe24524dc7cd9bb96d7d6d7eaebb18d0e01c2 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Mon, 1 Sep 2014 14:53:13 +0200 Subject: [PATCH 7/9] Greater timeouts for moving and renaming folders --- .../lib/resources/files/MoveRemoteFileOperation.java | 6 +++--- .../lib/resources/files/RenameRemoteFileOperation.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java index 258087c3..844c727e 100644 --- a/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java @@ -53,8 +53,8 @@ public class MoveRemoteFileOperation extends RemoteOperation { private static final String TAG = MoveRemoteFileOperation.class.getSimpleName(); - private static final int RENAME_READ_TIMEOUT = 10000; - private static final int RENAME_CONNECTION_TIMEOUT = 5000; + private static final int MOVE_READ_TIMEOUT = 600000; + private static final int MOVE_CONNECTION_TIMEOUT = 5000; private String mSrcRemotePath; private String mTargetRemotePath; @@ -113,7 +113,7 @@ public class MoveRemoteFileOperation extends RemoteOperation { client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath), mOverwrite ); - int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT); + int status = client.executeMethod(move, MOVE_READ_TIMEOUT, MOVE_CONNECTION_TIMEOUT); /// process response if (status == HttpStatus.SC_MULTI_STATUS) { diff --git a/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java index a42543b0..be7b90e3 100644 --- a/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java @@ -47,7 +47,7 @@ public class RenameRemoteFileOperation extends RemoteOperation { private static final String TAG = RenameRemoteFileOperation.class.getSimpleName(); - private static final int RENAME_READ_TIMEOUT = 10000; + private static final int RENAME_READ_TIMEOUT = 600000; private static final int RENAME_CONNECTION_TIMEOUT = 5000; private String mOldName; From df84917376e9d804897822cb138aaf0ba879d854 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 3 Sep 2014 11:42:23 +0200 Subject: [PATCH 8/9] Redirect 'destination' header in custom redirections --- .../android/lib/common/OwnCloudClient.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index 7b48bbc0..1e4f48f1 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -225,6 +225,26 @@ public class OwnCloudClient extends HttpClient { Log.d(TAG + " #" + mInstanceNumber, "Location to redirect: " + location.getValue()); method.setURI(new URI(location.getValue(), true)); + Header destination = method.getRequestHeader("Destination"); + if (destination == null) { + destination = method.getRequestHeader("destination"); + } + if (destination != null) { + String locationStr = location.getValue(); + int suffixIndex = locationStr.lastIndexOf( + (mCredentials instanceof OwnCloudBearerCredentials) ? + AccountUtils.ODAV_PATH : + AccountUtils.WEBDAV_PATH_4_0 + ); + String redirectionBase = locationStr.substring(0, suffixIndex); + + String destinationStr = destination.getValue(); + String destinationPath = destinationStr.substring(mBaseUri.toString().length()); + String redirectedDestination = redirectionBase + destinationPath; + + destination.setValue(redirectedDestination); + method.setRequestHeader(destination); + } status = super.executeMethod(method); redirectionsCount++; From 5d146c923620523a871a0fe50bdcbc3b7559df8c Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 4 Sep 2014 13:53:51 +0200 Subject: [PATCH 9/9] Some improvementes in tests on failed move operations --- .../lib/test_project/test/MoveFileTest.java | 78 ++++++++++++------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java index 175fc230..e5ec8a37 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -29,6 +29,7 @@ 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; @@ -76,19 +77,21 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 /// Paths to files and folders in fixture private static final String SRC_BASE_FOLDER = "/src/"; - private static final String SRC_BASE_FOLDER_NON_CREATED = "/src_non_created/"; private static final String TARGET_BASE_FOLDER = "/target/"; + private static final String NO_FILE = "nofile.txt"; private static final String FILE1 = "file1.txt"; private static final String FILE2 = "file2.txt"; private static final String FILE3 = "file3.txt"; private static final String FILE4 = "file4.txt"; private static final String FILE5 = "file5.txt"; + private static final String FILE6 = "file6.txt"; + private static final String FILE7 = "file7.txt"; private static final String EMPTY = "empty/"; + private static final String NO_FOLDER = "nofolder/"; private static final String FOLDER1 = "folder1/"; private static final String FOLDER2 = "folder2/"; private static final String FOLDER3 = "folder3/"; private static final String FOLDER4 = "folder4/"; - private static final String FOLDER5 = "folder5/"; private static final String SRC_PATH_TO_FILE_1 = SRC_BASE_FOLDER + FILE1; private static final String TARGET_PATH_TO_FILE_1 = TARGET_BASE_FOLDER + FILE1; @@ -102,7 +105,13 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 private static final String SRC_PATH_TO_FILE_4 = SRC_BASE_FOLDER + FILE4; - private static final String SRC_PATH_TO_FILE_NON_EXISTS = SRC_BASE_FOLDER + FILE5; + private static final String SRC_PATH_TO_FILE_5 = SRC_BASE_FOLDER + FILE5; + + private static final String SRC_PATH_TO_FILE_6 = SRC_BASE_FOLDER + FILE6; + + private static final String SRC_PATH_TO_FILE_7 = SRC_BASE_FOLDER + FILE7; + + private static final String SRC_PATH_TO_NON_EXISTENT_FILE = SRC_BASE_FOLDER + NO_FILE; private static final String SRC_PATH_TO_EMPTY_FOLDER = SRC_BASE_FOLDER + EMPTY; private static final String TARGET_PATH_TO_EMPTY_FOLDER = TARGET_BASE_FOLDER + EMPTY; @@ -117,17 +126,22 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 private static final String SRC_PATH_TO_FULL_FOLDER_3 = SRC_BASE_FOLDER + FOLDER3; private static final String SRC_PATH_TO_FULL_FOLDER_4 = SRC_BASE_FOLDER + FOLDER4; - private static final String SRC_PATH_TO_FULL_FOLDER_5 = SRC_BASE_FOLDER + FOLDER5; private static final String SRC_PATH_TO_FULL_FOLDER_3_RENAMED = SRC_BASE_FOLDER + "renamed_" + FOLDER3; - private static final String SRC_PATH_TO_FULL_FOLDER_4_RENAMED_INVALID_CHARS = - SRC_BASE_FOLDER + "renamed:??_" + FOLDER4; + private static final String TARGET_PATH_RENAMED_WITH_INVALID_CHARS = + SRC_BASE_FOLDER + "renamed:??_" + FILE6; - private static final String SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4 = SRC_BASE_FOLDER - + FOLDER4 + FOLDER5; + private static final String TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4 = TARGET_BASE_FOLDER + + FOLDER4; + + private static final String TARGET_PATH_TO_NON_EXISTENT_FILE = TARGET_BASE_FOLDER + NO_FILE; + private static final String TARGET_PATH_TO_FILE_5_INTO_NON_EXISTENT_FOLDER = + TARGET_BASE_FOLDER + NO_FOLDER + FILE5; + + private static final String TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7 = TARGET_BASE_FOLDER + FILE7; private static final String[] FOLDERS_IN_FIXTURE = { SRC_PATH_TO_EMPTY_FOLDER, @@ -150,10 +164,14 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER1, SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2, - SRC_PATH_TO_FULL_FOLDER_5, - SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + SRC_PATH_TO_FULL_FOLDER_4, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER2, TARGET_BASE_FOLDER, + TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4 }; private static final String[] FILES_IN_FIXTURE = { @@ -161,6 +179,7 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 SRC_PATH_TO_FILE_2, SRC_PATH_TO_FILE_3, SRC_PATH_TO_FILE_4, + SRC_PATH_TO_FILE_5, SRC_PATH_TO_FULL_FOLDER_1 + FILE1, SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FILE1, @@ -176,6 +195,13 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE1, SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE2, SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2 + FILE2, + + SRC_PATH_TO_FULL_FOLDER_4 + FILE1, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FILE2, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER2 + FILE2, + + TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7 }; @@ -321,40 +347,40 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 result = moveOperation.execute(mClient); assertTrue(result.isSuccess()); - // move to the same name folder but overwrite it + // move overwriting moveOperation = new MoveRemoteFileOperation( - SRC_PATH_TO_FULL_FOLDER_5, - SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + SRC_PATH_TO_FULL_FOLDER_4, + TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4, true ); result = moveOperation.execute(mClient); assertTrue(result.isSuccess()); - // Failed cases + /// Failed cases // file to move does not exist moveOperation = new MoveRemoteFileOperation( - SRC_PATH_TO_FILE_NON_EXISTS, - SRC_PATH_TO_FULL_FOLDER_4, + SRC_PATH_TO_NON_EXISTENT_FILE, + TARGET_PATH_TO_NON_EXISTENT_FILE, false ); result = moveOperation.execute(mClient); - assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + assertTrue(result.getCode() == ResultCode.FILE_NOT_FOUND); // folder to move into does no exist moveOperation = new MoveRemoteFileOperation( - SRC_BASE_FOLDER_NON_CREATED, - SRC_PATH_TO_FILE_4, + SRC_PATH_TO_FILE_5, + TARGET_PATH_TO_FILE_5_INTO_NON_EXISTENT_FOLDER, false ); result = moveOperation.execute(mClient); - assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + assertTrue(result.getHttpCode() == HttpStatus.SC_CONFLICT); // target location (renaming) has invalid characters moveOperation = new MoveRemoteFileOperation( - SRC_PATH_TO_FULL_FOLDER_4, - SRC_PATH_TO_FULL_FOLDER_4_RENAMED_INVALID_CHARS, + SRC_PATH_TO_FILE_6, + TARGET_PATH_RENAMED_WITH_INVALID_CHARS, false ); result = moveOperation.execute(mClient); @@ -362,8 +388,8 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 // name collision moveOperation = new MoveRemoteFileOperation( - SRC_PATH_TO_FULL_FOLDER_5, - SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + SRC_PATH_TO_FILE_7, + TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7, false ); result = moveOperation.execute(mClient); @@ -372,7 +398,7 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 // move a folder into a descendant moveOperation = new MoveRemoteFileOperation( SRC_BASE_FOLDER, - SRC_PATH_TO_FULL_FOLDER_4, + SRC_PATH_TO_EMPTY_FOLDER, false ); result = moveOperation.execute(mClient); @@ -392,7 +418,7 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 for (String path : mPathsToCleanUp) { RemoteOperationResult removeResult = TestActivity.removeFile(path, mClient); - if (!removeResult.isSuccess()) { + if (!removeResult.isSuccess() && removeResult.getCode() != ResultCode.TIMEOUT ) { Utils.logAndThrow(LOG_TAG, removeResult); } }