From bf1ee8f9efaac42c0907603cf42df67348dc8c21 Mon Sep 17 00:00:00 2001 From: Viktor Scharf Date: Tue, 12 Apr 2022 08:51:35 +0200 Subject: [PATCH] [tests-only] apiTest: list of trash files and restore files from the trash (#3462) * apiTest: see trashbin and restore files from trash --- ...ected-failures-localAPI-on-OCIS-storage.md | 2 +- .../apiSpaces/removeSpaceObjects.feature | 155 ++++++---------- .../apiSpaces/restoreSpaceObjects.feature | 67 +++++++ .../features/bootstrap/SpacesContext.php | 174 +++++++++++++++++- 4 files changed, 291 insertions(+), 107 deletions(-) create mode 100644 tests/acceptance/features/apiSpaces/restoreSpaceObjects.feature diff --git a/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md b/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md index c70e6b623b..ae26ed68e5 100644 --- a/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md +++ b/tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md @@ -23,6 +23,6 @@ The expected failures in this file are from features in the owncloud/ocis repo. - [apiSpaces/quota.feature:56](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/quota.feature#L56) #### [Viewer and editor has the possibility to disable the space](https://github.com/owncloud/ocis/issues/3031) -- [apiSpaces/removeSpaceObjects.feature:121](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/removeSpaceObjects.feature#L121) +- [apiSpaces/removeSpaceObjects.feature:74](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/removeSpaceObjects.feature#L74) - [apiSpaces/deleteSpaces.feature:73](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/deleteSpaces.feature#L73) - [apiSpaces/deleteSpaces.feature:84](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/deleteSpaces.feature#L84) diff --git a/tests/acceptance/features/apiSpaces/removeSpaceObjects.feature b/tests/acceptance/features/apiSpaces/removeSpaceObjects.feature index aa15aa89d7..95112c0619 100644 --- a/tests/acceptance/features/apiSpaces/removeSpaceObjects.feature +++ b/tests/acceptance/features/apiSpaces/removeSpaceObjects.feature @@ -3,126 +3,79 @@ Feature: Remove files, folder As a user I want to be able to remove files, folders Users with the editor role can also remove objects - Users with the viewer role cannot remove objects + Users with the viewer role cannot remove objects 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 "Brian" has been created with default attributes and without skeleton files + Given these users have been created with default attributes and without skeleton files: + | username | + | Alice | + | Brian | And the administrator has given "Alice" the role "Admin" using the settings api + And user "Alice" has created a space "delete objects" with the default quota using the GraphApi + And user "Alice" has created a folder "folderForDeleting/sub1/sub2" in space "delete objects" + And user "Alice" has uploaded a file inside space "delete objects" with content "some content" to "text.txt" -# owner of space (admin permissions) - Scenario: An owner can delete a folder with some subfolders in a Space via the webDav API - Given user "Alice" has created a space "Owner deletes folder" of type "project" with quota "10" - And user "Alice" has created a folder "folderForDeleting/sub1/sub2" in space "Owner deletes folder" - When user "Alice" removes the object "folderForDeleting" from space "Owner deletes folder" - Then the HTTP status code should be "204" - And for user "Alice" the space "Owner deletes folder" should not contain these entries: + Scenario Outline: An user deletes a folder with some subfolders in a Space via the webDav API + Given user "Alice" has shared a space "delete objects" to user "Brian" with role "" + When user "" removes the folder "folderForDeleting" from space "delete objects" + Then the HTTP status code should be "" + And for user "" the space "delete objects" contain these entries: | folderForDeleting | + And as "" folder "folderForDeleting" exist in the trashbin of the space "delete objects" + Examples: + | user | role | code | shouldOrNotBeInSpace | shouldOrNotBeInTrash | + | Alice | manager | 204 | should not | should | + | Brian | manager | 204 | should not | should | + | Brian | editor | 204 | should not | should | + | Brian | viewer | 403 | should | should not | - Scenario: An owner can delete a subfolder in a Space via the webDav API - Given user "Alice" has created a space "Owner deletes subfolder" of type "project" with quota "10" - And user "Alice" has created a subfolder "folder/subFolderForDeleting" in space "Owner deletes subfolder" - When user "Alice" removes the object "folder/subFolderForDeleting" from space "Owner deletes subfolder" - Then the HTTP status code should be "204" - And for user "Alice" the space "Owner deletes subfolder" should contain these entries: - | folder | - And for user "Alice" folder "folder/" of the space "Owner deletes subfolder" should not contain these entries: - | subFolderForDeleting | - - - Scenario: An owner can delete a file in a Space via the webDav API - Given user "Alice" has created a space "Owner deletes file" of type "project" with quota "20" - And user "Alice" has uploaded a file inside space "Owner deletes file" with content "some content" to "text.txt" - When user "Alice" removes the object "text.txt" from space "Owner deletes file" - Then the HTTP status code should be "204" - And for user "Alice" the space "Owner deletes file" should not contain these entries: - | text.txt | - When user "Alice" lists all available spaces via the GraphApi - Then the json responded should contain a space "Owner deletes file" with these key and value pairs: - | key | value | - | name | Owner deletes file | - | quota@@@used | 0 | - -# editor role - - Scenario: An editor can delete a folder with some subfolders in a Space via the webDav API - Given user "Alice" has created a space "Editor deletes folder" of type "project" with quota "10" - And user "Alice" has created a folder "folderForDeleting/sub1/sub2" in space "Editor deletes folder" - And user "Alice" has shared a space "Editor deletes folder" to user "Brian" with role "editor" - When user "Brian" removes the object "folderForDeleting" from space "Editor deletes folder" - Then the HTTP status code should be "204" - And for user "Brian" the space "Editor deletes folder" should not contain these entries: + Scenario Outline: An user deletes a subfolder in a Space via the webDav API + Given user "Alice" has shared a space "delete objects" to user "Brian" with role "" + When user "" removes the folder "folderForDeleting/sub1" from space "delete objects" + Then the HTTP status code should be "" + And for user "" the space "delete objects" should contain these entries: | folderForDeleting | + And for user "" folder "folderForDeleting/" of the space "delete objects" contain these entries: + | sub1 | + And as "" folder "sub1" exist in the trashbin of the space "delete objects" + Examples: + | user | role | code | shouldOrNotBeInSpace | shouldOrNotBeInTrash | + | Alice | manager | 204 | should not | should | + | Brian | manager | 204 | should not | should | + | Brian | editor | 204 | should not | should | + | Brian | viewer | 403 | should | should not | - Scenario: An editor can delete a subfolder in a Space via the webDav API - Given user "Alice" has created a space "Editor deletes subfolder" of type "project" with quota "10" - And user "Alice" has created a subfolder "folder/subFolderForDeleting" in space "Editor deletes subfolder" - And user "Alice" has shared a space "Editor deletes subfolder" to user "Brian" with role "editor" - When user "Brian" removes the object "folder/subFolderForDeleting" from space "Editor deletes subfolder" - Then the HTTP status code should be "204" - And for user "Brian" the space "Editor deletes subfolder" should contain these entries: - | folder | - And for user "Brian" folder "folder/" of the space "Editor deletes subfolder" should not contain these entries: - | subFolderForDeleting | - - - Scenario: An editor can delete a file in a Space via the webDav API - Given user "Alice" has created a space "Editor deletes file" of type "project" with quota "20" - And user "Alice" has uploaded a file inside space "Editor deletes file" with content "some content" to "text.txt" - And user "Alice" has shared a space "Editor deletes file" to user "Brian" with role "editor" - When user "Brian" removes the object "text.txt" from space "Editor deletes file" - Then the HTTP status code should be "204" - And for user "Brian" the space "Editor deletes file" should not contain these entries: + Scenario Outline: An user deletes a file in a Space via the webDav API + Given user "Alice" has shared a space "delete objects" to user "Brian" with role "" + When user "" removes the file "text.txt" from space "delete objects" + Then the HTTP status code should be "" + And for user "" the space "delete objects" contain these entries: | text.txt | - When user "Brian" lists all available spaces via the GraphApi - Then the json responded should contain a space "Editor deletes file" with these key and value pairs: - | key | value | - | name | Editor deletes file | - | quota@@@used | 0 | - -# viewer role - - Scenario: A viewer cannot delete a folder with some subfolders in a Space via the webDav API - Given user "Alice" has created a space "Viewer deletes folder" of type "project" with quota "10" - And user "Alice" has created a folder "folderForDeleting/sub1/sub2" in space "Viewer deletes folder" - And user "Alice" has shared a space "Viewer deletes folder" to user "Brian" with role "viewer" - When user "Brian" removes the object "folderForDeleting" from space "Viewer deletes folder" - Then the HTTP status code should be "403" - And for user "Brian" the space "Viewer deletes folder" should contain these entries: - | folderForDeleting | + And as "" file "text.txt" exist in the trashbin of the space "delete objects" + When user "" lists all available spaces via the GraphApi + Then the json responded should contain a space "delete objects" with these key and value pairs: + | key | value | + | name | delete objects | + | quota@@@used | | + Examples: + | user | role | code | shouldOrNotBeInSpace | shouldOrNotBeInTrash | quotaValue | + | Alice | manager | 204 | should not | should | 0 | + | Brian | manager | 204 | should not | should | 0 | + | Brian | editor | 204 | should not | should | 0 | + | Brian | viewer | 403 | should | should not | 12 | - Scenario: A viewer cannot delete a subfolder in a Space via the webDav API - Given user "Alice" has created a space "Viewer deletes subfolder" of type "project" with quota "10" - And user "Alice" has created a subfolder "folder/subFolderForDeleting" in space "Viewer deletes subfolder" - And user "Alice" has shared a space "Viewer deletes subfolder" to user "Brian" with role "viewer" - When user "Brian" removes the object "folder/subFolderForDeleting" from space "Viewer deletes subfolder" - Then the HTTP status code should be "403" - And for user "Brian" folder "folder/" of the space "Viewer deletes subfolder" should contain these entries: - | subFolderForDeleting | - - - Scenario: A viewer cannot delete a file in a Space via the webDav API - Given user "Alice" has created a space "Viewer deletes file" of type "project" with quota "20" - And user "Alice" has uploaded a file inside space "Viewer deletes file" with content "some content" to "text.txt" - And user "Alice" has shared a space "Viewer deletes file" to user "Brian" with role "viewer" - When user "Brian" removes the object "text.txt" from space "Viewer deletes file" - Then the HTTP status code should be "403" - And for user "Brian" the space "Viewer deletes file" should contain these entries: - | text.txt | - - Scenario: An user is unable to delete a Space via the webDav API Given user "Alice" has created a space "user deletes a space" of type "project" with quota "20" - When user "Alice" removes the object "" from space "user deletes a space" + When user "Alice" removes the folder "" from space "user deletes a space" Then the HTTP status code should be "405" When user "Alice" lists all available spaces via the GraphApi Then the json responded should contain a space "user deletes a space" with these key and value pairs: - | key | value | - | name | user deletes a space | + | key | value | + | name | user deletes a space | diff --git a/tests/acceptance/features/apiSpaces/restoreSpaceObjects.feature b/tests/acceptance/features/apiSpaces/restoreSpaceObjects.feature new file mode 100644 index 0000000000..05f71eec45 --- /dev/null +++ b/tests/acceptance/features/apiSpaces/restoreSpaceObjects.feature @@ -0,0 +1,67 @@ +@api @skipOnOcV10 +Feature: Restore files, folder + As a user with manager and editor role + I want to be able to restore files, folders + Users with the viewer role cannot restore objects + + 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 these users have been created with default attributes and without skeleton files: + | username | + | Alice | + | Brian | + | Bob | + | Carol | + And the administrator has given "Alice" the role "Admin" using the settings api + And user "Alice" creates a space "restore objects" of type "project" with the default quota using the GraphApi + And user "Alice" has created a folder "newFolder" in space "restore objects" + And user "Alice" has uploaded a file inside space "restore objects" with content "test" to "newFolder/file.txt" + + + Scenario Outline: An user with different role can see deleted objects in trash bin of the space via the webDav API + Given user "Alice" has shared a space "restore objects" to user "Brian" with role "" + And user "Alice" has removed the file "newFolder/file.txt" from space "restore objects" + And user "Alice" has removed the folder "newFolder" from space "restore objects" + When user "" lists all deleted files in the trash bin of the space "restore objects" + Then the HTTP status code should be "207" + And as "" folder "newFolder" should exist in the trashbin of the space "restore objects" + And as "" file "file.txt" should exist in the trashbin of the space "restore objects" + Examples: + | user | role | + | Brian | manager | + | Brian | editor | + | Brian | viewer | + + + Scenario Outline: An user restores a folder with some objects from the trash via the webDav API + Given user "Alice" has shared a space "restore objects" to user "Brian" with role "" + And user "Alice" has removed the folder "newFolder" from space "restore objects" + When user "" restores the folder "newFolder" from the trash of the space "restore objects" to "/newFolder" + Then the HTTP status code should be "" + And for user "" the space "restore objects" contain these entries: + | newFolder | + And as "" folder "newFolder" exist in the trashbin of the space "restore objects" + Examples: + | user | role | code | shouldOrNotBeInSpace | shouldOrNotBeInTrash | + | Alice | manager | 201 | should | should not | + | Brian | manager | 201 | should | should not | + | Brian | editor | 201 | should | should not | + | Brian | viewer | 403 | should not | should | + + + Scenario Outline: An user restores a file from the trash via the webDav API + Given user "Alice" has shared a space "restore objects" to user "Brian" with role "" + And user "Alice" has removed the file "newFolder/file.txt" from space "restore objects" + When user "" restores the file "file.txt" from the trash of the space "restore objects" to "newFolder/file.txt" + Then the HTTP status code should be "" + And for user "" folder "newFolder" of the space "restore objects" contain these files: + | file.txt | + And as "" file "file.txt" exist in the trashbin of the space "restore objects" + Examples: + | user | role | code | shouldOrNotBeInSpace | shouldOrNotBeInTrash | + | Alice | manager | 201 | should | should not | + | Brian | manager | 201 | should | should not | + | Brian | editor | 201 | should | should not | + | Brian | viewer | 403 | should not | should | diff --git a/tests/acceptance/features/bootstrap/SpacesContext.php b/tests/acceptance/features/bootstrap/SpacesContext.php index dd6d6e8311..6556134a74 100644 --- a/tests/acceptance/features/bootstrap/SpacesContext.php +++ b/tests/acceptance/features/bootstrap/SpacesContext.php @@ -49,6 +49,11 @@ class SpacesContext implements Context { */ private OCSContext $ocsContext; + /** + * @var TrashbinContext + */ + private TrashbinContext $trashbinContext; + /** * @var string */ @@ -323,6 +328,7 @@ class SpacesContext implements Context { // Get all the contexts you need in this context $this->featureContext = $environment->getContext('FeatureContext'); $this->ocsContext = $environment->getContext('OCSContext'); + $this->trashbinContext = $environment->getContext('TrashbinContext'); // Run the BeforeScenario function in OCSContext to set it up correctly $this->ocsContext->before($scope); $this->baseUrl = \trim($this->featureContext->getBaseUrl(), "/"); @@ -1432,7 +1438,7 @@ class SpacesContext implements Context { } /** - * @When /^user "([^"]*)" has set the file "([^"]*)" as a (description|space image)\s? in a special section of the "([^"]*)" space$/ + * @Given /^user "([^"]*)" has set the file "([^"]*)" as a (description|space image)\s? in a special section of the "([^"]*)" space$/ * * @param string $user * @param string $file @@ -1516,7 +1522,7 @@ class SpacesContext implements Context { } /** - * @When /^user "([^"]*)" has created a space "([^"]*)" with the default quota using the GraphApi$/ + * @Given /^user "([^"]*)" has created a space "([^"]*)" with the default quota using the GraphApi$/ * * @param string $user * @param string $spaceName @@ -1766,7 +1772,7 @@ class SpacesContext implements Context { } /** - * @When /^user "([^"]*)" removes the object "([^"]*)" from space "([^"]*)"$/ + * @When /^user "([^"]*)" removes the (?:file|folder) "([^"]*)" from space "([^"]*)"$/ * * @param string $user * @param string $object @@ -1818,7 +1824,30 @@ class SpacesContext implements Context { } /** - * @When /^user "([^"]*)" has disabled a space "([^"]*)"$/ + * @Given /^user "([^"]*)" has removed the (?:file|folder) "([^"]*)" from space "([^"]*)"$/ + * + * @param string $user + * @param string $object + * @param string $spaceName + * + * @return void + * @throws GuzzleException + */ + public function sendUserHasRemovedObjectFromSpaceRequest( + string $user, + string $object, + string $spaceName + ): void { + $this->sendRemoveObjectFromSpaceRequest($user, $object, $spaceName); + $expectedHTTPStatus = "204"; + $this->featureContext->theHTTPStatusCodeShouldBe( + $expectedHTTPStatus, + "Expected response status code should be $expectedHTTPStatus" + ); + } + + /** + * @Given /^user "([^"]*)" has disabled a space "([^"]*)"$/ * * @param string $user * @param string $spaceName @@ -1919,7 +1948,7 @@ class SpacesContext implements Context { } /** - * @When /^user "([^"]*)" has restored a disabled space "([^"]*)"$/ + * @Given /^user "([^"]*)" has restored a disabled space "([^"]*)"$/ * * @param string $user * @param string $spaceName @@ -1938,4 +1967,139 @@ class SpacesContext implements Context { "Expected response status code should be $expectedHTTPStatus" ); } + + /** + * @When /^user "([^"]*)" lists all deleted files in the trash bin of the space "([^"]*)"$/ + * + * @param string $user + * @param string $spaceName + * + * @return void + * @throws GuzzleException + */ + public function userListAllDeletedFilesinTrash( + string $user, + string $spaceName + ): void { + $space = $this->getSpaceByName($user, $spaceName); + $fullUrl = $this->baseUrl . "/remote.php/dav/spaces/trash-bin/" . $space["id"]; + $this->featureContext->setResponse( + HttpRequestHelper::sendRequest( + $fullUrl, + "", + 'PROPFIND', + $user, + $this->featureContext->getPasswordForUser($user), + [], + "" + ) + ); + } + + /** + * User get all objects in the trash of project space + * + * method "getTrashbinContentFromResponseXml" borrowed from core repository + * and return array like: + * [1] => Array + * ( + * [href] => /remote.php/dav/spaces/trash-bin/spaceId/objectId/ + * [name] => deleted folder + * [mtime] => 1649147272 + * [original-location] => deleted folder + * ) + * + * @param string $user + * @param string $spaceName + * + * @return array + * @throws GuzzleException + */ + public function getObjectsInTrashbin( + string $user, + string $spaceName + ): array { + $this->userListAllDeletedFilesinTrash($user, $spaceName); + $this->featureContext->theHTTPStatusCodeShouldBe( + 207, + "Expected response status code should be 207" + ); + return $this->trashbinContext->getTrashbinContentFromResponseXml( + $this->featureContext->getResponseXml($this->featureContext->getResponse()) + ); + } + + /** + * @Then /^as "([^"]*)" (?:file|folder|entry) "([^"]*)" should (not|)\s?exist in the trashbin of the space "([^"]*)"$/ + * + * @param string $user + * @param string $object + * @param string $shouldOrNot (not|) + * @param string $spaceName + * + * @return void + * @throws GuzzleException + */ + public function checkExistanceOfObjectsInTrashbin( + string $user, + string $object, + string $shouldOrNot, + string $spaceName + ): void { + $objectsInTrash = $this->getObjectsInTrashbin($user, $spaceName); + + $expectedObject = ""; + foreach ($objectsInTrash as $objectInTrash) { + if ($objectInTrash["name"] === $object) { + $expectedObject = $objectInTrash["name"]; + } + }; + if ($shouldOrNot === "not") { + Assert::assertEmpty($expectedObject, "$object is found in the trash, but should not be there"); + } else Assert::assertNotEmpty($expectedObject, "$object is not found in the trash"); + } + + /** + * @When /^user "([^"]*)" restores the (?:file|folder) "([^"]*)" from the trash of the space "([^"]*)" to "([^"]*)"$/ + * + * @param string $user + * @param string $object + * @param string $spaceName + * @param string $destination + * + * @return void + * @throws GuzzleException + */ + public function userRestoresSpaceObjectsFromTrashRequest( + string $user, + string $object, + string $spaceName, + string $destination + ): void { + $space = $this->getSpaceByName($user, $spaceName); + + // find object in trash + $objectsInTrash = $this->getObjectsInTrashbin($user, $spaceName); + foreach ($objectsInTrash as $objectInTrash) { + if ($objectInTrash["name"] === $object) { + $pathToDeletedObject = $objectInTrash["href"]; + } + }; + + $destination = $this->baseUrl . "/remote.php/dav/spaces/" . $space["id"] . $destination; + $header = ["Destination" => $destination, "Overwrite" => "F"]; + + $fullUrl = $this->baseUrl . $pathToDeletedObject; + $this->featureContext->setResponse( + HttpRequestHelper::sendRequest( + $fullUrl, + "", + 'MOVE', + $user, + $this->featureContext->getPasswordForUser($user), + $header, + "" + ) + ); + } }