Merge pull request #10624 from owncloud/set-chunking-version

[tests-only][full-ci] refactor: Set chunking version 1 as default
This commit is contained in:
Sawjan Gurung
2024-12-13 11:25:54 +05:45
committed by GitHub
4 changed files with 47 additions and 314 deletions

View File

@@ -46,8 +46,7 @@ class UploadHelper extends Assert {
* @param string|null $xRequestId
* @param array|null $headers
* @param int|null $davPathVersionToUse (1|2)
* @param int|null $chunkingVersion (1|2|null)
* if set to null chunking will not be used
* @param bool $doChunkUpload
* @param int|null $noOfChunks how many chunks to upload
* @param bool|null $isGivenStep
*
@@ -63,12 +62,11 @@ class UploadHelper extends Assert {
?string $xRequestId = '',
?array $headers = [],
?int $davPathVersionToUse = 1,
?int $chunkingVersion = null,
bool $doChunkUpload = false,
?int $noOfChunks = 1,
?bool $isGivenStep = false
?bool $isGivenStep = false,
): ResponseInterface {
//simple upload with no chunking
if ($chunkingVersion === null) {
if (!$doChunkUpload) {
$data = \file_get_contents($source);
return WebDavHelper::makeDavRequest(
$baseUrl,
@@ -91,56 +89,16 @@ class UploadHelper extends Assert {
null,
$isGivenStep
);
} else {
//prepare chunking
$chunks = self::chunkFile($source, $noOfChunks);
$chunkingId = 'chunking-' . \rand(1000, 9999);
$v2ChunksDestination = '/uploads/' . $user . '/' . $chunkingId;
}
//prepare chunking
$chunks = self::chunkFile($source, $noOfChunks);
$chunkingId = 'chunking-' . \rand(1000, 9999);
$result = null;
//prepare chunking version specific stuff
if ($chunkingVersion === 1) {
$headers['OC-Chunked'] = '1';
} elseif ($chunkingVersion === 2) {
$result = WebDavHelper::makeDavRequest(
$baseUrl,
$user,
$password,
'MKCOL',
$v2ChunksDestination,
$headers,
null,
$xRequestId,
null,
$davPathVersionToUse,
"uploads",
null,
"basic",
false,
0,
null,
[],
null,
$isGivenStep
);
if ($result->getStatusCode() >= 400) {
return $result;
}
}
//upload chunks
foreach ($chunks as $index => $chunk) {
if ($chunkingVersion === 1) {
$filename = $destination . "-" . $chunkingId . "-" .
\count($chunks) . '-' . $index;
$davRequestType = "files";
} else {
// do chunking version 2
$filename = $v2ChunksDestination . '/' . $index;
$davRequestType = "uploads";
}
$filename = $destination . "-" . $chunkingId . "-" . \count($chunks) . '-' . $index;
$result = WebDavHelper::makeDavRequest(
$baseUrl,
$user,
@@ -152,7 +110,7 @@ class UploadHelper extends Assert {
$xRequestId,
$chunk,
$davPathVersionToUse,
$davRequestType,
"files",
null,
"basic",
false,
@@ -166,121 +124,11 @@ class UploadHelper extends Assert {
return $result;
}
}
//finish upload for new chunking
if ($chunkingVersion === 2) {
$source = $v2ChunksDestination . '/.file';
$headers['Destination'] = $baseUrl . "/" .
WebDavHelper::getDavPath($davPathVersionToUse, $user) .
$destination;
$result = WebDavHelper::makeDavRequest(
$baseUrl,
$user,
$password,
'MOVE',
$source,
$headers,
null,
$xRequestId,
null,
$davPathVersionToUse,
"uploads",
null,
"basic",
false,
0,
null,
[],
null,
$isGivenStep
);
if ($result->getStatusCode() >= 400) {
return $result;
}
}
self::assertNotNull($result, __METHOD__ . " chunking version $chunkingVersion was requested but no upload was done.");
self::assertNotNull($result, __METHOD__ . " chunking was requested but no upload was done.");
return $result;
}
/**
* Upload the same file multiple times with different mechanisms.
*
* @param string|null $baseUrl URL of owncloud
* @param string|null $user user who uploads
* @param string|null $password
* @param string|null $source source file path
* @param string|null $destination destination path on the server
* @param string|null $xRequestId
* @param bool $overwriteMode when false creates separate files to test uploading brand-new files,
* when true it just overwrites the same file over and over again with the same name
* @param string|null $exceptChunkingType empty string or "old" or "new"
*
* @return array of ResponseInterface
* @throws GuzzleException
*/
public static function uploadWithAllMechanisms(
?string $baseUrl,
?string $user,
?string $password,
?string $source,
?string $destination,
?string $xRequestId = '',
?bool $overwriteMode = false,
?string $exceptChunkingType = ''
):array {
$responses = [];
foreach ([1, 2] as $davPathVersion) {
if ($davPathVersion === 1) {
$davHuman = 'old';
} else {
$davHuman = 'new';
}
switch ($exceptChunkingType) {
case 'old':
$exceptChunkingVersion = 1;
break;
case 'new':
$exceptChunkingVersion = 2;
break;
default:
$exceptChunkingVersion = -1;
break;
}
foreach ([null, 1, 2] as $chunkingVersion) {
if ($chunkingVersion === $exceptChunkingVersion) {
continue;
}
$valid = WebDavHelper::isValidDavChunkingCombination(
$davPathVersion,
$chunkingVersion
);
if ($valid === false) {
continue;
}
$finalDestination = $destination;
if (!$overwriteMode && $chunkingVersion !== null) {
$finalDestination .= "-{$davHuman}dav-{$davHuman}chunking";
} elseif (!$overwriteMode && $chunkingVersion === null) {
$finalDestination .= "-{$davHuman}dav-regular";
}
$responses[] = self::upload(
$baseUrl,
$user,
$password,
$source,
$finalDestination,
$xRequestId,
[],
$davPathVersion,
$chunkingVersion,
2
);
}
}
return $responses;
}
/**
* cut the file in multiple chunks
* returns an array of chunks with the content of the file

View File

@@ -816,34 +816,6 @@ class WebDavHelper {
return \preg_replace("/([^:]\/)\/+/", '$1', $url);
}
/**
* Decides if the proposed dav version and chunking version are
* a valid combination.
* If no chunkingVersion is specified, then any dav version is valid.
* If a chunkingVersion is specified, then it has to match the dav version.
* Note: in future, the dav and chunking versions might or might not
* move together and/or be supported together. So a more complex
* matrix could be needed here.
*
* @param string|int $davPathVersion
* @param string|int|null $chunkingVersion
*
* @return boolean is this a valid combination
*/
public static function isValidDavChunkingCombination(
$davPathVersion,
$chunkingVersion
): bool {
if ($davPathVersion === self::DAV_VERSION_SPACES) {
// allow only old chunking version when using the spaces dav
return $chunkingVersion === 1;
}
return (
($chunkingVersion === 'no' || $chunkingVersion === null) ||
($davPathVersion === $chunkingVersion)
);
}
/**
* get Mtime of File in a public link share
*

View File

@@ -68,8 +68,6 @@ trait WebDav {
private int $httpRequestTimeout = 0;
private ?int $chunkingToUse = null;
/**
* The ability to do requests with depth infinity is disabled by default.
* This remembers when the setting dav.propfind.depth_infinity has been
@@ -1626,7 +1624,7 @@ trait WebDav {
* @param array|null $headers
* @param int|null $noOfChunks Only use for chunked upload when $this->chunkingToUse is not null
*
* @return void
* @return ResponseInterface
* @throws Exception
*/
public function uploadFileWithHeaders(
@@ -1635,30 +1633,27 @@ trait WebDav {
string $destination,
?array $headers = [],
?int $noOfChunks = 0
):void {
$chunkingVersion = $this->chunkingToUse;
): ResponseInterface {
$doChunkUpload = true;
if ($noOfChunks <= 0) {
$chunkingVersion = null;
}
try {
$this->pauseUploadDelete();
$this->response = UploadHelper::upload(
$this->getBaseUrl(),
$this->getActualUsername($user),
$this->getUserPassword($user),
$source,
$destination,
$this->getStepLineRef(),
$headers,
$this->getDavPathVersion(),
$chunkingVersion,
$noOfChunks
);
$this->lastUploadDeleteTime = \time();
} catch (BadResponseException $e) {
// 4xx and 5xx responses cause an exception
$this->response = $e->getResponse();
$doChunkUpload = false;
}
$this->pauseUploadDelete();
$response = UploadHelper::upload(
$this->getBaseUrl(),
$this->getActualUsername($user),
$this->getUserPassword($user),
$source,
$destination,
$this->getStepLineRef(),
$headers,
$this->getDavPathVersion(),
$doChunkUpload,
$noOfChunks,
);
$this->lastUploadDeleteTime = \time();
return $response;
}
/**
@@ -1669,7 +1664,7 @@ trait WebDav {
* @param boolean $async
* @param array|null $headers
*
* @return void
* @return ResponseInterface
*/
public function userUploadsAFileInChunk(
string $user,
@@ -1678,7 +1673,7 @@ trait WebDav {
int $noOfChunks = 2,
bool $async = false,
?array $headers = []
):void {
): ResponseInterface {
$user = $this->getActualUsername($user);
Assert::assertGreaterThan(
0,
@@ -1686,52 +1681,16 @@ trait WebDav {
"What does it mean to have $noOfChunks chunks?"
);
// use chunking version 1 as default, since version 2 uses "remote.php/dav/uploads" endpoint and it doesn't exist in oCIS
$this->chunkingToUse = 1;
if ($async === true) {
$headers['OC-LazyOps'] = 'true';
}
$this->uploadFileWithHeaders(
return $this->uploadFileWithHeaders(
$user,
$this->acceptanceTestsDirLocation() . $source,
$destination,
$headers,
$noOfChunks
);
$this->pushToLastStatusCodesArrays();
}
/**
* Uploading with old/new DAV and chunked/non-chunked.
* Except do not do the new-DAV-new-chunking combination. That is not being
* supported on all implementations.
*
* @When user :user uploads file :source to filenames based on :destination with all mechanisms except new chunking using the WebDAV API
*
* @param string $user
* @param string $source
* @param string $destination
*
* @return void
* @throws Exception
*/
public function userUploadsAFileToWithAllMechanismsExceptNewChunking(
string $user,
string $source,
string $destination
):void {
$user = $this->getActualUsername($user);
$this->uploadResponses = UploadHelper::uploadWithAllMechanisms(
$this->getBaseUrl(),
$this->getActualUsername($user),
$this->getUserPassword($user),
$this->acceptanceTestsDirLocation() . $source,
$destination,
$this->getStepLineRef(),
false,
'new'
);
}
/**
@@ -1751,24 +1710,9 @@ trait WebDav {
string $destination,
int $noOfChunks = 2
):void {
$this->userUploadsAFileInChunk($user, $source, $destination, $noOfChunks);
}
/**
* @Then /^the HTTP status code of all upload responses should be "([^"]*)"$/
*
* @param int $statusCode
*
* @return void
*/
public function theHTTPStatusCodeOfAllUploadResponsesShouldBe(int $statusCode):void {
foreach ($this->uploadResponses as $response) {
Assert::assertEquals(
$statusCode,
$response->getStatusCode(),
'Response did not return expected status code'
);
}
$response = $this->userUploadsAFileInChunk($user, $source, $destination, $noOfChunks);
$this->setResponse($response);
$this->pushToLastStatusCodesArrays();
}
/**
@@ -1960,32 +1904,6 @@ trait WebDav {
}
}
/**
* @Then /^the HTTP status code of all upload responses should be between "(\d+)" and "(\d+)"$/
*
* @param int $minStatusCode
* @param int $maxStatusCode
*
* @return void
*/
public function theHTTPStatusCodeOfAllUploadResponsesShouldBeBetween(
int $minStatusCode,
int $maxStatusCode
):void {
foreach ($this->uploadResponses as $response) {
Assert::assertGreaterThanOrEqual(
$minStatusCode,
$response->getStatusCode(),
'Response did not return expected status code'
);
Assert::assertLessThanOrEqual(
$maxStatusCode,
$response->getStatusCode(),
'Response did not return expected status code'
);
}
}
/**
* @param string $user
* @param string $destination
@@ -2203,7 +2121,7 @@ trait WebDav {
$this->getStepLineRef(),
["X-OC-Mtime" => $mtime],
$this->getDavPathVersion(),
null,
false,
1,
$isGivenStep
);
@@ -2238,7 +2156,7 @@ trait WebDav {
$this->getStepLineRef(),
["X-OC-Mtime" => $mtime],
$this->getDavPathVersion(),
null,
false,
1,
true
);

View File

@@ -20,13 +20,10 @@ Feature: dav-versions
| spaces |
Scenario Outline: upload file and no version is available using various chunking methods (except new chunking)
Scenario Outline: no version is available while uploading a file with multiple chunks
Given using <dav-path-version> DAV path
When user "Alice" uploads file "filesForUpload/davtest.txt" to filenames based on "/davtest.txt" with all mechanisms except new chunking using the WebDAV API
Then the HTTP status code of all upload responses should be "201"
And the version folder of file "/davtest.txt-olddav-regular" for user "Alice" should contain "0" elements
And the version folder of file "/davtest.txt-newdav-regular" for user "Alice" should contain "0" elements
And the version folder of file "/davtest.txt-olddav-oldchunking" for user "Alice" should contain "0" elements
When user "Alice" uploads file "filesForUpload/davtest.txt" to "lorem.txt" in 2 chunks using the WebDAV API
Then the version folder of file "lorem.txt" for user "Alice" should contain "0" elements
Examples:
| dav-path-version |
| old |
@@ -48,14 +45,12 @@ Feature: dav-versions
| spaces |
Scenario Outline: upload a file twice and versions are available using various chunking methods (except new chunking)
Scenario Outline: versions are available while uploading a file twice with multiple chunks
Given using <dav-path-version> DAV path
When user "Alice" uploads file "filesForUpload/davtest.txt" to filenames based on "/davtest.txt" with all mechanisms except new chunking using the WebDAV API
And user "Alice" uploads file "filesForUpload/davtest.txt" to filenames based on "/davtest.txt" with all mechanisms except new chunking using the WebDAV API
Then the HTTP status code of all upload responses should be between "201" and "204"
And the version folder of file "/davtest.txt-olddav-regular" for user "Alice" should contain "1" element
And the version folder of file "/davtest.txt-newdav-regular" for user "Alice" should contain "1" element
And the version folder of file "/davtest.txt-olddav-oldchunking" for user "Alice" should contain "1" element
When user "Alice" uploads file "filesForUpload/davtest.txt" to "lorem.txt" in 2 chunks using the WebDAV API
And user "Alice" uploads file "filesForUpload/davtest.txt" to "lorem.txt" in 3 chunks using the WebDAV API
Then the HTTP status code of responses on all endpoints should be "201"
And the version folder of file "lorem.txt" for user "Alice" should contain "1" element
Examples:
| dav-path-version |
| old |