aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/Files/Node/HookConnectorTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lib/Files/Node/HookConnectorTest.php')
-rw-r--r--tests/lib/Files/Node/HookConnectorTest.php327
1 files changed, 327 insertions, 0 deletions
diff --git a/tests/lib/Files/Node/HookConnectorTest.php b/tests/lib/Files/Node/HookConnectorTest.php
new file mode 100644
index 00000000000..3f3957bab1d
--- /dev/null
+++ b/tests/lib/Files/Node/HookConnectorTest.php
@@ -0,0 +1,327 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+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 OC\Memcache\ArrayCache;
+use OCP\EventDispatcher\GenericEvent as APIGenericEvent;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\Config\IUserMountCache;
+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\ICacheFactory;
+use OCP\IUserManager;
+use OCP\Server;
+use Psr\Log\LoggerInterface;
+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 IEventDispatcher */
+ protected $eventDispatcher;
+
+ private LoggerInterface $logger;
+
+ /** @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 will setup the FS
+ $this->loginAsUser($this->userId);
+ $this->registerMount($this->userId, new Temporary(), '/' . $this->userId . '/files/');
+ $cacheFactory = $this->createMock(ICacheFactory::class);
+ $cacheFactory->method('createLocal')
+ ->willReturnCallback(function () {
+ return new ArrayCache();
+ });
+ $this->view = new View();
+ $this->root = new Root(
+ Filesystem::getMountManager(),
+ $this->view,
+ Server::get(IUserManager::class)->get($this->userId),
+ Server::get(IUserMountCache::class),
+ $this->createMock(LoggerInterface::class),
+ $this->createMock(IUserManager::class),
+ $this->createMock(IEventDispatcher::class),
+ $cacheFactory,
+ );
+ $this->eventDispatcher = Server::get(IEventDispatcher::class);
+ $this->logger = Server::get(LoggerInterface::class);
+ }
+
+ protected function tearDown(): void {
+ parent::tearDown();
+ \OC_Hook::clear('OC_Filesystem');
+ \OC_Util::tearDownFS();
+ }
+
+ public static function viewToNodeProvider(): array {
+ return [
+ [function (): void {
+ Filesystem::file_put_contents('test.txt', 'asd');
+ }, 'preWrite', '\OCP\Files::preWrite', BeforeNodeWrittenEvent::class],
+ [function (): void {
+ Filesystem::file_put_contents('test.txt', 'asd');
+ }, 'postWrite', '\OCP\Files::postWrite', NodeWrittenEvent::class],
+ [function (): void {
+ Filesystem::file_put_contents('test.txt', 'asd');
+ }, 'preCreate', '\OCP\Files::preCreate', BeforeNodeCreatedEvent::class],
+ [function (): void {
+ Filesystem::file_put_contents('test.txt', 'asd');
+ }, 'postCreate', '\OCP\Files::postCreate', NodeCreatedEvent::class],
+ [function (): void {
+ Filesystem::mkdir('test.txt');
+ }, 'preCreate', '\OCP\Files::preCreate', BeforeNodeCreatedEvent::class],
+ [function (): void {
+ Filesystem::mkdir('test.txt');
+ }, 'postCreate', '\OCP\Files::postCreate', NodeCreatedEvent::class],
+ [function (): void {
+ Filesystem::touch('test.txt');
+ }, 'preTouch', '\OCP\Files::preTouch', BeforeNodeTouchedEvent::class],
+ [function (): void {
+ Filesystem::touch('test.txt');
+ }, 'postTouch', '\OCP\Files::postTouch', NodeTouchedEvent::class],
+ [function (): void {
+ Filesystem::touch('test.txt');
+ }, 'preCreate', '\OCP\Files::preCreate', BeforeNodeCreatedEvent::class],
+ [function (): void {
+ Filesystem::touch('test.txt');
+ }, 'postCreate', '\OCP\Files::postCreate', NodeCreatedEvent::class],
+ [function (): void {
+ Filesystem::file_put_contents('test.txt', 'asd');
+ Filesystem::unlink('test.txt');
+ }, 'preDelete', '\OCP\Files::preDelete', BeforeNodeDeletedEvent::class],
+ [function (): void {
+ Filesystem::file_put_contents('test.txt', 'asd');
+ Filesystem::unlink('test.txt');
+ }, 'postDelete', '\OCP\Files::postDelete', NodeDeletedEvent::class],
+ [function (): void {
+ Filesystem::mkdir('test.txt');
+ Filesystem::rmdir('test.txt');
+ }, 'preDelete', '\OCP\Files::preDelete', BeforeNodeDeletedEvent::class],
+ [function (): void {
+ Filesystem::mkdir('test.txt');
+ Filesystem::rmdir('test.txt');
+ }, 'postDelete', '\OCP\Files::postDelete', NodeDeletedEvent::class],
+ ];
+ }
+
+ /**
+ * @param callable $operation
+ * @param string $expectedHook
+ */
+ #[\PHPUnit\Framework\Attributes\DataProvider('viewToNodeProvider')]
+ public function testViewToNode(callable $operation, $expectedHook, $expectedLegacyEvent, $expectedEvent): void {
+ $connector = new HookConnector($this->root, $this->view, $this->eventDispatcher, $this->logger);
+ $connector->viewToNode();
+ $hookCalled = false;
+ /** @var Node $hookNode */
+ $hookNode = null;
+
+ $this->root->listen('\OC\Files', $expectedHook, function ($node) use (&$hookNode, &$hookCalled): void {
+ $hookCalled = true;
+ $hookNode = $node;
+ });
+
+ $dispatcherCalled = false;
+ /** @var Node $dispatcherNode */
+ $dispatcherNode = null;
+ $this->eventDispatcher->addListener($expectedLegacyEvent, function ($event) use (&$dispatcherCalled, &$dispatcherNode): void {
+ /** @var GenericEvent|APIGenericEvent $event */
+ $dispatcherCalled = true;
+ $dispatcherNode = $event->getSubject();
+ });
+
+ $newDispatcherCalled = false;
+ $newDispatcherNode = null;
+ $this->eventDispatcher->addListener($expectedEvent, function ($event) use ($expectedEvent, &$newDispatcherCalled, &$newDispatcherNode): void {
+ 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 static function viewToNodeProviderCopyRename(): array {
+ return [
+ [function (): void {
+ Filesystem::file_put_contents('source', 'asd');
+ Filesystem::rename('source', 'target');
+ }, 'preRename', '\OCP\Files::preRename', BeforeNodeRenamedEvent::class],
+ [function (): void {
+ Filesystem::file_put_contents('source', 'asd');
+ Filesystem::rename('source', 'target');
+ }, 'postRename', '\OCP\Files::postRename', NodeRenamedEvent::class],
+ [function (): void {
+ Filesystem::file_put_contents('source', 'asd');
+ Filesystem::copy('source', 'target');
+ }, 'preCopy', '\OCP\Files::preCopy', BeforeNodeCopiedEvent::class],
+ [function (): void {
+ Filesystem::file_put_contents('source', 'asd');
+ Filesystem::copy('source', 'target');
+ }, 'postCopy', '\OCP\Files::postCopy', NodeCopiedEvent::class],
+ ];
+ }
+
+ /**
+ * @param callable $operation
+ * @param string $expectedHook
+ */
+ #[\PHPUnit\Framework\Attributes\DataProvider('viewToNodeProviderCopyRename')]
+ public function testViewToNodeCopyRename(callable $operation, $expectedHook, $expectedLegacyEvent, $expectedEvent): void {
+ $connector = new HookConnector($this->root, $this->view, $this->eventDispatcher, $this->logger);
+ $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): void {
+ $hookCalled = true;
+ $hookSourceNode = $sourceNode;
+ $hookTargetNode = $targetNode;
+ });
+
+ $dispatcherCalled = false;
+ /** @var Node $dispatcherSourceNode */
+ $dispatcherSourceNode = null;
+ /** @var Node $dispatcherTargetNode */
+ $dispatcherTargetNode = null;
+ $this->eventDispatcher->addListener($expectedLegacyEvent, function ($event) use (&$dispatcherSourceNode, &$dispatcherTargetNode, &$dispatcherCalled): void {
+ /** @var GenericEvent|APIGenericEvent $event */
+ $dispatcherCalled = true;
+ [$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): void {
+ 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(): void {
+ $connector = new HookConnector($this->root, $this->view, $this->eventDispatcher, $this->logger);
+ $connector->viewToNode();
+ $hookCalled = false;
+ /** @var Node $hookNode */
+ $hookNode = null;
+
+ $this->root->listen('\OC\Files', 'postDelete', function ($node) use (&$hookNode, &$hookCalled): void {
+ $hookCalled = true;
+ $hookNode = $node;
+ });
+
+ $dispatcherCalled = false;
+ /** @var Node $dispatcherNode */
+ $dispatcherNode = null;
+ $this->eventDispatcher->addListener('\OCP\Files::postDelete', function ($event) use (&$dispatcherCalled, &$dispatcherNode): void {
+ /** @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): void {
+ 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());
+ }
+}