From da889ff029446119cf6159e75c48ef83be7de7e8 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 25 Mar 2014 16:37:46 +0100 Subject: [PATCH] Added experimental switch to count external storage data in quota This includes all mountpoints except the Shared one in the used space calculation. Added unit tests for ext storage inclusion in quota calculation --- config/config.sample.php | 4 +- lib/private/files/view.php | 8 +- lib/private/helper.php | 47 ++++++++++- tests/lib/helperstorage.php | 151 ++++++++++++++++++++++++++++++------ 4 files changed, 183 insertions(+), 27 deletions(-) diff --git a/config/config.sample.php b/config/config.sample.php index 0a81543589..4b1ab2fce5 100755 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -291,6 +291,9 @@ $CONFIG = array( */ 'cache_path' => '', +/* EXPERIMENTAL: option whether to include external storage in quota calculation, defaults to false */ +'quota_include_external_storage' => false, + /* * specifies how often the filesystem is checked for changes made outside owncloud * 0 -> never check the filesystem for outside changes, provides a performance increase when it's certain that no changes are made directly to the filesystem @@ -301,5 +304,4 @@ $CONFIG = array( /* If true, prevent owncloud from changing the cache due to changes in the filesystem for all storage */ 'filesystem_cache_readonly' => false, - ); diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 0b8d336f26..2e189d12db 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -807,7 +807,8 @@ class View { * get the filesystem info * * @param string $path - * @param boolean $includeMountPoints whether to add mountpoint sizes, + * @param boolean|string $includeMountPoints true to add mountpoint sizes, + * 'ext' to add only ext storage mount point sizes. Defaults to true. * defaults to true * @return \OC\Files\FileInfo|false */ @@ -847,10 +848,15 @@ class View { if ($data and isset($data['fileid'])) { if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') { //add the sizes of other mountpoints to the folder + $extOnly = ($includeMountPoints === 'ext'); $mountPoints = Filesystem::getMountPoints($path); foreach ($mountPoints as $mountPoint) { $subStorage = Filesystem::getStorage($mountPoint); if ($subStorage) { + // exclude shared storage ? + if ($extOnly && $subStorage instanceof \OC\Files\Storage\Shared) { + continue; + } $subCache = $subStorage->getCache(''); $rootEntry = $subCache->get(''); $data['size'] += isset($rootEntry['size']) ? $rootEntry['size'] : 0; diff --git a/lib/private/helper.php b/lib/private/helper.php index 9ac07bbd3b..a054fc485a 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -936,6 +936,8 @@ class OC_Helper { */ public static function getStorageInfo($path, $rootInfo = null) { // return storage info without adding mount points + $includeExtStorage = \OC_Config::getValue('quota_include_external_storage', false); + if (is_null($rootInfo)) { $rootInfo = \OC\Files\Filesystem::getFileInfo($path, false); } @@ -944,8 +946,20 @@ class OC_Helper { $used = 0; } $quota = 0; - // TODO: need a better way to get total space from storage $storage = $rootInfo->getStorage(); + if ($includeExtStorage && $storage->instanceOfStorage('\OC\Files\Storage\Shared')) { + $includeExtStorage = false; + } + if ($includeExtStorage) { + $quota = OC_Util::getUserQuota(\OCP\User::getUser()); + if ($quota !== \OC\Files\SPACE_UNLIMITED) { + // always get free space / total space from root + mount points + $path = ''; + return self::getGlobalStorageInfo(); + } + } + + // TODO: need a better way to get total space from storage if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')) { $quota = $storage->getQuota(); } @@ -967,4 +981,35 @@ class OC_Helper { return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative); } + + /** + * Get storage info including all mount points and quota + * + * @return array + */ + private static function getGlobalStorageInfo() { + $quota = OC_Util::getUserQuota(\OCP\User::getUser()); + + $rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext'); + $used = $rootInfo['size']; + if ($used < 0) { + $used = 0; + } + + $total = $quota; + $free = $quota - $used; + + if ($total > 0) { + if ($quota > 0 && $total > $quota) { + $total = $quota; + } + // prevent division by zero or error codes (negative values) + $relative = round(($used / $total) * 10000) / 100; + } else { + $relative = 0; + } + + return array('free' => $free, 'used' => $used, 'total' => $total, 'relative' => $relative); + + } } diff --git a/tests/lib/helperstorage.php b/tests/lib/helperstorage.php index 010a54e3bb..4fdd9dd6b9 100644 --- a/tests/lib/helperstorage.php +++ b/tests/lib/helperstorage.php @@ -15,35 +15,58 @@ class Test_Helper_Storage extends PHPUnit_Framework_TestCase { public function setUp() { $this->user = 'user_' . uniqid(); - \OC\Files\Filesystem::tearDown(); - \OC\Files\Filesystem::init($this->user, '/' . $this->user . '/files'); + \OC_User::createUser($this->user, $this->user); + \OC\Files\Filesystem::tearDown(); + \OC_User::setUserId($this->user); + \OC\Files\Filesystem::init($this->user, '/' . $this->user . '/files'); + \OC\Files\Filesystem::clearMounts(); + + $this->storageMock = null; + } + + public function tearDown() { + $this->user = null; + + if ($this->storageMock) { + $this->storageMock->getCache()->clear(); + $this->storageMock = null; + } + \OC\Files\Filesystem::tearDown(); + + \OC_User::setUserId(''); + \OC_User::deleteUser($this->user); + \OC_Preferences::deleteUser($this->user); + } + + /** + * Returns a storage mock that returns the given value as + * free space + * + * @param int $freeSpace free space value + * @return \OC\Files\Storage\Storage + */ + private function getStorageMock($freeSpace = 12) { $this->storageMock = $this->getMock( '\OC\Files\Storage\Temporary', array('free_space'), array('') ); - \OC\Files\Filesystem::clearMounts(); $this->storageMock->expects($this->once()) ->method('free_space') ->will($this->returnValue(12)); - } - - public function tearDown() { - $this->user = null; - - $this->storageMock->getCache()->clear(); - \OC\Files\Filesystem::tearDown(); + return $this->storageMock; } /** * Test getting the storage info */ function testGetStorageInfo() { - \OC\Files\Filesystem::mount($this->storageMock, array(), '/' . $this->user . '/files'); - $this->storageMock->file_put_contents('test.txt', '01234'); + $homeStorage = $this->getStorageMock(12); + \OC\Files\Filesystem::mount($homeStorage, array(), '/' . $this->user . '/files'); + $homeStorage->file_put_contents('test.txt', '01234'); $storageInfo = \OC_Helper::getStorageInfo(''); $this->assertEquals(12, $storageInfo['free']); @@ -51,18 +74,96 @@ class Test_Helper_Storage extends PHPUnit_Framework_TestCase { $this->assertEquals(17, $storageInfo['total']); } + /** + * Test getting the storage info, ignoring extra mount points + */ + function testGetStorageInfoExcludingExtStorage() { + $homeStorage = $this->getStorageMock(12); + \OC\Files\Filesystem::mount($homeStorage, array(), '/' . $this->user . '/files'); + $homeStorage->file_put_contents('test.txt', '01234'); + + $extStorage = new \OC\Files\Storage\Temporary(array()); + $extStorage->file_put_contents('extfile.txt', 'abcdefghijklmnopq'); + $extStorage->getScanner()->scan(''); // update root size + + \OC\Files\Filesystem::mount($extStorage, array(), '/' . $this->user . '/files/ext'); + + $storageInfo = \OC_Helper::getStorageInfo(''); + $this->assertEquals(12, $storageInfo['free']); + $this->assertEquals(5, $storageInfo['used']); + $this->assertEquals(17, $storageInfo['total']); + } + + /** + * Test getting the storage info, including extra mount points + */ + function testGetStorageInfoIncludingExtStorage() { + $homeStorage = new \OC\Files\Storage\Temporary(array()); + \OC\Files\Filesystem::mount($homeStorage, array(), '/' . $this->user . '/files'); + $homeStorage->file_put_contents('test.txt', '01234'); + + $extStorage = new \OC\Files\Storage\Temporary(array()); + $extStorage->file_put_contents('extfile.txt', 'abcdefghijklmnopq'); + $extStorage->getScanner()->scan(''); // update root size + + \OC\Files\Filesystem::mount($extStorage, array(), '/' . $this->user . '/files/ext'); + + $oldConfig = \OC_Config::getValue('quota_include_external_storage', false); + \OC_Config::setValue('quota_include_external_storage', 'true'); + + $config = \OC::$server->getConfig(); + $userQuota = $config->setUserValue($this->user, 'files', 'quota', '25'); + + $storageInfo = \OC_Helper::getStorageInfo(''); + $this->assertEquals(3, $storageInfo['free']); + $this->assertEquals(22, $storageInfo['used']); + $this->assertEquals(25, $storageInfo['total']); + + \OC_Config::setValue('quota_include_external_storage', $oldConfig); + $userQuota = $config->setUserValue($this->user, 'files', 'quota', 'default'); + } + + /** + * Test getting the storage info excluding extra mount points + * when user has no quota set, even when quota ext storage option + * was set + */ + function testGetStorageInfoIncludingExtStorageWithNoUserQuota() { + $homeStorage = $this->getStorageMock(12); + \OC\Files\Filesystem::mount($homeStorage, array(), '/' . $this->user . '/files'); + $homeStorage->file_put_contents('test.txt', '01234'); + + $extStorage = new \OC\Files\Storage\Temporary(array()); + $extStorage->file_put_contents('extfile.txt', 'abcdefghijklmnopq'); + $extStorage->getScanner()->scan(''); // update root size + + \OC\Files\Filesystem::mount($extStorage, array(), '/' . $this->user . '/files/ext'); + + $oldConfig = \OC_Config::getValue('quota_include_external_storage', false); + \OC_Config::setValue('quota_include_external_storage', 'true'); + + $storageInfo = \OC_Helper::getStorageInfo(''); + $this->assertEquals(12, $storageInfo['free']); + $this->assertEquals(5, $storageInfo['used']); + $this->assertEquals(17, $storageInfo['total']); + + \OC_Config::setValue('quota_include_external_storage', $oldConfig); + } + + /** * Test getting the storage info with quota enabled */ function testGetStorageInfoWithQuota() { - $this->storageMock->file_put_contents('test.txt', '01234'); - $this->storageMock = new \OC\Files\Storage\Wrapper\Quota( + $homeStorage = $this->getStorageMock(12); + $homeStorage->file_put_contents('test.txt', '01234'); + $homeStorage = new \OC\Files\Storage\Wrapper\Quota( array( - 'storage' => $this->storageMock, + 'storage' => $homeStorage, 'quota' => 7 ) ); - \OC\Files\Filesystem::mount($this->storageMock, array(), '/' . $this->user . '/files'); + \OC\Files\Filesystem::mount($homeStorage, array(), '/' . $this->user . '/files'); $storageInfo = \OC_Helper::getStorageInfo(''); $this->assertEquals(2, $storageInfo['free']); @@ -74,14 +175,15 @@ class Test_Helper_Storage extends PHPUnit_Framework_TestCase { * Test getting the storage info when data exceeds quota */ function testGetStorageInfoWhenSizeExceedsQuota() { - $this->storageMock->file_put_contents('test.txt', '0123456789'); - $this->storageMock = new \OC\Files\Storage\Wrapper\Quota( + $homeStorage = $this->getStorageMock(12); + $homeStorage->file_put_contents('test.txt', '0123456789'); + $homeStorage = new \OC\Files\Storage\Wrapper\Quota( array( - 'storage' => $this->storageMock, + 'storage' => $homeStorage, 'quota' => 7 ) ); - \OC\Files\Filesystem::mount($this->storageMock, array(), '/' . $this->user . '/files'); + \OC\Files\Filesystem::mount($homeStorage, array(), '/' . $this->user . '/files'); $storageInfo = \OC_Helper::getStorageInfo(''); $this->assertEquals(0, $storageInfo['free']); @@ -95,14 +197,15 @@ class Test_Helper_Storage extends PHPUnit_Framework_TestCase { * free storage space is less than the quota */ function testGetStorageInfoWhenFreeSpaceLessThanQuota() { - $this->storageMock->file_put_contents('test.txt', '01234'); - $this->storageMock = new \OC\Files\Storage\Wrapper\Quota( + $homeStorage = $this->getStorageMock(12); + $homeStorage->file_put_contents('test.txt', '01234'); + $homeStorage = new \OC\Files\Storage\Wrapper\Quota( array( - 'storage' => $this->storageMock, + 'storage' => $homeStorage, 'quota' => 18 ) ); - \OC\Files\Filesystem::mount($this->storageMock, array(), '/' . $this->user . '/files'); + \OC\Files\Filesystem::mount($homeStorage, array(), '/' . $this->user . '/files'); $storageInfo = \OC_Helper::getStorageInfo(''); $this->assertEquals(12, $storageInfo['free']);