mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-23 22:29:59 -05:00
Copied acceptance tests infrastructures from oC/core
Signed-off-by: Kiran Parajuli <kiranparajuli589@gmail.com>
This commit is contained in:
committed by
Phil Davis
parent
b84f1f2048
commit
7d152e2ad1
@@ -16,5 +16,5 @@ exclude_paths:
|
||||
- 'tests/acceptance/expected-failures-*.md'
|
||||
- 'tests/acceptance/features/bootstrap/**'
|
||||
- 'tests/TestHelpers/**'
|
||||
|
||||
- 'tests/acceptance/run.sh'
|
||||
...
|
||||
|
||||
@@ -716,7 +716,6 @@ def localApiTestPipeline(ctx):
|
||||
"steps": skipIfUnchanged(ctx, "acceptance-tests") +
|
||||
restoreBuildArtifactCache(ctx, "ocis-binary-amd64", "ocis/bin") +
|
||||
ocisServer(storage, params["accounts_hash_difficulty"], extra_server_environment = params["extraServerEnvironment"]) +
|
||||
restoreBuildArtifactCache(ctx, "testrunner", dirs["core"]) +
|
||||
localApiTests(suite, storage, params["extraEnvironment"]) +
|
||||
failEarly(ctx, early_fail),
|
||||
"services": redisForOCStorage(storage),
|
||||
@@ -736,7 +735,6 @@ def localApiTests(suite, storage, extra_environment = {}):
|
||||
environment = {
|
||||
"TEST_WITH_GRAPH_API": "true",
|
||||
"PATH_TO_OCIS": dirs["base"],
|
||||
"PATH_TO_CORE": "%s/%s" % (dirs["base"], dirs["core"]),
|
||||
"TEST_SERVER_URL": "https://ocis-server:9200",
|
||||
"OCIS_REVA_DATA_ROOT": "%s" % (dirs["ocisRevaDataRoot"] if storage == "owncloud" else ""),
|
||||
"OCIS_SKELETON_STRATEGY": "%s" % ("copy" if storage == "owncloud" else "upload"),
|
||||
|
||||
4
Makefile
4
Makefile
@@ -106,11 +106,11 @@ PARALLEL_BEHAT_YML=tests/parallelDeployAcceptance/config/behat.yml
|
||||
|
||||
.PHONY: test-acceptance-api
|
||||
test-acceptance-api: vendor-bin/behat/vendor
|
||||
BEHAT_BIN=$(BEHAT_BIN) $(PATH_TO_CORE)/tests/acceptance/run.sh --remote --type api
|
||||
BEHAT_BIN=$(BEHAT_BIN) $(PWD)/tests/acceptance/run.sh --type api
|
||||
|
||||
.PHONY: test-paralleldeployment-api
|
||||
test-paralleldeployment-api: vendor-bin/behat/vendor
|
||||
BEHAT_BIN=$(BEHAT_BIN) BEHAT_YML=$(PARALLEL_BEHAT_YML) $(PATH_TO_CORE)/tests/acceptance/run.sh --type api
|
||||
BEHAT_BIN=$(BEHAT_BIN) BEHAT_YML=$(PARALLEL_BEHAT_YML) $(PWD)/tests/acceptance/run.sh --type api
|
||||
|
||||
vendor/bamarni/composer-bin-plugin: composer.lock
|
||||
composer install
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
"bamarni/composer-bin-plugin": true
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-simplexml": "*",
|
||||
"bamarni/composer-bin-plugin": "^1.4"
|
||||
},
|
||||
"extra": {
|
||||
|
||||
@@ -84,7 +84,7 @@ class GraphHelper {
|
||||
*/
|
||||
public static function getFullUrl(string $baseUrl, string $path): string {
|
||||
$fullUrl = $baseUrl;
|
||||
if (\substr($fullUrl, -1) !== '/') {
|
||||
if (!str_ends_with($fullUrl, '/')) {
|
||||
$fullUrl .= '/';
|
||||
}
|
||||
$fullUrl .= 'graph/v1.0/' . $path;
|
||||
|
||||
622
tests/TestHelpers/HttpRequestHelper.php
Normal file
622
tests/TestHelpers/HttpRequestHelper.php
Normal file
@@ -0,0 +1,622 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2017 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace TestHelpers;
|
||||
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use SimpleXMLElement;
|
||||
use Sabre\Xml\LibXMLException;
|
||||
use Sabre\Xml\Reader;
|
||||
use GuzzleHttp\Pool;
|
||||
|
||||
/**
|
||||
* Helper for HTTP requests
|
||||
*/
|
||||
class HttpRequestHelper {
|
||||
public const HTTP_TOO_EARLY = 425;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $oCSelectorCookie = null;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getOCSelectorCookie(): string {
|
||||
return self::$oCSelectorCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $oCSelectorCookie "owncloud-selector=oc10;path=/;"
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setOCSelectorCookie(string $oCSelectorCookie): void {
|
||||
self::$oCSelectorCookie = $oCSelectorCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some systems-under-test do async post-processing of operations like upload,
|
||||
* move etc. If a client does a request on the resource before the post-processing
|
||||
* is finished, then the server should return HTTP_TOO_EARLY "425". Clients are
|
||||
* expected to retry the request "some time later" (tm).
|
||||
*
|
||||
* On such systems, when HTTP_TOO_EARLY status is received, the test code will
|
||||
* retry the request at 1-second intervals until either some other HTTP status
|
||||
* is received or the retry-limit is reached.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function numRetriesOnHttpTooEarly():int {
|
||||
if (OcisHelper::isTestingOnOcisOrReva()) {
|
||||
// Currently reva and oCIS may return HTTP_TOO_EARLY
|
||||
// So try up to 10 times before giving up.
|
||||
return 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $url
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $method
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param array|null $headers ['X-MyHeader' => 'value']
|
||||
* @param mixed $body
|
||||
* @param array|null $config
|
||||
* @param CookieJar|null $cookies
|
||||
* @param bool $stream Set to true to stream a response rather
|
||||
* than download it all up-front.
|
||||
* @param int|null $timeout
|
||||
* @param Client|null $client
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public static function sendRequest(
|
||||
?string $url,
|
||||
?string $xRequestId,
|
||||
?string $method = 'GET',
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?array $headers = null,
|
||||
$body = null,
|
||||
?array $config = null,
|
||||
?CookieJar $cookies = null,
|
||||
bool $stream = false,
|
||||
?int $timeout = 0,
|
||||
?Client $client = null
|
||||
):ResponseInterface {
|
||||
if ($client === null) {
|
||||
$client = self::createClient(
|
||||
$user,
|
||||
$password,
|
||||
$config,
|
||||
$cookies,
|
||||
$stream,
|
||||
$timeout
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @var RequestInterface $request
|
||||
*/
|
||||
$request = self::createRequest(
|
||||
$url,
|
||||
$xRequestId,
|
||||
$method,
|
||||
$headers,
|
||||
$body
|
||||
);
|
||||
|
||||
if ((\getenv('DEBUG_ACCEPTANCE_REQUESTS') !== false) || (\getenv('DEBUG_ACCEPTANCE_API_CALLS') !== false)) {
|
||||
$debugRequests = true;
|
||||
} else {
|
||||
$debugRequests = false;
|
||||
}
|
||||
|
||||
if ((\getenv('DEBUG_ACCEPTANCE_RESPONSES') !== false) || (\getenv('DEBUG_ACCEPTANCE_API_CALLS') !== false)) {
|
||||
$debugResponses = true;
|
||||
} else {
|
||||
$debugResponses = false;
|
||||
}
|
||||
|
||||
if ($debugRequests) {
|
||||
self::debugRequest($request, $user, $password);
|
||||
}
|
||||
|
||||
$sendRetryLimit = self::numRetriesOnHttpTooEarly();
|
||||
$sendCount = 0;
|
||||
$sendExceptionHappened = false;
|
||||
|
||||
do {
|
||||
// The exceptions that might happen here include:
|
||||
// ConnectException - in that case there is no response. Don't catch the exception.
|
||||
// RequestException - if there is something in the response then pass it back.
|
||||
// otherwise re-throw the exception.
|
||||
// GuzzleException - something else unexpected happened. Don't catch the exception.
|
||||
try {
|
||||
$response = $client->send($request);
|
||||
} catch (RequestException $ex) {
|
||||
$sendExceptionHappened = true;
|
||||
$response = $ex->getResponse();
|
||||
|
||||
//if the response was null for some reason do not return it but re-throw
|
||||
if ($response === null) {
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
if ($debugResponses) {
|
||||
self::debugResponse($response);
|
||||
}
|
||||
$sendCount = $sendCount + 1;
|
||||
$loopAgain = !$sendExceptionHappened && ($response->getStatusCode() === self::HTTP_TOO_EARLY) && ($sendCount <= $sendRetryLimit);
|
||||
if ($loopAgain) {
|
||||
// we need to repeat the send request, because we got HTTP_TOO_EARLY
|
||||
// wait 1 second before sending again, to give the server some time
|
||||
// to finish whatever post-processing it might be doing.
|
||||
\sleep(1);
|
||||
}
|
||||
} while ($loopAgain);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print details about the request.
|
||||
*
|
||||
* @param RequestInterface|null $request
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function debugRequest(?RequestInterface $request, ?string $user, ?string $password):void {
|
||||
print("### AUTH: $user:$password\n");
|
||||
print("### REQUEST: " . $request->getMethod() . " " . $request->getUri() . "\n");
|
||||
self::printHeaders($request->getHeaders());
|
||||
self::printBody($request->getBody());
|
||||
print("\n### END REQUEST\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Print details about the response.
|
||||
*
|
||||
* @param ResponseInterface|null $response
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function debugResponse(?ResponseInterface $response):void {
|
||||
print("### RESPONSE\n");
|
||||
print("Status: " . $response->getStatusCode() . "\n");
|
||||
self::printHeaders($response->getHeaders());
|
||||
self::printBody($response->getBody());
|
||||
print("\n### END RESPONSE\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Print details about the headers.
|
||||
*
|
||||
* @param array|null $headers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function printHeaders(?array $headers):void {
|
||||
if ($headers) {
|
||||
print("Headers:\n");
|
||||
foreach ($headers as $header => $value) {
|
||||
if (\is_array($value)) {
|
||||
print($header . ": " . \implode(', ', $value) . "\n");
|
||||
} else {
|
||||
print($header . ": " . $value . "\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print("Headers: none\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print details about the body.
|
||||
*
|
||||
* @param StreamInterface|null $body
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function printBody(?StreamInterface $body):void {
|
||||
print("Body:\n");
|
||||
\var_dump($body->getContents());
|
||||
// Rewind the stream so that later code can read from the start.
|
||||
$body->rewind();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the requests to the server in parallel.
|
||||
* This function takes an array of requests and an optional client.
|
||||
* It will send all the requests to the server using the Pool object in guzzle.
|
||||
*
|
||||
* @param array|null $requests
|
||||
* @param Client|null $client
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function sendBatchRequest(
|
||||
?array $requests,
|
||||
?Client $client
|
||||
):array {
|
||||
$results = Pool::batch($client, $requests);
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Guzzle Client
|
||||
* This creates a client object that can be used later to send a request object(s)
|
||||
*
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param array|null $config
|
||||
* @param CookieJar|null $cookies
|
||||
* @param bool $stream Set to true to stream a response rather
|
||||
* than download it all up-front.
|
||||
* @param int|null $timeout
|
||||
*
|
||||
* @return Client
|
||||
*/
|
||||
public static function createClient(
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?array $config = null,
|
||||
?CookieJar $cookies = null,
|
||||
?bool $stream = false,
|
||||
?int $timeout = 0
|
||||
):Client {
|
||||
$options = [];
|
||||
if ($user !== null) {
|
||||
$options['auth'] = [$user, $password];
|
||||
}
|
||||
if ($config !== null) {
|
||||
$options['config'] = $config;
|
||||
}
|
||||
if ($cookies !== null) {
|
||||
$options['cookies'] = $cookies;
|
||||
}
|
||||
$options['stream'] = $stream;
|
||||
$options['verify'] = false;
|
||||
$options['timeout'] = $timeout;
|
||||
$client = new Client($options);
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an http request based on given parameters.
|
||||
* This creates a RequestInterface object that can be used with a client to send a request.
|
||||
* This enables us to create multiple requests in advance so that we can send them to the server at once in parallel.
|
||||
*
|
||||
* @param string|null $url
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $method
|
||||
* @param array|null $headers ['X-MyHeader' => 'value']
|
||||
* @param string|array $body either the actual string to send in the body,
|
||||
* or an array of key-value pairs to be converted
|
||||
* into a body with http_build_query.
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public static function createRequest(
|
||||
?string $url,
|
||||
?string $xRequestId = '',
|
||||
?string $method = 'GET',
|
||||
?array $headers = null,
|
||||
$body = null
|
||||
):RequestInterface {
|
||||
if ($headers === null) {
|
||||
$headers = [];
|
||||
}
|
||||
if ($xRequestId !== '') {
|
||||
$headers['X-Request-ID'] = $xRequestId;
|
||||
}
|
||||
if (\is_array($body)) {
|
||||
// when creating the client, it is possible to set 'form_params' and
|
||||
// the Client constructor sorts out doing this http_build_query stuff.
|
||||
// But 'new Request' does not have the flexibility to do that.
|
||||
// So we need to do it here.
|
||||
$body = \http_build_query($body, '', '&');
|
||||
$headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
if (OcisHelper::isTestingParallelDeployment()) {
|
||||
// oCIS cannot handle '/apps/testing' endpoints
|
||||
// so those requests must be redirected to oC10 server
|
||||
// change server to oC10 if the request url has `/apps/testing`
|
||||
if (strpos($url, "/apps/testing") !== false) {
|
||||
$oCISServerUrl = \getenv('TEST_SERVER_URL');
|
||||
$oC10ServerUrl = \getenv('TEST_OC10_URL');
|
||||
$url = str_replace($oCISServerUrl, $oC10ServerUrl, $url);
|
||||
} else {
|
||||
// set 'owncloud-server' selector cookie for oCIS requests
|
||||
$headers['Cookie'] = self::getOCSelectorCookie();
|
||||
}
|
||||
}
|
||||
|
||||
$request = new Request(
|
||||
$method,
|
||||
$url,
|
||||
$headers,
|
||||
$body
|
||||
);
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* same as HttpRequestHelper::sendRequest() but with "GET" as method
|
||||
*
|
||||
* @param string|null $url
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param array|null $headers ['X-MyHeader' => 'value']
|
||||
* @param mixed $body
|
||||
* @param array|null $config
|
||||
* @param CookieJar|null $cookies
|
||||
* @param boolean $stream
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
* @see HttpRequestHelper::sendRequest()
|
||||
*/
|
||||
public static function get(
|
||||
?string $url,
|
||||
?string $xRequestId,
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?array $headers = null,
|
||||
$body = null,
|
||||
?array $config = null,
|
||||
?CookieJar $cookies = null,
|
||||
?bool $stream = false
|
||||
):ResponseInterface {
|
||||
return self::sendRequest(
|
||||
$url,
|
||||
$xRequestId,
|
||||
'GET',
|
||||
$user,
|
||||
$password,
|
||||
$headers,
|
||||
$body,
|
||||
$config,
|
||||
$cookies,
|
||||
$stream
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* same as HttpRequestHelper::sendRequest() but with "POST" as method
|
||||
*
|
||||
* @param string|null $url
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param array|null $headers ['X-MyHeader' => 'value']
|
||||
* @param mixed $body
|
||||
* @param array|null $config
|
||||
* @param CookieJar|null $cookies
|
||||
* @param boolean $stream
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
* @see HttpRequestHelper::sendRequest()
|
||||
*/
|
||||
public static function post(
|
||||
?string $url,
|
||||
?string $xRequestId,
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?array $headers = null,
|
||||
$body = null,
|
||||
?array $config = null,
|
||||
?CookieJar $cookies = null,
|
||||
?bool $stream = false
|
||||
):ResponseInterface {
|
||||
return self::sendRequest(
|
||||
$url,
|
||||
$xRequestId,
|
||||
'POST',
|
||||
$user,
|
||||
$password,
|
||||
$headers,
|
||||
$body,
|
||||
$config,
|
||||
$cookies,
|
||||
$stream
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* same as HttpRequestHelper::sendRequest() but with "PUT" as method
|
||||
*
|
||||
* @param string|null $url
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param array|null $headers ['X-MyHeader' => 'value']
|
||||
* @param mixed $body
|
||||
* @param array|null $config
|
||||
* @param CookieJar|null $cookies
|
||||
* @param boolean $stream
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
* @see HttpRequestHelper::sendRequest()
|
||||
*/
|
||||
public static function put(
|
||||
?string $url,
|
||||
?string $xRequestId,
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?array $headers = null,
|
||||
$body = null,
|
||||
?array $config = null,
|
||||
?CookieJar $cookies = null,
|
||||
?bool $stream = false
|
||||
):ResponseInterface {
|
||||
return self::sendRequest(
|
||||
$url,
|
||||
$xRequestId,
|
||||
'PUT',
|
||||
$user,
|
||||
$password,
|
||||
$headers,
|
||||
$body,
|
||||
$config,
|
||||
$cookies,
|
||||
$stream
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* same as HttpRequestHelper::sendRequest() but with "DELETE" as method
|
||||
*
|
||||
* @param string|null $url
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param array|null $headers ['X-MyHeader' => 'value']
|
||||
* @param mixed $body
|
||||
* @param array|null $config
|
||||
* @param CookieJar|null $cookies
|
||||
* @param boolean $stream
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
* @see HttpRequestHelper::sendRequest()
|
||||
*
|
||||
*/
|
||||
public static function delete(
|
||||
?string $url,
|
||||
?string $xRequestId,
|
||||
?string $user = null,
|
||||
?string $password = null,
|
||||
?array $headers = null,
|
||||
$body = null,
|
||||
?array $config = null,
|
||||
?CookieJar $cookies = null,
|
||||
?bool $stream = false
|
||||
):ResponseInterface {
|
||||
return self::sendRequest(
|
||||
$url,
|
||||
$xRequestId,
|
||||
'DELETE',
|
||||
$user,
|
||||
$password,
|
||||
$headers,
|
||||
$body,
|
||||
$config,
|
||||
$cookies,
|
||||
$stream
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response as XML and returns a SimpleXMLElement with these
|
||||
* registered namespaces:
|
||||
* | prefix | namespace |
|
||||
* | d | DAV: |
|
||||
* | oc | http://owncloud.org/ns |
|
||||
* | ocs | http://open-collaboration-services.org/ns |
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param string|null $exceptionText text to put at the front of exception messages
|
||||
*
|
||||
* @return SimpleXMLElement
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getResponseXml(ResponseInterface $response, ?string $exceptionText = ''):SimpleXMLElement {
|
||||
// rewind just to make sure we can re-parse it in case it was parsed already...
|
||||
$response->getBody()->rewind();
|
||||
$contents = $response->getBody()->getContents();
|
||||
try {
|
||||
$responseXmlObject = new SimpleXMLElement($contents);
|
||||
$responseXmlObject->registerXPathNamespace(
|
||||
'ocs',
|
||||
'http://open-collaboration-services.org/ns'
|
||||
);
|
||||
$responseXmlObject->registerXPathNamespace(
|
||||
'oc',
|
||||
'http://owncloud.org/ns'
|
||||
);
|
||||
$responseXmlObject->registerXPathNamespace(
|
||||
'd',
|
||||
'DAV:'
|
||||
);
|
||||
return $responseXmlObject;
|
||||
} catch (Exception $e) {
|
||||
if ($exceptionText !== '') {
|
||||
$exceptionText = $exceptionText . ' ';
|
||||
}
|
||||
if ($contents === '') {
|
||||
throw new Exception($exceptionText . "Received empty response where XML was expected");
|
||||
}
|
||||
$message = $exceptionText . "Exception parsing response body: \"" . $contents . "\"";
|
||||
throw new Exception($message, 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parses the body content of $response and returns an array representing the XML
|
||||
* This function returns an array with the following three elements:
|
||||
* * name - The root element name.
|
||||
* * value - The value for the root element.
|
||||
* * attributes - An array of attributes.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function parseResponseAsXml(ResponseInterface $response):array {
|
||||
$body = $response->getBody()->getContents();
|
||||
$parsedResponse = [];
|
||||
if ($body && \substr($body, 0, 1) === '<') {
|
||||
try {
|
||||
$reader = new Reader();
|
||||
$reader->xml($body);
|
||||
$parsedResponse = $reader->parse();
|
||||
} catch (LibXMLException $e) {
|
||||
// Sometimes the body can be a real page of HTML and text.
|
||||
// So it may not be a complete ordinary piece of XML.
|
||||
// The XML parse might fail with an exception message like:
|
||||
// Opening and ending tag mismatch: link line 31 and head.
|
||||
}
|
||||
}
|
||||
return $parsedResponse;
|
||||
}
|
||||
}
|
||||
364
tests/TestHelpers/OcisHelper.php
Normal file
364
tests/TestHelpers/OcisHelper.php
Normal file
@@ -0,0 +1,364 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2020 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace TestHelpers;
|
||||
|
||||
use Exception;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
/**
|
||||
* Class OcisHelper
|
||||
*
|
||||
* Helper functions that are needed to run tests on OCIS
|
||||
*
|
||||
* @package TestHelpers
|
||||
*/
|
||||
class OcisHelper {
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTestingOnOcis():bool {
|
||||
return (\getenv("TEST_OCIS") === "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTestingOnReva():bool {
|
||||
return (\getenv("TEST_REVA") === "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTestingOnOcisOrReva():bool {
|
||||
return (self::isTestingOnOcis() || self::isTestingOnReva());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTestingOnOc10():bool {
|
||||
return (!self::isTestingOnOcisOrReva());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTestingParallelDeployment(): bool {
|
||||
return (\getenv("TEST_PARALLEL_DEPLOYMENT") === "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTestingWithGraphApi(): bool {
|
||||
return \getenv('TEST_WITH_GRAPH_API') === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string false if no command given or the command as string
|
||||
*/
|
||||
public static function getDeleteUserDataCommand() {
|
||||
$cmd = \getenv("DELETE_USER_DATA_CMD");
|
||||
if ($cmd === false || \trim($cmd) === "") {
|
||||
return false;
|
||||
}
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getStorageDriver():string {
|
||||
$storageDriver = (\getenv("STORAGE_DRIVER"));
|
||||
if ($storageDriver === false) {
|
||||
return "OWNCLOUD";
|
||||
}
|
||||
$storageDriver = \strtoupper($storageDriver);
|
||||
if ($storageDriver !== "OCIS" && $storageDriver !== "EOS" && $storageDriver !== "OWNCLOUD" && $storageDriver !== "S3NG") {
|
||||
throw new Exception(
|
||||
"Invalid storage driver. " .
|
||||
"STORAGE_DRIVER must be OCIS|EOS|OWNCLOUD|S3NG"
|
||||
);
|
||||
}
|
||||
return $storageDriver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $user
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function deleteRevaUserData(?string $user = ""):void {
|
||||
$deleteCmd = self::getDeleteUserDataCommand();
|
||||
if ($deleteCmd === false) {
|
||||
if (self::getStorageDriver() === "OWNCLOUD") {
|
||||
self::recurseRmdir(self::getOcisRevaDataRoot() . $user);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (self::getStorageDriver() === "EOS") {
|
||||
$deleteCmd = \str_replace(
|
||||
"%s",
|
||||
$user[0] . '/' . $user,
|
||||
$deleteCmd
|
||||
);
|
||||
} else {
|
||||
$deleteCmd = \sprintf($deleteCmd, $user);
|
||||
}
|
||||
\exec($deleteCmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for Recursive Copy of file/folder
|
||||
* For more info check this out https://gist.github.com/gserrano/4c9648ec9eb293b9377b
|
||||
*
|
||||
* @param string|null $source
|
||||
* @param string|null $destination
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function recurseCopy(?string $source, ?string $destination):void {
|
||||
$dir = \opendir($source);
|
||||
@\mkdir($destination);
|
||||
while (($file = \readdir($dir)) !== false) {
|
||||
if (($file != '.') && ($file != '..')) {
|
||||
if (\is_dir($source . '/' . $file)) {
|
||||
self::recurseCopy($source . '/' . $file, $destination . '/' . $file);
|
||||
} else {
|
||||
\copy($source . '/' . $file, $destination . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
\closedir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for Recursive Upload of file/folder
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $source
|
||||
* @param string|null $userId
|
||||
* @param string|null $password
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $destination
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function recurseUpload(
|
||||
?string $baseUrl,
|
||||
?string $source,
|
||||
?string $userId,
|
||||
?string $password,
|
||||
?string $xRequestId = '',
|
||||
?string $destination = ''
|
||||
):void {
|
||||
if ($destination !== '') {
|
||||
$response = WebDavHelper::makeDavRequest(
|
||||
$baseUrl,
|
||||
$userId,
|
||||
$password,
|
||||
"MKCOL",
|
||||
$destination,
|
||||
[],
|
||||
$xRequestId
|
||||
);
|
||||
if ($response->getStatusCode() !== 201) {
|
||||
throw new Exception("Could not create folder destination" . $response->getBody()->getContents());
|
||||
}
|
||||
}
|
||||
|
||||
$dir = \opendir($source);
|
||||
while (($file = \readdir($dir)) !== false) {
|
||||
if (($file != '.') && ($file != '..')) {
|
||||
$sourcePath = $source . '/' . $file;
|
||||
$destinationPath = $destination . '/' . $file;
|
||||
if (\is_dir($sourcePath)) {
|
||||
self::recurseUpload(
|
||||
$baseUrl,
|
||||
$sourcePath,
|
||||
$userId,
|
||||
$password,
|
||||
$xRequestId,
|
||||
$destinationPath
|
||||
);
|
||||
} else {
|
||||
$response = UploadHelper::upload(
|
||||
$baseUrl,
|
||||
$userId,
|
||||
$password,
|
||||
$sourcePath,
|
||||
$destinationPath,
|
||||
$xRequestId
|
||||
);
|
||||
$responseStatus = $response->getStatusCode();
|
||||
if ($responseStatus !== 201) {
|
||||
throw new Exception(
|
||||
"Could not upload skeleton file $sourcePath to $destinationPath for user '$userId' status '$responseStatus' response body: '"
|
||||
. $response->getBody()->getContents() . "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
\closedir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public static function getLdapPort():int {
|
||||
$port = \getenv("REVA_LDAP_PORT");
|
||||
return $port ? (int)$port : 636;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function useSsl():bool {
|
||||
$useSsl = \getenv("REVA_LDAP_USESSL");
|
||||
if ($useSsl === false) {
|
||||
return (self::getLdapPort() === 636);
|
||||
} else {
|
||||
return $useSsl === "true";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getBaseDN():string {
|
||||
$dn = \getenv("REVA_LDAP_BASE_DN");
|
||||
return $dn ? $dn : "dc=owncloud,dc=com";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getGroupsOU():string {
|
||||
$ou = \getenv("REVA_LDAP_GROUPS_OU");
|
||||
return $ou ? $ou : "TestGroups";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getUsersOU():string {
|
||||
$ou = \getenv("REVA_LDAP_USERS_OU");
|
||||
return $ou ? $ou : "TestUsers";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getGroupSchema():string {
|
||||
$schema = \getenv("REVA_LDAP_GROUP_SCHEMA");
|
||||
return $schema ? $schema : "rfc2307";
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getHostname():string {
|
||||
$hostname = \getenv("REVA_LDAP_HOSTNAME");
|
||||
return $hostname ? $hostname : "localhost";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getBindDN():string {
|
||||
$dn = \getenv("REVA_LDAP_BIND_DN");
|
||||
return $dn ? $dn : "cn=admin,dc=owncloud,dc=com";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getBindPassword():string {
|
||||
$pw = \getenv("REVA_LDAP_BIND_PASSWORD");
|
||||
return $pw ? $pw : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private static function getOcisRevaDataRoot():string {
|
||||
$root = \getenv("OCIS_REVA_DATA_ROOT");
|
||||
if (($root === false || $root === "") && self::isTestingOnOcisOrReva()) {
|
||||
$root = "/var/tmp/ocis/owncloud/";
|
||||
}
|
||||
if (!\file_exists($root)) {
|
||||
echo "WARNING: reva data root folder ($root) does not exist\n";
|
||||
}
|
||||
return $root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $dir
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function recurseRmdir(?string $dir):bool {
|
||||
if (\file_exists($dir) === true) {
|
||||
$files = \array_diff(\scandir($dir), ['.', '..']);
|
||||
foreach ($files as $file) {
|
||||
if (\is_dir("$dir/$file")) {
|
||||
self::recurseRmdir("$dir/$file");
|
||||
} else {
|
||||
\unlink("$dir/$file");
|
||||
}
|
||||
}
|
||||
return \rmdir($dir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* On Eos storage backend when the user data is cleared after test run
|
||||
* Running another test immediately fails. So Send this request to create user home directory
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string|null $xRequestId
|
||||
*
|
||||
* @return void
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public static function createEOSStorageHome(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $xRequestId = ''
|
||||
):void {
|
||||
HttpRequestHelper::get(
|
||||
$baseUrl . "/ocs/v2.php/apps/notifications/api/v1/notifications",
|
||||
$xRequestId,
|
||||
$user,
|
||||
$password
|
||||
);
|
||||
}
|
||||
}
|
||||
103
tests/TestHelpers/OcsApiHelper.php
Normal file
103
tests/TestHelpers/OcsApiHelper.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2017 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace TestHelpers;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Helper to make requests to the OCS API
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
*
|
||||
*/
|
||||
class OcsApiHelper {
|
||||
/**
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user if set to null no authentication header will be sent
|
||||
* @param string|null $password
|
||||
* @param string|null $method HTTP Method
|
||||
* @param string|null $path
|
||||
* @param string|null $xRequestId
|
||||
* @param mixed $body array of key, value pairs e.g ['value' => 'yes']
|
||||
* @param int|null $ocsApiVersion (1|2) default 2
|
||||
* @param array|null $headers
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public static function sendRequest(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $method,
|
||||
?string $path,
|
||||
?string $xRequestId = '',
|
||||
$body = [],
|
||||
?int $ocsApiVersion = 2,
|
||||
?array $headers = []
|
||||
):ResponseInterface {
|
||||
$fullUrl = $baseUrl;
|
||||
if (\substr($fullUrl, -1) !== '/') {
|
||||
$fullUrl .= '/';
|
||||
}
|
||||
$fullUrl .= "ocs/v{$ocsApiVersion}.php" . $path;
|
||||
$headers['OCS-APIREQUEST'] = true;
|
||||
return HttpRequestHelper::sendRequest($fullUrl, $xRequestId, $method, $user, $password, $headers, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $method HTTP Method
|
||||
* @param string|null $path
|
||||
* @param string|null $xRequestId
|
||||
* @param mixed $body array of key, value pairs e.g ['value' => 'yes']
|
||||
* @param int|null $ocsApiVersion (1|2) default 2
|
||||
* @param array|null $headers
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public static function createOcsRequest(
|
||||
?string $baseUrl,
|
||||
?string $method,
|
||||
?string $path,
|
||||
?string $xRequestId = '',
|
||||
$body = [],
|
||||
?int $ocsApiVersion = 2,
|
||||
?array $headers = []
|
||||
):RequestInterface {
|
||||
$fullUrl = $baseUrl;
|
||||
if (\substr($fullUrl, -1) !== '/') {
|
||||
$fullUrl .= '/';
|
||||
}
|
||||
$fullUrl .= "ocs/v{$ocsApiVersion}.php" . $path;
|
||||
return HttpRequestHelper::createRequest(
|
||||
$fullUrl,
|
||||
$xRequestId,
|
||||
$method,
|
||||
$headers,
|
||||
$body
|
||||
);
|
||||
}
|
||||
}
|
||||
1268
tests/TestHelpers/SetupHelper.php
Normal file
1268
tests/TestHelpers/SetupHelper.php
Normal file
File diff suppressed because it is too large
Load Diff
261
tests/TestHelpers/SharingHelper.php
Normal file
261
tests/TestHelpers/SharingHelper.php
Normal file
@@ -0,0 +1,261 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2017 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace TestHelpers;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use SimpleXMLElement;
|
||||
|
||||
/**
|
||||
* manage Shares via OCS API
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
*
|
||||
*/
|
||||
class SharingHelper {
|
||||
public const PERMISSION_TYPES = [
|
||||
'read' => 1,
|
||||
'update' => 2,
|
||||
'create' => 4,
|
||||
'delete' => 8,
|
||||
'share' => 16,
|
||||
];
|
||||
|
||||
public const SHARE_TYPES = [
|
||||
'user' => 0,
|
||||
'group' => 1,
|
||||
'public_link' => 3,
|
||||
'federated' => 6,
|
||||
];
|
||||
|
||||
public const SHARE_STATES = [
|
||||
'accepted' => 0,
|
||||
'pending' => 1,
|
||||
'rejected' => 2,
|
||||
'declined' => 2, // declined is a synonym for rejected
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $baseUrl baseURL of the ownCloud installation without /ocs.
|
||||
* @param string $user user that creates the share.
|
||||
* @param string $password password of the user that creates the share.
|
||||
* @param string $path The path to the file or folder which should be shared.
|
||||
* @param string|int $shareType The type of the share. This can be one of:
|
||||
* 0 = user, 1 = group, 3 = public (link),
|
||||
* 6 = federated (cloud share).
|
||||
* Pass either the number or the keyword.
|
||||
* @param string $xRequestId
|
||||
* @param string|null $shareWith The user or group id with which the file should
|
||||
* be shared.
|
||||
* @param boolean|null $publicUpload Whether to allow public upload to a public
|
||||
* shared folder.
|
||||
* @param string|null $sharePassword The password to protect the public link
|
||||
* share with.
|
||||
* @param string|int|string[]|int[]|null $permissions The permissions to set on the share.
|
||||
* 1 = read; 2 = update; 4 = create;
|
||||
* 8 = delete; 16 = share
|
||||
* (default: 31, for public shares: 1)
|
||||
* Pass either the (total) number or array of numbers,
|
||||
* or any of the above keywords or array of keywords.
|
||||
* @param string|null $linkName A (human-readable) name for the share,
|
||||
* which can be up to 64 characters in length.
|
||||
* @param string|null $expireDate An expire date for public link shares.
|
||||
* This argument expects a date string
|
||||
* in the format 'YYYY-MM-DD'.
|
||||
* @param int $ocsApiVersion
|
||||
* @param int $sharingApiVersion
|
||||
* @param string $sharingApp
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function createShare(
|
||||
string $baseUrl,
|
||||
string $user,
|
||||
string $password,
|
||||
string $path,
|
||||
$shareType,
|
||||
string $xRequestId = '',
|
||||
?string $shareWith = null,
|
||||
?bool $publicUpload = false,
|
||||
string $sharePassword = null,
|
||||
$permissions = null,
|
||||
?string $linkName = null,
|
||||
?string $expireDate = null,
|
||||
int $ocsApiVersion = 1,
|
||||
int $sharingApiVersion = 1,
|
||||
string $sharingApp = 'files_sharing'
|
||||
): ResponseInterface {
|
||||
$fd = [];
|
||||
foreach ([$path, $baseUrl, $user, $password] as $variableToCheck) {
|
||||
if (!\is_string($variableToCheck)) {
|
||||
throw new InvalidArgumentException(
|
||||
"mandatory argument missing or wrong type ($variableToCheck => "
|
||||
. \gettype($variableToCheck) . ")"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($permissions !== null) {
|
||||
$fd['permissions'] = self::getPermissionSum($permissions);
|
||||
}
|
||||
|
||||
if (!\in_array($ocsApiVersion, [1, 2], true)) {
|
||||
throw new InvalidArgumentException(
|
||||
"invalid ocsApiVersion ($ocsApiVersion)"
|
||||
);
|
||||
}
|
||||
if (!\in_array($sharingApiVersion, [1, 2], true)) {
|
||||
throw new InvalidArgumentException(
|
||||
"invalid sharingApiVersion ($sharingApiVersion)"
|
||||
);
|
||||
}
|
||||
|
||||
$fullUrl = $baseUrl;
|
||||
if (\substr($fullUrl, -1) !== '/') {
|
||||
$fullUrl .= '/';
|
||||
}
|
||||
$fullUrl .= "ocs/v{$ocsApiVersion}.php/apps/{$sharingApp}/api/v{$sharingApiVersion}/shares";
|
||||
|
||||
$fd['path'] = $path;
|
||||
$fd['shareType'] = self::getShareType($shareType);
|
||||
|
||||
if ($shareWith !== null) {
|
||||
$fd['shareWith'] = $shareWith;
|
||||
}
|
||||
if ($publicUpload !== null) {
|
||||
$fd['publicUpload'] = (bool) $publicUpload;
|
||||
}
|
||||
if ($sharePassword !== null) {
|
||||
$fd['password'] = $sharePassword;
|
||||
}
|
||||
if ($linkName !== null) {
|
||||
$fd['name'] = $linkName;
|
||||
}
|
||||
if ($expireDate !== null) {
|
||||
$fd['expireDate'] = $expireDate;
|
||||
}
|
||||
$headers = ['OCS-APIREQUEST' => 'true'];
|
||||
|
||||
return HttpRequestHelper::post(
|
||||
$fullUrl,
|
||||
$xRequestId,
|
||||
$user,
|
||||
$password,
|
||||
$headers,
|
||||
$fd
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates the permission sum (int) from given permissions
|
||||
* permissions can be passed in as int, string or array of int or string
|
||||
* 'read' => 1
|
||||
* 'update' => 2
|
||||
* 'create' => 4
|
||||
* 'delete' => 8
|
||||
* 'share' => 16
|
||||
*
|
||||
* @param string[]|string|int|int[] $permissions
|
||||
*
|
||||
* @return int
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
*/
|
||||
public static function getPermissionSum($permissions):int {
|
||||
if (\is_numeric($permissions)) {
|
||||
// Allow any permission number so that test scenarios can
|
||||
// specifically test invalid permission values
|
||||
return (int) $permissions;
|
||||
}
|
||||
if (!\is_array($permissions)) {
|
||||
$permissions = [$permissions];
|
||||
}
|
||||
$permissionSum = 0;
|
||||
foreach ($permissions as $permission) {
|
||||
if (\array_key_exists($permission, self::PERMISSION_TYPES)) {
|
||||
$permissionSum += self::PERMISSION_TYPES[$permission];
|
||||
} elseif (\in_array($permission, self::PERMISSION_TYPES, true)) {
|
||||
$permissionSum += (int) $permission;
|
||||
} else {
|
||||
throw new InvalidArgumentException(
|
||||
"invalid permission type ($permission)"
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($permissionSum < 1 || $permissionSum > 31) {
|
||||
throw new InvalidArgumentException(
|
||||
"invalid permission total ($permissionSum)"
|
||||
);
|
||||
}
|
||||
return $permissionSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the share type number corresponding to the share type keyword
|
||||
*
|
||||
* @param string|int $shareType a keyword from SHARE_TYPES or a share type number
|
||||
*
|
||||
* @return int
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
*/
|
||||
public static function getShareType($shareType):int {
|
||||
if (\array_key_exists($shareType, self::SHARE_TYPES)) {
|
||||
return self::SHARE_TYPES[$shareType];
|
||||
} else {
|
||||
if (\ctype_digit($shareType)) {
|
||||
$shareType = (int) $shareType;
|
||||
}
|
||||
$key = \array_search($shareType, self::SHARE_TYPES, true);
|
||||
if ($key !== false) {
|
||||
return self::SHARE_TYPES[$key];
|
||||
}
|
||||
throw new InvalidArgumentException(
|
||||
"invalid share type ($shareType)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param SimpleXMLElement $responseXmlObject
|
||||
* @param string $errorMessage
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*
|
||||
*/
|
||||
public static function getLastShareIdFromResponse(
|
||||
SimpleXMLElement $responseXmlObject,
|
||||
string $errorMessage = "cannot find share id in response"
|
||||
):string {
|
||||
$xmlPart = $responseXmlObject->xpath("//data/element[last()]/id");
|
||||
|
||||
if (!\is_array($xmlPart) || (\count($xmlPart) === 0)) {
|
||||
throw new Exception($errorMessage);
|
||||
}
|
||||
return $xmlPart[0]->__toString();
|
||||
}
|
||||
}
|
||||
14
tests/TestHelpers/SpaceNotFoundException.php
Normal file
14
tests/TestHelpers/SpaceNotFoundException.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Sagar Gurung <sagar@jankatitech.com>
|
||||
*
|
||||
*/
|
||||
namespace TestHelpers;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class SpaceNotFoundException
|
||||
* Exception when space id for a user is not found
|
||||
*/
|
||||
class SpaceNotFoundException extends Exception {
|
||||
}
|
||||
46
tests/TestHelpers/TranslationHelper.php
Normal file
46
tests/TestHelpers/TranslationHelper.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Talank Baral <talank@jankaritech.com>
|
||||
* @copyright Copyright (c) 2021 Talank Baral talank@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace TestHelpers;
|
||||
|
||||
/**
|
||||
* Class TranslationHelper
|
||||
*
|
||||
* Helper functions that are needed to run tests on different languages
|
||||
*
|
||||
* @package TestHelpers
|
||||
*/
|
||||
class TranslationHelper {
|
||||
/**
|
||||
* @param string|null $language
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getLanguage(?string $language): ?string {
|
||||
if (!isset($language)) {
|
||||
if (\getenv('OC_LANGUAGE') !== false) {
|
||||
$language = \getenv('OC_LANGUAGE');
|
||||
}
|
||||
}
|
||||
return $language;
|
||||
}
|
||||
}
|
||||
318
tests/TestHelpers/UploadHelper.php
Normal file
318
tests/TestHelpers/UploadHelper.php
Normal file
@@ -0,0 +1,318 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2017 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace TestHelpers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Helper for Uploads
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
*
|
||||
*/
|
||||
class UploadHelper extends \PHPUnit\Framework\Assert {
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl URL of owncloud
|
||||
* e.g. http://localhost:8080
|
||||
* should include the subfolder
|
||||
* if owncloud runs in a subfolder
|
||||
* e.g. http://localhost:8080/owncloud-core
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string|null $source
|
||||
* @param string|null $destination
|
||||
* @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 int|null $noOfChunks how many chunks do we want to upload
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function upload(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $source,
|
||||
?string $destination,
|
||||
?string $xRequestId = '',
|
||||
?array $headers = [],
|
||||
?int $davPathVersionToUse = 1,
|
||||
?int $chunkingVersion = null,
|
||||
?int $noOfChunks = 1
|
||||
): ResponseInterface {
|
||||
//simple upload with no chunking
|
||||
if ($chunkingVersion === null) {
|
||||
$data = \file_get_contents($source);
|
||||
return WebDavHelper::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
"PUT",
|
||||
$destination,
|
||||
$headers,
|
||||
$xRequestId,
|
||||
$data,
|
||||
$davPathVersionToUse
|
||||
);
|
||||
} else {
|
||||
//prepare chunking
|
||||
$chunks = self::chunkFile($source, $noOfChunks);
|
||||
$chunkingId = 'chunking-' . (string)\rand(1000, 9999);
|
||||
$v2ChunksDestination = '/uploads/' . $user . '/' . $chunkingId;
|
||||
}
|
||||
|
||||
//prepare chunking version specific stuff
|
||||
if ($chunkingVersion === 1) {
|
||||
$headers['OC-Chunked'] = '1';
|
||||
} elseif ($chunkingVersion === 2) {
|
||||
$result = WebDavHelper::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
'MKCOL',
|
||||
$v2ChunksDestination,
|
||||
$headers,
|
||||
$xRequestId,
|
||||
null,
|
||||
$davPathVersionToUse,
|
||||
"uploads"
|
||||
);
|
||||
if ($result->getStatusCode() >= 400) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
//upload chunks
|
||||
foreach ($chunks as $index => $chunk) {
|
||||
if ($chunkingVersion === 1) {
|
||||
$filename = $destination . "-" . $chunkingId . "-" .
|
||||
\count($chunks) . '-' . ( string ) $index;
|
||||
$davRequestType = "files";
|
||||
} elseif ($chunkingVersion === 2) {
|
||||
$filename = $v2ChunksDestination . '/' . (string)($index);
|
||||
$davRequestType = "uploads";
|
||||
}
|
||||
$result = WebDavHelper::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
"PUT",
|
||||
$filename,
|
||||
$headers,
|
||||
$xRequestId,
|
||||
$chunk,
|
||||
$davPathVersionToUse,
|
||||
$davRequestType
|
||||
);
|
||||
if ($result->getStatusCode() >= 400) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
//finish upload for new chunking
|
||||
if ($chunkingVersion === 2) {
|
||||
$source = $v2ChunksDestination . '/.file';
|
||||
$headers['Destination'] = $baseUrl . "/" .
|
||||
WebDavHelper::getDavPath($user, $davPathVersionToUse) .
|
||||
$destination;
|
||||
$result = WebDavHelper::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
'MOVE',
|
||||
$source,
|
||||
$headers,
|
||||
$xRequestId,
|
||||
null,
|
||||
$davPathVersionToUse,
|
||||
"uploads"
|
||||
);
|
||||
if ($result->getStatusCode() >= 400) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
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
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @param string|null $file
|
||||
* @param int|null $noOfChunks
|
||||
*
|
||||
* @return array $string
|
||||
*/
|
||||
public static function chunkFile(?string $file, ?int $noOfChunks = 1):array {
|
||||
$size = \filesize($file);
|
||||
$chunkSize = \ceil($size / $noOfChunks);
|
||||
$chunks = [];
|
||||
$fp = \fopen($file, 'r');
|
||||
while (!\feof($fp) && \ftell($fp) < $size) {
|
||||
$chunks[] = \fread($fp, (int)$chunkSize);
|
||||
}
|
||||
\fclose($fp);
|
||||
if (\count($chunks) === 0) {
|
||||
// chunk an empty file
|
||||
$chunks[] = '';
|
||||
}
|
||||
return $chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a File with a specific size
|
||||
*
|
||||
* @param string|null $name full path of the file to create
|
||||
* @param int|null $size
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function createFileSpecificSize(?string $name, ?int $size):void {
|
||||
if (\file_exists($name)) {
|
||||
\unlink($name);
|
||||
}
|
||||
$file = \fopen($name, 'w');
|
||||
\fseek($file, \max($size - 1, 0), SEEK_CUR);
|
||||
if ($size) {
|
||||
\fwrite($file, 'a'); // write a dummy char at SIZE position
|
||||
}
|
||||
\fclose($file);
|
||||
self::assertEquals(
|
||||
1,
|
||||
\file_exists($name)
|
||||
);
|
||||
self::assertEquals(
|
||||
$size,
|
||||
\filesize($name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a File with a specific text content
|
||||
*
|
||||
* @param string|null $name full path of the file to create
|
||||
* @param string|null $text
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function createFileWithText(?string $name, ?string $text):void {
|
||||
$file = \fopen($name, 'w');
|
||||
\fwrite($file, $text);
|
||||
\fclose($file);
|
||||
self::assertEquals(
|
||||
1,
|
||||
\file_exists($name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the path of a file from FilesForUpload directory
|
||||
*
|
||||
* @param string|null $name name of the file to upload
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getUploadFilesDir(?string $name):string {
|
||||
return \getenv("FILES_FOR_UPLOAD") . $name;
|
||||
}
|
||||
}
|
||||
375
tests/TestHelpers/UserHelper.php
Normal file
375
tests/TestHelpers/UserHelper.php
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2017 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace TestHelpers;
|
||||
|
||||
use Exception;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Helper to administrate users (and groups) through the provisioning API
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
*
|
||||
*/
|
||||
class UserHelper {
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string $user
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @param string $adminUser
|
||||
* @param string $adminPassword
|
||||
* @param string $xRequestId
|
||||
* @param int|null $ocsApiVersion
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function editUser(
|
||||
?string $baseUrl,
|
||||
string $user,
|
||||
string $key,
|
||||
string $value,
|
||||
string $adminUser,
|
||||
string $adminPassword,
|
||||
string $xRequestId = '',
|
||||
?int $ocsApiVersion = 2
|
||||
):ResponseInterface {
|
||||
return OcsApiHelper::sendRequest(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
"PUT",
|
||||
"/cloud/users/" . $user,
|
||||
$xRequestId,
|
||||
["key" => $key, "value" => $value],
|
||||
$ocsApiVersion
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send batch requests to edit the user.
|
||||
* This will send multiple requests in parallel to the server which will be faster in comparison to waiting for each request to complete.
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param array|null $editData ['user' => '', 'key' => '', 'value' => '']
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $ocsApiVersion
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function editUserBatch(
|
||||
?string $baseUrl,
|
||||
?array $editData,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId = '',
|
||||
?int $ocsApiVersion = 2
|
||||
):array {
|
||||
$requests = [];
|
||||
$client = HttpRequestHelper::createClient(
|
||||
$adminUser,
|
||||
$adminPassword
|
||||
);
|
||||
|
||||
foreach ($editData as $data) {
|
||||
$path = "/cloud/users/" . $data['user'];
|
||||
$body = ["key" => $data['key'], 'value' => $data["value"]];
|
||||
// Create the OCS API requests and push them to an array.
|
||||
\array_push(
|
||||
$requests,
|
||||
OcsApiHelper::createOcsRequest(
|
||||
$baseUrl,
|
||||
'PUT',
|
||||
$path,
|
||||
$xRequestId,
|
||||
$body
|
||||
)
|
||||
);
|
||||
}
|
||||
// Send the array of requests at once in parallel.
|
||||
$results = HttpRequestHelper::sendBatchRequest($requests, $client);
|
||||
|
||||
foreach ($results as $e) {
|
||||
if ($e instanceof ClientException) {
|
||||
$httpStatusCode = $e->getResponse()->getStatusCode();
|
||||
$reasonPhrase = $e->getResponse()->getReasonPhrase();
|
||||
throw new Exception(
|
||||
"Unexpected failure when editing a user: HTTP status $httpStatusCode HTTP reason $reasonPhrase"
|
||||
);
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $userName
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $ocsApiVersion
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function getUser(
|
||||
?string $baseUrl,
|
||||
?string $userName,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId = '',
|
||||
?int $ocsApiVersion = 2
|
||||
):ResponseInterface {
|
||||
return OcsApiHelper::sendRequest(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
"GET",
|
||||
"/cloud/users/" . $userName,
|
||||
$xRequestId,
|
||||
[],
|
||||
$ocsApiVersion
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $userName
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $ocsApiVersion
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function deleteUser(
|
||||
?string $baseUrl,
|
||||
?string $userName,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId = '',
|
||||
?int $ocsApiVersion = 2
|
||||
):ResponseInterface {
|
||||
return OcsApiHelper::sendRequest(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
"DELETE",
|
||||
"/cloud/users/" . $userName,
|
||||
$xRequestId,
|
||||
[],
|
||||
$ocsApiVersion
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $group
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function createGroup(
|
||||
?string $baseUrl,
|
||||
?string $group,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId = ''
|
||||
):ResponseInterface {
|
||||
return OcsApiHelper::sendRequest(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
"POST",
|
||||
"/cloud/groups",
|
||||
$xRequestId,
|
||||
['groupid' => $group]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $group
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $ocsApiVersion
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function deleteGroup(
|
||||
?string $baseUrl,
|
||||
?string $group,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId = '',
|
||||
?int $ocsApiVersion = 2
|
||||
):ResponseInterface {
|
||||
$group = \rawurlencode($group);
|
||||
return OcsApiHelper::sendRequest(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
"DELETE",
|
||||
"/cloud/groups/" . $group,
|
||||
$xRequestId,
|
||||
[],
|
||||
$ocsApiVersion
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user
|
||||
* @param string|null $group
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $ocsApiVersion (1|2)
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function addUserToGroup(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $group,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId = '',
|
||||
?int $ocsApiVersion = 2
|
||||
):ResponseInterface {
|
||||
return OcsApiHelper::sendRequest(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
"POST",
|
||||
"/cloud/users/" . $user . "/groups",
|
||||
$xRequestId,
|
||||
['groupid' => $group],
|
||||
$ocsApiVersion
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user
|
||||
* @param string|null $group
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $ocsApiVersion (1|2)
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function removeUserFromGroup(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $group,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId,
|
||||
?int $ocsApiVersion = 2
|
||||
):ResponseInterface {
|
||||
return OcsApiHelper::sendRequest(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
"DELETE",
|
||||
"/cloud/users/" . $user . "/groups",
|
||||
$xRequestId,
|
||||
['groupid' => $group],
|
||||
$ocsApiVersion
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $search
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function getGroups(
|
||||
?string $baseUrl,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId = '',
|
||||
?string $search =""
|
||||
):ResponseInterface {
|
||||
return OcsApiHelper::sendRequest(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
"GET",
|
||||
"/cloud/groups?search=" . $search,
|
||||
$xRequestId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $adminUser
|
||||
* @param string|null $adminPassword
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $search
|
||||
*
|
||||
* @return string[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getGroupsAsArray(
|
||||
?string $baseUrl,
|
||||
?string $adminUser,
|
||||
?string $adminPassword,
|
||||
?string $xRequestId = '',
|
||||
?string $search = ""
|
||||
):array {
|
||||
$result = self::getGroups(
|
||||
$baseUrl,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
$xRequestId,
|
||||
$search
|
||||
);
|
||||
$groups = HttpRequestHelper::getResponseXml($result, __METHOD__)->xpath(".//groups")[0];
|
||||
$return = [];
|
||||
foreach ($groups as $group) {
|
||||
$return[] = $group->__toString();
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
898
tests/TestHelpers/WebDavHelper.php
Normal file
898
tests/TestHelpers/WebDavHelper.php
Normal file
@@ -0,0 +1,898 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2017 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace TestHelpers;
|
||||
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use DateTime;
|
||||
use TestHelpers\SpaceNotFoundException;
|
||||
|
||||
/**
|
||||
* Helper to make WebDav Requests
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
*
|
||||
*/
|
||||
class WebDavHelper {
|
||||
public const DAV_VERSION_OLD = 1;
|
||||
public const DAV_VERSION_NEW = 2;
|
||||
public const DAV_VERSION_SPACES = 3;
|
||||
public static $SPACE_ID_FROM_OCIS = '';
|
||||
|
||||
/**
|
||||
* @var array of users with their different spaces ids
|
||||
*/
|
||||
public static $spacesIdRef = [];
|
||||
|
||||
/**
|
||||
* clear space id reference for user
|
||||
*
|
||||
* @param string|null $user
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function removeSpaceIdReferenceForUser(
|
||||
?string $user
|
||||
):void {
|
||||
if (\array_key_exists($user, self::$spacesIdRef)) {
|
||||
unset(self::$spacesIdRef[$user]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the id of a file
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string|null $path
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $davPathVersionToUse
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getFileIdForPath(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $path,
|
||||
?string $xRequestId = '',
|
||||
?int $davPathVersionToUse = self::DAV_VERSION_NEW
|
||||
): string {
|
||||
$body
|
||||
= '<?xml version="1.0"?>
|
||||
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
|
||||
<d:prop>
|
||||
<oc:fileid />
|
||||
</d:prop>
|
||||
</d:propfind>';
|
||||
$response = self::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
"PROPFIND",
|
||||
$path,
|
||||
null,
|
||||
$xRequestId,
|
||||
$body,
|
||||
$davPathVersionToUse
|
||||
);
|
||||
\preg_match(
|
||||
'/\<oc:fileid\>([^\<]*)\<\/oc:fileid\>/',
|
||||
$response->getBody()->getContents(),
|
||||
$matches
|
||||
);
|
||||
|
||||
if (!isset($matches[1])) {
|
||||
throw new Exception("could not find fileId of $path");
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns body for propfind
|
||||
*
|
||||
* @param array|null $properties
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getBodyForPropfind(?array $properties): string {
|
||||
$propertyBody = "";
|
||||
$extraNamespaces = "";
|
||||
foreach ($properties as $namespaceString => $property) {
|
||||
if (\is_int($namespaceString)) {
|
||||
//default namespace prefix if the property has no array key
|
||||
//also used if no prefix is given in the property value
|
||||
$namespacePrefix = "d";
|
||||
} else {
|
||||
//calculate the namespace prefix and namespace from the array key
|
||||
$matches = [];
|
||||
\preg_match("/^(.*)='(.*)'$/", $namespaceString, $matches);
|
||||
$nameSpace = $matches[2];
|
||||
$namespacePrefix = $matches[1];
|
||||
$extraNamespaces .= " xmlns:$namespacePrefix=\"$nameSpace\" ";
|
||||
}
|
||||
//if a namespace prefix is given in the property value use that
|
||||
if (\strpos($property, ":") !== false) {
|
||||
$propertyParts = \explode(":", $property);
|
||||
$namespacePrefix = $propertyParts[0];
|
||||
$property = $propertyParts[1];
|
||||
}
|
||||
$propertyBody .= "<$namespacePrefix:$property/>";
|
||||
}
|
||||
$body = "<?xml version=\"1.0\"?>
|
||||
<d:propfind
|
||||
xmlns:d=\"DAV:\"
|
||||
xmlns:oc=\"http://owncloud.org/ns\"
|
||||
xmlns:ocs=\"http://open-collaboration-services.org/ns\"
|
||||
$extraNamespaces>
|
||||
<d:prop>$propertyBody</d:prop>
|
||||
</d:propfind>";
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a PROPFIND request
|
||||
* with these registered namespaces:
|
||||
* | prefix | namespace |
|
||||
* | d | DAV: |
|
||||
* | oc | http://owncloud.org/ns |
|
||||
* | ocs | http://open-collaboration-services.org/ns |
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string|null $path
|
||||
* @param string[] $properties
|
||||
* string can contain namespace prefix,
|
||||
* if no prefix is given 'd:' is used as prefix
|
||||
* if associated array is used then the key will be used as namespace
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $folderDepth
|
||||
* @param string|null $type
|
||||
* @param int|null $davPathVersionToUse
|
||||
* @param string|null $doDavRequestAsUser
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function propfind(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $path,
|
||||
?array $properties,
|
||||
?string $xRequestId = '',
|
||||
?string $folderDepth = '0',
|
||||
?string $type = "files",
|
||||
?int $davPathVersionToUse = self::DAV_VERSION_NEW,
|
||||
?string $doDavRequestAsUser = null
|
||||
):ResponseInterface {
|
||||
$body = self::getBodyForPropfind($properties);
|
||||
$folderDepth = (string) $folderDepth;
|
||||
if ($folderDepth !== '0' && $folderDepth !== '1' && $folderDepth !== 'infinity') {
|
||||
throw new InvalidArgumentException('Invalid depth value ' . $folderDepth);
|
||||
}
|
||||
$headers = ['Depth' => $folderDepth];
|
||||
return self::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
"PROPFIND",
|
||||
$path,
|
||||
$headers,
|
||||
$xRequestId,
|
||||
$body,
|
||||
$davPathVersionToUse,
|
||||
$type,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
[],
|
||||
$doDavRequestAsUser
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string|null $path
|
||||
* @param string|null $propertyName
|
||||
* @param string|null $propertyValue
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null $namespaceString string containing prefix and namespace
|
||||
* e.g "x1='http://whatever.org/ns'"
|
||||
* @param int|null $davPathVersionToUse
|
||||
* @param string|null $type
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function proppatch(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $path,
|
||||
?string $propertyName,
|
||||
?string $propertyValue,
|
||||
?string $xRequestId = '',
|
||||
?string $namespaceString = "oc='http://owncloud.org/ns'",
|
||||
?int $davPathVersionToUse = self::DAV_VERSION_NEW,
|
||||
?string $type="files"
|
||||
):ResponseInterface {
|
||||
$matches = [];
|
||||
\preg_match("/^(.*)='(.*)'$/", $namespaceString, $matches);
|
||||
$namespace = $matches[2];
|
||||
$namespacePrefix = $matches[1];
|
||||
$propertyBody = "<$namespacePrefix:$propertyName" .
|
||||
" xmlns:$namespacePrefix=\"$namespace\">" .
|
||||
"$propertyValue" .
|
||||
"</$namespacePrefix:$propertyName>";
|
||||
$body = "<?xml version=\"1.0\"?>
|
||||
<d:propertyupdate xmlns:d=\"DAV:\"
|
||||
xmlns:oc=\"http://owncloud.org/ns\">
|
||||
<d:set>
|
||||
<d:prop>$propertyBody</d:prop>
|
||||
</d:set>
|
||||
</d:propertyupdate>";
|
||||
return self::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
"PROPPATCH",
|
||||
$path,
|
||||
[],
|
||||
$xRequestId,
|
||||
$body,
|
||||
$davPathVersionToUse,
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets namespace-prefix, namespace url and propName from provided namespaceString or property
|
||||
* or otherwise use default
|
||||
*
|
||||
* @param string|null $namespaceString
|
||||
* @param string|null $property
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getPropertyWithNamespaceInfo(?string $namespaceString = "", ?string $property = ""):array {
|
||||
$namespace = "";
|
||||
$namespacePrefix = "";
|
||||
if (\is_int($namespaceString)) {
|
||||
//default namespace prefix if the property has no array key
|
||||
//also used if no prefix is given in the property value
|
||||
$namespacePrefix = "d";
|
||||
$namespace = "DAV:";
|
||||
} elseif ($namespaceString) {
|
||||
//calculate the namespace prefix and namespace from the array key
|
||||
$matches = [];
|
||||
\preg_match("/^(.*)='(.*)'$/", $namespaceString, $matches);
|
||||
$namespacePrefix = $matches[1];
|
||||
$namespace = $matches[2];
|
||||
}
|
||||
//if a namespace prefix is given in the property value use that
|
||||
if ($property && \strpos($property, ":")) {
|
||||
$propertyParts = \explode(":", $property);
|
||||
$namespacePrefix = $propertyParts[0];
|
||||
$property = $propertyParts[1];
|
||||
}
|
||||
return [$namespacePrefix, $namespace, $property];
|
||||
}
|
||||
|
||||
/**
|
||||
* sends HTTP request PROPPATCH method with multiple properties
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string $path
|
||||
* @param array|null $propertiesArray
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $davPathVersion
|
||||
* @param string|null $namespaceString
|
||||
* @param string|null $type
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public static function proppatchWithMultipleProps(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
string $path,
|
||||
?array $propertiesArray,
|
||||
?string $xRequestId = '',
|
||||
?int $davPathVersion = null,
|
||||
?string $namespaceString = "oc='http://owncloud.org/ns'",
|
||||
?string $type="files"
|
||||
):ResponseInterface {
|
||||
$propertyBody = "";
|
||||
foreach ($propertiesArray as $propertyArray) {
|
||||
$property = $propertyArray["propertyName"];
|
||||
$value = $propertyArray["propertyValue"];
|
||||
[$namespacePrefix, $namespace, $property] = self::getPropertyWithNamespaceInfo(
|
||||
$namespaceString,
|
||||
$property
|
||||
);
|
||||
$propertyBody .= "\n\t<$namespacePrefix:$property>" .
|
||||
"$value" .
|
||||
"</$namespacePrefix:$property>";
|
||||
}
|
||||
$body = "<?xml version=\"1.0\"?>
|
||||
<d:propertyupdate xmlns:d=\"DAV:\"
|
||||
xmlns:oc=\"http://owncloud.org/ns\">
|
||||
<d:set>
|
||||
<d:prop>$propertyBody
|
||||
</d:prop>
|
||||
</d:set>
|
||||
</d:propertyupdate>";
|
||||
return self::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
"PROPPATCH",
|
||||
$path,
|
||||
[],
|
||||
$xRequestId,
|
||||
$body,
|
||||
$davPathVersion,
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the response to listing a folder (collection)
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string|null $path
|
||||
* @param string|null $folderDepth
|
||||
* @param string|null $xRequestId
|
||||
* @param string[] $properties
|
||||
* @param string|null $type
|
||||
* @param int|null $davPathVersionToUse
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public static function listFolder(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $path,
|
||||
?string $folderDepth,
|
||||
?string $xRequestId = '',
|
||||
?array $properties = null,
|
||||
?string $type = "files",
|
||||
?int $davPathVersionToUse = self::DAV_VERSION_NEW
|
||||
):ResponseInterface {
|
||||
if (!$properties) {
|
||||
$properties = [
|
||||
'getetag', 'resourcetype'
|
||||
];
|
||||
}
|
||||
return self::propfind(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
$path,
|
||||
$properties,
|
||||
$xRequestId,
|
||||
$folderDepth,
|
||||
$type,
|
||||
$davPathVersionToUse
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates UUIDv4
|
||||
* Example: 123e4567-e89b-12d3-a456-426614174000
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function generateUUIDv4():string {
|
||||
// generate 16 bytes (128 bits) of random data or use the data passed into the function.
|
||||
$data = random_bytes(16);
|
||||
\assert(\strlen($data) == 16);
|
||||
|
||||
$data[6] = \chr(\ord($data[6]) & 0x0f | 0x40); // set version to 0100
|
||||
$data[8] = \chr(\ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
|
||||
|
||||
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* fetches personal space id for provided user
|
||||
*
|
||||
* @param string $baseUrl
|
||||
* @param string $user
|
||||
* @param string $password
|
||||
* @param string $xRequestId
|
||||
*
|
||||
* @return string
|
||||
* @throws GuzzleException
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getPersonalSpaceIdForUser(string $baseUrl, string $user, string $password, string $xRequestId):string {
|
||||
if (\array_key_exists($user, self::$spacesIdRef) && \array_key_exists("personal", self::$spacesIdRef[$user])) {
|
||||
return self::$spacesIdRef[$user]["personal"];
|
||||
}
|
||||
$trimmedBaseUrl = \trim($baseUrl, "/");
|
||||
$drivesPath = '/graph/v1.0/me/drives';
|
||||
$fullUrl = $trimmedBaseUrl . $drivesPath;
|
||||
$response = HttpRequestHelper::get(
|
||||
$fullUrl,
|
||||
$xRequestId,
|
||||
$user,
|
||||
$password
|
||||
);
|
||||
$bodyContents = $response->getBody()->getContents();
|
||||
$json = \json_decode($bodyContents);
|
||||
$personalSpaceId = '';
|
||||
if ($json === null) {
|
||||
// the graph endpoint did not give a useful answer
|
||||
// try getting the information from the webdav endpoint
|
||||
$fullUrl = $trimmedBaseUrl . '/remote.php/webdav';
|
||||
$response = HttpRequestHelper::sendRequest(
|
||||
$fullUrl,
|
||||
$xRequestId,
|
||||
'PROPFIND',
|
||||
$user,
|
||||
$password
|
||||
);
|
||||
// we expect to get a multipart XML response with status 207
|
||||
$status = $response->getStatusCode();
|
||||
if ($status === 401) {
|
||||
throw new SpaceNotFoundException(__METHOD__ . " Personal space not found for user " . $user);
|
||||
} elseif ($status !== 207) {
|
||||
throw new Exception(
|
||||
__METHOD__ . " webdav propfind for user $user failed with status $status - so the personal space id cannot be discovered"
|
||||
);
|
||||
}
|
||||
$responseXmlObject = HttpRequestHelper::getResponseXml(
|
||||
$response,
|
||||
__METHOD__
|
||||
);
|
||||
$xmlPart = $responseXmlObject->xpath("/d:multistatus/d:response[1]/d:propstat/d:prop/oc:id");
|
||||
if ($xmlPart === false) {
|
||||
throw new Exception(
|
||||
__METHOD__ . " oc:id not found in webdav propfind for user $user - so the personal space id cannot be discovered"
|
||||
);
|
||||
}
|
||||
$ocIdRawString = $xmlPart[0]->__toString();
|
||||
$separator = "!";
|
||||
if (\strpos($ocIdRawString, $separator) !== false) {
|
||||
// The string is not base64-encoded, because the exclamation mark is not in the base64 alphabet.
|
||||
// We expect to have a string with 2 parts separated by the exclamation mark.
|
||||
// This is the format introduced in 2022-02
|
||||
// oc:id should be something like:
|
||||
// "7464caf6-1799-103c-9046-c7b74deb5f63!7464caf6-1799-103c-9046-c7b74deb5f63"
|
||||
// There is no encoding to decode.
|
||||
$decodedId = $ocIdRawString;
|
||||
} else {
|
||||
// fall-back to assuming that the oc:id is base64-encoded
|
||||
// That is the format used before and up to 2022-02
|
||||
// This can be removed after both the edge and master branches of cs3org/reva are using the new format.
|
||||
// oc:id should be some base64 encoded string like:
|
||||
// "NzQ2NGNhZjYtMTc5OS0xMDNjLTkwNDYtYzdiNzRkZWI1ZjYzOjc0NjRjYWY2LTE3OTktMTAzYy05MDQ2LWM3Yjc0ZGViNWY2Mw=="
|
||||
// That should decode to something like:
|
||||
// "7464caf6-1799-103c-9046-c7b74deb5f63:7464caf6-1799-103c-9046-c7b74deb5f63"
|
||||
$decodedId = base64_decode($ocIdRawString);
|
||||
$separator = ":";
|
||||
}
|
||||
$ocIdParts = \explode($separator, $decodedId);
|
||||
if (\count($ocIdParts) !== 2) {
|
||||
throw new Exception(
|
||||
__METHOD__ . " the oc:id $decodedId for user $user does not have 2 parts separated by '$separator', so the personal space id cannot be discovered"
|
||||
);
|
||||
}
|
||||
$personalSpaceId = $ocIdParts[0];
|
||||
} else {
|
||||
foreach ($json->value as $spaces) {
|
||||
if ($spaces->driveType === "personal") {
|
||||
$personalSpaceId = $spaces->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($personalSpaceId) {
|
||||
// If env var LOG_PERSONAL_SPACE_ID is defined, then output the details of the personal space id.
|
||||
// This is a useful debugging tool to have confidence that the personal space id is found correctly.
|
||||
if (\getenv('LOG_PERSONAL_SPACE_ID') !== false) {
|
||||
echo __METHOD__ . " personal space id of user $user is $personalSpaceId\n";
|
||||
}
|
||||
self::$spacesIdRef[$user] = [];
|
||||
self::$spacesIdRef[$user]["personal"] = $personalSpaceId;
|
||||
return $personalSpaceId;
|
||||
} else {
|
||||
throw new SpaceNotFoundException(__METHOD__ . " Personal space not found for user " . $user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* First checks if a user exist to return its space ID
|
||||
* In case of any exception, it returns a fake space ID
|
||||
*
|
||||
* @param string $baseUrl
|
||||
* @param string $user
|
||||
* @param string $password
|
||||
* @param string $xRequestId
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getPersonalSpaceIdForUserOrFakeIfNotFound(string $baseUrl, string $user, string $password, string $xRequestId):string {
|
||||
try {
|
||||
$spaceId = self::getPersonalSpaceIdForUser(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
$xRequestId,
|
||||
);
|
||||
} catch (SpaceNotFoundException $e) {
|
||||
// if the fetch fails, and the user is not found, then a fake space id is prepared
|
||||
// this is useful for testing when the personal space is of a non-existing user
|
||||
$fakeSpaceId = self::generateUUIDv4();
|
||||
self::$spacesIdRef[$user]["personal"] = $fakeSpaceId;
|
||||
$spaceId = $fakeSpaceId;
|
||||
}
|
||||
return $spaceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a DAV request
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* URL of owncloud e.g. http://localhost:8080
|
||||
* should include the subfolder if owncloud runs in a subfolder
|
||||
* e.g. http://localhost:8080/owncloud-core
|
||||
* @param string|null $user
|
||||
* @param string|null $password or token when bearer auth is used
|
||||
* @param string|null $method PUT, GET, DELETE, etc.
|
||||
* @param string|null $path
|
||||
* @param array|null $headers
|
||||
* @param string|null $xRequestId
|
||||
* @param string|null|resource|StreamInterface $body
|
||||
* @param int|null $davPathVersionToUse (1|2|3)
|
||||
* @param string|null $type of request
|
||||
* @param string|null $sourceIpAddress to initiate the request from
|
||||
* @param string|null $authType basic|bearer
|
||||
* @param bool $stream Set to true to stream a response rather
|
||||
* than download it all up-front.
|
||||
* @param int|null $timeout
|
||||
* @param Client|null $client
|
||||
* @param array|null $urlParameter to concatenate with path
|
||||
* @param string|null $doDavRequestAsUser run the DAV as this user, if null its same as $user
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function makeDavRequest(
|
||||
?string $baseUrl,
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $method,
|
||||
?string $path,
|
||||
?array $headers,
|
||||
?string $xRequestId = '',
|
||||
$body = null,
|
||||
?int $davPathVersionToUse = self::DAV_VERSION_OLD,
|
||||
?string $type = "files",
|
||||
?string $sourceIpAddress = null,
|
||||
?string $authType = "basic",
|
||||
?bool $stream = false,
|
||||
?int $timeout = 0,
|
||||
?Client $client = null,
|
||||
?array $urlParameter = [],
|
||||
?string $doDavRequestAsUser = null
|
||||
):ResponseInterface {
|
||||
$baseUrl = self::sanitizeUrl($baseUrl, true);
|
||||
|
||||
// We need to manipulate and use path as a string.
|
||||
// So ensure that it is a string to avoid any type-conversion errors.
|
||||
if ($path === null) {
|
||||
$path = "";
|
||||
}
|
||||
|
||||
// get space id if testing with spaces dav
|
||||
if (self::$SPACE_ID_FROM_OCIS === '' && $davPathVersionToUse === self::DAV_VERSION_SPACES) {
|
||||
$spaceId = self::getPersonalSpaceIdForUserOrFakeIfNotFound(
|
||||
$baseUrl,
|
||||
$doDavRequestAsUser ?? $user,
|
||||
$password,
|
||||
$xRequestId
|
||||
);
|
||||
} else {
|
||||
$spaceId = self::$SPACE_ID_FROM_OCIS;
|
||||
}
|
||||
|
||||
$davPath = self::getDavPath($doDavRequestAsUser ?? $user, $davPathVersionToUse, $type, $spaceId);
|
||||
|
||||
//replace %, # and ? and in the path, Guzzle will not encode them
|
||||
$urlSpecialChar = [['%', '#', '?'], ['%25', '%23', '%3F']];
|
||||
$path = \str_replace($urlSpecialChar[0], $urlSpecialChar[1], $path);
|
||||
|
||||
if (!empty($urlParameter)) {
|
||||
$urlParameter = \http_build_query($urlParameter, '', '&');
|
||||
$path .= '?' . $urlParameter;
|
||||
}
|
||||
$fullUrl = self::sanitizeUrl($baseUrl . $davPath . $path);
|
||||
|
||||
if ($authType === 'bearer') {
|
||||
$headers['Authorization'] = 'Bearer ' . $password;
|
||||
$user = null;
|
||||
$password = null;
|
||||
}
|
||||
if ($type === "public-files-new") {
|
||||
if ($password === null || $password === "") {
|
||||
$user = null;
|
||||
} else {
|
||||
$user = "public";
|
||||
}
|
||||
}
|
||||
$config = null;
|
||||
if ($sourceIpAddress !== null) {
|
||||
$config = [ 'curl' => [ CURLOPT_INTERFACE => $sourceIpAddress ]];
|
||||
}
|
||||
|
||||
if ($headers !== null) {
|
||||
foreach ($headers as $key => $value) {
|
||||
//? and # need to be encoded in the Destination URL
|
||||
if ($key === "Destination") {
|
||||
$headers[$key] = \str_replace(
|
||||
$urlSpecialChar[0],
|
||||
$urlSpecialChar[1],
|
||||
$value
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Clear the space ID from ocis after each request
|
||||
self::$SPACE_ID_FROM_OCIS = '';
|
||||
return HttpRequestHelper::sendRequest(
|
||||
$fullUrl,
|
||||
$xRequestId,
|
||||
$method,
|
||||
$user,
|
||||
$password,
|
||||
$headers,
|
||||
$body,
|
||||
$config,
|
||||
null,
|
||||
$stream,
|
||||
$timeout,
|
||||
$client
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the dav path
|
||||
*
|
||||
* @param string|null $user
|
||||
* @param int|null $davPathVersionToUse (1|2)
|
||||
* @param string|null $type
|
||||
* @param string|null $spaceId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getDavPath(
|
||||
?string $user,
|
||||
?int $davPathVersionToUse = null,
|
||||
?string $type = "files",
|
||||
?string $spaceId = null
|
||||
):string {
|
||||
$newTrashbinDavPath = "remote.php/dav/trash-bin/$user/";
|
||||
if ($type === "public-files" || $type === "public-files-old") {
|
||||
return "public.php/webdav/";
|
||||
}
|
||||
if ($type === "public-files-new") {
|
||||
return "remote.php/dav/public-files/$user/";
|
||||
}
|
||||
if ($type === "archive") {
|
||||
return "remote.php/dav/archive/$user/files";
|
||||
}
|
||||
if ($type === "customgroups") {
|
||||
return "remote.php/dav/";
|
||||
}
|
||||
if ($davPathVersionToUse === self::DAV_VERSION_SPACES) {
|
||||
if (($spaceId === null) || (\strlen($spaceId) === 0)) {
|
||||
throw new InvalidArgumentException(
|
||||
__METHOD__ . " A spaceId must be passed when using DAV path version 3 (spaces)"
|
||||
);
|
||||
}
|
||||
if ($type === "trash-bin") {
|
||||
return "/remote.php/dav/spaces/trash-bin/" . $spaceId . '/';
|
||||
}
|
||||
return "dav/spaces/" . $spaceId . '/';
|
||||
} else {
|
||||
if ($davPathVersionToUse === self::DAV_VERSION_OLD) {
|
||||
if ($type === "trash-bin") {
|
||||
// Since there is no trash bin endpoint for old dav version, new dav version's endpoint is used here.
|
||||
return $newTrashbinDavPath;
|
||||
}
|
||||
return "remote.php/webdav/";
|
||||
} elseif ($davPathVersionToUse === self::DAV_VERSION_NEW) {
|
||||
if ($type === "files") {
|
||||
$path = 'remote.php/dav/files/';
|
||||
return $path . $user . '/';
|
||||
} elseif ($type === "trash-bin") {
|
||||
return $newTrashbinDavPath;
|
||||
} else {
|
||||
return "remote.php/dav";
|
||||
}
|
||||
} else {
|
||||
throw new InvalidArgumentException(
|
||||
"DAV path version $davPathVersionToUse is unknown"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* make sure there are no double slash in the URL
|
||||
*
|
||||
* @param string|null $url
|
||||
* @param bool|null $trailingSlash forces a trailing slash
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function sanitizeUrl(?string $url, ?bool $trailingSlash = false):string {
|
||||
if ($trailingSlash === true) {
|
||||
$url = $url . "/";
|
||||
} else {
|
||||
$url = \rtrim($url, "/");
|
||||
}
|
||||
$url = \preg_replace("/([^:]\/)\/+/", '$1', $url);
|
||||
return $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
|
||||
*
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $fileName
|
||||
* @param string|null $token
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $davVersionToUse
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getMtimeOfFileinPublicLinkShare(
|
||||
?string $baseUrl,
|
||||
?string $fileName,
|
||||
?string $token,
|
||||
?string $xRequestId = '',
|
||||
?int $davVersionToUse = self::DAV_VERSION_NEW
|
||||
):string {
|
||||
$response = self::propfind(
|
||||
$baseUrl,
|
||||
null,
|
||||
null,
|
||||
"/public-files/{$token}/{$fileName}",
|
||||
['d:getlastmodified'],
|
||||
$xRequestId,
|
||||
'1',
|
||||
null,
|
||||
$davVersionToUse
|
||||
);
|
||||
$responseXmlObject = HttpRequestHelper::getResponseXml(
|
||||
$response,
|
||||
__METHOD__
|
||||
);
|
||||
$xmlPart = $responseXmlObject->xpath("//d:getlastmodified");
|
||||
|
||||
return $xmlPart[0]->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* get Mtime of a resource
|
||||
*
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string|null $baseUrl
|
||||
* @param string|null $resource
|
||||
* @param string|null $xRequestId
|
||||
* @param int|null $davPathVersionToUse
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getMtimeOfResource(
|
||||
?string $user,
|
||||
?string $password,
|
||||
?string $baseUrl,
|
||||
?string $resource,
|
||||
?string $xRequestId = '',
|
||||
?int $davPathVersionToUse = self::DAV_VERSION_NEW
|
||||
):string {
|
||||
$response = self::propfind(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
$resource,
|
||||
["getlastmodified"],
|
||||
$xRequestId,
|
||||
"0",
|
||||
"files",
|
||||
$davPathVersionToUse
|
||||
);
|
||||
$responseXmlObject = HttpRequestHelper::getResponseXml(
|
||||
$response,
|
||||
__METHOD__
|
||||
);
|
||||
$xmlpart = $responseXmlObject->xpath("//d:getlastmodified");
|
||||
Assert::assertArrayHasKey(
|
||||
0,
|
||||
$xmlpart,
|
||||
__METHOD__ . " XML part does not have key 0. Expected a value at index 0 of 'xmlPart' but, found: " . (string) json_encode($xmlpart)
|
||||
);
|
||||
$mtime = new DateTime($xmlpart[0]->__toString());
|
||||
return $mtime->format('U');
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ default:
|
||||
- WebDavPropertiesContext:
|
||||
- TUSContext:
|
||||
- SpacesTUSContext:
|
||||
|
||||
|
||||
apiContract:
|
||||
paths:
|
||||
- '%paths.base%/../features/apiContract'
|
||||
@@ -152,4 +152,6 @@ default:
|
||||
- TrashbinContext:
|
||||
|
||||
extensions:
|
||||
rdx\behatvars\BehatVariablesExtension: ~
|
||||
|
||||
Cjm\Behat\StepThroughExtension: ~
|
||||
|
||||
591
tests/acceptance/features/bootstrap/AppConfigurationContext.php
Normal file
591
tests/acceptance/features/bootstrap/AppConfigurationContext.php
Normal file
@@ -0,0 +1,591 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Joas Schilling <coding@schilljs.com>
|
||||
* @author Sergio Bertolin <sbertolin@owncloud.com>
|
||||
* @author Phillip Davis <phil@jankaritech.com>
|
||||
* @copyright Copyright (c) 2018, ownCloud GmbH
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use TestHelpers\AppConfigHelper;
|
||||
use TestHelpers\OcsApiHelper;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use Behat\Behat\Context\Context;
|
||||
|
||||
/**
|
||||
* AppConfiguration trait
|
||||
*/
|
||||
class AppConfigurationContext implements Context {
|
||||
/**
|
||||
* @var FeatureContext
|
||||
*/
|
||||
private $featureContext;
|
||||
|
||||
/**
|
||||
* @When /^the administrator sets parameter "([^"]*)" of app "([^"]*)" to ((?:'[^']*')|(?:"[^"]*"))$/
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param string $app
|
||||
* @param string $value
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function adminSetsServerParameterToUsingAPI(
|
||||
string $parameter,
|
||||
string $app,
|
||||
string $value
|
||||
):void {
|
||||
// The capturing group of the regex always includes the quotes at each
|
||||
// end of the captured string, so trim them.
|
||||
$value = \trim($value, $value[0]);
|
||||
$this->modifyAppConfig($app, $parameter, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^parameter "([^"]*)" of app "([^"]*)" has been set to ((?:'[^']*')|(?:"[^"]*"))$/
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param string $app
|
||||
* @param string $value
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function serverParameterHasBeenSetTo(string $parameter, string $app, string $value):void {
|
||||
// The capturing group of the regex always includes the quotes at each
|
||||
// end of the captured string, so trim them.
|
||||
if (\TestHelpers\OcisHelper::isTestingOnOcisOrReva()) {
|
||||
return;
|
||||
}
|
||||
$value = \trim($value, $value[0]);
|
||||
$this->modifyAppConfig($app, $parameter, $value);
|
||||
$this->featureContext->clearStatusCodeArrays();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the capabilities setting of :capabilitiesApp path :capabilitiesPath should be :expectedValue
|
||||
* @Given the capabilities setting of :capabilitiesApp path :capabilitiesPath has been confirmed to be :expectedValue
|
||||
*
|
||||
* @param string $capabilitiesApp the "app" name in the capabilities response
|
||||
* @param string $capabilitiesPath the path to the element
|
||||
* @param string $expectedValue
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theCapabilitiesSettingOfAppParameterShouldBe(
|
||||
string $capabilitiesApp,
|
||||
string $capabilitiesPath,
|
||||
string $expectedValue
|
||||
):void {
|
||||
$this->theAdministratorGetsCapabilitiesCheckResponse();
|
||||
$actualValue = $this->getAppParameter($capabilitiesApp, $capabilitiesPath);
|
||||
|
||||
Assert::assertEquals(
|
||||
$expectedValue,
|
||||
$actualValue,
|
||||
__METHOD__
|
||||
. " $capabilitiesApp path $capabilitiesPath should be $expectedValue but is $actualValue"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $capabilitiesApp the "app" name in the capabilities response
|
||||
* @param string $capabilitiesPath the path to the element
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getAppParameter(string $capabilitiesApp, string $capabilitiesPath):string {
|
||||
return $this->getParameterValueFromXml(
|
||||
$this->getCapabilitiesXml(__METHOD__),
|
||||
$capabilitiesApp,
|
||||
$capabilitiesPath
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :username retrieves the capabilities using the capabilities API
|
||||
*
|
||||
* @param string $username
|
||||
*
|
||||
* @return void
|
||||
* @throws GuzzleException
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function userGetsCapabilities(string $username):void {
|
||||
$user = $this->featureContext->getActualUsername($username);
|
||||
$password = $this->featureContext->getPasswordForUser($user);
|
||||
$this->featureContext->setResponse(
|
||||
OcsApiHelper::sendRequest(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$user,
|
||||
$password,
|
||||
'GET',
|
||||
'/cloud/capabilities',
|
||||
$this->featureContext->getStepLineRef(),
|
||||
[],
|
||||
$this->featureContext->getOcsApiVersion()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :username has retrieved the capabilities
|
||||
*
|
||||
* @param string $username
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userGetsCapabilitiesCheckResponse(string $username):void {
|
||||
$this->userGetsCapabilities($username);
|
||||
$statusCode = $this->featureContext->getResponse()->getStatusCode();
|
||||
if ($statusCode !== 200) {
|
||||
throw new \Exception(
|
||||
__METHOD__
|
||||
. " user $username returned unexpected status $statusCode"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @When the user retrieves the capabilities using the capabilities API
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function theUserGetsCapabilities():void {
|
||||
$this->userGetsCapabilities($this->featureContext->getCurrentUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given the user has retrieved the capabilities
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theUserGetsCapabilitiesCheckResponse():void {
|
||||
$this->userGetsCapabilitiesCheckResponse($this->featureContext->getCurrentUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getAdminUsernameForCapabilitiesCheck():string {
|
||||
if (\TestHelpers\OcisHelper::isTestingOnReva()) {
|
||||
// When testing on reva we don't have a user called "admin" to use
|
||||
// to access the capabilities. So create an ordinary user on-the-fly
|
||||
// with a default password. That user should be able to get a
|
||||
// capabilities response that the test can process.
|
||||
$adminUsername = "PseudoAdminForRevaTest";
|
||||
$createdUsers = $this->featureContext->getCreatedUsers();
|
||||
if (!\array_key_exists($adminUsername, $createdUsers)) {
|
||||
$this->featureContext->createUser($adminUsername);
|
||||
}
|
||||
} else {
|
||||
$adminUsername = $this->featureContext->getAdminUsername();
|
||||
}
|
||||
return $adminUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* @When the administrator retrieves the capabilities using the capabilities API
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function theAdministratorGetsCapabilities():void {
|
||||
$this->userGetsCapabilities($this->getAdminUsernameForCapabilitiesCheck());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given the administrator has retrieved the capabilities
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theAdministratorGetsCapabilitiesCheckResponse():void {
|
||||
$this->userGetsCapabilitiesCheckResponse($this->getAdminUsernameForCapabilitiesCheck());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $exceptionText text to put at the front of exception messages
|
||||
*
|
||||
* @return SimpleXMLElement latest retrieved capabilities in XML format
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getCapabilitiesXml(string $exceptionText = ''): SimpleXMLElement {
|
||||
if ($exceptionText === '') {
|
||||
$exceptionText = __METHOD__;
|
||||
}
|
||||
return $this->featureContext->getResponseXml(null, $exceptionText)->data->capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $exceptionText text to put at the front of exception messages
|
||||
*
|
||||
* @return SimpleXMLElement latest retrieved version data in XML format
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getVersionXml(string $exceptionText = ''): SimpleXMLElement {
|
||||
if ($exceptionText === '') {
|
||||
$exceptionText = __METHOD__;
|
||||
}
|
||||
return $this->featureContext->getResponseXml(null, $exceptionText)->data->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SimpleXMLElement $xml of the capabilities
|
||||
* @param string $capabilitiesApp the "app" name in the capabilities response
|
||||
* @param string $capabilitiesPath the path to the element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getParameterValueFromXml(
|
||||
SimpleXMLElement $xml,
|
||||
string $capabilitiesApp,
|
||||
string $capabilitiesPath
|
||||
):string {
|
||||
$path_to_element = \explode('@@@', $capabilitiesPath);
|
||||
$answeredValue = $xml->{$capabilitiesApp};
|
||||
foreach ($path_to_element as $element) {
|
||||
$nameIndexParts = \explode('[', $element);
|
||||
if (isset($nameIndexParts[1])) {
|
||||
// This part of the path should be something like "some_element[1]"
|
||||
// Separately extract the name and the index
|
||||
$name = $nameIndexParts[0];
|
||||
$index = (int) \explode(']', $nameIndexParts[1])[0];
|
||||
// and use those to construct the reference into the next XML level
|
||||
$answeredValue = $answeredValue->{$name}[$index];
|
||||
} else {
|
||||
if ($element !== "") {
|
||||
$answeredValue = $answeredValue->{$element};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (string) $answeredValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SimpleXMLElement $xml of the capabilities
|
||||
* @param string $capabilitiesApp the "app" name in the capabilities response
|
||||
* @param string $capabilitiesPath the path to the element
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function parameterValueExistsInXml(
|
||||
SimpleXMLElement $xml,
|
||||
string $capabilitiesApp,
|
||||
string $capabilitiesPath
|
||||
):bool {
|
||||
$path_to_element = \explode('@@@', $capabilitiesPath);
|
||||
$answeredValue = $xml->{$capabilitiesApp};
|
||||
|
||||
foreach ($path_to_element as $element) {
|
||||
$nameIndexParts = \explode('[', $element);
|
||||
if (isset($nameIndexParts[1])) {
|
||||
// This part of the path should be something like "some_element[1]"
|
||||
// Separately extract the name and the index
|
||||
$name = $nameIndexParts[0];
|
||||
$index = (int) \explode(']', $nameIndexParts[1])[0];
|
||||
// and use those to construct the reference into the next XML level
|
||||
if (isset($answeredValue->{$name}[$index])) {
|
||||
$answeredValue = $answeredValue->{$name}[$index];
|
||||
} else {
|
||||
// The path ends at this level
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (isset($answeredValue->{$element})) {
|
||||
$answeredValue = $answeredValue->{$element};
|
||||
} else {
|
||||
// The path ends at this level
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $app
|
||||
* @param string $parameter
|
||||
* @param string $value
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function modifyAppConfig(string $app, string $parameter, string $value):void {
|
||||
AppConfigHelper::modifyAppConfig(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$this->featureContext->getAdminUsername(),
|
||||
$this->featureContext->getAdminPassword(),
|
||||
$app,
|
||||
$parameter,
|
||||
$value,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
$this->featureContext->getOcsApiVersion()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $appParameterValues
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function modifyAppConfigs(array $appParameterValues):void {
|
||||
AppConfigHelper::modifyAppConfigs(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$this->featureContext->getAdminUsername(),
|
||||
$this->featureContext->getAdminPassword(),
|
||||
$appParameterValues,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
$this->featureContext->getOcsApiVersion()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When the administrator adds url :url as trusted server using the testing API
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return void
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function theAdministratorAddsUrlAsTrustedServerUsingTheTestingApi(string $url):void {
|
||||
$adminUser = $this->featureContext->getAdminUsername();
|
||||
$response = OcsApiHelper::sendRequest(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$adminUser,
|
||||
$this->featureContext->getAdminPassword(),
|
||||
'POST',
|
||||
"/apps/testing/api/v1/trustedservers",
|
||||
$this->featureContext->getStepLineRef(),
|
||||
['url' => $this->featureContext->substituteInLineCodes($url)]
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
$this->featureContext->pushToLastStatusCodesArrays();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return text that contains the details of the URL, including any differences due to inline codes
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getUrlStringForMessage(string $url):string {
|
||||
$text = $url;
|
||||
$expectedUrl = $this->featureContext->substituteInLineCodes($url);
|
||||
if ($expectedUrl !== $url) {
|
||||
$text .= " ($expectedUrl)";
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getNotTrustedServerMessage(string $url):string {
|
||||
return
|
||||
"URL "
|
||||
. $this->getUrlStringForMessage($url)
|
||||
. " is not a trusted server but should be";
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then url :url should be a trusted server
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function urlShouldBeATrustedServer(string $url):void {
|
||||
$trustedServers = $this->featureContext->getTrustedServers();
|
||||
foreach ($trustedServers as $server => $id) {
|
||||
if ($server === $this->featureContext->substituteInLineCodes($url)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Assert::fail($this->getNotTrustedServerMessage($url));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the trusted server list should include these urls:
|
||||
*
|
||||
* @param TableNode $table
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theTrustedServerListShouldIncludeTheseUrls(TableNode $table):void {
|
||||
$trustedServers = $this->featureContext->getTrustedServers();
|
||||
$expected = $table->getColumnsHash();
|
||||
|
||||
foreach ($expected as $server) {
|
||||
$found = false;
|
||||
foreach ($trustedServers as $url => $id) {
|
||||
if ($url === $this->featureContext->substituteInLineCodes($server['url'])) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
Assert::fail($this->getNotTrustedServerMessage($server['url']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given the administrator has added url :url as trusted server
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function theAdministratorHasAddedUrlAsTrustedServer(string $url):void {
|
||||
$this->theAdministratorAddsUrlAsTrustedServerUsingTheTestingApi($url);
|
||||
$status = $this->featureContext->getResponse()->getStatusCode();
|
||||
if ($status !== 201) {
|
||||
throw new \Exception(
|
||||
__METHOD__ .
|
||||
" Could not add trusted server " . $this->getUrlStringForMessage($url)
|
||||
. ". The request failed with status $status"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @When the administrator deletes url :url from trusted servers using the testing API
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return void
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function theAdministratorDeletesUrlFromTrustedServersUsingTheTestingApi(string $url):void {
|
||||
$adminUser = $this->featureContext->getAdminUsername();
|
||||
$response = OcsApiHelper::sendRequest(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$adminUser,
|
||||
$this->featureContext->getAdminPassword(),
|
||||
'DELETE',
|
||||
"/apps/testing/api/v1/trustedservers",
|
||||
$this->featureContext->getStepLineRef(),
|
||||
['url' => $this->featureContext->substituteInLineCodes($url)]
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then url :url should not be a trusted server
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function urlShouldNotBeATrustedServer(string $url):void {
|
||||
$trustedServers = $this->featureContext->getTrustedServers();
|
||||
foreach ($trustedServers as $server => $id) {
|
||||
if ($server === $this->featureContext->substituteInLineCodes($url)) {
|
||||
Assert::fail(
|
||||
"URL " . $this->getUrlStringForMessage($url)
|
||||
. " is a trusted server but is not expected to be"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @When the administrator deletes all trusted servers using the testing API
|
||||
*
|
||||
* @return void
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function theAdministratorDeletesAllTrustedServersUsingTheTestingApi():void {
|
||||
$adminUser = $this->featureContext->getAdminUsername();
|
||||
$response = OcsApiHelper::sendRequest(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$adminUser,
|
||||
$this->featureContext->getAdminPassword(),
|
||||
'DELETE',
|
||||
"/apps/testing/api/v1/trustedservers/all",
|
||||
$this->featureContext->getStepLineRef()
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given the trusted server list is cleared
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theTrustedServerListIsCleared():void {
|
||||
$this->theAdministratorDeletesAllTrustedServersUsingTheTestingApi();
|
||||
$statusCode = $this->featureContext->getResponse()->getStatusCode();
|
||||
if ($statusCode !== 204) {
|
||||
$contents = $this->featureContext->getResponse()->getBody()->getContents();
|
||||
throw new \Exception(
|
||||
__METHOD__
|
||||
. " Failed to clear all trusted servers" . $contents
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the trusted server list should be empty
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theTrustedServerListShouldBeEmpty():void {
|
||||
$trustedServers = $this->featureContext->getTrustedServers();
|
||||
Assert::assertEmpty(
|
||||
$trustedServers,
|
||||
__METHOD__ . " Trusted server list is not empty"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @BeforeScenario
|
||||
*
|
||||
* @param BeforeScenarioScope $scope
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUpScenario(BeforeScenarioScope $scope):void {
|
||||
// Get the environment
|
||||
$environment = $scope->getEnvironment();
|
||||
// Get all the contexts you need in this context
|
||||
$this->featureContext = $environment->getContext('FeatureContext');
|
||||
}
|
||||
}
|
||||
1158
tests/acceptance/features/bootstrap/AuthContext.php
Normal file
1158
tests/acceptance/features/bootstrap/AuthContext.php
Normal file
File diff suppressed because it is too large
Load Diff
223
tests/acceptance/features/bootstrap/CapabilitiesContext.php
Normal file
223
tests/acceptance/features/bootstrap/CapabilitiesContext.php
Normal file
@@ -0,0 +1,223 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Joas Schilling <coding@schilljs.com>
|
||||
* @author Sergio Bertolin <sbertolin@owncloud.com>
|
||||
* @author Phillip Davis <phil@jankaritech.com>
|
||||
* @copyright Copyright (c) 2018, ownCloud GmbH
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use PHPUnit\Framework\Assert;
|
||||
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
/**
|
||||
* Capabilities context.
|
||||
*/
|
||||
class CapabilitiesContext implements Context {
|
||||
/**
|
||||
*
|
||||
* @var FeatureContext
|
||||
*/
|
||||
private $featureContext;
|
||||
|
||||
/**
|
||||
* @Then the capabilities should contain
|
||||
*
|
||||
* @param TableNode|null $formData
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkCapabilitiesResponse(TableNode $formData):void {
|
||||
$capabilitiesXML = $this->featureContext->appConfigurationContext->getCapabilitiesXml(__METHOD__);
|
||||
$assertedSomething = false;
|
||||
|
||||
$this->featureContext->verifyTableNodeColumns($formData, ['value', 'path_to_element', 'capability']);
|
||||
|
||||
foreach ($formData->getHash() as $row) {
|
||||
$row['value'] = $this->featureContext->substituteInLineCodes($row['value']);
|
||||
Assert::assertEquals(
|
||||
$row['value'] === "EMPTY" ? '' : $row['value'],
|
||||
$this->featureContext->appConfigurationContext->getParameterValueFromXml(
|
||||
$capabilitiesXML,
|
||||
$row['capability'],
|
||||
$row['path_to_element']
|
||||
),
|
||||
"Failed field {$row['capability']} {$row['path_to_element']}"
|
||||
);
|
||||
$assertedSomething = true;
|
||||
}
|
||||
|
||||
Assert::assertTrue(
|
||||
$assertedSomething,
|
||||
'there was nothing in the table of expected capabilities'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the version data in the response should contain
|
||||
*
|
||||
* @param TableNode|null $formData
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkVersionResponse(TableNode $formData):void {
|
||||
$versionXML = $this->featureContext->appConfigurationContext->getVersionXml(__METHOD__);
|
||||
$assertedSomething = false;
|
||||
|
||||
$this->featureContext->verifyTableNodeColumns($formData, ['name', 'value']);
|
||||
|
||||
foreach ($formData->getHash() as $row) {
|
||||
$row['value'] = $this->featureContext->substituteInLineCodes($row['value']);
|
||||
$actualValue = $versionXML->{$row['name']};
|
||||
|
||||
Assert::assertEquals(
|
||||
$row['value'] === "EMPTY" ? '' : $row['value'],
|
||||
$actualValue,
|
||||
"Failed field {$row['name']}"
|
||||
);
|
||||
$assertedSomething = true;
|
||||
}
|
||||
|
||||
Assert::assertTrue(
|
||||
$assertedSomething,
|
||||
'there was nothing in the table of expected version data'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the major-minor-micro version data in the response should match the version string
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkVersionMajorMinorMicroResponse():void {
|
||||
$versionXML = $this->featureContext->appConfigurationContext->getVersionXml(__METHOD__);
|
||||
$versionString = (string) $versionXML->string;
|
||||
// We expect that versionString will be in a format like "10.9.2 beta" or "10.9.2-alpha" or "10.9.2"
|
||||
$result = \preg_match('/^[0-9]+\.[0-9]+\.[0-9]+/', $versionString, $matches);
|
||||
Assert::assertSame(
|
||||
1,
|
||||
$result,
|
||||
__METHOD__ . " version string '$versionString' does not start with a semver version"
|
||||
);
|
||||
// semVerParts should have an array with the 3 semver components of the version, e.g. "1", "9" and "2".
|
||||
$semVerParts = \explode('.', $matches[0]);
|
||||
$expectedMajor = $semVerParts[0];
|
||||
$expectedMinor = $semVerParts[1];
|
||||
$expectedMicro = $semVerParts[2];
|
||||
$actualMajor = (string) $versionXML->major;
|
||||
$actualMinor = (string) $versionXML->minor;
|
||||
$actualMicro = (string) $versionXML->micro;
|
||||
Assert::assertSame(
|
||||
$expectedMajor,
|
||||
$actualMajor,
|
||||
__METHOD__ . "'major' data item does not match with major version in string '$versionString'"
|
||||
);
|
||||
Assert::assertSame(
|
||||
$expectedMinor,
|
||||
$actualMinor,
|
||||
__METHOD__ . "'minor' data item does not match with minor version in string '$versionString'"
|
||||
);
|
||||
Assert::assertSame(
|
||||
$expectedMicro,
|
||||
$actualMicro,
|
||||
__METHOD__ . "'micro' data item does not match with micro (patch) version in string '$versionString'"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the :pathToElement capability of files sharing app should be :value
|
||||
*
|
||||
* @param string $pathToElement
|
||||
* @param string $value
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theCapabilityOfFilesSharingAppShouldBe(
|
||||
string $pathToElement,
|
||||
string $value
|
||||
):void {
|
||||
$this->featureContext->appConfigurationContext->userGetsCapabilitiesCheckResponse(
|
||||
$this->featureContext->getCurrentUser()
|
||||
);
|
||||
$capabilitiesXML = $this->featureContext->appConfigurationContext->getCapabilitiesXml(__METHOD__);
|
||||
$actualValue = $this->featureContext->appConfigurationContext->getParameterValueFromXml(
|
||||
$capabilitiesXML,
|
||||
"files_sharing",
|
||||
$pathToElement
|
||||
);
|
||||
Assert::assertEquals(
|
||||
$value === "EMPTY" ? '' : $value,
|
||||
$actualValue,
|
||||
"Expected {$pathToElement} capability of files sharing app to be {$value}, but got {$actualValue}"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the capabilities should not contain
|
||||
*
|
||||
* @param TableNode|null $formData
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function theCapabilitiesShouldNotContain(TableNode $formData):void {
|
||||
$capabilitiesXML = $this->featureContext->appConfigurationContext->getCapabilitiesXml(__METHOD__);
|
||||
$assertedSomething = false;
|
||||
|
||||
foreach ($formData->getHash() as $row) {
|
||||
Assert::assertFalse(
|
||||
$this->featureContext->appConfigurationContext->parameterValueExistsInXml(
|
||||
$capabilitiesXML,
|
||||
$row['capability'],
|
||||
$row['path_to_element']
|
||||
),
|
||||
"Capability {$row['capability']} {$row['path_to_element']} exists but it should not exist"
|
||||
);
|
||||
$assertedSomething = true;
|
||||
}
|
||||
|
||||
Assert::assertTrue(
|
||||
$assertedSomething,
|
||||
'there was nothing in the table of not expected capabilities'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will run before EVERY scenario.
|
||||
* It will set the properties for this object.
|
||||
*
|
||||
* @BeforeScenario
|
||||
*
|
||||
* @param BeforeScenarioScope $scope
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function before(BeforeScenarioScope $scope):void {
|
||||
// Get the environment
|
||||
$environment = $scope->getEnvironment();
|
||||
// Get all the contexts you need in this context
|
||||
$this->featureContext = $environment->getContext('FeatureContext');
|
||||
}
|
||||
}
|
||||
464
tests/acceptance/features/bootstrap/ChecksumContext.php
Normal file
464
tests/acceptance/features/bootstrap/ChecksumContext.php
Normal file
@@ -0,0 +1,464 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* @author Roeland Jago Douma <rullzer@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2018, ownCloud GmbH
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use TestHelpers\WebDavHelper;
|
||||
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
/**
|
||||
* Checksum functions
|
||||
*/
|
||||
class ChecksumContext implements Context {
|
||||
/**
|
||||
*
|
||||
* @var FeatureContext
|
||||
*/
|
||||
private $featureContext;
|
||||
|
||||
/**
|
||||
* @When user :user uploads file :source to :destination with checksum :checksum using the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @param string $checksum
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userUploadsFileToWithChecksumUsingTheAPI(
|
||||
string $user,
|
||||
string $source,
|
||||
string $destination,
|
||||
string $checksum
|
||||
):void {
|
||||
$file = \file_get_contents(
|
||||
$this->featureContext->acceptanceTestsDirLocation() . $source
|
||||
);
|
||||
$response = $this->featureContext->makeDavRequest(
|
||||
$user,
|
||||
'PUT',
|
||||
$destination,
|
||||
['OC-Checksum' => $checksum],
|
||||
$file,
|
||||
"files"
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :user has uploaded file :source to :destination with checksum :checksum
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @param string $checksum
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userHasUploadedFileToWithChecksumUsingTheAPI(
|
||||
string $user,
|
||||
string $source,
|
||||
string $destination,
|
||||
string $checksum
|
||||
):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$this->userUploadsFileToWithChecksumUsingTheAPI(
|
||||
$user,
|
||||
$source,
|
||||
$destination,
|
||||
$checksum
|
||||
);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBeSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user uploads file with content :content and checksum :checksum to :destination using the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $content
|
||||
* @param string $checksum
|
||||
* @param string $destination
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userUploadsFileWithContentAndChecksumToUsingTheAPI(
|
||||
string $user,
|
||||
string $content,
|
||||
string $checksum,
|
||||
string $destination
|
||||
):void {
|
||||
$response = $this->featureContext->makeDavRequest(
|
||||
$user,
|
||||
'PUT',
|
||||
$destination,
|
||||
['OC-Checksum' => $checksum],
|
||||
$content,
|
||||
"files"
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :user has uploaded file with content :content and checksum :checksum to :destination
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $content
|
||||
* @param string $checksum
|
||||
* @param string $destination
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userHasUploadedFileWithContentAndChecksumToUsingTheAPI(
|
||||
string $user,
|
||||
string $content,
|
||||
string $checksum,
|
||||
string $destination
|
||||
):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$this->userUploadsFileWithContentAndChecksumToUsingTheAPI(
|
||||
$user,
|
||||
$content,
|
||||
$checksum,
|
||||
$destination
|
||||
);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBeSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user requests the checksum of :path via propfind
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userRequestsTheChecksumOfViaPropfind(string $user, string $path):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$body = '<?xml version="1.0"?>
|
||||
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
|
||||
<d:prop>
|
||||
<oc:checksums />
|
||||
</d:prop>
|
||||
</d:propfind>';
|
||||
$password = $this->featureContext->getPasswordForUser($user);
|
||||
$response = WebDavHelper::makeDavRequest(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$user,
|
||||
$password,
|
||||
'PROPFIND',
|
||||
$path,
|
||||
null,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
$body,
|
||||
$this->featureContext->getDavPathVersion()
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the webdav checksum should match :expectedChecksum
|
||||
*
|
||||
* @param string $expectedChecksum
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theWebdavChecksumShouldMatch(string $expectedChecksum):void {
|
||||
$service = new Sabre\Xml\Service();
|
||||
$bodyContents = $this->featureContext->getResponse()->getBody()->getContents();
|
||||
$parsed = $service->parse($bodyContents);
|
||||
|
||||
/*
|
||||
* Fetch the checksum array
|
||||
* The checksums are way down in the array:
|
||||
* $checksums = $parsed[0]['value'][1]['value'][0]['value'][0];
|
||||
* And inside is the actual checksum string:
|
||||
* $checksums['value'][0]['value']
|
||||
* The Asserts below check the existence of the expected key at every level
|
||||
* of the nested array. This helps to see what happened if a test fails
|
||||
* because the response structure is not as expected.
|
||||
*/
|
||||
|
||||
Assert::assertIsArray(
|
||||
$parsed,
|
||||
__METHOD__ . " could not parse response as XML. Expected parsed XML to be an array but found " . $bodyContents
|
||||
);
|
||||
Assert::assertArrayHasKey(
|
||||
0,
|
||||
$parsed,
|
||||
__METHOD__ . " parsed XML does not have key 0"
|
||||
);
|
||||
$parsed0 = $parsed[0];
|
||||
Assert::assertArrayHasKey(
|
||||
'value',
|
||||
$parsed0,
|
||||
__METHOD__ . " parsed XML parsed0 does not have key value"
|
||||
);
|
||||
$parsed0Value = $parsed0['value'];
|
||||
Assert::assertArrayHasKey(
|
||||
1,
|
||||
$parsed0Value,
|
||||
__METHOD__ . " parsed XML parsed0Value does not have key 1"
|
||||
);
|
||||
$parsed0Value1 = $parsed0Value[1];
|
||||
Assert::assertArrayHasKey(
|
||||
'value',
|
||||
$parsed0Value1,
|
||||
__METHOD__ . " parsed XML parsed0Value1 does not have key value after key 1"
|
||||
);
|
||||
$parsed0Value1Value = $parsed0Value1['value'];
|
||||
Assert::assertArrayHasKey(
|
||||
0,
|
||||
$parsed0Value1Value,
|
||||
__METHOD__ . " parsed XML parsed0Value1Value does not have key 0"
|
||||
);
|
||||
$parsed0Value1Value0 = $parsed0Value1Value[0];
|
||||
Assert::assertArrayHasKey(
|
||||
'value',
|
||||
$parsed0Value1Value0,
|
||||
__METHOD__ . " parsed XML parsed0Value1Value0 does not have key value"
|
||||
);
|
||||
$parsed0Value1Value0Value = $parsed0Value1Value0['value'];
|
||||
Assert::assertArrayHasKey(
|
||||
0,
|
||||
$parsed0Value1Value0Value,
|
||||
__METHOD__ . " parsed XML parsed0Value1Value0Value does not have key 0"
|
||||
);
|
||||
$checksums = $parsed0Value1Value0Value[0];
|
||||
Assert::assertArrayHasKey(
|
||||
'value',
|
||||
$checksums,
|
||||
__METHOD__ . " parsed XML checksums does not have key value"
|
||||
);
|
||||
$checksumsValue = $checksums['value'];
|
||||
Assert::assertArrayHasKey(
|
||||
0,
|
||||
$checksumsValue,
|
||||
__METHOD__ . " parsed XML checksumsValue does not have key 0"
|
||||
);
|
||||
$checksumsValue0 = $checksumsValue[0];
|
||||
Assert::assertArrayHasKey(
|
||||
'value',
|
||||
$checksumsValue0,
|
||||
__METHOD__ . " parsed XML checksumsValue0 does not have key value"
|
||||
);
|
||||
$actualChecksum = $checksumsValue0['value'];
|
||||
Assert::assertEquals(
|
||||
$expectedChecksum,
|
||||
$actualChecksum,
|
||||
"Expected: webDav checksum should be {$expectedChecksum} but got {$actualChecksum}"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then as user :user the webdav checksum of :path via propfind should match :expectedChecksum
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
* @param string $expectedChecksum
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theWebdavChecksumOfViaPropfindShouldMatch(string $user, string $path, string $expectedChecksum):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$this->userRequestsTheChecksumOfViaPropfind($user, $path);
|
||||
$this->theWebdavChecksumShouldMatch($expectedChecksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the header checksum should match :expectedChecksum
|
||||
*
|
||||
* @param string $expectedChecksum
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theHeaderChecksumShouldMatch(string $expectedChecksum):void {
|
||||
$headerChecksums
|
||||
= $this->featureContext->getResponse()->getHeader('OC-Checksum');
|
||||
|
||||
Assert::assertIsArray(
|
||||
$headerChecksums,
|
||||
__METHOD__ . " getHeader('OC-Checksum') did not return an array"
|
||||
);
|
||||
|
||||
Assert::assertNotEmpty(
|
||||
$headerChecksums,
|
||||
__METHOD__ . " getHeader('OC-Checksum') returned an empty array. No checksum header was found."
|
||||
);
|
||||
|
||||
$checksumCount = \count($headerChecksums);
|
||||
|
||||
Assert::assertTrue(
|
||||
$checksumCount === 1,
|
||||
__METHOD__ . " Expected 1 checksum in the header but found $checksumCount checksums"
|
||||
);
|
||||
|
||||
$headerChecksum
|
||||
= $headerChecksums[0];
|
||||
Assert::assertEquals(
|
||||
$expectedChecksum,
|
||||
$headerChecksum,
|
||||
"Expected: header checksum should match {$expectedChecksum} but got {$headerChecksum}"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the header checksum when user :arg1 downloads file :arg2 using the WebDAV API should match :arg3
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $fileName
|
||||
* @param string $expectedChecksum
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theHeaderChecksumWhenUserDownloadsFileUsingTheWebdavApiShouldMatch(string $user, string $fileName, string $expectedChecksum):void {
|
||||
$this->featureContext->userDownloadsFileUsingTheAPI($user, $fileName);
|
||||
$this->theHeaderChecksumShouldMatch($expectedChecksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the webdav checksum should be empty
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theWebdavChecksumShouldBeEmpty():void {
|
||||
$service = new Sabre\Xml\Service();
|
||||
$parsed = $service->parse(
|
||||
$this->featureContext->getResponse()->getBody()->getContents()
|
||||
);
|
||||
|
||||
/*
|
||||
* Fetch the checksum array
|
||||
* Maybe we want to do this a bit cleaner ;)
|
||||
*/
|
||||
$status = $parsed[0]['value'][1]['value'][1]['value'];
|
||||
$expectedStatus = 'HTTP/1.1 404 Not Found';
|
||||
Assert::assertEquals(
|
||||
$expectedStatus,
|
||||
$status,
|
||||
"Expected status to be {$expectedStatus} but got {$status}"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the OC-Checksum header should not be there
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theOcChecksumHeaderShouldNotBeThere():void {
|
||||
$isHeader = $this->featureContext->getResponse()->hasHeader('OC-Checksum');
|
||||
Assert::assertFalse(
|
||||
$isHeader,
|
||||
"Expected no checksum header but got "
|
||||
. $this->featureContext->getResponse()->getHeader('OC-Checksum')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user uploads chunk file :num of :total with :data to :destination with checksum :expectedChecksum using the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param int $num
|
||||
* @param int $total
|
||||
* @param string $data
|
||||
* @param string $destination
|
||||
* @param string $expectedChecksum
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userUploadsChunkFileOfWithToWithChecksum(
|
||||
string $user,
|
||||
int $num,
|
||||
int $total,
|
||||
string $data,
|
||||
string $destination,
|
||||
string $expectedChecksum
|
||||
):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$num -= 1;
|
||||
$file = "$destination-chunking-42-$total-$num";
|
||||
$response = $this->featureContext->makeDavRequest(
|
||||
$user,
|
||||
'PUT',
|
||||
$file,
|
||||
['OC-Checksum' => $expectedChecksum, 'OC-Chunked' => '1'],
|
||||
$data,
|
||||
"files"
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :user has uploaded chunk file :num of :total with :data to :destination with checksum :expectedChecksum
|
||||
*
|
||||
* @param string $user
|
||||
* @param int $num
|
||||
* @param int $total
|
||||
* @param string $data
|
||||
* @param string $destination
|
||||
* @param string $expectedChecksum
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userHasUploadedChunkFileOfWithToWithChecksum(
|
||||
string $user,
|
||||
int $num,
|
||||
int $total,
|
||||
string $data,
|
||||
string $destination,
|
||||
string $expectedChecksum
|
||||
):void {
|
||||
$this->userUploadsChunkFileOfWithToWithChecksum(
|
||||
$user,
|
||||
$num,
|
||||
$total,
|
||||
$data,
|
||||
$destination,
|
||||
$expectedChecksum
|
||||
);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBeOr(201, 206);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will run before EVERY scenario.
|
||||
* It will set the properties for this object.
|
||||
*
|
||||
* @BeforeScenario
|
||||
*
|
||||
* @param BeforeScenarioScope $scope
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function before(BeforeScenarioScope $scope):void {
|
||||
// Get the environment
|
||||
$environment = $scope->getEnvironment();
|
||||
// Get all the contexts you need in this context
|
||||
$this->featureContext = $environment->getContext('FeatureContext');
|
||||
}
|
||||
}
|
||||
361
tests/acceptance/features/bootstrap/FavoritesContext.php
Normal file
361
tests/acceptance/features/bootstrap/FavoritesContext.php
Normal file
@@ -0,0 +1,361 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2018 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use TestHelpers\WebDavHelper;
|
||||
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
/**
|
||||
* context containing favorites related API steps
|
||||
*/
|
||||
class FavoritesContext implements Context {
|
||||
/**
|
||||
*
|
||||
* @var FeatureContext
|
||||
*/
|
||||
private $featureContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var WebDavPropertiesContext
|
||||
*/
|
||||
private $webDavPropertiesContext;
|
||||
|
||||
/**
|
||||
* @param string$user
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userFavoritesElement(string $user, string $path):void {
|
||||
$response = $this->changeFavStateOfAnElement(
|
||||
$user,
|
||||
$path,
|
||||
1
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user favorites element :path using the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userFavoritesElementUsingWebDavApi(string $user, string $path):void {
|
||||
$this->userFavoritesElement($user, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :user has favorited element :path
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userHasFavoritedElementUsingWebDavApi(string $user, string $path):void {
|
||||
$this->userFavoritesElement($user, $path);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBeSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When the user favorites element :path using the WebDAV API
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function theUserFavoritesElement(string $path):void {
|
||||
$this->userFavoritesElement(
|
||||
$this->featureContext->getCurrentUser(),
|
||||
$path
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given the user has favorited element :path
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function theUserHasFavoritedElement(string $path):void {
|
||||
$this->userFavoritesElement(
|
||||
$this->featureContext->getCurrentUser(),
|
||||
$path
|
||||
);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBe(
|
||||
207,
|
||||
"Expected response status code to be 207 (Multi-status), but not found! "
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $user
|
||||
* @param $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userUnfavoritesElement(string $user, string $path):void {
|
||||
$response = $this->changeFavStateOfAnElement(
|
||||
$user,
|
||||
$path,
|
||||
0
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user unfavorites element :path using the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userUnfavoritesElementUsingWebDavApi(string $user, string $path):void {
|
||||
$this->userUnfavoritesElement($user, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :user has unfavorited element :path
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userHasUnfavoritedElementUsingWebDavApi(string $user, string $path):void {
|
||||
$this->userUnfavoritesElement($user, $path);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBeSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^user "([^"]*)" should (not|)\s?have favorited the following elements$/
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $shouldOrNot (not|)
|
||||
* @param TableNode $expectedElements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function checkFavoritedElements(
|
||||
string $user,
|
||||
string $shouldOrNot,
|
||||
TableNode $expectedElements
|
||||
):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$this->userListsFavorites($user, null);
|
||||
$this->featureContext->propfindResultShouldContainEntries(
|
||||
$shouldOrNot,
|
||||
$expectedElements,
|
||||
$user
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^user "([^"]*)" lists the favorites and limits the result to ([\d*]) elements using the WebDAV API$/
|
||||
*
|
||||
* @param string $user
|
||||
* @param int|null $limit
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userListsFavorites(string $user, ?int $limit = null):void {
|
||||
$renamedUser = $this->featureContext->getActualUsername($user);
|
||||
$baseUrl = $this->featureContext->getBaseUrl();
|
||||
$password = $this->featureContext->getPasswordForUser($user);
|
||||
$body
|
||||
= "<?xml version='1.0' encoding='utf-8' ?>\n" .
|
||||
" <oc:filter-files xmlns:a='DAV:' xmlns:oc='http://owncloud.org/ns' >\n" .
|
||||
" <a:prop><oc:favorite/></a:prop>\n" .
|
||||
" <oc:filter-rules><oc:favorite>1</oc:favorite></oc:filter-rules>\n";
|
||||
|
||||
if ($limit !== null) {
|
||||
$body .= " <oc:search>\n" .
|
||||
" <oc:limit>$limit</oc:limit>\n" .
|
||||
" </oc:search>\n";
|
||||
}
|
||||
|
||||
$body .= " </oc:filter-files>";
|
||||
$response = WebDavHelper::makeDavRequest(
|
||||
$baseUrl,
|
||||
$renamedUser,
|
||||
$password,
|
||||
"REPORT",
|
||||
"/",
|
||||
null,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
$body,
|
||||
$this->featureContext->getDavPathVersion()
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function theUserUnfavoritesElement(string $path):void {
|
||||
$this->userUnfavoritesElement(
|
||||
$this->featureContext->getCurrentUser(),
|
||||
$path
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When the user unfavorites element :path using the WebDAV API
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function theUserUnfavoritesElementUsingWebDavApi(string $path):void {
|
||||
$this->theUserUnfavoritesElement($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given the user has unfavorited element :path
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function theUserHasUnfavoritedElementUsingWebDavApi(string $path):void {
|
||||
$this->theUserUnfavoritesElement($path);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBeSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^as user "([^"]*)" (?:file|folder|entry) "([^"]*)" should be favorited$/
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
* @param integer $expectedValue 0|1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function asUserFileOrFolderShouldBeFavorited(string $user, string $path, int $expectedValue = 1):void {
|
||||
$property = "oc:favorite";
|
||||
$this->webDavPropertiesContext->asUserFolderShouldContainAPropertyWithValue(
|
||||
$user,
|
||||
$path,
|
||||
$property,
|
||||
(string)$expectedValue
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^as user "([^"]*)" (?:file|folder|entry) "([^"]*)" should not be favorited$/
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function asUserFileShouldNotBeFavorited(string $user, string $path):void {
|
||||
$this->asUserFileOrFolderShouldBeFavorited($user, $path, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^as the user (?:file|folder|entry) "([^"]*)" should be favorited$/
|
||||
*
|
||||
* @param string $path
|
||||
* @param integer $expectedValue 0|1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function asTheUserFileOrFolderShouldBeFavorited(string $path, int $expectedValue = 1):void {
|
||||
$this->asUserFileOrFolderShouldBeFavorited(
|
||||
$this->featureContext->getCurrentUser(),
|
||||
$path,
|
||||
$expectedValue
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^as the user (?:file|folder|entry) "([^"]*)" should not be favorited$/
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function asTheUserFileOrFolderShouldNotBeFavorited(string $path):void {
|
||||
$this->asTheUserFileOrFolderShouldBeFavorited($path, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the elements of a proppatch
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
* @param int|null $favOrUnfav 1 = favorite, 0 = unfavorite
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function changeFavStateOfAnElement(
|
||||
string $user,
|
||||
string $path,
|
||||
?int $favOrUnfav
|
||||
):ResponseInterface {
|
||||
$renamedUser = $this->featureContext->getActualUsername($user);
|
||||
return WebDavHelper::proppatch(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$renamedUser,
|
||||
$this->featureContext->getPasswordForUser($user),
|
||||
$path,
|
||||
'favorite',
|
||||
(string)$favOrUnfav,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
"oc='http://owncloud.org/ns'",
|
||||
$this->featureContext->getDavPathVersion()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will run before EVERY scenario.
|
||||
* It will set the properties for this object.
|
||||
*
|
||||
* @BeforeScenario
|
||||
*
|
||||
* @param BeforeScenarioScope $scope
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function before(BeforeScenarioScope $scope):void {
|
||||
// Get the environment
|
||||
$environment = $scope->getEnvironment();
|
||||
// Get all the contexts you need in this context
|
||||
$this->featureContext = $environment->getContext('FeatureContext');
|
||||
$this->webDavPropertiesContext = $environment->getContext(
|
||||
'WebDavPropertiesContext'
|
||||
);
|
||||
}
|
||||
}
|
||||
4488
tests/acceptance/features/bootstrap/FeatureContext.php
Normal file
4488
tests/acceptance/features/bootstrap/FeatureContext.php
Normal file
File diff suppressed because it is too large
Load Diff
443
tests/acceptance/features/bootstrap/FilesVersionsContext.php
Normal file
443
tests/acceptance/features/bootstrap/FilesVersionsContext.php
Normal file
@@ -0,0 +1,443 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2018, ownCloud GmbH
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use TestHelpers\HttpRequestHelper;
|
||||
use TestHelpers\WebDavHelper;
|
||||
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
/**
|
||||
* Steps that relate to files_versions app
|
||||
*/
|
||||
class FilesVersionsContext implements Context {
|
||||
/**
|
||||
*
|
||||
* @var FeatureContext
|
||||
*/
|
||||
private $featureContext;
|
||||
|
||||
/**
|
||||
* @param string $fileId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getVersionsPathForFileId(string $fileId):string {
|
||||
return "/meta/$fileId/v";
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user tries to get versions of file :file from :fileOwner
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $file
|
||||
* @param string $fileOwner
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userTriesToGetFileVersions(string $user, string $file, string $fileOwner):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$fileOwner = $this->featureContext->getActualUsername($fileOwner);
|
||||
$fileId = $this->featureContext->getFileIdForPath($fileOwner, $file);
|
||||
Assert::assertNotNull($fileId, __METHOD__ . " fileid of file $file user $fileOwner not found (the file may not exist)");
|
||||
$response = $this->featureContext->makeDavRequest(
|
||||
$user,
|
||||
"PROPFIND",
|
||||
$this->getVersionsPathForFileId($fileId),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'2'
|
||||
);
|
||||
$this->featureContext->setResponse($response, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user gets the number of versions of file :file
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $file
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userGetsFileVersions(string $user, string $file):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$fileId = $this->featureContext->getFileIdForPath($user, $file);
|
||||
Assert::assertNotNull($fileId, __METHOD__ . " fileid of file $file user $user not found (the file may not exist)");
|
||||
$response = $this->featureContext->makeDavRequest(
|
||||
$user,
|
||||
"PROPFIND",
|
||||
$this->getVersionsPathForFileId($fileId),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'2'
|
||||
);
|
||||
$this->featureContext->setResponse($response, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user gets the version metadata of file :file
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $file
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userGetsVersionMetadataOfFile(string $user, string $file):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$fileId = $this->featureContext->getFileIdForPath($user, $file);
|
||||
Assert::assertNotNull($fileId, __METHOD__ . " fileid of file $file user $user not found (the file may not exist)");
|
||||
$body = '<?xml version="1.0"?>
|
||||
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
|
||||
<d:prop>
|
||||
<oc:meta-version-edited-by />
|
||||
<oc:meta-version-edited-by-name />
|
||||
</d:prop>
|
||||
</d:propfind>';
|
||||
$response = $this->featureContext->makeDavRequest(
|
||||
$user,
|
||||
"PROPFIND",
|
||||
$this->getVersionsPathForFileId($fileId),
|
||||
null,
|
||||
$body,
|
||||
null,
|
||||
'2'
|
||||
);
|
||||
$this->featureContext->setResponse($response, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user restores version index :versionIndex of file :path using the WebDAV API
|
||||
* @Given user :user has restored version index :versionIndex of file :path
|
||||
*
|
||||
* @param string $user
|
||||
* @param int $versionIndex
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userRestoresVersionIndexOfFile(string $user, int $versionIndex, string $path):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$fileId = $this->featureContext->getFileIdForPath($user, $path);
|
||||
Assert::assertNotNull($fileId, __METHOD__ . " fileid of file $path user $user not found (the file may not exist)");
|
||||
$responseXml = $this->listVersionFolder($user, $fileId, 1);
|
||||
$xmlPart = $responseXml->xpath("//d:response/d:href");
|
||||
//restoring the version only works with DAV path v2
|
||||
$destinationUrl = $this->featureContext->getBaseUrl() . "/" .
|
||||
WebDavHelper::getDavPath($user, 2) . \trim($path, "/");
|
||||
$fullUrl = $this->featureContext->getBaseUrlWithoutPath() .
|
||||
$xmlPart[$versionIndex];
|
||||
$response = HttpRequestHelper::sendRequest(
|
||||
$fullUrl,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
'COPY',
|
||||
$user,
|
||||
$this->featureContext->getPasswordForUser($user),
|
||||
['Destination' => $destinationUrl]
|
||||
);
|
||||
$this->featureContext->setResponse($response, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the version folder of file :path for user :user should contain :count element(s)
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $user
|
||||
* @param int $count
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theVersionFolderOfFileShouldContainElements(
|
||||
string $path,
|
||||
string $user,
|
||||
int $count
|
||||
):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$fileId = $this->featureContext->getFileIdForPath($user, $path);
|
||||
Assert::assertNotNull($fileId, __METHOD__ . " file $path user $user not found (the file may not exist)");
|
||||
$this->theVersionFolderOfFileIdShouldContainElements($fileId, $user, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the version folder of fileId :fileId for user :user should contain :count element(s)
|
||||
*
|
||||
* @param string $fileId
|
||||
* @param string $user
|
||||
* @param int $count
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theVersionFolderOfFileIdShouldContainElements(
|
||||
string $fileId,
|
||||
string $user,
|
||||
int $count
|
||||
):void {
|
||||
$responseXml = $this->listVersionFolder($user, $fileId, 1);
|
||||
$xmlPart = $responseXml->xpath("//d:prop/d:getetag");
|
||||
Assert::assertEquals(
|
||||
$count,
|
||||
\count($xmlPart) - 1,
|
||||
"could not find $count version element(s) in \n" . $responseXml->asXML()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the content length of file :path with version index :index for user :user in versions folder should be :length
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $index
|
||||
* @param string $user
|
||||
* @param int $length
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theContentLengthOfFileForUserInVersionsFolderIs(
|
||||
string $path,
|
||||
int $index,
|
||||
string $user,
|
||||
int $length
|
||||
):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$fileId = $this->featureContext->getFileIdForPath($user, $path);
|
||||
Assert::assertNotNull($fileId, __METHOD__ . " fileid of file $path user $user not found (the file may not exist)");
|
||||
$responseXml = $this->listVersionFolder(
|
||||
$user,
|
||||
$fileId,
|
||||
1,
|
||||
['getcontentlength']
|
||||
);
|
||||
$xmlPart = $responseXml->xpath("//d:prop/d:getcontentlength");
|
||||
Assert::assertEquals(
|
||||
$length,
|
||||
(int) $xmlPart[$index],
|
||||
"The content length of file {$path} with version {$index} for user {$user} was
|
||||
expected to be {$length} but the actual content length is {$xmlPart[$index]}"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^as (?:users|user) "([^"]*)" the authors of the versions of file "([^"]*)" should be:$/
|
||||
*
|
||||
* @param string $users comma-separated list of usernames
|
||||
* @param string $filename
|
||||
* @param TableNode $table
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function asUsersAuthorsOfVersionsOfFileShouldBe(
|
||||
string $users,
|
||||
string $filename,
|
||||
TableNode $table
|
||||
): void {
|
||||
$this->featureContext->verifyTableNodeColumns(
|
||||
$table,
|
||||
['index', 'author']
|
||||
);
|
||||
$requiredVersionMetadata = $table->getHash();
|
||||
$usersArray = \explode(",", $users);
|
||||
foreach ($usersArray as $username) {
|
||||
$actualUsername = $this->featureContext->getActualUsername($username);
|
||||
$this->userGetsVersionMetadataOfFile($actualUsername, $filename);
|
||||
foreach ($requiredVersionMetadata as $versionMetadata) {
|
||||
$this->featureContext->theAuthorOfEditedVersionFile(
|
||||
$versionMetadata['index'],
|
||||
$versionMetadata['author']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user downloads the version of file :path with the index :index
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
* @param string $index
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function downloadVersion(string $user, string $path, string $index):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$fileId = $this->featureContext->getFileIdForPath($user, $path);
|
||||
Assert::assertNotNull($fileId, __METHOD__ . " fileid of file $path user $user not found (the file may not exist)");
|
||||
$index = (int)$index;
|
||||
$responseXml = $this->listVersionFolder($user, $fileId, 1);
|
||||
$xmlPart = $responseXml->xpath("//d:response/d:href");
|
||||
if (!isset($xmlPart[$index])) {
|
||||
Assert::fail(
|
||||
'could not find version of path "' . $path . '" with index "' . $index . '"'
|
||||
);
|
||||
}
|
||||
// the href already contains the path
|
||||
$url = WebDavHelper::sanitizeUrl(
|
||||
$this->featureContext->getBaseUrlWithoutPath() . $xmlPart[$index]
|
||||
);
|
||||
$response = HttpRequestHelper::get(
|
||||
$url,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
$user,
|
||||
$this->featureContext->getPasswordForUser($user)
|
||||
);
|
||||
$this->featureContext->setResponse($response, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^the content of version index "([^"]*)" of file "([^"]*)" for user "([^"]*)" should be "([^"]*)"$/
|
||||
*
|
||||
* @param string $index
|
||||
* @param string $path
|
||||
* @param string $user
|
||||
* @param string $content
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theContentOfVersionIndexOfFileForUserShouldBe(
|
||||
string $index,
|
||||
string $path,
|
||||
string $user,
|
||||
string $content
|
||||
): void {
|
||||
$this->downloadVersion($user, $path, $index);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBe("200");
|
||||
$this->featureContext->downloadedContentShouldBe($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^user "([^"]*)" retrieves the meta information of (file|fileId) "([^"]*)" using the meta API$/
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $fileOrFileId
|
||||
* @param string $path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userGetMetaInfo(string $user, string $fileOrFileId, string $path):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$baseUrl = $this->featureContext->getBaseUrl();
|
||||
$password = $this->featureContext->getPasswordForUser($user);
|
||||
|
||||
if ($fileOrFileId === "file") {
|
||||
$fileId = $this->featureContext->getFileIdForPath($user, $path);
|
||||
$metaPath = "/meta/$fileId/";
|
||||
} else {
|
||||
$metaPath = "/meta/$path/";
|
||||
}
|
||||
|
||||
$body = '<?xml version="1.0" encoding="utf-8"?>
|
||||
<a:propfind xmlns:a="DAV:" xmlns:oc="http://owncloud.org/ns">
|
||||
<a:prop>
|
||||
<oc:meta-path-for-user />
|
||||
</a:prop>
|
||||
</a:propfind>';
|
||||
|
||||
$response = WebDavHelper::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
"PROPFIND",
|
||||
$metaPath,
|
||||
['Content-Type' => 'text/xml','Depth' => '0'],
|
||||
$this->featureContext->getStepLineRef(),
|
||||
$body,
|
||||
$this->featureContext->getDavPathVersion(),
|
||||
null
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
$responseXml = HttpRequestHelper::getResponseXml(
|
||||
$response,
|
||||
__METHOD__
|
||||
);
|
||||
$this->featureContext->setResponseXmlObject($responseXml);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the result parsed into an SimpleXMLElement
|
||||
* with an registered namespace with 'd' as prefix and 'DAV:' as namespace
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $fileId
|
||||
* @param int $folderDepth
|
||||
* @param string[]|null $properties
|
||||
*
|
||||
* @return SimpleXMLElement
|
||||
* @throws Exception
|
||||
*/
|
||||
public function listVersionFolder(
|
||||
string $user,
|
||||
string $fileId,
|
||||
int $folderDepth,
|
||||
?array $properties = null
|
||||
):SimpleXMLElement {
|
||||
if (!$properties) {
|
||||
$properties = [
|
||||
'getetag'
|
||||
];
|
||||
}
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$password = $this->featureContext->getPasswordForUser($user);
|
||||
$response = WebDavHelper::propfind(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$user,
|
||||
$password,
|
||||
$this->getVersionsPathForFileId($fileId),
|
||||
$properties,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
(string) $folderDepth,
|
||||
"versions"
|
||||
);
|
||||
return HttpRequestHelper::getResponseXml(
|
||||
$response,
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will run before EVERY scenario.
|
||||
* It will set the properties for this object.
|
||||
*
|
||||
* @BeforeScenario
|
||||
*
|
||||
* @param BeforeScenarioScope $scope
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function before(BeforeScenarioScope $scope):void {
|
||||
// Get the environment
|
||||
$environment = $scope->getEnvironment();
|
||||
// Get all the contexts you need in this context
|
||||
$this->featureContext = $environment->getContext('FeatureContext');
|
||||
}
|
||||
}
|
||||
1011
tests/acceptance/features/bootstrap/OCSContext.php
Normal file
1011
tests/acceptance/features/bootstrap/OCSContext.php
Normal file
File diff suppressed because it is too large
Load Diff
3748
tests/acceptance/features/bootstrap/OccContext.php
Normal file
3748
tests/acceptance/features/bootstrap/OccContext.php
Normal file
File diff suppressed because it is too large
Load Diff
6141
tests/acceptance/features/bootstrap/Provisioning.php
Normal file
6141
tests/acceptance/features/bootstrap/Provisioning.php
Normal file
File diff suppressed because it is too large
Load Diff
1661
tests/acceptance/features/bootstrap/PublicWebDavContext.php
Normal file
1661
tests/acceptance/features/bootstrap/PublicWebDavContext.php
Normal file
File diff suppressed because it is too large
Load Diff
192
tests/acceptance/features/bootstrap/SearchContext.php
Normal file
192
tests/acceptance/features/bootstrap/SearchContext.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
* @copyright Copyright (c) 2018 Artur Neumann artur@jankaritech.com
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License,
|
||||
* as published by the Free Software Foundation;
|
||||
* either version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use TestHelpers\OcisHelper;
|
||||
use TestHelpers\WebDavHelper;
|
||||
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
/**
|
||||
* context containing search related API steps
|
||||
*/
|
||||
class SearchContext implements Context {
|
||||
/**
|
||||
*
|
||||
* @var FeatureContext
|
||||
*/
|
||||
private $featureContext;
|
||||
|
||||
/**
|
||||
* @When user :user searches for :pattern using the WebDAV API
|
||||
* @When user :user searches for :pattern and limits the results to :limit items using the WebDAV API
|
||||
* @When user :user searches for :pattern using the WebDAV API requesting these properties:
|
||||
* @When user :user searches for :pattern and limits the results to :limit items using the WebDAV API requesting these properties:
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $pattern
|
||||
* @param string|null $limit
|
||||
* @param TableNode|null $properties
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function userSearchesUsingWebDavAPI(
|
||||
string $user,
|
||||
string $pattern,
|
||||
?string $limit = null,
|
||||
TableNode $properties = null
|
||||
):void {
|
||||
// Because indexing of newly uploaded files or directories with ocis is decoupled and occurs asynchronously, a short wait is necessary before searching files or folders.
|
||||
if (OcisHelper::isTestingOnOcis()) {
|
||||
sleep(4);
|
||||
}
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$baseUrl = $this->featureContext->getBaseUrl();
|
||||
$password = $this->featureContext->getPasswordForUser($user);
|
||||
$body
|
||||
= "<?xml version='1.0' encoding='utf-8' ?>\n" .
|
||||
" <oc:search-files xmlns:a='DAV:' xmlns:oc='http://owncloud.org/ns' >\n" .
|
||||
" <oc:search>\n" .
|
||||
" <oc:pattern>$pattern</oc:pattern>\n";
|
||||
if ($limit !== null) {
|
||||
$body .= " <oc:limit>$limit</oc:limit>\n";
|
||||
}
|
||||
|
||||
$body .= " </oc:search>\n";
|
||||
if ($properties !== null) {
|
||||
$propertiesRows = $properties->getRows();
|
||||
$body .= " <a:prop>";
|
||||
foreach ($propertiesRows as $property) {
|
||||
$body .= "<$property[0]/>";
|
||||
}
|
||||
$body .= " </a:prop>";
|
||||
}
|
||||
$body .= " </oc:search-files>";
|
||||
$response = WebDavHelper::makeDavRequest(
|
||||
$baseUrl,
|
||||
$user,
|
||||
$password,
|
||||
"REPORT",
|
||||
"/",
|
||||
null,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
$body,
|
||||
$this->featureContext->getDavPathVersion()
|
||||
);
|
||||
$this->featureContext->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then file/folder :path in the search result of user :user should contain these properties:
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $user
|
||||
* @param TableNode $properties
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function fileOrFolderInTheSearchResultShouldContainProperties(
|
||||
string $path,
|
||||
string $user,
|
||||
TableNode $properties
|
||||
):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$this->featureContext->verifyTableNodeColumns($properties, ['name', 'value']);
|
||||
$properties = $properties->getHash();
|
||||
$fileResult = $this->featureContext->findEntryFromPropfindResponse(
|
||||
$path,
|
||||
$user,
|
||||
"REPORT",
|
||||
);
|
||||
Assert::assertNotFalse(
|
||||
$fileResult,
|
||||
"could not find file/folder '$path'"
|
||||
);
|
||||
$fileProperties = $fileResult['value'][1]['value'][0]['value'];
|
||||
foreach ($properties as $property) {
|
||||
$foundProperty = false;
|
||||
$property['value'] = $this->featureContext->substituteInLineCodes(
|
||||
$property['value'],
|
||||
$user
|
||||
);
|
||||
foreach ($fileProperties as $fileProperty) {
|
||||
if ($fileProperty['name'] === $property['name']) {
|
||||
Assert::assertMatchesRegularExpression(
|
||||
"/" . $property['value'] . "/",
|
||||
$fileProperty['value']
|
||||
);
|
||||
$foundProperty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert::assertTrue(
|
||||
$foundProperty,
|
||||
"could not find property '" . $property['name'] . "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will run before EVERY scenario.
|
||||
* It will set the properties for this object.
|
||||
*
|
||||
* @BeforeScenario
|
||||
*
|
||||
* @param BeforeScenarioScope $scope
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function before(BeforeScenarioScope $scope):void {
|
||||
// Get the environment
|
||||
$environment = $scope->getEnvironment();
|
||||
// Get all the contexts you need in this context
|
||||
$this->featureContext = $environment->getContext('FeatureContext');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the search result by tags for user :user should contain these entries:
|
||||
*
|
||||
* @param string|null $user
|
||||
* @param TableNode $expectedEntries
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function theSearchResultByTagsForUserShouldContainTheseEntries(
|
||||
?string $user,
|
||||
TableNode $expectedEntries
|
||||
):void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$this->featureContext->verifyTableNodeColumnsCount($expectedEntries, 1);
|
||||
$expectedEntries = $expectedEntries->getRows();
|
||||
$expectedEntriesArray = [];
|
||||
$responseResourcesArray = $this->featureContext->findEntryFromReportResponse($user);
|
||||
foreach ($expectedEntries as $item) {
|
||||
\array_push($expectedEntriesArray, $item[0]);
|
||||
}
|
||||
Assert::assertEqualsCanonicalizing($expectedEntriesArray, $responseResourcesArray);
|
||||
}
|
||||
}
|
||||
4391
tests/acceptance/features/bootstrap/Sharing.php
Normal file
4391
tests/acceptance/features/bootstrap/Sharing.php
Normal file
File diff suppressed because it is too large
Load Diff
489
tests/acceptance/features/bootstrap/TUSContext.php
Normal file
489
tests/acceptance/features/bootstrap/TUSContext.php
Normal file
@@ -0,0 +1,489 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @author Artur Neumann <artur@jankaritech.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2020, ownCloud GmbH
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use TestHelpers\HttpRequestHelper;
|
||||
use TestHelpers\WebDavHelper;
|
||||
use TusPhp\Exception\ConnectionException;
|
||||
use TusPhp\Exception\TusException;
|
||||
use TusPhp\Tus\Client;
|
||||
use PHPUnit\Framework\Assert;
|
||||
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
/**
|
||||
* TUS related test steps
|
||||
*/
|
||||
class TUSContext implements Context {
|
||||
/**
|
||||
*
|
||||
* @var FeatureContext
|
||||
*/
|
||||
private $featureContext;
|
||||
|
||||
private $resourceLocation = null;
|
||||
|
||||
/**
|
||||
* @When user :user creates a new TUS resource on the WebDAV API with these headers:
|
||||
*
|
||||
* @param string $user
|
||||
* @param TableNode $headers
|
||||
* @param string $content
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function createNewTUSResourceWithHeaders(string $user, TableNode $headers, string $content = ''): void {
|
||||
$this->featureContext->verifyTableNodeColumnsCount($headers, 2);
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$password = $this->featureContext->getUserPassword($user);
|
||||
$this->resourceLocation = null;
|
||||
|
||||
$this->featureContext->setResponse(
|
||||
$this->featureContext->makeDavRequest(
|
||||
$user,
|
||||
"POST",
|
||||
null,
|
||||
$headers->getRowsHash(),
|
||||
$content,
|
||||
"files",
|
||||
null,
|
||||
false,
|
||||
$password
|
||||
)
|
||||
);
|
||||
$locationHeader = $this->featureContext->getResponse()->getHeader('Location');
|
||||
if (\sizeof($locationHeader) > 0) {
|
||||
$this->resourceLocation = $locationHeader[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :user has created a new TUS resource on the WebDAV API with these headers:
|
||||
*
|
||||
* @param string $user
|
||||
* @param TableNode $headers Tus-Resumable: 1.0.0 header is added automatically
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function createNewTUSResource(string $user, TableNode $headers): void {
|
||||
$rows = $headers->getRows();
|
||||
$rows[] = ['Tus-Resumable', '1.0.0'];
|
||||
$this->createNewTUSResourceWithHeaders($user, new TableNode($rows));
|
||||
$this->featureContext->theHTTPStatusCodeShouldBe(201);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^user "([^"]*)" sends a chunk to the last created TUS Location with offset "([^"]*)" and data "([^"]*)" using the WebDAV API$/
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $offset
|
||||
* @param string $data
|
||||
* @param string $checksum
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws GuzzleException
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function sendsAChunkToTUSLocationWithOffsetAndData(string $user, string $offset, string $data, string $checksum = ''): void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$password = $this->featureContext->getUserPassword($user);
|
||||
$this->featureContext->setResponse(
|
||||
HttpRequestHelper::sendRequest(
|
||||
$this->resourceLocation,
|
||||
$this->featureContext->getStepLineRef(),
|
||||
'PATCH',
|
||||
$user,
|
||||
$password,
|
||||
[
|
||||
'Content-Type' => 'application/offset+octet-stream',
|
||||
'Tus-Resumable' => '1.0.0',
|
||||
'Upload-Checksum' => $checksum,
|
||||
'Upload-Offset' => $offset
|
||||
],
|
||||
$data
|
||||
)
|
||||
);
|
||||
WebDavHelper::$SPACE_ID_FROM_OCIS = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user uploads file :source to :destination using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string|null $user
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @param array $uploadMetadata array of metadata to be placed in the
|
||||
* `Upload-Metadata` header.
|
||||
* see https://tus.io/protocols/resumable-upload.html#upload-metadata
|
||||
* Don't Base64 encode the value.
|
||||
* @param int $noOfChunks
|
||||
* @param int|null $bytes
|
||||
* @param string $checksum
|
||||
*
|
||||
* @return void
|
||||
* @throws ConnectionException
|
||||
* @throws GuzzleException
|
||||
* @throws JsonException
|
||||
* @throws ReflectionException
|
||||
* @throws TusException
|
||||
*/
|
||||
public function userUploadsUsingTusAFileTo(
|
||||
?string $user,
|
||||
string $source,
|
||||
string $destination,
|
||||
array $uploadMetadata = [],
|
||||
int $noOfChunks = 1,
|
||||
int $bytes = null,
|
||||
string $checksum = ''
|
||||
): void {
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$password = $this->featureContext->getUserPassword($user);
|
||||
$headers = [
|
||||
'Authorization' => 'Basic ' . \base64_encode($user . ':' . $password)
|
||||
];
|
||||
if ($bytes !== null) {
|
||||
$creationWithUploadHeader = [
|
||||
'Content-Type' => 'application/offset+octet-stream',
|
||||
'Tus-Resumable' => '1.0.0'
|
||||
];
|
||||
$headers = \array_merge($headers, $creationWithUploadHeader);
|
||||
}
|
||||
if ($checksum != '') {
|
||||
$checksumHeader = [
|
||||
'Upload-Checksum' => $checksum
|
||||
];
|
||||
$headers = \array_merge($headers, $checksumHeader);
|
||||
}
|
||||
|
||||
$client = new Client(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
['verify' => false,
|
||||
'headers' => $headers
|
||||
]
|
||||
);
|
||||
$client->setApiPath(
|
||||
WebDavHelper::getDavPath(
|
||||
$user,
|
||||
$this->featureContext->getDavPathVersion(),
|
||||
"files",
|
||||
WebDavHelper::$SPACE_ID_FROM_OCIS
|
||||
? WebDavHelper::$SPACE_ID_FROM_OCIS
|
||||
: $this->featureContext->getPersonalSpaceIdForUser($user)
|
||||
)
|
||||
);
|
||||
WebDavHelper::$SPACE_ID_FROM_OCIS = '';
|
||||
$client->setMetadata($uploadMetadata);
|
||||
$sourceFile = $this->featureContext->acceptanceTestsDirLocation() . $source;
|
||||
$client->setKey((string)rand())->file($sourceFile, $destination);
|
||||
$this->featureContext->pauseUploadDelete();
|
||||
|
||||
if ($bytes !== null) {
|
||||
$client->file($sourceFile, $destination)->createWithUpload($client->getKey(), $bytes);
|
||||
} elseif ($noOfChunks === 1) {
|
||||
$client->file($sourceFile, $destination)->upload();
|
||||
} else {
|
||||
$bytesPerChunk = (int)\ceil(\filesize($sourceFile) / $noOfChunks);
|
||||
for ($i = 0; $i < $noOfChunks; $i++) {
|
||||
$client->upload($bytesPerChunk);
|
||||
}
|
||||
}
|
||||
$this->featureContext->setLastUploadDeleteTime(\time());
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user uploads file with content :content to :destination using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $content
|
||||
* @param string $destination
|
||||
*
|
||||
* @return void
|
||||
* @throws GuzzleException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userUploadsAFileWithContentToUsingTus(
|
||||
string $user,
|
||||
string $content,
|
||||
string $destination
|
||||
): void {
|
||||
$tmpfname = $this->writeDataToTempFile($content);
|
||||
try {
|
||||
$this->userUploadsUsingTusAFileTo(
|
||||
$user,
|
||||
\basename($tmpfname),
|
||||
$destination
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
Assert::assertStringContainsString('TusPhp\Exception\FileException: Unable to create resource', (string)$e);
|
||||
}
|
||||
\unlink($tmpfname);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user uploads file with content :content in :noOfChunks chunks to :destination using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string|null $user
|
||||
* @param string $content
|
||||
* @param int|null $noOfChunks
|
||||
* @param string $destination
|
||||
*
|
||||
* @return void
|
||||
* @throws ConnectionException
|
||||
* @throws GuzzleException
|
||||
* @throws JsonException
|
||||
* @throws ReflectionException
|
||||
* @throws TusException
|
||||
* @throws Exception
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function userUploadsAFileWithContentInChunksUsingTus(
|
||||
?string $user,
|
||||
string $content,
|
||||
?int $noOfChunks,
|
||||
string $destination
|
||||
): void {
|
||||
$tmpfname = $this->writeDataToTempFile($content);
|
||||
$this->userUploadsUsingTusAFileTo(
|
||||
$user,
|
||||
\basename($tmpfname),
|
||||
$destination,
|
||||
[],
|
||||
$noOfChunks
|
||||
);
|
||||
\unlink($tmpfname);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user uploads file :source to :destination with mtime :mtime using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @param string $mtime Time in human readable format is taken as input which is converted into milliseconds that is used by API
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function userUploadsFileWithContentToWithMtimeUsingTUS(
|
||||
string $user,
|
||||
string $source,
|
||||
string $destination,
|
||||
string $mtime
|
||||
): void {
|
||||
$mtime = new DateTime($mtime);
|
||||
$mtime = $mtime->format('U');
|
||||
$user = $this->featureContext->getActualUsername($user);
|
||||
$this->userUploadsUsingTusAFileTo(
|
||||
$user,
|
||||
$source,
|
||||
$destination,
|
||||
['mtime' => $mtime]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $content
|
||||
*
|
||||
* @return string the file name
|
||||
* @throws Exception
|
||||
*/
|
||||
private function writeDataToTempFile(string $content): string {
|
||||
$tmpfname = \tempnam(
|
||||
$this->featureContext->acceptanceTestsDirLocation(),
|
||||
"tus-upload-test-"
|
||||
);
|
||||
if ($tmpfname === false) {
|
||||
throw new \Exception("could not create a temporary filename");
|
||||
}
|
||||
$tempfile = \fopen($tmpfname, "w");
|
||||
if ($tempfile === false) {
|
||||
throw new \Exception("could not open " . $tmpfname . " for write");
|
||||
}
|
||||
\fwrite($tempfile, $content);
|
||||
\fclose($tempfile);
|
||||
return $tmpfname;
|
||||
}
|
||||
|
||||
/**
|
||||
* @BeforeScenario
|
||||
*
|
||||
* @param BeforeScenarioScope $scope
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUpScenario(BeforeScenarioScope $scope): void {
|
||||
// Get the environment
|
||||
$environment = $scope->getEnvironment();
|
||||
// Get all the contexts you need in this context
|
||||
$this->featureContext = $environment->getContext('FeatureContext');
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user creates a new TUS resource with content :content on the WebDAV API with these headers:
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $content
|
||||
* @param TableNode $headers
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function userCreatesWithUpload(
|
||||
string $user,
|
||||
string $content,
|
||||
TableNode $headers
|
||||
): void {
|
||||
$this->createNewTUSResourceWithHeaders($user, $headers, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user creates file :source and uploads content :content in the same request using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $source
|
||||
* @param string $content
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function userUploadsWithCreatesWithUpload(
|
||||
string $user,
|
||||
string $source,
|
||||
string $content
|
||||
): void {
|
||||
$tmpfname = $this->writeDataToTempFile($content);
|
||||
$this->userUploadsUsingTusAFileTo(
|
||||
$user,
|
||||
\basename($tmpfname),
|
||||
$source,
|
||||
[],
|
||||
1,
|
||||
-1
|
||||
);
|
||||
\unlink($tmpfname);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user uploads file with checksum :checksum to the last created TUS Location with offset :offset and content :content using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $checksum
|
||||
* @param string $offset
|
||||
* @param string $content
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userUploadsFileWithChecksum(
|
||||
string $user,
|
||||
string $checksum,
|
||||
string $offset,
|
||||
string $content
|
||||
): void {
|
||||
$this->sendsAChunkToTUSLocationWithOffsetAndData($user, $offset, $content, $checksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :user has uploaded file with checksum :checksum to the last created TUS Location with offset :offset and content :content using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $checksum
|
||||
* @param string $offset
|
||||
* @param string $content
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userHasUploadedFileWithChecksum(
|
||||
string $user,
|
||||
string $checksum,
|
||||
string $offset,
|
||||
string $content
|
||||
): void {
|
||||
$this->sendsAChunkToTUSLocationWithOffsetAndData($user, $offset, $content, $checksum);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBe(204, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user sends a chunk to the last created TUS Location with offset :offset and data :data with checksum :checksum using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $offset
|
||||
* @param string $data
|
||||
* @param string $checksum
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userUploadsChunkFileWithChecksum(string $user, string $offset, string $data, string $checksum): void {
|
||||
$this->sendsAChunkToTUSLocationWithOffsetAndData($user, $offset, $data, $checksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given user :user has uploaded a chunk to the last created TUS Location with offset :offset and data :data with checksum :checksum using the TUS protocol on the WebDAV API
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $offset
|
||||
* @param string $data
|
||||
* @param string $checksum
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userHasUploadedChunkFileWithChecksum(string $user, string $offset, string $data, string $checksum): void {
|
||||
$this->sendsAChunkToTUSLocationWithOffsetAndData($user, $offset, $data, $checksum);
|
||||
$this->featureContext->theHTTPStatusCodeShouldBe(204, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @When user :user overwrites recently shared file with offset :offset and data :data with checksum :checksum using the TUS protocol on the WebDAV API with these headers:
|
||||
* @When user :user overwrites existing file with offset :offset and data :data with checksum :checksum using the TUS protocol on the WebDAV API with these headers:
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $offset
|
||||
* @param string $data
|
||||
* @param string $checksum
|
||||
* @param TableNode $headers Tus-Resumable: 1.0.0 header is added automatically
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws GuzzleException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function userOverwritesFileWithChecksum(string $user, string $offset, string $data, string $checksum, TableNode $headers): void {
|
||||
$this->createNewTUSResource($user, $headers);
|
||||
$this->userHasUploadedChunkFileWithChecksum($user, $offset, $data, $checksum);
|
||||
}
|
||||
}
|
||||
1182
tests/acceptance/features/bootstrap/TrashbinContext.php
Normal file
1182
tests/acceptance/features/bootstrap/TrashbinContext.php
Normal file
File diff suppressed because it is too large
Load Diff
5527
tests/acceptance/features/bootstrap/WebDav.php
Normal file
5527
tests/acceptance/features/bootstrap/WebDav.php
Normal file
File diff suppressed because it is too large
Load Diff
1396
tests/acceptance/features/bootstrap/WebDavPropertiesContext.php
Normal file
1396
tests/acceptance/features/bootstrap/WebDavPropertiesContext.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,19 +20,44 @@
|
||||
*
|
||||
*/
|
||||
|
||||
$pathToCore = \getenv('PATH_TO_CORE');
|
||||
if ($pathToCore === false) {
|
||||
$pathToCore = "../core";
|
||||
}
|
||||
use Composer\Autoload\ClassLoader;
|
||||
|
||||
require_once $pathToCore . '/tests/acceptance/features/bootstrap/bootstrap.php';
|
||||
$classLoader = new ClassLoader();
|
||||
|
||||
$classLoader = new \Composer\Autoload\ClassLoader();
|
||||
$classLoader->addPsr4(
|
||||
"",
|
||||
$pathToCore . "/tests/acceptance/features/bootstrap",
|
||||
true
|
||||
);
|
||||
$classLoader->addPsr4("TestHelpers\\", __DIR__ . "/../../../TestHelpers", true);
|
||||
|
||||
$classLoader->register();
|
||||
|
||||
// Sleep for 10 milliseconds
|
||||
const STANDARD_SLEEP_TIME_MILLISEC = 10;
|
||||
const STANDARD_SLEEP_TIME_MICROSEC = STANDARD_SLEEP_TIME_MILLISEC * 1000;
|
||||
|
||||
// Long timeout for use in code that needs to wait for known slow UI
|
||||
const LONG_UI_WAIT_TIMEOUT_MILLISEC = 60000;
|
||||
// Default timeout for use in code that needs to wait for the UI
|
||||
const STANDARD_UI_WAIT_TIMEOUT_MILLISEC = 10000;
|
||||
// Minimum timeout for use in code that needs to wait for the UI
|
||||
const MINIMUM_UI_WAIT_TIMEOUT_MILLISEC = 500;
|
||||
const MINIMUM_UI_WAIT_TIMEOUT_MICROSEC = MINIMUM_UI_WAIT_TIMEOUT_MILLISEC * 1000;
|
||||
|
||||
// Minimum timeout for emails
|
||||
const EMAIL_WAIT_TIMEOUT_SEC = 10;
|
||||
const EMAIL_WAIT_TIMEOUT_MILLISEC = EMAIL_WAIT_TIMEOUT_SEC * 1000;
|
||||
|
||||
// Default number of times to retry where retries are useful
|
||||
const STANDARD_RETRY_COUNT = 5;
|
||||
// Minimum number of times to retry where retries are useful
|
||||
const MINIMUM_RETRY_COUNT = 2;
|
||||
|
||||
// The remote server-under-test might or might not happen to have this directory.
|
||||
// If it does not exist, then the tests may end up creating it.
|
||||
const ACCEPTANCE_TEST_DIR_ON_REMOTE_SERVER = "tests/acceptance";
|
||||
|
||||
// The following directory should NOT already exist on the remote server-under-test.
|
||||
// Acceptance tests are free to do anything needed in this directory, and to
|
||||
// delete it during or at the end of testing.
|
||||
const TEMPORARY_STORAGE_DIR_ON_REMOTE_SERVER = ACCEPTANCE_TEST_DIR_ON_REMOTE_SERVER . "/server_tmp";
|
||||
|
||||
// The following directory is created, used, and deleted by tests that need to
|
||||
// use some "local external storage" on the server.
|
||||
const LOCAL_STORAGE_DIR_ON_REMOTE_SERVER = TEMPORARY_STORAGE_DIR_ON_REMOTE_SERVER . "/local_storage";
|
||||
|
||||
9
tests/acceptance/filesForUpload/'single'quotes.txt
Normal file
9
tests/acceptance/filesForUpload/'single'quotes.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
a file with a single quote i its name
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
BIN
tests/acceptance/filesForUpload/data.tar.gz
Normal file
BIN
tests/acceptance/filesForUpload/data.tar.gz
Normal file
Binary file not shown.
BIN
tests/acceptance/filesForUpload/data.zip
Normal file
BIN
tests/acceptance/filesForUpload/data.zip
Normal file
Binary file not shown.
1
tests/acceptance/filesForUpload/davtest.txt
Normal file
1
tests/acceptance/filesForUpload/davtest.txt
Normal file
@@ -0,0 +1 @@
|
||||
Dav-Test
|
||||
BIN
tests/acceptance/filesForUpload/example.gif
Normal file
BIN
tests/acceptance/filesForUpload/example.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 226 KiB |
1
tests/acceptance/filesForUpload/file_to_overwrite.txt
Normal file
1
tests/acceptance/filesForUpload/file_to_overwrite.txt
Normal file
@@ -0,0 +1 @@
|
||||
BLABLABLA
|
||||
93
tests/acceptance/filesForUpload/lorem-big.txt
Normal file
93
tests/acceptance/filesForUpload/lorem-big.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
a big lorem file
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
7
tests/acceptance/filesForUpload/lorem.txt
Normal file
7
tests/acceptance/filesForUpload/lorem.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
9
tests/acceptance/filesForUpload/new-'single'quotes.txt
Normal file
9
tests/acceptance/filesForUpload/new-'single'quotes.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
a file with a single quote i its name, but different to the original one
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
BIN
tests/acceptance/filesForUpload/new-data.tar.gz
Normal file
BIN
tests/acceptance/filesForUpload/new-data.tar.gz
Normal file
Binary file not shown.
BIN
tests/acceptance/filesForUpload/new-data.zip
Normal file
BIN
tests/acceptance/filesForUpload/new-data.zip
Normal file
Binary file not shown.
93
tests/acceptance/filesForUpload/new-lorem-big.txt
Normal file
93
tests/acceptance/filesForUpload/new-lorem-big.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
a big lorem file but different to the original one
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
9
tests/acceptance/filesForUpload/new-lorem.txt
Normal file
9
tests/acceptance/filesForUpload/new-lorem.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
lorem file that is different from the original one
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
@@ -0,0 +1,9 @@
|
||||
a file with funny characters in the file name but different from the original one
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
BIN
tests/acceptance/filesForUpload/simple.odt
Normal file
BIN
tests/acceptance/filesForUpload/simple.odt
Normal file
Binary file not shown.
BIN
tests/acceptance/filesForUpload/simple.pdf
Normal file
BIN
tests/acceptance/filesForUpload/simple.pdf
Normal file
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
a file with funny characters in the file name
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
BIN
tests/acceptance/filesForUpload/testavatar.jpg
Normal file
BIN
tests/acceptance/filesForUpload/testavatar.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
tests/acceptance/filesForUpload/testavatar.png
Normal file
BIN
tests/acceptance/filesForUpload/testavatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
3
tests/acceptance/filesForUpload/textfile.txt
Normal file
3
tests/acceptance/filesForUpload/textfile.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
This is a testfile.
|
||||
|
||||
Cheers.
|
||||
0
tests/acceptance/filesForUpload/zerobyte.txt
Normal file
0
tests/acceptance/filesForUpload/zerobyte.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
This must be the last skeleton file in this folder, when sorted alphabetically.
|
||||
Tests for performing actions on the last file in the folder try to find and use
|
||||
this file name.
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
@@ -0,0 +1,11 @@
|
||||
This file has a name so it would be the last after the upload, when sorted alphabetically.
|
||||
Tests for performing actions on the last file in the folder try to find and use
|
||||
this file name.
|
||||
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
|
||||
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
|
||||
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est
|
||||
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
|
||||
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
|
||||
130
tests/acceptance/lint-expected-failures.sh
Executable file
130
tests/acceptance/lint-expected-failures.sh
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
log_error() {
|
||||
echo -e "\e[31m$1\e[0m"
|
||||
}
|
||||
|
||||
log_info() {
|
||||
echo -e "\e[34m$1\e[0m"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "\e[32m$1\e[0m"
|
||||
}
|
||||
|
||||
declare -A scenarioLines
|
||||
|
||||
if [ -n "${EXPECTED_FAILURES_FILE}" ]
|
||||
then
|
||||
if [ -f "${EXPECTED_FAILURES_FILE}" ]
|
||||
then
|
||||
log_info "Checking expected failures in ${EXPECTED_FAILURES_FILE}"
|
||||
else
|
||||
log_error "Expected failures file ${EXPECTED_FAILURES_FILE} not found"
|
||||
log_error "Check the setting of EXPECTED_FAILURES_FILE environment variable"
|
||||
exit 1
|
||||
fi
|
||||
FINAL_EXIT_STATUS=0
|
||||
# If the last line of the expected-failures file ends without a newline character
|
||||
# then that line may not get processed by some of the bash code in this script
|
||||
# So check that the last character in the file is a newline
|
||||
if [ "$(tail -c1 "${EXPECTED_FAILURES_FILE}" | wc -l)" -eq 0 ]
|
||||
then
|
||||
log_error "Expected failures file ${EXPECTED_FAILURES_FILE} must end with a newline"
|
||||
log_error "Put a newline at the end of the last line and try again"
|
||||
FINAL_EXIT_STATUS=1
|
||||
fi
|
||||
# Check the expected-failures file to ensure that the lines are self-consistent
|
||||
# In most cases the features that are being run are in owncloud/core,
|
||||
# so assume that by default.
|
||||
FEATURE_FILE_REPO="owncloud/core"
|
||||
FEATURE_FILE_PATH="tests/acceptance/features"
|
||||
LINE_NUMBER=0
|
||||
while read -r INPUT_LINE
|
||||
do
|
||||
LINE_NUMBER=$(("$LINE_NUMBER" + 1))
|
||||
|
||||
# Ignore comment lines (starting with hash)
|
||||
if [[ "${INPUT_LINE}" =~ ^# ]]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
# A line of text in the feature file can be used to indicate that the
|
||||
# features being run are actually from some other repo. For example:
|
||||
# "The expected failures in this file are from features in the owncloud/ocis repo."
|
||||
# Write a line near the top of the expected-failures file to "declare" this,
|
||||
# overriding the default "owncloud/core"
|
||||
FEATURE_FILE_SPEC_LINE_FOUND="false"
|
||||
if [[ "${INPUT_LINE}" =~ features[[:blank:]]in[[:blank:]]the[[:blank:]]([a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+)[[:blank:]]repo ]]; then
|
||||
FEATURE_FILE_REPO="${BASH_REMATCH[1]}"
|
||||
log_info "Features are expected to be in the ${FEATURE_FILE_REPO} repo\n"
|
||||
FEATURE_FILE_SPEC_LINE_FOUND="true"
|
||||
fi
|
||||
if [[ "${INPUT_LINE}" =~ repo[[:blank:]]in[[:blank:]]the[[:blank:]]([a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+)[[:blank:]]folder[[:blank:]]tree ]]; then
|
||||
FEATURE_FILE_PATH="${BASH_REMATCH[1]}"
|
||||
log_info "Features are expected to be in the ${FEATURE_FILE_PATH} folder tree\n"
|
||||
FEATURE_FILE_SPEC_LINE_FOUND="true"
|
||||
fi
|
||||
if [[ $FEATURE_FILE_SPEC_LINE_FOUND == "true" ]]; then
|
||||
continue
|
||||
fi
|
||||
# Match lines that have "- [someSuite/someName.feature:n]" pattern on start
|
||||
# the part inside the brackets is the suite, feature and line number of the expected failure.
|
||||
if [[ "${INPUT_LINE}" =~ ^-[[:space:]]\[([a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+\.feature:[0-9]+)] ]]; then
|
||||
SUITE_SCENARIO_LINE="${BASH_REMATCH[1]}"
|
||||
elif [[
|
||||
# report for lines like: " - someSuite/someName.feature:n"
|
||||
"${INPUT_LINE}" =~ ^[[:space:]]*-[[:space:]][a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+\.feature:[0-9]+[[:space:]]*$ ||
|
||||
# report for lines starting with: "[someSuite/someName.feature:n]"
|
||||
"${INPUT_LINE}" =~ ^[[:space:]]*\[([a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+\.feature:[0-9]+)]
|
||||
]]; then
|
||||
log_error "> Line ${LINE_NUMBER}: Not in the correct format."
|
||||
log_error " + Actual Line : '${INPUT_LINE}'"
|
||||
log_error " - Expected Format : '- [suite/scenario.feature:line_number](scenario_line_url)'"
|
||||
FINAL_EXIT_STATUS=1
|
||||
continue
|
||||
else
|
||||
# otherwise, ignore the line
|
||||
continue
|
||||
fi
|
||||
# Find the link in round-brackets that should be after the SUITE_SCENARIO_LINE
|
||||
if [[ "${INPUT_LINE}" =~ \(([a-zA-Z0-9:/.#_-]+)\) ]]; then
|
||||
ACTUAL_LINK="${BASH_REMATCH[1]}"
|
||||
else
|
||||
log_error "Line ${LINE_NUMBER}: ${INPUT_LINE} : Link is empty"
|
||||
FINAL_EXIT_STATUS=1
|
||||
continue
|
||||
fi
|
||||
if [[ -n "${scenarioLines[${SUITE_SCENARIO_LINE}]:-}" ]];
|
||||
then
|
||||
log_error "> Line ${LINE_NUMBER}: Scenario line ${SUITE_SCENARIO_LINE} is duplicated"
|
||||
FINAL_EXIT_STATUS=1
|
||||
fi
|
||||
scenarioLines[${SUITE_SCENARIO_LINE}]="exists"
|
||||
OLD_IFS=${IFS}
|
||||
IFS=':'
|
||||
read -ra FEATURE_PARTS <<< "${SUITE_SCENARIO_LINE}"
|
||||
IFS=${OLD_IFS}
|
||||
SUITE_FEATURE="${FEATURE_PARTS[0]}"
|
||||
FEATURE_LINE="${FEATURE_PARTS[1]}"
|
||||
EXPECTED_LINK="https://github.com/${FEATURE_FILE_REPO}/blob/master/${FEATURE_FILE_PATH}/${SUITE_FEATURE}#L${FEATURE_LINE}"
|
||||
if [[ "${ACTUAL_LINK}" != "${EXPECTED_LINK}" ]]; then
|
||||
log_error "> Line ${LINE_NUMBER}: Link is not correct for ${SUITE_SCENARIO_LINE}"
|
||||
log_error " + Actual link : ${ACTUAL_LINK}"
|
||||
log_error " - Expected link : ${EXPECTED_LINK}"
|
||||
FINAL_EXIT_STATUS=1
|
||||
fi
|
||||
|
||||
done < "${EXPECTED_FAILURES_FILE}"
|
||||
else
|
||||
log_error "Environment variable EXPECTED_FAILURES_FILE must be defined to be the file to check"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ${FINAL_EXIT_STATUS} == 1 ]
|
||||
then
|
||||
log_error "\nErrors were found in the expected failures file - see the messages above!"
|
||||
else
|
||||
log_success "\nNo problems were found in the expected failures file."
|
||||
fi
|
||||
exit ${FINAL_EXIT_STATUS}
|
||||
1376
tests/acceptance/run.sh
Executable file
1376
tests/acceptance/run.sh
Executable file
File diff suppressed because it is too large
Load Diff
@@ -20,18 +20,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
$pathToCore = \getenv('PATH_TO_CORE');
|
||||
if ($pathToCore === false) {
|
||||
$pathToCore = "../core";
|
||||
}
|
||||
use Composer\Autoload\ClassLoader;
|
||||
|
||||
require_once $pathToCore . '/tests/acceptance/features/bootstrap/bootstrap.php';
|
||||
|
||||
$classLoader = new \Composer\Autoload\ClassLoader();
|
||||
$classLoader = new ClassLoader();
|
||||
$classLoader->addPsr4(
|
||||
"",
|
||||
$pathToCore . "/tests/acceptance/features/bootstrap",
|
||||
__DIR__ . "/../../../tests/acceptance/features/bootstrap",
|
||||
true
|
||||
);
|
||||
|
||||
$classLoader->addPsr4("TestHelpers\\", __DIR__ . "/../../../TestHelpers", true);
|
||||
$classLoader->register();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"require": {
|
||||
"behat/behat": "^3.9",
|
||||
"behat/gherkin": "^4.9",
|
||||
"behat/mink": "1.7.1",
|
||||
"friends-of-behat/mink-extension": "^2.5",
|
||||
"ciaranmcnulty/behat-stepthroughextension" : "dev-master",
|
||||
|
||||
Reference in New Issue
Block a user