From 80c299eb930988a8eadd98d91c35f24b1ad95581 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Fri, 29 Oct 2021 10:46:20 +0200 Subject: [PATCH 1/2] 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 7ebf25713543c094645eda1f6b0b26dbde28311c Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Tue, 9 Nov 2021 14:31:11 +0100 Subject: [PATCH 2/2] 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]); } /**