2013-08-12 09:37:15 -04:00
|
|
|
<?php
|
2025-06-30 09:04:05 -04:00
|
|
|
|
2026-06-19 07:06:53 -04:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
2013-08-12 09:37:15 -04:00
|
|
|
/**
|
2024-05-10 09:09:14 -04:00
|
|
|
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
|
|
|
|
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
|
|
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
2013-08-12 09:37:15 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace Test\Files\Utils;
|
|
|
|
|
|
2014-06-02 09:17:00 -04:00
|
|
|
use OC\Files\Filesystem;
|
2014-11-24 09:54:42 -05:00
|
|
|
use OC\Files\Mount\MountPoint;
|
2026-04-08 04:30:36 -04:00
|
|
|
use OC\Files\SetupManager;
|
2013-08-12 09:37:15 -04:00
|
|
|
use OC\Files\Storage\Temporary;
|
2025-06-12 12:31:58 -04:00
|
|
|
use OC\Files\Utils\Scanner;
|
2019-12-11 05:27:05 -05:00
|
|
|
use OCP\EventDispatcher\IEventDispatcher;
|
2016-09-12 15:29:38 -04:00
|
|
|
use OCP\Files\Config\IMountProvider;
|
2025-06-12 12:31:58 -04:00
|
|
|
use OCP\Files\Config\IMountProviderCollection;
|
2015-06-22 08:41:08 -04:00
|
|
|
use OCP\Files\Storage\IStorageFactory;
|
2025-06-12 12:31:58 -04:00
|
|
|
use OCP\IDBConnection;
|
2015-06-22 08:41:08 -04:00
|
|
|
use OCP\IUser;
|
2025-06-12 12:31:58 -04:00
|
|
|
use OCP\IUserManager;
|
|
|
|
|
use OCP\Server;
|
2026-06-19 07:06:53 -04:00
|
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
|
|
|
use PHPUnit\Framework\Attributes\Group;
|
2022-03-21 06:17:14 -04:00
|
|
|
use Psr\Log\LoggerInterface;
|
2026-06-19 07:06:53 -04:00
|
|
|
use Test\TestCase;
|
|
|
|
|
use Test\Util\User\Dummy;
|
2013-08-12 09:37:15 -04:00
|
|
|
|
2025-06-12 12:31:58 -04:00
|
|
|
class TestScanner extends Scanner {
|
2026-06-19 07:06:53 -04:00
|
|
|
/** @var array<string, MountPoint> $mounts */
|
|
|
|
|
private array $mounts = [];
|
|
|
|
|
|
|
|
|
|
public function addMount(MountPoint $mount): void {
|
|
|
|
|
$this->mounts[$mount->getMountPoint()] = $mount;
|
2013-08-12 09:37:15 -04:00
|
|
|
}
|
|
|
|
|
|
2026-04-28 13:29:54 -04:00
|
|
|
#[\Override]
|
2026-06-19 07:06:53 -04:00
|
|
|
protected function getMounts(string $dir): array {
|
2013-08-12 09:37:15 -04:00
|
|
|
return $this->mounts;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-19 07:06:53 -04:00
|
|
|
#[Group('DB')]
|
|
|
|
|
class ScannerTest extends TestCase {
|
|
|
|
|
private Dummy $userBackend;
|
2015-06-22 08:41:08 -04:00
|
|
|
|
2026-04-28 13:29:54 -04:00
|
|
|
#[\Override]
|
2019-11-21 10:40:38 -05:00
|
|
|
protected function setUp(): void {
|
2014-11-12 09:54:41 -05:00
|
|
|
parent::setUp();
|
|
|
|
|
|
2026-06-19 07:06:53 -04:00
|
|
|
$this->userBackend = new Dummy();
|
2025-06-12 12:31:58 -04:00
|
|
|
Server::get(IUserManager::class)->registerBackend($this->userBackend);
|
2015-04-08 06:03:55 -04:00
|
|
|
$this->loginAsUser();
|
2014-11-12 09:54:41 -05:00
|
|
|
}
|
|
|
|
|
|
2026-04-28 13:29:54 -04:00
|
|
|
#[\Override]
|
2019-11-21 10:40:38 -05:00
|
|
|
protected function tearDown(): void {
|
2015-04-08 06:03:55 -04:00
|
|
|
$this->logout();
|
2025-06-12 12:31:58 -04:00
|
|
|
Server::get(IUserManager::class)->removeBackend($this->userBackend);
|
2014-11-12 09:54:41 -05:00
|
|
|
parent::tearDown();
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-12 09:37:15 -04:00
|
|
|
public function testReuseExistingRoot(): void {
|
2020-03-26 04:30:18 -04:00
|
|
|
$storage = new Temporary([]);
|
2014-11-24 09:54:42 -05:00
|
|
|
$mount = new MountPoint($storage, '');
|
2014-06-03 05:34:48 -04:00
|
|
|
Filesystem::getMountManager()->addMount($mount);
|
2013-08-12 09:37:15 -04:00
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
|
|
|
|
|
$storage->mkdir('folder');
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'qwerty');
|
|
|
|
|
$storage->file_put_contents('folder/bar.txt', 'qwerty');
|
|
|
|
|
|
2026-04-08 04:30:36 -04:00
|
|
|
$scanner = new TestScanner(
|
|
|
|
|
Server::get(IUserManager::class)->get(''),
|
|
|
|
|
Server::get(IDBConnection::class),
|
|
|
|
|
$this->createMock(IEventDispatcher::class),
|
|
|
|
|
Server::get(LoggerInterface::class),
|
|
|
|
|
Server::get(SetupManager::class),
|
|
|
|
|
);
|
2013-08-12 09:37:15 -04:00
|
|
|
$scanner->addMount($mount);
|
|
|
|
|
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
$this->assertTrue($cache->inCache('folder/bar.txt'));
|
|
|
|
|
$oldRoot = $cache->get('');
|
|
|
|
|
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
$newRoot = $cache->get('');
|
|
|
|
|
$this->assertEquals($oldRoot, $newRoot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testReuseExistingFile(): void {
|
2020-03-26 04:30:18 -04:00
|
|
|
$storage = new Temporary([]);
|
2014-11-24 09:54:42 -05:00
|
|
|
$mount = new MountPoint($storage, '');
|
2014-06-03 05:34:48 -04:00
|
|
|
Filesystem::getMountManager()->addMount($mount);
|
2013-08-12 09:37:15 -04:00
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
|
|
|
|
|
$storage->mkdir('folder');
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'qwerty');
|
|
|
|
|
$storage->file_put_contents('folder/bar.txt', 'qwerty');
|
|
|
|
|
|
2026-04-08 04:30:36 -04:00
|
|
|
$scanner = new TestScanner(
|
|
|
|
|
Server::get(IUserManager::class)->get(''),
|
|
|
|
|
Server::get(IDBConnection::class),
|
|
|
|
|
$this->createMock(IEventDispatcher::class),
|
|
|
|
|
Server::get(LoggerInterface::class),
|
|
|
|
|
Server::get(SetupManager::class),
|
|
|
|
|
);
|
2013-08-12 09:37:15 -04:00
|
|
|
$scanner->addMount($mount);
|
|
|
|
|
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
$this->assertTrue($cache->inCache('folder/bar.txt'));
|
|
|
|
|
$old = $cache->get('folder/bar.txt');
|
|
|
|
|
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
$new = $cache->get('folder/bar.txt');
|
|
|
|
|
$this->assertEquals($old, $new);
|
|
|
|
|
}
|
2014-06-02 09:17:00 -04:00
|
|
|
|
2015-06-22 08:41:08 -04:00
|
|
|
public function testScanSubMount(): void {
|
|
|
|
|
$uid = $this->getUniqueID();
|
|
|
|
|
$this->userBackend->createUser($uid, 'test');
|
|
|
|
|
|
2016-09-12 15:29:38 -04:00
|
|
|
$mountProvider = $this->createMock(IMountProvider::class);
|
2015-06-22 08:41:08 -04:00
|
|
|
|
2020-03-26 04:30:18 -04:00
|
|
|
$storage = new Temporary([]);
|
2015-06-22 08:41:08 -04:00
|
|
|
$mount = new MountPoint($storage, '/' . $uid . '/files/foo');
|
|
|
|
|
|
|
|
|
|
$mountProvider->expects($this->any())
|
|
|
|
|
->method('getMountsForUser')
|
2020-03-25 17:21:27 -04:00
|
|
|
->willReturnCallback(function (IUser $user, IStorageFactory $storageFactory) use ($mount, $uid) {
|
2015-06-22 08:41:08 -04:00
|
|
|
if ($user->getUID() === $uid) {
|
|
|
|
|
return [$mount];
|
|
|
|
|
} else {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
2020-03-25 17:21:27 -04:00
|
|
|
});
|
2015-06-22 08:41:08 -04:00
|
|
|
|
2025-06-12 12:31:58 -04:00
|
|
|
Server::get(IMountProviderCollection::class)->registerProvider($mountProvider);
|
2015-06-22 08:41:08 -04:00
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
|
|
|
|
|
$storage->mkdir('folder');
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'qwerty');
|
|
|
|
|
$storage->file_put_contents('folder/bar.txt', 'qwerty');
|
|
|
|
|
|
2026-04-08 04:30:36 -04:00
|
|
|
$scanner = new Scanner(
|
|
|
|
|
Server::get(IUserManager::class)->get($uid),
|
|
|
|
|
Server::get(IDBConnection::class),
|
|
|
|
|
Server::get(IEventDispatcher::class),
|
|
|
|
|
Server::get(LoggerInterface::class),
|
|
|
|
|
Server::get(SetupManager::class),
|
|
|
|
|
);
|
2015-06-22 08:41:08 -04:00
|
|
|
|
|
|
|
|
$this->assertFalse($cache->inCache('folder/bar.txt'));
|
|
|
|
|
$scanner->scan('/' . $uid . '/files/foo');
|
|
|
|
|
$this->assertTrue($cache->inCache('folder/bar.txt'));
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-19 07:06:53 -04:00
|
|
|
public static function invalidPathProvider(): \Generator {
|
|
|
|
|
yield [ '../' ];
|
|
|
|
|
yield [ '..\\' ];
|
|
|
|
|
yield [ '../..\\../' ];
|
2015-07-27 05:18:41 -04:00
|
|
|
}
|
|
|
|
|
|
2026-06-19 07:06:53 -04:00
|
|
|
#[DataProvider(methodName: 'invalidPathProvider')]
|
|
|
|
|
public function testInvalidPathScanning(string $invalidPath): void {
|
2019-11-27 09:27:18 -05:00
|
|
|
$this->expectException(\InvalidArgumentException::class);
|
|
|
|
|
$this->expectExceptionMessage('Invalid path to scan');
|
|
|
|
|
|
2026-04-08 04:30:36 -04:00
|
|
|
$scanner = new TestScanner(
|
|
|
|
|
Server::get(IUserManager::class)->get(''),
|
|
|
|
|
Server::get(IDBConnection::class),
|
|
|
|
|
$this->createMock(IEventDispatcher::class),
|
|
|
|
|
Server::get(LoggerInterface::class),
|
|
|
|
|
Server::get(SetupManager::class),
|
|
|
|
|
);
|
2015-07-27 05:18:41 -04:00
|
|
|
$scanner->scan($invalidPath);
|
|
|
|
|
}
|
2016-04-25 11:23:48 -04:00
|
|
|
|
|
|
|
|
public function testPropagateEtag(): void {
|
2020-03-26 04:30:18 -04:00
|
|
|
$storage = new Temporary([]);
|
2016-04-25 11:23:48 -04:00
|
|
|
$mount = new MountPoint($storage, '');
|
|
|
|
|
Filesystem::getMountManager()->addMount($mount);
|
|
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
|
|
|
|
|
$storage->mkdir('folder');
|
|
|
|
|
$storage->file_put_contents('folder/bar.txt', 'qwerty');
|
|
|
|
|
$storage->touch('folder/bar.txt', time() - 200);
|
|
|
|
|
|
2026-04-08 04:30:36 -04:00
|
|
|
$scanner = new TestScanner(
|
|
|
|
|
Server::get(IUserManager::class)->get(''),
|
|
|
|
|
Server::get(IDBConnection::class),
|
|
|
|
|
$this->createMock(IEventDispatcher::class),
|
|
|
|
|
Server::get(LoggerInterface::class),
|
|
|
|
|
Server::get(SetupManager::class),
|
|
|
|
|
);
|
2016-04-25 11:23:48 -04:00
|
|
|
$scanner->addMount($mount);
|
|
|
|
|
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
$this->assertTrue($cache->inCache('folder/bar.txt'));
|
|
|
|
|
$oldRoot = $cache->get('');
|
|
|
|
|
|
|
|
|
|
$storage->file_put_contents('folder/bar.txt', 'qwerty');
|
|
|
|
|
$scanner->scan('');
|
|
|
|
|
$newRoot = $cache->get('');
|
|
|
|
|
|
|
|
|
|
$this->assertNotEquals($oldRoot->getEtag(), $newRoot->getEtag());
|
|
|
|
|
}
|
2016-11-10 09:44:18 -05:00
|
|
|
|
2018-05-18 17:51:08 -04:00
|
|
|
public function testShallow(): void {
|
2020-03-26 04:30:18 -04:00
|
|
|
$storage = new Temporary([]);
|
2018-05-18 17:51:08 -04:00
|
|
|
$mount = new MountPoint($storage, '');
|
|
|
|
|
Filesystem::getMountManager()->addMount($mount);
|
|
|
|
|
$cache = $storage->getCache();
|
|
|
|
|
|
|
|
|
|
$storage->mkdir('folder');
|
|
|
|
|
$storage->mkdir('folder/subfolder');
|
|
|
|
|
$storage->file_put_contents('foo.txt', 'qwerty');
|
|
|
|
|
$storage->file_put_contents('folder/bar.txt', 'qwerty');
|
|
|
|
|
$storage->file_put_contents('folder/subfolder/foobar.txt', 'qwerty');
|
|
|
|
|
|
2026-04-08 04:30:36 -04:00
|
|
|
$scanner = new TestScanner(
|
|
|
|
|
Server::get(IUserManager::class)->get(''),
|
|
|
|
|
Server::get(IDBConnection::class),
|
|
|
|
|
$this->createMock(IEventDispatcher::class),
|
|
|
|
|
Server::get(LoggerInterface::class),
|
|
|
|
|
Server::get(SetupManager::class),
|
|
|
|
|
);
|
2018-05-18 17:51:08 -04:00
|
|
|
$scanner->addMount($mount);
|
|
|
|
|
|
2026-06-19 07:06:53 -04:00
|
|
|
$scanner->scan('', false);
|
2018-05-18 17:51:08 -04:00
|
|
|
$this->assertTrue($cache->inCache('folder'));
|
|
|
|
|
$this->assertFalse($cache->inCache('folder/subfolder'));
|
|
|
|
|
$this->assertTrue($cache->inCache('foo.txt'));
|
|
|
|
|
$this->assertFalse($cache->inCache('folder/bar.txt'));
|
|
|
|
|
$this->assertFalse($cache->inCache('folder/subfolder/foobar.txt'));
|
|
|
|
|
|
2026-06-19 07:06:53 -04:00
|
|
|
$scanner->scan('folder', false);
|
2018-05-18 17:51:08 -04:00
|
|
|
$this->assertTrue($cache->inCache('folder'));
|
|
|
|
|
$this->assertTrue($cache->inCache('folder/subfolder'));
|
|
|
|
|
$this->assertTrue($cache->inCache('foo.txt'));
|
|
|
|
|
$this->assertTrue($cache->inCache('folder/bar.txt'));
|
|
|
|
|
$this->assertFalse($cache->inCache('folder/subfolder/foobar.txt'));
|
|
|
|
|
}
|
2013-08-12 09:37:15 -04:00
|
|
|
}
|