nextcloud/tests/lib/Files/Config/UserMountCacheTest.php

497 lines
15 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\Config;
use OC\DB\QueryBuilder\Literal;
use OC\Files\Mount\MountPoint;
use OC\Files\Storage\Storage;
use OC\Log;
use OC\User\Manager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\ICachedMountInfo;
use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IUserManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Test\TestCase;
use Test\Util\User\Dummy;
/**
* @group DB
*/
class UserMountCacheTest extends TestCase {
/**
* @var IDBConnection
*/
private $connection;
/**
* @var IUserManager
*/
private $userManager;
/**
* @var \OC\Files\Config\UserMountCache
*/
private $cache;
private $fileIds = [];
protected function setUp(): void {
$this->fileIds = [];
$this->connection = \OC::$server->getDatabaseConnection();
$this->userManager = new Manager($this->createMock(IConfig::class), $this->createMock(EventDispatcherInterface::class), $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class));
$userBackend = new Dummy();
$userBackend->createUser('u1', '');
$userBackend->createUser('u2', '');
$userBackend->createUser('u3', '');
$this->userManager->registerBackend($userBackend);
$this->cache = new \OC\Files\Config\UserMountCache($this->connection, $this->userManager, $this->createMock(Log::class));
}
protected function tearDown(): void {
$builder = $this->connection->getQueryBuilder();
$builder->delete('mounts')->execute();
$builder = $this->connection->getQueryBuilder();
foreach ($this->fileIds as $fileId) {
$builder->delete('filecache')
->where($builder->expr()->eq('fileid', new Literal($fileId)))
->execute();
}
}
private function getStorage($storageId) {
$rootId = $this->createCacheEntry('', $storageId);
$storageCache = $this->getMockBuilder('\OC\Files\Cache\Storage')
->disableOriginalConstructor()
->getMock();
$storageCache->expects($this->any())
->method('getNumericId')
->willReturn($storageId);
$cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
->disableOriginalConstructor()
->getMock();
$cache->expects($this->any())
->method('getId')
->willReturn($rootId);
$storage = $this->getMockBuilder('\OC\Files\Storage\Storage')
->disableOriginalConstructor()
->getMock();
$storage->expects($this->any())
->method('getStorageCache')
->willReturn($storageCache);
$storage->expects($this->any())
->method('getCache')
->willReturn($cache);
return [$storage, $rootId];
}
private function clearCache() {
$this->invokePrivate($this->cache, 'mountsForUsers', [[]]);
}
public function testNewMounts() {
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
$mount = new MountPoint($storage, '/asd/');
$this->cache->registerMounts($user, [$mount]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForUser($user);
$this->assertCount(1, $cachedMounts);
$cachedMount = $cachedMounts[0];
$this->assertEquals('/asd/', $cachedMount->getMountPoint());
$this->assertEquals($user, $cachedMount->getUser());
$this->assertEquals($storage->getCache()->getId(''), $cachedMount->getRootId());
$this->assertEquals($storage->getStorageCache()->getNumericId(), $cachedMount->getStorageId());
}
public function testSameMounts() {
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
$mount = new MountPoint($storage, '/asd/');
$this->cache->registerMounts($user, [$mount]);
$this->clearCache();
$this->cache->registerMounts($user, [$mount]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForUser($user);
$this->assertCount(1, $cachedMounts);
$cachedMount = $cachedMounts[0];
$this->assertEquals('/asd/', $cachedMount->getMountPoint());
$this->assertEquals($user, $cachedMount->getUser());
$this->assertEquals($storage->getCache()->getId(''), $cachedMount->getRootId());
$this->assertEquals($storage->getStorageCache()->getNumericId(), $cachedMount->getStorageId());
}
public function testRemoveMounts() {
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
$mount = new MountPoint($storage, '/asd/');
$this->cache->registerMounts($user, [$mount]);
$this->clearCache();
$this->cache->registerMounts($user, []);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForUser($user);
$this->assertCount(0, $cachedMounts);
}
public function testChangeMounts() {
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
$mount = new MountPoint($storage, '/bar/');
$this->cache->registerMounts($user, [$mount]);
$this->clearCache();
$mount = new MountPoint($storage, '/foo/');
$this->cache->registerMounts($user, [$mount]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForUser($user);
$this->assertCount(1, $cachedMounts);
$cachedMount = $cachedMounts[0];
$this->assertEquals('/foo/', $cachedMount->getMountPoint());
}
public function testChangeMountId() {
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
$mount = new MountPoint($storage, '/foo/', null, null, null, null);
$this->cache->registerMounts($user, [$mount]);
$this->clearCache();
$mount = new MountPoint($storage, '/foo/', null, null, null, 1);
$this->cache->registerMounts($user, [$mount]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForUser($user);
$this->assertCount(1, $cachedMounts);
$cachedMount = $cachedMounts[0];
$this->assertEquals(1, $cachedMount->getMountId());
}
public function testGetMountsForUser() {
$user1 = $this->userManager->get('u1');
$user2 = $this->userManager->get('u2');
$user3 = $this->userManager->get('u3');
[$storage1, $id1] = $this->getStorage(1);
[$storage2, $id2] = $this->getStorage(2);
$mount1 = new MountPoint($storage1, '/foo/');
$mount2 = new MountPoint($storage2, '/bar/');
$this->cache->registerMounts($user1, [$mount1, $mount2]);
$this->cache->registerMounts($user2, [$mount2]);
$this->cache->registerMounts($user3, [$mount2]);
$this->clearCache();
$user3->delete();
$cachedMounts = $this->cache->getMountsForUser($user1);
$this->assertCount(2, $cachedMounts);
$this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
$this->assertEquals($user1, $cachedMounts[0]->getUser());
$this->assertEquals($id1, $cachedMounts[0]->getRootId());
$this->assertEquals(1, $cachedMounts[0]->getStorageId());
$this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
$this->assertEquals($user1, $cachedMounts[1]->getUser());
$this->assertEquals($id2, $cachedMounts[1]->getRootId());
$this->assertEquals(2, $cachedMounts[1]->getStorageId());
$cachedMounts = $this->cache->getMountsForUser($user3);
$this->assertEmpty($cachedMounts);
}
public function testGetMountsByStorageId() {
$user1 = $this->userManager->get('u1');
$user2 = $this->userManager->get('u2');
[$storage1, $id1] = $this->getStorage(1);
[$storage2, $id2] = $this->getStorage(2);
$mount1 = new MountPoint($storage1, '/foo/');
$mount2 = new MountPoint($storage2, '/bar/');
$this->cache->registerMounts($user1, [$mount1, $mount2]);
$this->cache->registerMounts($user2, [$mount2]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForStorageId(2);
$this->sortMounts($cachedMounts);
$this->assertCount(2, $cachedMounts);
$this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
$this->assertEquals($user1, $cachedMounts[0]->getUser());
$this->assertEquals($id2, $cachedMounts[0]->getRootId());
$this->assertEquals(2, $cachedMounts[0]->getStorageId());
$this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
$this->assertEquals($user2, $cachedMounts[1]->getUser());
$this->assertEquals($id2, $cachedMounts[1]->getRootId());
$this->assertEquals(2, $cachedMounts[1]->getStorageId());
}
public function testGetMountsByRootId() {
$user1 = $this->userManager->get('u1');
$user2 = $this->userManager->get('u2');
[$storage1, $id1] = $this->getStorage(1);
[$storage2, $id2] = $this->getStorage(2);
$mount1 = new MountPoint($storage1, '/foo/');
$mount2 = new MountPoint($storage2, '/bar/');
$this->cache->registerMounts($user1, [$mount1, $mount2]);
$this->cache->registerMounts($user2, [$mount2]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForRootId($id2);
$this->sortMounts($cachedMounts);
$this->assertCount(2, $cachedMounts);
$this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
$this->assertEquals($user1, $cachedMounts[0]->getUser());
$this->assertEquals($id2, $cachedMounts[0]->getRootId());
$this->assertEquals(2, $cachedMounts[0]->getStorageId());
$this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
$this->assertEquals($user2, $cachedMounts[1]->getUser());
$this->assertEquals($id2, $cachedMounts[1]->getRootId());
$this->assertEquals(2, $cachedMounts[1]->getStorageId());
}
private function sortMounts(&$mounts) {
usort($mounts, function (ICachedMountInfo $a, ICachedMountInfo $b) {
return strcmp($a->getUser()->getUID(), $b->getUser()->getUID());
});
}
private function createCacheEntry($internalPath, $storageId, $size = 0) {
$internalPath = trim($internalPath, '/');
$inserted = $this->connection->insertIfNotExist('*PREFIX*filecache', [
'storage' => $storageId,
'path' => $internalPath,
'path_hash' => md5($internalPath),
'parent' => -1,
'name' => basename($internalPath),
'mimetype' => 0,
'mimepart' => 0,
'size' => $size,
'storage_mtime' => 0,
'encrypted' => 0,
'unencrypted_size' => 0,
'etag' => '',
'permissions' => 31
], ['storage', 'path_hash']);
if ($inserted) {
$id = (int)$this->connection->lastInsertId('*PREFIX*filecache');
$this->fileIds[] = $id;
} else {
$sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` =?';
$query = $this->connection->prepare($sql);
$query->execute([$storageId, md5($internalPath)]);
return (int)$query->fetchOne();
}
return $id;
}
public function testGetMountsForFileIdRootId() {
$user1 = $this->userManager->get('u1');
[$storage1, $rootId] = $this->getStorage(2);
$mount1 = new MountPoint($storage1, '/foo/');
$this->cache->registerMounts($user1, [$mount1]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForFileId($rootId);
$this->assertCount(1, $cachedMounts);
$this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
$this->assertEquals($user1, $cachedMounts[0]->getUser());
$this->assertEquals($rootId, $cachedMounts[0]->getRootId());
$this->assertEquals(2, $cachedMounts[0]->getStorageId());
}
public function testGetMountsForFileIdSubFolder() {
$user1 = $this->userManager->get('u1');
$fileId = $this->createCacheEntry('/foo/bar', 2);
[$storage1, $rootId] = $this->getStorage(2);
$mount1 = new MountPoint($storage1, '/foo/');
$this->cache->registerMounts($user1, [$mount1]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForFileId($fileId);
$this->assertCount(1, $cachedMounts);
$this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
$this->assertEquals($user1, $cachedMounts[0]->getUser());
$this->assertEquals($rootId, $cachedMounts[0]->getRootId());
$this->assertEquals(2, $cachedMounts[0]->getStorageId());
$this->assertEquals('foo/bar', $cachedMounts[0]->getInternalPath());
$this->assertEquals('/foo/foo/bar', $cachedMounts[0]->getPath());
}
public function testGetMountsForFileIdSubFolderMount() {
$user1 = $this->userManager->get('u1');
[$storage1, $rootId] = $this->getStorage(2);
$folderId = $this->createCacheEntry('/foo', 2);
$fileId = $this->createCacheEntry('/foo/bar', 2);
$mount1 = $this->getMockBuilder('\OC\Files\Mount\MountPoint')
->setConstructorArgs([$storage1, '/'])
->setMethods(['getStorageRootId'])
->getMock();
$mount1->expects($this->any())
->method('getStorageRootId')
->willReturn($folderId);
$this->cache->registerMounts($user1, [$mount1]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForFileId($fileId);
$this->assertCount(1, $cachedMounts);
$this->assertEquals('/', $cachedMounts[0]->getMountPoint());
$this->assertEquals($user1, $cachedMounts[0]->getUser());
$this->assertEquals($folderId, $cachedMounts[0]->getRootId());
$this->assertEquals(2, $cachedMounts[0]->getStorageId());
$this->assertEquals('foo', $cachedMounts[0]->getRootInternalPath());
$this->assertEquals('bar', $cachedMounts[0]->getInternalPath());
$this->assertEquals('/bar', $cachedMounts[0]->getPath());
}
public function testGetMountsForFileIdSubFolderMountOutside() {
$user1 = $this->userManager->get('u1');
[$storage1, $rootId] = $this->getStorage(2);
$folderId = $this->createCacheEntry('/foo', 2);
$fileId = $this->createCacheEntry('/bar/asd', 2);
$mount1 = $this->getMockBuilder('\OC\Files\Mount\MountPoint')
->setConstructorArgs([$storage1, '/foo/'])
->setMethods(['getStorageRootId'])
->getMock();
$mount1->expects($this->any())
->method('getStorageRootId')
->willReturn($folderId);
$this->cache->registerMounts($user1, [$mount1]);
$this->cache->registerMounts($user1, [$mount1]);
$this->clearCache();
$cachedMounts = $this->cache->getMountsForFileId($fileId);
$this->assertCount(0, $cachedMounts);
}
public function testGetMountsForFileIdDeletedUser() {
$user1 = $this->userManager->get('u1');
[$storage1, $rootId] = $this->getStorage(2);
$rootId = $this->createCacheEntry('', 2);
$mount1 = new MountPoint($storage1, '/foo/');
$this->cache->registerMounts($user1, [$mount1]);
$user1->delete();
$this->clearCache();
$cachedMounts = $this->cache->getMountsForFileId($rootId);
$this->assertEmpty($cachedMounts);
}
public function testGetUsedSpaceForUsers() {
$user1 = $this->userManager->get('u1');
$user2 = $this->userManager->get('u2');
/** @var Storage $storage1 */
[$storage1, $rootId] = $this->getStorage(2);
$folderId = $this->createCacheEntry('files', 2, 100);
$fileId = $this->createCacheEntry('files/foo', 2, 7);
$storage1->getCache()->put($folderId, ['size' => 100]);
$storage1->getCache()->update($fileId, ['size' => 70]);
$mount1 = $this->getMockBuilder(MountPoint::class)
->setConstructorArgs([$storage1, '/u1/'])
->setMethods(['getStorageRootId', 'getNumericStorageId'])
->getMock();
$mount1->expects($this->any())
->method('getStorageRootId')
->willReturn($rootId);
$mount1->expects($this->any())
->method('getNumericStorageId')
->willReturn(2);
$this->cache->registerMounts($user1, [$mount1]);
$result = $this->cache->getUsedSpaceForUsers([$user1, $user2]);
$this->assertEquals(['u1' => 100], $result);
}
}