aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/tests/unit/Files
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dav/tests/unit/Files')
-rw-r--r--apps/dav/tests/unit/Files/FileSearchBackendTest.php243
-rw-r--r--apps/dav/tests/unit/Files/MultipartRequestParserTest.php205
-rw-r--r--apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php256
3 files changed, 427 insertions, 277 deletions
diff --git a/apps/dav/tests/unit/Files/FileSearchBackendTest.php b/apps/dav/tests/unit/Files/FileSearchBackendTest.php
index dec5db1b1b0..c6d6f85347b 100644
--- a/apps/dav/tests/unit/Files/FileSearchBackendTest.php
+++ b/apps/dav/tests/unit/Files/FileSearchBackendTest.php
@@ -1,38 +1,21 @@
<?php
+
+declare(strict_types=1);
/**
- * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace OCA\DAV\Tests\Files;
+
+namespace OCA\DAV\Tests\unit\Files;
use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchQuery;
use OC\Files\View;
-use OCA\DAV\Connector\Sabre\CachingTree;
use OCA\DAV\Connector\Sabre\Directory;
use OCA\DAV\Connector\Sabre\File;
use OCA\DAV\Connector\Sabre\FilesPlugin;
+use OCA\DAV\Connector\Sabre\ObjectTree;
+use OCA\DAV\Connector\Sabre\Server;
use OCA\DAV\Files\FileSearchBackend;
use OCP\Files\FileInfo;
use OCP\Files\Folder;
@@ -40,37 +23,28 @@ use OCP\Files\IRootFolder;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchComparison;
use OCP\Files\Search\ISearchQuery;
+use OCP\FilesMetadata\IFilesMetadataManager;
use OCP\IUser;
use OCP\Share\IManager;
+use PHPUnit\Framework\MockObject\MockObject;
use SearchDAV\Backend\SearchPropertyDefinition;
use SearchDAV\Query\Limit;
+use SearchDAV\Query\Literal;
+use SearchDAV\Query\Operator;
use SearchDAV\Query\Query;
+use SearchDAV\Query\Scope;
use Test\TestCase;
class FileSearchBackendTest extends TestCase {
- /** @var CachingTree|\PHPUnit\Framework\MockObject\MockObject */
- private $tree;
-
- /** @var IUser */
- private $user;
-
- /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject */
- private $rootFolder;
-
- /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */
- private $shareManager;
-
- /** @var View|\PHPUnit\Framework\MockObject\MockObject */
- private $view;
-
- /** @var Folder|\PHPUnit\Framework\MockObject\MockObject */
- private $searchFolder;
-
- /** @var FileSearchBackend */
- private $search;
-
- /** @var Directory|\PHPUnit\Framework\MockObject\MockObject */
- private $davFolder;
+ private ObjectTree&MockObject $tree;
+ private Server&MockObject $server;
+ private IUser&MockObject $user;
+ private IRootFolder&MockObject $rootFolder;
+ private IManager&MockObject $shareManager;
+ private View&MockObject $view;
+ private Folder&MockObject $searchFolder;
+ private Directory&MockObject $davFolder;
+ private FileSearchBackend $search;
protected function setUp(): void {
parent::setUp();
@@ -80,28 +54,23 @@ class FileSearchBackendTest extends TestCase {
->method('getUID')
->willReturn('test');
- $this->tree = $this->getMockBuilder(CachingTree::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->view = $this->getMockBuilder(View::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->view->expects($this->any())
- ->method('getRelativePath')
- ->willReturnArgument(0);
-
+ $this->tree = $this->createMock(ObjectTree::class);
+ $this->server = $this->createMock(Server::class);
+ $this->view = $this->createMock(View::class);
$this->rootFolder = $this->createMock(IRootFolder::class);
-
$this->shareManager = $this->createMock(IManager::class);
-
$this->searchFolder = $this->createMock(Folder::class);
-
$fileInfo = $this->createMock(FileInfo::class);
-
$this->davFolder = $this->createMock(Directory::class);
+ $this->view->expects($this->any())
+ ->method('getRoot')
+ ->willReturn('');
+
+ $this->view->expects($this->any())
+ ->method('getRelativePath')
+ ->willReturnArgument(0);
+
$this->davFolder->expects($this->any())
->method('getFileInfo')
->willReturn($fileInfo);
@@ -110,10 +79,12 @@ class FileSearchBackendTest extends TestCase {
->method('get')
->willReturn($this->searchFolder);
- $this->search = new FileSearchBackend($this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view);
+ $filesMetadataManager = $this->createMock(IFilesMetadataManager::class);
+
+ $this->search = new FileSearchBackend($this->server, $this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager);
}
- public function testSearchFilename() {
+ public function testSearchFilename(): void {
$this->tree->expects($this->any())
->method('getNodeForPath')
->willReturn($this->davFolder);
@@ -132,17 +103,17 @@ class FileSearchBackendTest extends TestCase {
$this->user
))
->willReturn([
- new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path')
+ new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
]);
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_EQUAL, '{DAV:}displayname', 'foo');
+ $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}displayname', 'foo');
$result = $this->search->search($query);
$this->assertCount(1, $result);
$this->assertEquals('/files/test/test/path', $result[0]->href);
}
- public function testSearchMimetype() {
+ public function testSearchMimetype(): void {
$this->tree->expects($this->any())
->method('getNodeForPath')
->willReturn($this->davFolder);
@@ -161,17 +132,17 @@ class FileSearchBackendTest extends TestCase {
$this->user
))
->willReturn([
- new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path')
+ new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
]);
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_EQUAL, '{DAV:}getcontenttype', 'foo');
+ $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}getcontenttype', 'foo');
$result = $this->search->search($query);
$this->assertCount(1, $result);
$this->assertEquals('/files/test/test/path', $result[0]->href);
}
- public function testSearchSize() {
+ public function testSearchSize(): void {
$this->tree->expects($this->any())
->method('getNodeForPath')
->willReturn($this->davFolder);
@@ -190,17 +161,17 @@ class FileSearchBackendTest extends TestCase {
$this->user
))
->willReturn([
- new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path')
+ new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
]);
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_GREATER_THAN, FilesPlugin::SIZE_PROPERTYNAME, 10);
+ $query = $this->getBasicQuery(Operator::OPERATION_GREATER_THAN, FilesPlugin::SIZE_PROPERTYNAME, 10);
$result = $this->search->search($query);
$this->assertCount(1, $result);
$this->assertEquals('/files/test/test/path', $result[0]->href);
}
- public function testSearchMtime() {
+ public function testSearchMtime(): void {
$this->tree->expects($this->any())
->method('getNodeForPath')
->willReturn($this->davFolder);
@@ -219,17 +190,17 @@ class FileSearchBackendTest extends TestCase {
$this->user
))
->willReturn([
- new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path')
+ new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
]);
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_GREATER_THAN, '{DAV:}getlastmodified', 10);
+ $query = $this->getBasicQuery(Operator::OPERATION_GREATER_THAN, '{DAV:}getlastmodified', 10);
$result = $this->search->search($query);
$this->assertCount(1, $result);
$this->assertEquals('/files/test/test/path', $result[0]->href);
}
- public function testSearchIsCollection() {
+ public function testSearchIsCollection(): void {
$this->tree->expects($this->any())
->method('getNodeForPath')
->willReturn($this->davFolder);
@@ -248,10 +219,10 @@ class FileSearchBackendTest extends TestCase {
$this->user
))
->willReturn([
- new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path')
+ new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
]);
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_IS_COLLECTION, 'yes');
+ $query = $this->getBasicQuery(Operator::OPERATION_IS_COLLECTION, 'yes');
$result = $this->search->search($query);
$this->assertCount(1, $result);
@@ -259,7 +230,7 @@ class FileSearchBackendTest extends TestCase {
}
- public function testSearchInvalidProp() {
+ public function testSearchInvalidProp(): void {
$this->expectException(\InvalidArgumentException::class);
$this->tree->expects($this->any())
@@ -269,25 +240,25 @@ class FileSearchBackendTest extends TestCase {
$this->searchFolder->expects($this->never())
->method('search');
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_EQUAL, '{DAV:}getetag', 'foo');
+ $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}getetag', 'foo');
$this->search->search($query);
}
- private function getBasicQuery($type, $property, $value = null) {
- $scope = new \SearchDAV\Query\Scope('/', 'infinite');
+ private function getBasicQuery(string $type, string $property, int|string|null $value = null) {
+ $scope = new Scope('/', 'infinite');
$scope->path = '/';
$from = [$scope];
$orderBy = [];
$select = [];
if (is_null($value)) {
- $where = new \SearchDAV\Query\Operator(
+ $where = new Operator(
$type,
- [new \SearchDAV\Query\Literal($property)]
+ [new Literal($property)]
);
} else {
- $where = new \SearchDAV\Query\Operator(
+ $where = new Operator(
$type,
- [new SearchPropertyDefinition($property, true, true, true), new \SearchDAV\Query\Literal($value)]
+ [new SearchPropertyDefinition($property, true, true, true), new Literal($value)]
);
}
$limit = new Limit();
@@ -296,7 +267,7 @@ class FileSearchBackendTest extends TestCase {
}
- public function testSearchNonFolder() {
+ public function testSearchNonFolder(): void {
$this->expectException(\InvalidArgumentException::class);
$davNode = $this->createMock(File::class);
@@ -305,11 +276,11 @@ class FileSearchBackendTest extends TestCase {
->method('getNodeForPath')
->willReturn($davNode);
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_EQUAL, '{DAV:}displayname', 'foo');
+ $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}displayname', 'foo');
$this->search->search($query);
}
- public function testSearchLimitOwnerBasic() {
+ public function testSearchLimitOwnerBasic(): void {
$this->tree->expects($this->any())
->method('getNodeForPath')
->willReturn($this->davFolder);
@@ -321,11 +292,11 @@ class FileSearchBackendTest extends TestCase {
->willReturnCallback(function ($query) use (&$receivedQuery) {
$receivedQuery = $query;
return [
- new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path')
+ new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
];
});
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
+ $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
$this->search->search($query);
$this->assertNotNull($receivedQuery);
@@ -338,7 +309,7 @@ class FileSearchBackendTest extends TestCase {
$this->assertEmpty($operator->getArguments());
}
- public function testSearchLimitOwnerNested() {
+ public function testSearchLimitOwnerNested(): void {
$this->tree->expects($this->any())
->method('getNodeForPath')
->willReturn($this->davFolder);
@@ -350,22 +321,22 @@ class FileSearchBackendTest extends TestCase {
->willReturnCallback(function ($query) use (&$receivedQuery) {
$receivedQuery = $query;
return [
- new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path')
+ new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
];
});
- $query = $this->getBasicQuery(\SearchDAV\Query\Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
- $query->where = new \SearchDAV\Query\Operator(
- \SearchDAV\Query\Operator::OPERATION_AND,
+ $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
+ $query->where = new Operator(
+ Operator::OPERATION_AND,
[
- new \SearchDAV\Query\Operator(
- \SearchDAV\Query\Operator::OPERATION_EQUAL,
- [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new \SearchDAV\Query\Literal('image/png')]
+ new Operator(
+ Operator::OPERATION_EQUAL,
+ [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new Literal('image/png')]
+ ),
+ new Operator(
+ Operator::OPERATION_EQUAL,
+ [new SearchPropertyDefinition(FilesPlugin::OWNER_ID_PROPERTYNAME, true, true, true), new Literal($this->user->getUID())]
),
- new \SearchDAV\Query\Operator(
- \SearchDAV\Query\Operator::OPERATION_EQUAL,
- [new SearchPropertyDefinition(FilesPlugin::OWNER_ID_PROPERTYNAME, true, true, true), new \SearchDAV\Query\Literal($this->user->getUID())]
- )
]
);
$this->search->search($query);
@@ -385,4 +356,66 @@ class FileSearchBackendTest extends TestCase {
$this->assertEquals(ISearchBinaryOperator::OPERATOR_AND, $operator->getType());
$this->assertEmpty($operator->getArguments());
}
+
+ public function testSearchOperatorLimit(): void {
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->willReturn($this->davFolder);
+
+ $innerOperator = new Operator(
+ Operator::OPERATION_EQUAL,
+ [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new Literal('image/png')]
+ );
+ // 5 child operators
+ $level1Operator = new Operator(
+ Operator::OPERATION_AND,
+ [
+ $innerOperator,
+ $innerOperator,
+ $innerOperator,
+ $innerOperator,
+ $innerOperator,
+ ]
+ );
+ // 5^2 = 25 child operators
+ $level2Operator = new Operator(
+ Operator::OPERATION_AND,
+ [
+ $level1Operator,
+ $level1Operator,
+ $level1Operator,
+ $level1Operator,
+ $level1Operator,
+ ]
+ );
+ // 5^3 = 125 child operators
+ $level3Operator = new Operator(
+ Operator::OPERATION_AND,
+ [
+ $level2Operator,
+ $level2Operator,
+ $level2Operator,
+ $level2Operator,
+ $level2Operator,
+ ]
+ );
+
+ $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
+ $query->where = $level3Operator;
+ $this->expectException(\InvalidArgumentException::class);
+ $this->search->search($query);
+ }
+
+ public function testPreloadPropertyFor(): void {
+ $node1 = $this->createMock(File::class);
+ $node2 = $this->createMock(Directory::class);
+ $nodes = [$node1, $node2];
+ $requestProperties = ['{DAV:}getcontenttype', '{DAV:}getlastmodified'];
+
+ $this->server->expects($this->once())
+ ->method('emit')
+ ->with('preloadProperties', [$nodes, $requestProperties]);
+
+ $this->search->preloadPropertyFor($nodes, $requestProperties);
+ }
}
diff --git a/apps/dav/tests/unit/Files/MultipartRequestParserTest.php b/apps/dav/tests/unit/Files/MultipartRequestParserTest.php
index ec9e2d0a383..dc0e884f07c 100644
--- a/apps/dav/tests/unit/Files/MultipartRequestParserTest.php
+++ b/apps/dav/tests/unit/Files/MultipartRequestParserTest.php
@@ -1,71 +1,70 @@
<?php
+
+declare(strict_types=1);
/**
- * @copyright Copyright (c) 2021, Louis Chemineau <louis@chmn.me>
- *
- * @author Louis Chemineau <louis@chmn.me>
- *
- * @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/>
- *
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
*/
-namespace OCA\DAV\Tests\unit\DAV;
+namespace OCA\DAV\Tests\unit\Files;
+use OCA\DAV\BulkUpload\MultipartRequestParser;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+use Sabre\HTTP\RequestInterface;
use Test\TestCase;
-use \OCA\DAV\BulkUpload\MultipartRequestParser;
class MultipartRequestParserTest extends TestCase {
- private function getValidBodyObject() {
+
+ protected LoggerInterface&MockObject $logger;
+
+ protected function setUp(): void {
+ parent::setUp();
+ $this->logger = $this->createMock(LoggerInterface::class);
+ }
+
+ private static function getValidBodyObject(): array {
return [
[
- "headers" => [
- "Content-Length" => 7,
- "X-File-MD5" => "4f2377b4d911f7ec46325fe603c3af03",
- "X-File-Path" => "/coucou.txt"
+ 'headers' => [
+ 'Content-Length' => 7,
+ 'X-File-MD5' => '4f2377b4d911f7ec46325fe603c3af03',
+ 'OC-Checksum' => 'md5:4f2377b4d911f7ec46325fe603c3af03',
+ 'X-File-Path' => '/coucou.txt'
],
- "content" => "Coucou\n"
+ 'content' => "Coucou\n"
]
];
}
- private function getMultipartParser(array $parts, array $headers = [], string $boundary = "boundary_azertyuiop"): MultipartRequestParser {
- $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ private function getMultipartParser(array $parts, array $headers = [], string $boundary = 'boundary_azertyuiop'): MultipartRequestParser {
+ /** @var RequestInterface&MockObject $request */
+ $request = $this->getMockBuilder(RequestInterface::class)
->disableOriginalConstructor()
->getMock();
- $headers = array_merge(['Content-Type' => 'multipart/related; boundary='.$boundary], $headers);
+ $headers = array_merge(['Content-Type' => 'multipart/related; boundary=' . $boundary], $headers);
$request->expects($this->any())
->method('getHeader')
->willReturnCallback(function (string $key) use (&$headers) {
return $headers[$key];
});
- $body = "";
+ $body = '';
foreach ($parts as $part) {
- $body .= '--'.$boundary."\r\n";
+ $body .= '--' . $boundary . "\r\n";
foreach ($part['headers'] as $headerKey => $headerPart) {
- $body .= $headerKey.": ".$headerPart."\r\n";
+ $body .= $headerKey . ': ' . $headerPart . "\r\n";
}
$body .= "\r\n";
- $body .= $part['content']."\r\n";
+ $body .= $part['content'] . "\r\n";
}
- $body .= '--'.$boundary."--";
+ $body .= '--' . $boundary . '--';
- $stream = fopen('php://temp','r+');
+ $stream = fopen('php://temp', 'r+');
fwrite($stream, $body);
rewind($stream);
@@ -73,16 +72,17 @@ class MultipartRequestParserTest extends TestCase {
->method('getBody')
->willReturn($stream);
- return new MultipartRequestParser($request);
+ return new MultipartRequestParser($request, $this->logger);
}
/**
* Test validation of the request's body type
*/
- public function testBodyTypeValidation() {
- $bodyStream = "I am not a stream, but pretend to be";
- $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+ public function testBodyTypeValidation(): void {
+ $bodyStream = 'I am not a stream, but pretend to be';
+ /** @var RequestInterface&MockObject $request */
+ $request = $this->getMockBuilder(RequestInterface::class)
->disableOriginalConstructor()
->getMock();
$request->expects($this->any())
@@ -90,7 +90,30 @@ class MultipartRequestParserTest extends TestCase {
->willReturn($bodyStream);
$this->expectExceptionMessage('Body should be of type resource');
- new MultipartRequestParser($request);
+ new MultipartRequestParser($request, $this->logger);
+ }
+
+ /**
+ * Test with valid request.
+ * - valid boundary
+ * - valid hash
+ * - valid content-length
+ * - valid file content
+ * - valid file path
+ */
+ public function testValidRequest(): void {
+ $bodyObject = self::getValidBodyObject();
+ unset($bodyObject['0']['headers']['X-File-MD5']);
+
+ $multipartParser = $this->getMultipartParser($bodyObject);
+
+ [$headers, $content] = $multipartParser->parseNextPart();
+
+ $this->assertSame((int)$headers['content-length'], 7, 'Content-Length header should be the same as provided.');
+ $this->assertSame($headers['oc-checksum'], 'md5:4f2377b4d911f7ec46325fe603c3af03', 'OC-Checksum header should be the same as provided.');
+ $this->assertSame($headers['x-file-path'], '/coucou.txt', 'X-File-Path header should be the same as provided.');
+
+ $this->assertSame($content, "Coucou\n", 'Content should be the same');
}
/**
@@ -101,54 +124,72 @@ class MultipartRequestParserTest extends TestCase {
* - valid file content
* - valid file path
*/
- public function testValidRequest() {
- $multipartParser = $this->getMultipartParser(
- $this->getValidBodyObject()
- );
+ public function testValidRequestWithMd5(): void {
+ $bodyObject = self::getValidBodyObject();
+ unset($bodyObject['0']['headers']['OC-Checksum']);
+
+ $multipartParser = $this->getMultipartParser($bodyObject);
[$headers, $content] = $multipartParser->parseNextPart();
- $this->assertSame((int)$headers["content-length"], 7, "Content-Length header should be the same as provided.");
- $this->assertSame($headers["x-file-md5"], "4f2377b4d911f7ec46325fe603c3af03", "X-File-MD5 header should be the same as provided.");
- $this->assertSame($headers["x-file-path"], "/coucou.txt", "X-File-Path header should be the same as provided.");
+ $this->assertSame((int)$headers['content-length'], 7, 'Content-Length header should be the same as provided.');
+ $this->assertSame($headers['x-file-md5'], '4f2377b4d911f7ec46325fe603c3af03', 'X-File-MD5 header should be the same as provided.');
+ $this->assertSame($headers['x-file-path'], '/coucou.txt', 'X-File-Path header should be the same as provided.');
+
+ $this->assertSame($content, "Coucou\n", 'Content should be the same');
+ }
- $this->assertSame($content, "Coucou\n", "Content should be the same");
+ /**
+ * Test with invalid hash.
+ */
+ public function testInvalidHash(): void {
+ $bodyObject = self::getValidBodyObject();
+ $bodyObject['0']['headers']['OC-Checksum'] = 'md5:f2377b4d911f7ec46325fe603c3af03';
+ unset($bodyObject['0']['headers']['X-File-MD5']);
+ $multipartParser = $this->getMultipartParser(
+ $bodyObject
+ );
+
+ $this->expectExceptionMessage('Computed md5 hash is incorrect (4f2377b4d911f7ec46325fe603c3af03).');
+ $multipartParser->parseNextPart();
}
/**
* Test with invalid md5 hash.
*/
- public function testInvalidMd5Hash() {
- $bodyObject = $this->getValidBodyObject();
- $bodyObject["0"]["headers"]["X-File-MD5"] = "f2377b4d911f7ec46325fe603c3af03";
+ public function testInvalidMd5Hash(): void {
+ $bodyObject = self::getValidBodyObject();
+ unset($bodyObject['0']['headers']['OC-Checksum']);
+ $bodyObject['0']['headers']['X-File-MD5'] = 'f2377b4d911f7ec46325fe603c3af03';
$multipartParser = $this->getMultipartParser(
$bodyObject
);
- $this->expectExceptionMessage('Computed md5 hash is incorrect.');
+ $this->expectExceptionMessage('Computed md5 hash is incorrect (4f2377b4d911f7ec46325fe603c3af03).');
$multipartParser->parseNextPart();
}
/**
- * Test with a null md5 hash.
+ * Test with a null hash headers.
*/
- public function testNullMd5Hash() {
- $bodyObject = $this->getValidBodyObject();
- unset($bodyObject["0"]["headers"]["X-File-MD5"]);
+ public function testNullHash(): void {
+ $bodyObject = self::getValidBodyObject();
+ unset($bodyObject['0']['headers']['OC-Checksum']);
+ unset($bodyObject['0']['headers']['X-File-MD5']);
$multipartParser = $this->getMultipartParser(
$bodyObject
);
- $this->expectExceptionMessage('The X-File-MD5 header must not be null.');
+ $this->expectExceptionMessage('The hash headers must not be null.');
$multipartParser->parseNextPart();
}
/**
* Test with a null Content-Length.
*/
- public function testNullContentLength() {
- $bodyObject = $this->getValidBodyObject();
- unset($bodyObject["0"]["headers"]["Content-Length"]);
+ public function testNullContentLength(): void {
+ $bodyObject = self::getValidBodyObject();
+ unset($bodyObject['0']['headers']['Content-Length']);
$multipartParser = $this->getMultipartParser(
$bodyObject
);
@@ -160,36 +201,36 @@ class MultipartRequestParserTest extends TestCase {
/**
* Test with a lower Content-Length.
*/
- public function testLowerContentLength() {
- $bodyObject = $this->getValidBodyObject();
- $bodyObject["0"]["headers"]["Content-Length"] = 6;
+ public function testLowerContentLength(): void {
+ $bodyObject = self::getValidBodyObject();
+ $bodyObject['0']['headers']['Content-Length'] = 6;
$multipartParser = $this->getMultipartParser(
$bodyObject
);
- $this->expectExceptionMessage('Computed md5 hash is incorrect.');
+ $this->expectExceptionMessage('Computed md5 hash is incorrect (41060d3ddfdf63e68fc2bf196f652ee9).');
$multipartParser->parseNextPart();
}
/**
* Test with a higher Content-Length.
*/
- public function testHigherContentLength() {
- $bodyObject = $this->getValidBodyObject();
- $bodyObject["0"]["headers"]["Content-Length"] = 8;
+ public function testHigherContentLength(): void {
+ $bodyObject = self::getValidBodyObject();
+ $bodyObject['0']['headers']['Content-Length'] = 8;
$multipartParser = $this->getMultipartParser(
$bodyObject
);
- $this->expectExceptionMessage('Computed md5 hash is incorrect.');
+ $this->expectExceptionMessage('Computed md5 hash is incorrect (0161002bbee6a744f18741b8a914e413).');
$multipartParser->parseNextPart();
}
/**
* Test with wrong boundary in body.
*/
- public function testWrongBoundary() {
- $bodyObject = $this->getValidBodyObject();
+ public function testWrongBoundary(): void {
+ $bodyObject = self::getValidBodyObject();
$multipartParser = $this->getMultipartParser(
$bodyObject,
['Content-Type' => 'multipart/related; boundary=boundary_poiuytreza']
@@ -202,8 +243,8 @@ class MultipartRequestParserTest extends TestCase {
/**
* Test with no boundary in request headers.
*/
- public function testNoBoundaryInHeader() {
- $bodyObject = $this->getValidBodyObject();
+ public function testNoBoundaryInHeader(): void {
+ $bodyObject = self::getValidBodyObject();
$this->expectExceptionMessage('Error while parsing boundary in Content-Type header.');
$this->getMultipartParser(
$bodyObject,
@@ -214,8 +255,8 @@ class MultipartRequestParserTest extends TestCase {
/**
* Test with no boundary in the request's headers.
*/
- public function testNoBoundaryInBody() {
- $bodyObject = $this->getValidBodyObject();
+ public function testNoBoundaryInBody(): void {
+ $bodyObject = self::getValidBodyObject();
$multipartParser = $this->getMultipartParser(
$bodyObject,
['Content-Type' => 'multipart/related; boundary=boundary_azertyuiop'],
@@ -229,8 +270,8 @@ class MultipartRequestParserTest extends TestCase {
/**
* Test with a boundary with quotes in the request's headers.
*/
- public function testBoundaryWithQuotes() {
- $bodyObject = $this->getValidBodyObject();
+ public function testBoundaryWithQuotes(): void {
+ $bodyObject = self::getValidBodyObject();
$multipartParser = $this->getMultipartParser(
$bodyObject,
['Content-Type' => 'multipart/related; boundary="boundary_azertyuiop"'],
@@ -245,8 +286,8 @@ class MultipartRequestParserTest extends TestCase {
/**
* Test with a wrong Content-Type in the request's headers.
*/
- public function testWrongContentType() {
- $bodyObject = $this->getValidBodyObject();
+ public function testWrongContentType(): void {
+ $bodyObject = self::getValidBodyObject();
$this->expectExceptionMessage('Content-Type must be multipart/related');
$this->getMultipartParser(
$bodyObject,
@@ -257,8 +298,8 @@ class MultipartRequestParserTest extends TestCase {
/**
* Test with a wrong key after the content type in the request's headers.
*/
- public function testWrongKeyInContentType() {
- $bodyObject = $this->getValidBodyObject();
+ public function testWrongKeyInContentType(): void {
+ $bodyObject = self::getValidBodyObject();
$this->expectExceptionMessage('Boundary is invalid');
$this->getMultipartParser(
$bodyObject,
@@ -269,8 +310,8 @@ class MultipartRequestParserTest extends TestCase {
/**
* Test with a null Content-Type in the request's headers.
*/
- public function testNullContentType() {
- $bodyObject = $this->getValidBodyObject();
+ public function testNullContentType(): void {
+ $bodyObject = self::getValidBodyObject();
$this->expectExceptionMessage('Content-Type can not be null');
$this->getMultipartParser(
$bodyObject,
diff --git a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php
index a24125b6804..1a7ab7179e1 100644
--- a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php
+++ b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php
@@ -1,33 +1,19 @@
<?php
+
+declare(strict_types=1);
/**
- * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Georg Ehrke <oc.list@georgehrke.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace OCA\DAV\Tests\Files\Sharing;
+namespace OCA\DAV\Tests\unit\Files\Sharing;
-use OC\Files\View;
use OCA\DAV\Files\Sharing\FilesDropPlugin;
-use Sabre\DAV\Exception\MethodNotAllowed;
+use OCP\Files\Folder;
+use OCP\Files\NotFoundException;
+use OCP\Share\IAttributes;
+use OCP\Share\IShare;
+use PHPUnit\Framework\MockObject\MockObject;
+use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Server;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
@@ -35,148 +21,238 @@ use Test\TestCase;
class FilesDropPluginTest extends TestCase {
- /** @var View|\PHPUnit\Framework\MockObject\MockObject */
- private $view;
-
- /** @var Server|\PHPUnit\Framework\MockObject\MockObject */
- private $server;
-
- /** @var FilesDropPlugin */
- private $plugin;
+ private FilesDropPlugin $plugin;
- /** @var RequestInterface|\PHPUnit\Framework\MockObject\MockObject */
- private $request;
-
- /** @var ResponseInterface|\PHPUnit\Framework\MockObject\MockObject */
- private $response;
+ private Folder&MockObject $node;
+ private IShare&MockObject $share;
+ private Server&MockObject $server;
+ private RequestInterface&MockObject $request;
+ private ResponseInterface&MockObject $response;
protected function setUp(): void {
parent::setUp();
- $this->view = $this->createMock(View::class);
+ $this->node = $this->createMock(Folder::class);
+ $this->node->method('getPath')
+ ->willReturn('/files/token');
+
+ $this->share = $this->createMock(IShare::class);
+ $this->share->expects(self::any())
+ ->method('getNode')
+ ->willReturn($this->node);
$this->server = $this->createMock(Server::class);
$this->plugin = new FilesDropPlugin();
$this->request = $this->createMock(RequestInterface::class);
$this->response = $this->createMock(ResponseInterface::class);
- $this->response->expects($this->never())
- ->method($this->anything());
- }
-
- public function testInitialize() {
- $this->server->expects($this->once())
- ->method('on')
- ->with(
- $this->equalTo('beforeMethod:*'),
- $this->equalTo([$this->plugin, 'beforeMethod']),
- $this->equalTo(999)
- );
+ $attributes = $this->createMock(IAttributes::class);
+ $this->share->expects($this->any())
+ ->method('getAttributes')
+ ->willReturn($attributes);
- $this->plugin->initialize($this->server);
+ $this->share
+ ->method('getToken')
+ ->willReturn('token');
}
- public function testNotEnabled() {
- $this->view->expects($this->never())
- ->method($this->anything());
-
+ public function testNotEnabled(): void {
$this->request->expects($this->never())
->method($this->anything());
$this->plugin->beforeMethod($this->request, $this->response);
}
- public function testValid() {
+ public function testValid(): void {
$this->plugin->enable();
- $this->plugin->setView($this->view);
+ $this->plugin->setShare($this->share);
$this->request->method('getMethod')
->willReturn('PUT');
$this->request->method('getPath')
- ->willReturn('file.txt');
+ ->willReturn('/files/token/file.txt');
$this->request->method('getBaseUrl')
->willReturn('https://example.com');
- $this->view->method('file_exists')
- ->with('/file.txt')
- ->willReturn(false);
+ $this->node->expects(self::once())
+ ->method('getNonExistingName')
+ ->with('file.txt')
+ ->willReturn('file.txt');
$this->request->expects($this->once())
->method('setUrl')
- ->with('https://example.com/file.txt');
+ ->with('https://example.com/files/token/file.txt');
$this->plugin->beforeMethod($this->request, $this->response);
}
- public function testFileAlreadyExistsValid() {
+ public function testFileAlreadyExistsValid(): void {
$this->plugin->enable();
- $this->plugin->setView($this->view);
+ $this->plugin->setShare($this->share);
$this->request->method('getMethod')
->willReturn('PUT');
$this->request->method('getPath')
- ->willReturn('file.txt');
+ ->willReturn('/files/token/file.txt');
$this->request->method('getBaseUrl')
->willReturn('https://example.com');
- $this->view->method('file_exists')
- ->willReturnCallback(function ($path) {
- if ($path === 'file.txt' || $path === '/file.txt') {
- return true;
- } else {
- return false;
- }
- });
+ $this->node->method('getNonExistingName')
+ ->with('file.txt')
+ ->willReturn('file (2).txt');
$this->request->expects($this->once())
->method('setUrl')
- ->with($this->equalTo('https://example.com/file (2).txt'));
+ ->with($this->equalTo('https://example.com/files/token/file (2).txt'));
$this->plugin->beforeMethod($this->request, $this->response);
}
- public function testNoMKCOL() {
+ public function testNoMKCOLWithoutNickname(): void {
$this->plugin->enable();
- $this->plugin->setView($this->view);
+ $this->plugin->setShare($this->share);
$this->request->method('getMethod')
->willReturn('MKCOL');
- $this->expectException(MethodNotAllowed::class);
+ $this->expectException(BadRequest::class);
+
+ $this->plugin->beforeMethod($this->request, $this->response);
+ }
+
+ public function testMKCOLWithNickname(): void {
+ $this->plugin->enable();
+ $this->plugin->setShare($this->share);
+
+ $this->request->method('getMethod')
+ ->willReturn('MKCOL');
+
+ $this->request->method('hasHeader')
+ ->with('X-NC-Nickname')
+ ->willReturn(true);
+ $this->request->method('getHeader')
+ ->with('X-NC-Nickname')
+ ->willReturn('nickname');
+
+ $this->expectNotToPerformAssertions();
$this->plugin->beforeMethod($this->request, $this->response);
}
- public function testNoSubdirPut() {
+ public function testSubdirPut(): void {
$this->plugin->enable();
- $this->plugin->setView($this->view);
+ $this->plugin->setShare($this->share);
$this->request->method('getMethod')
->willReturn('PUT');
+ $this->request->method('hasHeader')
+ ->with('X-NC-Nickname')
+ ->willReturn(true);
+ $this->request->method('getHeader')
+ ->with('X-NC-Nickname')
+ ->willReturn('nickname');
+
$this->request->method('getPath')
- ->willReturn('folder/file.txt');
+ ->willReturn('/files/token/folder/file.txt');
$this->request->method('getBaseUrl')
->willReturn('https://example.com');
- $this->view->method('file_exists')
- ->willReturnCallback(function ($path) {
- if ($path === 'file.txt' || $path === '/file.txt') {
- return true;
- } else {
- return false;
- }
- });
+ $nodeName = $this->createMock(Folder::class);
+ $nodeFolder = $this->createMock(Folder::class);
+ $nodeFolder->expects(self::once())
+ ->method('getPath')
+ ->willReturn('/files/token/nickname/folder');
+ $nodeFolder->method('getNonExistingName')
+ ->with('file.txt')
+ ->willReturn('file.txt');
+ $nodeName->expects(self::once())
+ ->method('get')
+ ->with('folder')
+ ->willThrowException(new NotFoundException());
+ $nodeName->expects(self::once())
+ ->method('newFolder')
+ ->with('folder')
+ ->willReturn($nodeFolder);
+
+ $this->node->expects(self::once())
+ ->method('get')
+ ->willThrowException(new NotFoundException());
+ $this->node->expects(self::once())
+ ->method('newFolder')
+ ->with('nickname')
+ ->willReturn($nodeName);
$this->request->expects($this->once())
->method('setUrl')
- ->with($this->equalTo('https://example.com/file (2).txt'));
+ ->with($this->equalTo('https://example.com/files/token/nickname/folder/file.txt'));
$this->plugin->beforeMethod($this->request, $this->response);
}
+
+ public function testRecursiveFolderCreation(): void {
+ $this->plugin->enable();
+ $this->plugin->setShare($this->share);
+
+ $this->request->method('getMethod')
+ ->willReturn('PUT');
+ $this->request->method('hasHeader')
+ ->with('X-NC-Nickname')
+ ->willReturn(true);
+ $this->request->method('getHeader')
+ ->with('X-NC-Nickname')
+ ->willReturn('nickname');
+
+ $this->request->method('getPath')
+ ->willReturn('/files/token/folder/subfolder/file.txt');
+ $this->request->method('getBaseUrl')
+ ->willReturn('https://example.com');
+
+ $this->request->expects($this->once())
+ ->method('setUrl')
+ ->with($this->equalTo('https://example.com/files/token/nickname/folder/subfolder/file.txt'));
+
+ $subfolder = $this->createMock(Folder::class);
+ $subfolder->expects(self::once())
+ ->method('getNonExistingName')
+ ->with('file.txt')
+ ->willReturn('file.txt');
+ $subfolder->expects(self::once())
+ ->method('getPath')
+ ->willReturn('/files/token/nickname/folder/subfolder');
+
+ $folder = $this->createMock(Folder::class);
+ $folder->expects(self::once())
+ ->method('get')
+ ->with('subfolder')
+ ->willReturn($subfolder);
+
+ $nickname = $this->createMock(Folder::class);
+ $nickname->expects(self::once())
+ ->method('get')
+ ->with('folder')
+ ->willReturn($folder);
+
+ $this->node->method('get')
+ ->with('nickname')
+ ->willReturn($nickname);
+ $this->plugin->beforeMethod($this->request, $this->response);
+ }
+
+ public function testOnMkcol(): void {
+ $this->plugin->enable();
+ $this->plugin->setShare($this->share);
+
+ $this->response->expects($this->once())
+ ->method('setStatus')
+ ->with(201);
+
+ $response = $this->plugin->onMkcol($this->request, $this->response);
+ $this->assertFalse($response);
+ }
}