Skip to content

Commit

Permalink
Refactor Trashbin::calculateFreeSpace to be testable
Browse files Browse the repository at this point in the history
  • Loading branch information
VicDeo committed Jan 11, 2018
1 parent 728a085 commit 1a7dc7d
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 58 deletions.
15 changes: 13 additions & 2 deletions apps/files_trashbin/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* @author Roeland Jago Douma <rullzer@owncloud.com>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Viktar Dubiniuk <dubiniuk@owncloud.com>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @license AGPL-3.0
Expand All @@ -23,6 +23,7 @@
namespace OCA\Files_Trashbin\AppInfo;

use OCA\Files_Trashbin\Expiration;
use OCA\Files_Trashbin\Quota;
use OCP\AppFramework\App;

class Application extends App {
Expand All @@ -39,10 +40,20 @@ public function __construct (array $urlParams = []) {
* Register expiration
*/
$container->registerService('Expiration', function($c) {
return new Expiration(
return new Expiration(
$c->query('ServerContainer')->getConfig(),
$c->query('OCP\AppFramework\Utility\ITimeFactory')
);
});

/*
* Register quota
*/
$container->registerService('Quota', function($c) {
return new Quota(
$c->getServer()->getUserManager(),
$c->query('ServerContainer')->getConfig()
);
});
}
}
105 changes: 105 additions & 0 deletions apps/files_trashbin/lib/Quota.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php
/**
* @author Viktar Dubiniuk <dubiniuk@owncloud.com>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCA\Files_Trashbin;

use OC\Files\Filesystem;
use OCP\Files\FileInfo;
use OCP\IConfig;
use OCP\IUserManager;
use OCP\IUser;

class Quota {

// percent of free disk space/quota that triggers trashbin cleanup by default
const DEFAULTMAXSIZE = 50;

/** @var IUserManager */
protected $userManager;

/** @var IConfig */
protected $config;

public function __construct(IUserManager $userManager, IConfig $config){
$this->userManager = $userManager;
$this->config = $config;
}

/**
* Calculate remaining free space for trash bin
*
* @param integer $trashbinSize current size of the trash bin
* @param string $user
* @return int available free space for trash bin
*/
public function calculateFreeSpace($trashbinSize, $user) {
$userObject = $this->userManager->get($user);
if(is_null($userObject)) {
return 0;
}
$quota = $this->getUserQuota($userObject);

$userFolder = \OC::$server->getUserFolder($user);
if(is_null($userFolder)) {
return 0;
}

$free = $quota - $userFolder->getSize(); // remaining free space for user
if ($free > 0) {
// does trashbin size hit purge limit with the current free space
$availableSpace = ($free * $this->getPurgeLimit() / 100) - $trashbinSize;
} else {
$availableSpace = $free - $trashbinSize;
}

return $availableSpace;
}

/**
* Get a percentage of free space that should trigger
* cleanup for outdated files in trashbin
*
* @return int
*/
public function getPurgeLimit(){
return $this->config->getSystemValue('trashbin_purge_limit', self::DEFAULTMAXSIZE);
}


/**
* Get user quota or free space when there is no quota set
*
* @param IUser $user
* @return int|mixed
*/
protected function getUserQuota(IUser $user) {
$quota = \OC_Util::getUserQuota($user);
if ($quota === FileInfo::SPACE_UNLIMITED) {
$quota = Filesystem::free_space('/');
// inf or unknown free space
if ($quota < 0) {
$quota = PHP_INT_MAX;
}
}

return $quota;
}
}
74 changes: 18 additions & 56 deletions apps/files_trashbin/lib/Trashbin.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* @author Sjors van der Pluijm <sjors@desjors.nl>
* @author Steven Bühner <buehner@me.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
* @author Viktar Dubiniuk <dubiniuk@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
Expand Down Expand Up @@ -46,9 +46,6 @@

class Trashbin {

// unit: percentage; 50% of available disk space/quota
const DEFAULTMAXSIZE = 50;

/**
* Whether versions have already be rescanned during this PHP request
*
Expand Down Expand Up @@ -664,8 +661,6 @@ public static function file_exists($filename, $timestamp = null) {

if ($timestamp) {
$filename = $filename . '.d' . $timestamp;
} else {
$filename = $filename;
}

$target = Filesystem::normalizePath('files_trashbin/files/' . $filename);
Expand All @@ -683,61 +678,14 @@ public static function deleteUser($uid) {
return $query->execute([$uid]);
}

/**
* calculate remaining free space for trash bin
*
* @param integer $trashbinSize current size of the trash bin
* @param string $user
* @return int available free space for trash bin
*/
private static function calculateFreeSpace($trashbinSize, $user) {
$softQuota = true;
$userObject = \OC::$server->getUserManager()->get($user);
if(is_null($userObject)) {
return 0;
}
$quota = \OC_Util::getUserQuota($userObject);
if ($quota === \OCP\Files\FileInfo::SPACE_UNLIMITED) {
$quota = Filesystem::free_space('/');
$softQuota = false;
// inf or unknown free space
if ($quota < 0) {
$quota = PHP_INT_MAX;
}
} else {
$quota = \OCP\Util::computerFileSize($quota);
}

// calculate available space for trash bin
// subtract size of files and current trash bin size from quota
if ($softQuota) {
$userFolder = \OC::$server->getUserFolder($user);
if(is_null($userFolder)) {
return 0;
}
$free = $quota - $userFolder->getSize(); // remaining free space for user
if ($free > 0) {
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $trashbinSize; // how much space can be used for versions
} else {
$availableSpace = $free - $trashbinSize;
}
} else {
$availableSpace = $quota;
}

return $availableSpace;
}

/**
* resize trash bin if necessary after a new file was added to ownCloud
*
* @param string $user user id
*/
public static function resizeTrash($user) {

$size = self::getTrashbinSize($user);

$freeSpace = self::calculateFreeSpace($size, $user);
$freeSpace = self::getQuota()->calculateFreeSpace($size, $user);

if ($freeSpace < 0) {
self::scheduleExpire($user);
Expand All @@ -751,7 +699,7 @@ public static function resizeTrash($user) {
*/
public static function expire($user) {
$trashBinSize = self::getTrashbinSize($user);
$availableSpace = self::calculateFreeSpace($trashBinSize, $user);
$availableSpace = self::getQuota()->calculateFreeSpace($trashBinSize, $user);

$dirContent = Helper::getTrashFiles('/', $user, 'mtime');

Expand All @@ -764,6 +712,14 @@ public static function expire($user) {
self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
}

/**
* @return Quota
*/
protected static function getQuota() {
$application = new Application();
return $application->getContainer()->query('Quota');
}

/**
* @param string $user
*/
Expand Down Expand Up @@ -794,7 +750,13 @@ protected static function deleteFiles($files, $user, $availableSpace) {
foreach ($files as $file) {
if ($availableSpace < 0 && $expiration->isExpired($file['mtime'], true)) {
$tmp = self::delete($file['name'], $user, $file['mtime']);
\OCP\Util::writeLog('files_trashbin', 'remove "' . $file['name'] . '" (' . $tmp . 'B) to meet the limit of trash bin size (50% of available quota)', \OCP\Util::INFO);
$message = sprintf(
'remove "%s" (%dB) to meet the limit of trash bin size (%d%% of available quota)',
$file['name'],
$tmp,
self::getQuota()->getPurgeLimit()
);
\OCP\Util::writeLog('files_trashbin', $message, \OCP\Util::INFO);
$availableSpace += $tmp;
$size += $tmp;
} else {
Expand Down
53 changes: 53 additions & 0 deletions apps/files_trashbin/tests/QuotaTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
/**
* @author Viktar Dubiniuk <dubiniuk@owncloud.com>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

use OCA\Files_Trashbin\Quota;
use OCP\IConfig;
use OCP\IUserManager;

class QuotaTest extends \Test\TestCase {

/** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */
private $userManager;

/** @var IConfig | \PHPUnit_Framework_MockObject_MockObject */
protected $config;

protected function setUp() {
parent::setUp();

$this->userManager = $this->getMockBuilder(IUserManager::class)
->getMock();
$this->config = $this->getMockBuilder(IConfig::class)
->getMock();
}

public function testNonExistingUserNoNeedPurge() {
$this->userManager->expects($this->any())
->method('get')
->willReturn(null);

$quota = new Quota($this->userManager, $this->config);
$neededSpace = $quota->calculateFreeSpace(100, 'anyuser');
$this->assertEquals(0, $neededSpace);
}

}
5 changes: 5 additions & 0 deletions config/config.sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,11 @@
*/
'trashbin_retention_obligation' => 'auto',

/**
* This setting defines percentage of free space occupied by deleted files
* that triggers auto purging of deleted files for this user
*/
'trashbin_purge_limit' => 50,

/**
* File versions
Expand Down

0 comments on commit 1a7dc7d

Please sign in to comment.