Add integration tests for comments

This adds integration tests for the comments. Especially with regard to the permission handling, didn't find any problem in it.

Fixes https://github.com/owncloud/core/issues/22367
This commit is contained in:
Lukas Reschke 2016-02-18 23:07:41 +01:00
parent 32e4256945
commit 16be9af20a
5 changed files with 531 additions and 2 deletions

View File

@ -12,6 +12,8 @@ default:
- admin - admin
- admin - admin
regular_user_password: 123456 regular_user_password: 123456
- CommentsContext:
baseUrl: http://localhost:8080
federation: federation:
paths: paths:
- %paths.base%/../federation_features - %paths.base%/../federation_features

View File

@ -0,0 +1,263 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
*
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
require __DIR__ . '/../../vendor/autoload.php';
class CommentsContext implements \Behat\Behat\Context\Context {
/** @var string */
private $baseUrl;
/** @var array */
private $response;
/** @var int */
private $commentId;
/** @var int */
private $fileId;
/**
* @param string $baseUrl
*/
public function __construct($baseUrl) {
$this->baseUrl = $baseUrl;
// in case of ci deployment we take the server url from the environment
$testServerUrl = getenv('TEST_SERVER_URL');
if ($testServerUrl !== false) {
$this->baseUrl = substr($testServerUrl, 0, -5);
}
}
/** @AfterScenario */
public function teardownScenario(\Behat\Behat\Hook\Scope\AfterScenarioScope $scope) {
$client = new \GuzzleHttp\Client();
try {
$client->delete(
$this->baseUrl.'/remote.php/webdav/myFileToComment.txt',
[
'auth' => [
'user0',
'123456',
],
'headers' => [
'Content-Type' => 'application/json',
],
]
);
} catch (\GuzzleHttp\Exception\ClientException $e) {
$e->getResponse();
}
}
/**
* @return int
*/
private function getFileIdForPath($path) {
$url = $this->baseUrl.'/remote.php/webdav/'.$path;
$context = stream_context_create(array(
'http' => array(
'method' => 'PROPFIND',
'header' => "Authorization: Basic dXNlcjA6MTIzNDU2\r\nContent-Type: application/x-www-form-urlencoded",
'content' => '<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:fileid />
</d:prop>
</d:propfind>'
)
));
$response = file_get_contents($url, false, $context);
preg_match_all('/\<oc:fileid\>(.*)\<\/oc:fileid\>/', $response, $matches);
return (int)$matches[1][0];
}
/**
* @When :user posts a comment with content :content on the file named :fileName it should return :statusCode
*/
public function postsACommentWithContentOnTheFileNamedItShouldReturn($user, $content, $fileName, $statusCode) {
$fileId = $this->getFileIdForPath($fileName);
$this->fileId = (int)$fileId;
$url = $this->baseUrl.'/remote.php/dav/comments/files/'.$fileId.'/';
$client = new \GuzzleHttp\Client();
try {
$res = $client->post(
$url,
[
'body' => '{"actorId":"user0","actorDisplayName":"user0","actorType":"users","verb":"comment","message":"' . $content . '","creationDateTime":"Thu, 18 Feb 2016 17:04:18 GMT","objectType":"files"}',
'auth' => [
$user,
'123456',
],
'headers' => [
'Content-Type' => 'application/json',
],
]
);
} catch (\GuzzleHttp\Exception\ClientException $e) {
$res = $e->getResponse();
}
if($res->getStatusCode() !== (int)$statusCode) {
throw new \Exception("Response status code was not $statusCode (".$res->getStatusCode().")");
}
}
/**
* @Then As :user load all the comments of the file named :fileName it should return :statusCode
*/
public function asLoadloadAllTheCommentsOfTheFileNamedItShouldReturn($user, $fileName, $statusCode) {
$fileId = $this->getFileIdForPath($fileName);
$url = $this->baseUrl.'/remote.php/dav/comments/files/'.$fileId.'/';
try {
$client = new \GuzzleHttp\Client();
$res = $client->createRequest(
'REPORT',
$url,
[
'body' => '<?xml version="1.0" encoding="utf-8" ?>
<oc:filter-comments xmlns:D="DAV:" xmlns:oc="http://owncloud.org/ns">
<oc:limit>200</oc:limit>
<oc:offset>0</oc:offset>
</oc:filter-comments>
',
'auth' => [
$user,
'123456',
],
'headers' => [
'Content-Type' => 'application/json',
],
]
);
$res = $client->send($res);
} catch (\GuzzleHttp\Exception\ClientException $e) {
$res = $e->getResponse();
}
if($res->getStatusCode() !== (int)$statusCode) {
throw new \Exception("Response status code was not $statusCode (".$res->getStatusCode().")");
}
if($res->getStatusCode() === 207) {
$service = new Sabre\Xml\Service();
$this->response = $service->parse($res->getBody()->getContents());
$this->commentId = (int)$this->response[0]['value'][2]['value'][0]['value'][0]['value'];
}
}
/**
* @Given As :user sending :verb to :url with
*/
public function asUserSendingToWith($user, $verb, $url, \Behat\Gherkin\Node\TableNode $body) {
$client = new \GuzzleHttp\Client();
$options = [];
$options['auth'] = [$user, '123456'];
$fd = $body->getRowsHash();
$options['body'] = $fd;
$client->send($client->createRequest($verb, $this->baseUrl.'/ocs/v1.php/'.$url, $options));
}
/**
* @Then As :user delete the created comment it should return :statusCode
*/
public function asDeleteTheCreatedCommentItShouldReturn($user, $statusCode) {
$url = $this->baseUrl.'/remote.php/dav/comments/files/'.$this->fileId.'/'.$this->commentId;
$client = new \GuzzleHttp\Client();
try {
$res = $client->delete(
$url,
[
'auth' => [
$user,
'123456',
],
'headers' => [
'Content-Type' => 'application/json',
],
]
);
} catch (\GuzzleHttp\Exception\ClientException $e) {
$res = $e->getResponse();
}
if($res->getStatusCode() !== (int)$statusCode) {
throw new \Exception("Response status code was not $statusCode (".$res->getStatusCode().")");
}
}
/**
* @Then the response should contain a property :key with value :value
*/
public function theResponseShouldContainAPropertyWithValue($key, $value) {
$keys = $this->response[0]['value'][2]['value'][0]['value'];
$found = false;
foreach($keys as $singleKey) {
if($singleKey['name'] === '{http://owncloud.org/ns}'.substr($key, 3)) {
if($singleKey['value'] === $value) {
$found = true;
}
}
}
if($found === false) {
throw new \Exception("Cannot find property $key with $value");
}
}
/**
* @Then the response should contain only :number comments
*/
public function theResponseShouldContainOnlyComments($number) {
if(count($this->response) !== (int)$number) {
throw new \Exception("Found more comments than $number (".count($this->response).")");
}
}
/**
* @Then As :user edit the last created comment and set text to :text it should return :statusCode
*/
public function asEditTheLastCreatedCommentAndSetTextToItShouldReturn($user, $text, $statusCode) {
$client = new \GuzzleHttp\Client();
$options = [];
$options['auth'] = [$user, '123456'];
$options['body'] = '<?xml version="1.0"?>
<d:propertyupdate xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:set>
<d:prop>
<oc:message>'.$text.'</oc:message>
</d:prop>
</d:set>
</d:propertyupdate>';
try {
$res = $client->send($client->createRequest('PROPPATCH', $this->baseUrl.'/remote.php/dav/comments/files/' . $this->fileId . '/' . $this->commentId, $options));
} catch (\GuzzleHttp\Exception\ClientException $e) {
$res = $e->getResponse();
}
if($res->getStatusCode() !== (int)$statusCode) {
throw new \Exception("Response status code was not $statusCode (".$res->getStatusCode().")");
}
}
}

View File

@ -370,5 +370,49 @@ 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';
$client = new \GuzzleHttp\Client();
$res = $client->get(
$url,
[
'auth' => [
$user,
'123456',
],
'headers' => [
'Content-Type' => 'application/json',
],
]
);
$json = json_decode($res->getBody()->getContents(), true);
$deleted = false;
foreach($json['ocs']['data'] as $data) {
if (stripslashes($data['path']) === $fileName) {
$id = $data['id'];
$client->delete(
$this->baseUrl.'v2.php/apps/files_sharing/api/v1/shares/'.$id,
[
'auth' => [
$user,
'123456',
],
'headers' => [
'Content-Type' => 'application/json',
],
]
);
$deleted = true;
}
}
if($deleted === false) {
throw new \Exception("Could not delete file $fileName");
}
}
} }

View File

@ -10,7 +10,6 @@ require __DIR__ . '/../../vendor/autoload.php';
trait WebDav { trait WebDav {
/** @var string*/ /** @var string*/
private $davPath = "remote.php/webdav"; private $davPath = "remote.php/webdav";
@ -162,6 +161,18 @@ trait WebDav{
} }
} }
/**
* @When User :user deletes file :file
*/
public function userDeletesFile($user, $file) {
try {
$this->response = $this->makeDavRequest($user, 'DELETE', $file, []);
} catch (\GuzzleHttp\Exception\ServerException $e) {
// 4xx and 5xx responses cause an exception
$this->response = $e->getResponse();
}
}
/** /**
* @Given User :user created a folder :destination * @Given User :user created a folder :destination
*/ */

View File

@ -0,0 +1,209 @@
Feature: comments
Scenario: Creating a comment on a file belonging to myself
Given user "user0" exists
Given As an "user0"
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
When "user0" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
And the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user0"
And the response should contain only "1" comments
Scenario: Creating a comment on a shared file belonging to another user
Given user "user0" exists
Given user "user1" exists
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Given As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
| path | myFileToComment.txt |
| shareWith | user1 |
| shareType | 0 |
When "user1" posts a comment with content "A comment from another user" on the file named "/myFileToComment.txt" it should return "201"
Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
And the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "A comment from another user"
And the response should contain a property "oc:actorDisplayName" with value "user1"
And the response should contain only "1" comments
Scenario: Creating a comment on a non-shared file belonging to another user
Given user "user0" exists
Given user "user1" exists
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Then "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "404"
Scenario: Reading comments on a non-shared file belonging to another user
Given user "user0" exists
Given user "user1" exists
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "404"
Scenario: Deleting my own comments on a file belonging to myself
Given user "user0" exists
Given As an "user0"
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Given "user0" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
When As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
Then the response should contain a property "oc:parentId" with value "0"
Then the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user0"
And the response should contain only "1" comments
And As "user0" delete the created comment it should return "204"
And As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
And the response should contain only "0" comments
Scenario: Deleting my own comments on a file shared by somebody else
Given user "user0" exists
Given user "user1" exists
Given As an "user0"
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Given As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
| path | myFileToComment.txt |
| shareWith | user1 |
| shareType | 0 |
Given "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
When As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
Then the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user1"
And the response should contain only "1" comments
And As "user1" delete the created comment it should return "204"
And As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
And the response should contain only "0" comments
Scenario: Deleting my own comments on a file unshared by someone else
Given user "user0" exists
Given user "user1" exists
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Given As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
| path | myFileToComment.txt |
| shareWith | user1 |
| shareType | 0 |
Given "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
When As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
Then the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user1"
And the response should contain only "1" comments
And As "user0" remove all shares from the file named "/myFileToComment.txt"
And As "user1" delete the created comment it should return "404"
And As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "404"
Scenario: Edit my own comments on a file belonging to myself
Given user "user0" exists
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Given "user0" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
When As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
Then the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user0"
And the response should contain only "1" comments
When As "user0" edit the last created comment and set text to "My edited comment" it should return "207"
Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
And the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My edited comment"
And the response should contain a property "oc:actorDisplayName" with value "user0"
Scenario: Edit my own comments on a file shared by someone with me
Given user "user0" exists
Given user "user1" exists
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Given As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
| path | myFileToComment.txt |
| shareWith | user1 |
| shareType | 0 |
Given "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
When As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
Then the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user1"
And the response should contain only "1" comments
Given As "user1" edit the last created comment and set text to "My edited comment" it should return "207"
Then As "user1" load all the comments of the file named "/myFileToComment.txt" it should return "207"
And the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My edited comment"
And the response should contain a property "oc:actorDisplayName" with value "user1"
Scenario: Edit my own comments on a file unshared by someone with me
Given user "user0" exists
Given user "user1" exists
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Given As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
| path | myFileToComment.txt |
| shareWith | user1 |
| shareType | 0 |
When "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
And the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user1"
And the response should contain only "1" comments
And As "user0" remove all shares from the file named "/myFileToComment.txt"
When As "user1" edit the last created comment and set text to "My edited comment" it should return "404"
Then As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
And the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user1"
Scenario: Edit comments of other users should not be possible
Given user "user0" exists
Given user "user1" exists
Given User "user0" uploads file "data/textfile.txt" to "/myFileToComment.txt"
Given As "user0" sending "POST" to "/apps/files_sharing/api/v1/shares" with
| path | myFileToComment.txt |
| shareWith | user1 |
| shareType | 0 |
Given "user1" posts a comment with content "My first comment" on the file named "/myFileToComment.txt" it should return "201"
When As "user0" load all the comments of the file named "/myFileToComment.txt" it should return "207"
Then the response should contain a property "oc:parentId" with value "0"
And the response should contain a property "oc:childrenCount" with value "0"
And the response should contain a property "oc:verb" with value "comment"
And the response should contain a property "oc:actorType" with value "users"
And the response should contain a property "oc:objectType" with value "files"
And the response should contain a property "oc:message" with value "My first comment"
And the response should contain a property "oc:actorDisplayName" with value "user1"
And the response should contain only "1" comments
Then As "user0" edit the last created comment and set text to "My edited comment" it should return "403"