summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Petry <pvince81@owncloud.com>2016-11-07 22:52:07 +0100
committerLukas Reschke <lukas@statuscode.ch>2016-12-19 14:10:12 +0100
commit55bf9e3f711c5eacfe2c096dd2ee99bc4e7fcf8a (patch)
tree02739b79b894b8c8d347b70296fe8f0ed26d1581
parent9b71ee27ff95336c36d608217d9621110e6674c1 (diff)
downloadnextcloud-server-55bf9e3f711c5eacfe2c096dd2ee99bc4e7fcf8a.tar.gz
nextcloud-server-55bf9e3f711c5eacfe2c096dd2ee99bc4e7fcf8a.zip
Add transfer ownership integration tests (#26543)
* Add transfer ownership integration tests * Added more transfer ownership tests and OCC checks Signed-off-by: Lukas Reschke <lukas@statuscode.ch>
-rw-r--r--build/integration/config/behat.yml5
-rw-r--r--build/integration/features/bootstrap/CommandLine.php167
-rw-r--r--build/integration/features/bootstrap/CommandLineContext.php99
-rw-r--r--build/integration/features/bootstrap/WebDav.php1
-rw-r--r--build/integration/features/transfer-ownership.feature119
-rwxr-xr-xbuild/integration/run.sh54
6 files changed, 405 insertions, 40 deletions
diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml
index 9ef36f083e9..82ad6eaa170 100644
--- a/build/integration/config/behat.yml
+++ b/build/integration/config/behat.yml
@@ -22,6 +22,9 @@ default:
baseUrl: http://localhost:8080
- ChecksumsContext:
baseUrl: http://localhost:8080
+ - CommandLineContext:
+ baseUrl: http://localhost:8080
+ ocPath: ../../
federation:
paths:
- %paths.base%/../federation_features
@@ -73,8 +76,6 @@ default:
- admin
regular_user_password: 123456
-
-
extensions:
jarnaiz\JUnitFormatter\JUnitFormatterExtension:
filename: report.xml
diff --git a/build/integration/features/bootstrap/CommandLine.php b/build/integration/features/bootstrap/CommandLine.php
new file mode 100644
index 00000000000..c0caf5f8e6e
--- /dev/null
+++ b/build/integration/features/bootstrap/CommandLine.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+trait CommandLine {
+ /** @var int return code of last command */
+ private $lastCode;
+ /** @var string stdout of last command */
+ private $lastStdOut;
+ /** @var string stderr of last command */
+ private $lastStdErr;
+
+ /** @var string */
+ protected $ocPath = '../..';
+
+ /**
+ * Invokes an OCC command
+ *
+ * @param string OCC command, the part behind "occ". For example: "files:transfer-ownership"
+ * @return int exit code
+ */
+ public function runOcc($args = []) {
+ $args = array_map(function($arg) {
+ return escapeshellarg($arg);
+ }, $args);
+ $args[] = '--no-ansi';
+ $args = implode(' ', $args);
+
+ $descriptor = [
+ 0 => ['pipe', 'r'],
+ 1 => ['pipe', 'w'],
+ 2 => ['pipe', 'w'],
+ ];
+ $process = proc_open('php console.php ' . $args, $descriptor, $pipes, $this->ocPath);
+ $this->lastStdOut = stream_get_contents($pipes[1]);
+ $this->lastStdErr = stream_get_contents($pipes[2]);
+ $this->lastCode = proc_close($process);
+ return $this->lastCode;
+ }
+
+ /**
+ * @Given /^invoking occ with "([^"]*)"$/
+ */
+ public function invokingTheCommand($cmd) {
+ $args = explode(' ', $cmd);
+ $this->runOcc($args);
+ }
+
+ /**
+ * Find exception texts in stderr
+ */
+ public function findExceptions() {
+ $exceptions = [];
+ $captureNext = false;
+ // the exception text usually appears after an "[Exception"] row
+ foreach (explode("\n", $this->lastStdErr) as $line) {
+ if (preg_match('/\[Exception\]/', $line)) {
+ $captureNext = true;
+ continue;
+ }
+ if ($captureNext) {
+ $exceptions[] = trim($line);
+ $captureNext = false;
+ }
+ }
+
+ return $exceptions;
+ }
+
+ /**
+ * Finds all lines containing the given text
+ *
+ * @param string $input stdout or stderr output
+ * @param string $text text to search for
+ * @return array array of lines that matched
+ */
+ public function findLines($input, $text) {
+ $results = [];
+ // the exception text usually appears after an "[Exception"] row
+ foreach (explode("\n", $input) as $line) {
+ if (strpos($line, $text) >= 0) {
+ $results[] = $line;
+ }
+ }
+
+ return $results;
+ }
+
+ /**
+ * @Then /^the command was successful$/
+ */
+ public function theCommandWasSuccessful() {
+ $exceptions = $this->findExceptions();
+ if ($this->lastCode !== 0) {
+ $msg = 'The command was not successful, exit code was ' . $this->lastCode . '.';
+ if (!empty($exceptions)) {
+ $msg .= ' Exceptions: ' . implode(', ', $exceptions);
+ }
+ throw new \Exception($msg);
+ } else if (!empty($exceptions)) {
+ $msg = 'The command was successful but triggered exceptions: ' . implode(', ', $exceptions);
+ throw new \Exception($msg);
+ }
+ }
+
+ /**
+ * @Then /^the command failed with exit code ([0-9]+)$/
+ */
+ public function theCommandFailedWithExitCode($exitCode) {
+ if ($this->lastCode !== (int)$exitCode) {
+ throw new \Exception('The command was expected to fail with exit code ' . $exitCode . ' but got ' . $this->lastCode);
+ }
+ }
+
+ /**
+ * @Then /^the command failed with exception text "([^"]*)"$/
+ */
+ public function theCommandFailedWithException($exceptionText) {
+ $exceptions = $this->findExceptions();
+ if (empty($exceptions)) {
+ throw new \Exception('The command did not throw any exceptions');
+ }
+
+ if (!in_array($exceptionText, $exceptions)) {
+ throw new \Exception('The command did not throw any exception with the text "' . $exceptionText . '"');
+ }
+ }
+
+ /**
+ * @Then /^the command output contains the text "([^"]*)"$/
+ */
+ public function theCommandOutputContainsTheText($text) {
+ $lines = $this->findLines($this->lastStdOut, $text);
+ if (empty($lines)) {
+ throw new \Exception('The command did not output the expected text on stdout "' . $exceptionText . '"');
+ }
+ }
+
+ /**
+ * @Then /^the command error output contains the text "([^"]*)"$/
+ */
+ public function theCommandErrorOutputContainsTheText($text) {
+ $lines = $this->findLines($this->lastStdErr, $text);
+ if (empty($lines)) {
+ throw new \Exception('The command did not output the expected text on stderr "' . $exceptionText . '"');
+ }
+ }
+}
diff --git a/build/integration/features/bootstrap/CommandLineContext.php b/build/integration/features/bootstrap/CommandLineContext.php
new file mode 100644
index 00000000000..374a14410bf
--- /dev/null
+++ b/build/integration/features/bootstrap/CommandLineContext.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+use Behat\Behat\Hook\Scope\BeforeScenarioScope;
+
+class CommandLineContext implements \Behat\Behat\Context\Context {
+ use CommandLine;
+
+ private $lastTransferPath;
+
+ private $featureContext;
+
+ public function __construct($ocPath, $baseUrl) {
+ $this->ocPath = rtrim($ocPath, '/') . '/';
+ $this->localBaseUrl = $baseUrl;
+ $this->remoteBaseUrl = $baseUrl;
+ }
+
+ /** @BeforeScenario */
+ public function gatherContexts(BeforeScenarioScope $scope) {
+ $environment = $scope->getEnvironment();
+ // this should really be "WebDavContext" ...
+ $this->featureContext = $environment->getContext('FeatureContext');
+ }
+
+ private function findLastTransferFolderForUser($sourceUser, $targetUser) {
+ $foundPaths = [];
+ $results = $this->featureContext->listFolder($targetUser, '', 1);
+ foreach ($results as $path => $data) {
+ $path = rawurldecode($path);
+ $parts = explode(' ', $path);
+ if (basename($parts[0]) !== 'transferred') {
+ continue;
+ }
+ if (isset($parts[2]) && $parts[2] === $sourceUser) {
+ // store timestamp as key
+ $foundPaths[] = [
+ 'date' => strtotime(dirname($parts[4])),
+ 'path' => $path,
+ ];
+ }
+ }
+
+ if (empty($foundPaths)) {
+ return null;
+ }
+
+ usort($foundPaths, function($a, $b) {
+ return $a['date'] - $b['date'];
+ });
+
+ $davPath = rtrim($this->featureContext->getDavFilesPath($targetUser), '/');
+
+ $foundPath = end($foundPaths)['path'];
+ // strip dav path
+ return substr($foundPath, strlen($davPath) + 1);
+ }
+
+ /**
+ * @When /^transfering ownership from "([^"]+)" to "([^"]+)"/
+ */
+ public function transferingOwnership($user1, $user2) {
+ if ($this->runOcc(['files:transfer-ownership', $user1, $user2]) === 0) {
+ $this->lastTransferPath = $this->findLastTransferFolderForUser($user1, $user2);
+ } else {
+ // failure
+ $this->lastTransferPath = null;
+ }
+ }
+
+ /**
+ * @When /^using received transfer folder of "([^"]+)" as dav path$/
+ */
+ public function usingTransferFolderAsDavPath($user) {
+ $davPath = $this->featureContext->getDavFilesPath($user);
+ $davPath = rtrim($davPath, '/') . $this->lastTransferPath;
+ $this->featureContext->usingDavPath($davPath);
+ }
+}
diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php
index 0a08e764e30..c44a6175579 100644
--- a/build/integration/features/bootstrap/WebDav.php
+++ b/build/integration/features/bootstrap/WebDav.php
@@ -514,6 +514,7 @@ trait WebDav {
*/
public function userCreatedAFolder($user, $destination) {
try {
+ $destination = '/' . ltrim($destination, '/');
$this->response = $this->makeDavRequest($user, "MKCOL", $destination, []);
} catch (\GuzzleHttp\Exception\ServerException $e) {
// 4xx and 5xx responses cause an exception
diff --git a/build/integration/features/transfer-ownership.feature b/build/integration/features/transfer-ownership.feature
new file mode 100644
index 00000000000..92361f70900
--- /dev/null
+++ b/build/integration/features/transfer-ownership.feature
@@ -0,0 +1,119 @@
+Feature: transfer-ownership
+
+ Scenario: transfering ownership of a file
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" uploads file "data/textfile.txt" to "/somefile.txt"
+ When transfering ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is"
+
+ Scenario: transfering ownership of a folder
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ When transfering ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+
+ Scenario: transfering ownership of file shares
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user0" uploads file "data/textfile.txt" to "/somefile.txt"
+ And file "/somefile.txt" of user "user0" is shared with user "user2" with permissions 19
+ When transfering ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/somefile.txt" with range "bytes=0-6" should be "This is"
+
+ Scenario: transfering ownership of folder shared with third user
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with user "user2" with permissions 31
+ When transfering ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+
+ Scenario: transfering ownership of folder shared with transfer recipient
+ Given user "user0" exists
+ And user "user1" exists
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with user "user1" with permissions 31
+ When transfering ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ Then as "user1" the folder "/test" does not exist
+ And using received transfer folder of "user1" as dav path
+ And Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+
+ Scenario: transfering ownership of folder doubly shared with third user
+ Given group "group1" exists
+ And user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user2" belongs to group "group1"
+ And User "user0" created a folder "/test"
+ And User "user0" uploads file "data/textfile.txt" to "/test/somefile.txt"
+ And folder "/test" of user "user0" is shared with group "group1" with permissions 31
+ And folder "/test" of user "user0" is shared with user "user2" with permissions 31
+ When transfering ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user2"
+ Then Downloaded content when downloading file "/test/somefile.txt" with range "bytes=0-6" should be "This is"
+
+ Scenario: transfering ownership does not transfer received shares
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user2" created a folder "/test"
+ And folder "/test" of user "user2" is shared with user "user0" with permissions 31
+ When transfering ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then as "user1" the folder "/test" does not exist
+
+ @local_storage
+ Scenario: transfering ownership does not transfer external storage
+ Given user "user0" exists
+ And user "user1" exists
+ When transfering ownership from "user0" to "user1"
+ And the command was successful
+ And As an "user1"
+ And using received transfer folder of "user1" as dav path
+ Then as "user1" the folder "/local_storage" does not exist
+
+ Scenario: transfering ownership does not fail with shared trashed files
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And User "user0" created a folder "/sub"
+ And User "user0" created a folder "/sub/test"
+ And folder "/sub/test" of user "user0" is shared with user "user2" with permissions 31
+ And User "user0" deletes folder "/sub"
+ When transfering ownership from "user0" to "user1"
+ Then the command was successful
+
+ Scenario: transfering ownership fails with invalid source user
+ Given user "user0" exists
+ When transfering ownership from "invalid_user" to "user0"
+ Then the command error output contains the text "Unknown source user"
+ And the command failed with exit code 1
+
+ Scenario: transfering ownership fails with invalid target user
+ Given user "user0" exists
+ When transfering ownership from "user0" to "invalid_user"
+ Then the command error output contains the text "Unknown target user"
+ And the command failed with exit code 1
+
diff --git a/build/integration/run.sh b/build/integration/run.sh
index 145415fd079..ff5efe0c3ec 100755
--- a/build/integration/run.sh
+++ b/build/integration/run.sh
@@ -1,31 +1,13 @@
#!/usr/bin/env bash
-COMPOSER=$(which composer)
+composer install
+
+OC_PATH=../../
+OCC=${OC_PATH}occ
SCENARIO_TO_RUN=$1
HIDE_OC_LOGS=$2
-if [ -x "$COMPOSER" ]; then
- echo "Using composer executable $COMPOSER"
-else
- echo "Could not find composer executable" >&2
- exit 1
-fi
-
-INSTALLED=$(../../occ status | grep installed: | cut -d " " -f 5)
-
-if [ "$INSTALLED" == "true" ]; then
- # Disable bruteforce protection because the integration tests do trigger them
- ../../occ config:system:set auth.bruteforce.protection.enabled --value false --type bool
-else
- if [ "$SCENARIO_TO_RUN" != "setup_features/setup.feature" ]; then
- echo "Nextcloud instance needs to be installed" >&2
- exit 1
- fi
-fi
-
-composer install
-
# avoid port collision on jenkins - use $EXECUTOR_NUMBER
if [ -z "$EXECUTOR_NUMBER" ]; then
EXECUTOR_NUMBER=0
@@ -45,34 +27,30 @@ echo $PHPPID_FED
export TEST_SERVER_URL="http://localhost:$PORT/ocs/"
export TEST_SERVER_FED_URL="http://localhost:$PORT_FED/ocs/"
-if [ "$INSTALLED" == "true" ]; then
- #Enable external storage app
- ../../occ app:enable files_external
+#Enable external storage app
+$OCC app:enable files_external
- mkdir -p work/local_storage
- OUTPUT_CREATE_STORAGE=`../../occ files_external:create local_storage local null::null -c datadir=./build/integration/work/local_storage`
+mkdir -p work/local_storage
+OUTPUT_CREATE_STORAGE=`$OCC files_external:create local_storage local null::null -c datadir=./build/integration/work/local_storage`
- ID_STORAGE=`echo $OUTPUT_CREATE_STORAGE | awk {'print $5'}`
+ID_STORAGE=`echo $OUTPUT_CREATE_STORAGE | awk {'print $5'}`
- ../../occ files_external:option $ID_STORAGE enable_sharing true
-fi
+$OCC files_external:option $ID_STORAGE enable_sharing true
-vendor/bin/behat -f junit -f pretty $SCENARIO_TO_RUN
+vendor/bin/behat --strict -f junit -f pretty $SCENARIO_TO_RUN
RESULT=$?
kill $PHPPID
kill $PHPPID_FED
-if [ "$INSTALLED" -eq "true" ]; then
- ../../occ files_external:delete -y $ID_STORAGE
+$OCC files_external:delete -y $ID_STORAGE
- #Disable external storage app
- ../../occ app:disable files_external
-fi
+#Disable external storage app
+$OCC app:disable files_external
if [ -z $HIDE_OC_LOGS ]; then
- tail "../../data/nextcloud.log"
+ tail "${OC_PATH}/data/owncloud.log"
fi
+echo "runsh: Exit code: $RESULT"
exit $RESULT
-