Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/build
diff options
context:
space:
mode:
authorSergio Bertolín <sbertolin@solidgear.es>2016-07-28 16:52:08 +0300
committerThomas Müller <DeepDiver1975@users.noreply.github.com>2016-07-28 16:52:08 +0300
commit396a4ad9a04520731c9106f5d84d9abca6c63d6f (patch)
treeaa1eee353482ac9a096830bcf606025a70b0f5e3 /build
parent023a525e1710145ef252be526a4fe230b3f13e84 (diff)
Stable9 backport integration tests (#25631)
* Bring all tests from master * Removed not applying tests of webdav * Removed tests about disabling/enabling users * Fixed/removed some sharing tests for 9.0 * fixed capabilities tests * Fixed security headers confusion * Indentation * Removed merging shares tests
Diffstat (limited to 'build')
-rw-r--r--build/integration/capabilities_features/capabilities.feature30
-rw-r--r--build/integration/config/behat.yml14
-rw-r--r--build/integration/features/bootstrap/AppConfiguration.php103
-rw-r--r--build/integration/features/bootstrap/BasicStructure.php68
-rw-r--r--build/integration/features/bootstrap/CalDavContext.php10
-rw-r--r--build/integration/features/bootstrap/CapabilitiesContext.php86
-rw-r--r--build/integration/features/bootstrap/CardDavContext.php16
-rw-r--r--build/integration/features/bootstrap/ChecksumsContext.php24
-rw-r--r--build/integration/features/bootstrap/CommentsContext.php31
-rw-r--r--build/integration/features/bootstrap/FeatureContext.php5
-rw-r--r--build/integration/features/bootstrap/FederationContext.php41
-rw-r--r--build/integration/features/bootstrap/Provisioning.php118
-rw-r--r--build/integration/features/bootstrap/ShareesContext.php73
-rw-r--r--build/integration/features/bootstrap/Sharing.php128
-rw-r--r--build/integration/features/bootstrap/TagsContext.php202
-rw-r--r--build/integration/features/bootstrap/WebDav.php243
-rw-r--r--build/integration/features/dav-v2.feature55
-rw-r--r--build/integration/features/favorites.feature42
-rw-r--r--build/integration/features/provisioning-v1.feature17
-rw-r--r--build/integration/features/sharees.feature148
-rw-r--r--build/integration/features/sharing-v1.feature16
-rw-r--r--build/integration/features/tags.feature1
-rw-r--r--build/integration/features/webdav-related.feature47
-rw-r--r--build/integration/federation_features/federated.feature170
-rw-r--r--build/integration/sharees_features/sharees.feature240
25 files changed, 1491 insertions, 437 deletions
diff --git a/build/integration/capabilities_features/capabilities.feature b/build/integration/capabilities_features/capabilities.feature
index 3c1eb025ec7..48da09b698a 100644
--- a/build/integration/capabilities_features/capabilities.feature
+++ b/build/integration/capabilities_features/capabilities.feature
@@ -16,6 +16,7 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -35,6 +36,7 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -73,6 +75,7 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -92,6 +95,7 @@ Feature: capabilities
| files_sharing | resharing | EMPTY |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -111,6 +115,7 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | EMPTY |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -130,6 +135,7 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | EMPTY |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -150,6 +156,7 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -170,6 +177,7 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -190,6 +198,7 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
@@ -212,6 +221,27 @@ Feature: capabilities
| files_sharing | resharing | 1 |
| files_sharing | federation@@@outgoing | 1 |
| files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
+ | files | bigfilechunking | 1 |
+ | files | undelete | 1 |
+ | files | versioning | 1 |
+
+ Scenario: Changing group sharing allowed
+ Given As an "admin"
+ And parameter "shareapi_allow_group_sharing" of app "core" is set to "no"
+ When sending "GET" to "/cloud/capabilities"
+ Then the HTTP status code should be "200"
+ And fields of capabilities match with
+ | capability | path_to_element | value |
+ | core | pollinterval | 60 |
+ | core | webdav-root | remote.php/webdav |
+ | files_sharing | api_enabled | 1 |
+ | files_sharing | public@@@enabled | 1 |
+ | files_sharing | public@@@upload | 1 |
+ | files_sharing | resharing | 1 |
+ | files_sharing | federation@@@outgoing | 1 |
+ | files_sharing | federation@@@incoming | 1 |
+ | files_sharing | group_sharing | EMPTY |
| files | bigfilechunking | 1 |
| files | undelete | 1 |
| files | versioning | 1 |
diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml
index 4b5b5b16ef8..aed2d962682 100644
--- a/build/integration/config/behat.yml
+++ b/build/integration/config/behat.yml
@@ -14,14 +14,14 @@ default:
regular_user_password: 123456
- CommentsContext:
baseUrl: http://localhost:8080
- - TagsContext:
- baseUrl: http://localhost:8080
- CardDavContext:
baseUrl: http://localhost:8080
- CalDavContext:
baseUrl: http://localhost:8080
- ChecksumsContext:
baseUrl: http://localhost:8080
+ - TagsContext:
+ baseUrl: http://localhost:8080
federation:
paths:
- %paths.base%/../federation_features
@@ -42,6 +42,16 @@ default:
- admin
- admin
regular_user_password: 123456
+ sharees:
+ paths:
+ - %paths.base%/../sharees_features
+ contexts:
+ - ShareesContext:
+ baseUrl: http://localhost:8080/ocs/
+ admin:
+ - admin
+ - admin
+ regular_user_password: 123456
diff --git a/build/integration/features/bootstrap/AppConfiguration.php b/build/integration/features/bootstrap/AppConfiguration.php
new file mode 100644
index 00000000000..af904a30896
--- /dev/null
+++ b/build/integration/features/bootstrap/AppConfiguration.php
@@ -0,0 +1,103 @@
+<?php
+
+use Behat\Behat\Hook\Scope\AfterScenarioScope;
+use Behat\Behat\Hook\Scope\BeforeScenarioScope;
+use GuzzleHttp\Message\ResponseInterface;
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+trait AppConfiguration {
+ /** @var string */
+ private $currentUser = '';
+
+ /** @var ResponseInterface */
+ private $response = null;
+
+ abstract public function sendingTo($verb, $url);
+ abstract public function sendingToWith($verb, $url, $body);
+ abstract public function theOCSStatusCodeShouldBe($statusCode);
+ abstract public function theHTTPStatusCodeShouldBe($statusCode);
+
+ /**
+ * @Given /^parameter "([^"]*)" of app "([^"]*)" is set to "([^"]*)"$/
+ * @param string $parameter
+ * @param string $app
+ * @param string $value
+ */
+ public function serverParameterIsSetTo($parameter, $app, $value) {
+ $user = $this->currentUser;
+ $this->currentUser = 'admin';
+
+ $this->modifyServerConfig($app, $parameter, $value);
+
+ $this->currentUser = $user;
+ }
+
+ /**
+ * @param string $app
+ * @param string $parameter
+ * @param string $value
+ */
+ protected function modifyServerConfig($app, $parameter, $value) {
+ $body = new \Behat\Gherkin\Node\TableNode([['value', $value]]);
+ $this->sendingToWith('post', "/apps/testing/api/v1/app/{$app}/{$parameter}", $body);
+ $this->theHTTPStatusCodeShouldBe('200');
+ $this->theOCSStatusCodeShouldBe('100');
+ }
+
+ protected function setStatusTestingApp($enabled) {
+ $this->sendingTo(($enabled ? 'post' : 'delete'), '/cloud/apps/testing');
+ $this->theHTTPStatusCodeShouldBe('200');
+ $this->theOCSStatusCodeShouldBe('100');
+
+ $this->sendingTo('get', '/cloud/apps?filter=enabled');
+ $this->theHTTPStatusCodeShouldBe('200');
+ if ($enabled) {
+ PHPUnit_Framework_Assert::assertContains('testing', $this->response->getBody()->getContents());
+ } else {
+ PHPUnit_Framework_Assert::assertNotContains('testing', $this->response->getBody()->getContents());
+ }
+ }
+
+ abstract protected function resetAppConfigs();
+
+ /**
+ * @BeforeScenario
+ *
+ * Enable the testing app before the first scenario of the feature and
+ * reset the configs before each scenario
+ * @param BeforeScenarioScope $event
+ */
+ public function prepareParameters(BeforeScenarioScope $event){
+ $user = $this->currentUser;
+ $this->currentUser = 'admin';
+
+ $scenarios = $event->getFeature()->getScenarios();
+ if ($event->getScenario() === reset($scenarios)) {
+ $this->setStatusTestingApp(true);
+ }
+
+ $this->resetAppConfigs();
+
+ $this->currentUser = $user;
+ }
+
+ /**
+ * @AfterScenario
+ *
+ * Reset the values after the last scenario of the feature and disable the testing app
+ * @param AfterScenarioScope $event
+ */
+ public function undoChangingParameters(AfterScenarioScope $event) {
+ $scenarios = $event->getFeature()->getScenarios();
+ if ($event->getScenario() === end($scenarios)) {
+ $user = $this->currentUser;
+ $this->currentUser = 'admin';
+
+ $this->resetAppConfigs();
+
+ $this->setStatusTestingApp(false);
+ $this->currentUser = $user;
+ }
+ }
+}
diff --git a/build/integration/features/bootstrap/BasicStructure.php b/build/integration/features/bootstrap/BasicStructure.php
index 0084597836f..f693a242e17 100644
--- a/build/integration/features/bootstrap/BasicStructure.php
+++ b/build/integration/features/bootstrap/BasicStructure.php
@@ -1,13 +1,12 @@
<?php
-use Behat\Behat\Context\Context;
-use Behat\Behat\Context\SnippetAcceptingContext;
use GuzzleHttp\Client;
use GuzzleHttp\Message\ResponseInterface;
require __DIR__ . '/../../vendor/autoload.php';
trait BasicStructure {
+
/** @var string */
private $currentUser = '';
@@ -17,6 +16,9 @@ trait BasicStructure {
/** @var string */
private $baseUrl = '';
+ /** @var int */
+ private $apiVersion = 1;
+
/** @var ResponseInterface */
private $response = null;
@@ -24,7 +26,7 @@ trait BasicStructure {
private $cookieJar;
/** @var string */
- private $requesttoken;
+ private $requestToken;
public function __construct($baseUrl, $admin, $regular_user_password) {
@@ -32,8 +34,8 @@ trait BasicStructure {
$this->baseUrl = $baseUrl;
$this->adminUser = $admin;
$this->regularUser = $regular_user_password;
- $this->localBaseUrl = substr($this->baseUrl, 0, -4);
- $this->remoteBaseUrl = substr($this->baseUrl, 0, -4);
+ $this->localBaseUrl = $this->baseUrl;
+ $this->remoteBaseUrl = $this->baseUrl;
$this->currentServer = 'LOCAL';
$this->cookieJar = new \GuzzleHttp\Cookie\CookieJar();
@@ -52,29 +54,43 @@ trait BasicStructure {
}
/**
+ * @Given /^using api version "([^"]*)"$/
+ * @param string $version
+ */
+ public function usingApiVersion($version) {
+ $this->apiVersion = $version;
+ }
+
+ /**
* @Given /^As an "([^"]*)"$/
+ * @param string $user
*/
public function asAn($user) {
$this->currentUser = $user;
}
/**
- * @Given /^Using server "([^"]*)"$/
+ * @Given /^Using server "(LOCAL|REMOTE)"$/
+ * @param string $server
+ * @return string Previous used server
*/
public function usingServer($server) {
+ $previousServer = $this->currentServer;
if ($server === 'LOCAL'){
$this->baseUrl = $this->localBaseUrl;
$this->currentServer = 'LOCAL';
- } elseif ($server === 'REMOTE'){
+ return $previousServer;
+ } else {
$this->baseUrl = $this->remoteBaseUrl;
$this->currentServer = 'REMOTE';
- } else{
- PHPUnit_Framework_Assert::fail("Server can only be LOCAL or REMOTE");
+ return $previousServer;
}
}
/**
* @When /^sending "([^"]*)" to "([^"]*)"$/
+ * @param string $verb
+ * @param string $url
*/
public function sendingTo($verb, $url) {
$this->sendingToWith($verb, $url, null);
@@ -92,6 +108,8 @@ trait BasicStructure {
/**
* This function is needed to use a vertical fashion in the gherkin tables.
+ * @param array $arrayOfArrays
+ * @return array
*/
public function simplifyArray($arrayOfArrays){
$a = array_map(function($subArray) { return $subArray[0]; }, $arrayOfArrays);
@@ -100,6 +118,9 @@ trait BasicStructure {
/**
* @When /^sending "([^"]*)" to "([^"]*)" with$/
+ * @param string $verb
+ * @param string $url
+ * @param \Behat\Gherkin\Node\TableNode $body
*/
public function sendingToWith($verb, $url, $body) {
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php" . $url;
@@ -130,6 +151,7 @@ trait BasicStructure {
/**
* @Then /^the OCS status code should be "([^"]*)"$/
+ * @param int $statusCode
*/
public function theOCSStatusCodeShouldBe($statusCode) {
PHPUnit_Framework_Assert::assertEquals($statusCode, $this->getOCSResponse($this->response));
@@ -137,6 +159,7 @@ trait BasicStructure {
/**
* @Then /^the HTTP status code should be "([^"]*)"$/
+ * @param int $statusCode
*/
public function theHTTPStatusCodeShouldBe($statusCode) {
PHPUnit_Framework_Assert::assertEquals($statusCode, $this->response->getStatusCode());
@@ -146,14 +169,15 @@ trait BasicStructure {
* @param ResponseInterface $response
*/
private function extracRequestTokenFromResponse(ResponseInterface $response) {
- $this->requesttoken = substr(preg_replace('/(.*)data-requesttoken="(.*)">(.*)/sm', '\2', $response->getBody()->getContents()), 0, 89);
+ $this->requestToken = substr(preg_replace('/(.*)data-requesttoken="(.*)">(.*)/sm', '\2', $response->getBody()->getContents()), 0, 89);
}
/**
* @Given Logging in using web as :user
+ * @param string $user
*/
public function loggingInUsingWebAs($user) {
- $loginUrl = substr($this->baseUrl, 0, -5);
+ $loginUrl = substr($this->baseUrl, 0, -5) . '/login';
// Request a new session and extract CSRF token
$client = new Client();
$response = $client->get(
@@ -173,7 +197,7 @@ trait BasicStructure {
'body' => [
'user' => $user,
'password' => $password,
- 'requesttoken' => $this->requesttoken,
+ 'requesttoken' => $this->requestToken,
],
'cookies' => $this->cookieJar,
]
@@ -183,6 +207,8 @@ trait BasicStructure {
/**
* @When Sending a :method to :url with requesttoken
+ * @param string $method
+ * @param string $url
*/
public function sendingAToWithRequesttoken($method, $url) {
$baseUrl = substr($this->baseUrl, 0, -5);
@@ -195,7 +221,7 @@ trait BasicStructure {
'cookies' => $this->cookieJar,
]
);
- $request->addHeader('requesttoken', $this->requesttoken);
+ $request->addHeader('requesttoken', $this->requestToken);
try {
$this->response = $client->send($request);
} catch (\GuzzleHttp\Exception\ClientException $e) {
@@ -205,6 +231,8 @@ trait BasicStructure {
/**
* @When Sending a :method to :url without requesttoken
+ * @param string $method
+ * @param string $url
*/
public function sendingAToWithoutRequesttoken($method, $url) {
$baseUrl = substr($this->baseUrl, 0, -5);
@@ -231,6 +259,17 @@ trait BasicStructure {
}
/**
+ * @Given User :user modifies text of :filename with text :text
+ * @param string $user
+ * @param string $filename
+ * @param string $text
+ */
+ public function modifyTextOfFile($user, $filename, $text) {
+ self::removeFile("../../data/$user/files", "$filename");
+ file_put_contents("../../data/$user/files" . "$filename", "$text");
+ }
+
+ /**
* @BeforeSuite
*/
public static function addFilesToSkeleton(){
@@ -248,7 +287,6 @@ trait BasicStructure {
mkdir("../../core/skeleton/PARENT/CHILD", 0777, true);
}
file_put_contents("../../core/skeleton/PARENT/CHILD/" . "child.txt", "ownCloud test text file\n");
-
}
/**
@@ -269,8 +307,6 @@ trait BasicStructure {
if (is_dir("../../core/skeleton/PARENT")) {
rmdir("../../core/skeleton/PARENT");
}
-
-
}
}
diff --git a/build/integration/features/bootstrap/CalDavContext.php b/build/integration/features/bootstrap/CalDavContext.php
index 88711f3aa73..30c50630b3e 100644
--- a/build/integration/features/bootstrap/CalDavContext.php
+++ b/build/integration/features/bootstrap/CalDavContext.php
@@ -71,6 +71,8 @@ class CalDavContext implements \Behat\Behat\Context\Context {
/**
* @When :user requests calendar :calendar
+ * @param string $user
+ * @param string $calendar
*/
public function requestsCalendar($user, $calendar) {
$davUrl = $this->baseUrl . '/remote.php/dav/calendars/'.$calendar;
@@ -93,6 +95,8 @@ class CalDavContext implements \Behat\Behat\Context\Context {
/**
* @Then The CalDAV HTTP status code should be :code
+ * @param int $code
+ * @throws \Exception
*/
public function theCaldavHttpStatusCodeShouldBe($code) {
if((int)$code !== $this->response->getStatusCode()) {
@@ -115,6 +119,8 @@ class CalDavContext implements \Behat\Behat\Context\Context {
/**
* @Then The exception is :message
+ * @param string $message
+ * @throws \Exception
*/
public function theExceptionIs($message) {
$result = $this->responseXml['value'][0]['value'];
@@ -132,6 +138,8 @@ class CalDavContext implements \Behat\Behat\Context\Context {
/**
* @Then The error message is :message
+ * @param string $message
+ * @throws \Exception
*/
public function theErrorMessageIs($message) {
$result = $this->responseXml['value'][1]['value'];
@@ -149,6 +157,8 @@ class CalDavContext implements \Behat\Behat\Context\Context {
/**
* @Given :user creates a calendar named :name
+ * @param string $user
+ * @param string $name
*/
public function createsACalendarNamed($user, $name) {
$davUrl = $this->baseUrl . '/remote.php/dav/calendars/'.$user.'/'.$name;
diff --git a/build/integration/features/bootstrap/CapabilitiesContext.php b/build/integration/features/bootstrap/CapabilitiesContext.php
index d30984f0db7..57db3555790 100644
--- a/build/integration/features/bootstrap/CapabilitiesContext.php
+++ b/build/integration/features/bootstrap/CapabilitiesContext.php
@@ -15,20 +15,7 @@ require __DIR__ . '/../../vendor/autoload.php';
class CapabilitiesContext implements Context, SnippetAcceptingContext {
use BasicStructure;
- use Provisioning;
- use Sharing;
-
- /**
- * @Given /^parameter "([^"]*)" of app "([^"]*)" is set to "([^"]*)"$/
- */
- public function serverParameterIsSetTo($parameter, $app, $value){
- $user = $this->currentUser;
- $this->currentUser = 'admin';
-
- $this->modifyServerConfig($app, $parameter, $value);
-
- $this->currentUser = $user;
- }
+ use AppConfiguration;
/**
* @Then /^fields of capabilities match with$/
@@ -39,9 +26,9 @@ class CapabilitiesContext implements Context, SnippetAcceptingContext {
foreach ($formData->getHash() as $row) {
$path_to_element = explode('@@@', $row['path_to_element']);
- $answeredValue = $capabilitiesXML->$row['capability'];
+ $answeredValue = $capabilitiesXML->{$row['capability']};
for ($i = 0; $i < count($path_to_element); $i++){
- $answeredValue = $answeredValue->$path_to_element[$i];
+ $answeredValue = $answeredValue->{$path_to_element[$i]};
}
$answeredValue = (string)$answeredValue;
PHPUnit_Framework_Assert::assertEquals(
@@ -64,71 +51,6 @@ class CapabilitiesContext implements Context, SnippetAcceptingContext {
$this->modifyServerConfig('core', 'shareapi_allow_public_notification', 'no');
$this->modifyServerConfig('core', 'shareapi_default_expire_date', 'no');
$this->modifyServerConfig('core', 'shareapi_enforce_expire_date', 'no');
- }
-
- /**
- * @BeforeScenario
- *
- * Enable the testing app before the first scenario of the feature and
- * reset the configs before each scenario
- * @param BeforeScenarioScope $event
- */
- public function prepareParameters(BeforeScenarioScope $event){
- $user = $this->currentUser;
- $this->currentUser = 'admin';
-
- $scenarios = $event->getFeature()->getScenarios();
- if ($event->getScenario() === reset($scenarios)) {
- $this->setStatusTestingApp(true);
- }
-
- $this->resetAppConfigs();
-
- $this->currentUser = $user;
- }
-
- /**
- * @AfterScenario
- *
- * Reset the values after the last scenario of the feature and disable the testing app
- * @param AfterScenarioScope $event
- */
- public function undoChangingParameters(AfterScenarioScope $event) {
- $scenarios = $event->getFeature()->getScenarios();
- if ($event->getScenario() === end($scenarios)) {
- $user = $this->currentUser;
- $this->currentUser = 'admin';
-
- $this->resetAppConfigs();
-
- $this->setStatusTestingApp(false);
- $this->currentUser = $user;
- }
- }
-
- /**
- * @param string $app
- * @param string $parameter
- * @param string $value
- */
- protected function modifyServerConfig($app, $parameter, $value) {
- $body = new \Behat\Gherkin\Node\TableNode([['value', $value]]);
- $this->sendingToWith('post', "/apps/testing/api/v1/app/{$app}/{$parameter}", $body);
- $this->theHTTPStatusCodeShouldBe('200');
- $this->theOCSStatusCodeShouldBe('100');
- }
-
- protected function setStatusTestingApp($enabled) {
- $this->sendingTo(($enabled ? 'post' : 'delete'), '/cloud/apps/testing');
- $this->theHTTPStatusCodeShouldBe('200');
- $this->theOCSStatusCodeShouldBe('100');
-
- $this->sendingTo('get', '/cloud/apps?filter=enabled');
- $this->theHTTPStatusCodeShouldBe('200');
- if ($enabled) {
- PHPUnit_Framework_Assert::assertContains('testing', $this->response->getBody()->getContents());
- } else {
- PHPUnit_Framework_Assert::assertNotContains('testing', $this->response->getBody()->getContents());
- }
+ $this->modifyServerConfig('core', 'shareapi_allow_group_sharing', 'yes');
}
}
diff --git a/build/integration/features/bootstrap/CardDavContext.php b/build/integration/features/bootstrap/CardDavContext.php
index 251d76d0833..d317ba5193f 100644
--- a/build/integration/features/bootstrap/CardDavContext.php
+++ b/build/integration/features/bootstrap/CardDavContext.php
@@ -73,6 +73,10 @@ class CardDavContext implements \Behat\Behat\Context\Context {
/**
* @When :user requests addressbook :addressBook with statuscode :statusCode
+ * @param string $user
+ * @param string $addressBook
+ * @param int $statusCode
+ * @throws \Exception
*/
public function requestsAddressbookWithStatuscode($user, $addressBook, $statusCode) {
$davUrl = $this->baseUrl . '/remote.php/dav/addressbooks/users/'.$addressBook;
@@ -112,6 +116,10 @@ class CardDavContext implements \Behat\Behat\Context\Context {
/**
* @Given :user creates an addressbook named :addressBook with statuscode :statusCode
+ * @param string $user
+ * @param string $addressBook
+ * @param int $statusCode
+ * @throws \Exception
*/
public function createsAnAddressbookNamedWithStatuscode($user, $addressBook, $statusCode) {
$davUrl = $this->baseUrl . '/remote.php/dav/addressbooks/users/'.$user.'/'.$addressBook;
@@ -121,9 +129,7 @@ class CardDavContext implements \Behat\Behat\Context\Context {
'MKCOL',
$davUrl,
[
- 'body' => '<d:mkcol xmlns:c="urn:ietf:params:xml:ns:caldav"
- xmlns:card="urn:ietf:params:xml:ns:carddav"
- xmlns:cs="http://calendarserver.org/ns/"
+ 'body' => '<d:mkcol xmlns:card="urn:ietf:params:xml:ns:carddav"
xmlns:d="DAV:">
<d:set>
<d:prop>
@@ -158,6 +164,8 @@ class CardDavContext implements \Behat\Behat\Context\Context {
/**
* @When The CardDAV exception is :message
+ * @param string $message
+ * @throws \Exception
*/
public function theCarddavExceptionIs($message) {
$result = $this->responseXml['value'][0]['value'];
@@ -175,6 +183,8 @@ class CardDavContext implements \Behat\Behat\Context\Context {
/**
* @When The CardDAV error message is :arg1
+ * @param string $message
+ * @throws \Exception
*/
public function theCarddavErrorMessageIs($message) {
$result = $this->responseXml['value'][1]['value'];
diff --git a/build/integration/features/bootstrap/ChecksumsContext.php b/build/integration/features/bootstrap/ChecksumsContext.php
index a5d20ba965d..af8f9e5590d 100644
--- a/build/integration/features/bootstrap/ChecksumsContext.php
+++ b/build/integration/features/bootstrap/ChecksumsContext.php
@@ -2,7 +2,6 @@
require __DIR__ . '/../../vendor/autoload.php';
-use Behat\Gherkin\Node\TableNode;
use GuzzleHttp\Client;
use GuzzleHttp\Message\ResponseInterface;
@@ -50,6 +49,10 @@ class ChecksumsContext implements \Behat\Behat\Context\Context {
/**
* @When user :user uploads file :source to :destination with checksum :checksum
+ * @param string $user
+ * @param string $source
+ * @param string $destination
+ * @param string $checksum
*/
public function userUploadsFileToWithChecksum($user, $source, $destination, $checksum)
{
@@ -76,6 +79,8 @@ class ChecksumsContext implements \Behat\Behat\Context\Context {
/**
* @Then The webdav response should have a status code :statusCode
+ * @param int $statusCode
+ * @throws \Exception
*/
public function theWebdavResponseShouldHaveAStatusCode($statusCode) {
if((int)$statusCode !== $this->response->getStatusCode()) {
@@ -85,6 +90,8 @@ class ChecksumsContext implements \Behat\Behat\Context\Context {
/**
* @When user :user request the checksum of :path via propfind
+ * @param string $user
+ * @param string $path
*/
public function userRequestTheChecksumOfViaPropfind($user, $path)
{
@@ -109,6 +116,8 @@ class ChecksumsContext implements \Behat\Behat\Context\Context {
/**
* @Then The webdav checksum should match :checksum
+ * @param string $checksum
+ * @throws \Exception
*/
public function theWebdavChecksumShouldMatch($checksum)
{
@@ -128,6 +137,8 @@ class ChecksumsContext implements \Behat\Behat\Context\Context {
/**
* @When user :user downloads the file :path
+ * @param string $user
+ * @param string $path
*/
public function userDownloadsTheFile($user, $path)
{
@@ -144,6 +155,8 @@ class ChecksumsContext implements \Behat\Behat\Context\Context {
/**
* @Then The header checksum should match :checksum
+ * @param string $checksum
+ * @throws \Exception
*/
public function theHeaderChecksumShouldMatch($checksum)
{
@@ -154,6 +167,9 @@ class ChecksumsContext implements \Behat\Behat\Context\Context {
/**
* @Given User :user copied file :source to :destination
+ * @param string $user
+ * @param string $source
+ * @param string $destination
*/
public function userCopiedFileTo($user, $source, $destination)
{
@@ -204,6 +220,12 @@ class ChecksumsContext implements \Behat\Behat\Context\Context {
/**
* @Given user :user uploads chunk file :num of :total with :data to :destination with checksum :checksum
+ * @param string $user
+ * @param int $num
+ * @param int $total
+ * @param string $data
+ * @param string $destination
+ * @param string $checksum
*/
public function userUploadsChunkFileOfWithToWithChecksum($user, $num, $total, $data, $destination, $checksum)
{
diff --git a/build/integration/features/bootstrap/CommentsContext.php b/build/integration/features/bootstrap/CommentsContext.php
index d720bb8dcd6..e74e9580dcc 100644
--- a/build/integration/features/bootstrap/CommentsContext.php
+++ b/build/integration/features/bootstrap/CommentsContext.php
@@ -45,7 +45,7 @@ class CommentsContext implements \Behat\Behat\Context\Context {
}
/** @AfterScenario */
- public function teardownScenario(\Behat\Behat\Hook\Scope\AfterScenarioScope $scope) {
+ public function teardownScenario() {
$client = new \GuzzleHttp\Client();
try {
$client->delete(
@@ -66,6 +66,7 @@ class CommentsContext implements \Behat\Behat\Context\Context {
}
/**
+ * @param string $path
* @return int
*/
private function getFileIdForPath($path) {
@@ -90,6 +91,11 @@ class CommentsContext implements \Behat\Behat\Context\Context {
/**
* @When :user posts a comment with content :content on the file named :fileName it should return :statusCode
+ * @param string $user
+ * @param string $content
+ * @param string $fileName
+ * @param int $statusCode
+ * @throws \Exception
*/
public function postsACommentWithContentOnTheFileNamedItShouldReturn($user, $content, $fileName, $statusCode) {
$fileId = $this->getFileIdForPath($fileName);
@@ -123,6 +129,10 @@ class CommentsContext implements \Behat\Behat\Context\Context {
/**
* @Then As :user load all the comments of the file named :fileName it should return :statusCode
+ * @param string $user
+ * @param string $fileName
+ * @param int $statusCode
+ * @throws \Exception
*/
public function asLoadloadAllTheCommentsOfTheFileNamedItShouldReturn($user, $fileName, $statusCode) {
$fileId = $this->getFileIdForPath($fileName);
@@ -135,7 +145,7 @@ class CommentsContext implements \Behat\Behat\Context\Context {
$url,
[
'body' => '<?xml version="1.0" encoding="utf-8" ?>
-<oc:filter-comments xmlns:D="DAV:" xmlns:oc="http://owncloud.org/ns">
+<oc:filter-comments xmlns:oc="http://owncloud.org/ns">
<oc:limit>200</oc:limit>
<oc:offset>0</oc:offset>
</oc:filter-comments>
@@ -167,6 +177,11 @@ class CommentsContext implements \Behat\Behat\Context\Context {
/**
* @Given As :user sending :verb to :url with
+ * @param string $user
+ * @param string $verb
+ * @param string $url
+ * @param \Behat\Gherkin\Node\TableNode $body
+ * @throws \Exception
*/
public function asUserSendingToWith($user, $verb, $url, \Behat\Gherkin\Node\TableNode $body) {
$client = new \GuzzleHttp\Client();
@@ -179,6 +194,9 @@ class CommentsContext implements \Behat\Behat\Context\Context {
/**
* @Then As :user delete the created comment it should return :statusCode
+ * @param string $user
+ * @param int $statusCode
+ * @throws \Exception
*/
public function asDeleteTheCreatedCommentItShouldReturn($user, $statusCode) {
$url = $this->baseUrl.'/remote.php/dav/comments/files/'.$this->fileId.'/'.$this->commentId;
@@ -208,6 +226,9 @@ class CommentsContext implements \Behat\Behat\Context\Context {
/**
* @Then the response should contain a property :key with value :value
+ * @param string $key
+ * @param string $value
+ * @throws \Exception
*/
public function theResponseShouldContainAPropertyWithValue($key, $value) {
$keys = $this->response[0]['value'][2]['value'][0]['value'];
@@ -226,6 +247,8 @@ class CommentsContext implements \Behat\Behat\Context\Context {
/**
* @Then the response should contain only :number comments
+ * @param int $number
+ * @throws \Exception
*/
public function theResponseShouldContainOnlyComments($number) {
if(count($this->response) !== (int)$number) {
@@ -235,6 +258,10 @@ class CommentsContext implements \Behat\Behat\Context\Context {
/**
* @Then As :user edit the last created comment and set text to :text it should return :statusCode
+ * @param string $user
+ * @param string $text
+ * @param int $statusCode
+ * @throws \Exception
*/
public function asEditTheLastCreatedCommentAndSetTextToItShouldReturn($user, $text, $statusCode) {
$client = new \GuzzleHttp\Client();
diff --git a/build/integration/features/bootstrap/FeatureContext.php b/build/integration/features/bootstrap/FeatureContext.php
index 78ff4e7833d..21ca8d87295 100644
--- a/build/integration/features/bootstrap/FeatureContext.php
+++ b/build/integration/features/bootstrap/FeatureContext.php
@@ -2,8 +2,6 @@
use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;
-use GuzzleHttp\Client;
-use GuzzleHttp\Message\ResponseInterface;
require __DIR__ . '/../../vendor/autoload.php';
@@ -12,8 +10,5 @@ require __DIR__ . '/../../vendor/autoload.php';
* Features context.
*/
class FeatureContext implements Context, SnippetAcceptingContext {
- use BasicStructure;
- use Provisioning;
- use Sharing;
use WebDav;
}
diff --git a/build/integration/features/bootstrap/FederationContext.php b/build/integration/features/bootstrap/FederationContext.php
index 279b5206dee..55f3a55da0d 100644
--- a/build/integration/features/bootstrap/FederationContext.php
+++ b/build/integration/features/bootstrap/FederationContext.php
@@ -12,16 +12,43 @@ require __DIR__ . '/../../vendor/autoload.php';
*/
class FederationContext implements Context, SnippetAcceptingContext {
- use BasicStructure;
- use Provisioning;
- use Sharing;
+ use WebDav;
/**
- * @When /^User "([^"]*)" from server "([^"]*)" shares "([^"]*)" with user "([^"]*)" from server "([^"]*)"$/
+ * @Given /^User "([^"]*)" from server "(LOCAL|REMOTE)" shares "([^"]*)" with user "([^"]*)" from server "(LOCAL|REMOTE)"$/
+ *
+ * @param string $sharerUser
+ * @param string $sharerServer "LOCAL" or "REMOTE"
+ * @param string $sharerPath
+ * @param string $shareeUser
+ * @param string $shareeServer "LOCAL" or "REMOTE"
*/
- public function federateSharing($userLocal, $serverLocal, $pathLocal, $userRemote, $serverRemote){
- $shareWith = "$userRemote@" . substr($this->remoteBaseUrl, 0, -4);
- $this->createShare($userLocal, $pathLocal, 6, $shareWith, null, null, null);
+ public function federateSharing($sharerUser, $sharerServer, $sharerPath, $shareeUser, $shareeServer){
+ if ($shareeServer == "REMOTE"){
+ $shareWith = "$shareeUser@" . substr($this->remoteBaseUrl, 0, -4);
+ } else {
+ $shareWith = "$shareeUser@" . substr($this->localBaseUrl, 0, -4);
+ }
+ $previous = $this->usingServer($sharerServer);
+ $this->createShare($sharerUser, $sharerPath, 6, $shareWith, null, null, null);
+ $this->usingServer($previous);
}
+ /**
+ * @When /^User "([^"]*)" from server "(LOCAL|REMOTE)" accepts last pending share$/
+ * @param string $user
+ * @param string $server
+ */
+ public function acceptLastPendingShare($user, $server){
+ $previous = $this->usingServer($server);
+ $this->asAn($user);
+ $this->sendingToWith('GET', "/apps/files_sharing/api/v1/remote_shares/pending", null);
+ $this->theHTTPStatusCodeShouldBe('200');
+ $this->theOCSStatusCodeShouldBe('100');
+ $share_id = $this->response->xml()->data[0]->element[0]->id;
+ $this->sendingToWith('POST', "/apps/files_sharing/api/v1/remote_shares/pending/{$share_id}", null);
+ $this->theHTTPStatusCodeShouldBe('200');
+ $this->theOCSStatusCodeShouldBe('100');
+ $this->usingServer($previous);
+ }
}
diff --git a/build/integration/features/bootstrap/Provisioning.php b/build/integration/features/bootstrap/Provisioning.php
index 6d710b2016f..6cf57514483 100644
--- a/build/integration/features/bootstrap/Provisioning.php
+++ b/build/integration/features/bootstrap/Provisioning.php
@@ -1,16 +1,12 @@
<?php
-use Behat\Behat\Context\Context;
-use Behat\Behat\Context\SnippetAcceptingContext;
use GuzzleHttp\Client;
use GuzzleHttp\Message\ResponseInterface;
require __DIR__ . '/../../vendor/autoload.php';
trait Provisioning {
-
- /** @var int */
- private $apiVersion = 1;
+ use BasicStructure;
/** @var array */
private $createdUsers = [];
@@ -25,14 +21,8 @@ trait Provisioning {
private $createdGroups = [];
/**
- * @Given /^using api version "([^"]*)"$/
- */
- public function usingApiVersion($version) {
- $this->apiVersion = $version;
- }
-
- /**
* @Given /^user "([^"]*)" exists$/
+ * @param string $user
*/
public function assureUserExists($user) {
try {
@@ -45,11 +35,11 @@ trait Provisioning {
}
$this->userExists($user);
PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
-
}
/**
* @Given /^user "([^"]*)" does not exist$/
+ * @param string $user
*/
public function userDoesNotExist($user) {
try {
@@ -142,6 +132,8 @@ trait Provisioning {
/**
* @Then /^check that user "([^"]*)" belongs to group "([^"]*)"$/
+ * @param string $user
+ * @param string $group
*/
public function checkThatUserBelongsToGroup($user, $group) {
$fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups";
@@ -167,7 +159,6 @@ trait Provisioning {
}
$this->response = $client->get($fullUrl, $options);
- $groups = array($group);
$respondedArray = $this->getArrayOfGroupsResponded($this->response);
if (array_key_exists($group, $respondedArray)) {
@@ -179,20 +170,25 @@ trait Provisioning {
/**
* @Given /^user "([^"]*)" belongs to group "([^"]*)"$/
+ * @param string $user
+ * @param string $group
*/
public function assureUserBelongsToGroup($user, $group){
+ $previous_user = $this->currentUser;
+ $this->currentUser = "admin";
+
if (!$this->userBelongsToGroup($user, $group)){
- $previous_user = $this->currentUser;
- $this->currentUser = "admin";
$this->addingUserToGroup($user, $group);
- $this->currentUser = $previous_user;
}
- $this->checkThatUserBelongsToGroup($user, $group);
+ $this->checkThatUserBelongsToGroup($user, $group);
+ $this->currentUser = $previous_user;
}
/**
* @Given /^user "([^"]*)" does not belong to group "([^"]*)"$/
+ * @param string $user
+ * @param string $group
*/
public function userDoesNotBelongToGroup($user, $group) {
$fullUrl = $this->baseUrl . "v2.php/cloud/users/$user/groups";
@@ -209,8 +205,9 @@ trait Provisioning {
PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
}
- /**
+ /**
* @When /^creating the group "([^"]*)"$/
+ * @param string $group
*/
public function creatingTheGroup($group) {
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups";
@@ -233,7 +230,22 @@ trait Provisioning {
}
/**
+ * @When /^assure user "([^"]*)" is disabled$/
+ */
+ public function assureUserIsDisabled($user) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user/disable";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->send($client->createRequest("PUT", $fullUrl, $options));
+ }
+
+ /**
* @When /^Deleting the user "([^"]*)"$/
+ * @param string $user
*/
public function deletingTheUser($user) {
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user";
@@ -248,6 +260,7 @@ trait Provisioning {
/**
* @When /^Deleting the group "([^"]*)"$/
+ * @param string $group
*/
public function deletingTheGroup($group) {
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/groups/$group";
@@ -262,6 +275,8 @@ trait Provisioning {
/**
* @Given /^Add user "([^"]*)" to the group "([^"]*)"$/
+ * @param string $user
+ * @param string $group
*/
public function addUserToGroup($user, $group) {
$this->userExists($user);
@@ -272,6 +287,8 @@ trait Provisioning {
/**
* @When /^User "([^"]*)" is added to the group "([^"]*)"$/
+ * @param string $user
+ * @param string $group
*/
public function addingUserToGroup($user, $group) {
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user/groups";
@@ -300,6 +317,7 @@ trait Provisioning {
/**
* @Given /^group "([^"]*)" exists$/
+ * @param string $group
*/
public function assureGroupExists($group) {
try {
@@ -316,6 +334,7 @@ trait Provisioning {
/**
* @Given /^group "([^"]*)" does not exist$/
+ * @param string $group
*/
public function groupDoesNotExist($group) {
try {
@@ -339,6 +358,8 @@ trait Provisioning {
/**
* @Given /^user "([^"]*)" is subadmin of group "([^"]*)"$/
+ * @param string $user
+ * @param string $group
*/
public function userIsSubadminOfGroup($user, $group) {
$fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group/subadmins";
@@ -356,7 +377,28 @@ trait Provisioning {
}
/**
+ * @Given /^Assure user "([^"]*)" is subadmin of group "([^"]*)"$/
+ * @param string $user
+ * @param string $group
+ */
+ public function assureUserIsSubadminOfGroup($user, $group) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user/subadmins";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+ $options['body'] = [
+ 'groupid' => $group
+ ];
+ $this->response = $client->send($client->createRequest("POST", $fullUrl, $options));
+ PHPUnit_Framework_Assert::assertEquals(200, $this->response->getStatusCode());
+ }
+
+ /**
* @Given /^user "([^"]*)" is not a subadmin of group "([^"]*)"$/
+ * @param string $user
+ * @param string $group
*/
public function userIsNotSubadminOfGroup($user, $group) {
$fullUrl = $this->baseUrl . "v2.php/cloud/groups/$group/subadmins";
@@ -484,6 +526,7 @@ trait Provisioning {
/**
* @Given /^app "([^"]*)" is disabled$/
+ * @param string $app
*/
public function appIsDisabled($app) {
$fullUrl = $this->baseUrl . "v2.php/cloud/apps?filter=disabled";
@@ -501,6 +544,7 @@ trait Provisioning {
/**
* @Given /^app "([^"]*)" is enabled$/
+ * @param string $app
*/
public function appIsEnabled($app) {
$fullUrl = $this->baseUrl . "v2.php/cloud/apps?filter=enabled";
@@ -517,7 +561,41 @@ trait Provisioning {
}
/**
+ * @Then /^user "([^"]*)" is disabled$/
+ * @param string $user
+ */
+ public function userIsDisabled($user) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ PHPUnit_Framework_Assert::assertEquals("false", $this->response->xml()->data[0]->enabled);
+ }
+
+ /**
+ * @Then /^user "([^"]*)" is enabled$/
+ * @param string $user
+ */
+ public function userIsEnabled($user) {
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/cloud/users/$user";
+ $client = new Client();
+ $options = [];
+ if ($this->currentUser === 'admin') {
+ $options['auth'] = $this->adminUser;
+ }
+
+ $this->response = $client->get($fullUrl, $options);
+ PHPUnit_Framework_Assert::assertEquals("true", $this->response->xml()->data[0]->enabled);
+ }
+
+ /**
* @Given user :user has a quota of :quota
+ * @param string $user
+ * @param string $quota
*/
public function userHasAQuotaOf($user, $quota)
{
@@ -532,6 +610,7 @@ trait Provisioning {
/**
* @Given user :user has unlimited quota
+ * @param string $user
*/
public function userHasUnlimitedQuota($user)
{
@@ -573,4 +652,5 @@ trait Provisioning {
}
$this->usingServer($previousServer);
}
+
}
diff --git a/build/integration/features/bootstrap/ShareesContext.php b/build/integration/features/bootstrap/ShareesContext.php
new file mode 100644
index 00000000000..bd08ae6e138
--- /dev/null
+++ b/build/integration/features/bootstrap/ShareesContext.php
@@ -0,0 +1,73 @@
+<?php
+
+use Behat\Behat\Context\Context;
+use Behat\Behat\Context\SnippetAcceptingContext;
+use GuzzleHttp\Message\ResponseInterface;
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+
+/**
+ * Features context.
+ */
+class ShareesContext implements Context, SnippetAcceptingContext {
+ use Provisioning;
+ use AppConfiguration;
+
+ /**
+ * @When /^getting sharees for$/
+ * @param \Behat\Gherkin\Node\TableNode $body
+ */
+ public function whenGettingShareesFor($body) {
+ $url = '/apps/files_sharing/api/v1/sharees';
+ if ($body instanceof \Behat\Gherkin\Node\TableNode) {
+ $parameters = [];
+ foreach ($body->getRowsHash() as $key => $value) {
+ $parameters[] = $key . '=' . $value;
+ }
+ if (!empty($parameters)) {
+ $url .= '?' . implode('&', $parameters);
+ }
+ }
+
+ $this->sendingTo('GET', $url);
+ }
+
+ /**
+ * @Then /^"([^"]*)" sharees returned (are|is empty)$/
+ * @param string $shareeType
+ * @param string $isEmpty
+ * @param \Behat\Gherkin\Node\TableNode|null $shareesList
+ */
+ public function thenListOfSharees($shareeType, $isEmpty, $shareesList = null) {
+ if ($isEmpty !== 'is empty') {
+ $sharees = $shareesList->getRows();
+ $respondedArray = $this->getArrayOfShareesResponded($this->response, $shareeType);
+ PHPUnit_Framework_Assert::assertEquals($sharees, $respondedArray);
+ } else {
+ $respondedArray = $this->getArrayOfShareesResponded($this->response, $shareeType);
+ PHPUnit_Framework_Assert::assertEmpty($respondedArray);
+ }
+ }
+
+ public function getArrayOfShareesResponded(ResponseInterface $response, $shareeType) {
+ $elements = $response->xml()->data;
+ $elements = json_decode(json_encode($elements), 1);
+ if (strpos($shareeType, 'exact ') === 0) {
+ $elements = $elements['exact'];
+ $shareeType = substr($shareeType, 6);
+ }
+
+ $sharees = [];
+ foreach ($elements[$shareeType] as $element) {
+ $sharees[] = [$element['label'], $element['value']['shareType'], $element['value']['shareWith']];
+ }
+ return $sharees;
+ }
+
+ protected function resetAppConfigs() {
+ $this->modifyServerConfig('core', 'shareapi_only_share_with_group_members', 'no');
+ $this->modifyServerConfig('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes');
+ $this->modifyServerConfig('core', 'shareapi_allow_group_sharing', 'yes');
+ }
+}
diff --git a/build/integration/features/bootstrap/Sharing.php b/build/integration/features/bootstrap/Sharing.php
index 884d69597fc..2c8c1798250 100644
--- a/build/integration/features/bootstrap/Sharing.php
+++ b/build/integration/features/bootstrap/Sharing.php
@@ -1,7 +1,5 @@
<?php
-use Behat\Behat\Context\Context;
-use Behat\Behat\Context\SnippetAcceptingContext;
use GuzzleHttp\Client;
use GuzzleHttp\Message\ResponseInterface;
@@ -9,7 +7,8 @@ require __DIR__ . '/../../vendor/autoload.php';
-trait Sharing{
+trait Sharing {
+ use Provisioning;
/** @var int */
private $sharingApiVersion = 1;
@@ -22,10 +21,11 @@ trait Sharing{
/**
* @Given /^as "([^"]*)" creating a share with$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
+ * @param string $user
+ * @param \Behat\Gherkin\Node\TableNode|null $body
*/
public function asCreatingAShareWith($user, $body) {
- $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v1/shares";
+ $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares";
$client = new Client();
$options = [];
if ($user === 'admin') {
@@ -54,10 +54,10 @@ trait Sharing{
/**
* @When /^creating a share with$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
+ * @param \Behat\Gherkin\Node\TableNode|null $body
*/
public function creatingShare($body) {
- return $this->asCreatingAShareWith($this->currentUser, $body);
+ $this->asCreatingAShareWith($this->currentUser, $body);
}
/**
@@ -112,7 +112,7 @@ trait Sharing{
* @When /^Adding expiration date to last share$/
*/
public function addingExpirationDate() {
- $share_id = $this->lastShareData->data[0]->id;
+ $share_id = (string) $this->lastShareData->data[0]->id;
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
$client = new Client();
$options = [];
@@ -132,7 +132,7 @@ trait Sharing{
* @param \Behat\Gherkin\Node\TableNode|null $body
*/
public function updatingLastShare($body) {
- $share_id = $this->lastShareData->data[0]->id;
+ $share_id = (string) $this->lastShareData->data[0]->id;
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/$share_id";
$client = new Client();
$options = [];
@@ -225,6 +225,9 @@ trait Sharing{
elseif ((string)$element->$field == $contentExpected){
return True;
}
+ else{
+ print($element->$field);
+ }
}
return False;
@@ -247,6 +250,8 @@ trait Sharing{
/**
* @Then /^File "([^"]*)" should be included in the response$/
+ *
+ * @param string $filename
*/
public function checkSharedFileInResponse($filename){
PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse('file_target', "/$filename"));
@@ -254,6 +259,8 @@ trait Sharing{
/**
* @Then /^File "([^"]*)" should not be included in the response$/
+ *
+ * @param string $filename
*/
public function checkSharedFileNotInResponse($filename){
PHPUnit_Framework_Assert::assertEquals(False, $this->isFieldInResponse('file_target', "/$filename"));
@@ -261,6 +268,8 @@ trait Sharing{
/**
* @Then /^User "([^"]*)" should be included in the response$/
+ *
+ * @param string $user
*/
public function checkSharedUserInResponse($user){
PHPUnit_Framework_Assert::assertEquals(True, $this->isFieldInResponse('share_with', "$user"));
@@ -268,15 +277,17 @@ trait Sharing{
/**
* @Then /^User "([^"]*)" should not be included in the response$/
+ *
+ * @param string $user
*/
public function checkSharedUserNotInResponse($user){
PHPUnit_Framework_Assert::assertEquals(False, $this->isFieldInResponse('share_with', "$user"));
}
- public function isUserOrGroupInSharedData($userOrGroup){
+ public function isUserOrGroupInSharedData($userOrGroup, $permissions = null){
$data = $this->response->xml()->data[0];
foreach($data as $element) {
- if ($element->share_with == $userOrGroup){
+ if ($element->share_with == $userOrGroup && ($permissions === null || $permissions == $element->permissions)){
return True;
}
}
@@ -284,9 +295,13 @@ trait Sharing{
}
/**
- * @Given /^file "([^"]*)" of user "([^"]*)" is shared with user "([^"]*)"$/
+ * @Given /^(file|folder|entry) "([^"]*)" of user "([^"]*)" is shared with user "([^"]*)"( with permissions ([\d]*))?$/
+ *
+ * @param string $filepath
+ * @param string $user1
+ * @param string $user2
*/
- public function assureFileIsShared($filepath, $user1, $user2){
+ public function assureFileIsShared($entry, $filepath, $user1, $user2, $withPerms = null, $permissions = null){
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares" . "?path=$filepath";
$client = new Client();
$options = [];
@@ -296,19 +311,23 @@ trait Sharing{
$options['auth'] = [$user1, $this->regularUser];
}
$this->response = $client->get($fullUrl, $options);
- if ($this->isUserOrGroupInSharedData($user2)){
+ if ($this->isUserOrGroupInSharedData($user2, $permissions)){
return;
} else {
- $this->createShare($user1, $filepath, 0, $user2, null, null, null);
+ $this->createShare($user1, $filepath, 0, $user2, null, null, $permissions);
}
$this->response = $client->get($fullUrl, $options);
- PHPUnit_Framework_Assert::assertEquals(True, $this->isUserOrGroupInSharedData($user2));
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isUserOrGroupInSharedData($user2, $permissions));
}
/**
- * @Given /^file "([^"]*)" of user "([^"]*)" is shared with group "([^"]*)"$/
+ * @Given /^(file|folder|entry) "([^"]*)" of user "([^"]*)" is shared with group "([^"]*)"( with permissions ([\d]*))?$/
+ *
+ * @param string $filepath
+ * @param string $user
+ * @param string $group
*/
- public function assureFileIsSharedWithGroup($filepath, $user, $group){
+ public function assureFileIsSharedWithGroup($entry, $filepath, $user, $group, $withPerms = null, $permissions = null){
$fullUrl = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares" . "?path=$filepath";
$client = new Client();
$options = [];
@@ -318,13 +337,13 @@ trait Sharing{
$options['auth'] = [$user, $this->regularUser];
}
$this->response = $client->get($fullUrl, $options);
- if ($this->isUserOrGroupInSharedData($group)){
+ if ($this->isUserOrGroupInSharedData($group, $permissions)){
return;
} else {
- $this->createShare($user, $filepath, 1, $group, null, null, null);
+ $this->createShare($user, $filepath, 1, $group, null, null, $permissions);
}
$this->response = $client->get($fullUrl, $options);
- PHPUnit_Framework_Assert::assertEquals(True, $this->isUserOrGroupInSharedData($group));
+ PHPUnit_Framework_Assert::assertEquals(True, $this->isUserOrGroupInSharedData($group, $permissions));
}
/**
@@ -367,13 +386,21 @@ trait Sharing{
/**
* @Then /^Share fields of last share match with$/
- * @param \Behat\Gherkin\Node\TableNode|null $formData
+ * @param \Behat\Gherkin\Node\TableNode|null $body
*/
public function checkShareFields($body){
if ($body instanceof \Behat\Gherkin\Node\TableNode) {
$fd = $body->getRowsHash();
foreach($fd as $field => $value) {
+ if (substr($field, 0, 10 ) === "share_with"){
+ $value = str_replace("REMOTE", substr($this->remoteBaseUrl, 0, -5), $value);
+ $value = str_replace("LOCAL", substr($this->localBaseUrl, 0, -5), $value);
+ }
+ if (substr($field, 0, 6 ) === "remote"){
+ $value = str_replace("REMOTE", substr($this->remoteBaseUrl, 0, -4), $value);
+ $value = str_replace("LOCAL", substr($this->localBaseUrl, 0, -4), $value);
+ }
if (!$this->isFieldInResponse($field, $value)){
PHPUnit_Framework_Assert::fail("$field" . " doesn't have value " . "$value");
}
@@ -385,7 +412,7 @@ trait Sharing{
* @Then As :user remove all shares from the file named :fileName
*/
public function asRemoveAllSharesFromTheFileNamed($user, $fileName) {
- $url = $this->baseUrl.'v2.php/apps/files_sharing/api/v1/shares?format=json';
+ $url = $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares?format=json";
$client = new \GuzzleHttp\Client();
$res = $client->get(
$url,
@@ -405,7 +432,7 @@ trait Sharing{
if (stripslashes($data['path']) === $fileName) {
$id = $data['id'];
$client->delete(
- $this->baseUrl.'v2.php/apps/files_sharing/api/v1/shares/'.$id,
+ $this->baseUrl . "v{$this->apiVersion}.php/apps/files_sharing/api/v{$this->sharingApiVersion}/shares/{$id}",
[
'auth' => [
$user,
@@ -439,59 +466,8 @@ trait Sharing{
public function shareIdsShouldMatch()
{
if ($this->savedShareId !== $this->lastShareData['data']['id']) {
- throw new \Excetion('Expected the same link share to be returned');
- }
- }
-
- /**
- * @When /^getting sharees for$/
- * @param \Behat\Gherkin\Node\TableNode $body
- */
- public function whenGettingShareesFor($body) {
- $url = '/apps/files_sharing/api/v1/sharees';
- if ($body instanceof \Behat\Gherkin\Node\TableNode) {
- $parameters = [];
- foreach ($body->getRowsHash() as $key => $value) {
- $parameters[] = $key . '=' . $value;
- }
- if (!empty($parameters)) {
- $url .= '?' . implode('&', $parameters);
- }
- }
-
- $this->sendingTo('GET', $url);
- }
-
- /**
- * @Then /^"([^"]*)" sharees returned (are|is empty)$/
- * @param string $shareeType
- * @param string $isEmpty
- * @param \Behat\Gherkin\Node\TableNode|null $shareesList
- */
- public function thenListOfSharees($shareeType, $isEmpty, $shareesList = null) {
- if ($isEmpty !== 'is empty') {
- $sharees = $shareesList->getRows();
- $respondedArray = $this->getArrayOfShareesResponded($this->response, $shareeType);
- PHPUnit_Framework_Assert::assertEquals($sharees, $respondedArray);
- } else {
- $respondedArray = $this->getArrayOfShareesResponded($this->response, $shareeType);
- PHPUnit_Framework_Assert::assertEmpty($respondedArray);
- }
- }
-
- public function getArrayOfShareesResponded(ResponseInterface $response, $shareeType) {
- $elements = $response->xml()->data;
- $elements = json_decode(json_encode($elements), 1);
- if (strpos($shareeType, 'exact ') === 0) {
- $elements = $elements['exact'];
- $shareeType = substr($shareeType, 6);
- }
-
- $sharees = [];
- foreach ($elements[$shareeType] as $element) {
- $sharees[] = [$element['label'], $element['value']['shareType'], $element['value']['shareWith']];
+ throw new \Exception('Expected the same link share to be returned');
}
- return $sharees;
}
}
diff --git a/build/integration/features/bootstrap/TagsContext.php b/build/integration/features/bootstrap/TagsContext.php
index 5e1f62ba838..447f51e3781 100644
--- a/build/integration/features/bootstrap/TagsContext.php
+++ b/build/integration/features/bootstrap/TagsContext.php
@@ -97,24 +97,36 @@ class TagsContext implements \Behat\Behat\Context\Context {
}
/**
- * @When :user creates a :type tag with name :name
+ * @param string $user
+ * @param string $type
+ * @param string $name
+ * @param string $groups
*/
- public function createsATagWithName($user, $type, $name) {
- $userVisible = 'true';
- $userAssignable = 'true';
+ private function createTag($user, $type, $name, $groups = null) {
+ $userVisible = true;
+ $userAssignable = true;
switch ($type) {
case 'normal':
break;
case 'not user-assignable':
- $userAssignable = 'false';
+ $userAssignable = false;
break;
case 'not user-visible':
- $userVisible = 'false';
+ $userVisible = false;
break;
default:
throw new \Exception('Unsupported type');
}
+ $body = [
+ 'name' => $name,
+ 'userVisible' => $userVisible,
+ 'userAssignable' => $userAssignable,
+ ];
+ if ($groups !== null) {
+ $body['groups'] = $groups;
+ }
+
try {
$this->response = $this->client->post(
$this->baseUrl . '/remote.php/dav/systemtags/',
@@ -126,16 +138,41 @@ class TagsContext implements \Behat\Behat\Context\Context {
'headers' => [
'Content-Type' => 'application/json',
],
- 'body' => '{"name":"'.$name.'","userVisible":'.$userVisible.',"userAssignable":'.$userAssignable.'}',
+ 'body' => json_encode($body)
]
);
- } catch (\GuzzleHttp\Exception\ClientException $e){
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
$this->response = $e->getResponse();
}
}
/**
+ * @When :user creates a :type tag with name :name
+ * @param string $user
+ * @param string $type
+ * @param string $name
+ * @throws \Exception
+ */
+ public function createsATagWithName($user, $type, $name) {
+ $this->createTag($user, $type, $name);
+ }
+
+ /**
+ * @When :user creates a :type tag with name :name and groups :groups
+ * @param string $user
+ * @param string $type
+ * @param string $name
+ * @param string $groups
+ * @throws \Exception
+ */
+ public function createsATagWithNameAndGroups($user, $type, $name, $groups) {
+ $this->createTag($user, $type, $name, $groups);
+ }
+
+ /**
* @Then The response should have a status code :statusCode
+ * @param int $statusCode
+ * @throws \Exception
*/
public function theResponseShouldHaveAStatusCode($statusCode) {
if((int)$statusCode !== $this->response->getStatusCode()) {
@@ -149,21 +186,30 @@ class TagsContext implements \Behat\Behat\Context\Context {
* @param string $user
* @return array
*/
- private function requestTagsForUser($user) {
+ private function requestTagsForUser($user, $withGroups = false) {
try {
- $request = $this->client->createRequest(
- 'PROPFIND',
- $this->baseUrl . '/remote.php/dav/systemtags/',
- [
- 'body' => '<?xml version="1.0"?>
+ $body = '<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:id />
<oc:display-name />
<oc:user-visible />
- <oc:user-assignable />
+ <oc:user-assignable />
+ <oc:can-assign />
+';
+
+ if ($withGroups) {
+ $body .= '<oc:groups />';
+ }
+
+ $body .= '
</d:prop>
-</d:propfind>',
+</d:propfind>';
+ $request = $this->client->createRequest(
+ 'PROPFIND',
+ $this->baseUrl . '/remote.php/dav/systemtags/',
+ [
+ 'body' => $body,
'auth' => [
$user,
$this->getPasswordForUser($user),
@@ -187,11 +233,15 @@ class TagsContext implements \Behat\Behat\Context\Context {
continue;
}
+ // FIXME: use actual property names instead of guessing index position
$tags[$singleEntry[0]['value']] = [
'display-name' => $singleEntry[1]['value'],
'user-visible' => $singleEntry[2]['value'],
'user-assignable' => $singleEntry[3]['value'],
];
+ if (isset($singleEntry[5])) {
+ $tags[$singleEntry[0]['value']]['groups'] = $singleEntry[5]['value'];
+ }
}
return $tags;
@@ -199,6 +249,9 @@ class TagsContext implements \Behat\Behat\Context\Context {
/**
* @Then The following tags should exist for :user
+ * @param string $user
+ * @param TableNode $table
+ * @throws \Exception
*/
public function theFollowingTagsShouldExistFor($user, TableNode $table) {
$tags = $this->requestTagsForUser($user);
@@ -230,7 +283,24 @@ class TagsContext implements \Behat\Behat\Context\Context {
}
/**
+ * @Then The :type tag with name :tagName has the groups :groups
+ */
+ public function theTagHasGroup($type, $tagName, $groups) {
+ $foundTag = $this->findTag($type, $tagName, 'admin', true);
+ if ($foundTag === null) {
+ throw new \Exception('No matching tag found');
+ }
+
+ if ($foundTag['groups'] !== $groups) {
+ throw new \Exception('Tag has groups "' . $foundTag['group'] . '" instead of the expected "' . $groups . '"');
+ }
+ }
+
+ /**
* @Then :count tags should exist for :user
+ * @param int $count
+ * @param string $user
+ * @throws \Exception
*/
public function tagsShouldExistFor($count, $user) {
if((int)$count !== count($this->requestTagsForUser($user))) {
@@ -239,6 +309,45 @@ class TagsContext implements \Behat\Behat\Context\Context {
}
/**
+ * Find tag by type and name
+ *
+ * @param string $type tag type
+ * @param string $tagName tag name
+ * @param string $user retrieved from which user
+ * @param bool $withGroups whether to also query the tag's groups
+ *
+ * @return array tag values or null if not found
+ */
+ private function findTag($type, $tagName, $user = 'admin', $withGroups = false) {
+ $tags = $this->requestTagsForUser($user, $withGroups);
+ $userAssignable = 'true';
+ $userVisible = 'true';
+ switch ($type) {
+ case 'normal':
+ break;
+ case 'not user-assignable':
+ $userAssignable = 'false';
+ break;
+ case 'not user-visible':
+ $userVisible = 'false';
+ break;
+ default:
+ throw new \Exception('Unsupported type');
+ }
+
+ $foundTag = null;
+ foreach ($tags as $tag) {
+ if ($tag['display-name'] === $tagName
+ && $tag['user-visible'] === $userVisible
+ && $tag['user-assignable'] === $userAssignable) {
+ $foundTag = $tag;
+ break;
+ }
+ }
+ return $foundTag;
+ }
+
+ /**
* @param string $name
* @return int
*/
@@ -256,6 +365,10 @@ class TagsContext implements \Behat\Behat\Context\Context {
/**
* @When :user edits the tag with name :oldNmae and sets its name to :newName
+ * @param string $user
+ * @param string $oldName
+ * @param string $newName
+ * @throws \Exception
*/
public function editsTheTagWithNameAndSetsItsNameTo($user, $oldName, $newName) {
$tagId = $this->findTagIdByName($oldName);
@@ -289,7 +402,47 @@ class TagsContext implements \Behat\Behat\Context\Context {
}
/**
+ * @When :user edits the tag with name :oldNmae and sets its groups to :groups
+ * @param string $user
+ * @param string $oldName
+ * @param string $groups
+ * @throws \Exception
+ */
+ public function editsTheTagWithNameAndSetsItsGroupsTo($user, $oldName, $groups) {
+ $tagId = $this->findTagIdByName($oldName);
+ if($tagId === 0) {
+ throw new \Exception('Could not find tag to rename');
+ }
+
+ try {
+ $request = $this->client->createRequest(
+ 'PROPPATCH',
+ $this->baseUrl . '/remote.php/dav/systemtags/' . $tagId,
+ [
+ 'body' => '<?xml version="1.0"?>
+<d:propertyupdate xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
+ <d:set>
+ <d:prop>
+ <oc:groups>' . $groups . '</oc:groups>
+ </d:prop>
+ </d:set>
+</d:propertyupdate>',
+ 'auth' => [
+ $user,
+ $this->getPasswordForUser($user),
+ ],
+ ]
+ );
+ $this->response = $this->client->send($request);
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ $this->response = $e->getResponse();
+ }
+ }
+
+ /**
* @When :user deletes the tag with name :name
+ * @param string $user
+ * @param string $name
*/
public function deletesTheTagWithName($user, $name) {
$tagId = $this->findTagIdByName($name);
@@ -338,6 +491,10 @@ class TagsContext implements \Behat\Behat\Context\Context {
/**
* @When :taggingUser adds the tag :tagName to :fileName shared by :sharingUser
+ * @param string $taggingUser
+ * @param string $tagName
+ * @param string $fileName
+ * @param string $sharingUser
*/
public function addsTheTagToSharedBy($taggingUser, $tagName, $fileName, $sharingUser) {
$fileId = $this->getFileIdForPath($fileName, $sharingUser);
@@ -360,6 +517,10 @@ class TagsContext implements \Behat\Behat\Context\Context {
/**
* @Then :fileName shared by :sharingUser has the following tags
+ * @param string $fileName
+ * @param string $sharingUser
+ * @param TableNode $table
+ * @throws \Exception
*/
public function sharedByHasTheFollowingTags($fileName, $sharingUser, TableNode $table) {
$loadedExpectedTags = $table->getTable();
@@ -406,6 +567,11 @@ class TagsContext implements \Behat\Behat\Context\Context {
/**
* @Then :fileName shared by :sharingUser has the following tags for :user
+ * @param string $fileName
+ * @param string $sharingUser
+ * @param string $user
+ * @param TableNode $table
+ * @throws \Exception
*/
public function sharedByHasTheFollowingTagsFor($fileName, $sharingUser, $user, TableNode $table) {
$loadedExpectedTags = $table->getTable();
@@ -460,6 +626,10 @@ class TagsContext implements \Behat\Behat\Context\Context {
/**
* @When :user removes the tag :tagName from :fileName shared by :shareUser
+ * @param string $user
+ * @param string $tagName
+ * @param string $fileName
+ * @param string $shareUser
*/
public function removesTheTagFromSharedBy($user, $tagName, $fileName, $shareUser) {
$tagId = $this->findTagIdByName($tagName);
diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php
index f7861399d76..092c79fe020 100644
--- a/build/integration/features/bootstrap/WebDav.php
+++ b/build/integration/features/bootstrap/WebDav.php
@@ -1,7 +1,5 @@
<?php
-use Behat\Behat\Context\Context;
-use Behat\Behat\Context\SnippetAcceptingContext;
use GuzzleHttp\Client as GClient;
use GuzzleHttp\Message\ResponseInterface;
use Sabre\DAV\Client as SClient;
@@ -10,6 +8,8 @@ require __DIR__ . '/../../vendor/autoload.php';
trait WebDav {
+ use Sharing;
+
/** @var string*/
private $davPath = "remote.php/webdav";
/** @var ResponseInterface */
@@ -46,9 +46,12 @@ trait WebDav {
}
/**
- * @Given /^User "([^"]*)" moved file "([^"]*)" to "([^"]*)"$/
+ * @Given /^User "([^"]*)" moved (file|folder|entry) "([^"]*)" to "([^"]*)"$/
+ * @param string $user
+ * @param string $fileSource
+ * @param string $fileDestination
*/
- public function userMovedFile($user, $fileSource, $fileDestination){
+ public function userMovedFile($user, $entry, $fileSource, $fileDestination){
$fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath;
$headers['Destination'] = $fullUrl . $fileDestination;
$this->response = $this->makeDavRequest($user, "MOVE", $fileSource, $headers);
@@ -56,9 +59,12 @@ trait WebDav {
}
/**
- * @When /^User "([^"]*)" moves file "([^"]*)" to "([^"]*)"$/
+ * @When /^User "([^"]*)" moves (file|folder|entry) "([^"]*)" to "([^"]*)"$/
+ * @param string $user
+ * @param string $fileSource
+ * @param string $fileDestination
*/
- public function userMovesFile($user, $fileSource, $fileDestination){
+ public function userMovesFile($user, $entry, $fileSource, $fileDestination){
$fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath;
$headers['Destination'] = $fullUrl . $fileDestination;
try {
@@ -86,15 +92,17 @@ trait WebDav {
/**
* @When /^Downloading file "([^"]*)" with range "([^"]*)"$/
+ * @param string $fileSource
+ * @param string $range
*/
public function downloadFileWithRange($fileSource, $range){
- $fullUrl = substr($this->baseUrl, 0, -4) . $this->davPath;
$headers['Range'] = $range;
$this->response = $this->makeDavRequest($this->currentUser, "GET", $fileSource, $headers);
}
/**
* @When /^Downloading last public shared file with range "([^"]*)"$/
+ * @param string $range
*/
public function downloadPublicFileWithRange($range){
$token = $this->lastShareData->data->token;
@@ -112,7 +120,27 @@ trait WebDav {
}
/**
+ * @When /^Downloading last public shared file inside a folder "([^"]*)" with range "([^"]*)"$/
+ * @param string $range
+ */
+ public function downloadPublicFileInsideAFolderWithRange($path, $range){
+ $token = $this->lastShareData->data->token;
+ $fullUrl = substr($this->baseUrl, 0, -4) . "public.php/webdav" . "$path";
+ $headers['Range'] = $range;
+
+ $client = new GClient();
+ $options = [];
+ $options['auth'] = [$token, ""];
+
+ $request = $client->createRequest("GET", $fullUrl, $options);
+ $request->addHeader('Range', $range);
+
+ $this->response = $client->send($request);
+ }
+
+ /**
* @Then /^Downloaded content should be "([^"]*)"$/
+ * @param string $content
*/
public function downloadedContentShouldBe($content){
PHPUnit_Framework_Assert::assertEquals($content, (string)$this->response->getBody());
@@ -120,6 +148,9 @@ trait WebDav {
/**
* @Then /^Downloaded content when downloading file "([^"]*)" with range "([^"]*)" should be "([^"]*)"$/
+ * @param string $fileSource
+ * @param string $range
+ * @param string $content
*/
public function downloadedContentWhenDownloadindShouldBe($fileSource, $range, $content){
$this->downloadFileWithRange($fileSource, $range);
@@ -128,6 +159,7 @@ trait WebDav {
/**
* @When Downloading file :fileName
+ * @param string $fileName
*/
public function downloadingFile($fileName) {
try {
@@ -139,6 +171,8 @@ trait WebDav {
/**
* @Then The following headers should be set
+ * @param \Behat\Gherkin\Node\TableNode $table
+ * @throws \Exception
*/
public function theFollowingHeadersShouldBeSet(\Behat\Gherkin\Node\TableNode $table) {
foreach($table->getTable() as $header) {
@@ -160,6 +194,8 @@ trait WebDav {
/**
* @Then Downloaded content should start with :start
+ * @param int $start
+ * @throws \Exception
*/
public function downloadedContentShouldStartWith($start) {
if(strpos($this->response->getBody()->getContents(), $start) !== 0) {
@@ -175,6 +211,8 @@ trait WebDav {
/**
* @Then /^as "([^"]*)" gets properties of folder "([^"]*)" with$/
+ * @param string $user
+ * @param string $path
* @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
*/
public function asGetsPropertiesOfFolderWith($user, $path, $propertiesTable) {
@@ -188,7 +226,36 @@ trait WebDav {
}
/**
+ * @Then /^as "([^"]*)" the (file|folder|entry) "([^"]*)" does not exist$/
+ * @param string $user
+ * @param string $path
+ * @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
+ */
+ public function asTheFileOrFolderDoesNotExist($user, $entry, $path) {
+ $client = $this->getSabreClient($user);
+ $response = $client->request('HEAD', $this->makeSabrePath($path));
+ if ($response['statusCode'] !== 404) {
+ throw new \Exception($entry . ' "' . $path . '" expected to not exist (status code ' . $response['statusCode'] . ', expected 404)');
+ }
+
+ return $response;
+ }
+
+ /**
+ * @Then /^as "([^"]*)" the (file|folder|entry) "([^"]*)" exists$/
+ * @param string $user
+ * @param string $path
+ * @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
+ */
+ public function asTheFileOrFolderExists($user, $entry, $path) {
+ $this->response = $this->listFolder($user, $path, 0);
+ }
+
+ /**
* @Then the single response should contain a property :key with value :value
+ * @param string $key
+ * @param string $expectedValue
+ * @throws \Exception
*/
public function theSingleResponseShouldContainAPropertyWithValue($key, $expectedValue) {
$keys = $this->response;
@@ -197,7 +264,7 @@ trait WebDav {
}
$value = $keys[$key];
- if ($value !== $expectedValue) {
+ if ($value != $expectedValue) {
throw new \Exception("Property \"$key\" found with value \"$value\", expected \"$expectedValue\"");
}
}
@@ -252,9 +319,25 @@ trait WebDav {
}
}
-
/*Returns the elements of a propfind, $folderDepth requires 1 to see elements without children*/
public function listFolder($user, $path, $folderDepth, $properties = null){
+ $client = $this->getSabreClient($user);
+ if (!$properties) {
+ $properties = [
+ '{DAV:}getetag'
+ ];
+ }
+
+ $response = $client->propfind($this->makeSabrePath($path), $properties, $folderDepth);
+
+ return $response;
+ }
+
+ public function makeSabrePath($path) {
+ return $this->encodePath($this->davPath . '/' . ltrim($path, '/'));
+ }
+
+ public function getSabreClient($user) {
$fullUrl = substr($this->baseUrl, 0, -4);
$settings = array(
@@ -268,21 +351,12 @@ trait WebDav {
$settings['password'] = $this->regularUser;
}
- $client = new SClient($settings);
-
- if (!$properties) {
- $properties = [
- '{DAV:}getetag'
- ];
- }
-
- $response = $client->propfind($this->davPath . '/' . ltrim($path, '/'), $properties, $folderDepth);
-
- return $response;
+ return new SClient($settings);
}
/**
* @Then /^user "([^"]*)" should see following elements$/
+ * @param string $user
* @param \Behat\Gherkin\Node\TableNode|null $expectedElements
*/
public function checkElementList($user, $expectedElements){
@@ -301,6 +375,9 @@ trait WebDav {
/**
* @When User :user uploads file :source to :destination
+ * @param string $user
+ * @param string $source
+ * @param string $destination
*/
public function userUploadsAFileTo($user, $source, $destination)
{
@@ -314,7 +391,23 @@ trait WebDav {
}
/**
+ * @When User :user uploads file with content :content to :destination
+ */
+ public function userUploadsAFileWithContentTo($user, $content, $destination)
+ {
+ $file = \GuzzleHttp\Stream\Stream::factory($content);
+ try {
+ $this->response = $this->makeDavRequest($user, "PUT", $destination, [], $file);
+ } catch (\GuzzleHttp\Exception\ServerException $e) {
+ // 4xx and 5xx responses cause an exception
+ $this->response = $e->getResponse();
+ }
+ }
+
+ /**
* @When User :user deletes file :file
+ * @param string $user
+ * @param string $file
*/
public function userDeletesFile($user, $file) {
try {
@@ -327,10 +420,12 @@ trait WebDav {
/**
* @Given User :user created a folder :destination
+ * @param string $user
+ * @param string $destination
*/
public function userCreatedAFolder($user, $destination){
try {
- $this->response = $this->makeDavRequest($user, "MKCOL", $destination, []);
+ $this->response = $this->makeDavRequest($user, "MKCOL", '/' . ltrim($destination, '/'), []);
} catch (\GuzzleHttp\Exception\ServerException $e) {
// 4xx and 5xx responses cause an exception
$this->response = $e->getResponse();
@@ -339,6 +434,11 @@ trait WebDav {
/**
* @Given user :user uploads chunk file :num of :total with :data to :destination
+ * @param string $user
+ * @param int $num
+ * @param int $total
+ * @param string $data
+ * @param string $destination
*/
public function userUploadsChunkFileOfWithToWithChecksum($user, $num, $total, $data, $destination)
{
@@ -348,5 +448,104 @@ trait WebDav {
$this->makeDavRequest($user, 'PUT', $file, ['OC-Chunked' => '1'], $data);
}
-}
+ /**
+ * @Given user :user creates a new chunking upload with id :id
+ */
+ public function userCreatesANewChunkingUploadWithId($user, $id)
+ {
+ $destination = '/uploads/'.$user.'/'.$id;
+ $this->makeDavRequest($user, 'MKCOL', $destination, []);
+ }
+
+ /**
+ * @Given user :user uploads new chunk file :num with :data to id :id
+ */
+ public function userUploadsNewChunkFileOfWithToId($user, $num, $data, $id)
+ {
+ $data = \GuzzleHttp\Stream\Stream::factory($data);
+ $destination = '/uploads/'.$user.'/'.$id.'/'.$num;
+ $this->makeDavRequest($user, 'PUT', $destination, [], $data);
+ }
+
+ /**
+ * @Given user :user moves new chunk file with id :id to :dest
+ */
+ public function userMovesNewChunkFileWithIdToMychunkedfile($user, $id, $dest)
+ {
+ $source = '/uploads/'.$user.'/'.$id.'/.file';
+ $destination = substr($this->baseUrl, 0, -4) . $this->davPath . '/files/'.$user.$dest;
+ $this->makeDavRequest($user, 'MOVE', $source, [
+ 'Destination' => $destination
+ ]);
+ }
+
+ /**
+ * @Given /^Downloading file "([^"]*)" as "([^"]*)"$/
+ */
+ public function downloadingFileAs($fileName, $user) {
+ try {
+ $this->response = $this->makeDavRequest($user, 'GET', $fileName, []);
+ } catch (\GuzzleHttp\Exception\ServerException $ex) {
+ $this->response = $ex->getResponse();
+ }
+ }
+
+ /**
+ * URL encodes the given path but keeps the slashes
+ *
+ * @param string $path to encode
+ * @return string encoded path
+ */
+ private function encodePath($path) {
+ // slashes need to stay
+ return str_replace('%2F', '/', rawurlencode($path));
+ }
+
+ /**
+ * @When user :user favorites element :path
+ */
+ public function userFavoritesElement($user, $path){
+ $this->response = $this->changeFavStateOfAnElement($user, $path, 1, 0, null);
+ }
+
+ /**
+ * @When user :user unfavorites element :path
+ */
+ public function userUnfavoritesElement($user, $path){
+ $this->response = $this->changeFavStateOfAnElement($user, $path, 0, 0, null);
+ }
+
+ /*Set the elements of a proppatch, $folderDepth requires 1 to see elements without children*/
+ public function changeFavStateOfAnElement($user, $path, $favOrUnfav, $folderDepth, $properties = null){
+ $fullUrl = substr($this->baseUrl, 0, -4);
+ $settings = array(
+ 'baseUri' => $fullUrl,
+ 'userName' => $user,
+ );
+ if ($user === 'admin') {
+ $settings['password'] = $this->adminUser[1];
+ } else {
+ $settings['password'] = $this->regularUser;
+ }
+ $client = new SClient($settings);
+ if (!$properties) {
+ $properties = [
+ '{http://owncloud.org/ns}favorite' => $favOrUnfav
+ ];
+ }
+
+ $response = $client->proppatch($this->davPath . '/' . ltrim($path, '/'), $properties, $folderDepth);
+ return $response;
+ }
+
+ /**
+ * @Then /^as "([^"]*)" gets properties of file "([^"]*)" with$/
+ * @param string $user
+ * @param string $path
+ * @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
+ */
+ public function asGetsPropertiesOfFileWith($user, $path, $propertiesTable) {
+ $this->asGetsPropertiesOfFolderWith($user, $path, $propertiesTable);
+ }
+}
diff --git a/build/integration/features/dav-v2.feature b/build/integration/features/dav-v2.feature
new file mode 100644
index 00000000000..9de78a7ed16
--- /dev/null
+++ b/build/integration/features/dav-v2.feature
@@ -0,0 +1,55 @@
+Feature: dav-v2
+ Background:
+ Given using api version "1"
+
+ Scenario: moving a file new endpoint way
+ Given using dav path "remote.php/dav"
+ And As an "admin"
+ And user "user0" exists
+ When User "user0" moves file "/files/user0/textfile0.txt" to "/files/user0/abcde.txt"
+ Then the HTTP status code should be "201"
+
+ Scenario: download a file with range using new endpoint
+ Given using dav path "remote.php/dav"
+ And As an "admin"
+ And user "user0" exists
+ And As an "user0"
+ When Downloading file "/files/user0/welcome.txt" with range "bytes=51-77"
+ Then Downloaded content should be "example file for developers"
+
+ Scenario: Downloading a file on the new endpoint should serve security headers
+ Given using dav path "remote.php/dav/files/admin/"
+ And As an "admin"
+ When Downloading file "welcome.txt"
+ Then The following headers should be set
+ |Content-Disposition|attachment; filename*=UTF-8''welcome.txt; filename="welcome.txt"|
+ |Content-Security-Policy|default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src * data: blob:; font-src 'self' data:; media-src *; connect-src *|
+ |X-Content-Type-Options |nosniff|
+ |X-Download-Options|noopen|
+ |X-Frame-Options|Sameorigin|
+ |X-Permitted-Cross-Domain-Policies|none|
+ |X-Robots-Tag|none|
+ |X-XSS-Protection|1; mode=block|
+ And Downloaded content should start with "Welcome to your ownCloud account!"
+
+ Scenario: Doing a GET with a web login should work without CSRF token on the new backend
+ Given Logging in using web as "admin"
+ When Sending a "GET" to "/remote.php/dav/files/admin/welcome.txt" without requesttoken
+ Then Downloaded content should start with "Welcome to your ownCloud account!"
+ Then the HTTP status code should be "200"
+
+ Scenario: Doing a GET with a web login should work with CSRF token on the new backend
+ Given Logging in using web as "admin"
+ When Sending a "GET" to "/remote.php/dav/files/admin/welcome.txt" with requesttoken
+ Then Downloaded content should start with "Welcome to your ownCloud account!"
+ Then the HTTP status code should be "200"
+
+ Scenario: Doing a PROPFIND with a web login should not work without CSRF token on the new backend
+ Given Logging in using web as "admin"
+ When Sending a "PROPFIND" to "/remote.php/dav/files/admin/welcome.txt" without requesttoken
+ Then the HTTP status code should be "401"
+
+ Scenario: Doing a PROPFIND with a web login should work with CSRF token on the new backend
+ Given Logging in using web as "admin"
+ When Sending a "PROPFIND" to "/remote.php/dav/files/admin/welcome.txt" with requesttoken
+ Then the HTTP status code should be "207"
diff --git a/build/integration/features/favorites.feature b/build/integration/features/favorites.feature
new file mode 100644
index 00000000000..86643fdd1e2
--- /dev/null
+++ b/build/integration/features/favorites.feature
@@ -0,0 +1,42 @@
+Feature: favorite
+ Background:
+ Given using api version "1"
+
+ Scenario: Favorite a folder
+ Given using dav path "remote.php/webdav"
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/FOLDER"
+ Then as "user0" gets properties of folder "/FOLDER" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "1"
+
+ Scenario: Favorite and unfavorite a folder
+ Given using dav path "remote.php/webdav"
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/FOLDER"
+ And user "user0" unfavorites element "/FOLDER"
+ Then as "user0" gets properties of folder "/FOLDER" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value ""
+
+ Scenario: Favorite a file
+ Given using dav path "remote.php/webdav"
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/textfile0.txt"
+ Then as "user0" gets properties of file "/textfile0.txt" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value "1"
+
+ Scenario: Favorite and unfavorite a file
+ Given using dav path "remote.php/webdav"
+ And As an "admin"
+ And user "user0" exists
+ When user "user0" favorites element "/textfile0.txt"
+ And user "user0" unfavorites element "/textfile0.txt"
+ Then as "user0" gets properties of file "/textfile0.txt" with
+ |{http://owncloud.org/ns}favorite|
+ And the single response should contain a property "{http://owncloud.org/ns}favorite" with value ""
+
diff --git a/build/integration/features/provisioning-v1.feature b/build/integration/features/provisioning-v1.feature
index 8c32c04523c..625d24260de 100644
--- a/build/integration/features/provisioning-v1.feature
+++ b/build/integration/features/provisioning-v1.feature
@@ -315,3 +315,20 @@ Feature: provisioning
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And app "files_external" is disabled
+
+ Scenario: Making a web request with an enabled user
+ Given As an "admin"
+ And user "user0" exists
+ And As an "user0"
+ When sending "GET" to "/index.php/apps/files"
+ Then the HTTP status code should be "200"
+
+ Scenario: Making a web request with a disabled user
+ Given As an "admin"
+ And user "user0" exists
+ And assure user "user0" is disabled
+ And As an "user0"
+ When sending "GET" to "/index.php/apps/files"
+ Then the OCS status code should be "999"
+ And the HTTP status code should be "200"
+
diff --git a/build/integration/features/sharees.feature b/build/integration/features/sharees.feature
deleted file mode 100644
index ea3a2c9bcea..00000000000
--- a/build/integration/features/sharees.feature
+++ /dev/null
@@ -1,148 +0,0 @@
-Feature: sharees
- Background:
- Given using api version "1"
-
- Scenario: Search without exact match
- Given user "test" exists
- And user "Sharee1" exists
- And group "ShareeGroup" exists
- And As an "test"
- When getting sharees for
- | search | Sharee |
- | itemType | file |
- Then the OCS status code should be "100"
- And the HTTP status code should be "200"
- And "exact users" sharees returned is empty
- And "users" sharees returned are
- | Sharee1 | 0 | Sharee1 |
- And "exact groups" sharees returned is empty
- And "groups" sharees returned are
- | ShareeGroup | 1 | ShareeGroup |
- And "exact remotes" sharees returned is empty
- And "remotes" sharees returned is empty
-
- Scenario: Search without exact match not-exact casing
- Given user "test" exists
- And user "Sharee1" exists
- And group "ShareeGroup" exists
- And As an "test"
- When getting sharees for
- | search | sharee |
- | itemType | file |
- Then the OCS status code should be "100"
- And the HTTP status code should be "200"
- And "exact users" sharees returned is empty
- And "users" sharees returned are
- | Sharee1 | 0 | Sharee1 |
- And "exact groups" sharees returned is empty
- And "groups" sharees returned are
- | ShareeGroup | 1 | ShareeGroup |
- And "exact remotes" sharees returned is empty
- And "remotes" sharees returned is empty
-
- Scenario: Search with exact match
- Given user "test" exists
- And user "Sharee1" exists
- And group "ShareeGroup" exists
- And As an "test"
- When getting sharees for
- | search | Sharee1 |
- | itemType | file |
- Then the OCS status code should be "100"
- And the HTTP status code should be "200"
- Then "exact users" sharees returned are
- | Sharee1 | 0 | Sharee1 |
- Then "users" sharees returned is empty
- Then "exact groups" sharees returned is empty
- Then "groups" sharees returned is empty
- Then "exact remotes" sharees returned is empty
- Then "remotes" sharees returned is empty
-
- Scenario: Search with exact match not-exact casing
- Given user "test" exists
- And user "Sharee1" exists
- And group "ShareeGroup" exists
- And As an "test"
- When getting sharees for
- | search | sharee1 |
- | itemType | file |
- Then the OCS status code should be "100"
- And the HTTP status code should be "200"
- Then "exact users" sharees returned are
- | Sharee1 | 0 | Sharee1 |
- Then "users" sharees returned is empty
- Then "exact groups" sharees returned is empty
- Then "groups" sharees returned is empty
- Then "exact remotes" sharees returned is empty
- Then "remotes" sharees returned is empty
-
- Scenario: Search with exact match not-exact casing group
- Given user "test" exists
- And user "Sharee1" exists
- And group "ShareeGroup" exists
- And As an "test"
- When getting sharees for
- | search | shareegroup |
- | itemType | file |
- Then the OCS status code should be "100"
- And the HTTP status code should be "200"
- Then "exact users" sharees returned is empty
- Then "users" sharees returned is empty
- Then "exact groups" sharees returned are
- | ShareeGroup | 1 | ShareeGroup |
- Then "groups" sharees returned is empty
- Then "exact remotes" sharees returned is empty
- Then "remotes" sharees returned is empty
-
- Scenario: Search with "self"
- Given user "test" exists
- And user "Sharee1" exists
- And group "ShareeGroup" exists
- And As an "Sharee1"
- When getting sharees for
- | search | Sharee1 |
- | itemType | file |
- Then the OCS status code should be "100"
- And the HTTP status code should be "200"
- Then "exact users" sharees returned are
- | Sharee1 | 0 | Sharee1 |
- Then "users" sharees returned is empty
- Then "exact groups" sharees returned is empty
- Then "groups" sharees returned is empty
- Then "exact remotes" sharees returned is empty
- Then "remotes" sharees returned is empty
-
- Scenario: Remote sharee for files
- Given user "test" exists
- And user "Sharee1" exists
- And group "ShareeGroup" exists
- And As an "test"
- When getting sharees for
- | search | test@localhost |
- | itemType | file |
- Then the OCS status code should be "100"
- And the HTTP status code should be "200"
- Then "exact users" sharees returned is empty
- Then "users" sharees returned is empty
- Then "exact groups" sharees returned is empty
- Then "groups" sharees returned is empty
- Then "exact remotes" sharees returned are
- | test@localhost | 6 | test@localhost |
- Then "remotes" sharees returned is empty
-
- Scenario: Remote sharee for calendars not allowed
- Given user "test" exists
- And user "Sharee1" exists
- And group "ShareeGroup" exists
- And As an "test"
- When getting sharees for
- | search | test@localhost |
- | itemType | calendar |
- Then the OCS status code should be "100"
- And the HTTP status code should be "200"
- Then "exact users" sharees returned is empty
- Then "users" sharees returned is empty
- Then "exact groups" sharees returned is empty
- Then "groups" sharees returned is empty
- Then "exact remotes" sharees returned is empty
- Then "remotes" sharees returned is empty
diff --git a/build/integration/features/sharing-v1.feature b/build/integration/features/sharing-v1.feature
index ed8f3b23f25..da6ab1d71d3 100644
--- a/build/integration/features/sharing-v1.feature
+++ b/build/integration/features/sharing-v1.feature
@@ -266,6 +266,20 @@ Feature: sharing
And User "user2" should be included in the response
And User "user3" should not be included in the response
+ Scenario: Reshared files can be still accessed if a user in the middle removes it.
+ Given user "user0" exists
+ And user "user1" exists
+ And user "user2" exists
+ And user "user3" exists
+ And file "textfile0.txt" of user "user0" is shared with user "user1"
+ And file "textfile0 (2).txt" of user "user1" is shared with user "user2"
+ And file "textfile0 (2).txt" of user "user2" is shared with user "user3"
+ And As an "user1"
+ When User "user1" deletes file "/textfile0 (2).txt"
+ And As an "user3"
+ And Downloading file "/textfile0 (2).txt" with range "bytes=1-7"
+ Then Downloaded content should be "wnCloud"
+
Scenario: getting share info of a share
Given user "user0" exists
And user "user1" exists
@@ -582,7 +596,7 @@ Feature: sharing
| shareType | 3 |
Then share ids should match
- Scenario: unique target names for incomming shares
+ Scenario: unique target names for incoming shares
Given user "user0" exists
And user "user1" exists
And user "user2" exists
diff --git a/build/integration/features/tags.feature b/build/integration/features/tags.feature
index 286fb62bf42..e2acadbe541 100644
--- a/build/integration/features/tags.feature
+++ b/build/integration/features/tags.feature
@@ -368,3 +368,4 @@ Feature: tags
And "/myFileToTag.txt" shared by "user0" has the following tags for "user1"
||
And The response should have a status code "404"
+
diff --git a/build/integration/features/webdav-related.feature b/build/integration/features/webdav-related.feature
index f0712751b7f..d19fd4988d4 100644
--- a/build/integration/features/webdav-related.feature
+++ b/build/integration/features/webdav-related.feature
@@ -169,6 +169,15 @@ Feature: webdav-related
And Downloading last public shared file with range "bytes=51-77"
Then Downloaded content should be "example file for developers"
+ Scenario: download a public shared file inside a folder with range
+ Given user "user0" exists
+ And As an "user0"
+ When creating a share with
+ | path | PARENT |
+ | shareType | 3 |
+ And Downloading last public shared file inside a folder "/parent.txt" with range "bytes=1-7"
+ Then Downloaded content should be "wnCloud"
+
Scenario: Downloading a file on the old endpoint should serve security headers
Given using dav path "remote.php/webdav"
And As an "admin"
@@ -184,43 +193,6 @@ Feature: webdav-related
|X-XSS-Protection|1; mode=block|
And Downloaded content should start with "Welcome to your ownCloud account!"
- Scenario: Downloading a file on the new endpoint should serve security headers
- Given using dav path "remote.php/dav/files/admin/"
- And As an "admin"
- When Downloading file "/welcome.txt"
- Then The following headers should be set
- |Content-Disposition|attachment; filename*=UTF-8''welcome.txt; filename="welcome.txt"|
- |Content-Security-Policy|default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src * data: blob:; font-src 'self' data:; media-src *; connect-src *|
- |X-Content-Type-Options |nosniff|
- |X-Download-Options|noopen|
- |X-Frame-Options|Sameorigin|
- |X-Permitted-Cross-Domain-Policies|none|
- |X-Robots-Tag|none|
- |X-XSS-Protection|1; mode=block|
- And Downloaded content should start with "Welcome to your ownCloud account!"
-
- Scenario: Doing a GET with a web login should work without CSRF token on the new backend
- Given Logging in using web as "admin"
- When Sending a "GET" to "/remote.php/dav/files/admin/welcome.txt" without requesttoken
- Then Downloaded content should start with "Welcome to your ownCloud account!"
- Then the HTTP status code should be "200"
-
- Scenario: Doing a GET with a web login should work with CSRF token on the new backend
- Given Logging in using web as "admin"
- When Sending a "GET" to "/remote.php/dav/files/admin/welcome.txt" with requesttoken
- Then Downloaded content should start with "Welcome to your ownCloud account!"
- Then the HTTP status code should be "200"
-
- Scenario: Doing a PROPFIND with a web login should not work without CSRF token on the new backend
- Given Logging in using web as "admin"
- When Sending a "PROPFIND" to "/remote.php/dav/files/admin/welcome.txt" without requesttoken
- Then the HTTP status code should be "401"
-
- Scenario: Doing a PROPFIND with a web login should work with CSRF token on the new backend
- Given Logging in using web as "admin"
- When Sending a "PROPFIND" to "/remote.php/dav/files/admin/welcome.txt" with requesttoken
- Then the HTTP status code should be "207"
-
Scenario: Doing a GET with a web login should work without CSRF token on the old backend
Given Logging in using web as "admin"
When Sending a "GET" to "/remote.php/webdav/welcome.txt" without requesttoken
@@ -342,3 +314,4 @@ Feature: webdav-related
| 0 |
| 1 |
| 3 |
+
diff --git a/build/integration/federation_features/federated.feature b/build/integration/federation_features/federated.feature
index 5437d01dee2..8bf8e921b0f 100644
--- a/build/integration/federation_features/federated.feature
+++ b/build/integration/federation_features/federated.feature
@@ -10,7 +10,177 @@ Feature: federated
When User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
Then the OCS status code should be "100"
And the HTTP status code should be "200"
+ And Share fields of last share match with
+ | id | A_NUMBER |
+ | item_type | file |
+ | item_source | A_NUMBER |
+ | share_type | 6 |
+ | file_source | A_NUMBER |
+ | path | /textfile0.txt |
+ | permissions | 19 |
+ | stime | A_NUMBER |
+ | storage | A_NUMBER |
+ | mail_send | 0 |
+ | uid_owner | user0 |
+ | storage_id | home::user0 |
+ | file_parent | A_NUMBER |
+ | displayname_owner | user0 |
+ | share_with | user1@REMOTE |
+ | share_with_displayname | user1@REMOTE |
+ Scenario: Federate share a file with local server
+ Given Using server "LOCAL"
+ And user "user0" exists
+ And Using server "REMOTE"
+ And user "user1" exists
+ When User "user1" from server "REMOTE" shares "/textfile0.txt" with user "user0" from server "LOCAL"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And Share fields of last share match with
+ | id | A_NUMBER |
+ | item_type | file |
+ | item_source | A_NUMBER |
+ | share_type | 6 |
+ | file_source | A_NUMBER |
+ | path | /textfile0.txt |
+ | permissions | 19 |
+ | stime | A_NUMBER |
+ | storage | A_NUMBER |
+ | mail_send | 0 |
+ | uid_owner | user1 |
+ | storage_id | home::user1 |
+ | file_parent | A_NUMBER |
+ | displayname_owner | user1 |
+ | share_with | user0@LOCAL |
+ | share_with_displayname | user0@LOCAL |
+
+ Scenario: Remote sharee can see the pending share
+ Given Using server "REMOTE"
+ And user "user1" exists
+ And Using server "LOCAL"
+ And user "user0" exists
+ And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
+ And Using server "REMOTE"
+ And As an "user1"
+ When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And Share fields of last share match with
+ | id | A_NUMBER |
+ | remote | LOCAL |
+ | remote_id | A_NUMBER |
+ | share_token | A_TOKEN |
+ | name | /textfile0.txt |
+ | owner | user0 |
+ | user | user1 |
+ | mountpoint | {{TemporaryMountPointName#/textfile0.txt}} |
+ | accepted | 0 |
+
+ Scenario: accept a pending remote share
+ Given Using server "REMOTE"
+ And user "user1" exists
+ And Using server "LOCAL"
+ And user "user0" exists
+ And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
+ When User "user1" from server "REMOTE" accepts last pending share
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+
+ Scenario: Reshare a federated shared file
+ Given Using server "REMOTE"
+ And user "user1" exists
+ And user "user2" exists
+ And Using server "LOCAL"
+ And user "user0" exists
+ And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
+ And User "user1" from server "REMOTE" accepts last pending share
+ And Using server "REMOTE"
+ And As an "user1"
+ When creating a share with
+ | path | /textfile0 (2).txt |
+ | shareType | 0 |
+ | shareWith | user2 |
+ | permissions | 19 |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And Share fields of last share match with
+ | id | A_NUMBER |
+ | item_type | file |
+ | item_source | A_NUMBER |
+ | share_type | 0 |
+ | file_source | A_NUMBER |
+ | path | /textfile0 (2).txt |
+ | permissions | 19 |
+ | stime | A_NUMBER |
+ | storage | A_NUMBER |
+ | mail_send | 0 |
+ | uid_owner | user1 |
+ | file_parent | A_NUMBER |
+ | displayname_owner | user1 |
+ | share_with | user2 |
+ | share_with_displayname | user2 |
+
+ Scenario: Overwrite a federated shared file as recipient
+ Given Using server "REMOTE"
+ And user "user1" exists
+ And user "user2" exists
+ And Using server "LOCAL"
+ And user "user0" exists
+ And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
+ And User "user1" from server "REMOTE" accepts last pending share
+ And Using server "REMOTE"
+ And As an "user1"
+ And User "user1" modifies text of "/textfile0.txt" with text "BLABLABLA"
+ When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/textfile0 (2).txt"
+ And Downloading file "/textfile0 (2).txt" with range "bytes=0-8"
+ Then Downloaded content should be "BLABLABLA"
+
+ Scenario: Overwrite a federated shared folder as recipient
+ Given Using server "REMOTE"
+ And user "user1" exists
+ And user "user2" exists
+ And Using server "LOCAL"
+ And user "user0" exists
+ And User "user0" from server "LOCAL" shares "/PARENT" with user "user1" from server "REMOTE"
+ And User "user1" from server "REMOTE" accepts last pending share
+ And Using server "REMOTE"
+ And As an "user1"
+ And User "user1" modifies text of "/textfile0.txt" with text "BLABLABLA"
+ When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/PARENT (2)/textfile0.txt"
+ And Downloading file "/PARENT (2)/textfile0.txt" with range "bytes=0-8"
+ Then Downloaded content should be "BLABLABLA"
+
+ Scenario: Overwrite a federated shared file as recipient using old chunking
+ Given Using server "REMOTE"
+ And user "user1" exists
+ And user "user2" exists
+ And Using server "LOCAL"
+ And user "user0" exists
+ And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
+ And User "user1" from server "REMOTE" accepts last pending share
+ And Using server "REMOTE"
+ And As an "user1"
+ And user "user1" uploads chunk file "1" of "3" with "AAAAA" to "/textfile0 (2).txt"
+ And user "user1" uploads chunk file "2" of "3" with "BBBBB" to "/textfile0 (2).txt"
+ And user "user1" uploads chunk file "3" of "3" with "CCCCC" to "/textfile0 (2).txt"
+ When Downloading file "/textfile0 (2).txt" with range "bytes=0-4"
+ Then Downloaded content should be "AAAAA"
+
+ Scenario: Overwrite a federated shared folder as recipient using old chunking
+ Given Using server "REMOTE"
+ And user "user1" exists
+ And user "user2" exists
+ And Using server "LOCAL"
+ And user "user0" exists
+ And User "user0" from server "LOCAL" shares "/PARENT" with user "user1" from server "REMOTE"
+ And User "user1" from server "REMOTE" accepts last pending share
+ And Using server "REMOTE"
+ And As an "user1"
+ And user "user1" uploads chunk file "1" of "3" with "AAAAA" to "/PARENT (2)/textfile0.txt"
+ And user "user1" uploads chunk file "2" of "3" with "BBBBB" to "/PARENT (2)/textfile0.txt"
+ And user "user1" uploads chunk file "3" of "3" with "CCCCC" to "/PARENT (2)/textfile0.txt"
+ When Downloading file "/PARENT (2)/textfile0.txt" with range "bytes=3-13"
+ Then Downloaded content should be "AABBBBBCCCC"
diff --git a/build/integration/sharees_features/sharees.feature b/build/integration/sharees_features/sharees.feature
new file mode 100644
index 00000000000..58570cfc5f1
--- /dev/null
+++ b/build/integration/sharees_features/sharees.feature
@@ -0,0 +1,240 @@
+Feature: sharees
+ Background:
+ Given using api version "1"
+ And user "test" exists
+ And user "Sharee1" exists
+ And group "ShareeGroup" exists
+ And user "test" belongs to group "ShareeGroup"
+
+ Scenario: Search without exact match
+ Given As an "test"
+ When getting sharees for
+ | search | Sharee |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned is empty
+ And "users" sharees returned are
+ | Sharee1 | 0 | Sharee1 |
+ And "exact groups" sharees returned is empty
+ And "groups" sharees returned are
+ | ShareeGroup | 1 | ShareeGroup |
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty
+
+ Scenario: Search without exact match not-exact casing
+ Given As an "test"
+ When getting sharees for
+ | search | sharee |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned is empty
+ And "users" sharees returned are
+ | Sharee1 | 0 | Sharee1 |
+ And "exact groups" sharees returned is empty
+ And "groups" sharees returned are
+ | ShareeGroup | 1 | ShareeGroup |
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty
+
+ Scenario: Search only with group members - denied
+ Given As an "test"
+ And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes"
+ When getting sharees for
+ | search | sharee |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned is empty
+ And "users" sharees returned is empty
+ And "exact groups" sharees returned is empty
+ And "groups" sharees returned are
+ | ShareeGroup | 1 | ShareeGroup |
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty
+
+ Scenario: Search only with group members - allowed
+ Given As an "test"
+ And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes"
+ And user "Sharee1" belongs to group "ShareeGroup"
+ When getting sharees for
+ | search | sharee |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned is empty
+ And "users" sharees returned are
+ | Sharee1 | 0 | Sharee1 |
+ And "exact groups" sharees returned is empty
+ And "groups" sharees returned are
+ | ShareeGroup | 1 | ShareeGroup |
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty
+
+ Scenario: Search only with group members - no group as non-member
+ Given As an "Sharee1"
+ And parameter "shareapi_only_share_with_group_members" of app "core" is set to "yes"
+ When getting sharees for
+ | search | sharee |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned is empty
+ And "users" sharees returned is empty
+ And "exact groups" sharees returned is empty
+ And "groups" sharees returned is empty
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty
+
+ Scenario: Search without exact match no iteration allowed
+ Given As an "test"
+ And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no"
+ When getting sharees for
+ | search | Sharee |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned is empty
+ And "users" sharees returned is empty
+ And "exact groups" sharees returned is empty
+ And "groups" sharees returned is empty
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty
+
+ Scenario: Search with exact match no iteration allowed
+ Given As an "test"
+ And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no"
+ When getting sharees for
+ | search | Sharee1 |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned are
+ | Sharee1 | 0 | Sharee1 |
+ And "users" sharees returned is empty
+ And "exact groups" sharees returned is empty
+ And "groups" sharees returned is empty
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty
+
+ Scenario: Search with exact match group no iteration allowed
+ Given As an "test"
+ And parameter "shareapi_allow_share_dialog_user_enumeration" of app "core" is set to "no"
+ When getting sharees for
+ | search | ShareeGroup |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned is empty
+ And "users" sharees returned is empty
+ And "exact groups" sharees returned are
+ | ShareeGroup | 1 | ShareeGroup |
+ And "groups" sharees returned is empty
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty
+
+ Scenario: Search with exact match
+ Given As an "test"
+ When getting sharees for
+ | search | Sharee1 |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ Then "exact users" sharees returned are
+ | Sharee1 | 0 | Sharee1 |
+ Then "users" sharees returned is empty
+ Then "exact groups" sharees returned is empty
+ Then "groups" sharees returned is empty
+ Then "exact remotes" sharees returned is empty
+ Then "remotes" sharees returned is empty
+
+ Scenario: Search with exact match not-exact casing
+ Given As an "test"
+ When getting sharees for
+ | search | sharee1 |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ Then "exact users" sharees returned are
+ | Sharee1 | 0 | Sharee1 |
+ Then "users" sharees returned is empty
+ Then "exact groups" sharees returned is empty
+ Then "groups" sharees returned is empty
+ Then "exact remotes" sharees returned is empty
+ Then "remotes" sharees returned is empty
+
+ Scenario: Search with exact match not-exact casing group
+ Given As an "test"
+ When getting sharees for
+ | search | shareegroup |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ Then "exact users" sharees returned is empty
+ Then "users" sharees returned is empty
+ Then "exact groups" sharees returned are
+ | ShareeGroup | 1 | ShareeGroup |
+ Then "groups" sharees returned is empty
+ Then "exact remotes" sharees returned is empty
+ Then "remotes" sharees returned is empty
+
+ Scenario: Search with "self"
+ Given As an "Sharee1"
+ When getting sharees for
+ | search | Sharee1 |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ Then "exact users" sharees returned are
+ | Sharee1 | 0 | Sharee1 |
+ Then "users" sharees returned is empty
+ Then "exact groups" sharees returned is empty
+ Then "groups" sharees returned is empty
+ Then "exact remotes" sharees returned is empty
+ Then "remotes" sharees returned is empty
+
+ Scenario: Remote sharee for files
+ Given As an "test"
+ When getting sharees for
+ | search | test@localhost |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ Then "exact users" sharees returned is empty
+ Then "users" sharees returned is empty
+ Then "exact groups" sharees returned is empty
+ Then "groups" sharees returned is empty
+ Then "exact remotes" sharees returned are
+ | test@localhost | 6 | test@localhost |
+ Then "remotes" sharees returned is empty
+
+ Scenario: Remote sharee for calendars not allowed
+ Given As an "test"
+ When getting sharees for
+ | search | test@localhost |
+ | itemType | calendar |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ Then "exact users" sharees returned is empty
+ Then "users" sharees returned is empty
+ Then "exact groups" sharees returned is empty
+ Then "groups" sharees returned is empty
+ Then "exact remotes" sharees returned is empty
+ Then "remotes" sharees returned is empty
+
+ Scenario: Group sharees not returned when group sharing is disabled
+ Given As an "test"
+ And parameter "shareapi_allow_group_sharing" of app "core" is set to "no"
+ When getting sharees for
+ | search | sharee |
+ | itemType | file |
+ Then the OCS status code should be "100"
+ And the HTTP status code should be "200"
+ And "exact users" sharees returned is empty
+ And "users" sharees returned are
+ | Sharee1 | 0 | Sharee1 |
+ And "exact groups" sharees returned is empty
+ And "groups" sharees returned is empty
+ And "exact remotes" sharees returned is empty
+ And "remotes" sharees returned is empty