From 80c299eb930988a8eadd98d91c35f24b1ad95581 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Fri, 29 Oct 2021 10:46:20 +0200 Subject: [PATCH 01/12] Upload a file --- ...{ListSpaces.feature => listSpaces.feature} | 2 +- .../features/apiSpaces/uploadSpaces.feature | 50 + .../features/bootstrap/SpacesContext.php | 1357 +++++++++-------- 3 files changed, 761 insertions(+), 648 deletions(-) rename tests/acceptance/features/apiSpaces/{ListSpaces.feature => listSpaces.feature} (96%) create mode 100644 tests/acceptance/features/apiSpaces/uploadSpaces.feature diff --git a/tests/acceptance/features/apiSpaces/ListSpaces.feature b/tests/acceptance/features/apiSpaces/listSpaces.feature similarity index 96% rename from tests/acceptance/features/apiSpaces/ListSpaces.feature rename to tests/acceptance/features/apiSpaces/listSpaces.feature index 209f0ffc5b..01458e1003 100644 --- a/tests/acceptance/features/apiSpaces/ListSpaces.feature +++ b/tests/acceptance/features/apiSpaces/listSpaces.feature @@ -55,7 +55,7 @@ Feature: List and create spaces | quota@@@total | 2000 | | root@@@webDavUrl | %base_url%/dav/spaces/%space_id% | - Scenario: Alice creates folder via Graph api in space, she expects a 201 code and she checks that folder exists + Scenario: Alice creates a folder via the Graph api in space, she expects a 201 code and she checks that folder exists Given the administrator gives "Alice" the role "Admin" using the settings api When user "Alice" creates a space "Project Venus" of type "project" with quota "2000" using the GraphApi And user "Alice" lists all available spaces via the GraphApi diff --git a/tests/acceptance/features/apiSpaces/uploadSpaces.feature b/tests/acceptance/features/apiSpaces/uploadSpaces.feature new file mode 100644 index 0000000000..cd017f30b0 --- /dev/null +++ b/tests/acceptance/features/apiSpaces/uploadSpaces.feature @@ -0,0 +1,50 @@ +@api @skipOnOcV10 +Feature: Upload files into a space + As a user + I want to be able to work with project spaces and quota + + Note - this feature is run in CI with ACCOUNTS_HASH_DIFFICULTY set to the default for production + See https://github.com/owncloud/ocis/issues/1542 and https://github.com/owncloud/ocis/pull/839 + + Background: + Given user "Alice" has been created with default attributes and without skeleton files + And user "Bob" has been created with default attributes and without skeleton files + + Scenario: Alice creates a folder via Graph api and uploads a file + Given the administrator gives "Alice" the role "Admin" using the settings api + When user "Alice" creates a space "Project Moon" of type "project" with quota "2000" using the GraphApi + And user "Alice" lists all available spaces via the GraphApi + And user "Alice" creates a folder "NewFolder" in space "Project Moon" using the WebDav Api + Then the HTTP status code should be "201" + And user "Alice" uploads a file inside space "Project Moon" with content "Test" to "test.txt" using the WebDAV API + Then the HTTP status code should be "201" + When user "Alice" lists the content of the space with the name "Project Moon" using the WebDav Api + Then the propfind result of the space should contain these entries: + | NewFolder/ | + | test.txt | + + Scenario: Alice creates uploads a file and checks her quota + Given the administrator gives "Alice" the role "Admin" using the settings api + When user "Alice" creates a space "Project Saturn" of type "project" with quota "2000" using the GraphApi + And the json responded should contain a space "Project Saturn" with these key and value pairs: + | key | value | + | driveType | project | + | id | %space_id% | + | name | Project Saturn| + | quota@@@total | 2000 | + And user "Alice" lists all available spaces via the GraphApi + And user "Alice" uploads a file inside space "Project Saturn" with content "Test" to "test.txt" using the WebDAV API + Then the HTTP status code should be "201" + When user "Alice" lists the content of the space with the name "Project Saturn" using the WebDav Api + Then the propfind result of the space should contain these entries: + | test.txt | + And user "Alice" lists all available spaces via the GraphApi + And the json responded should contain a space "Project Saturn" with these key and value pairs: + | key | value | + | driveType | project | + | id | %space_id% | + | name | Project Saturn| + | quota@@@state | normal | + | quota@@@total | 2000 | + | quota@@@remaining| 1996 | + | quota@@@used | 4 | diff --git a/tests/acceptance/features/bootstrap/SpacesContext.php b/tests/acceptance/features/bootstrap/SpacesContext.php index 8c8232573f..19af029a7e 100644 --- a/tests/acceptance/features/bootstrap/SpacesContext.php +++ b/tests/acceptance/features/bootstrap/SpacesContext.php @@ -20,6 +20,7 @@ * */ use Behat\Behat\Context\Context; +use Behat\Behat\Hook\Scope\AfterScenarioScope; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Behat\Gherkin\Node\TableNode; use GuzzleHttp\Exception\GuzzleException; @@ -35,692 +36,754 @@ require_once 'bootstrap.php'; */ class SpacesContext implements Context { - /** - * @var FeatureContext - */ - private FeatureContext $featureContext; + /** + * @var FeatureContext + */ + private FeatureContext $featureContext; - /** - * @var array - */ - private array $availableSpaces; + /** + * @var array + */ + private array $availableSpaces; - /** - * @return array - */ - public function getAvailableSpaces(): array { - return $this->availableSpaces; - } + /** + * @return array + */ + public function getAvailableSpaces(): array { + return $this->availableSpaces; + } - /** - * @param array $availableSpaces - * - * @return void - */ - public function setAvailableSpaces(array $availableSpaces): void { - $this->availableSpaces = $availableSpaces; - } + /** + * @param array $availableSpaces + * + * @return void + */ + public function setAvailableSpaces(array $availableSpaces): void { + $this->availableSpaces = $availableSpaces; + } - /** - * response content parsed from XML to an array - * - * @var array - */ - private array $responseXml = []; + /** + * response content parsed from XML to an array + * + * @var array + */ + private array $responseXml = []; - /** - * @return array - */ - public function getResponseXml(): array { - return $this->responseXml; - } + /** + * @return array + */ + public function getResponseXml(): array { + return $this->responseXml; + } - /** - * @param array $responseXml - * - * @return void - */ - public function setResponseXml(array $responseXml): void { - $this->responseXml = $responseXml; - } + /** + * @param array $responseXml + * + * @return void + */ + public function setResponseXml(array $responseXml): void { + $this->responseXml = $responseXml; + } - /** - * space id from last propfind request - * - * @var string - */ - private string $responseSpaceId; + /** + * space id from last propfind request + * + * @var string + */ + private string $responseSpaceId; - /** - * @param string $responseSpaceId - * - * @return void - */ - public function setResponseSpaceId(string $responseSpaceId): void { - $this->responseSpaceId = $responseSpaceId; - } + /** + * @param string $responseSpaceId + * + * @return void + */ + public function setResponseSpaceId(string $responseSpaceId): void { + $this->responseSpaceId = $responseSpaceId; + } - /** - * @return string - */ - public function getResponseSpaceId(): string { - return $this->responseSpaceId; - } + /** + * @return string + */ + public function getResponseSpaceId(): string { + return $this->responseSpaceId; + } - /** - * Get SpaceId by Name - * - * @param $name string - * - * @return string - * - * @throws Exception - */ - public function getSpaceIdByName(string $name): string { - $response = json_decode($this->featureContext->getResponse()->getBody(), true, 512, JSON_THROW_ON_ERROR); - if (isset($response['name']) && $response['name'] === $name) { - return $response["id"]; - } - foreach ($response["value"] as $spaceCandidate) { - if ($spaceCandidate['name'] === $name) { - return $spaceCandidate["id"]; - } - } - throw new Exception(__METHOD__ . " space with name $name not found"); - } + /** + * Get SpaceId by Name + * + * @param $name string + * @return string + * @throws Exception + */ + public function getSpaceIdByNameFromResponse(string $name): string + { + $space = $this->getSpaceByNameFromResponse($name); + Assert::assertIsArray($space, "Space with name $name not found"); + if (!isset($space["id"])) { + throw new Exception(__METHOD__ . " space with name $name not found"); + } + return $space["id"]; + } - /** - * Get Space Array by name - * - * @param string $name - * - * @return array - * - * @throws Exception - */ - public function getSpaceByName(string $name): array { - $response = json_decode($this->featureContext->getResponse()->getBody(), true, 512, JSON_THROW_ON_ERROR); - $spaceAsArray = $response; - if (isset($response['name']) && $response['name'] === $name) { - return $response; - } - foreach ($spaceAsArray["value"] as $spaceCandidate) { - if ($spaceCandidate['name'] === $name) { - return $spaceCandidate; - } - } - return []; - } + /** + * Get Space Array by name + * + * @param string $name + * @return array + * @throws Exception + */ + public function getSpaceByNameFromResponse(string $name): array + { + $response = json_decode($this->featureContext->getResponse()->getBody(), true, 512, JSON_THROW_ON_ERROR); + $spaceAsArray = $response; + if (isset($response['name']) && $response['name'] === $name) { + return $response; + } + foreach ($spaceAsArray["value"] as $spaceCandidate) { + if ($spaceCandidate['name'] === $name) { + return $spaceCandidate; + } + } + return []; + } - /** - * @BeforeScenario - * - * @param BeforeScenarioScope $scope - * - * @return void - * - * @throws Exception - */ - 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'); - SetupHelper::init( - $this->featureContext->getAdminUsername(), - $this->featureContext->getAdminPassword(), - $this->featureContext->getBaseUrl(), - $this->featureContext->getOcPath() - ); - } + /** + * @param string $name + * @return array + */ + public function getSpaceByName(string $name): array { + $spaces = $this->getAvailableSpaces(); + Assert::assertIsArray($spaces[$name]); + return $spaces[$name]; + } - /** - * Send Graph List Spaces Request - * - * @param string $baseUrl - * @param string $user - * @param string $password - * @param string $urlArguments - * @param string $xRequestId - * @param array $body - * @param array $headers - * - * @return ResponseInterface - * - * @throws GuzzleException - */ - public function listSpacesRequest( - string $baseUrl, - string $user, - string $password, - string $urlArguments, - string $xRequestId = '', - array $body = [], - array $headers = [] - ): ResponseInterface { - $fullUrl = $baseUrl; - if (!str_ends_with($fullUrl, '/')) { - $fullUrl .= '/'; - } - $fullUrl .= "graph/v1.0/me/drives/" . $urlArguments; + /** + * @BeforeScenario + * + * @param BeforeScenarioScope $scope + * + * @return void + * @throws Exception + */ + 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'); + SetupHelper::init( + $this->featureContext->getAdminUsername(), + $this->featureContext->getAdminPassword(), + $this->featureContext->getBaseUrl(), + $this->featureContext->getOcPath() + ); + } - return HttpRequestHelper::get($fullUrl, $xRequestId, $user, $password, $headers, $body); - } + /** + * Send Graph List Spaces Request + * + * @param string $baseUrl + * @param string $user + * @param string $password + * @param string $urlArguments + * @param string $xRequestId + * @param array $body + * @param array $headers + * + * @return ResponseInterface + * + * @throws GuzzleException + */ + public function listSpacesRequest( + string $baseUrl, + string $user, + string $password, + string $urlArguments, + string $xRequestId = '', + array $body = [], + array $headers = [] + ): ResponseInterface { + $fullUrl = $baseUrl; + if (!str_ends_with($fullUrl, '/')) { + $fullUrl .= '/'; + } + $fullUrl .= "graph/v1.0/me/drives/" . $urlArguments; - /** - * Send Graph Create Space Request - * - * @param string $baseUrl - * @param string $user - * @param string $password - * @param string $body - * @param string $xRequestId - * @param array $headers - * - * @return ResponseInterface - * - * @throws GuzzleException - */ - public function sendCreateSpaceRequest( - string $baseUrl, - string $user, - string $password, - string $body, - string $xRequestId = '', - array $headers = [] - ): ResponseInterface { - $fullUrl = $baseUrl; - if (!str_ends_with($fullUrl, '/')) { - $fullUrl .= '/'; - } - $fullUrl .= "graph/v1.0/drives/"; + return HttpRequestHelper::get($fullUrl, $xRequestId, $user, $password, $headers, $body); + } - return HttpRequestHelper::post($fullUrl, $xRequestId, $user, $password, $headers, $body); - } + /** + * Send Graph Create Space Request + * + * @param string $baseUrl + * @param string $user + * @param string $password + * @param string $body + * @param string $xRequestId + * @param array $headers + * + * @return ResponseInterface + * + * @throws GuzzleException + */ + public function sendCreateSpaceRequest( + string $baseUrl, + string $user, + string $password, + string $body, + string $xRequestId = '', + array $headers = [] + ): ResponseInterface { + $fullUrl = $baseUrl; + if (!str_ends_with($fullUrl, '/')) { + $fullUrl .= '/'; + } + $fullUrl .= "graph/v1.0/drives/"; - /** - * Send Propfind Request to Url - * - * @param string $fullUrl - * @param string $user - * @param string $password - * @param string $xRequestId - * @param array $headers - * - * @return ResponseInterface - * - * @throws GuzzleException - */ - public function sendPropfindRequestToUrl( - string $fullUrl, - string $user, - string $password, - string $xRequestId = '', - array $headers = [] - ): ResponseInterface { - return HttpRequestHelper::sendRequest($fullUrl, $xRequestId, 'PROPFIND', $user, $password, $headers); - } + return HttpRequestHelper::post($fullUrl, $xRequestId, $user, $password, $headers, $body); + } - /** - * @When /^user "([^"]*)" lists all available spaces via the GraphApi$/ - * - * @param string $user - * - * @return void - * - * @throws GuzzleException - */ - public function theUserListsAllHisAvailableSpacesUsingTheGraphApi(string $user): void { - $this->featureContext->setResponse( - $this->listSpacesRequest( - $this->featureContext->getBaseUrl(), - $user, - $this->featureContext->getPasswordForUser($user), - "", - "" - ) - ); - $this->rememberTheAvailableSpaces(); - } + /** + * Send Propfind Request to Url + * + * @param string $fullUrl + * @param string $user + * @param string $password + * @param string $xRequestId + * @param array $headers + * + * @return ResponseInterface + * + * @throws GuzzleException + */ + public function sendPropfindRequestToUrl( + string $fullUrl, + string $user, + string $password, + string $xRequestId = '', + array $headers = [] + ): ResponseInterface { + return HttpRequestHelper::sendRequest($fullUrl, $xRequestId, 'PROPFIND', $user, $password, $headers); + } - /** - * @When /^user "([^"]*)" creates a space "([^"]*)" of type "([^"]*)" with the default quota using the GraphApi$/ - * - * @param string $user - * @param string $spaceName - * @param string $spaceType - * - * @return void - * - * @throws GuzzleException - * @throws Exception - */ - public function theUserCreatesASpaceUsingTheGraphApi( - string $user, - string $spaceName, - string $spaceType - ): void { - $space = ["Name" => $spaceName, "driveType" => $spaceType]; - $body = json_encode($space, JSON_THROW_ON_ERROR); - $this->featureContext->setResponse( - $this->sendCreateSpaceRequest( - $this->featureContext->getBaseUrl(), - $user, - $this->featureContext->getPasswordForUser($user), - $body, - "" - ) - ); - } + /** + * Send Put Request to Url + * + * @param string $fullUrl + * @param string $user + * @param string $password + * @param string $xRequestId + * @param array $headers + * @param string $content + * @return ResponseInterface + * @throws GuzzleException + */ + public function sendPutRequestToUrl( + string $fullUrl, + string $user, + string $password, + string $xRequestId = '', + array $headers = [], + string $content = "" + ): ResponseInterface + { + return HttpRequestHelper::sendRequest($fullUrl, $xRequestId, 'PUT', $user, $password, $headers, $content); + } - /** - * @When /^user "([^"]*)" creates a space "([^"]*)" of type "([^"]*)" with quota "([^"]*)" using the GraphApi$/ - * - * @param string $user - * @param string $spaceName - * @param string $spaceType - * @param int $quota - * - * @return void - * - * @throws GuzzleException - * @throws Exception - */ - public function theUserCreatesASpaceWithQuotaUsingTheGraphApi( - string $user, - string $spaceName, - string $spaceType, - int $quota - ): void { - $space = ["Name" => $spaceName, "driveType" => $spaceType, "quota" => ["total" => $quota]]; - $body = json_encode($space); - $this->featureContext->setResponse( - $this->sendCreateSpaceRequest( - $this->featureContext->getBaseUrl(), - $user, - $this->featureContext->getPasswordForUser($user), - $body, - "" - ) - ); - } + /** + * @When /^user "([^"]*)" lists all available spaces via the GraphApi$/ + * + * @param string $user + * @return void + * @throws GuzzleException + */ + public function theUserListsAllHisAvailableSpacesUsingTheGraphApi(string $user): void + { + $this->featureContext->setResponse( + $this->listSpacesRequest( + $this->featureContext->getBaseUrl(), + $user, + $this->featureContext->getPasswordForUser($user), + "", + "" + ) + ); + $this->rememberTheAvailableSpaces(); + } - /** - * @When /^the administrator gives "([^"]*)" the role "([^"]*)" using the settings api$/ - * - * @param string $user - * @param string $role - * - * @return void - * - * @throws GuzzleException - * @throws Exception - */ - public function theAdministratorGivesUserTheRole(string $user, string $role): void { - $admin = $this->featureContext->getAdminUsername(); - $password = $this->featureContext->getAdminPassword(); - $headers = []; - $bundles = []; - $accounts = []; - $assignment = []; + /** + * @When /^user "([^"]*)" creates a space "([^"]*)" of type "([^"]*)" with the default quota using the GraphApi$/ + * + * @param string $user + * @param string $spaceName + * @param string $spaceType + * + * @return void + * + * @throws GuzzleException + * @throws Exception + */ + public function theUserCreatesASpaceUsingTheGraphApi( + string $user, + string $spaceName, + string $spaceType + ): void { + $space = ["Name" => $spaceName, "driveType" => $spaceType]; + $body = json_encode($space, JSON_THROW_ON_ERROR); + $this->featureContext->setResponse( + $this->sendCreateSpaceRequest( + $this->featureContext->getBaseUrl(), + $user, + $this->featureContext->getPasswordForUser($user), + $body, + "" + ) + ); + } - $baseUrl = $this->featureContext->getBaseUrl(); - if (!str_ends_with($baseUrl, '/')) { - $baseUrl .= '/'; - } - // get the roles list first - $fullUrl = $baseUrl . "api/v0/settings/roles-list"; - $this->featureContext->setResponse(HttpRequestHelper::post($fullUrl, "", $admin, $password, $headers, "{}")); - if ($this->featureContext->getResponse()) { - $rawBody = $this->featureContext->getResponse()->getBody()->getContents(); - if (isset(\json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["bundles"])) { - $bundles = \json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["bundles"]; - } - } - $roleToAssign = ""; - foreach ($bundles as $value) { - // find the selected role - if ($value["displayName"] === $role) { - $roleToAssign = $value; - } - } - Assert::assertNotEmpty($roleToAssign, "The selected role $role could not be found"); + /** + * @When /^user "([^"]*)" creates a space "([^"]*)" of type "([^"]*)" with quota "([^"]*)" using the GraphApi$/ + * + * @param string $user + * @param string $spaceName + * @param string $spaceType + * @param int $quota + * + * @return void + * + * @throws GuzzleException + * @throws Exception + */ + public function theUserCreatesASpaceWithQuotaUsingTheGraphApi( + string $user, + string $spaceName, + string $spaceType, + int $quota + ): void { + $space = ["Name" => $spaceName, "driveType" => $spaceType, "quota" => ["total" => $quota]]; + $body = json_encode($space); + $this->featureContext->setResponse( + $this->sendCreateSpaceRequest( + $this->featureContext->getBaseUrl(), + $user, + $this->featureContext->getPasswordForUser($user), + $body, + "" + ) + ); + } - // get the accounts list first - $fullUrl = $baseUrl . "api/v0/accounts/accounts-list"; - $this->featureContext->setResponse(HttpRequestHelper::post($fullUrl, "", $admin, $password, $headers, "{}")); - if ($this->featureContext->getResponse()) { - $rawBody = $this->featureContext->getResponse()->getBody()->getContents(); - if (isset(\json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["accounts"])) { - $accounts = \json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["accounts"]; - } - } - $accountToChange = ""; - foreach ($accounts as $account) { - // find the selected user - if ($account["preferredName"] === $user) { - $accountToChange = $account; - } - } - Assert::assertNotEmpty($accountToChange, "The selected account $user does not exist"); + /** + * @When /^the administrator gives "([^"]*)" the role "([^"]*)" using the settings api$/ + * + * @param string $user + * @param string $role + * + * @return void + * + * @throws GuzzleException + * @throws Exception + */ + public function theAdministratorGivesUserTheRole(string $user, string $role): void { + $admin = $this->featureContext->getAdminUsername(); + $password = $this->featureContext->getAdminPassword(); + $headers = []; + $bundles = []; + $accounts = []; + $assignment = []; - // set the new role - $fullUrl = $baseUrl . "api/v0/settings/assignments-add"; - $body = json_encode(["account_uuid" => $accountToChange["id"], "role_id" => $roleToAssign["id"]], JSON_THROW_ON_ERROR); + $baseUrl = $this->featureContext->getBaseUrl(); + if (!str_ends_with($baseUrl, '/')) { + $baseUrl .= '/'; + } + // get the roles list first + $fullUrl = $baseUrl . "api/v0/settings/roles-list"; + $this->featureContext->setResponse(HttpRequestHelper::post($fullUrl, "", $admin, $password, $headers, "{}")); + if ($this->featureContext->getResponse()) { + $rawBody = $this->featureContext->getResponse()->getBody()->getContents(); + if (isset(\json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["bundles"])) { + $bundles = \json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["bundles"]; + } + } + $roleToAssign = ""; + foreach ($bundles as $value) { + // find the selected role + if ($value["displayName"] === $role) { + $roleToAssign = $value; + } + } + Assert::assertNotEmpty($roleToAssign, "The selected role $role could not be found"); - $this->featureContext->setResponse(HttpRequestHelper::post($fullUrl, "", $admin, $password, $headers, $body)); - if ($this->featureContext->getResponse()) { - $rawBody = $this->featureContext->getResponse()->getBody()->getContents(); - if (isset(\json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["assignment"])) { - $assignment = \json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["assignment"]; - } - } + // get the accounts list first + $fullUrl = $baseUrl . "api/v0/accounts/accounts-list"; + $this->featureContext->setResponse(HttpRequestHelper::post($fullUrl, "", $admin, $password, $headers, "{}")); + if ($this->featureContext->getResponse()) { + $rawBody = $this->featureContext->getResponse()->getBody()->getContents(); + if (isset(\json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["accounts"])) { + $accounts = \json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["accounts"]; + } + } + $accountToChange = ""; + foreach ($accounts as $account) { + // find the selected user + if ($account["preferredName"] === $user) { + $accountToChange = $account; + } + } + Assert::assertNotEmpty($accountToChange, "The selected account $user does not exist"); - Assert::assertEquals($accountToChange["id"], $assignment["accountUuid"]); - Assert::assertEquals($roleToAssign["id"], $assignment["roleId"]); - } + // set the new role + $fullUrl = $baseUrl . "api/v0/settings/assignments-add"; + $body = json_encode(["account_uuid" => $accountToChange["id"], "role_id" => $roleToAssign["id"]], JSON_THROW_ON_ERROR); - /** - * Remember the available Spaces - * - * @return void - * - * @throws Exception - */ - public function rememberTheAvailableSpaces(): void { - $rawBody = $this->featureContext->getResponse()->getBody()->getContents(); - $drives = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR); - if (isset($drives["value"])) { - $drives = $drives["value"]; - } + $this->featureContext->setResponse(HttpRequestHelper::post($fullUrl, "", $admin, $password, $headers, $body)); + if ($this->featureContext->getResponse()) { + $rawBody = $this->featureContext->getResponse()->getBody()->getContents(); + if (isset(\json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["assignment"])) { + $assignment = \json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR)["assignment"]; + } + } - Assert::assertArrayHasKey(0, $drives, "No drives were found on that endpoint"); - $spaces = []; - foreach ($drives as $drive) { - $spaces[$drive["name"]] = $drive; - } - $this->setAvailableSpaces($spaces); - Assert::assertNotEmpty($spaces, "No spaces have been found"); - } + Assert::assertEquals($accountToChange["id"], $assignment["accountUuid"]); + Assert::assertEquals($roleToAssign["id"], $assignment["roleId"]); + } - /** - * @When /^user "([^"]*)" lists the content of the space with the name "([^"]*)" using the WebDav Api$/ - * - * @param string $user - * @param string $name - * - * @return void - * - * @throws GuzzleException - */ - public function theUserListsTheContentOfAPersonalSpaceRootUsingTheWebDAvApi( - string $user, - string $name - ): void { - $spaceId = $this->getAvailableSpaces()[$name]["id"]; - $spaceWebDavUrl = $this->getAvailableSpaces()[$name]["root"]["webDavUrl"]; - $this->featureContext->setResponse( - $this->sendPropfindRequestToUrl( - $spaceWebDavUrl, - $user, - $this->featureContext->getPasswordForUser($user), - "", - [], - ) - ); - $this->setResponseSpaceId($spaceId); - $this->setResponseXml( - HttpRequestHelper::parseResponseAsXml($this->featureContext->getResponse()) - ); - } + /** + * Remember the available Spaces + * + * @return void + * + * @throws Exception + */ + public function rememberTheAvailableSpaces(): void { + $rawBody = $this->featureContext->getResponse()->getBody()->getContents(); + $drives = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR); + if (isset($drives["value"])) { + $drives = $drives["value"]; + } - /** - * @Then /^the (?:propfind|search) result of the space should (not|)\s?contain these (?:files|entries):$/ - * - * @param string $shouldOrNot (not|) - * @param TableNode $expectedFiles - * - * @return void - * - * @throws Exception - */ - public function thePropfindResultShouldContainEntries( - string $shouldOrNot, - TableNode $expectedFiles - ):void { - $this->propfindResultShouldContainEntries( - $shouldOrNot, - $expectedFiles, - ); - } + Assert::assertArrayHasKey(0, $drives, "No drives were found on that endpoint"); + $spaces = []; + foreach ($drives as $drive) { + $spaces[$drive["name"]] = $drive; + } + $this->setAvailableSpaces($spaces); + Assert::assertNotEmpty($spaces, "No spaces have been found"); + } - /** - * @Then /^the json responded should contain a space "([^"]*)" with these key and value pairs:$/ - * - * @param string $spaceName - * @param TableNode $table - * - * @return void - * - * @throws Exception - */ - public function jsonRespondedShouldContain( - string $spaceName, - TableNode $table - ): void { - $this->featureContext->verifyTableNodeColumns($table, ['key', 'value']); - Assert::assertIsArray($spaceAsArray = $this->getSpaceByName($spaceName), "No space with name $spaceName found"); - foreach ($table->getHash() as $row) { - // remember the original Space Array - $original = $spaceAsArray; - $row['value'] = $this->featureContext->substituteInLineCodes( - $row['value'], - $this->featureContext->getCurrentUser(), - [], - [ - [ - "code" => "%space_id%", - "function" => - [$this, "getSpaceIdByName"], - "parameter" => [$spaceName] - ] - ] - ); - $segments = explode("@@@", $row["key"]); - // traverse down in the array - foreach ($segments as $segment) { - $arrayKeyExists = \array_key_exists($segment, $spaceAsArray); - $key = $row["key"]; - Assert::assertTrue($arrayKeyExists, "The key $key does not exist on the response"); - if ($arrayKeyExists) { - $spaceAsArray = $spaceAsArray[$segment]; - } - } - Assert::assertEquals($row["value"], $spaceAsArray); - // set the spaceArray to the point before traversing - $spaceAsArray = $original; - } - } + /** + * @When /^user "([^"]*)" lists the content of the space with the name "([^"]*)" using the WebDav Api$/ + * + * @param string $user + * @param string $name + * @return void + * @throws GuzzleException + */ + public function theUserListsTheContentOfAPersonalSpaceRootUsingTheWebDAvApi( + string $user, + string $name + ): void + { + $space = $this->getSpaceByName($name); + Assert::assertIsArray($space); + Assert::assertNotEmpty($spaceId = $space["id"]); + Assert::assertNotEmpty($spaceWebDavUrl = $space["root"]["webDavUrl"]); + $this->featureContext->setResponse( + $this->sendPropfindRequestToUrl( + $spaceWebDavUrl, + $user, + $this->featureContext->getPasswordForUser($user), + "", + [], + ) + ); + $this->setResponseSpaceId($spaceId); + $this->setResponseXml(HttpRequestHelper::parseResponseAsXml($this->featureContext->getResponse()) + ); + } - /** - * @param string $shouldOrNot (not|) - * @param TableNode $expectedFiles - * - * @return void - * - * @throws Exception - */ - public function propfindResultShouldContainEntries( - string $shouldOrNot, - TableNode $expectedFiles - ): void { - $this->verifyTableNodeColumnsCount($expectedFiles, 1); - $elementRows = $expectedFiles->getRows(); - $should = ($shouldOrNot !== "not"); + /** + * @Then /^the (?:propfind|search) result of the space should (not|)\s?contain these (?:files|entries):$/ + * + * @param string $shouldOrNot (not|) + * @param TableNode $expectedFiles + * + * @return void + * + * @throws Exception + */ + public function thePropfindResultShouldContainEntries( + string $shouldOrNot, + TableNode $expectedFiles + ):void { + $this->propfindResultShouldContainEntries( + $shouldOrNot, + $expectedFiles, + ); + } - foreach ($elementRows as $expectedFile) { - $fileFound = $this->findEntryFromPropfindResponse( - $expectedFile[0] - ); - if ($should) { - Assert::assertNotEmpty( - $fileFound, - "response does not contain the entry '$expectedFile[0]'" - ); - } else { - Assert::assertFalse( - $fileFound, - "response does contain the entry '$expectedFile[0]' but should not" - ); - } - } - } + /** + * @Then /^the json responded should contain a space "([^"]*)" with these key and value pairs:$/ + * + * @param string $spaceName + * @param TableNode $table + * + * @return void + * @throws Exception + */ + public function jsonRespondedShouldContain( + string $spaceName, + TableNode $table + ): void { + $this->featureContext->verifyTableNodeColumns($table, ['key', 'value']); + Assert::assertIsArray($spaceAsArray = $this->getSpaceByNameFromResponse($spaceName), "No space with name $spaceName found"); + foreach ($table->getHash() as $row) { + // remember the original Space Array + $original = $spaceAsArray; + $row['value'] = $this->featureContext->substituteInLineCodes( + $row['value'], + $this->featureContext->getCurrentUser(), + [], + [ + [ + "code" => "%space_id%", + "function" => + [$this, "getSpaceIdByNameFromResponse"], + "parameter" => [$spaceName] + ] + ] + ); + $segments = explode("@@@", $row["key"]); + // traverse down in the array + foreach ($segments as $segment) { + $arrayKeyExists = array_key_exists($segment, $spaceAsArray); + $key = $row["key"]; + Assert::assertTrue($arrayKeyExists, "The key $key does not exist on the response"); + if ($arrayKeyExists) { + $spaceAsArray = $spaceAsArray[$segment]; + } + } + Assert::assertEquals($row["value"], $spaceAsArray); + // set the spaceArray to the point before traversing + $spaceAsArray = $original; + } + } - /** - * Verify that the tableNode contains expected number of columns - * - * @param TableNode $table - * @param int $count - * - * @return void - * - * @throws Exception - */ - public function verifyTableNodeColumnsCount( - TableNode $table, - int $count - ): void { - if (\count($table->getRows()) < 1) { - throw new Exception("Table should have at least one row."); - } - $rowCount = \count($table->getRows()[0]); - if ($count !== $rowCount) { - throw new Exception("Table expected to have $count rows but found $rowCount"); - } - } + /** + * @param string $shouldOrNot (not|) + * @param TableNode $expectedFiles + * + * @return void + * + * @throws Exception + */ + public function propfindResultShouldContainEntries( + string $shouldOrNot, + TableNode $expectedFiles + ): void { + $this->verifyTableNodeColumnsCount($expectedFiles, 1); + $elementRows = $expectedFiles->getRows(); + $should = ($shouldOrNot !== "not"); - /** - * parses a PROPFIND response from $this->response into xml - * and returns found search results if found else returns false - * - * @param string|null $entryNameToSearch - * - * @return array - * string if $entryNameToSearch is given and is found - * array if $entryNameToSearch is not given - * boolean false if $entryNameToSearch is given and is not found - */ - public function findEntryFromPropfindResponse( - string $entryNameToSearch = null - ): array { - $spaceId = $this->getResponseSpaceId(); - //if we are using that step the second time in a scenario e.g. 'But ... should not' - //then don't parse the result again, because the result in a ResponseInterface - if (empty($this->getResponseXml())) { - $this->setResponseXml( - HttpRequestHelper::parseResponseAsXml($this->featureContext->getResponse()) - ); - } - Assert::assertNotEmpty($this->getResponseXml(), __METHOD__ . ' Response is empty'); - Assert::assertNotEmpty($spaceId, __METHOD__ . ' SpaceId is empty'); + foreach ($elementRows as $expectedFile) { + $fileFound = $this->findEntryFromPropfindResponse( + $expectedFile[0] + ); + if ($should) { + Assert::assertNotEmpty( + $fileFound, + "response does not contain the entry '$expectedFile[0]'" + ); + } else { + Assert::assertFalse( + $fileFound, + "response does contain the entry '$expectedFile[0]' but should not" + ); + } + } + } - // trim any leading "/" passed by the caller, we can just match the "raw" name - $trimmedEntryNameToSearch = \trim($entryNameToSearch, "/"); + /** + * Verify that the tableNode contains expected number of columns + * + * @param TableNode $table + * @param int $count + * + * @return void + * + * @throws Exception + */ + public function verifyTableNodeColumnsCount( + TableNode $table, + int $count + ): void { + if (\count($table->getRows()) < 1) { + throw new Exception("Table should have at least one row."); + } + $rowCount = \count($table->getRows()[0]); + if ($count !== $rowCount) { + throw new Exception("Table expected to have $count rows but found $rowCount"); + } + } - // topWebDavPath should be something like /remote.php/webdav/ or - // /remote.php/dav/files/alice/ - $topWebDavPath = "/" . "dav/spaces/" . $spaceId . "/"; + /** + * parses a PROPFIND response from $this->response into xml + * and returns found search results if found else returns false + * + * @param string|null $entryNameToSearch + * + * @return array + * string if $entryNameToSearch is given and is found + * array if $entryNameToSearch is not given + * boolean false if $entryNameToSearch is given and is not found + */ + public function findEntryFromPropfindResponse( + string $entryNameToSearch = null + ): array { + $spaceId = $this->getResponseSpaceId(); + //if we are using that step the second time in a scenario e.g. 'But ... should not' + //then don't parse the result again, because the result in a ResponseInterface + if (empty($this->getResponseXml())) { + $this->setResponseXml( + HttpRequestHelper::parseResponseAsXml($this->featureContext->getResponse()) + ); + } + Assert::assertNotEmpty($this->getResponseXml(), __METHOD__ . ' Response is empty'); + Assert::assertNotEmpty($spaceId, __METHOD__ . ' SpaceId is empty'); - Assert::assertIsArray( - $this->responseXml, - __METHOD__ . " responseXml for space $spaceId is not an array" - ); - Assert::assertArrayHasKey( - "value", - $this->responseXml, - __METHOD__ . " responseXml for space $spaceId does not have key 'value'" - ); - $multistatusResults = $this->responseXml["value"]; - $results = []; - if ($multistatusResults !== null) { - foreach ($multistatusResults as $multistatusResult) { - $entryPath = $multistatusResult['value'][0]['value']; - $entryName = \str_replace($topWebDavPath, "", $entryPath); - $entryName = \rawurldecode($entryName); - $entryName = \trim($entryName, "/"); - if ($trimmedEntryNameToSearch === $entryName) { - return $multistatusResult; - } - $results[] = $entryName; - } - } - if ($entryNameToSearch === null) { - return $results; - } - return []; - } + // trim any leading "/" passed by the caller, we can just match the "raw" name + $trimmedEntryNameToSearch = \trim($entryNameToSearch, "/"); - /** - * @When /^user "([^"]*)" creates a folder "([^"]*)" in space "([^"]*)" using the WebDav Api$/ - * - * @param string $user - * @param string $folder - * @param string $spaceName - * - * @return void - * - * @throws GuzzleException - */ - public function theUserCreatesAFolderUsingTheGraphApi( - string $user, - string $folder, - string $spaceName - ): void { - $this->featureContext->setResponse( - $this->sendCreateFolderRequest( - $this->featureContext->getBaseUrl(), - "MKCOL", - $user, - $this->featureContext->getPasswordForUser($user), - $folder, - $spaceName - ) - ); - } + // topWebDavPath should be something like /remote.php/webdav/ or + // /remote.php/dav/files/alice/ + $topWebDavPath = "/" . "dav/spaces/" . $spaceId . "/"; - /** - * Send Graph Create Space Request - * - * @param string $baseUrl - * @param string $method - * @param string $user - * @param string $password - * @param string $folder - * @param string $spaceName - * @param string $xRequestId - * @param array $headers - * - * @return ResponseInterface - * - * @throws GuzzleException - */ - public function sendCreateFolderRequest( - string $baseUrl, - string $method, - string $user, - string $password, - string $folder, - string $spaceName, - string $xRequestId = '', - array $headers = [] - ): ResponseInterface { - $spaceId = $this->getAvailableSpaces()[$spaceName]["id"]; - $fullUrl = $baseUrl; - if (!str_ends_with($fullUrl, '/')) { - $fullUrl .= '/'; - } - $fullUrl .= "dav/spaces/" . $spaceId . '/' . $folder; + Assert::assertIsArray( + $this->responseXml, + __METHOD__ . " responseXml for space $spaceId is not an array" + ); + Assert::assertArrayHasKey( + "value", + $this->responseXml, + __METHOD__ . " responseXml for space $spaceId does not have key 'value'" + ); + $multistatusResults = $this->responseXml["value"]; + $results = []; + if ($multistatusResults !== null) { + foreach ($multistatusResults as $multistatusResult) { + $entryPath = $multistatusResult['value'][0]['value']; + $entryName = \str_replace($topWebDavPath, "", $entryPath); + $entryName = \rawurldecode($entryName); + $entryName = \trim($entryName, "/"); + if ($trimmedEntryNameToSearch === $entryName) { + return $multistatusResult; + } + $results[] = $entryName; + } + } + if ($entryNameToSearch === null) { + return $results; + } + return []; + } - return HttpRequestHelper::sendRequest($fullUrl, $xRequestId, $method, $user, $password, $headers); - } + /** + * @When /^user "([^"]*)" creates a folder "([^"]*)" in space "([^"]*)" using the WebDav Api$/ + * + * @param string $user + * @param string $folder + * @param string $spaceName + * + * @return void + * + * @throws GuzzleException + */ + public function theUserCreatesAFolderUsingTheGraphApi( + string $user, + string $folder, + string $spaceName + ): void { + $this->featureContext->setResponse( + $this->sendCreateFolderRequest( + $this->featureContext->getBaseUrl(), + "MKCOL", + $user, + $this->featureContext->getPasswordForUser($user), + $folder, + $spaceName + ) + ); + } + + /** + * @When /^user "([^"]*)" uploads a file inside space "([^"]*)" with content "([^"]*)" to "([^"]*)" using the WebDAV API$/ + * + * @param string $user + * @param string $spaceName + * @param string $content + * @param string $destination + * + * @return void + * @throws GuzzleException + * @throws Exception + */ + public function theUserUploadsAFileToSpace( + string $user, + string $spaceName, + string $content, + string $destination + ): void + { + $space = $this->getSpaceByName($spaceName); + Assert::assertIsArray($space, "Space with name $spaceName not found"); + Assert::assertNotEmpty($space["root"]["webDavUrl"], "WebDavUrl for space with name $spaceName not found"); + + $this->featureContext->setResponse( + $this->sendPutRequestToUrl( + $space["root"]["webDavUrl"] . "/" . $destination, + $user, + $this->featureContext->getPasswordForUser($user), + "", + [], + $content + ) + ); + $this->featureContext->theHTTPStatusCodeShouldBe([201, 204]); + } + + /** + * Send Graph Create Folder Request + * + * @param string $baseUrl + * @param string $method + * @param string $user + * @param string $password + * @param string $folder + * @param string $spaceName + * @param string $xRequestId + * @param array $headers + * + * @return ResponseInterface + * + * @throws GuzzleException + */ + public function sendCreateFolderRequest( + string $baseUrl, + string $method, + string $user, + string $password, + string $folder, + string $spaceName, + string $xRequestId = '', + array $headers = [] + ): ResponseInterface { + $spaceId = $this->getAvailableSpaces()[$spaceName]["id"]; + $fullUrl = $baseUrl; + if (!str_ends_with($fullUrl, '/')) { + $fullUrl .= '/'; + } + $fullUrl .= "dav/spaces/" . $spaceId . '/' . $folder; + + return HttpRequestHelper::sendRequest($fullUrl, $xRequestId, $method, $user, $password, $headers); + } } From 13098d9f32fc4b9aa561d89d0589651639295345 Mon Sep 17 00:00:00 2001 From: Artur Neumann Date: Tue, 2 Nov 2021 11:56:05 +0100 Subject: [PATCH 02/12] API tests for archiver endpoint (single file) --- tests/acceptance/config/behat.yml | 17 +++ .../features/apiArchiver/downloadById.feature | 20 +++ .../features/bootstrap/ArchiverContext.php | 119 ++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 tests/acceptance/features/apiArchiver/downloadById.feature create mode 100644 tests/acceptance/features/bootstrap/ArchiverContext.php diff --git a/tests/acceptance/config/behat.yml b/tests/acceptance/config/behat.yml index e3ba6e95a1..016de39b49 100644 --- a/tests/acceptance/config/behat.yml +++ b/tests/acceptance/config/behat.yml @@ -48,6 +48,23 @@ default: - TrashbinContext: - WebDavPropertiesContext: + apiArchiver: + paths: + - '%paths.base%/../features/apiArchiver' + contexts: + - ArchiverContext: + - OccContext: + - FeatureContext: &common_feature_context_params + baseUrl: http://localhost:8080 + adminUsername: admin + adminPassword: admin + regularUserPassword: 123456 + ocPath: apps/testing/api/v1/occ + - CapabilitiesContext: + - ChecksumContext: + - FilesVersionsContext: + - PublicWebDavContext: + extensions: jarnaiz\JUnitFormatter\JUnitFormatterExtension: filename: report.xml diff --git a/tests/acceptance/features/apiArchiver/downloadById.feature b/tests/acceptance/features/apiArchiver/downloadById.feature new file mode 100644 index 0000000000..656fe7dd45 --- /dev/null +++ b/tests/acceptance/features/apiArchiver/downloadById.feature @@ -0,0 +1,20 @@ +@api @skipOnOcV10 +Feature: download multiple resources bundled into an archive + As a user + I want to be able to download multiple items at once + So that I don't have to execute repetitive tasks + + As a developer + I want to be able to use the resource ID to download multiple items at once + So that I don't have to know the full path of the resource + + Background: + Given user "Alice" has been created with default attributes and without skeleton files + + Scenario: download a single file + Given user "Alice" has uploaded file with content "some data" to "/textfile0.txt" + When user "Alice" downloads the archive of "/textfile0.txt" using the resource id + Then the HTTP status code should be "200" + And the downloaded archive should contain these files: + | name | content | + | textfile0.txt | some data | diff --git a/tests/acceptance/features/bootstrap/ArchiverContext.php b/tests/acceptance/features/bootstrap/ArchiverContext.php new file mode 100644 index 0000000000..336cb7a546 --- /dev/null +++ b/tests/acceptance/features/bootstrap/ArchiverContext.php @@ -0,0 +1,119 @@ + + * @copyright Copyright (c) 2021 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 + * + */ + +use Behat\Behat\Context\Context; +use Behat\Behat\Hook\Scope\BeforeScenarioScope; +use Behat\Gherkin\Node\TableNode; +use TestHelpers\HttpRequestHelper; +use TestHelpers\SetupHelper; +use wapmorgan\UnifiedArchive\UnifiedArchive; +use PHPUnit\Framework\Assert; + +require_once 'bootstrap.php'; + +/** + * Context for Archiver specific steps + */ +class ArchiverContext implements Context { + + /** + * @var FeatureContext + */ + private $featureContext; + + /** + * @BeforeScenario + * + * @param BeforeScenarioScope $scope + * + * @return void + * + * @throws Exception + */ + 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'); + SetupHelper::init( + $this->featureContext->getAdminUsername(), + $this->featureContext->getAdminPassword(), + $this->featureContext->getBaseUrl(), + $this->featureContext->getOcPath() + ); + } + + /** + * @When user :user downloads the archive of :resourceId using the resource id + * + * @param string $user + * @param string $resource + * + * @return void + * + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function userDownloadsTheArchiveOfUsingTheResourceId(string $user, string $resource): void { + $resourceId = $this->featureContext->getFileIdForPath($user, $resource); + $user = $this->featureContext->getActualUsername($user); + $this->featureContext->setResponse( + HttpRequestHelper::get( + $this->featureContext->getBaseUrl() . '/archiver?id=' . $resourceId, + '', + $user, + $this->featureContext->getPasswordForUser($user) + ) + ); + } + + /** + * @Then the downloaded archive should contain these files: + * + * @param TableNode $expectedFiles + * + * @return void + * + * @throws Exception + */ + public function theDownloadedArchiveShouldContainTheseFiles(TableNode $expectedFiles) { + $this->featureContext->verifyTableNodeColumns($expectedFiles, ['name', 'content']); + $tempFile = \tempnam(\sys_get_temp_dir(), 'OcAcceptanceTests_'); + \unlink($tempFile); // we only need the name + $tempFile = $tempFile . '.tar'; // it needs the extension + \file_put_contents($tempFile, $this->featureContext->getResponse()->getBody()->getContents()); + $archive = UnifiedArchive::open($tempFile); + foreach ($expectedFiles->getHash() as $expectedFile) { + Assert::assertTrue( + $archive->hasFile($expectedFile['name']), + __METHOD__ . + " archive does not contain '" . $expectedFile['name'] . "'" + ); + Assert::assertEquals( + $expectedFile['content'], + $archive->getFileContent($expectedFile['name']), + __METHOD__ . + " content of '" . $expectedFile['name'] . "' not as expected" + ); + } + \unlink($tempFile); + } +} From baec00746224b0e79c9440d75708ec4b4679c215 Mon Sep 17 00:00:00 2001 From: Willy Kloucek Date: Tue, 9 Nov 2021 09:47:17 +0100 Subject: [PATCH 03/12] update reva --- changelog/unreleased/update-reva.md | 7 +++++++ go.mod | 3 ++- go.sum | 13 +++++-------- 3 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 changelog/unreleased/update-reva.md diff --git a/changelog/unreleased/update-reva.md b/changelog/unreleased/update-reva.md new file mode 100644 index 0000000000..1d8dd1f9cf --- /dev/null +++ b/changelog/unreleased/update-reva.md @@ -0,0 +1,7 @@ +Enhancement: Update reva to v1.16 + +Updated reva to v1.16 +This update includes: + * TODO before oCIS release + +https://github.com/owncloud/ocis/pull/2737 diff --git a/go.mod b/go.mod index 005e31ba82..d4924f59f4 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/blevesearch/bleve/v2 v2.2.2 github.com/coreos/go-oidc/v3 v3.1.0 github.com/cs3org/go-cs3apis v0.0.0-20211018122138-391b29bd7803 - github.com/cs3org/reva v1.15.1-0.20211027114107-4879bf6be97a + github.com/cs3org/reva v1.15.1-0.20211108144647-80f5ec9b8978 github.com/disintegration/imaging v1.6.2 github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733 github.com/go-chi/chi/v5 v5.0.5 @@ -155,6 +155,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/juliangruber/go-intersect v1.0.0 // indirect github.com/kevinburke/ssh_config v1.1.0 // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect diff --git a/go.sum b/go.sum index 818264e59e..d4d97f7d87 100644 --- a/go.sum +++ b/go.sum @@ -296,8 +296,8 @@ github.com/crewjam/saml v0.4.5/go.mod h1:qCJQpUtZte9R1ZjUBcW8qtCNlinbO363ooNl02S github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4= github.com/cs3org/go-cs3apis v0.0.0-20211018122138-391b29bd7803 h1:R/6llgTNKxQQ7GaSTgFn6Fp8N50wIlagmdR7WY5LntM= github.com/cs3org/go-cs3apis v0.0.0-20211018122138-391b29bd7803/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= -github.com/cs3org/reva v1.15.1-0.20211027114107-4879bf6be97a h1:rg00QAtWaC4vQMWJzp6m5UQfO1WgBg9g9tXz8jvjGtA= -github.com/cs3org/reva v1.15.1-0.20211027114107-4879bf6be97a/go.mod h1:Pwo2bbUCXDfGPIxh1392/a7393H7S+roP7ccip67wTI= +github.com/cs3org/reva v1.15.1-0.20211108144647-80f5ec9b8978 h1:dWtEiKDU8l+8EdSryCEMLj0jySc3U7JXya8NcFlP+YA= +github.com/cs3org/reva v1.15.1-0.20211108144647-80f5ec9b8978/go.mod h1:1psTtxa3/7kQJNUqu3pyu3K2Q3VVOgOE/8rk5gS9XdY= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= @@ -378,7 +378,6 @@ github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4Q github.com/go-asn1-ber/asn1-ber v1.5.3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.5 h1:l3RJ8T8TAqLsXFfah+RA6N4pydMbPwSdvNM+AFWvLUM= github.com/go-chi/chi/v5 v5.0.5/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE= @@ -765,6 +764,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juliangruber/go-intersect v1.0.0 h1:0XNPNaEoPd7PZljVNZLk4qrRkR153Sjk2ZL1426zFQ0= +github.com/juliangruber/go-intersect v1.0.0/go.mod h1:unIef4vysSJvZ6adJAAPiBVKpS4r/IOkmfuFghRFDDM= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= @@ -1310,19 +1311,15 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.26.0/go.mod h1:4wsfAAW5N9wUHM0QTmZS8z7fvYZ1rv3m+sVeSpf8NhU= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.26.1 h1:puWrOArBwWlr5dq6vyZ6fKykHyS8JgMIVhTBA8XsGuU= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.26.1/go.mod h1:4wsfAAW5N9wUHM0QTmZS8z7fvYZ1rv3m+sVeSpf8NhU= -go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= go.opentelemetry.io/otel v1.1.0 h1:8p0uMLcyyIx0KHNTgO8o3CW8A1aA+dJZJW6PvnMz0Wc= go.opentelemetry.io/otel v1.1.0/go.mod h1:7cww0OW51jQ8IaZChIEdqLwgh+44+7uiTdWsAL0wQpA= -go.opentelemetry.io/otel/exporters/jaeger v1.0.1/go.mod h1:85Ym3qknJdIdfRzYS9Ofy9NeLi9gKPFzFDBEHCKpfXI= go.opentelemetry.io/otel/exporters/jaeger v1.1.0 h1:VRF+Hf3EePFO6ab7/wfPoyWzSY4z5X0tTvQtV9/Mq8Y= go.opentelemetry.io/otel/exporters/jaeger v1.1.0/go.mod h1:D/GIBwAdrFTTqCy1iITpC9nh5rgJpIbFVgkhlz2vCXk= -go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= go.opentelemetry.io/otel/sdk v1.1.0 h1:j/1PngUJIDOddkCILQYTevrTIbWd494djgGkSsMit+U= go.opentelemetry.io/otel/sdk v1.1.0/go.mod h1:3aQvM6uLm6C4wJpHtT8Od3vNzeZ34Pqc6bps8MywWzo= -go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= go.opentelemetry.io/otel/trace v1.1.0 h1:N25T9qCL0+7IpOT8RrRy0WYlL7y6U0WiUJzXcVdXY/o= go.opentelemetry.io/otel/trace v1.1.0/go.mod h1:i47XtdcBQiktu5IsrPqOHe8w+sBmnLwwHt8wiUsWGTI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= From 916f0a6225ff9f1c7a496de8d67b6e1babab87c7 Mon Sep 17 00:00:00 2001 From: Artur Neumann Date: Tue, 9 Nov 2021 15:02:13 +0545 Subject: [PATCH 04/12] delete `hasFile` check this is not needed as the lib checks the file existance on `getFileContent` and gives a nice eror message if it does not exist --- tests/acceptance/features/bootstrap/ArchiverContext.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/acceptance/features/bootstrap/ArchiverContext.php b/tests/acceptance/features/bootstrap/ArchiverContext.php index 336cb7a546..4b737f302e 100644 --- a/tests/acceptance/features/bootstrap/ArchiverContext.php +++ b/tests/acceptance/features/bootstrap/ArchiverContext.php @@ -102,11 +102,6 @@ class ArchiverContext implements Context { \file_put_contents($tempFile, $this->featureContext->getResponse()->getBody()->getContents()); $archive = UnifiedArchive::open($tempFile); foreach ($expectedFiles->getHash() as $expectedFile) { - Assert::assertTrue( - $archive->hasFile($expectedFile['name']), - __METHOD__ . - " archive does not contain '" . $expectedFile['name'] . "'" - ); Assert::assertEquals( $expectedFile['content'], $archive->getFileContent($expectedFile['name']), From c97cbf9b98a280d449328b39260e34035afe739d Mon Sep 17 00:00:00 2001 From: Artur Neumann Date: Tue, 9 Nov 2021 15:04:05 +0545 Subject: [PATCH 05/12] test downloading a folder --- .../features/apiArchiver/downloadById.feature | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/acceptance/features/apiArchiver/downloadById.feature b/tests/acceptance/features/apiArchiver/downloadById.feature index 656fe7dd45..75dba81893 100644 --- a/tests/acceptance/features/apiArchiver/downloadById.feature +++ b/tests/acceptance/features/apiArchiver/downloadById.feature @@ -18,3 +18,14 @@ Feature: download multiple resources bundled into an archive And the downloaded archive should contain these files: | name | content | | textfile0.txt | some data | + + Scenario: download a single folder + Given user "Alice" has created folder "my_data" + And user "Alice" has uploaded file with content "some data" to "/my_data/textfile0.txt" + And user "Alice" has uploaded file with content "more data" to "/my_data/an_other_file.txt" + When user "Alice" downloads the archive of "/my_data" using the resource id + Then the HTTP status code should be "200" + And the downloaded archive should contain these files: + | name | content | + | my_data/textfile0.txt | some data | + | my_data/an_other_file.txt | more data | From 23cb8f25a72c1b3fb396a68de0d16b3e2acec175 Mon Sep 17 00:00:00 2001 From: Artur Neumann Date: Tue, 9 Nov 2021 15:05:32 +0545 Subject: [PATCH 06/12] run apiArchiver tests in drone --- .drone.star | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.star b/.drone.star index 32b11b4e8b..cdef01deca 100644 --- a/.drone.star +++ b/.drone.star @@ -237,6 +237,7 @@ def testPipelines(ctx): pipelines = [ localApiTests(ctx, "ocis", "apiAccountsHashDifficulty", "default"), localApiTests(ctx, "ocis", "apiSpaces", "default"), + localApiTests(ctx, "ocis", "apiArchiver", "default"), ] if "skip" not in config["apiTests"] or not config["apiTests"]["skip"]: From c573e8aed9dedad33547bcb04fe27b3568849efd Mon Sep 17 00:00:00 2001 From: Willy Kloucek <34452982+wkloucek@users.noreply.github.com> Date: Tue, 9 Nov 2021 09:50:47 +0000 Subject: [PATCH 07/12] Automated changelog update [skip ci] --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88669244ee..077da46158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The following sections list the changes for unreleased. * Bugfix - Fix error logging when there is no thumbnail for a file: [#2702](https://github.com/owncloud/ocis/pull/2702) * Bugfix - Don't announce resharing via capabilities: [#2690](https://github.com/owncloud/ocis/pull/2690) * Enhancement - Add API to list all spaces: [#2692](https://github.com/owncloud/ocis/pull/2692) +* Enhancement - Update reva to v1.16: [#2737](https://github.com/owncloud/ocis/pull/2737) ## Details @@ -57,6 +58,12 @@ The following sections list the changes for unreleased. spaces. https://github.com/owncloud/ocis/pull/2692 + +* Enhancement - Update reva to v1.16: [#2737](https://github.com/owncloud/ocis/pull/2737) + + Updated reva to v1.16 This update includes: * TODO before oCIS release + + https://github.com/owncloud/ocis/pull/2737 # Changelog for [1.14.0] (2021-10-27) The following sections list the changes for 1.14.0. From cdb90383f66d93c11c2cdefd4eec73ec97404026 Mon Sep 17 00:00:00 2001 From: Willy Kloucek Date: Tue, 9 Nov 2021 10:59:27 +0100 Subject: [PATCH 08/12] fix opening images in media viewer for some usernames --- changelog/unreleased/fix-mediaviewer-url-encoded.md | 5 +++++ webdav/pkg/dav/requests/thumbnail.go | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 changelog/unreleased/fix-mediaviewer-url-encoded.md diff --git a/changelog/unreleased/fix-mediaviewer-url-encoded.md b/changelog/unreleased/fix-mediaviewer-url-encoded.md new file mode 100644 index 0000000000..a15e7b4d16 --- /dev/null +++ b/changelog/unreleased/fix-mediaviewer-url-encoded.md @@ -0,0 +1,5 @@ +Bugfix: Fix opening images in media viewer for some usernames + +We've fixed the opening of images in the media viewer for user names containing special characters (eg. `@`) which will be URL-escaped. Before this fix users could not see the image in the media viewer. Now the user name is correctly escaped and the user can view the image in the media viewer. + +https://github.com/owncloud/ocis/pull/2738 diff --git a/webdav/pkg/dav/requests/thumbnail.go b/webdav/pkg/dav/requests/thumbnail.go index 4bb1fc35a8..6ce7b3d38a 100644 --- a/webdav/pkg/dav/requests/thumbnail.go +++ b/webdav/pkg/dav/requests/thumbnail.go @@ -66,10 +66,15 @@ func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) { // So using the URLParam function is not possible. func extractFilePath(r *http.Request) (string, error) { user := chi.URLParam(r, "user") + user, err := url.QueryUnescape(user) + if err != nil { + return "", errors.New("could not unescape user") + } if user != "" { parts := strings.SplitN(r.URL.Path, user, 2) return parts[1], nil } + token := chi.URLParam(r, "token") if token != "" { parts := strings.SplitN(r.URL.Path, token, 2) From 8249209e1f112ac34c2cbba255bbdeb2b37ebadc Mon Sep 17 00:00:00 2001 From: Willy Kloucek Date: Tue, 9 Nov 2021 12:49:39 +0100 Subject: [PATCH 09/12] redirect from login --- .../oc10_ocis_parallel/config/ocis/proxy-config.dist.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/deployments/examples/oc10_ocis_parallel/config/ocis/proxy-config.dist.json b/deployments/examples/oc10_ocis_parallel/config/ocis/proxy-config.dist.json index 23269f4323..ce44aa43f7 100644 --- a/deployments/examples/oc10_ocis_parallel/config/ocis/proxy-config.dist.json +++ b/deployments/examples/oc10_ocis_parallel/config/ocis/proxy-config.dist.json @@ -54,6 +54,14 @@ "endpoint": "/index.php/", "backend": "http://localhost:9140" }, + { + "endpoint": "/index.php/login", + "backend": "http://localhost:9100" + }, + { + "endpoint": "/login", + "backend": "http://localhost:9100" + }, { "endpoint": "/data", "backend": "http://localhost:9140" From 89d4f2ae28acd608046002ca0fff640db8b0a5f0 Mon Sep 17 00:00:00 2001 From: Willy Kloucek <34452982+wkloucek@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:06:57 +0000 Subject: [PATCH 10/12] Automated changelog update [skip ci] --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 077da46158..0db025acea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The following sections list the changes for unreleased. * Bugfix - Don't allow empty password: [#197](https://github.com/owncloud/product/issues/197) * Bugfix - Fix basic auth config: [#2719](https://github.com/owncloud/ocis/pull/2719) * Bugfix - Fix oCIS startup ony systems with IPv6: [#2698](https://github.com/owncloud/ocis/pull/2698) +* Bugfix - Fix opening images in media viewer for some usernames: [#2738](https://github.com/owncloud/ocis/pull/2738) * Bugfix - Fix error logging when there is no thumbnail for a file: [#2702](https://github.com/owncloud/ocis/pull/2702) * Bugfix - Don't announce resharing via capabilities: [#2690](https://github.com/owncloud/ocis/pull/2690) * Enhancement - Add API to list all spaces: [#2692](https://github.com/owncloud/ocis/pull/2692) @@ -37,6 +38,15 @@ The following sections list the changes for unreleased. https://github.com/owncloud/ocis/issues/2300 https://github.com/owncloud/ocis/pull/2698 +* Bugfix - Fix opening images in media viewer for some usernames: [#2738](https://github.com/owncloud/ocis/pull/2738) + + We've fixed the opening of images in the media viewer for user names containing special + characters (eg. `@`) which will be URL-escaped. Before this fix users could not see the image in + the media viewer. Now the user name is correctly escaped and the user can view the image in the + media viewer. + + https://github.com/owncloud/ocis/pull/2738 + * Bugfix - Fix error logging when there is no thumbnail for a file: [#2702](https://github.com/owncloud/ocis/pull/2702) We've fixed the behavior of the logging when there is no thumbnail for a file (because the From 5b6bae0349a3c90638459eddb49fa2181f670fb3 Mon Sep 17 00:00:00 2001 From: Willy Kloucek Date: Tue, 9 Nov 2021 16:55:46 +0100 Subject: [PATCH 11/12] add archiver and app provider route to all deployment examples --- .../cs3_users_ocis/config/ocis/proxy-config.json | 6 +++++- .../config/ocis/proxy-config.dist.json | 10 +++++++++- .../ocis_hello/config/ocis/proxy-config.json | 10 +++++++++- proxy/config/proxy-example-migration.json | 6 +++++- proxy/config/proxy-example-regex.json | 6 +++++- proxy/config/proxy-example.json | 12 ++++++++---- 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/deployments/examples/cs3_users_ocis/config/ocis/proxy-config.json b/deployments/examples/cs3_users_ocis/config/ocis/proxy-config.json index b2132efa6a..76285d79b4 100644 --- a/deployments/examples/cs3_users_ocis/config/ocis/proxy-config.json +++ b/deployments/examples/cs3_users_ocis/config/ocis/proxy-config.json @@ -65,6 +65,10 @@ "endpoint": "/app/", "backend": "http://localhost:9140" }, + { + "endpoint": "/archiver", + "backend": "http://localhost:9140" + }, { "endpoint": "/data", "backend": "http://localhost:9140" @@ -88,4 +92,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/deployments/examples/oc10_ocis_parallel/config/ocis/proxy-config.dist.json b/deployments/examples/oc10_ocis_parallel/config/ocis/proxy-config.dist.json index 23269f4323..7820454ee2 100644 --- a/deployments/examples/oc10_ocis_parallel/config/ocis/proxy-config.dist.json +++ b/deployments/examples/oc10_ocis_parallel/config/ocis/proxy-config.dist.json @@ -62,6 +62,14 @@ "endpoint": "/graph/", "backend": "http://localhost:9120" }, + { + "endpoint": "/app/", + "backend": "http://localhost:9140" + }, + { + "endpoint": "/archiver", + "backend": "http://localhost:9140" + }, { "endpoint": "/graph-explorer/", "backend": "http://localhost:9135" @@ -90,4 +98,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/deployments/examples/ocis_hello/config/ocis/proxy-config.json b/deployments/examples/ocis_hello/config/ocis/proxy-config.json index 8d597d1924..fd1ea36315 100644 --- a/deployments/examples/ocis_hello/config/ocis/proxy-config.json +++ b/deployments/examples/ocis_hello/config/ocis/proxy-config.json @@ -65,6 +65,14 @@ "endpoint": "/data", "backend": "http://localhost:9140" }, + { + "endpoint": "/app/", + "backend": "http://localhost:9140" + }, + { + "endpoint": "/archiver", + "backend": "http://localhost:9140" + }, { "endpoint": "/graph/", "backend": "http://localhost:9120" @@ -100,4 +108,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/proxy/config/proxy-example-migration.json b/proxy/config/proxy-example-migration.json index 31af7c0192..54e0583262 100644 --- a/proxy/config/proxy-example-migration.json +++ b/proxy/config/proxy-example-migration.json @@ -80,6 +80,10 @@ "endpoint": "/app/", "backend": "http://localhost:9140" }, + { + "endpoint": "/archiver", + "backend": "http://localhost:9140" + }, { "endpoint": "/graph-explorer/", "backend": "http://localhost:9135" @@ -157,4 +161,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/proxy/config/proxy-example-regex.json b/proxy/config/proxy-example-regex.json index c9bd2e5084..49f5d66744 100644 --- a/proxy/config/proxy-example-regex.json +++ b/proxy/config/proxy-example-regex.json @@ -114,6 +114,10 @@ "endpoint": "/app/", "backend": "http://localhost:9140" }, + { + "endpoint": "/archiver", + "backend": "http://localhost:9140" + }, { "endpoint": "/graph/", "backend": "http://localhost:9120" @@ -195,4 +199,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/proxy/config/proxy-example.json b/proxy/config/proxy-example.json index 78196f6924..75f50065ee 100644 --- a/proxy/config/proxy-example.json +++ b/proxy/config/proxy-example.json @@ -67,9 +67,13 @@ "backend": "http://localhost:9140" }, { - "endpoint": "/app/", - "backend": "http://localhost:9140" - }, + "endpoint": "/app/", + "backend": "http://localhost:9140" + }, + { + "endpoint": "/archiver", + "backend": "http://localhost:9140" + }, { "endpoint": "/graph/", "backend": "http://localhost:9120" @@ -97,4 +101,4 @@ ] } ] -} +} \ No newline at end of file From 7ebf25713543c094645eda1f6b0b26dbde28311c Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Tue, 9 Nov 2021 14:31:11 +0100 Subject: [PATCH 12/12] Add user bob --- .../features/apiSpaces/listSpaces.feature | 10 ------ .../features/apiSpaces/uploadSpaces.feature | 34 ++++++++++++++++++- .../features/bootstrap/SpacesContext.php | 3 +- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/tests/acceptance/features/apiSpaces/listSpaces.feature b/tests/acceptance/features/apiSpaces/listSpaces.feature index 01458e1003..f92c2b7152 100644 --- a/tests/acceptance/features/apiSpaces/listSpaces.feature +++ b/tests/acceptance/features/apiSpaces/listSpaces.feature @@ -54,13 +54,3 @@ Feature: List and create spaces | name | Project Venus | | quota@@@total | 2000 | | root@@@webDavUrl | %base_url%/dav/spaces/%space_id% | - - Scenario: Alice creates a folder via the Graph api in space, she expects a 201 code and she checks that folder exists - Given the administrator gives "Alice" the role "Admin" using the settings api - When user "Alice" creates a space "Project Venus" of type "project" with quota "2000" using the GraphApi - And user "Alice" lists all available spaces via the GraphApi - And user "Alice" creates a folder "mainFolder" in space "Project Venus" using the WebDav Api - Then the HTTP status code should be "201" - When user "Alice" lists the content of the space with the name "Project Venus" using the WebDav Api - Then the propfind result of the space should contain these entries: - | mainFolder/ | diff --git a/tests/acceptance/features/apiSpaces/uploadSpaces.feature b/tests/acceptance/features/apiSpaces/uploadSpaces.feature index cd017f30b0..721d5345aa 100644 --- a/tests/acceptance/features/apiSpaces/uploadSpaces.feature +++ b/tests/acceptance/features/apiSpaces/uploadSpaces.feature @@ -10,6 +10,27 @@ Feature: Upload files into a space Given user "Alice" has been created with default attributes and without skeleton files And user "Bob" has been created with default attributes and without skeleton files + Scenario: Alice creates a folder via the Graph api in space, she expects a 201 code and she checks that folder exists + Given the administrator gives "Alice" the role "Admin" using the settings api + When user "Alice" creates a space "Project Venus" of type "project" with quota "2000" using the GraphApi + And user "Alice" lists all available spaces via the GraphApi + And user "Alice" creates a folder "mainFolder" in space "Project Venus" using the WebDav Api + Then the HTTP status code should be "201" + When user "Alice" lists the content of the space with the name "Project Venus" using the WebDav Api + Then the propfind result of the space should contain these entries: + | mainFolder | + + Scenario: Bob creates a folder via the Graph api in a space, he expects a 404 code and + Alice checks that this folder does not exist + Given the administrator gives "Alice" the role "Admin" using the settings api + When user "Alice" creates a space "Project Merkur" of type "project" with quota "2000" using the GraphApi + And user "Alice" lists all available spaces via the GraphApi + And user "Bob" creates a folder "forAlice" in space "Project Merkur" using the WebDav Api + Then the HTTP status code should be "404" + When user "Alice" lists the content of the space with the name "Project Merkur" using the WebDav Api + Then the propfind result of the space should not contain these entries: + | forAlice | + Scenario: Alice creates a folder via Graph api and uploads a file Given the administrator gives "Alice" the role "Admin" using the settings api When user "Alice" creates a space "Project Moon" of type "project" with quota "2000" using the GraphApi @@ -20,9 +41,20 @@ Feature: Upload files into a space Then the HTTP status code should be "201" When user "Alice" lists the content of the space with the name "Project Moon" using the WebDav Api Then the propfind result of the space should contain these entries: - | NewFolder/ | + | NewFolder | | test.txt | + Scenario: Bob uploads a file via the Graph api in a space, he expects a 404 code and + Alice checks that this file does not exist + Given the administrator gives "Alice" the role "Admin" using the settings api + When user "Alice" creates a space "Project Pluto" of type "project" with quota "2000" using the GraphApi + And user "Alice" lists all available spaces via the GraphApi + And user "Bob" uploads a file inside space "Project Pluto" with content "Test" to "test.txt" using the WebDAV API + Then the HTTP status code should be "404" + When user "Alice" lists the content of the space with the name "Project Pluto" using the WebDav Api + Then the propfind result of the space should not contain these entries: + | test.txt | + Scenario: Alice creates uploads a file and checks her quota Given the administrator gives "Alice" the role "Admin" using the settings api When user "Alice" creates a space "Project Saturn" of type "project" with quota "2000" using the GraphApi diff --git a/tests/acceptance/features/bootstrap/SpacesContext.php b/tests/acceptance/features/bootstrap/SpacesContext.php index 19af029a7e..047c9505ea 100644 --- a/tests/acceptance/features/bootstrap/SpacesContext.php +++ b/tests/acceptance/features/bootstrap/SpacesContext.php @@ -595,7 +595,7 @@ class SpacesContext implements Context { "response does not contain the entry '$expectedFile[0]'" ); } else { - Assert::assertFalse( + Assert::assertEmpty( $fileFound, "response does contain the entry '$expectedFile[0]' but should not" ); @@ -748,7 +748,6 @@ class SpacesContext implements Context { $content ) ); - $this->featureContext->theHTTPStatusCodeShouldBe([201, 204]); } /**