Skip to content

Commit 4158d7c

Browse files
Vincent PetryDeepDiver1975
authored andcommitted
Add transfer ownership integration tests (#26543)
* Add transfer ownership integration tests * Added more transfer ownership tests and OCC checks
1 parent f31082b commit 4158d7c

File tree

6 files changed

+398
-9
lines changed

6 files changed

+398
-9
lines changed

build/integration/config/behat.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ default:
2222
baseUrl: http://localhost:8080
2323
- TagsContext:
2424
baseUrl: http://localhost:8080
25+
- CommandLineContext:
26+
baseUrl: http://localhost:8080
27+
ocPath: ../../
2528
federation:
2629
paths:
2730
- %paths.base%/../federation_features
@@ -53,8 +56,6 @@ default:
5356
- admin
5457
regular_user_password: 123456
5558

56-
57-
5859
extensions:
5960
jarnaiz\JUnitFormatter\JUnitFormatterExtension:
6061
filename: report.xml
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
/**
3+
* @author Vincent Petry <pvince81@owncloud.com>
4+
*
5+
* @copyright Copyright (c) 2016, ownCloud, Inc.
6+
* @license AGPL-3.0
7+
*
8+
* This code is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License, version 3,
10+
* as published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License, version 3,
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>
19+
*
20+
*/
21+
22+
require __DIR__ . '/../../vendor/autoload.php';
23+
24+
trait CommandLine {
25+
/** @var int return code of last command */
26+
private $lastCode;
27+
/** @var string stdout of last command */
28+
private $lastStdOut;
29+
/** @var string stderr of last command */
30+
private $lastStdErr;
31+
32+
/** @var string */
33+
protected $ocPath = '../..';
34+
35+
/**
36+
* Invokes an OCC command
37+
*
38+
* @param string OCC command, the part behind "occ". For example: "files:transfer-ownership"
39+
* @return int exit code
40+
*/
41+
public function runOcc($args = []) {
42+
$args = array_map(function($arg) {
43+
return escapeshellarg($arg);
44+
}, $args);
45+
$args[] = '--no-ansi';
46+
$args = implode(' ', $args);
47+
48+
$descriptor = [
49+
0 => ['pipe', 'r'],
50+
1 => ['pipe', 'w'],
51+
2 => ['pipe', 'w'],
52+
];
53+
$process = proc_open('php console.php ' . $args, $descriptor, $pipes, $this->ocPath);
54+
$this->lastStdOut = stream_get_contents($pipes[1]);
55+
$this->lastStdErr = stream_get_contents($pipes[2]);
56+
$this->lastCode = proc_close($process);
57+
return $this->lastCode;
58+
}
59+
60+
/**
61+
* @Given /^invoking occ with "([^"]*)"$/
62+
*/
63+
public function invokingTheCommand($cmd) {
64+
$args = explode(' ', $cmd);
65+
$this->runOcc($args);
66+
}
67+
68+
/**
69+
* Find exception texts in stderr
70+
*/
71+
public function findExceptions() {
72+
$exceptions = [];
73+
$captureNext = false;
74+
// the exception text usually appears after an "[Exception"] row
75+
foreach (explode("\n", $this->lastStdErr) as $line) {
76+
if (preg_match('/\[Exception\]/', $line)) {
77+
$captureNext = true;
78+
continue;
79+
}
80+
if ($captureNext) {
81+
$exceptions[] = trim($line);
82+
$captureNext = false;
83+
}
84+
}
85+
86+
return $exceptions;
87+
}
88+
89+
/**
90+
* Finds all lines containing the given text
91+
*
92+
* @param string $input stdout or stderr output
93+
* @param string $text text to search for
94+
* @return array array of lines that matched
95+
*/
96+
public function findLines($input, $text) {
97+
$results = [];
98+
// the exception text usually appears after an "[Exception"] row
99+
foreach (explode("\n", $input) as $line) {
100+
if (strpos($line, $text) >= 0) {
101+
$results[] = $line;
102+
}
103+
}
104+
105+
return $results;
106+
}
107+
108+
/**
109+
* @Then /^the command was successful$/
110+
*/
111+
public function theCommandWasSuccessful() {
112+
$exceptions = $this->findExceptions();
113+
if ($this->lastCode !== 0) {
114+
$msg = 'The command was not successful, exit code was ' . $this->lastCode . '.';
115+
if (!empty($exceptions)) {
116+
$msg .= ' Exceptions: ' . implode(', ', $exceptions);
117+
}
118+
throw new \Exception($msg);
119+
} else if (!empty($exceptions)) {
120+
$msg = 'The command was successful but triggered exceptions: ' . implode(', ', $exceptions);
121+
throw new \Exception($msg);
122+
}
123+
}
124+
125+
/**
126+
* @Then /^the command failed with exit code ([0-9]+)$/
127+
*/
128+
public function theCommandFailedWithExitCode($exitCode) {
129+
if ($this->lastCode !== (int)$exitCode) {
130+
throw new \Exception('The command was expected to fail with exit code ' . $exitCode . ' but got ' . $this->lastCode);
131+
}
132+
}
133+
134+
/**
135+
* @Then /^the command failed with exception text "([^"]*)"$/
136+
*/
137+
public function theCommandFailedWithException($exceptionText) {
138+
$exceptions = $this->findExceptions();
139+
if (empty($exceptions)) {
140+
throw new \Exception('The command did not throw any exceptions');
141+
}
142+
143+
if (!in_array($exceptionText, $exceptions)) {
144+
throw new \Exception('The command did not throw any exception with the text "' . $exceptionText . '"');
145+
}
146+
}
147+
148+
/**
149+
* @Then /^the command output contains the text "([^"]*)"$/
150+
*/
151+
public function theCommandOutputContainsTheText($text) {
152+
$lines = $this->findLines($this->lastStdOut, $text);
153+
if (empty($lines)) {
154+
throw new \Exception('The command did not output the expected text on stdout "' . $exceptionText . '"');
155+
}
156+
}
157+
158+
/**
159+
* @Then /^the command error output contains the text "([^"]*)"$/
160+
*/
161+
public function theCommandErrorOutputContainsTheText($text) {
162+
$lines = $this->findLines($this->lastStdErr, $text);
163+
if (empty($lines)) {
164+
throw new \Exception('The command did not output the expected text on stderr "' . $exceptionText . '"');
165+
}
166+
}
167+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
/**
3+
* @author Vincent Petry <pvince81@owncloud.com>
4+
*
5+
* @copyright Copyright (c) 2016, ownCloud, Inc.
6+
* @license AGPL-3.0
7+
*
8+
* This code is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License, version 3,
10+
* as published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License, version 3,
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>
19+
*
20+
*/
21+
22+
require __DIR__ . '/../../vendor/autoload.php';
23+
24+
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
25+
26+
class CommandLineContext implements \Behat\Behat\Context\Context {
27+
use CommandLine;
28+
29+
private $lastTransferPath;
30+
31+
private $featureContext;
32+
33+
public function __construct($ocPath, $baseUrl) {
34+
$this->ocPath = rtrim($ocPath, '/') . '/';
35+
$this->localBaseUrl = $baseUrl;
36+
$this->remoteBaseUrl = $baseUrl;
37+
}
38+
39+
/** @BeforeScenario */
40+
public function gatherContexts(BeforeScenarioScope $scope) {
41+
$environment = $scope->getEnvironment();
42+
// this should really be "WebDavContext" ...
43+
$this->featureContext = $environment->getContext('FeatureContext');
44+
}
45+
46+
private function findLastTransferFolderForUser($sourceUser, $targetUser) {
47+
$foundPaths = [];
48+
$results = $this->featureContext->listFolder($targetUser, '', 1);
49+
foreach ($results as $path => $data) {
50+
$path = rawurldecode($path);
51+
$parts = explode(' ', $path);
52+
if (basename($parts[0]) !== 'transferred') {
53+
continue;
54+
}
55+
if (isset($parts[2]) && $parts[2] === $sourceUser) {
56+
// store timestamp as key
57+
$foundPaths[] = [
58+
'date' => strtotime(dirname($parts[4])),
59+
'path' => $path,
60+
];
61+
}
62+
}
63+
64+
if (empty($foundPaths)) {
65+
return null;
66+
}
67+
68+
usort($foundPaths, function($a, $b) {
69+
return $a['date'] - $b['date'];
70+
});
71+
72+
$davPath = rtrim($this->featureContext->getDavFilesPath($targetUser), '/');
73+
74+
$foundPath = end($foundPaths)['path'];
75+
// strip dav path
76+
return substr($foundPath, strlen($davPath) + 1);
77+
}
78+
79+
/**
80+
* @When /^transfering ownership from "([^"]+)" to "([^"]+)"/
81+
*/
82+
public function transferingOwnership($user1, $user2) {
83+
if ($this->runOcc(['files:transfer-ownership', $user1, $user2]) === 0) {
84+
$this->lastTransferPath = $this->findLastTransferFolderForUser($user1, $user2);
85+
} else {
86+
// failure
87+
$this->lastTransferPath = null;
88+
}
89+
}
90+
91+
/**
92+
* @When /^using received transfer folder of "([^"]+)" as dav path$/
93+
*/
94+
public function usingTransferFolderAsDavPath($user) {
95+
$davPath = $this->featureContext->getDavFilesPath($user);
96+
$davPath = rtrim($davPath, '/') . $this->lastTransferPath;
97+
$this->featureContext->usingDavPath($davPath);
98+
}
99+
}

build/integration/features/bootstrap/WebDav.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ public function userDeletesFile($user, $file) {
435435
*/
436436
public function userCreatedAFolder($user, $destination){
437437
try {
438+
$destination = '/' . ltrim($destination, '/');
438439
$this->response = $this->makeDavRequest($user, "MKCOL", $this->getFilesPath() . ltrim($destination, $this->getFilesPath()), []);
439440
} catch (\GuzzleHttp\Exception\ServerException $e) {
440441
// 4xx and 5xx responses cause an exception

0 commit comments

Comments
 (0)