From 6fc9df19a07d7d299b4dad3e6d76df516fbbaaba Mon Sep 17 00:00:00 2001
From: Artur Neumann <info@individual-it.net>
Date: Thu, 6 Sep 2018 22:37:50 +0545
Subject: [PATCH 1/5] tests for async move

---
 tests/TestHelpers/HttpRequestHelper.php       |   9 +-
 tests/TestHelpers/WebDavHelper.php            |  10 +-
 .../apiCapabilities/capabilities.feature      |  18 ++
 .../features/apiMain/checksums.feature        |  48 +++
 .../uploadFileAsyncUsingNewChunking.feature   | 165 +++++++++++
 .../apiWebdavProperties/moveFileAsync.feature | 269 +++++++++++++++++
 .../features/bootstrap/BasicStructure.php     |  25 +-
 .../acceptance/features/bootstrap/WebDav.php  | 277 ++++++++++++++++--
 8 files changed, 788 insertions(+), 33 deletions(-)
 create mode 100644 tests/acceptance/features/apiWebdavOperations/uploadFileAsyncUsingNewChunking.feature
 create mode 100644 tests/acceptance/features/apiWebdavProperties/moveFileAsync.feature

diff --git a/tests/TestHelpers/HttpRequestHelper.php b/tests/TestHelpers/HttpRequestHelper.php
index d6dc86c29bb1..392f728828df 100644
--- a/tests/TestHelpers/HttpRequestHelper.php
+++ b/tests/TestHelpers/HttpRequestHelper.php
@@ -42,7 +42,9 @@ class HttpRequestHelper {
 	 * @param mixed $body
 	 * @param array $config
 	 * @param CookieJar $cookies
-	 * @param boolean $stream
+	 * @param bool $stream Set to true to stream a response rather
+	 *                     than download it all up-front.
+	 * @param int $timeout
 	 *
 	 * @throws BadResponseException
 	 * @return ResponseInterface
@@ -56,7 +58,8 @@ public static function sendRequest(
 		$body = null,
 		$config = null,
 		$cookies = null,
-		$stream = false
+		$stream = false,
+		$timeout = 0
 	) {
 		$client = new Client();
 		$options = [];
@@ -74,7 +77,7 @@ public static function sendRequest(
 		}
 		$options['stream'] = $stream;
 		$options['verify'] = false;
-		
+		$options['timeout'] = $timeout;
 		$request = $client->createRequest($method, $url, $options);
 		if ($headers !== null) {
 			foreach ($headers as $key => $value) {
diff --git a/tests/TestHelpers/WebDavHelper.php b/tests/TestHelpers/WebDavHelper.php
index 1fdfef1a1397..92bfbdbbf978 100644
--- a/tests/TestHelpers/WebDavHelper.php
+++ b/tests/TestHelpers/WebDavHelper.php
@@ -87,6 +87,9 @@ public static function getFileIdForPath(
 	 * @param string $type of request
 	 * @param string $sourceIpAddress to initiate the request from
 	 * @param string $authType basic|bearer
+	 * @param bool $stream Set to true to stream a response rather
+	 *                     than download it all up-front.
+	 * @param int $timeout
 	 *
 	 * @return ResponseInterface
 	 */
@@ -102,7 +105,9 @@ public static function makeDavRequest(
 		$davPathVersionToUse = 1,
 		$type = "files",
 		$sourceIpAddress = null,
-		$authType = "basic"
+		$authType = "basic",
+		$stream = false,
+		$timeout = 0
 	) {
 		$baseUrl = self::sanitizeUrl($baseUrl, true);
 		$davPath = self::getDavPath($user, $davPathVersionToUse, $type);
@@ -138,7 +143,8 @@ public static function makeDavRequest(
 		}
 
 		return HttpRequestHelper::sendRequest(
-			$fullUrl, $method, $user, $password, $headers, $body, $config
+			$fullUrl, $method, $user, $password, $headers, $body, $config, null,
+			$stream, $timeout
 		);
 	}
 
diff --git a/tests/acceptance/features/apiCapabilities/capabilities.feature b/tests/acceptance/features/apiCapabilities/capabilities.feature
index d3445ef23a49..e908a075a9a7 100644
--- a/tests/acceptance/features/apiCapabilities/capabilities.feature
+++ b/tests/acceptance/features/apiCapabilities/capabilities.feature
@@ -69,6 +69,24 @@ Feature: capabilities
     Then the capabilities should contain
       | files         | versioning                            | 1                 |
 
+	#feature added in #32414 will be released in 10.0.10
+  @skipOnOcV10.0.9
+  Scenario: getting async capabilites when async operations are enabled
+    Given the administrator has enabled async operations
+    When the user retrieves the capabilities using the capabilities API
+    Then the capabilities should contain
+      | capability | path_to_element | value |
+      | async      |                 | 1.0   |
+
+	#feature added in #32414 will be released in 10.0.10
+  @skipOnOcV10.0.9
+  Scenario: getting async capabilites when async operations are disabled
+    Given the administrator has disabled async operations
+    When the user retrieves the capabilities using the capabilities API
+    Then the capabilities should contain
+      | capability | path_to_element | value |
+      | async      |                 | EMPTY |
+
   Scenario: Changing public upload
     Given parameter "shareapi_allow_public_upload" of app "core" has been set to "no"
     When the administrator retrieves the capabilities using the capabilities API
diff --git a/tests/acceptance/features/apiMain/checksums.feature b/tests/acceptance/features/apiMain/checksums.feature
index 30e41036f37b..3333fa0ca74a 100644
--- a/tests/acceptance/features/apiMain/checksums.feature
+++ b/tests/acceptance/features/apiMain/checksums.feature
@@ -145,6 +145,54 @@ Feature: checksums
     And user "user0" should not see the following elements
       | /myChunkedFile.txt |
 
+  Scenario: Upload new dav chunked file using async MOVE where checksum matches
+    Given using new DAV path
+    And the administrator has enabled async operations
+    When user "user0" creates a new chunking upload with id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "2" with "BBBBB" to id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "3" with "CCCCC" to id "chunking-42" using the WebDAV API
+    And user "user0" moves new chunk file with id "chunking-42" asynchronously to "/myChunkedFile.txt" with checksum "SHA1:5d84d61b03fdacf813640f5242d309721e0629b1" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/myChunkedFile.txt" for user "user0" should be "BBBBBCCCCC"
+
+  Scenario: Upload new dav chunked file using async MOVE where checksum does not matches
+    Given using new DAV path
+    And the administrator has enabled async operations
+    When user "user0" creates a new chunking upload with id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "2" with "BBBBB" to id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "3" with "CCCCC" to id "chunking-42" using the WebDAV API
+    And user "user0" moves new chunk file with id "chunking-42" asynchronously to "/myChunkedFile.txt" with checksum "SHA1:f005ba11" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status       | /^error$/ |
+      | errorCode    | /^400$/   |
+      | errorMessage | /^The computed checksum does not match the one received from the client.$/ |
+    And user "user0" should not see the following elements
+      | /myChunkedFile.txt |
+
+  Scenario: Upload new dav chunked file using async MOVE where checksum does not matches - retry with correct checksum
+    Given using new DAV path
+    And the administrator has enabled async operations
+    When user "user0" creates a new chunking upload with id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "2" with "BBBBB" to id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "3" with "CCCCC" to id "chunking-42" using the WebDAV API
+    And user "user0" moves new chunk file with id "chunking-42" asynchronously to "/myChunkedFile.txt" with checksum "SHA1:f005ba11" using the WebDAV API
+    And user "user0" moves new chunk file with id "chunking-42" asynchronously to "/myChunkedFile.txt" with checksum "SHA1:5d84d61b03fdacf813640f5242d309721e0629b1" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/myChunkedFile.txt" for user "user0" should be "BBBBBCCCCC"
+
   @skipOnStorage:ceph @files_primary_s3-issue-128
   Scenario Outline: Upload a file where checksum does not match
     Given using <dav_version> DAV path
diff --git a/tests/acceptance/features/apiWebdavOperations/uploadFileAsyncUsingNewChunking.feature b/tests/acceptance/features/apiWebdavOperations/uploadFileAsyncUsingNewChunking.feature
new file mode 100644
index 000000000000..7eab7122f519
--- /dev/null
+++ b/tests/acceptance/features/apiWebdavOperations/uploadFileAsyncUsingNewChunking.feature
@@ -0,0 +1,165 @@
+@api @TestAlsoOnExternalUserBackend
+Feature: upload file using new chunking
+  As a user
+  I want to be able to upload "large" files in chunks asynchronously
+  So that I do not have to wait for the long MOVE operation on assembly to finish
+
+  Background:
+    Given using new DAV path
+    And user "user0" has been created
+    And the owncloud log level has been set to debug
+    And the owncloud log has been cleared
+    And the administrator has enabled async operations
+
+  Scenario: Upload chunked file ordered asc using async MOVE
+    When user "user0" uploads the following chunks asynchronously to "/myChunkedFile.txt" with new chunking and using the WebDAV API
+      | 1 | AAAAA |
+      | 2 | BBBBB |
+      | 3 | CCCCC |
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/myChunkedFile.txt" for user "user0" should be "AAAAABBBBBCCCCC"
+    And the log file should not contain any log-entries containing these attributes:
+      | app |
+      | dav |
+
+  Scenario: Upload chunked file ordered desc using async MOVE
+    When user "user0" uploads the following chunks asynchronously to "/myChunkedFile.txt" with new chunking and using the WebDAV API
+      | 3 | CCCCC |
+      | 2 | BBBBB |
+      | 1 | AAAAA |
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/myChunkedFile.txt" for user "user0" should be "AAAAABBBBBCCCCC"
+    And the log file should not contain any log-entries containing these attributes:
+      | app |
+      | dav |
+
+  Scenario: Upload chunked file in random order using async MOVE
+    When user "user0" uploads the following chunks asynchronously to "/myChunkedFile.txt" with new chunking and using the WebDAV API
+      | 2 | BBBBB |
+      | 3 | CCCCC |
+      | 1 | AAAAA |
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/myChunkedFile.txt" for user "user0" should be "AAAAABBBBBCCCCC"
+    And the log file should not contain any log-entries containing these attributes:
+      | app |
+      | dav |
+
+  Scenario: Upload chunked file overwriting existing file using async MOVE
+    Given user "user0" has copied file "/textfile0.txt" to "/existingFile.txt"
+    When user "user0" uploads the following chunks asynchronously to "/existingFile.txt" with new chunking and using the WebDAV API
+      | 1 | AAAAA |
+      | 2 | BBBBB |
+      | 3 | CCCCC |
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/existingFile.txt" for user "user0" should be "AAAAABBBBBCCCCC"
+    And the log file should not contain any log-entries containing these attributes:
+      | app |
+      | dav |
+
+  Scenario: New chunked upload MOVE using old DAV path should fail
+    Given user "user0" has created a new chunking upload with id "chunking-42"
+    And user "user0" has uploaded new chunk file "2" with "BBBBB" to id "chunking-42"
+    And user "user0" has uploaded new chunk file "3" with "CCCCC" to id "chunking-42"
+    And user "user0" has uploaded new chunk file "1" with "AAAAA" to id "chunking-42"
+    When using old DAV path
+    And user "user0" moves new chunk file with id "chunking-42" asynchronously to "/myChunkedFile.txt" using the WebDAV API
+    Then the HTTP status code should be "404"
+
+  Scenario: Upload file via new chunking endpoint with wrong size header using async MOVE
+    Given user "user0" has created a new chunking upload with id "chunking-42"
+    And user "user0" has uploaded new chunk file "1" with "AAAAA" to id "chunking-42"
+    And user "user0" has uploaded new chunk file "2" with "BBBBB" to id "chunking-42"
+    And user "user0" has uploaded new chunk file "3" with "CCCCC" to id "chunking-42"
+    When user "user0" moves new chunk file with id "chunking-42" asynchronously to "/myChunkedFile.txt" with size 5 using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status       | /^error$/ |
+      | errorCode    | /^400$/   |
+      | errorMessage | /^Chunks on server do not sum up to 5 but to 15$/ |
+
+  Scenario: Upload file via new chunking endpoint with correct size header using async MOVE
+    Given user "user0" has created a new chunking upload with id "chunking-42"
+    And user "user0" has uploaded new chunk file "1" with "AAAAA" to id "chunking-42"
+    And user "user0" has uploaded new chunk file "2" with "BBBBB" to id "chunking-42"
+    And user "user0" has uploaded new chunk file "3" with "CCCCC" to id "chunking-42"
+    When user "user0" moves new chunk file with id "chunking-42" asynchronously to "/myChunkedFile.txt" with size 15 using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And as "user0" the file "/myChunkedFile.txt" should exist
+    And the content of file "/myChunkedFile.txt" for user "user0" should be "AAAAABBBBBCCCCC"
+    And the log file should not contain any log-entries containing these attributes:
+      | app |
+      | dav |
+
+  Scenario Outline: Upload files with difficult names using new chunking and async MOVE
+    When user "user0" creates a new chunking upload with id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "1" with "AAAAA" to id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "2" with "BBBBB" to id "chunking-42" using the WebDAV API
+    And user "user0" uploads new chunk file "3" with "CCCCC" to id "chunking-42" using the WebDAV API
+    And user "user0" moves new chunk file with id "chunking-42" asynchronously to "/<file-name>" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And as "user0" the file "/<file-name>" should exist
+    And the content of file "/<file-name>" for user "user0" should be "AAAAABBBBBCCCCC"
+    And the log file should not contain any log-entries containing these attributes:
+      | app |
+      | dav |
+    Examples:
+      | file-name |
+      | &#?       |
+      | TIÄFÜ     |
+
+  Scenario: disabled async operations leads to original behavior
+    Given the administrator has disabled async operations
+    When user "user0" uploads the following chunks asynchronously to "/myChunkedFile.txt" with new chunking and using the WebDAV API
+      | 1 | AAAAA |
+      | 2 | BBBBB |
+      | 3 | CCCCC |
+    Then the HTTP status code should be "201"
+    And the following headers should not be set
+      | OC-JobStatus-Location |
+    And the content of file "/myChunkedFile.txt" for user "user0" should be "AAAAABBBBBCCCCC"
+    
+  Scenario: enabling async operations does no difference to normal MOVE - Upload chunked file
+    When user "user0" uploads the following chunks to "/myChunkedFile.txt" with new chunking and using the WebDAV API
+      | 1 | AAAAA |
+      | 2 | BBBBB |
+      | 3 | CCCCC |
+    Then the HTTP status code should be "201"
+    And the following headers should not be set
+      | OC-JobStatus-Location |
+    And as "user0" the file "/myChunkedFile.txt" should exist
+    And the content of file "/myChunkedFile.txt" for user "user0" should be "AAAAABBBBBCCCCC"
+    And the log file should not contain any log-entries containing these attributes:
+      | app |
+      | dav |
diff --git a/tests/acceptance/features/apiWebdavProperties/moveFileAsync.feature b/tests/acceptance/features/apiWebdavProperties/moveFileAsync.feature
new file mode 100644
index 000000000000..2458114469d7
--- /dev/null
+++ b/tests/acceptance/features/apiWebdavProperties/moveFileAsync.feature
@@ -0,0 +1,269 @@
+@api @TestAlsoOnExternalUserBackend
+Feature: move (rename) file
+  As a user
+  I want to be able to move and rename files asynchronously
+  So that I can manage my file system
+
+  Background:
+    Given using new DAV path
+    And user "user0" has been created
+    And the administrator has enabled async operations
+
+  Scenario Outline: Moving a file
+    When user "user0" moves file "/welcome.txt" asynchronously to "/FOLDER/<destination-file-name>" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the downloaded content when downloading file "/FOLDER/<destination-file-name>" for user "user0" with range "bytes=0-6" should be "Welcome"
+    And user "user0" should not see the following elements
+      | /welcome.txt |
+    Examples:
+      | destination-file-name |
+      | नेपाली.txt              |
+      | strängé file.txt      |
+      | C++ file.cpp          |
+      | file #2.txt           |
+      | file ?2.txt           |
+
+  @skip @issue-32593 #ToDo: after fixing the issue add the ETag check to all tests where it makes sense and delete this test
+  Scenario: Moving a file
+    When user "user0" moves file "/welcome.txt" asynchronously to "/FOLDER/welcome.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | ETag   | /^[0-9a-f]{32}$/  |
+    And the downloaded content when downloading file "/FOLDER/welcome.txt" for user "user0" with range "bytes=0-6" should be "Welcome"
+    And user "user0" should not see the following elements
+      | /welcome.txt |
+
+  Scenario: Moving and overwriting a file
+    When user "user0" moves file "/welcome.txt" asynchronously to "/textfile0.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the downloaded content when downloading file "/textfile0.txt" for user "user0" with range "bytes=0-6" should be "Welcome"
+    And user "user0" should not see the following elements
+      | /welcome.txt |
+
+  Scenario: Moving (renaming) a file to be only different case
+    When user "user0" moves file "/textfile0.txt" asynchronously to "/TextFile0.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/TextFile0.txt" for user "user0" should be "ownCloud test text file 0" plus end-of-line
+    And user "user0" should not see the following elements
+      | /textfile0.txt |
+
+  Scenario: Moving (renaming) a file to a file with only different case to an existing file
+    When user "user0" moves file "/textfile1.txt" asynchronously to "/TextFile0.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/textfile0.txt" for user "user0" should be "ownCloud test text file 0" plus end-of-line
+    And the content of file "/TextFile0.txt" for user "user0" should be "ownCloud test text file 1" plus end-of-line
+    And user "user0" should not see the following elements
+      | /textfile1.txt |
+
+  Scenario: Moving (renaming) a file to a file in a folder with only different case to an existing file
+    When user "user0" moves file "/textfile1.txt" asynchronously to "/PARENT/Parent.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^finished$/      |
+      | fileId | /^[0-9a-z]{20,}$/ |
+    And the content of file "/PARENT/parent.txt" for user "user0" should be "ownCloud test text file parent" plus end-of-line
+    And the content of file "/PARENT/Parent.txt" for user "user0" should be "ownCloud test text file 1" plus end-of-line
+    And user "user0" should not see the following elements
+      | /textfile1.txt |
+
+  Scenario: Moving a file to a folder with no permissions
+    Given user "user1" has been created
+    And user "user1" has created a folder "/testshare"
+    And user "user1" has created a share with settings
+      | path        | testshare |
+      | shareType   | 0         |
+      | permissions | 1         |
+      | shareWith   | user0     |
+    When user "user0" moves file "/textfile0.txt" asynchronously to "/testshare/textfile0.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status    | /^error$/ |
+      | errorCode | /^403$/   |
+    And user "user0" downloads the file "/testshare/textfile0.txt" using the WebDAV API
+    Then the HTTP status code should be "404"
+    And user "user0" should see the following elements
+      | /textfile0.txt |
+
+  Scenario: Moving a file to overwrite a file in a folder with no permissions
+    Given user "user1" has been created
+    And user "user1" has created a folder "/testshare"
+    And user "user1" has created a share with settings
+      | path        | testshare |
+      | shareType   | 0         |
+      | permissions | 1         |
+      | shareWith   | user0     |
+    And user "user1" has copied file "/welcome.txt" to "/testshare/overwritethis.txt"
+    When user "user0" moves file "/textfile0.txt" asynchronously to "/testshare/overwritethis.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status    | /^error$/ |
+      | errorCode | /^403$/   |
+    And the downloaded content when downloading file "/testshare/overwritethis.txt" for user "user0" with range "bytes=0-6" should be "Welcome"
+    And user "user0" should see the following elements
+      | /textfile0.txt |
+
+  Scenario: move file into a not-existing folder
+    When user "user0" moves file "/welcome.txt" asynchronously to "/not-existing/welcome.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status       | /^error$/ |
+      | errorCode    | /^409$/   |
+      | errorMessage | /^The destination node is not found$/ |
+    And user "user0" should see the following elements
+      | /welcome.txt |
+
+  Scenario: rename a file into an invalid filename
+    When user "user0" moves file "/welcome.txt" asynchronously to "/a\\a" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status       | /^error$/ |
+      | errorCode    | /^400$/   |
+      | errorMessage | /^File name contains at least one invalid character$/ |
+    And user "user0" should see the following elements
+      | /welcome.txt |
+
+  Scenario: rename a file into a banned filename
+    When user "user0" moves file "/welcome.txt" asynchronously to "/.htaccess" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status       | /^error$/ |
+      | errorCode    | /^403$/   |
+    And user "user0" should see the following elements
+      | /welcome.txt |
+
+  Scenario: Renaming a file to a path with extension .part should not be possible
+    When user "user0" moves file "/welcome.txt" asynchronously to "/welcome.part" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status       | /^error$/ |
+      | errorCode    | /^400$/   |
+      | errorMessage | /^Can`t upload files with extension .part because these extensions are reserved for internal use.$/ |
+    And user "user0" should see the following elements
+      | /welcome.txt |
+    But user "user0" should not see the following elements
+      | /welcome.part |
+
+  Scenario: Checking file id after a move
+    Given user "user0" has stored id of file "/textfile0.txt"
+    When user "user0" moves file "/textfile0.txt" asynchronously to "/FOLDER/textfile0.txt" using the WebDAV API
+    Then user "user0" file "/FOLDER/textfile0.txt" should have the previously stored id
+    And user "user0" should not see the following elements
+      | /textfile0.txt |
+
+  Scenario: disabled async operations leads to original behavior
+    Given the administrator has disabled async operations
+    When user "user0" moves file "/welcome.txt" asynchronously to "/FOLDER/welcome.txt" using the WebDAV API
+    Then the HTTP status code should be "201"
+    And the following headers should not be set
+      | OC-JobStatus-Location |
+    And the downloaded content when downloading file "/FOLDER/welcome.txt" for user "user0" with range "bytes=0-6" should be "Welcome"
+
+  Scenario Outline: enabling async operations does no difference to normal MOVE - Moving a file
+    Given the administrator has enabled async operations
+    And using <dav_version> DAV path
+    When user "user0" moves file "/welcome.txt" to "/FOLDER/welcome.txt" using the WebDAV API
+    Then the HTTP status code should be "201"
+    And the downloaded content when downloading file "/FOLDER/welcome.txt" for user "user0" with range "bytes=0-6" should be "Welcome"
+    Examples:
+      | dav_version |
+      | old         |
+      | new         |
+
+  Scenario Outline: enabling async operations does no difference to normal MOVE - Moving and overwriting a file
+    Given the administrator has enabled async operations
+    And using <dav_version> DAV path
+    When user "user0" moves file "/welcome.txt" to "/textfile0.txt" using the WebDAV API
+    Then the HTTP status code should be "204"
+    And the downloaded content when downloading file "/textfile0.txt" for user "user0" with range "bytes=0-6" should be "Welcome"
+    Examples:
+      | dav_version |
+      | old         |
+      | new         |
+
+  Scenario Outline: enabling async operations does no difference to normal MOVE - Moving a file to a folder with no permissions
+    Given the administrator has enabled async operations
+    And using <dav_version> DAV path
+    And user "user1" has been created
+    And user "user1" has created a folder "/testshare"
+    And user "user1" has created a share with settings
+      | path        | testshare |
+      | shareType   | 0         |
+      | permissions | 1         |
+      | shareWith   | user0     |
+    When user "user0" moves file "/textfile0.txt" to "/testshare/textfile0.txt" using the WebDAV API
+    Then the HTTP status code should be "403"
+    When user "user0" downloads the file "/testshare/textfile0.txt" using the WebDAV API
+    Then the HTTP status code should be "404"
+    Examples:
+      | dav_version |
+      | old         |
+      | new         |
+
+  Scenario Outline: enabling async operations does no difference to normal MOVE - move file into a not-existing folder
+    Given the administrator has enabled async operations
+    And using <dav_version> DAV path
+    When user "user0" moves file "/welcome.txt" to "/not-existing/welcome.txt" using the WebDAV API
+    Then the HTTP status code should be "409"
+    Examples:
+      | dav_version |
+      | old         |
+      | new         |
+
+  Scenario Outline: enabling async operations does no difference to normal MOVE - rename a file into an invalid filename
+    Given the administrator has enabled async operations
+    And using <dav_version> DAV path
+    When user "user0" moves file "/welcome.txt" to "/a\\a" using the WebDAV API
+    Then the HTTP status code should be "400"
+    Examples:
+      | dav_version |
+      | old         |
+      | new         |
+
+  Scenario Outline: enabling async operations does no difference to normal MOVE - rename a file into a banned filename
+    Given the administrator has enabled async operations
+    And using <dav_version> DAV path
+    When user "user0" moves file "/welcome.txt" to "/.htaccess" using the WebDAV API
+    Then the HTTP status code should be "403"
+    Examples:
+      | dav_version |
+      | old         |
+      | new         |
+
+  #this does not work if firewall app is enabled
+  #and it also does not work with the php-dev server
+  Scenario: Moving and overwriting a file
+    #need to slowdown the request for longer than the timeout
+    #when doing LazyOps the server does not close the connection
+    #so we timout the request and chech the job-status
+    Given the HTTP-Request-timeout is set to 5 seconds
+    And the MOVE dav requests are slowed down by 10 seconds
+    When user "user0" moves file "/welcome.txt" asynchronously to "/textfile0.txt" using the WebDAV API
+    Then the HTTP status code should be "202"
+    And the following headers should match these regular expressions
+      | OC-JobStatus-Location | /%base_path%\/remote\.php\/dav\/job-status\/user0\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ |
+    And the oc job status values of last request for user "user0" should match these regular expressions
+      | status | /^started$/      |
\ No newline at end of file
diff --git a/tests/acceptance/features/bootstrap/BasicStructure.php b/tests/acceptance/features/bootstrap/BasicStructure.php
index 278a9271be40..2e7f37272a7d 100644
--- a/tests/acceptance/features/bootstrap/BasicStructure.php
+++ b/tests/acceptance/features/bootstrap/BasicStructure.php
@@ -512,6 +512,21 @@ public function getRemoteBaseUrlWithoutScheme() {
 		return $this->removeSchemeFromUrl($this->getRemoteBaseUrl());
 	}
 
+	/**
+	 * returns the base URL without any sub-path e.g. http://localhost:8080
+	 * of the base URL http://localhost:8080/owncloud
+	 *
+	 * @return string
+	 */
+	public function getBaseUrlWithoutPath() {
+		$parts = \parse_url($this->getBaseUrl());
+		$url = $parts ["scheme"] . "://" . $parts["host"];
+		if (isset($parts["port"])) {
+			$url = "$url:" . $parts["port"];
+		}
+		return $url;
+	}
+
 	/**
 	 * @return string
 	 */
@@ -1816,7 +1831,15 @@ public function substituteInLineCodes($value, $functions = []) {
 					"getLocalBaseUrlWithoutScheme"
 				],
 				"parameter" => []
-			]
+			],
+			[
+				"code" => "%base_path%",
+				"function" => [
+					$this,
+					"getBasePath"
+				],
+				"parameter" => []
+			],
 		];
 
 		foreach ($substitutions as $substitution) {
diff --git a/tests/acceptance/features/bootstrap/WebDav.php b/tests/acceptance/features/bootstrap/WebDav.php
index dc7440845c87..6dc6dc7f1823 100644
--- a/tests/acceptance/features/bootstrap/WebDav.php
+++ b/tests/acceptance/features/bootstrap/WebDav.php
@@ -22,10 +22,13 @@
 use Behat\Gherkin\Node\PyStringNode;
 use Behat\Gherkin\Node\TableNode;
 use GuzzleHttp\Message\ResponseInterface;
+use GuzzleHttp\Ring\Exception\ConnectException;
 use GuzzleHttp\Stream\StreamInterface;
 use Sabre\DAV\Client as SClient;
 use Sabre\DAV\Xml\Property\ResourceType;
 use Sabre\Xml\LibXMLException;
+use TestHelpers\OcsApiHelper;
+use TestHelpers\SetupHelper;
 use TestHelpers\WebDavHelper;
 use TestHelpers\HttpRequestHelper;
 use Sabre\DAV\Xml\Property\Complex;
@@ -72,6 +75,10 @@ trait WebDav {
 	 */
 	private $customDavPath = null;
 
+	private $oldAsyncSetting = null;
+	
+	private $oldDavSlowdownSetting = null;
+	
 	/**
 	 * response content parsed from XML to an array
 	 *
@@ -79,6 +86,7 @@ trait WebDav {
 	 */
 	private $responseXml = [];
 
+	private $httpRequestTimeout = 0;
 	/**
 	 * @Given /^using dav path "([^"]*)"$/
 	 *
@@ -249,6 +257,8 @@ public function parseResponseIntoXml($response = null) {
 	 * @param string $type
 	 * @param string|null $requestBody
 	 * @param string|null $davPathVersion
+	 * @param bool $stream Set to true to stream a response rather
+	 *                     than download it all up-front.
 	 * @param string|null $password
 	 *
 	 * @return ResponseInterface
@@ -262,6 +272,7 @@ public function makeDavRequest(
 		$type = "files",
 		$requestBody = null,
 		$davPathVersion = null,
+		$stream = false,
 		$password = null
 	) {
 		if ($this->customDavPath !== null) {
@@ -279,7 +290,63 @@ public function makeDavRequest(
 			$this->getBaseUrl(),
 			$user, $password, $method,
 			$path, $headers, $body, $requestBody, $davPathVersion,
-			$type
+			$type, null, "basic", $stream, $this->httpRequestTimeout
+		);
+	}
+
+	/**
+	 * @Given /^the administrator has (enabled|disabled) async operations$/
+	 */
+	public function triggerAsyncUpload($enabledOrDisabled) {
+		$switch = ($enabledOrDisabled !== "disabled");
+		if ($switch) {
+			$value = 'true';
+		} else {
+			$value = 'false';
+		}
+		if ($this->oldAsyncSetting === null) {
+			$oldAsyncSetting = SetupHelper::runOcc(
+				['config:system:get', 'dav.enable.async']
+			)['stdOut'];
+			$this->oldAsyncSetting = \trim($oldAsyncSetting);
+		}
+		$this->runOcc(
+			[
+				'config:system:set',
+				'dav.enable.async',
+				'--type',
+				'boolean',
+				'--value',
+				$value
+			]
+			);
+	}
+
+	/**
+	 * @Given the HTTP-Request-timeout is set to :seconds seconds
+	 * @param int $timeout
+	 */
+	public function setHttpTimeout($timeout) {
+		$this->httpRequestTimeout = (int)$timeout;
+	}
+
+	/**
+	 * @Given the :method dav requests are slowed down by :seconds seconds
+	 * @param int $timeout
+	 */
+	public function slowdownDavRequests($method, $seconds) {
+		if ($this->oldDavSlowdownSetting === null) {
+			$oldDavSlowdownSetting = SetupHelper::runOcc(
+				['config:system:get', 'dav.slowdown']
+			)['stdOut'];
+			$this->oldDavSlowdownSetting = \trim($oldDavSlowdownSetting);
+		}
+		OcsApiHelper::sendRequest(
+			$this->getBaseUrl(),
+			$this->getAdminUsername(),
+			$this->getAdminPassword(),
+			"PUT",
+			"/apps/testing/api/v1/davslowdown/$method/$seconds"
 		);
 	}
 
@@ -330,24 +397,41 @@ public function theUserHasMovedFile($fileSource, $fileDestination) {
 	}
 
 	/**
-	 * @When /^user "([^"]*)" moves (?:file|folder|entry) "([^"]*)" to "([^"]*)" using the WebDAV API$/
+	 * @When /^user "([^"]*)" moves (?:file|folder|entry) "([^"]*)"\s?(asynchronously|) to "([^"]*)" using the WebDAV API$/
 	 *
 	 * @param string $user
 	 * @param string $fileSource
+	 * @param string $type "asynchronously" or empty
 	 * @param string $fileDestination
 	 *
 	 * @return void
 	 */
 	public function userMovesFileUsingTheAPI(
-		$user, $fileSource, $fileDestination
+		$user, $fileSource, $type = "", $fileDestination
 	) {
 		$headers['Destination'] = $this->destinationHeaderValue(
 			$user, $fileDestination
 		);
-		$this->response = $this->makeDavRequest(
-			$user, "MOVE", $fileSource, $headers
-		);
-		$this->parseResponseIntoXml();
+		$stream = false;
+		if ($type === "asynchronously") {
+			$headers['OC-LazyOps'] = 'true';
+			if ($this->httpRequestTimeout > 0) {
+				//LazyOps is set and a request timeout, so we want to use stream
+				//to be able to read data from the request before its times out
+				//when doing LazyOps the server does not close the connection
+				//before its really finished
+				//but we want to read JobStatus-Location before the end of the job
+				//to see if it reports the correct values
+				$stream = true;
+			}
+		}
+		try {
+			$this->response = $this->makeDavRequest(
+				$user, "MOVE", $fileSource, $headers, null, "files", null, null, $stream
+			);
+			$this->parseResponseIntoXml();
+		} catch (ConnectException $e) {
+		}
 	}
 
 	/**
@@ -364,7 +448,7 @@ public function userOnMovesFileUsingTheAPI(
 		$user, $server, $fileSource, $fileDestination
 	) {
 		$previousServer = $this->usingServer($server);
-		$this->userMovesFileUsingTheAPI($user, $fileSource, $fileDestination);
+		$this->userMovesFileUsingTheAPI($user, $fileSource, "", $fileDestination);
 		$this->usingServer($previousServer);
 	}
 
@@ -877,6 +961,35 @@ public function downloadedContentShouldStartWith($start) {
 		}
 	}
 
+	/**
+	 * @Then the oc job status values of last request for user :user should match these regular expressions
+	 *
+	 * @param string $user
+	 * @param TableNode $table
+	 *
+	 * @return void
+	 */
+	public function jobStatusValuesShouldMatchRegEx($user, $table) {
+		$url = $this->response->getHeader("OC-JobStatus-Location");
+		$url = $this->getBaseUrlWithoutPath() . $url;
+		$response = HttpRequestHelper::get($url, $user, $this->getPasswordForUser($user));
+		$result = \json_decode($response->getBody()->getContents(), true);
+		PHPUnit_Framework_Assert::assertNotNull($result, "'$response' is not valid JSON");
+		foreach ($table->getTable() as $row) {
+			$expectedKey = $row[0];
+			PHPUnit_Framework_Assert::assertArrayHasKey(
+				$expectedKey, $result, "response does not have expected key '$expectedKey'"
+			);
+			$expectedValue = $this->substituteInLineCodes(
+				$row[1], ['preg_quote' => ['/'] ]
+			);
+			PHPUnit_Framework_Assert::assertNotFalse(
+				(bool)\preg_match($expectedValue, $result[$expectedKey]),
+				"'$expectedValue' does not match '$result[$expectedKey]'"
+			);
+		}
+	}
+
 	/**
 	 * @When /^user "([^"]*)" gets the properties of (?:file|folder|entry) "([^"]*)" using the WebDAV API$/
 	 *
@@ -2023,10 +2136,11 @@ public function userUploadsChunkedFile(
 	/**
 	 * New style chunking upload
 	 *
-	 * @When user :user uploads the following chunks to :file with new chunking and using the WebDAV API
-	 * @Given user :user has uploaded the following chunks to :file with new chunking
+	 * @When /^user "([^"]*)" uploads the following chunks\s?(asynchronously|) to "([^"]*)" with new chunking and using the WebDAV API$/
+	 * @Given /^user "([^"]*)" has uploaded the following chunks\s?(asynchronously|) to "([^"]*)" with new chunking$/
 	 *
 	 * @param string $user
+	 * @param string $type "asynchronously" or empty
 	 * @param string $file
 	 * @param TableNode $chunkDetails table of 2 columns, chunk number and chunk
 	 *                                content without column headings, e.g.
@@ -2036,9 +2150,15 @@ public function userUploadsChunkedFile(
 	 *
 	 * @return void
 	 */
-	public function userUploadsTheFollowingChunksUsingNewChunking($user, $file, TableNode $chunkDetails) {
+	public function userUploadsTheFollowingChunksUsingNewChunking(
+		$user, $type = "", $file, TableNode $chunkDetails
+	) {
+		$async = false;
+		if ($type === "asynchronously") {
+			$async = true;
+		}
 		$this->userUploadsChunksUsingNewChunking(
-			$user, $file, 'chunking-42', $chunkDetails->getTable()
+			$user, $file, 'chunking-42', $chunkDetails->getTable(), $async
 		);
 	}
 
@@ -2053,17 +2173,23 @@ public function userUploadsTheFollowingChunksUsingNewChunking($user, $file, Tabl
 	 *                            [0] the chunk number
 	 *                            [1] data content of the chunk
 	 *                            Chunks may be numbered out-of-order if desired.
-	 *
+	 * @param bool $async use asynchronous MOVE at the end or not
 	 * @return void
 	 */
-	public function userUploadsChunksUsingNewChunking($user, $file, $chunkingId, $chunkDetails) {
+	public function userUploadsChunksUsingNewChunking(
+		$user, $file, $chunkingId, $chunkDetails, $async = false
+	) {
 		$this->userCreatesANewChunkingUploadWithId($user, $chunkingId);
 		foreach ($chunkDetails as $chunkDetail) {
 			$chunkNumber = $chunkDetail[0];
 			$chunkContent = $chunkDetail[1];
 			$this->userUploadsNewChunkFileOfWithToId($user, $chunkNumber, $chunkContent, $chunkingId);
 		}
-		$this->userMovesNewChunkFileWithIdToMychunkedfile($user, $chunkingId, $file);
+		$headers = [];
+		if ($async === true) {
+			$headers = ['OC-LazyOps' => 'true'];
+		}
+		$this->moveNewDavChunkToFinalFile($user, $chunkingId, $file, $headers);
 	}
 
 	/**
@@ -2102,19 +2228,24 @@ public function userUploadsNewChunkFileOfWithToId($user, $num, $data, $id) {
 	}
 
 	/**
-	 * @When user :user moves new chunk file with id :id to :dest using the WebDAV API
-	 * @Given user :user has moved new chunk file with id :id to :dest
+	 * @When /^user "([^"]*)" moves new chunk file with id "([^"]*)"\s?(asynchronously|) to "([^"]*)" using the WebDAV API$/
+	 * @Given /^user "([^"]*)" has moved new chunk file with id "([^"]*)"\s?(asynchronously|) to "([^"]*)"$/
 	 *
 	 * @param string $user
 	 * @param string $id
+	 * @param string $type "asynchronously" or empty
 	 * @param string $dest
 	 *
 	 * @return void
 	 */
 	public function userMovesNewChunkFileWithIdToMychunkedfile(
-		$user, $id, $dest
+		$user, $id, $type, $dest
 	) {
-		$this->moveNewDavChunkToFinalFile($user, $id, $dest, []);
+		$headers = [];
+		if ($type === "asynchronously") {
+			$headers = ['OC-LazyOps' => 'true'];
+		}
+		$this->moveNewDavChunkToFinalFile($user, $id, $dest, $headers);
 	}
 
 	/**
@@ -2133,40 +2264,50 @@ public function userCancelsUploadWithId(
 	}
 
 	/**
-	 * @When user :user moves new chunk file with id :id to :dest with size :size using the WebDAV API
-	 * @Given user :user has moved new chunk file with id :id to :dest with size :size
+	 * @When /^user "([^"]*)" moves new chunk file with id "([^"]*)"\s?(asynchronously|) to "([^"]*)" with size (.*) using the WebDAV API$/
+	 * @Given /^user "([^"]*)" has moved new chunk file with id "([^"]*)"\s?(asynchronously|) to "([^"]*)" with size (.*)$/
 	 *
 	 * @param string $user
 	 * @param string $id
+	 * @param string $type "asynchronously" or empty
 	 * @param string $dest
 	 * @param int $size
 	 *
 	 * @return void
 	 */
 	public function userMovesNewChunkFileWithIdToMychunkedfileWithSize(
-		$user, $id, $dest, $size
+		$user, $id, $type, $dest, $size
 	) {
+		$headers = ['OC-Total-Length' => $size];
+		if ($type === "asynchronously") {
+			$headers['OC-LazyOps'] = 'true';
+		}
 		$this->moveNewDavChunkToFinalFile(
-			$user, $id, $dest, ['OC-Total-Length' => $size]
+			$user, $id, $dest, $headers
 		);
 	}
 
 	/**
-	 * @When user :user moves new chunk file with id :id to :dest with checksum :checksum using the WebDAV API
-	 * @Given user :user has moved new chunk file with id :id to :dest with checksum :checksum
+	 * @When /^user "([^"]*)" moves new chunk file with id "([^"]*)"\s?(asynchronously|) to "([^"]*)" with checksum "([^"]*)" using the WebDAV API$/
+	 * @Given /^user "([^"]*)" has moved new chunk file with id "([^"]*)"\s?(asynchronously|) to "([^"]*)" with checksum "([^"]*)"
 	 *
 	 * @param string $user
 	 * @param string $id
+	 * @param string $type "asynchronously" or empty
 	 * @param string $dest
 	 * @param string $checksum
 	 *
 	 * @return void
 	 */
 	public function userMovesNewChunkFileWithIdToMychunkedfileWithChecksum(
-		$user, $id, $dest, $checksum
+		$user, $id, $type, $dest, $checksum
 	) {
+		$headers = ['OC-Checksum' => $checksum];
+		if ($type === "asynchronously") {
+			$headers['OC-LazyOps'] = 'true';
+		}
 		$this->moveNewDavChunkToFinalFile(
-			$user, $id, $dest, ['OC-Checksum' => $checksum]
+			$user, $id, $dest, $headers
 		);
 	}
 
@@ -2392,6 +2533,52 @@ public function thereAreNoDuplicateHeaders() {
 		}
 	}
 
+	/**
+	 * @Then the following headers should not be set
+	 *
+	 * @param TableNode $table
+	 *
+	 * @return void
+	 * @throws \Exception
+	 */
+	public function theFollowingHeadersShouldNotBeSet(TableNode $table) {
+		foreach ($table->getTable() as $header) {
+			$headerName = $header[0];
+			$headerValue = $this->response->getHeader($headerName);
+			//Note: according to the documentation of getHeader it must return null
+			//if the header does not exist, but its returning an empty string
+			PHPUnit_Framework_Assert::assertEmpty(
+				$headerValue,
+				"header $headerName should not exist " .
+				"but does and is set to $headerValue"
+				);
+		}
+	}
+
+	/**
+	 * @Then the following headers should match these regular expressions
+	 *
+	 * @param TableNode $table
+	 *
+	 * @return void
+	 * @throws \Exception
+	 */
+	public function headersShouldMatchRegularExpressions(TableNode $table) {
+		foreach ($table->getTable() as $header) {
+			$headerName = $header[0];
+			$expectedHeaderValue = $header[1];
+			$expectedHeaderValue = $this->substituteInLineCodes(
+				$expectedHeaderValue, ['preg_quote' => ['/'] ]
+				);
+			
+			$returnedHeader = $this->response->getHeader($headerName);
+			PHPUnit_Framework_Assert::assertNotFalse(
+				(bool)\preg_match($expectedHeaderValue, $returnedHeader),
+				"'$expectedHeaderValue' does not match '$returnedHeader'"
+				);
+		}
+	}
+
 	/**
 	 * @Then /^user "([^"]*)" in folder "([^"]*)" should have favorited the following elements$/
 	 *
@@ -2722,4 +2909,40 @@ public function findFileFromPropfindResponse($user, $fileNameToSearch) {
 		}
 		return false;
 	}
+
+	/**
+	 * reset settings if they were set in the scenario
+	 *
+	 * @AfterScenario
+	 *
+	 * @return void
+	 */
+	public function resetOldSettingsAfterScenario() {
+		if ($this->oldAsyncSetting === "") {
+			SetupHelper::runOcc(['config:system:delete', 'dav.enable.async']);
+		} elseif ($this->oldAsyncSetting !== null) {
+			SetupHelper::runOcc(
+				[
+					'config:system:set',
+					'dav.enable.async',
+					'--type',
+					'boolean',
+					'--value',
+					$this->oldAsyncSetting
+				]
+			);
+		}
+		if ($this->oldDavSlowdownSetting === "") {
+			SetupHelper::runOcc(['config:system:delete', 'dav.slowdown']);
+		} elseif ($this->oldDavSlowdownSetting !== null) {
+			SetupHelper::runOcc(
+				[
+					'config:system:set',
+					'dav.slowdown',
+					'--value',
+					$this->oldDavSlowdownSetting
+				]
+			);
+		}
+	}
 }

From 2620e0536440f9cead09cb4a0487356bb2cf9981 Mon Sep 17 00:00:00 2001
From: Phil Davis <phil@jankaritech.com>
Date: Tue, 23 Oct 2018 22:04:03 +0545
Subject: [PATCH 2/5] Fix PHP style in WebDav.php

---
 .../acceptance/features/bootstrap/WebDav.php  | 28 ++++++++++++++-----
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/tests/acceptance/features/bootstrap/WebDav.php b/tests/acceptance/features/bootstrap/WebDav.php
index 6dc6dc7f1823..5b4e39b9babf 100644
--- a/tests/acceptance/features/bootstrap/WebDav.php
+++ b/tests/acceptance/features/bootstrap/WebDav.php
@@ -296,6 +296,11 @@ public function makeDavRequest(
 
 	/**
 	 * @Given /^the administrator has (enabled|disabled) async operations$/
+	 *
+	 * @param string $enabledOrDisabled
+	 *
+	 * @return void
+	 * @throws Exception
 	 */
 	public function triggerAsyncUpload($enabledOrDisabled) {
 		$switch = ($enabledOrDisabled !== "disabled");
@@ -319,12 +324,15 @@ public function triggerAsyncUpload($enabledOrDisabled) {
 				'--value',
 				$value
 			]
-			);
+		);
 	}
 
 	/**
 	 * @Given the HTTP-Request-timeout is set to :seconds seconds
+	 *
 	 * @param int $timeout
+	 *
+	 * @return void
 	 */
 	public function setHttpTimeout($timeout) {
 		$this->httpRequestTimeout = (int)$timeout;
@@ -332,7 +340,12 @@ public function setHttpTimeout($timeout) {
 
 	/**
 	 * @Given the :method dav requests are slowed down by :seconds seconds
-	 * @param int $timeout
+	 *
+	 * @param string $method
+	 * @param int $seconds
+	 *
+	 * @throws Exception
+	 * @return void
 	 */
 	public function slowdownDavRequests($method, $seconds) {
 		if ($this->oldDavSlowdownSetting === null) {
@@ -407,7 +420,7 @@ public function theUserHasMovedFile($fileSource, $fileDestination) {
 	 * @return void
 	 */
 	public function userMovesFileUsingTheAPI(
-		$user, $fileSource, $type = "", $fileDestination
+		$user, $fileSource, $type, $fileDestination
 	) {
 		$headers['Destination'] = $this->destinationHeaderValue(
 			$user, $fileDestination
@@ -2151,7 +2164,7 @@ public function userUploadsChunkedFile(
 	 * @return void
 	 */
 	public function userUploadsTheFollowingChunksUsingNewChunking(
-		$user, $type = "", $file, TableNode $chunkDetails
+		$user, $type, $file, TableNode $chunkDetails
 	) {
 		$async = false;
 		if ($type === "asynchronously") {
@@ -2174,6 +2187,7 @@ public function userUploadsTheFollowingChunksUsingNewChunking(
 	 *                            [1] data content of the chunk
 	 *                            Chunks may be numbered out-of-order if desired.
 	 * @param bool $async use asynchronous MOVE at the end or not
+	 *
 	 * @return void
 	 */
 	public function userUploadsChunksUsingNewChunking(
@@ -2551,7 +2565,7 @@ public function theFollowingHeadersShouldNotBeSet(TableNode $table) {
 				$headerValue,
 				"header $headerName should not exist " .
 				"but does and is set to $headerValue"
-				);
+			);
 		}
 	}
 
@@ -2569,13 +2583,13 @@ public function headersShouldMatchRegularExpressions(TableNode $table) {
 			$expectedHeaderValue = $header[1];
 			$expectedHeaderValue = $this->substituteInLineCodes(
 				$expectedHeaderValue, ['preg_quote' => ['/'] ]
-				);
+			);
 			
 			$returnedHeader = $this->response->getHeader($headerName);
 			PHPUnit_Framework_Assert::assertNotFalse(
 				(bool)\preg_match($expectedHeaderValue, $returnedHeader),
 				"'$expectedHeaderValue' does not match '$returnedHeader'"
-				);
+			);
 		}
 	}
 

From f10e033434ebc9c0b416a5bf579778ff3cfa787a Mon Sep 17 00:00:00 2001
From: Phil Davis <phil@jankaritech.com>
Date: Tue, 23 Oct 2018 22:09:16 +0545
Subject: [PATCH 3/5] Adjust async capabilities scenarios

---
 .../acceptance/features/apiCapabilities/capabilities.feature  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/acceptance/features/apiCapabilities/capabilities.feature b/tests/acceptance/features/apiCapabilities/capabilities.feature
index e908a075a9a7..2fd3eb5e5f83 100644
--- a/tests/acceptance/features/apiCapabilities/capabilities.feature
+++ b/tests/acceptance/features/apiCapabilities/capabilities.feature
@@ -73,7 +73,7 @@ Feature: capabilities
   @skipOnOcV10.0.9
   Scenario: getting async capabilites when async operations are enabled
     Given the administrator has enabled async operations
-    When the user retrieves the capabilities using the capabilities API
+    When the administrator retrieves the capabilities using the capabilities API
     Then the capabilities should contain
       | capability | path_to_element | value |
       | async      |                 | 1.0   |
@@ -82,7 +82,7 @@ Feature: capabilities
   @skipOnOcV10.0.9
   Scenario: getting async capabilites when async operations are disabled
     Given the administrator has disabled async operations
-    When the user retrieves the capabilities using the capabilities API
+    When the administrator retrieves the capabilities using the capabilities API
     Then the capabilities should contain
       | capability | path_to_element | value |
       | async      |                 | EMPTY |

From 3301bf67ea991df7d41174458aa997e5629d74e2 Mon Sep 17 00:00:00 2001
From: Phil Davis <phil@jankaritech.com>
Date: Tue, 23 Oct 2018 22:15:00 +0545
Subject: [PATCH 4/5] Adjust downloadFileAsUserUsingPassword() makeDavRequest()
 call

---
 tests/acceptance/features/bootstrap/WebDav.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tests/acceptance/features/bootstrap/WebDav.php b/tests/acceptance/features/bootstrap/WebDav.php
index 5b4e39b9babf..ee3f574fa61a 100644
--- a/tests/acceptance/features/bootstrap/WebDav.php
+++ b/tests/acceptance/features/bootstrap/WebDav.php
@@ -918,6 +918,7 @@ public function downloadFileAsUserUsingPassword(
 			"files",
 			null,
 			null,
+			false,
 			$password
 		);
 	}

From 39f11fccc36d9d7854d0b65749d9ea46f862c8e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20M=C3=BCller?= <thomas.mueller@tmit.eu>
Date: Wed, 24 Oct 2018 18:19:31 +0200
Subject: [PATCH 5/5] moveFileAsync.feature: adjust acceptance to new behavior
 - fixes #32598

---
 .../apiWebdavProperties/moveFileAsync.feature   | 17 +++--------------
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/tests/acceptance/features/apiWebdavProperties/moveFileAsync.feature b/tests/acceptance/features/apiWebdavProperties/moveFileAsync.feature
index 2458114469d7..a860f861addb 100644
--- a/tests/acceptance/features/apiWebdavProperties/moveFileAsync.feature
+++ b/tests/acceptance/features/apiWebdavProperties/moveFileAsync.feature
@@ -138,30 +138,19 @@ Feature: move (rename) file
 
   Scenario: rename a file into an invalid filename
     When user "user0" moves file "/welcome.txt" asynchronously to "/a\\a" using the WebDAV API
-    Then the HTTP status code should be "202"
-    And the oc job status values of last request for user "user0" should match these regular expressions
-      | status       | /^error$/ |
-      | errorCode    | /^400$/   |
-      | errorMessage | /^File name contains at least one invalid character$/ |
+    Then the HTTP status code should be "400"
     And user "user0" should see the following elements
       | /welcome.txt |
 
   Scenario: rename a file into a banned filename
     When user "user0" moves file "/welcome.txt" asynchronously to "/.htaccess" using the WebDAV API
-    Then the HTTP status code should be "202"
-    And the oc job status values of last request for user "user0" should match these regular expressions
-      | status       | /^error$/ |
-      | errorCode    | /^403$/   |
+    Then the HTTP status code should be "403"
     And user "user0" should see the following elements
       | /welcome.txt |
 
   Scenario: Renaming a file to a path with extension .part should not be possible
     When user "user0" moves file "/welcome.txt" asynchronously to "/welcome.part" using the WebDAV API
-    Then the HTTP status code should be "202"
-    And the oc job status values of last request for user "user0" should match these regular expressions
-      | status       | /^error$/ |
-      | errorCode    | /^400$/   |
-      | errorMessage | /^Can`t upload files with extension .part because these extensions are reserved for internal use.$/ |
+    Then the HTTP status code should be "400"
     And user "user0" should see the following elements
       | /welcome.txt |
     But user "user0" should not see the following elements