mirror of
https://github.com/nextcloud/server.git
synced 2026-02-03 20:41:22 -05:00
Right now if you want to get events via the Node API you have to have a real instance of the Root. Which in turns sets up the whole FS. We should make sure this is done lazy. Else enabling the preview generator for example makes you setup the whole FS on each and every authenticated call. Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
319 lines
11 KiB
PHP
319 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
|
|
* This file is licensed under the Affero General Public License version 3 or
|
|
* later.
|
|
* See the COPYING-README file.
|
|
*/
|
|
|
|
namespace Test\Files\Node;
|
|
|
|
use OC\Files\Filesystem;
|
|
use OC\Files\Node\HookConnector;
|
|
use OC\Files\Node\Root;
|
|
use OC\Files\Storage\Temporary;
|
|
use OC\Files\View;
|
|
use OCP\EventDispatcher\Event;
|
|
use OCP\EventDispatcher\GenericEvent as APIGenericEvent;
|
|
use OCP\EventDispatcher\IEventDispatcher;
|
|
use OCP\Files\Events\Node\AbstractNodeEvent;
|
|
use OCP\Files\Events\Node\AbstractNodesEvent;
|
|
use OCP\Files\Events\Node\BeforeNodeCopiedEvent;
|
|
use OCP\Files\Events\Node\BeforeNodeCreatedEvent;
|
|
use OCP\Files\Events\Node\BeforeNodeDeletedEvent;
|
|
use OCP\Files\Events\Node\BeforeNodeRenamedEvent;
|
|
use OCP\Files\Events\Node\BeforeNodeTouchedEvent;
|
|
use OCP\Files\Events\Node\BeforeNodeWrittenEvent;
|
|
use OCP\Files\Events\Node\NodeCopiedEvent;
|
|
use OCP\Files\Events\Node\NodeCreatedEvent;
|
|
use OCP\Files\Events\Node\NodeDeletedEvent;
|
|
use OCP\Files\Events\Node\NodeRenamedEvent;
|
|
use OCP\Files\Events\Node\NodeTouchedEvent;
|
|
use OCP\Files\Events\Node\NodeWrittenEvent;
|
|
use OCP\Files\Node;
|
|
use OCP\ILogger;
|
|
use OCP\IUserManager;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|
use Symfony\Component\EventDispatcher\GenericEvent;
|
|
use Test\TestCase;
|
|
use Test\Traits\MountProviderTrait;
|
|
use Test\Traits\UserTrait;
|
|
|
|
/**
|
|
* Class HookConnectorTest
|
|
*
|
|
* @group DB
|
|
*
|
|
* @package Test\Files\Node
|
|
*/
|
|
class HookConnectorTest extends TestCase {
|
|
use UserTrait;
|
|
use MountProviderTrait;
|
|
|
|
/** @var EventDispatcherInterface|MockObject */
|
|
protected $legacyDispatcher;
|
|
|
|
/** @var IEventDispatcher */
|
|
protected $eventDispatcher;
|
|
|
|
/** @var View */
|
|
private $view;
|
|
|
|
/** @var Root */
|
|
private $root;
|
|
|
|
/** @var string */
|
|
private $userId;
|
|
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
$this->userId = $this->getUniqueID();
|
|
$this->createUser($this->userId, 'pass');
|
|
$this->registerMount($this->userId, new Temporary(), '/' . $this->userId . '/files/');
|
|
\OC_Util::setupFS($this->userId);
|
|
$this->view = new View();
|
|
$this->root = new Root(
|
|
Filesystem::getMountManager(),
|
|
$this->view,
|
|
\OC::$server->getUserManager()->get($this->userId),
|
|
\OC::$server->getUserMountCache(),
|
|
$this->createMock(ILogger::class),
|
|
$this->createMock(IUserManager::class)
|
|
);
|
|
$this->legacyDispatcher = \OC::$server->getEventDispatcher();
|
|
$this->eventDispatcher = \OC::$server->query(IEventDispatcher::class);
|
|
}
|
|
|
|
protected function tearDown(): void {
|
|
parent::tearDown();
|
|
\OC_Hook::clear('OC_Filesystem');
|
|
\OC_Util::tearDownFS();
|
|
}
|
|
|
|
public function viewToNodeProvider() {
|
|
return [
|
|
[function () {
|
|
Filesystem::file_put_contents('test.txt', 'asd');
|
|
}, 'preWrite', '\OCP\Files::preWrite', BeforeNodeWrittenEvent::class],
|
|
[function () {
|
|
Filesystem::file_put_contents('test.txt', 'asd');
|
|
}, 'postWrite', '\OCP\Files::postWrite', NodeWrittenEvent::class],
|
|
[function () {
|
|
Filesystem::file_put_contents('test.txt', 'asd');
|
|
}, 'preCreate', '\OCP\Files::preCreate', BeforeNodeCreatedEvent::class],
|
|
[function () {
|
|
Filesystem::file_put_contents('test.txt', 'asd');
|
|
}, 'postCreate', '\OCP\Files::postCreate', NodeCreatedEvent::class],
|
|
[function () {
|
|
Filesystem::mkdir('test.txt');
|
|
}, 'preCreate', '\OCP\Files::preCreate', BeforeNodeCreatedEvent::class],
|
|
[function () {
|
|
Filesystem::mkdir('test.txt');
|
|
}, 'postCreate', '\OCP\Files::postCreate', NodeCreatedEvent::class],
|
|
[function () {
|
|
Filesystem::touch('test.txt');
|
|
}, 'preTouch', '\OCP\Files::preTouch', BeforeNodeTouchedEvent::class],
|
|
[function () {
|
|
Filesystem::touch('test.txt');
|
|
}, 'postTouch', '\OCP\Files::postTouch', NodeTouchedEvent::class],
|
|
[function () {
|
|
Filesystem::touch('test.txt');
|
|
}, 'preCreate', '\OCP\Files::preCreate', BeforeNodeCreatedEvent::class],
|
|
[function () {
|
|
Filesystem::touch('test.txt');
|
|
}, 'postCreate', '\OCP\Files::postCreate', NodeCreatedEvent::class],
|
|
[function () {
|
|
Filesystem::file_put_contents('test.txt', 'asd');
|
|
Filesystem::unlink('test.txt');
|
|
}, 'preDelete', '\OCP\Files::preDelete', BeforeNodeDeletedEvent::class],
|
|
[function () {
|
|
Filesystem::file_put_contents('test.txt', 'asd');
|
|
Filesystem::unlink('test.txt');
|
|
}, 'postDelete', '\OCP\Files::postDelete', NodeDeletedEvent::class],
|
|
[function () {
|
|
Filesystem::mkdir('test.txt');
|
|
Filesystem::rmdir('test.txt');
|
|
}, 'preDelete', '\OCP\Files::preDelete', BeforeNodeDeletedEvent::class],
|
|
[function () {
|
|
Filesystem::mkdir('test.txt');
|
|
Filesystem::rmdir('test.txt');
|
|
}, 'postDelete', '\OCP\Files::postDelete', NodeDeletedEvent::class],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param callable $operation
|
|
* @param string $expectedHook
|
|
* @dataProvider viewToNodeProvider
|
|
*/
|
|
public function testViewToNode(callable $operation, $expectedHook, $expectedLegacyEvent, $expectedEvent) {
|
|
$connector = new HookConnector($this->root, $this->view, $this->legacyDispatcher, $this->eventDispatcher);
|
|
$connector->viewToNode();
|
|
$hookCalled = false;
|
|
/** @var Node $hookNode */
|
|
$hookNode = null;
|
|
|
|
$this->root->listen('\OC\Files', $expectedHook, function ($node) use (&$hookNode, &$hookCalled) {
|
|
$hookCalled = true;
|
|
$hookNode = $node;
|
|
});
|
|
|
|
$dispatcherCalled = false;
|
|
/** @var Node $dispatcherNode */
|
|
$dispatcherNode = null;
|
|
$this->legacyDispatcher->addListener($expectedLegacyEvent, function ($event) use (&$dispatcherCalled, &$dispatcherNode) {
|
|
/** @var GenericEvent|APIGenericEvent $event */
|
|
$dispatcherCalled = true;
|
|
$dispatcherNode = $event->getSubject();
|
|
});
|
|
|
|
$newDispatcherCalled = false;
|
|
$newDispatcherNode = null;
|
|
$this->eventDispatcher->addListener($expectedEvent, function ($event) use ($expectedEvent, &$newDispatcherCalled, &$newDispatcherNode) {
|
|
if ($event instanceof $expectedEvent) {
|
|
/** @var AbstractNodeEvent $event */
|
|
$newDispatcherCalled = true;
|
|
$newDispatcherNode = $event->getNode();
|
|
}
|
|
});
|
|
|
|
$operation();
|
|
|
|
$this->assertTrue($hookCalled);
|
|
$this->assertEquals('/' . $this->userId . '/files/test.txt', $hookNode->getPath());
|
|
|
|
$this->assertTrue($dispatcherCalled);
|
|
$this->assertEquals('/' . $this->userId . '/files/test.txt', $dispatcherNode->getPath());
|
|
|
|
$this->assertTrue($newDispatcherCalled);
|
|
$this->assertEquals('/' . $this->userId . '/files/test.txt', $newDispatcherNode->getPath());
|
|
}
|
|
|
|
public function viewToNodeProviderCopyRename() {
|
|
return [
|
|
[function () {
|
|
Filesystem::file_put_contents('source', 'asd');
|
|
Filesystem::rename('source', 'target');
|
|
}, 'preRename', '\OCP\Files::preRename', BeforeNodeRenamedEvent::class],
|
|
[function () {
|
|
Filesystem::file_put_contents('source', 'asd');
|
|
Filesystem::rename('source', 'target');
|
|
}, 'postRename', '\OCP\Files::postRename', NodeRenamedEvent::class],
|
|
[function () {
|
|
Filesystem::file_put_contents('source', 'asd');
|
|
Filesystem::copy('source', 'target');
|
|
}, 'preCopy', '\OCP\Files::preCopy', BeforeNodeCopiedEvent::class],
|
|
[function () {
|
|
Filesystem::file_put_contents('source', 'asd');
|
|
Filesystem::copy('source', 'target');
|
|
}, 'postCopy', '\OCP\Files::postCopy', NodeCopiedEvent::class],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param callable $operation
|
|
* @param string $expectedHook
|
|
* @dataProvider viewToNodeProviderCopyRename
|
|
*/
|
|
public function testViewToNodeCopyRename(callable $operation, $expectedHook, $expectedLegacyEvent, $expectedEvent) {
|
|
$connector = new HookConnector($this->root, $this->view, $this->legacyDispatcher, $this->eventDispatcher);
|
|
$connector->viewToNode();
|
|
$hookCalled = false;
|
|
/** @var Node $hookSourceNode */
|
|
$hookSourceNode = null;
|
|
/** @var Node $hookTargetNode */
|
|
$hookTargetNode = null;
|
|
|
|
$this->root->listen('\OC\Files', $expectedHook, function ($sourceNode, $targetNode) use (&$hookCalled, &$hookSourceNode, &$hookTargetNode) {
|
|
$hookCalled = true;
|
|
$hookSourceNode = $sourceNode;
|
|
$hookTargetNode = $targetNode;
|
|
});
|
|
|
|
$dispatcherCalled = false;
|
|
/** @var Node $dispatcherSourceNode */
|
|
$dispatcherSourceNode = null;
|
|
/** @var Node $dispatcherTargetNode */
|
|
$dispatcherTargetNode = null;
|
|
$this->legacyDispatcher->addListener($expectedLegacyEvent, function ($event) use (&$dispatcherSourceNode, &$dispatcherTargetNode, &$dispatcherCalled) {
|
|
/** @var GenericEvent|APIGenericEvent $event */
|
|
$dispatcherCalled = true;
|
|
list($dispatcherSourceNode, $dispatcherTargetNode) = $event->getSubject();
|
|
});
|
|
|
|
$newDispatcherCalled = false;
|
|
/** @var Node $dispatcherSourceNode */
|
|
$newDispatcherSourceNode = null;
|
|
/** @var Node $dispatcherTargetNode */
|
|
$newDispatcherTargetNode = null;
|
|
$this->eventDispatcher->addListener($expectedEvent, function ($event) use ($expectedEvent, &$newDispatcherSourceNode, &$newDispatcherTargetNode, &$newDispatcherCalled) {
|
|
if ($event instanceof $expectedEvent) {
|
|
/** @var AbstractNodesEvent$event */
|
|
$newDispatcherCalled = true;
|
|
$newDispatcherSourceNode = $event->getSource();
|
|
$newDispatcherTargetNode = $event->getTarget();
|
|
}
|
|
});
|
|
|
|
$operation();
|
|
|
|
$this->assertTrue($hookCalled);
|
|
$this->assertEquals('/' . $this->userId . '/files/source', $hookSourceNode->getPath());
|
|
$this->assertEquals('/' . $this->userId . '/files/target', $hookTargetNode->getPath());
|
|
|
|
$this->assertTrue($dispatcherCalled);
|
|
$this->assertEquals('/' . $this->userId . '/files/source', $dispatcherSourceNode->getPath());
|
|
$this->assertEquals('/' . $this->userId . '/files/target', $dispatcherTargetNode->getPath());
|
|
|
|
$this->assertTrue($newDispatcherCalled);
|
|
$this->assertEquals('/' . $this->userId . '/files/source', $newDispatcherSourceNode->getPath());
|
|
$this->assertEquals('/' . $this->userId . '/files/target', $newDispatcherTargetNode->getPath());
|
|
}
|
|
|
|
public function testPostDeleteMeta() {
|
|
$connector = new HookConnector($this->root, $this->view, $this->legacyDispatcher, $this->eventDispatcher);
|
|
$connector->viewToNode();
|
|
$hookCalled = false;
|
|
/** @var Node $hookNode */
|
|
$hookNode = null;
|
|
|
|
$this->root->listen('\OC\Files', 'postDelete', function ($node) use (&$hookNode, &$hookCalled) {
|
|
$hookCalled = true;
|
|
$hookNode = $node;
|
|
});
|
|
|
|
$dispatcherCalled = false;
|
|
/** @var Node $dispatcherNode */
|
|
$dispatcherNode = null;
|
|
$this->legacyDispatcher->addListener('\OCP\Files::postDelete', function ($event) use (&$dispatcherCalled, &$dispatcherNode) {
|
|
/** @var GenericEvent|APIGenericEvent $event */
|
|
$dispatcherCalled = true;
|
|
$dispatcherNode = $event->getSubject();
|
|
});
|
|
|
|
$newDispatcherCalled = false;
|
|
/** @var Node $dispatcherNode */
|
|
$newDispatcherNode = null;
|
|
$this->eventDispatcher->addListener(NodeDeletedEvent::class, function ($event) use (&$newDispatcherCalled, &$newDispatcherNode) {
|
|
if ($event instanceof NodeDeletedEvent) {
|
|
/** @var AbstractNodeEvent $event */
|
|
$newDispatcherCalled = true;
|
|
$newDispatcherNode = $event->getNode();
|
|
}
|
|
});
|
|
|
|
Filesystem::file_put_contents('test.txt', 'asd');
|
|
$info = Filesystem::getFileInfo('test.txt');
|
|
Filesystem::unlink('test.txt');
|
|
|
|
$this->assertTrue($hookCalled);
|
|
$this->assertEquals($hookNode->getId(), $info->getId());
|
|
|
|
$this->assertTrue($dispatcherCalled);
|
|
$this->assertEquals($dispatcherNode->getId(), $info->getId());
|
|
|
|
$this->assertTrue($newDispatcherCalled);
|
|
$this->assertEquals($newDispatcherNode->getId(), $info->getId());
|
|
}
|
|
}
|